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

Merge tag 'iio-for-4.15b' of...

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

Jonathan writes:

Second set of IIO new device support, features and cleanup for 4.15

New device support
* cros_ec_accel_legacy
  - New driver for this older chromebook accelerometer.
* ds4422 dac driver
  - New driver and bindings for the Maxim ds4422 and ds4424 I2C DACs.
* kxcjk1013
  - Support the KXTF9 accelerometers.
* mcp320x
  - support mcp3550, mcp3551, mcp3553 21 bit ADCs.
* rfd77402
  - new driver for this laser range finder.
* st-sensors-accel
  - add support for the LIS2DW12 accelerometer with bindings
  - add support for the LIS3DHH accelerometer with bindings

New features
* core
  - Drop a duplicate forward declaration in iio.h
* Docs
  - add a clarification of the meaning of IIO_DISTANCE to reflect
    existing use in various range finding devices.
* st-sensors
  - add a register mask for the status register to correctly support
    2 channel devices.
  - decouple the irq1 and irq2 configuration parameters.
  - do not always write the enable_axis register as some newer devices
    are always on and don't support such configuration.
  - split open-drain control for irq1 and irq2
  - make sampling frequency control optional as non all hardware
    supports it.
* st-sensors-gyro
  - support 3 wire SPI mode
* st-sensors-magn
  - support 3 wire SPI mode
* st-sensors-pressure
  - support 3 wire SPI mode.

Cleanups and fixes
* ad7192
  - expand the buffer lock to cover device state protection rather than
    using core mlock to provide the state protection.
* ade7753
  - expand the buffer lock to cover device state protection as well
    rather than having an additional lock.
* dummy-evgen
  - Use the new irq_sim infrastructure rather than having our
    own local version of the same thing.
* hid-sensor-trigger
  - avoid touching sensors ever if user hasn't requested it.  This
    is a work around for one reported issue where turning a sensor
    off wasn't sufficient to make it actually switch off.  As we
    have only one report from what looks like buggy hardware we
    are sending this upstream the slow way.
* ina2xx
  - Adhere to the published ABI docs and use Ohms instead of
    microohms.  We don't think that anyone will notice this ABI fix
    but are sending it the slow route to reduce fallout if someone
    does!
* kxcjk1013 - refactors to support the KXTF9 being added.
  - Refactor ODR support.
  - Fix INT_CTRL/INT_SRC1 bit names to match the register name.
  - Extract code for reporting motion events as this isn't present
    on some parts to be supported.
  - Make the sysfs sampling_frequency_available stuff not a fixed
    string so as to allow for it to be chip type dependent.
  - Make the sampling frequency_available per type to match
    the sampling_frequency attributes.
* lsm6dsx - rework prior to new device support.
  - express the max fifo depth in 'scans' rather than bytes.
  - split control of the fifo mode fifo output data rate.
  - move decimator registers into the sensor_settings structure
    as this will make it easier to support devices that don't have
    this function.
  - add a fifo ops datastructure to allow for inter-part variations.
* max30100
  - fix i2c chip address in dt example
* max30102
  - use correct binding name for max30102 in example
* mma8452
  - Rename read/write event value callbacks to be more generic
    reflecting what they actually do now.
* rcar-gyroadc
  - pointer case to fix warnings when moving to 64 bit as this IP is
    present on new 64 bit SOCs
  - enable compile-testing to improve build coverage on this driver.
  - use the of_device_get_match_data helper instead of open coding
* sun4i-gpadc-iio
  - Register in the thermal framework after pm. Otherwise the IP is not
    enabled.
  - Don't fail probing if no thermal DT node is present.
* tsl2x7x
  - renaming tsl2x7x_settings to settings to avoid excessive line
    lengths.
  - Use IIO core to generate the integration_time sysfs attributes
    rather than hand rolling.
* vf6180
  - Move the range check on integration time to the setter function.
  - Refactor the code around integration time to be clearer including
    caching current integration time avoiding unnecessary chip reads.
  - cleanup the als_gain lookup avoiding reading registers on chip.
  - use rounded matching rather than precise values for als_gain
    lookup.
  - Correct the ALS  scale when non-default gain or integration time
    is used.
parents 1236d6bb 11b86c70
......@@ -1242,9 +1242,9 @@ What: /sys/.../iio:deviceX/in_distance_raw
KernelVersion: 4.0
Contact: linux-iio@vger.kernel.org
Description:
This attribute is used to read the distance covered by the user
since the last reboot while activated. Units after application
of scale are meters.
This attribute is used to read the measured distance to an object
or the distance covered by the user since the last reboot while
activated. Units after application of scale are meters.
What: /sys/bus/iio/devices/iio:deviceX/store_eeprom
KernelVersion: 3.4.0
......
......@@ -16,3 +16,13 @@ Description:
the motion sensor is placed. For example, in a laptop a motion
sensor can be located on the base or on the lid. Current valid
values are 'base' and 'lid'.
What: /sys/bus/iio/devices/iio:deviceX/id
Date: Septembre 2017
KernelVersion: 4.14
Contact: linux-iio@vger.kernel.org
Description:
This attribute is exposed by the CrOS EC legacy accelerometer
driver and represents the sensor ID as exposed by the EC. This
ID is used by the Android sensor service hardware abstraction
layer (sensor HAL) through the Android container on ChromeOS.
Maxim Integrated DS4422/DS4424 7-bit Sink/Source Current DAC Device Driver
Datasheet publicly available at:
https://datasheets.maximintegrated.com/en/ds/DS4422-DS4424.pdf
Required properties:
- compatible: Should be one of
maxim,ds4422
maxim,ds4424
- reg: Should contain the DAC I2C address
Optional properties:
- vcc-supply: Power supply is optional. If not defined, driver will ignore it.
Example:
ds4224@10 {
compatible = "maxim,ds4424";
reg = <0x10>; /* When A0, A1 pins are ground */
vcc-supply = <&vcc_3v3>;
};
......@@ -20,9 +20,9 @@ Optional properties:
Example:
max30100@057 {
max30100@57 {
compatible = "maxim,max30100";
reg = <57>;
reg = <0x57>;
maxim,led-current-microamp = <24000 50000>;
interrupt-parent = <&gpio1>;
interrupts = <16 2>;
......
......@@ -20,7 +20,7 @@ Optional properties:
Example:
max30100@57 {
max30102@57 {
compatible = "maxim,max30102";
reg = <0x57>;
maxim,red-led-current-microamp = <7000>;
......
......@@ -46,6 +46,8 @@ Accelerometers:
- st,h3lis331dl-accel
- st,lng2dm-accel
- st,lis3l02dq
- st,lis2dw12
- st,lis3dhh
Gyroscopes:
- st,l3g4200d-gyro
......
......@@ -148,6 +148,17 @@ config HID_SENSOR_ACCEL_3D
To compile this driver as a module, choose M here: the
module will be called hid-sensor-accel-3d.
config IIO_CROS_EC_ACCEL_LEGACY
tristate "ChromeOS EC Legacy Accelerometer Sensor"
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select CROS_EC_LPC_REGISTER_DEVICE
help
Say yes here to get support for accelerometers on Chromebook using
legacy EC firmware.
Sensor data is retrieved through IO memory.
Newer devices should use IIO_CROS_EC_SENSORS.
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
......@@ -219,8 +230,8 @@ config KXCJK1013
select IIO_TRIGGERED_BUFFER
help
Say Y here if you want to build a driver for the Kionix KXCJK-1013
triaxial acceleration sensor. This driver also supports KXCJ9-1008
and KXTJ2-1009.
triaxial acceleration sensor. This driver also supports KXCJ9-1008,
KXTJ2-1009 and KXTF9.
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
......
......@@ -43,6 +43,8 @@ obj-$(CONFIG_SCA3000) += sca3000.o
obj-$(CONFIG_STK8312) += stk8312.o
obj-$(CONFIG_STK8BA50) += stk8ba50.o
obj-$(CONFIG_IIO_CROS_EC_ACCEL_LEGACY) += cros_ec_accel_legacy.o
obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
......
This diff is collapsed.
This diff is collapsed.
......@@ -792,7 +792,7 @@ static int mma8452_get_event_regs(struct mma8452_data *data,
}
}
static int mma8452_read_thresh(struct iio_dev *indio_dev,
static int mma8452_read_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
......@@ -855,7 +855,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev,
}
}
static int mma8452_write_thresh(struct iio_dev *indio_dev,
static int mma8452_write_event_value(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
......@@ -1391,8 +1391,8 @@ static const struct iio_info mma8452_info = {
.read_raw = &mma8452_read_raw,
.write_raw = &mma8452_write_raw,
.event_attrs = &mma8452_event_attribute_group,
.read_event_value = &mma8452_read_thresh,
.write_event_value = &mma8452_write_thresh,
.read_event_value = &mma8452_read_event_value,
.write_event_value = &mma8452_write_event_value,
.read_event_config = &mma8452_read_event_config,
.write_event_config = &mma8452_write_event_config,
.debugfs_reg_access = &mma8452_reg_access_dbg,
......
......@@ -32,6 +32,8 @@ enum st_accel_type {
H3LIS331DL,
LIS331DL,
LIS3LV02DL,
LIS2DW12,
LIS3DHH,
ST_ACCEL_MAX,
};
......@@ -52,6 +54,8 @@ enum st_accel_type {
#define LIS2DH12_ACCEL_DEV_NAME "lis2dh12_accel"
#define LIS3L02DQ_ACCEL_DEV_NAME "lis3l02dq"
#define LNG2DM_ACCEL_DEV_NAME "lng2dm"
#define LIS2DW12_ACCEL_DEV_NAME "lis2dw12"
#define LIS3DHH_ACCEL_DEV_NAME "lis3dhh"
/**
* struct st_sensors_platform_data - default accel platform data
......
......@@ -159,12 +159,16 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x10,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x22,
.mask = 0x10,
},
.addr_ihl = 0x25,
.mask_ihl = 0x02,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
......@@ -229,14 +233,24 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x02,
.mask_int2 = 0x10,
.int1 = {
.addr = 0x22,
.mask = 0x02,
.addr_od = 0x22,
.mask_od = 0x40,
},
.int2 = {
.addr = 0x22,
.mask = 0x10,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
......@@ -313,12 +327,16 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x08,
},
.drdy_irq = {
.addr = 0x23,
.mask_int1 = 0x80,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x23,
.mask = 0x80,
},
.addr_ihl = 0x23,
.mask_ihl = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
.ig1 = {
.en_addr = 0x23,
.en_mask = 0x08,
......@@ -387,9 +405,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x01,
},
.drdy_irq = {
.addr = 0x21,
.mask_int1 = 0x04,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.int1 = {
.addr = 0x21,
.mask = 0x04,
},
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x21,
......@@ -444,14 +467,24 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x04,
.mask_int2 = 0x20,
.int1 = {
.addr = 0x22,
.mask = 0x04,
.addr_od = 0x22,
.mask_od = 0x40,
},
.int2 = {
.addr = 0x22,
.mask = 0x20,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x21,
......@@ -513,9 +546,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x02,
.mask_int2 = 0x10,
.int1 = {
.addr = 0x22,
.mask = 0x02,
},
.int2 = {
.addr = 0x22,
.mask = 0x10,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
},
......@@ -567,9 +605,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.bdu = {
},
.drdy_irq = {
.addr = 0x21,
.mask_int1 = 0x04,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.int1 = {
.addr = 0x21,
.mask = 0x04,
},
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x21,
......@@ -635,12 +678,16 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
},
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x10,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x22,
.mask = 0x10,
},
.addr_ihl = 0x25,
.mask_ihl = 0x02,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
......@@ -649,6 +696,139 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = true,
.bootime = 2,
},
{
.wai = 0x44,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS2DW12_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_12bit_channels,
.odr = {
.addr = 0x20,
.mask = 0xf0,
.odr_avl = {
{ .hz = 1, .value = 0x01, },
{ .hz = 12, .value = 0x02, },
{ .hz = 25, .value = 0x03, },
{ .hz = 50, .value = 0x04, },
{ .hz = 100, .value = 0x05, },
{ .hz = 200, .value = 0x06, },
},
},
.pw = {
.addr = 0x20,
.mask = 0xf0,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.fs = {
.addr = 0x25,
.mask = 0x30,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = 0x00,
.gain = IIO_G_TO_M_S_2(976),
},
[1] = {
.num = ST_ACCEL_FS_AVL_4G,
.value = 0x01,
.gain = IIO_G_TO_M_S_2(1952),
},
[2] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = 0x02,
.gain = IIO_G_TO_M_S_2(3904),
},
[3] = {
.num = ST_ACCEL_FS_AVL_16G,
.value = 0x03,
.gain = IIO_G_TO_M_S_2(7808),
},
},
},
.bdu = {
.addr = 0x21,
.mask = 0x08,
},
.drdy_irq = {
.int1 = {
.addr = 0x23,
.mask = 0x01,
.addr_od = 0x22,
.mask_od = 0x20,
},
.int2 = {
.addr = 0x24,
.mask = 0x01,
.addr_od = 0x22,
.mask_od = 0x20,
},
.addr_ihl = 0x22,
.mask_ihl = 0x08,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x01,
},
},
.sim = {
.addr = 0x21,
.value = BIT(0),
},
.multi_read_bit = false,
.bootime = 2,
},
{
.wai = 0x11,
.wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS,
.sensors_supported = {
[0] = LIS3DHH_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_16bit_channels,
.odr = {
/* just ODR = 1100Hz available */
.odr_avl = {
{ .hz = 1100, .value = 0x00, },
},
},
.pw = {
.addr = 0x20,
.mask = 0x80,
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.fs = {
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.gain = IIO_G_TO_M_S_2(76),
},
},
},
.bdu = {
.addr = 0x20,
.mask = 0x01,
},
.drdy_irq = {
.int1 = {
.addr = 0x21,
.mask = 0x80,
.addr_od = 0x23,
.mask_od = 0x04,
},
.int2 = {
.addr = 0x22,
.mask = 0x80,
.addr_od = 0x23,
.mask_od = 0x08,
},
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.multi_read_bit = false,
.bootime = 2,
},
};
static int st_accel_read_raw(struct iio_dev *indio_dev,
......
......@@ -94,6 +94,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lng2dm-accel",
.data = LNG2DM_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2dw12",
.data = LIS2DW12_ACCEL_DEV_NAME,
},
{},
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -129,6 +133,7 @@ static const struct i2c_device_id st_accel_id_table[] = {
{ H3LIS331DL_ACCEL_DEV_NAME, H3LIS331DL },
{ LIS331DL_ACCEL_DEV_NAME, LIS331DL },
{ LIS3LV02DL_ACCEL_DEV_NAME, LIS3LV02DL },
{ LIS2DW12_ACCEL_DEV_NAME, LIS2DW12 },
{},
};
MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
......
......@@ -82,6 +82,14 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lis331dl-accel",
.data = LIS331DL_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis2dw12",
.data = LIS2DW12_ACCEL_DEV_NAME,
},
{
.compatible = "st,lis3dhh",
.data = LIS3DHH_ACCEL_DEV_NAME,
},
{}
};
MODULE_DEVICE_TABLE(of, st_accel_of_match);
......@@ -133,6 +141,8 @@ static const struct spi_device_id st_accel_id_table[] = {
{ H3LIS331DL_ACCEL_DEV_NAME },
{ LIS331DL_ACCEL_DEV_NAME },
{ LIS3LV02DL_ACCEL_DEV_NAME },
{ LIS2DW12_ACCEL_DEV_NAME },
{ LIS3DHH_ACCEL_DEV_NAME },
{},
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
......
......@@ -475,12 +475,13 @@ config MAX9611
called max9611.
config MCP320X
tristate "Microchip Technology MCP3x01/02/04/08"
tristate "Microchip Technology MCP3x01/02/04/08 and MCP3550/1/3"
depends on SPI
help
Say yes here to build support for Microchip Technology's
MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204,
MCP3208 or MCP3301 analog to digital converter.
MCP3208, MCP3301, MCP3550, MCP3551 and MCP3553 analog to digital
converters.
This driver can also be built as a module. If so, the module will be
called mcp320x.
......@@ -593,7 +594,7 @@ config QCOM_SPMI_VADC
config RCAR_GYRO_ADC
tristate "Renesas R-Car GyroADC driver"
depends on ARCH_RCAR_GEN2 || (ARM && COMPILE_TEST)
depends on ARCH_RCAR_GEN2 || COMPILE_TEST
help
Say yes here to build support for the GyroADC found in Renesas
R-Car Gen2 SoCs. This block is a simple SPI offload engine for
......
......@@ -123,7 +123,7 @@ struct ina2xx_chip_info {
struct task_struct *task;
const struct ina2xx_config *config;
struct mutex state_lock;
unsigned int shunt_resistor;
unsigned int shunt_resistor_uohm;
int avg;
int int_time_vbus; /* Bus voltage integration time uS */
int int_time_vshunt; /* Shunt voltage integration time uS */
......@@ -436,7 +436,7 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
/*
* Set current LSB to 1mA, shunt is in uOhms
* (equation 13 in datasheet). We hardcode a Current_LSB
* of 1.0 x10-6. The only remaining parameter is RShunt.
* of 1.0 x10-3. The only remaining parameter is RShunt.
* There is no need to expose the CALIBRATION register
* to the user for now. But we need to reset this register
* if the user updates RShunt after driver init, e.g upon
......@@ -445,7 +445,7 @@ static ssize_t ina2xx_allow_async_readout_store(struct device *dev,
static int ina2xx_set_calibration(struct ina2xx_chip_info *chip)
{
u16 regval = DIV_ROUND_CLOSEST(chip->config->calibration_factor,
chip->shunt_resistor);
chip->shunt_resistor_uohm);
return regmap_write(chip->regmap, INA2XX_CALIBRATION, regval);
}
......@@ -455,7 +455,7 @@ static int set_shunt_resistor(struct ina2xx_chip_info *chip, unsigned int val)
if (val <= 0 || val > chip->config->calibration_factor)
return -EINVAL;
chip->shunt_resistor = val;
chip->shunt_resistor_uohm = val;
return 0;
}
......@@ -465,8 +465,9 @@ static ssize_t ina2xx_shunt_resistor_show(struct device *dev,
char *buf)
{
struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
int vals[2] = { chip->shunt_resistor_uohm, 1000000 };
return sprintf(buf, "%d\n", chip->shunt_resistor);
return iio_format_value(buf, IIO_VAL_FRACTIONAL, 1, vals);
}
static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
......@@ -474,14 +475,13 @@ static ssize_t ina2xx_shunt_resistor_store(struct device *dev,
const char *buf, size_t len)
{
struct ina2xx_chip_info *chip = iio_priv(dev_to_iio_dev(dev));
unsigned long val;
int ret;
int val, val_fract, ret;
ret = kstrtoul((const char *) buf, 10, &val);
ret = iio_str_to_fixpoint(buf, 100000, &val, &val_fract);
if (ret)
return ret;
ret = set_shunt_resistor(chip, val);
ret = set_shunt_resistor(chip, val * 1000000 + val_fract);
if (ret)
return ret;
......
......@@ -19,6 +19,11 @@
* ------------
* 13 bit converter
* MCP3301
* ------------
* 22 bit converter
* MCP3550
* MCP3551
* MCP3553
*
* Datasheet can be found here:
* http://ww1.microchip.com/downloads/en/DeviceDoc/21293C.pdf mcp3001
......@@ -28,6 +33,7 @@
* http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf mcp3202
* http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf mcp3204/08
* http://ww1.microchip.com/downloads/en/DeviceDoc/21700E.pdf mcp3301
* http://ww1.microchip.com/downloads/en/DeviceDoc/21950D.pdf mcp3550/1/3
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
......@@ -51,12 +57,17 @@ enum {
mcp3204,
mcp3208,
mcp3301,
mcp3550_50,
mcp3550_60,
mcp3551,
mcp3553,
};
struct mcp320x_chip_info {
const struct iio_chan_spec *channels;
unsigned int num_channels;
unsigned int resolution;
unsigned int conv_time; /* usec */
};
/**
......@@ -64,6 +75,8 @@ struct mcp320x_chip_info {
* @spi: SPI slave (parent of the IIO device)
* @msg: SPI message to select a channel and receive a value from the ADC
* @transfer: SPI transfers used by @msg
* @start_conv_msg: SPI message to start a conversion by briefly asserting CS
* @start_conv_transfer: SPI transfer used by @start_conv_msg
* @reg: regulator generating Vref
* @lock: protects read sequences
* @chip_info: ADC properties
......@@ -74,13 +87,15 @@ struct mcp320x {
struct spi_device *spi;
struct spi_message msg;
struct spi_transfer transfer[2];
struct spi_message start_conv_msg;
struct spi_transfer start_conv_transfer;
struct regulator *reg;
struct mutex lock;
const struct mcp320x_chip_info *chip_info;
u8 tx_buf ____cacheline_aligned;
u8 rx_buf[2];
u8 rx_buf[4];
};
static int mcp320x_channel_to_tx_data(int device_index,
......@@ -109,6 +124,15 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
{
int ret;
if (adc->chip_info->conv_time) {
ret = spi_sync(adc->spi, &adc->start_conv_msg);
if (ret < 0)
return ret;
usleep_range(adc->chip_info->conv_time,
adc->chip_info->conv_time + 100);
}
memset(&adc->rx_buf, 0, sizeof(adc->rx_buf));
if (adc->chip_info->num_channels > 1)
adc->tx_buf = mcp320x_channel_to_tx_data(device_index, channel,
......@@ -139,6 +163,31 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel,
*val = sign_extend32((adc->rx_buf[0] & 0x1f) << 8
| adc->rx_buf[1], 12);
return 0;
case mcp3550_50:
case mcp3550_60:
case mcp3551:
case mcp3553: {
u32 raw = be32_to_cpup((u32 *)adc->rx_buf);
if (!(adc->spi->mode & SPI_CPOL))
raw <<= 1; /* strip Data Ready bit in SPI mode 0,0 */
/*
* If the input is within -vref and vref, bit 21 is the sign.
* Up to 12% overrange or underrange are allowed, in which case
* bit 23 is the sign and bit 0 to 21 is the value.
*/
raw >>= 8;
if (raw & BIT(22) && raw & BIT(23))
return -EIO; /* cannot have overrange AND underrange */
else if (raw & BIT(22))
raw &= ~BIT(22); /* overrange */
else if (raw & BIT(23) || raw & BIT(21))
raw |= GENMASK(31, 22); /* underrange or negative */
*val = (s32)raw;
return 0;
}
default:
return -EINVAL;
}
......@@ -297,6 +346,31 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = {
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 13
},
[mcp3550_50] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
/* 2% max deviation + 144 clock periods to exit shutdown */
.conv_time = 80000 * 1.02 + 144000 / 102.4,
},
[mcp3550_60] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
.conv_time = 66670 * 1.02 + 144000 / 122.88,
},
[mcp3551] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
.conv_time = 73100 * 1.02 + 144000 / 112.64,
},
[mcp3553] = {
.channels = mcp3201_channels,
.num_channels = ARRAY_SIZE(mcp3201_channels),
.resolution = 21,
.conv_time = 16670 * 1.02 + 144000 / 122.88,
},
};
static int mcp320x_probe(struct spi_device *spi)
......@@ -304,7 +378,7 @@ static int mcp320x_probe(struct spi_device *spi)
struct iio_dev *indio_dev;
struct mcp320x *adc;
const struct mcp320x_chip_info *chip_info;
int ret;
int ret, device_index;
indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
if (!indio_dev)
......@@ -320,7 +394,8 @@ static int mcp320x_probe(struct spi_device *spi)
indio_dev->info = &mcp320x_info;
spi_set_drvdata(spi, indio_dev);
chip_info = &mcp320x_chip_infos[spi_get_device_id(spi)->driver_data];
device_index = spi_get_device_id(spi)->driver_data;
chip_info = &mcp320x_chip_infos[device_index];
indio_dev->channels = chip_info->channels;
indio_dev->num_channels = chip_info->num_channels;
......@@ -329,7 +404,8 @@ static int mcp320x_probe(struct spi_device *spi)
adc->transfer[0].tx_buf = &adc->tx_buf;
adc->transfer[0].len = sizeof(adc->tx_buf);
adc->transfer[1].rx_buf = adc->rx_buf;
adc->transfer[1].len = sizeof(adc->rx_buf);
adc->transfer[1].len = DIV_ROUND_UP(chip_info->resolution, 8);
if (chip_info->num_channels == 1)
/* single-channel converters are rx only (no MOSI pin) */
spi_message_init_with_transfers(&adc->msg,
......@@ -338,6 +414,32 @@ static int mcp320x_probe(struct spi_device *spi)
spi_message_init_with_transfers(&adc->msg, adc->transfer,
ARRAY_SIZE(adc->transfer));
switch (device_index) {
case mcp3550_50:
case mcp3550_60:
case mcp3551:
case mcp3553:
/* rx len increases from 24 to 25 bit in SPI mode 0,0 */
if (!(spi->mode & SPI_CPOL))
adc->transfer[1].len++;
/* conversions are started by asserting CS pin for 8 usec */
adc->start_conv_transfer.delay_usecs = 8;
spi_message_init_with_transfers(&adc->start_conv_msg,
&adc->start_conv_transfer, 1);
/*
* If CS was previously kept low (continuous conversion mode)
* and then changed to high, the chip is in shutdown.
* Sometimes it fails to wake from shutdown and clocks out
* only 0xffffff. The magic sequence of performing two
* conversions without delay between them resets the chip
* and ensures all subsequent conversions succeed.
*/
mcp320x_adc_conversion(adc, 0, 1, device_index, &ret);
mcp320x_adc_conversion(adc, 0, 1, device_index, &ret);
}
adc->reg = devm_regulator_get(&spi->dev, "vref");
if (IS_ERR(adc->reg))
return PTR_ERR(adc->reg);
......@@ -392,6 +494,10 @@ static const struct of_device_id mcp320x_dt_ids[] = {
{ .compatible = "microchip,mcp3204" },
{ .compatible = "microchip,mcp3208" },
{ .compatible = "microchip,mcp3301" },
{ .compatible = "microchip,mcp3550-50" },
{ .compatible = "microchip,mcp3550-60" },
{ .compatible = "microchip,mcp3551" },
{ .compatible = "microchip,mcp3553" },
{ }
};
MODULE_DEVICE_TABLE(of, mcp320x_dt_ids);
......@@ -407,6 +513,10 @@ static const struct spi_device_id mcp320x_id[] = {
{ "mcp3204", mcp3204 },
{ "mcp3208", mcp3208 },
{ "mcp3301", mcp3301 },
{ "mcp3550-50", mcp3550_50 },
{ "mcp3550-60", mcp3550_60 },
{ "mcp3551", mcp3551 },
{ "mcp3553", mcp3553 },
{ }
};
MODULE_DEVICE_TABLE(spi, mcp320x_id);
......@@ -423,5 +533,5 @@ static struct spi_driver mcp320x_driver = {
module_spi_driver(mcp320x_driver);
MODULE_AUTHOR("Oskar Andero <oskar.andero@gmail.com>");
MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08");
MODULE_DESCRIPTION("Microchip Technology MCP3x01/02/04/08 and MCP3550/1/3");
MODULE_LICENSE("GPL v2");
......@@ -348,7 +348,7 @@ static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
continue;
}
childmode = (unsigned int)of_id->data;
childmode = (uintptr_t)of_id->data;
switch (childmode) {
case RCAR_GYROADC_MODE_SELECT_1_MB88101A:
sample_width = 12;
......@@ -487,8 +487,6 @@ static int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev)
static int rcar_gyroadc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(rcar_gyroadc_match, &pdev->dev);
struct device *dev = &pdev->dev;
struct rcar_gyroadc *priv;
struct iio_dev *indio_dev;
......@@ -525,7 +523,8 @@ static int rcar_gyroadc_probe(struct platform_device *pdev)
if (ret)
return ret;
priv->model = (enum rcar_gyroadc_model)of_id->data;
priv->model = (enum rcar_gyroadc_model)
of_device_get_match_data(&pdev->dev);
platform_set_drvdata(pdev, indio_dev);
......
......@@ -528,17 +528,10 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev,
return ret;
}
if (!IS_ENABLED(CONFIG_THERMAL_OF))
return 0;
if (IS_ENABLED(CONFIG_THERMAL_OF))
info->sensor_device = &pdev->dev;
info->sensor_device = &pdev->dev;
info->tzd = thermal_zone_of_sensor_register(info->sensor_device, 0,
info, &sun4i_ts_tz_ops);
if (IS_ERR(info->tzd))
dev_err(&pdev->dev, "could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
return PTR_ERR_OR_ZERO(info->tzd);
return 0;
}
static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
......@@ -585,15 +578,6 @@ static int sun4i_gpadc_probe_mfd(struct platform_device *pdev,
* return the temperature.
*/
info->sensor_device = pdev->dev.parent;
info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
0, info,
&sun4i_ts_tz_ops);
if (IS_ERR(info->tzd)) {
dev_err(&pdev->dev,
"could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
return PTR_ERR(info->tzd);
}
} else {
indio_dev->num_channels =
ARRAY_SIZE(sun4i_gpadc_channels_no_temp);
......@@ -663,6 +647,22 @@ static int sun4i_gpadc_probe(struct platform_device *pdev)
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_enable(&pdev->dev);
if (IS_ENABLED(CONFIG_THERMAL_OF)) {
info->tzd = thermal_zone_of_sensor_register(info->sensor_device,
0, info,
&sun4i_ts_tz_ops);
/*
* Do not fail driver probing when failing to register in
* thermal because no thermal DT node is found.
*/
if (IS_ERR(info->tzd) && PTR_ERR(info->tzd) != -ENODEV) {
dev_err(&pdev->dev,
"could not register thermal sensor: %ld\n",
PTR_ERR(info->tzd));
return PTR_ERR(info->tzd);
}
}
ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0) {
dev_err(&pdev->dev, "could not register the device\n");
......
......@@ -179,6 +179,10 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
int ret;
atomic_set(&st->user_requested_state, state);
if (atomic_add_unless(&st->runtime_pm_enable, 1, 1))
pm_runtime_enable(&st->pdev->dev);
if (state)
ret = pm_runtime_get_sync(&st->pdev->dev);
else {
......@@ -221,7 +225,8 @@ static void hid_sensor_set_power_work(struct work_struct *work)
if (attrb->latency_ms > 0)
hid_sensor_set_report_latency(attrb, attrb->latency_ms);
_hid_sensor_power_state(attrb, true);
if (atomic_read(&attrb->user_requested_state))
_hid_sensor_power_state(attrb, true);
}
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
......@@ -232,7 +237,9 @@ static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb)
{
pm_runtime_disable(&attrb->pdev->dev);
if (atomic_read(&attrb->runtime_pm_enable))
pm_runtime_disable(&attrb->pdev->dev);
pm_runtime_set_suspended(&attrb->pdev->dev);
pm_runtime_put_noidle(&attrb->pdev->dev);
......@@ -282,7 +289,6 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
INIT_WORK(&attrb->work, hid_sensor_set_power_work);
pm_suspend_ignore_children(&attrb->pdev->dev, true);
pm_runtime_enable(&attrb->pdev->dev);
/* Default to 3 seconds, but can be changed from sysfs */
pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
3000);
......
......@@ -93,6 +93,9 @@ int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr)
struct st_sensor_odr_avl odr_out = {0, 0};
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (!sdata->sensor_settings->odr.addr)
return 0;
err = st_sensors_match_odr(sdata->sensor_settings, odr, &odr_out);
if (err < 0)
goto st_sensors_match_odr_error;
......@@ -221,11 +224,14 @@ EXPORT_SYMBOL(st_sensors_set_enable);
int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable)
{
struct st_sensor_data *sdata = iio_priv(indio_dev);
int err = 0;
return st_sensors_write_data_with_mask(indio_dev,
if (sdata->sensor_settings->enable_axis.addr)
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->enable_axis.addr,
sdata->sensor_settings->enable_axis.mask,
axis_enable);
return err;
}
EXPORT_SYMBOL(st_sensors_set_axis_enable);
......@@ -283,7 +289,8 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
struct st_sensor_data *sdata = iio_priv(indio_dev);
/* Sensor does not support interrupts */
if (sdata->sensor_settings->drdy_irq.addr == 0) {
if (!sdata->sensor_settings->drdy_irq.int1.addr &&
!sdata->sensor_settings->drdy_irq.int2.addr) {
if (pdata->drdy_int_pin)
dev_info(&indio_dev->dev,
"DRDY on pin INT%d specified, but sensor "
......@@ -294,7 +301,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
switch (pdata->drdy_int_pin) {
case 1:
if (sdata->sensor_settings->drdy_irq.mask_int1 == 0) {
if (!sdata->sensor_settings->drdy_irq.int1.mask) {
dev_err(&indio_dev->dev,
"DRDY on INT1 not available.\n");
return -EINVAL;
......@@ -302,7 +309,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
sdata->drdy_int_pin = 1;
break;
case 2:
if (sdata->sensor_settings->drdy_irq.mask_int2 == 0) {
if (!sdata->sensor_settings->drdy_irq.int2.mask) {
dev_err(&indio_dev->dev,
"DRDY on INT2 not available.\n");
return -EINVAL;
......@@ -315,7 +322,8 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
}
if (pdata->open_drain) {
if (!sdata->sensor_settings->drdy_irq.addr_od)
if (!sdata->sensor_settings->drdy_irq.int1.addr_od &&
!sdata->sensor_settings->drdy_irq.int2.addr_od)
dev_err(&indio_dev->dev,
"open drain requested but unsupported.\n");
else
......@@ -442,11 +450,21 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
}
if (sdata->int_pin_open_drain) {
u8 addr, mask;
if (sdata->drdy_int_pin == 1) {
addr = sdata->sensor_settings->drdy_irq.int1.addr_od;
mask = sdata->sensor_settings->drdy_irq.int1.mask_od;
} else {
addr = sdata->sensor_settings->drdy_irq.int2.addr_od;
mask = sdata->sensor_settings->drdy_irq.int2.mask_od;
}
dev_info(&indio_dev->dev,
"set interrupt line to open drain mode\n");
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->drdy_irq.addr_od,
sdata->sensor_settings->drdy_irq.mask_od, 1);
"set interrupt line to open drain mode on pin %d\n",
sdata->drdy_int_pin);
err = st_sensors_write_data_with_mask(indio_dev, addr,
mask, 1);
if (err < 0)
return err;
}
......@@ -460,17 +478,18 @@ EXPORT_SYMBOL(st_sensors_init_sensor);
int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
{
int err;
u8 drdy_mask;
u8 drdy_addr, drdy_mask;
struct st_sensor_data *sdata = iio_priv(indio_dev);
if (!sdata->sensor_settings->drdy_irq.addr) {
if (!sdata->sensor_settings->drdy_irq.int1.addr &&
!sdata->sensor_settings->drdy_irq.int2.addr) {
/*
* there are some devices (e.g. LIS3MDL) where drdy line is
* routed to a given pin and it is not possible to select a
* different one. Take into account irq status register
* to understand if irq trigger can be properly supported
*/
if (sdata->sensor_settings->drdy_irq.addr_stat_drdy)
if (sdata->sensor_settings->drdy_irq.stat_drdy.addr)
sdata->hw_irq_trigger = enable;
return 0;
}
......@@ -485,18 +504,20 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
goto st_accel_set_dataready_irq_error;
}
if (sdata->drdy_int_pin == 1)
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int1;
else
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;
if (sdata->drdy_int_pin == 1) {
drdy_addr = sdata->sensor_settings->drdy_irq.int1.addr;
drdy_mask = sdata->sensor_settings->drdy_irq.int1.mask;
} else {
drdy_addr = sdata->sensor_settings->drdy_irq.int2.addr;
drdy_mask = sdata->sensor_settings->drdy_irq.int2.mask;
}
/* Flag to the poll function that the hardware trigger is in use */
sdata->hw_irq_trigger = enable;
/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->drdy_irq.addr,
drdy_mask, (int)enable);
err = st_sensors_write_data_with_mask(indio_dev, drdy_addr,
drdy_mask, (int)enable);
st_accel_set_dataready_irq_error:
return err;
......
......@@ -31,7 +31,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
int ret;
/* How would I know if I can't check it? */
if (!sdata->sensor_settings->drdy_irq.addr_stat_drdy)
if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr)
return -EINVAL;
/* No scan mask, no interrupt */
......@@ -39,23 +39,15 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev,
return 0;
ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
sdata->sensor_settings->drdy_irq.stat_drdy.addr,
&status);
if (ret < 0) {
dev_err(sdata->dev,
"error checking samples available\n");
return ret;
}
/*
* the lower bits of .active_scan_mask[0] is directly mapped
* to the channels on the sensor: either bit 0 for
* one-dimensional sensors, or e.g. x,y,z for accelerometers,
* gyroscopes or magnetometers. No sensor use more than 3
* channels, so cut the other status bits here.
*/
status &= 0x07;
if (status & (u8)indio_dev->active_scan_mask[0])
if (status & sdata->sensor_settings->drdy_irq.stat_drdy.mask)
return 1;
return 0;
......@@ -212,7 +204,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
* it was "our" interrupt.
*/
if (sdata->int_pin_open_drain &&
sdata->sensor_settings->drdy_irq.addr_stat_drdy)
sdata->sensor_settings->drdy_irq.stat_drdy.addr)
irq_trig |= IRQF_SHARED;
err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
......
......@@ -222,6 +222,15 @@ config DPOT_DAC
To compile this driver as a module, choose M here: the module will be
called dpot-dac.
config DS4424
tristate "Maxim Integrated DS4422/DS4424 DAC driver"
depends on I2C
help
If you say yes here you get support for Maxim chips DS4422, DS4424.
This driver can also be built as a module. If so, the module
will be called ds4424.
config LPC18XX_DAC
tristate "NXP LPC18xx DAC driver"
depends on ARCH_LPC18XX || COMPILE_TEST
......
......@@ -23,6 +23,7 @@ obj-$(CONFIG_AD7303) += ad7303.o
obj-$(CONFIG_AD8801) += ad8801.o
obj-$(CONFIG_CIO_DAC) += cio-dac.o
obj-$(CONFIG_DPOT_DAC) += dpot-dac.o
obj-$(CONFIG_DS4424) += ds4424.o
obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o
obj-$(CONFIG_LTC2632) += ltc2632.o
obj-$(CONFIG_M62332) += m62332.o
......
/*
* Maxim Integrated
* 7-bit, Multi-Channel Sink/Source Current DAC Driver
* Copyright (C) 2017 Maxim Integrated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regulator/consumer.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#include <linux/iio/driver.h>
#include <linux/iio/machine.h>
#include <linux/iio/consumer.h>
#define DS4422_MAX_DAC_CHANNELS 2
#define DS4424_MAX_DAC_CHANNELS 4
#define DS4424_DAC_ADDR(chan) ((chan) + 0xf8)
#define DS4424_SOURCE_I 1
#define DS4424_SINK_I 0
#define DS4424_CHANNEL(chan) { \
.type = IIO_CURRENT, \
.indexed = 1, \
.output = 1, \
.channel = chan, \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
}
/*
* DS4424 DAC control register 8 bits
* [7] 0: to sink; 1: to source
* [6:0] steps to sink/source
* bit[7] looks like a sign bit, but the value of the register is
* not a two's complement code considering the bit[6:0] is a absolute
* distance from the zero point.
*/
union ds4424_raw_data {
struct {
u8 dx:7;
u8 source_bit:1;
};
u8 bits;
};
enum ds4424_device_ids {
ID_DS4422,
ID_DS4424,
};
struct ds4424_data {
struct i2c_client *client;
struct mutex lock;
uint8_t save[DS4424_MAX_DAC_CHANNELS];
struct regulator *vcc_reg;
uint8_t raw[DS4424_MAX_DAC_CHANNELS];
};
static const struct iio_chan_spec ds4424_channels[] = {
DS4424_CHANNEL(0),
DS4424_CHANNEL(1),
DS4424_CHANNEL(2),
DS4424_CHANNEL(3),
};
static int ds4424_get_value(struct iio_dev *indio_dev,
int *val, int channel)
{
struct ds4424_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
if (ret < 0)
goto fail;
*val = ret;
fail:
mutex_unlock(&data->lock);
return ret;
}
static int ds4424_set_value(struct iio_dev *indio_dev,
int val, struct iio_chan_spec const *chan)
{
struct ds4424_data *data = iio_priv(indio_dev);
int ret;
mutex_lock(&data->lock);
ret = i2c_smbus_write_byte_data(data->client,
DS4424_DAC_ADDR(chan->channel), val);
if (ret < 0)
goto fail;
data->raw[chan->channel] = val;
fail:
mutex_unlock(&data->lock);
return ret;
}
static int ds4424_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
union ds4424_raw_data raw;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
ret = ds4424_get_value(indio_dev, val, chan->channel);
if (ret < 0) {
pr_err("%s : ds4424_get_value returned %d\n",
__func__, ret);
return ret;
}
raw.bits = *val;
*val = raw.dx;
if (raw.source_bit == DS4424_SINK_I)
*val = -*val;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int ds4424_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
union ds4424_raw_data raw;
if (val2 != 0)
return -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (val < S8_MIN || val > S8_MAX)
return -EINVAL;
if (val > 0) {
raw.source_bit = DS4424_SOURCE_I;
raw.dx = val;
} else {
raw.source_bit = DS4424_SINK_I;
raw.dx = -val;
}
return ds4424_set_value(indio_dev, raw.bits, chan);
default:
return -EINVAL;
}
}
static int ds4424_verify_chip(struct iio_dev *indio_dev)
{
int ret, val;
ret = ds4424_get_value(indio_dev, &val, DS4424_DAC_ADDR(0));
if (ret < 0)
dev_err(&indio_dev->dev,
"%s failed. ret: %d\n", __func__, ret);
return ret;
}
static int __maybe_unused ds4424_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ds4424_data *data = iio_priv(indio_dev);
int ret = 0;
int i;
for (i = 0; i < indio_dev->num_channels; i++) {
data->save[i] = data->raw[i];
ret = ds4424_set_value(indio_dev, 0,
&indio_dev->channels[i]);
if (ret < 0)
return ret;
}
return ret;
}
static int __maybe_unused ds4424_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ds4424_data *data = iio_priv(indio_dev);
int ret = 0;
int i;
for (i = 0; i < indio_dev->num_channels; i++) {
ret = ds4424_set_value(indio_dev, data->save[i],
&indio_dev->channels[i]);
if (ret < 0)
return ret;
}
return ret;
}
static SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
static const struct iio_info ds4424_info = {
.read_raw = ds4424_read_raw,
.write_raw = ds4424_write_raw,
};
static int ds4424_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ds4424_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev) {
dev_err(&client->dev, "iio dev alloc failed.\n");
return -ENOMEM;
}
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
indio_dev->name = id->name;
indio_dev->dev.of_node = client->dev.of_node;
indio_dev->dev.parent = &client->dev;
if (!client->dev.of_node) {
dev_err(&client->dev,
"Not found DT.\n");
return -ENODEV;
}
data->vcc_reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(data->vcc_reg)) {
dev_err(&client->dev,
"Failed to get vcc-supply regulator. err: %ld\n",
PTR_ERR(data->vcc_reg));
return PTR_ERR(data->vcc_reg);
}
mutex_init(&data->lock);
ret = regulator_enable(data->vcc_reg);
if (ret < 0) {
dev_err(&client->dev,
"Unable to enable the regulator.\n");
return ret;
}
usleep_range(1000, 1200);
ret = ds4424_verify_chip(indio_dev);
if (ret < 0)
goto fail;
switch (id->driver_data) {
case ID_DS4422:
indio_dev->num_channels = DS4422_MAX_DAC_CHANNELS;
break;
case ID_DS4424:
indio_dev->num_channels = DS4424_MAX_DAC_CHANNELS;
break;
default:
dev_err(&client->dev,
"ds4424: Invalid chip id.\n");
ret = -ENXIO;
goto fail;
}
indio_dev->channels = ds4424_channels;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &ds4424_info;
ret = iio_device_register(indio_dev);
if (ret < 0) {
dev_err(&client->dev,
"iio_device_register failed. ret: %d\n", ret);
goto fail;
}
return ret;
fail:
regulator_disable(data->vcc_reg);
return ret;
}
static int ds4424_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ds4424_data *data = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
regulator_disable(data->vcc_reg);
return 0;
}
static const struct i2c_device_id ds4424_id[] = {
{ "ds4422", ID_DS4422 },
{ "ds4424", ID_DS4424 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds4424_id);
static const struct of_device_id ds4424_of_match[] = {
{ .compatible = "maxim,ds4422" },
{ .compatible = "maxim,ds4424" },
{ },
};
MODULE_DEVICE_TABLE(of, ds4424_of_match);
static struct i2c_driver ds4424_driver = {
.driver = {
.name = "ds4424",
.of_match_table = ds4424_of_match,
.pm = &ds4424_pm_ops,
},
.probe = ds4424_probe,
.remove = ds4424_remove,
.id_table = ds4424_id,
};
module_i2c_driver(ds4424_driver);
MODULE_DESCRIPTION("Maxim DS4424 DAC Driver");
MODULE_AUTHOR("Ismail H. Kose <ismail.kose@maximintegrated.com>");
MODULE_AUTHOR("Vishal Sood <vishal.sood@maximintegrated.com>");
MODULE_AUTHOR("David Jung <david.jung@maximintegrated.com>");
MODULE_LICENSE("GPL v2");
......@@ -5,7 +5,7 @@ menu "IIO dummy driver"
depends on IIO
config IIO_DUMMY_EVGEN
select IRQ_WORK
select IRQ_SIM
tristate
config IIO_SIMPLE_DUMMY
......
......@@ -24,97 +24,46 @@
#include "iio_dummy_evgen.h"
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/irq_work.h>
#include <linux/irq_sim.h>
/* Fiddly bit of faking and irq without hardware */
#define IIO_EVENTGEN_NO 10
/**
* struct iio_dummy_handle_irq - helper struct to simulate interrupt generation
* @work: irq_work used to run handlers from hardirq context
* @irq: fake irq line number to trigger an interrupt
*/
struct iio_dummy_handle_irq {
struct irq_work work;
int irq;
};
/**
* struct iio_dummy_evgen - evgen state
* @chip: irq chip we are faking
* @base: base of irq range
* @enabled: mask of which irqs are enabled
* @inuse: mask of which irqs are connected
* @regs: irq regs we are faking
* @lock: protect the evgen state
* @handler: helper for a 'hardware-like' interrupt simulation
* @inuse: mask of which irqs are connected
* @irq_sim: interrupt simulator
* @base: base of irq range
*/
struct iio_dummy_eventgen {
struct irq_chip chip;
int base;
bool enabled[IIO_EVENTGEN_NO];
bool inuse[IIO_EVENTGEN_NO];
struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
struct mutex lock;
struct iio_dummy_handle_irq handler;
bool inuse[IIO_EVENTGEN_NO];
struct irq_sim irq_sim;
int base;
};
/* We can only ever have one instance of this 'device' */
static struct iio_dummy_eventgen *iio_evgen;
static const char *iio_evgen_name = "iio_dummy_evgen";
static void iio_dummy_event_irqmask(struct irq_data *d)
{
struct irq_chip *chip = irq_data_get_irq_chip(d);
struct iio_dummy_eventgen *evgen =
container_of(chip, struct iio_dummy_eventgen, chip);
evgen->enabled[d->irq - evgen->base] = false;
}
static void iio_dummy_event_irqunmask(struct irq_data *d)
{
struct irq_chip *chip = irq_data_get_irq_chip(d);
struct iio_dummy_eventgen *evgen =
container_of(chip, struct iio_dummy_eventgen, chip);
evgen->enabled[d->irq - evgen->base] = true;
}
static void iio_dummy_work_handler(struct irq_work *work)
{
struct iio_dummy_handle_irq *irq_handler;
irq_handler = container_of(work, struct iio_dummy_handle_irq, work);
handle_simple_irq(irq_to_desc(irq_handler->irq));
}
static int iio_dummy_evgen_create(void)
{
int ret, i;
int ret;
iio_evgen = kzalloc(sizeof(*iio_evgen), GFP_KERNEL);
if (!iio_evgen)
return -ENOMEM;
iio_evgen->base = irq_alloc_descs(-1, 0, IIO_EVENTGEN_NO, 0);
if (iio_evgen->base < 0) {
ret = iio_evgen->base;
ret = irq_sim_init(&iio_evgen->irq_sim, IIO_EVENTGEN_NO);
if (ret) {
kfree(iio_evgen);
return ret;
}
iio_evgen->chip.name = iio_evgen_name;
iio_evgen->chip.irq_mask = &iio_dummy_event_irqmask;
iio_evgen->chip.irq_unmask = &iio_dummy_event_irqunmask;
for (i = 0; i < IIO_EVENTGEN_NO; i++) {
irq_set_chip(iio_evgen->base + i, &iio_evgen->chip);
irq_set_handler(iio_evgen->base + i, &handle_simple_irq);
irq_modify_status(iio_evgen->base + i,
IRQ_NOREQUEST | IRQ_NOAUTOEN,
IRQ_NOPROBE);
}
init_irq_work(&iio_evgen->handler.work, iio_dummy_work_handler);
iio_evgen->base = irq_sim_irqnum(&iio_evgen->irq_sim, 0);
mutex_init(&iio_evgen->lock);
return 0;
}
......@@ -132,15 +81,17 @@ int iio_dummy_evgen_get_irq(void)
return -ENODEV;
mutex_lock(&iio_evgen->lock);
for (i = 0; i < IIO_EVENTGEN_NO; i++)
for (i = 0; i < IIO_EVENTGEN_NO; i++) {
if (!iio_evgen->inuse[i]) {
ret = iio_evgen->base + i;
ret = irq_sim_irqnum(&iio_evgen->irq_sim, i);
iio_evgen->inuse[i] = true;
break;
}
}
mutex_unlock(&iio_evgen->lock);
if (i == IIO_EVENTGEN_NO)
return -ENOMEM;
return ret;
}
EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
......@@ -167,7 +118,7 @@ EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
static void iio_dummy_evgen_free(void)
{
irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
irq_sim_fini(&iio_evgen->irq_sim);
kfree(iio_evgen);
}
......@@ -192,9 +143,7 @@ static ssize_t iio_evgen_poke(struct device *dev,
iio_evgen->regs[this_attr->address].reg_id = this_attr->address;
iio_evgen->regs[this_attr->address].reg_data = event;
iio_evgen->handler.irq = iio_evgen->base + this_attr->address;
if (iio_evgen->enabled[this_attr->address])
irq_work_queue(&iio_evgen->handler.work);
irq_sim_fire(&iio_evgen->irq_sim, this_attr->address);
return len;
}
......
......@@ -111,14 +111,23 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int2 = 0x08,
.int2 = {
.addr = 0x22,
.mask = 0x08,
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -181,14 +190,23 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int2 = 0x08,
.int2 = {
.addr = 0x22,
.mask = 0x08,
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -246,14 +264,23 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = {
.mask = 0x80,
},
.drdy_irq = {
.addr = 0x22,
.mask_int2 = 0x08,
.int2 = {
.addr = 0x22,
.mask = 0x08,
},
/*
* The sensor has IHL (active low) and open
* drain settings, but only for INT1 and not
* for the DRDY line on INT2.
*/
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x23,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......
......@@ -29,8 +29,6 @@ enum st_lsm6dsx_hw_id {
#define ST_LSM6DSX_CHAN_SIZE 2
#define ST_LSM6DSX_SAMPLE_SIZE 6
#define ST_LSM6DSX_SAMPLE_DEPTH (ST_LSM6DSX_SAMPLE_SIZE / \
ST_LSM6DSX_CHAN_SIZE)
#if defined(CONFIG_SPI_MASTER)
#define ST_LSM6DSX_RX_MAX_LENGTH 256
......@@ -52,10 +50,38 @@ struct st_lsm6dsx_reg {
u8 mask;
};
/**
* struct st_lsm6dsx_fifo_ops - ST IMU FIFO settings
* @fifo_th: FIFO threshold register info (addr + mask).
* @fifo_diff: FIFO diff status register info (addr + mask).
* @th_wl: FIFO threshold word length.
*/
struct st_lsm6dsx_fifo_ops {
struct {
u8 addr;
u16 mask;
} fifo_th;
struct {
u8 addr;
u16 mask;
} fifo_diff;
u8 th_wl;
};
/**
* struct st_lsm6dsx_settings - ST IMU sensor settings
* @wai: Sensor WhoAmI default value.
* @max_fifo_size: Sensor max fifo length in FIFO words.
* @id: List of hw id supported by the driver configuration.
* @decimator: List of decimator register info (addr + mask).
* @fifo_ops: Sensor hw FIFO parameters.
*/
struct st_lsm6dsx_settings {
u8 wai;
u16 max_fifo_size;
enum st_lsm6dsx_hw_id id[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID];
struct st_lsm6dsx_fifo_ops fifo_ops;
};
enum st_lsm6dsx_sensor_id {
......@@ -79,7 +105,6 @@ enum st_lsm6dsx_fifo_mode {
* @watermark: Sensor watermark level.
* @sip: Number of samples in a given pattern.
* @decimator: FIFO decimation factor.
* @decimator_mask: Sensor mask for decimation register.
* @delta_ts: Delta time between two consecutive interrupts.
* @ts: Latest timestamp from the interrupt handler.
*/
......@@ -94,7 +119,6 @@ struct st_lsm6dsx_sensor {
u16 watermark;
u8 sip;
u8 decimator;
u8 decimator_mask;
s64 delta_ts;
s64 ts;
......
......@@ -35,10 +35,6 @@
#include "st_lsm6dsx.h"
#define ST_LSM6DSX_REG_FIFO_THL_ADDR 0x06
#define ST_LSM6DSX_REG_FIFO_THH_ADDR 0x07
#define ST_LSM6DSX_FIFO_TH_MASK GENMASK(11, 0)
#define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR 0x08
#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12
#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5)
#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12
......@@ -46,8 +42,6 @@
#define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a
#define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0)
#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
#define ST_LSM6DSX_REG_FIFO_DIFFL_ADDR 0x3a
#define ST_LSM6DSX_FIFO_DIFF_MASK GENMASK(11, 0)
#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
......@@ -110,8 +104,9 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
sensor = iio_priv(hw->iio_devs[i]);
const struct st_lsm6dsx_reg *dec_reg;
sensor = iio_priv(hw->iio_devs[i]);
/* update fifo decimators and sample in pattern */
if (hw->enable_mask & BIT(sensor->id)) {
sensor->sip = sensor->odr / min_odr;
......@@ -123,12 +118,13 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
data = 0;
}
err = st_lsm6dsx_write_with_mask(hw,
ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR,
sensor->decimator_mask, data);
if (err < 0)
return err;
dec_reg = &hw->settings->decimator[sensor->id];
if (dec_reg->addr) {
err = st_lsm6dsx_write_with_mask(hw, dec_reg->addr,
dec_reg->mask, data);
if (err < 0)
return err;
}
sip += sensor->sip;
}
hw->sip = sip;
......@@ -139,23 +135,10 @@ static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
enum st_lsm6dsx_fifo_mode fifo_mode)
{
u8 data;
int err;
switch (fifo_mode) {
case ST_LSM6DSX_FIFO_BYPASS:
data = fifo_mode;
break;
case ST_LSM6DSX_FIFO_CONT:
data = (ST_LSM6DSX_MAX_FIFO_ODR_VAL <<
__ffs(ST_LSM6DSX_FIFO_ODR_MASK)) | fifo_mode;
break;
default:
return -EINVAL;
}
err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
sizeof(data), &data);
err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_MODE_MASK, fifo_mode);
if (err < 0)
return err;
......@@ -164,9 +147,20 @@ int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
return 0;
}
static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor,
bool enable)
{
struct st_lsm6dsx_hw *hw = sensor->hw;
u8 data;
data = hw->enable_mask ? ST_LSM6DSX_MAX_FIFO_ODR_VAL : 0;
return st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
ST_LSM6DSX_FIFO_ODR_MASK, data);
}
int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
{
u16 fifo_watermark = ~0, cur_watermark, sip = 0;
u16 fifo_watermark = ~0, cur_watermark, sip = 0, fifo_th_mask;
struct st_lsm6dsx_hw *hw = sensor->hw;
struct st_lsm6dsx_sensor *cur_sensor;
__le16 wdata;
......@@ -191,20 +185,21 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
fifo_watermark = max_t(u16, fifo_watermark, sip);
fifo_watermark = (fifo_watermark / sip) * sip;
fifo_watermark = fifo_watermark * ST_LSM6DSX_SAMPLE_DEPTH;
fifo_watermark = fifo_watermark * hw->settings->fifo_ops.th_wl;
mutex_lock(&hw->lock);
err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_THH_ADDR,
err = hw->tf->read(hw->dev, hw->settings->fifo_ops.fifo_th.addr + 1,
sizeof(data), &data);
if (err < 0)
goto out;
fifo_watermark = ((data << 8) & ~ST_LSM6DSX_FIFO_TH_MASK) |
(fifo_watermark & ST_LSM6DSX_FIFO_TH_MASK);
fifo_th_mask = hw->settings->fifo_ops.fifo_th.mask;
fifo_watermark = ((data << 8) & ~fifo_th_mask) |
(fifo_watermark & fifo_th_mask);
wdata = cpu_to_le16(fifo_watermark);
err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_THL_ADDR,
err = hw->tf->write(hw->dev, hw->settings->fifo_ops.fifo_th.addr,
sizeof(wdata), (u8 *)&wdata);
out:
mutex_unlock(&hw->lock);
......@@ -223,6 +218,7 @@ int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
{
u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
u16 fifo_diff_mask = hw->settings->fifo_ops.fifo_diff.mask;
int err, acc_sip, gyro_sip, read_len, samples, offset;
struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
......@@ -230,7 +226,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
u8 buff[pattern_len];
__le16 fifo_status;
err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_DIFFL_ADDR,
err = hw->tf->read(hw->dev, hw->settings->fifo_ops.fifo_diff.addr,
sizeof(fifo_status), (u8 *)&fifo_status);
if (err < 0)
return err;
......@@ -238,7 +234,7 @@ static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
return 0;
fifo_len = (le16_to_cpu(fifo_status) & ST_LSM6DSX_FIFO_DIFF_MASK) *
fifo_len = (le16_to_cpu(fifo_status) & fifo_diff_mask) *
ST_LSM6DSX_CHAN_SIZE;
samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
fifo_len = (fifo_len / pattern_len) * pattern_len;
......@@ -345,6 +341,10 @@ static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
return err;
}
err = st_lsm6dsx_set_fifo_odr(sensor, enable);
if (err < 0)
return err;
err = st_lsm6dsx_update_decimators(hw);
if (err < 0)
return err;
......
......@@ -42,8 +42,6 @@
#include "st_lsm6dsx.h"
#define ST_LSM6DSX_REG_ACC_DEC_MASK GENMASK(2, 0)
#define ST_LSM6DSX_REG_GYRO_DEC_MASK GENMASK(5, 3)
#define ST_LSM6DSX_REG_INT1_ADDR 0x0d
#define ST_LSM6DSX_REG_INT2_ADDR 0x0e
#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3)
......@@ -156,25 +154,88 @@ static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
{
.wai = 0x69,
.max_fifo_size = 8192,
.max_fifo_size = 1365,
.id = {
[0] = ST_LSM6DS3_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
.mask = GENMASK(2, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
},
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(11, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
},
{
.wai = 0x69,
.max_fifo_size = 4096,
.max_fifo_size = 682,
.id = {
[0] = ST_LSM6DS3H_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
.mask = GENMASK(2, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
},
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(11, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
},
{
.wai = 0x6a,
.max_fifo_size = 4096,
.max_fifo_size = 682,
.id = {
[0] = ST_LSM6DSL_ID,
[1] = ST_LSM6DSM_ID,
},
.decimator = {
[ST_LSM6DSX_ID_ACC] = {
.addr = 0x08,
.mask = GENMASK(2, 0),
},
[ST_LSM6DSX_ID_GYRO] = {
.addr = 0x08,
.mask = GENMASK(5, 3),
},
},
.fifo_ops = {
.fifo_th = {
.addr = 0x06,
.mask = GENMASK(11, 0),
},
.fifo_diff = {
.addr = 0x3a,
.mask = GENMASK(11, 0),
},
.th_wl = 3, /* 1LSB = 2B */
},
},
};
......@@ -462,10 +523,9 @@ static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
{
struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
struct st_lsm6dsx_hw *hw = sensor->hw;
int err, max_fifo_len;
int err;
max_fifo_len = hw->settings->max_fifo_size / ST_LSM6DSX_SAMPLE_SIZE;
if (val < 1 || val > max_fifo_len)
if (val < 1 || val > hw->settings->max_fifo_size)
return -EINVAL;
err = st_lsm6dsx_update_watermark(sensor, val);
......@@ -646,7 +706,6 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
iio_dev->info = &st_lsm6dsx_acc_info;
sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK;
scnprintf(sensor->name, sizeof(sensor->name), "%s_accel",
name);
break;
......@@ -655,7 +714,6 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
iio_dev->info = &st_lsm6dsx_gyro_info;
sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK;
scnprintf(sensor->name, sizeof(sensor->name), "%s_gyro",
name);
break;
......
......@@ -24,6 +24,7 @@
#include <linux/err.h>
#include <linux/of.h>
#include <linux/delay.h>
#include <linux/util_macros.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
......@@ -86,6 +87,8 @@
struct vl6180_data {
struct i2c_client *client;
struct mutex lock;
unsigned int als_gain_milli;
unsigned int als_it_ms;
};
enum { VL6180_ALS, VL6180_RANGE, VL6180_PROX };
......@@ -275,19 +278,17 @@ static const struct iio_chan_spec vl6180_channels[] = {
};
/*
* Columns 3 & 4 represent the same value in decimal and hex notations.
* Kept in order to avoid the datatype conversion while reading the
* hardware_gain.
* Available Ambient Light Sensor gain settings, 1/1000th, and
* corresponding setting for the VL6180_ALS_GAIN register
*/
static const int vl6180_als_gain[8][4] = {
{ 1, 0, 70, VL6180_ALS_GAIN_1 },
{ 1, 250000, 69, VL6180_ALS_GAIN_1_25 },
{ 1, 670000, 68, VL6180_ALS_GAIN_1_67 },
{ 2, 500000, 67, VL6180_ALS_GAIN_2_5 },
{ 5, 0, 66, VL6180_ALS_GAIN_5 },
{ 10, 0, 65, VL6180_ALS_GAIN_10 },
{ 20, 0, 64, VL6180_ALS_GAIN_20 },
{ 40, 0, 71, VL6180_ALS_GAIN_40 }
static const int vl6180_als_gain_tab[8] = {
1000, 1250, 1670, 2500, 5000, 10000, 20000, 40000
};
static const u8 vl6180_als_gain_tab_bits[8] = {
VL6180_ALS_GAIN_1, VL6180_ALS_GAIN_1_25,
VL6180_ALS_GAIN_1_67, VL6180_ALS_GAIN_2_5,
VL6180_ALS_GAIN_5, VL6180_ALS_GAIN_10,
VL6180_ALS_GAIN_20, VL6180_ALS_GAIN_40
};
static int vl6180_read_raw(struct iio_dev *indio_dev,
......@@ -295,7 +296,7 @@ static int vl6180_read_raw(struct iio_dev *indio_dev,
int *val, int *val2, long mask)
{
struct vl6180_data *data = iio_priv(indio_dev);
int ret, i;
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
......@@ -306,19 +307,20 @@ static int vl6180_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
ret = vl6180_read_word(data->client, VL6180_ALS_IT);
if (ret < 0)
return ret;
*val = 0; /* 1 count = 1ms (0 = 1ms) */
*val2 = (ret + 1) * 1000; /* convert to seconds */
*val = data->als_it_ms;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_LIGHT:
*val = 0; /* one ALS count is 0.32 Lux */
*val2 = 320000;
break;
/* one ALS count is 0.32 Lux @ gain 1, IT 100 ms */
*val = 32000; /* 0.32 * 1000 * 100 */
*val2 = data->als_gain_milli * data->als_it_ms;
return IIO_VAL_FRACTIONAL;
case IIO_DISTANCE:
*val = 0; /* sensor reports mm, scale to meter */
*val2 = 1000;
......@@ -329,17 +331,11 @@ static int vl6180_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_HARDWAREGAIN:
ret = vl6180_read_byte(data->client, VL6180_ALS_GAIN);
if (ret < 0)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(vl6180_als_gain); i++) {
if (ret == vl6180_als_gain[i][2]) {
*val = vl6180_als_gain[i][0];
*val2 = vl6180_als_gain[i][1];
}
}
*val = data->als_gain_milli;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
......@@ -365,37 +361,53 @@ static int vl6180_hold(struct vl6180_data *data, bool hold)
static int vl6180_set_als_gain(struct vl6180_data *data, int val, int val2)
{
int i, ret;
for (i = 0; i < ARRAY_SIZE(vl6180_als_gain); i++) {
if (val == vl6180_als_gain[i][0] &&
val2 == vl6180_als_gain[i][1]) {
mutex_lock(&data->lock);
ret = vl6180_hold(data, true);
if (ret < 0)
goto fail;
ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
vl6180_als_gain[i][3]);
fail:
vl6180_hold(data, false);
mutex_unlock(&data->lock);
return ret;
}
}
int i, ret, gain;
return -EINVAL;
if (val < 1 || val > 40)
return -EINVAL;
gain = (val * 1000000 + val2) / 1000;
if (gain < 1 || gain > 40000)
return -EINVAL;
i = find_closest(gain, vl6180_als_gain_tab,
ARRAY_SIZE(vl6180_als_gain_tab));
mutex_lock(&data->lock);
ret = vl6180_hold(data, true);
if (ret < 0)
goto fail;
ret = vl6180_write_byte(data->client, VL6180_ALS_GAIN,
vl6180_als_gain_tab_bits[i]);
if (ret >= 0)
data->als_gain_milli = vl6180_als_gain_tab[i];
fail:
vl6180_hold(data, false);
mutex_unlock(&data->lock);
return ret;
}
static int vl6180_set_it(struct vl6180_data *data, int val2)
static int vl6180_set_it(struct vl6180_data *data, int val, int val2)
{
int ret;
int ret, it_ms;
it_ms = (val2 + 500) / 1000; /* round to ms */
if (val != 0 || it_ms < 1 || it_ms > 512)
return -EINVAL;
mutex_lock(&data->lock);
ret = vl6180_hold(data, true);
if (ret < 0)
goto fail;
ret = vl6180_write_word(data->client, VL6180_ALS_IT,
(val2 - 500) / 1000); /* write value in ms */
ret = vl6180_write_word(data->client, VL6180_ALS_IT, it_ms - 1);
if (ret >= 0)
data->als_it_ms = it_ms;
fail:
vl6180_hold(data, false);
mutex_unlock(&data->lock);
......@@ -411,10 +423,8 @@ static int vl6180_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_INT_TIME:
if (val != 0 || val2 < 500 || val2 >= 512500)
return -EINVAL;
return vl6180_set_it(data, val, val2);
return vl6180_set_it(data, val2);
case IIO_CHAN_INFO_HARDWAREGAIN:
if (chan->type != IIO_LIGHT)
return -EINVAL;
......@@ -467,11 +477,13 @@ static int vl6180_init(struct vl6180_data *data)
return ret;
/* ALS integration time: 100ms */
data->als_it_ms = 100;
ret = vl6180_write_word(client, VL6180_ALS_IT, VL6180_ALS_IT_100);
if (ret < 0)
return ret;
/* ALS gain: 1 */
data->als_gain_milli = 1000;
ret = vl6180_write_byte(client, VL6180_ALS_GAIN, VL6180_ALS_GAIN_1);
if (ret < 0)
return ret;
......
......@@ -317,7 +317,14 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
},
.drdy_irq = {
/* drdy line is routed drdy pin */
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x07,
},
},
.sim = {
.addr = 0x22,
.value = BIT(2),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -359,9 +366,14 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = {
.mask = 0x10,
},
.drdy_irq = {
.addr = 0x62,
.mask_int1 = 0x01,
.addr_stat_drdy = 0x67,
.int1 = {
.addr = 0x62,
.mask = 0x01,
},
.stat_drdy = {
.addr = 0x67,
.mask = 0x07,
},
},
.multi_read_bit = false,
.bootime = 2,
......
......@@ -280,14 +280,28 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.mask = 0x04,
},
.drdy_irq = {
.addr = 0x22,
.mask_int1 = 0x04,
.mask_int2 = 0x20,
.int1 = {
.addr = 0x22,
.mask = 0x04,
.addr_od = 0x22,
.mask_od = 0x40,
},
.int2 = {
.addr = 0x22,
.mask = 0x20,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x03,
},
},
.sim = {
.addr = 0x20,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -335,8 +349,9 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.addr = 0x20,
.mask = 0x04,
},
.drdy_irq = {
.addr = 0,
.sim = {
.addr = 0x20,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -388,14 +403,22 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.mask = 0x04,
},
.drdy_irq = {
.addr = 0x23,
.mask_int1 = 0x01,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x23,
.mask = 0x01,
.addr_od = 0x22,
.mask_od = 0x40,
},
.addr_ihl = 0x22,
.mask_ihl = 0x80,
.addr_od = 0x22,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x03,
},
},
.sim = {
.addr = 0x20,
.value = BIT(0),
},
.multi_read_bit = true,
.bootime = 2,
......@@ -449,14 +472,22 @@ static const struct st_sensor_settings st_press_sensors_settings[] = {
.mask = 0x02,
},
.drdy_irq = {
.addr = 0x12,
.mask_int1 = 0x04,
.mask_int2 = 0x00,
.int1 = {
.addr = 0x12,
.mask = 0x04,
.addr_od = 0x12,
.mask_od = 0x40,
},
.addr_ihl = 0x12,
.mask_ihl = 0x80,
.addr_od = 0x12,
.mask_od = 0x40,
.addr_stat_drdy = ST_SENSORS_DEFAULT_STAT_ADDR,
.stat_drdy = {
.addr = ST_SENSORS_DEFAULT_STAT_ADDR,
.mask = 0x03,
},
},
.sim = {
.addr = 0x10,
.value = BIT(0),
},
.multi_read_bit = false,
.bootime = 2,
......@@ -605,7 +636,8 @@ int st_press_common_probe(struct iio_dev *indio_dev)
press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz;
/* Some devices don't support a data ready pin. */
if (!pdata && press_data->sensor_settings->drdy_irq.addr)
if (!pdata && (press_data->sensor_settings->drdy_irq.int1.addr ||
press_data->sensor_settings->drdy_irq.int2.addr))
pdata = (struct st_sensors_platform_data *)&default_press_pdata;
err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
......
......@@ -32,6 +32,16 @@ config LIDAR_LITE_V2
To compile this driver as a module, choose M here: the
module will be called pulsedlight-lite-v2
config RFD77402
tristate "RFD77402 ToF sensor"
depends on I2C
help
Say Y to build a driver for the RFD77420 Time-of-Flight (distance)
sensor module with I2C interface.
To compile this driver as a module, choose M here: the
module will be called rfd77402.
config SRF04
tristate "Devantech SRF04 ultrasonic ranger sensor"
depends on GPIOLIB
......
......@@ -5,6 +5,7 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
obj-$(CONFIG_RFD77402) += rfd77402.o
obj-$(CONFIG_SRF04) += srf04.o
obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9500) += sx9500.o
/*
* rfd77402.c - Support for RF Digital RFD77402 Time-of-Flight (distance) sensor
*
* Copyright 2017 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
*
* This file is subject to the terms and conditions of version 2 of
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* 7-bit I2C slave address 0x4c
*
* TODO: interrupt
* https://media.digikey.com/pdf/Data%20Sheets/RF%20Digital%20PDFs/RFD77402.pdf
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
#define RFD77402_DRV_NAME "rfd77402"
#define RFD77402_ICSR 0x00 /* Interrupt Control Status Register */
#define RFD77402_ICSR_INT_MODE BIT(2)
#define RFD77402_ICSR_INT_POL BIT(3)
#define RFD77402_ICSR_RESULT BIT(4)
#define RFD77402_ICSR_M2H_MSG BIT(5)
#define RFD77402_ICSR_H2M_MSG BIT(6)
#define RFD77402_ICSR_RESET BIT(7)
#define RFD77402_CMD_R 0x04
#define RFD77402_CMD_SINGLE 0x01
#define RFD77402_CMD_STANDBY 0x10
#define RFD77402_CMD_MCPU_OFF 0x11
#define RFD77402_CMD_MCPU_ON 0x12
#define RFD77402_CMD_RESET BIT(6)
#define RFD77402_CMD_VALID BIT(7)
#define RFD77402_STATUS_R 0x06
#define RFD77402_STATUS_PM_MASK GENMASK(4, 0)
#define RFD77402_STATUS_STANDBY 0x00
#define RFD77402_STATUS_MCPU_OFF 0x10
#define RFD77402_STATUS_MCPU_ON 0x18
#define RFD77402_RESULT_R 0x08
#define RFD77402_RESULT_DIST_MASK GENMASK(12, 2)
#define RFD77402_RESULT_ERR_MASK GENMASK(14, 13)
#define RFD77402_RESULT_VALID BIT(15)
#define RFD77402_PMU_CFG 0x14
#define RFD77402_PMU_MCPU_INIT BIT(9)
#define RFD77402_I2C_INIT_CFG 0x1c
#define RFD77402_I2C_ADDR_INCR BIT(0)
#define RFD77402_I2C_DATA_INCR BIT(2)
#define RFD77402_I2C_HOST_DEBUG BIT(5)
#define RFD77402_I2C_MCPU_DEBUG BIT(6)
#define RFD77402_CMD_CFGR_A 0x0c
#define RFD77402_CMD_CFGR_B 0x0e
#define RFD77402_HFCFG_0 0x20
#define RFD77402_HFCFG_1 0x22
#define RFD77402_HFCFG_2 0x24
#define RFD77402_HFCFG_3 0x26
#define RFD77402_MOD_CHIP_ID 0x28
/* magic configuration values from datasheet */
static const struct {
u8 reg;
u16 val;
} rf77402_tof_config[] = {
{RFD77402_CMD_CFGR_A, 0xe100},
{RFD77402_CMD_CFGR_B, 0x10ff},
{RFD77402_HFCFG_0, 0x07d0},
{RFD77402_HFCFG_1, 0x5008},
{RFD77402_HFCFG_2, 0xa041},
{RFD77402_HFCFG_3, 0x45d4},
};
struct rfd77402_data {
struct i2c_client *client;
/* Serialize reads from the sensor */
struct mutex lock;
};
static const struct iio_chan_spec rfd77402_channels[] = {
{
.type = IIO_DISTANCE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE),
},
};
static int rfd77402_set_state(struct rfd77402_data *data, u8 state, u16 check)
{
int ret;
ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
state | RFD77402_CMD_VALID);
if (ret < 0)
return ret;
usleep_range(10000, 20000);
ret = i2c_smbus_read_word_data(data->client, RFD77402_STATUS_R);
if (ret < 0)
return ret;
if ((ret & RFD77402_STATUS_PM_MASK) != check)
return -ENODEV;
return 0;
}
static int rfd77402_measure(struct rfd77402_data *data)
{
int ret;
int tries = 10;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(data->client, RFD77402_CMD_R,
RFD77402_CMD_SINGLE |
RFD77402_CMD_VALID);
if (ret < 0)
goto err;
while (tries-- > 0) {
ret = i2c_smbus_read_byte_data(data->client, RFD77402_ICSR);
if (ret < 0)
goto err;
if (ret & RFD77402_ICSR_RESULT)
break;
msleep(20);
}
if (tries < 0) {
ret = -ETIMEDOUT;
goto err;
}
ret = i2c_smbus_read_word_data(data->client, RFD77402_RESULT_R);
if (ret < 0)
goto err;
if ((ret & RFD77402_RESULT_ERR_MASK) ||
!(ret & RFD77402_RESULT_VALID)) {
ret = -EIO;
goto err;
}
return (ret & RFD77402_RESULT_DIST_MASK) >> 2;
err:
rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
return ret;
}
static int rfd77402_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct rfd77402_data *data = iio_priv(indio_dev);
int ret;
switch (mask) {
case IIO_CHAN_INFO_RAW:
mutex_lock(&data->lock);
ret = rfd77402_measure(data);
mutex_unlock(&data->lock);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
/* 1 LSB is 1 mm */
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
}
}
static const struct iio_info rfd77402_info = {
.read_raw = rfd77402_read_raw,
};
static int rfd77402_init(struct rfd77402_data *data)
{
int ret, i;
ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
if (ret < 0)
return ret;
/* configure INT pad as push-pull, active low */
ret = i2c_smbus_write_byte_data(data->client, RFD77402_ICSR,
RFD77402_ICSR_INT_MODE);
if (ret < 0)
return ret;
/* I2C configuration */
ret = i2c_smbus_write_word_data(data->client, RFD77402_I2C_INIT_CFG,
RFD77402_I2C_ADDR_INCR |
RFD77402_I2C_DATA_INCR |
RFD77402_I2C_HOST_DEBUG |
RFD77402_I2C_MCPU_DEBUG);
if (ret < 0)
return ret;
/* set initialization */
ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0500);
if (ret < 0)
return ret;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_OFF,
RFD77402_STATUS_MCPU_OFF);
if (ret < 0)
return ret;
/* set initialization */
ret = i2c_smbus_write_word_data(data->client, RFD77402_PMU_CFG, 0x0600);
if (ret < 0)
return ret;
ret = rfd77402_set_state(data, RFD77402_CMD_MCPU_ON,
RFD77402_STATUS_MCPU_ON);
if (ret < 0)
return ret;
for (i = 0; i < ARRAY_SIZE(rf77402_tof_config); i++) {
ret = i2c_smbus_write_word_data(data->client,
rf77402_tof_config[i].reg,
rf77402_tof_config[i].val);
if (ret < 0)
return ret;
}
ret = rfd77402_set_state(data, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
return ret;
}
static int rfd77402_powerdown(struct rfd77402_data *data)
{
return rfd77402_set_state(data, RFD77402_CMD_STANDBY,
RFD77402_STATUS_STANDBY);
}
static int rfd77402_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rfd77402_data *data;
struct iio_dev *indio_dev;
int ret;
ret = i2c_smbus_read_word_data(client, RFD77402_MOD_CHIP_ID);
if (ret < 0)
return ret;
if (ret != 0xad01 && ret != 0xad02) /* known chip ids */
return -ENODEV;
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->client = client;
mutex_init(&data->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &rfd77402_info;
indio_dev->channels = rfd77402_channels;
indio_dev->num_channels = ARRAY_SIZE(rfd77402_channels);
indio_dev->name = RFD77402_DRV_NAME;
indio_dev->modes = INDIO_DIRECT_MODE;
ret = rfd77402_init(data);
if (ret < 0)
return ret;
ret = iio_device_register(indio_dev);
if (ret)
goto err_powerdown;
return 0;
err_powerdown:
rfd77402_powerdown(data);
return ret;
}
static int rfd77402_remove(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
iio_device_unregister(indio_dev);
rfd77402_powerdown(iio_priv(indio_dev));
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rfd77402_suspend(struct device *dev)
{
struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return rfd77402_powerdown(data);
}
static int rfd77402_resume(struct device *dev)
{
struct rfd77402_data *data = iio_priv(i2c_get_clientdata(
to_i2c_client(dev)));
return rfd77402_init(data);
}
#endif
static SIMPLE_DEV_PM_OPS(rfd77402_pm_ops, rfd77402_suspend, rfd77402_resume);
static const struct i2c_device_id rfd77402_id[] = {
{ "rfd77402", 0},
{ }
};
MODULE_DEVICE_TABLE(i2c, rfd77402_id);
static struct i2c_driver rfd77402_driver = {
.driver = {
.name = RFD77402_DRV_NAME,
.pm = &rfd77402_pm_ops,
},
.probe = rfd77402_probe,
.remove = rfd77402_remove,
.id_table = rfd77402_id,
};
module_i2c_driver(rfd77402_driver);
MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
MODULE_DESCRIPTION("RFD77402 Time-of-Flight sensor driver");
MODULE_LICENSE("GPL");
......@@ -162,6 +162,7 @@ struct ad7192_state {
u32 scale_avail[8][2];
u8 gpocon;
u8 devid;
struct mutex lock; /* protect sensor state */
struct ad_sigma_delta sd;
};
......@@ -461,10 +462,10 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_VOLTAGE:
mutex_lock(&indio_dev->mlock);
mutex_lock(&st->lock);
*val = st->scale_avail[AD7192_CONF_GAIN(st->conf)][0];
*val2 = st->scale_avail[AD7192_CONF_GAIN(st->conf)][1];
mutex_unlock(&indio_dev->mlock);
mutex_unlock(&st->lock);
return IIO_VAL_INT_PLUS_NANO;
case IIO_TEMP:
*val = 0;
......@@ -508,6 +509,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_SCALE:
ret = -EINVAL;
mutex_lock(&st->lock);
for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++)
if (val2 == st->scale_avail[i][1]) {
ret = 0;
......@@ -521,6 +523,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
ad7192_calibrate_all(st);
break;
}
mutex_unlock(&st->lock);
break;
case IIO_CHAN_INFO_SAMP_FREQ:
if (!val) {
......@@ -630,6 +633,8 @@ static int ad7192_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
mutex_init(&st->lock);
st->avdd = devm_regulator_get(&spi->dev, "avdd");
if (IS_ERR(st->avdd))
return PTR_ERR(st->avdd);
......
This diff is collapsed.
......@@ -80,13 +80,11 @@
* @us: actual spi_device
* @tx: transmit buffer
* @rx: receive buffer
* @buf_lock: mutex to protect tx and rx
* @lock: protect sensor data
* @buf_lock: mutex to protect tx, rx and write frequency
**/
struct ade7753_state {
struct spi_device *us;
struct mutex buf_lock;
struct mutex lock; /* protect sensor data */
u8 tx[ADE7753_MAX_TX] ____cacheline_aligned;
u8 rx[ADE7753_MAX_RX];
};
......@@ -109,6 +107,19 @@ static int ade7753_spi_write_reg_8(struct device *dev,
return ret;
}
static int __ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ade7753_state *st = iio_priv(indio_dev);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
return spi_write(st->us, st->tx, 3);
}
static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
u16 value)
{
......@@ -117,10 +128,7 @@ static int ade7753_spi_write_reg_16(struct device *dev, u8 reg_address,
struct ade7753_state *st = iio_priv(indio_dev);
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7753_WRITE_REG(reg_address);
st->tx[1] = (value >> 8) & 0xFF;
st->tx[2] = value & 0xFF;
ret = spi_write(st->us, st->tx, 3);
ret = __ade7753_spi_write_reg_16(dev, reg_address, value);
mutex_unlock(&st->buf_lock);
return ret;
......@@ -485,7 +493,7 @@ static ssize_t ade7753_write_frequency(struct device *dev,
if (!val)
return -EINVAL;
mutex_lock(&st->lock);
mutex_lock(&st->buf_lock);
t = 27900 / val;
if (t > 0)
......@@ -503,10 +511,10 @@ static ssize_t ade7753_write_frequency(struct device *dev,
reg &= ~(3 << 11);
reg |= t << 11;
ret = ade7753_spi_write_reg_16(dev, ADE7753_MODE, reg);
ret = __ade7753_spi_write_reg_16(dev, ADE7753_MODE, reg);
out:
mutex_unlock(&st->lock);
mutex_unlock(&st->buf_lock);
return ret ? ret : len;
}
......@@ -581,7 +589,6 @@ static int ade7753_probe(struct spi_device *spi)
st = iio_priv(indio_dev);
st->us = spi;
mutex_init(&st->buf_lock);
mutex_init(&st->lock);
indio_dev->name = spi->dev.driver->name;
indio_dev->dev.parent = &spi->dev;
......
......@@ -231,6 +231,7 @@ struct hid_sensor_common {
unsigned usage_id;
atomic_t data_ready;
atomic_t user_requested_state;
atomic_t runtime_pm_enable;
int poll_interval;
int raw_hystersis;
int latency_ms;
......
......@@ -130,29 +130,40 @@ struct st_sensor_das {
u8 mask;
};
/**
* struct st_sensor_int_drdy - ST sensor device drdy line parameters
* @addr: address of INT drdy register.
* @mask: mask to enable drdy line.
* @addr_od: address to enable/disable Open Drain on the INT line.
* @mask_od: mask to enable/disable Open Drain on the INT line.
*/
struct st_sensor_int_drdy {
u8 addr;
u8 mask;
u8 addr_od;
u8 mask_od;
};
/**
* struct st_sensor_data_ready_irq - ST sensor device data-ready interrupt
* @addr: address of the register.
* @mask_int1: mask to enable/disable IRQ on INT1 pin.
* @mask_int2: mask to enable/disable IRQ on INT2 pin.
* struct int1 - data-ready configuration register for INT1 pin.
* struct int2 - data-ready configuration register for INT2 pin.
* @addr_ihl: address to enable/disable active low on the INT lines.
* @mask_ihl: mask to enable/disable active low on the INT lines.
* @addr_od: address to enable/disable Open Drain on the INT lines.
* @mask_od: mask to enable/disable Open Drain on the INT lines.
* @addr_stat_drdy: address to read status of DRDY (data ready) interrupt
* struct stat_drdy - status register of DRDY (data ready) interrupt.
* struct ig1 - represents the Interrupt Generator 1 of sensors.
* @en_addr: address of the enable ig1 register.
* @en_mask: mask to write the on/off value for enable.
*/
struct st_sensor_data_ready_irq {
u8 addr;
u8 mask_int1;
u8 mask_int2;
struct st_sensor_int_drdy int1;
struct st_sensor_int_drdy int2;
u8 addr_ihl;
u8 mask_ihl;
u8 addr_od;
u8 mask_od;
u8 addr_stat_drdy;
struct {
u8 addr;
u8 mask;
} stat_drdy;
struct {
u8 en_addr;
u8 en_mask;
......
......@@ -365,7 +365,6 @@ unsigned int iio_get_time_res(const struct iio_dev *indio_dev);
#define INDIO_MAX_RAW_ELEMENTS 4
struct iio_trigger; /* forward declaration */
struct iio_dev;
/**
* struct iio_info - constant information about device
......
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