diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-08-12 12:43:41 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2015-08-12 12:43:41 -0700 |
commit | 1c46ae0af6df0bbde66c5e868563be57f18a27b4 (patch) | |
tree | b5dbe61f8d05f9c67aff0080ea87945342d58c7d /drivers/iio | |
parent | a73e99cb67e7438e5ab0c524ae63a8a27616c839 (diff) | |
parent | 41d903c00051d8f31c98a8136edbac67e6f8688f (diff) | |
download | linux-1c46ae0af6df0bbde66c5e868563be57f18a27b4.tar.bz2 |
Merge tag 'iio-for-4.3b-2' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Second set of new device support, features and cleanup for the 4.3 cycle.
Take 2 also includes a fix set that was too late for the 4.2 cycle.
As we had a lot of tools and docs work in this set, I have broken those
out into their own categories in this description.
Fixes from the pull request '4th set of IIO fixes for the 4.2 cycle'.
* Poll functions for both event chardev and the buffer one were returning
negative error codes (via a positive value).
* A recent change to lsiio adding some error handling that was wrong and
stopped the tool working.
* bmg160 was missing some dependencies in Kconfig
* berlin2-adc had a misshandled register (wrote a value rather than a bitmap)
New device support
* TI opt3001 light sensor
* TXC PA12 ALS and proximity sensor.
* mcp3301 ADC support (in mcp320x driver)
* ST lsm303agr accelerometer and magnetometer drivers (plus some st-sensors
common support to allow different WHOAMI register addresses, devices with
fixed scale and allow interrupt equiped magnetometers).
* ADIS16305, ADIS16367, ADIS16445IMUs (in the adis16400 driver)
* ADIS16266 gyro (in the adis16260 driver)
* ADIS16137 gyro (in the adis16136 driver)
New functionality
* mmc35240 DT bindings.
* Inverse unit conversion macros to aid handing of values written to sysfs
attributes.
Core cleanup
* Forward declaration of struct iio_trigger to avoid a compile warning.
Driver cleanup / fixes
* mxs-lradc
- Clarify which parts are supported.
- Fix spelling erorrs.
- Missing/extra includes
- reorder includes
- add datasheet name listings for all usable channels (to allow them
to be bound by name from consumer drivers)
* acpi-als - add some function prefixes as per general iio style.
* bmc150_magn - replace a magic value with the existing define.
* vf610 - determine possible sample frequencies taking into account the
electrical characteristics (defining a minimum sample time)
* dht11
- whitespace
- additional docs
- avoid mulitple assignments in one line
- Use the new funciton ktime_get_resolution_ns to cleanup a nasty trick
previously used for timing.
* Fix all drivers that consider 0 a valid IRQ for historical reasons.
* Export I2C module alias info where previously missing (to allow autoprobing)
* Export OF module alias info where previously missing.
* mmc35240 - switch some variables into arrays to improve readability.
* mlx90614 - define some magic numbers for readability.
* bmc150_magn
- expand area locked by a mutex to cover all the use of the
data->buffer.
- use descriptive naming for a mask instead of a magic value.
* berin2-adc
- pass up an error code rather that a generic error
- constify the iio_chan_spec
- some other little tidy ups.
* stk8312
- fix a dependency on triggered buffers in kconfig
- add a check for invalid attribute values
- improve error handling by returning error codes where possible and
return immediately where relevant
- rework macro defs to use GENMASK etc
- change some variable types to reduce unnecessary casting
- clean up code style
- drop a local buffer copy for bulk reads and use the one in data->buffer
instead.
* adis16400 - the adis16448 gyroscope scale was wrong.
* adis16480 - some more wrong scales for various parts.
* adis16300 - has an undocumented product id and serial number registers so
use them.
* iio_simple_dummy - fix some wrong code indentation.
* bmc150-accel - use the chip ID to detect the chip present rather than
verifying the expected part was there. This was in response to a wrong
ACPI entry on the WinBook TW100.
* mma8452
- fix _get_hp_filter_index
- drop a double include
- pass up an error code rather than rewriting it
- range check input values to attribute writes
- register defs tidy up using GENMASK and reordering them to be easier to
follow.
- various coding style cleanups
- put the Kconfig entry in the write place (alphabetically).
Tools related
* Tools cleanup - drop an explicity NULL comparison, some unnecessary braces,
use the ARRAY_SIZE macro, send error messages to stderr instead of dropping
them in the middle of normal output.
* Fix tools to allow that scale and offset attributes are optional.
* More tools fixes including allowing true 32bit data (previously an overflow
prevented more than 31bits)
* Drop a stray header guard that ended up in a c file.
* Make calc_digits static as it isn't exported or in the header.
* Set ci_array pointer to NULL after free as a protection against non safe
usage of the tools core code. Also convert a double pointer to a single
one as the extra level of indirection was unnecessary.
Docs
* DocBook introduction by Daniel Baluta. Glad we are beginning to
draw together some more introductory docs to suplement the various
tools / examples.
* Drop bytes_per_datum sysfs attribute docs as it no longer exists.
* A whole load of missing / fixing of kernel-doc for the core of IIO.
* Document the trigger name sysfs attribute in the ABI docs.
* Minor typos in the ABI docs related to power down modes.
Diffstat (limited to 'drivers/iio')
47 files changed, 2193 insertions, 415 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 00e7bcbdbe24..a59047d7657e 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -86,18 +86,6 @@ config KXSD9 To compile this driver as a module, choose M here: the module will be called kxsd9. -config MMA8452 - tristate "Freescale MMA8452Q Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the Freescale MMA8452Q 3-axis - accelerometer. - - To compile this driver as a module, choose M here: the module - will be called mma8452. - config KXCJK1013 tristate "Kionix 3-Axis Accelerometer Driver" depends on I2C @@ -111,6 +99,18 @@ config KXCJK1013 To compile this driver as a module, choose M here: the module will be called kxcjk-1013. +config MMA8452 + tristate "Freescale MMA8452Q Accelerometer Driver" + depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for the Freescale MMA8452Q 3-axis + accelerometer. + + To compile this driver as a module, choose M here: the module + will be called mma8452. + config MMA9551_CORE tristate @@ -140,6 +140,8 @@ config MMA9553 config STK8312 tristate "Sensortek STK8312 3-Axis Accelerometer Driver" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to get support for the Sensortek STK8312 3-axis accelerometer. diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index e84e2a1646df..0104cdef8709 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -151,6 +151,7 @@ struct bmc150_scale_info { }; struct bmc150_accel_chip_info { + const char *name; u8 chip_id; const struct iio_chan_spec *channels; int num_channels; @@ -345,63 +346,6 @@ static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, return 0; } -static int bmc150_accel_chip_init(struct bmc150_accel_data *data) -{ - int ret; - - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); - if (ret < 0) { - dev_err(&data->client->dev, "Error: Reading chip id\n"); - return ret; - } - - dev_dbg(&data->client->dev, "Chip Id %x\n", ret); - if (ret != data->chip_info->chip_id) { - dev_err(&data->client->dev, "Invalid chip %x\n", ret); - return -ENODEV; - } - - ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); - if (ret < 0) - return ret; - - /* Set Bandwidth */ - ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); - if (ret < 0) - return ret; - - /* Set Default Range */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_PMU_RANGE, - BMC150_ACCEL_DEF_RANGE_4G); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); - return ret; - } - - data->range = BMC150_ACCEL_DEF_RANGE_4G; - - /* Set default slope duration and thresholds */ - data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; - data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; - ret = bmc150_accel_update_slope(data); - if (ret < 0) - return ret; - - /* Set default as latched interrupts */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - return 0; -} - static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, int *val2) { @@ -1119,6 +1063,7 @@ enum { static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { [bmc150] = { + .name = "BMC150A", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1128,6 +1073,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bmi055] = { + .name = "BMI055A", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1137,6 +1083,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma255] = { + .name = "BMA0255", .chip_id = 0xFA, .channels = bmc150_accel_channels, .num_channels = ARRAY_SIZE(bmc150_accel_channels), @@ -1146,6 +1093,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {76590, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma250e] = { + .name = "BMA250E", .chip_id = 0xF9, .channels = bma250e_accel_channels, .num_channels = ARRAY_SIZE(bma250e_accel_channels), @@ -1155,6 +1103,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {306457, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma222e] = { + .name = "BMA222E", .chip_id = 0xF8, .channels = bma222e_accel_channels, .num_channels = ARRAY_SIZE(bma222e_accel_channels), @@ -1164,6 +1113,7 @@ static const struct bmc150_accel_chip_info bmc150_accel_chip_info_tbl[] = { {1225831, BMC150_ACCEL_DEF_RANGE_16G} }, }, [bma280] = { + .name = "BMA0280", .chip_id = 0xFB, .channels = bma280_accel_channels, .num_channels = ARRAY_SIZE(bma280_accel_channels), @@ -1410,20 +1360,6 @@ static irqreturn_t bmc150_accel_irq_handler(int irq, void *private) return IRQ_NONE; } -static const char *bmc150_accel_match_acpi_device(struct device *dev, int *data) -{ - const struct acpi_device_id *id; - - id = acpi_match_device(dev->driver->acpi_match_table, dev); - - if (!id) - return NULL; - - *data = (int)id->driver_data; - - return dev_name(dev); -} - static int bmc150_accel_gpio_probe(struct i2c_client *client, struct bmc150_accel_data *data) { @@ -1618,6 +1554,70 @@ static const struct iio_buffer_setup_ops bmc150_accel_buffer_ops = { .postdisable = bmc150_accel_buffer_postdisable, }; +static int bmc150_accel_chip_init(struct bmc150_accel_data *data) +{ + int ret, i; + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_CHIP_ID); + if (ret < 0) { + dev_err(&data->client->dev, "Error: Reading chip id\n"); + return ret; + } + + dev_dbg(&data->client->dev, "Chip Id %x\n", ret); + for (i = 0; i < ARRAY_SIZE(bmc150_accel_chip_info_tbl); i++) { + if (bmc150_accel_chip_info_tbl[i].chip_id == ret) { + data->chip_info = &bmc150_accel_chip_info_tbl[i]; + break; + } + } + + if (!data->chip_info) { + dev_err(&data->client->dev, "Unsupported chip %x\n", ret); + return -ENODEV; + } + + ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); + if (ret < 0) + return ret; + + /* Set Bandwidth */ + ret = bmc150_accel_set_bw(data, BMC150_ACCEL_DEF_BW, 0); + if (ret < 0) + return ret; + + /* Set Default Range */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_PMU_RANGE, + BMC150_ACCEL_DEF_RANGE_4G); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_pmu_range\n"); + return ret; + } + + data->range = BMC150_ACCEL_DEF_RANGE_4G; + + /* Set default slope duration and thresholds */ + data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; + data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = bmc150_accel_update_slope(data); + if (ret < 0) + return ret; + + /* Set default as latched interrupts */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_INT | + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, + "Error writing reg_int_rst_latch\n"); + return ret; + } + + return 0; +} + static int bmc150_accel_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1625,7 +1625,6 @@ static int bmc150_accel_probe(struct i2c_client *client, struct iio_dev *indio_dev; int ret; const char *name = NULL; - int chip_id = 0; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -1635,15 +1634,8 @@ static int bmc150_accel_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; - if (id) { + if (id) name = id->name; - chip_id = id->driver_data; - } - - if (ACPI_HANDLE(&client->dev)) - name = bmc150_accel_match_acpi_device(&client->dev, &chip_id); - - data->chip_info = &bmc150_accel_chip_info_tbl[chip_id]; ret = bmc150_accel_chip_init(data); if (ret < 0) @@ -1654,7 +1646,7 @@ static int bmc150_accel_probe(struct i2c_client *client, indio_dev->dev.parent = &client->dev; indio_dev->channels = data->chip_info->channels; indio_dev->num_channels = data->chip_info->num_channels; - indio_dev->name = name; + indio_dev->name = name ? name : data->chip_info->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmc150_accel_info; @@ -1670,7 +1662,7 @@ static int bmc150_accel_probe(struct i2c_client *client, if (client->irq < 0) client->irq = bmc150_accel_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq( &client->dev, client->irq, bmc150_accel_irq_handler, diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 8128579bff79..3292bc0c1d0e 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1240,7 +1240,7 @@ static int kxcjk1013_probe(struct i2c_client *client, if (client->irq < 0) client->irq = kxcjk1013_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, kxcjk1013_data_rdy_trig_poll, kxcjk1013_event_handler, diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index 13ea1ea23328..b921d84c1be6 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -16,7 +16,6 @@ #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/iio/trigger_consumer.h> #include <linux/iio/buffer.h> #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> @@ -24,54 +23,51 @@ #include <linux/iio/events.h> #include <linux/delay.h> -#define MMA8452_STATUS 0x00 -#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ -#define MMA8452_OUT_Y 0x03 -#define MMA8452_OUT_Z 0x05 -#define MMA8452_INT_SRC 0x0c -#define MMA8452_WHO_AM_I 0x0d -#define MMA8452_DATA_CFG 0x0e -#define MMA8452_HP_FILTER_CUTOFF 0x0f -#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK (BIT(0) | BIT(1)) -#define MMA8452_TRANSIENT_CFG 0x1d -#define MMA8452_TRANSIENT_CFG_ELE BIT(4) -#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) -#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) -#define MMA8452_TRANSIENT_SRC 0x1e -#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) -#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) -#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) -#define MMA8452_TRANSIENT_THS 0x1f -#define MMA8452_TRANSIENT_THS_MASK 0x7f -#define MMA8452_TRANSIENT_COUNT 0x20 -#define MMA8452_OFF_X 0x2f -#define MMA8452_OFF_Y 0x30 -#define MMA8452_OFF_Z 0x31 -#define MMA8452_CTRL_REG1 0x2a -#define MMA8452_CTRL_REG2 0x2b -#define MMA8452_CTRL_REG2_RST BIT(6) -#define MMA8452_CTRL_REG4 0x2d -#define MMA8452_CTRL_REG5 0x2e - -#define MMA8452_MAX_REG 0x31 - -#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) - -#define MMA8452_CTRL_DR_MASK (BIT(5) | BIT(4) | BIT(3)) -#define MMA8452_CTRL_DR_SHIFT 3 -#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ -#define MMA8452_CTRL_ACTIVE BIT(0) - -#define MMA8452_DATA_CFG_FS_MASK (BIT(1) | BIT(0)) -#define MMA8452_DATA_CFG_FS_2G 0 -#define MMA8452_DATA_CFG_FS_4G 1 -#define MMA8452_DATA_CFG_FS_8G 2 -#define MMA8452_DATA_CFG_HPF_MASK BIT(4) - -#define MMA8452_INT_DRDY BIT(0) -#define MMA8452_INT_TRANS BIT(5) - -#define MMA8452_DEVICE_ID 0x2a +#define MMA8452_STATUS 0x00 +#define MMA8452_STATUS_DRDY (BIT(2) | BIT(1) | BIT(0)) +#define MMA8452_OUT_X 0x01 /* MSB first, 12-bit */ +#define MMA8452_OUT_Y 0x03 +#define MMA8452_OUT_Z 0x05 +#define MMA8452_INT_SRC 0x0c +#define MMA8452_WHO_AM_I 0x0d +#define MMA8452_DATA_CFG 0x0e +#define MMA8452_DATA_CFG_FS_MASK GENMASK(1, 0) +#define MMA8452_DATA_CFG_FS_2G 0 +#define MMA8452_DATA_CFG_FS_4G 1 +#define MMA8452_DATA_CFG_FS_8G 2 +#define MMA8452_DATA_CFG_HPF_MASK BIT(4) +#define MMA8452_HP_FILTER_CUTOFF 0x0f +#define MMA8452_HP_FILTER_CUTOFF_SEL_MASK GENMASK(1, 0) +#define MMA8452_TRANSIENT_CFG 0x1d +#define MMA8452_TRANSIENT_CFG_HPF_BYP BIT(0) +#define MMA8452_TRANSIENT_CFG_CHAN(chan) BIT(chan + 1) +#define MMA8452_TRANSIENT_CFG_ELE BIT(4) +#define MMA8452_TRANSIENT_SRC 0x1e +#define MMA8452_TRANSIENT_SRC_XTRANSE BIT(1) +#define MMA8452_TRANSIENT_SRC_YTRANSE BIT(3) +#define MMA8452_TRANSIENT_SRC_ZTRANSE BIT(5) +#define MMA8452_TRANSIENT_THS 0x1f +#define MMA8452_TRANSIENT_THS_MASK GENMASK(6, 0) +#define MMA8452_TRANSIENT_COUNT 0x20 +#define MMA8452_CTRL_REG1 0x2a +#define MMA8452_CTRL_ACTIVE BIT(0) +#define MMA8452_CTRL_DR_MASK GENMASK(5, 3) +#define MMA8452_CTRL_DR_SHIFT 3 +#define MMA8452_CTRL_DR_DEFAULT 0x4 /* 50 Hz sample frequency */ +#define MMA8452_CTRL_REG2 0x2b +#define MMA8452_CTRL_REG2_RST BIT(6) +#define MMA8452_CTRL_REG4 0x2d +#define MMA8452_CTRL_REG5 0x2e +#define MMA8452_OFF_X 0x2f +#define MMA8452_OFF_Y 0x30 +#define MMA8452_OFF_Z 0x31 + +#define MMA8452_MAX_REG 0x31 + +#define MMA8452_INT_DRDY BIT(0) +#define MMA8452_INT_TRANS BIT(5) + +#define MMA8452_DEVICE_ID 0x2a struct mma8452_data { struct i2c_client *client; @@ -91,30 +87,34 @@ static int mma8452_drdy(struct mma8452_data *data) return ret; if ((ret & MMA8452_STATUS_DRDY) == MMA8452_STATUS_DRDY) return 0; + msleep(20); } dev_err(&data->client->dev, "data not ready\n"); + return -EIO; } static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) { int ret = mma8452_drdy(data); + if (ret < 0) return ret; - return i2c_smbus_read_i2c_block_data(data->client, - MMA8452_OUT_X, 3 * sizeof(__be16), (u8 *) buf); + + return i2c_smbus_read_i2c_block_data(data->client, MMA8452_OUT_X, + 3 * sizeof(__be16), (u8 *)buf); } -static ssize_t mma8452_show_int_plus_micros(char *buf, - const int (*vals)[2], int n) +static ssize_t mma8452_show_int_plus_micros(char *buf, const int (*vals)[2], + int n) { size_t len = 0; while (n-- > 0) - len += scnprintf(buf + len, PAGE_SIZE - len, - "%d.%06d ", vals[n][0], vals[n][1]); + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06d ", + vals[n][0], vals[n][1]); /* replace trailing space by newline */ buf[len - 1] = '\n'; @@ -123,7 +123,7 @@ static ssize_t mma8452_show_int_plus_micros(char *buf, } static int mma8452_get_int_plus_micros_index(const int (*vals)[2], int n, - int val, int val2) + int val, int val2) { while (n-- > 0) if (val == vals[n][0] && val2 == vals[n][1]) @@ -147,7 +147,7 @@ static const int mma8452_samp_freq[8][2] = { * Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048 * The userspace interface uses m/s^2 and we declare micro units * So scale factor is given by: - * g * N * 1000000 / 2048 for N = 2, 4, 8 and g=9.80665 + * g * N * 1000000 / 2048 for N = 2, 4, 8 and g = 9.80665 */ static const int mma8452_scales[3][2] = { {0, 9577}, {0, 19154}, {0, 38307} @@ -178,17 +178,19 @@ static const int mma8452_hp_filter_cutoff[8][4][2] = { }; static ssize_t mma8452_show_samp_freq_avail(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { return mma8452_show_int_plus_micros(buf, mma8452_samp_freq, - ARRAY_SIZE(mma8452_samp_freq)); + ARRAY_SIZE(mma8452_samp_freq)); } static ssize_t mma8452_show_scale_avail(struct device *dev, - struct device_attribute *attr, char *buf) + struct device_attribute *attr, + char *buf) { return mma8452_show_int_plus_micros(buf, mma8452_scales, - ARRAY_SIZE(mma8452_scales)); + ARRAY_SIZE(mma8452_scales)); } static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, @@ -205,22 +207,23 @@ static ssize_t mma8452_show_hp_cutoff_avail(struct device *dev, static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(mma8452_show_samp_freq_avail); static IIO_DEVICE_ATTR(in_accel_scale_available, S_IRUGO, - mma8452_show_scale_avail, NULL, 0); + mma8452_show_scale_avail, NULL, 0); static IIO_DEVICE_ATTR(in_accel_filter_high_pass_3db_frequency_available, - S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); + S_IRUGO, mma8452_show_hp_cutoff_avail, NULL, 0); static int mma8452_get_samp_freq_index(struct mma8452_data *data, - int val, int val2) + int val, int val2) { return mma8452_get_int_plus_micros_index(mma8452_samp_freq, - ARRAY_SIZE(mma8452_samp_freq), val, val2); + ARRAY_SIZE(mma8452_samp_freq), + val, val2); } -static int mma8452_get_scale_index(struct mma8452_data *data, - int val, int val2) +static int mma8452_get_scale_index(struct mma8452_data *data, int val, int val2) { return mma8452_get_int_plus_micros_index(mma8452_scales, - ARRAY_SIZE(mma8452_scales), val, val2); + ARRAY_SIZE(mma8452_scales), + val, val2); } static int mma8452_get_hp_filter_index(struct mma8452_data *data, @@ -229,7 +232,7 @@ static int mma8452_get_hp_filter_index(struct mma8452_data *data, int i = mma8452_get_odr_index(data); return mma8452_get_int_plus_micros_index(mma8452_hp_filter_cutoff[i], - ARRAY_SIZE(mma8452_scales[0]), val, val2); + ARRAY_SIZE(mma8452_hp_filter_cutoff[0]), val, val2); } static int mma8452_read_hp_filter(struct mma8452_data *data, int *hz, int *uHz) @@ -266,25 +269,31 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) return ret; - *val = sign_extend32( - be16_to_cpu(buffer[chan->scan_index]) >> 4, 11); + + *val = sign_extend32(be16_to_cpu(buffer[chan->scan_index]) >> 4, + 11); + return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: i = data->data_cfg & MMA8452_DATA_CFG_FS_MASK; *val = mma8452_scales[i][0]; *val2 = mma8452_scales[i][1]; + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_odr_index(data); *val = mma8452_samp_freq[i][0]; *val2 = mma8452_samp_freq[i][1]; + return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_CALIBBIAS: - ret = i2c_smbus_read_byte_data(data->client, MMA8452_OFF_X + - chan->scan_index); + ret = i2c_smbus_read_byte_data(data->client, + MMA8452_OFF_X + chan->scan_index); if (ret < 0) return ret; + *val = sign_extend32(ret, 7); + return IIO_VAL_INT; case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (data->data_cfg & MMA8452_DATA_CFG_HPF_MASK) { @@ -295,21 +304,23 @@ static int mma8452_read_raw(struct iio_dev *indio_dev, *val = 0; *val2 = 0; } + return IIO_VAL_INT_PLUS_MICRO; } + return -EINVAL; } static int mma8452_standby(struct mma8452_data *data) { return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, - data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); + data->ctrl_reg1 & ~MMA8452_CTRL_ACTIVE); } static int mma8452_active(struct mma8452_data *data) { return i2c_smbus_write_byte_data(data->client, MMA8452_CTRL_REG1, - data->ctrl_reg1); + data->ctrl_reg1); } static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) @@ -334,6 +345,7 @@ static int mma8452_change_config(struct mma8452_data *data, u8 reg, u8 val) ret = 0; fail: mutex_unlock(&data->lock); + return ret; } @@ -344,12 +356,13 @@ static int mma8452_set_hp_filter_frequency(struct mma8452_data *data, i = mma8452_get_hp_filter_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; reg = i2c_smbus_read_byte_data(data->client, MMA8452_HP_FILTER_CUTOFF); if (reg < 0) return reg; + reg &= ~MMA8452_HP_FILTER_CUTOFF_SEL_MASK; reg |= i; @@ -370,25 +383,30 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SAMP_FREQ: i = mma8452_get_samp_freq_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; data->ctrl_reg1 &= ~MMA8452_CTRL_DR_MASK; data->ctrl_reg1 |= i << MMA8452_CTRL_DR_SHIFT; + return mma8452_change_config(data, MMA8452_CTRL_REG1, - data->ctrl_reg1); + data->ctrl_reg1); case IIO_CHAN_INFO_SCALE: i = mma8452_get_scale_index(data, val, val2); if (i < 0) - return -EINVAL; + return i; + data->data_cfg &= ~MMA8452_DATA_CFG_FS_MASK; data->data_cfg |= i; + return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); case IIO_CHAN_INFO_CALIBBIAS: if (val < -128 || val > 127) return -EINVAL; - return mma8452_change_config(data, MMA8452_OFF_X + - chan->scan_index, val); + + return mma8452_change_config(data, + MMA8452_OFF_X + chan->scan_index, + val); case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY: if (val == 0 && val2 == 0) { @@ -399,8 +417,9 @@ static int mma8452_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return mma8452_change_config(data, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); default: return -EINVAL; @@ -425,6 +444,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, return ret; *val = ret & MMA8452_TRANSIENT_THS_MASK; + return IIO_VAL_INT; case IIO_EV_INFO_PERIOD: @@ -437,6 +457,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, mma8452_get_odr_index(data)]; *val = us / USEC_PER_SEC; *val2 = us % USEC_PER_SEC; + return IIO_VAL_INT_PLUS_MICRO; case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: @@ -453,6 +474,7 @@ static int mma8452_read_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return IIO_VAL_INT_PLUS_MICRO; default: @@ -472,19 +494,22 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: - return mma8452_change_config(data, MMA8452_TRANSIENT_THS, - val & MMA8452_TRANSIENT_THS_MASK); + if (val < 0 || val > MMA8452_TRANSIENT_THS_MASK) + return -EINVAL; + + return mma8452_change_config(data, MMA8452_TRANSIENT_THS, val); case IIO_EV_INFO_PERIOD: steps = (val * USEC_PER_SEC + val2) / mma8452_transient_time_step_us[ mma8452_get_odr_index(data)]; - if (steps > 0xff) + if (steps < 0 || steps > 0xff) return -EINVAL; return mma8452_change_config(data, MMA8452_TRANSIENT_COUNT, steps); + case IIO_EV_INFO_HIGH_PASS_FILTER_3DB: reg = i2c_smbus_read_byte_data(data->client, MMA8452_TRANSIENT_CFG); @@ -499,6 +524,7 @@ static int mma8452_write_thresh(struct iio_dev *indio_dev, if (ret < 0) return ret; } + return mma8452_change_config(data, MMA8452_TRANSIENT_CFG, reg); default: @@ -608,15 +634,16 @@ static irqreturn_t mma8452_trigger_handler(int irq, void *p) u8 buffer[16]; /* 3 16-bit channels + padding + ts */ int ret; - ret = mma8452_read(data, (__be16 *) buffer); + ret = mma8452_read(data, (__be16 *)buffer); if (ret < 0) goto done; iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns()); + iio_get_time_ns()); done: iio_trigger_notify_done(indio_dev->trig); + return IRQ_HANDLED; } @@ -674,10 +701,10 @@ static struct attribute_group mma8452_event_attribute_group = { .modified = 1, \ .channel2 = IIO_MOD_##axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ - BIT(IIO_CHAN_INFO_CALIBBIAS), \ + BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ - BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY), \ .scan_index = idx, \ .scan_type = { \ .sign = 's', \ @@ -780,6 +807,7 @@ static int mma8452_trigger_setup(struct iio_dev *indio_dev) return ret; indio_dev->trig = trig; + return 0; } @@ -849,7 +877,7 @@ static int mma8452_probe(struct i2c_client *client, data->data_cfg = MMA8452_DATA_CFG_FS_2G; ret = i2c_smbus_write_byte_data(client, MMA8452_DATA_CFG, - data->data_cfg); + data->data_cfg); if (ret < 0) return ret; @@ -891,14 +919,14 @@ static int mma8452_probe(struct i2c_client *client, } data->ctrl_reg1 = MMA8452_CTRL_ACTIVE | - (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); + (MMA8452_CTRL_DR_DEFAULT << MMA8452_CTRL_DR_SHIFT); ret = i2c_smbus_write_byte_data(client, MMA8452_CTRL_REG1, data->ctrl_reg1); if (ret < 0) goto trigger_cleanup; ret = iio_triggered_buffer_setup(indio_dev, NULL, - mma8452_trigger_handler, NULL); + mma8452_trigger_handler, NULL); if (ret < 0) goto trigger_cleanup; @@ -968,6 +996,7 @@ static const struct of_device_id mma8452_dt_ids[] = { { .compatible = "fsl,mma8452" }, { } }; +MODULE_DEVICE_TABLE(of, mma8452_dt_ids); static struct i2c_driver mma8452_driver = { .driver = { diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index a605280637e9..771858cb67a1 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1149,7 +1149,7 @@ static int mma9553_probe(struct i2c_client *client, if (client->irq < 0) client->irq = mma9553_gpio_probe(client); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, mma9553_irq_handler, mma9553_event_handler, diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index aa1001931d0c..468f21fa2950 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -26,6 +26,7 @@ #define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel" #define LSM303DLM_ACCEL_DEV_NAME "lsm303dlm_accel" #define LSM330_ACCEL_DEV_NAME "lsm330_accel" +#define LSM303AGR_ACCEL_DEV_NAME "lsm303agr_accel" /** * struct st_sensors_platform_data - default accel platform data diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 4002e6410444..ff30f8806880 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -226,12 +226,14 @@ static const struct iio_chan_spec st_accel_16bit_channels[] = { static const struct st_sensor_settings st_accel_sensors_settings[] = { { .wai = ST_ACCEL_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3DH_ACCEL_DEV_NAME, [1] = LSM303DLHC_ACCEL_DEV_NAME, [2] = LSM330D_ACCEL_DEV_NAME, [3] = LSM330DL_ACCEL_DEV_NAME, [4] = LSM330DLC_ACCEL_DEV_NAME, + [5] = LSM303AGR_ACCEL_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_accel_12bit_channels, .odr = { @@ -297,6 +299,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DLH_ACCEL_DEV_NAME, [1] = LSM303DL_ACCEL_DEV_NAME, @@ -359,6 +362,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_3_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM330_ACCEL_DEV_NAME, }, @@ -437,6 +441,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_4_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3LV02DL_ACCEL_DEV_NAME, }, @@ -494,6 +499,7 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { }, { .wai = ST_ACCEL_5_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS331DL_ACCEL_DEV_NAME, }, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index a2f1c20319eb..8b9cc84fd44f 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -68,6 +68,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lsm330-accel", .data = LSM330_ACCEL_DEV_NAME, }, + { + .compatible = "st,lsm303agr-accel", + .data = LSM303AGR_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -116,6 +120,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/accel/st_accel_spi.c b/drivers/iio/accel/st_accel_spi.c index 12ec29389e4b..54b61a3961c3 100644 --- a/drivers/iio/accel/st_accel_spi.c +++ b/drivers/iio/accel/st_accel_spi.c @@ -57,6 +57,7 @@ static const struct spi_device_id st_accel_id_table[] = { { LSM303DL_ACCEL_DEV_NAME }, { LSM303DLM_ACCEL_DEV_NAME }, { LSM330_ACCEL_DEV_NAME }, + { LSM303AGR_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_accel_id_table); diff --git a/drivers/iio/accel/stk8312.c b/drivers/iio/accel/stk8312.c index c2bd1444d6da..c764af284c94 100644 --- a/drivers/iio/accel/stk8312.c +++ b/drivers/iio/accel/stk8312.c @@ -37,16 +37,16 @@ #define STK8312_REG_OTPDATA 0x3E #define STK8312_REG_OTPCTRL 0x3F -#define STK8312_MODE_ACTIVE 0x01 +#define STK8312_MODE_ACTIVE BIT(0) #define STK8312_MODE_STANDBY 0x00 -#define STK8312_DREADY_BIT 0x10 -#define STK8312_INT_MODE 0xC0 -#define STK8312_RNG_MASK 0xC0 -#define STK8312_SR_MASK 0x07 -#define STK8312_SR_400HZ_IDX 0 +#define STK8312_MODE_INT_AH_PP 0xC0 /* active-high, push-pull */ +#define STK8312_DREADY_BIT BIT(4) +#define STK8312_RNG_6G 1 #define STK8312_RNG_SHIFT 6 -#define STK8312_READ_RETRIES 16 -#define STK8312_ALL_CHANNEL_MASK 7 +#define STK8312_RNG_MASK GENMASK(7, 6) +#define STK8312_SR_MASK GENMASK(2, 0) +#define STK8312_SR_400HZ_IDX 0 +#define STK8312_ALL_CHANNEL_MASK GENMASK(2, 0) #define STK8312_ALL_CHANNEL_SIZE 3 #define STK8312_DRIVER_NAME "stk8312" @@ -69,8 +69,8 @@ static const int stk8312_scale_table[][2] = { }; static const struct { - u16 val; - u32 val2; + int val; + int val2; } stk8312_samp_freq_table[] = { {400, 0}, {200, 0}, {100, 0}, {50, 0}, {25, 0}, {12, 500000}, {6, 250000}, {3, 125000} @@ -103,7 +103,7 @@ static const struct iio_chan_spec stk8312_channels[] = { struct stk8312_data { struct i2c_client *client; struct mutex lock; - int range; + u8 range; u8 sample_rate_idx; u8 mode; struct iio_trigger *dready_trig; @@ -144,22 +144,25 @@ static int stk8312_otp_init(struct stk8312_data *data) if (ret < 0) goto exit_err; count--; - } while (!(ret & 0x80) && count > 0); + } while (!(ret & BIT(7)) && count > 0); - if (count == 0) + if (count == 0) { + ret = -ETIMEDOUT; goto exit_err; + } ret = i2c_smbus_read_byte_data(client, STK8312_REG_OTPDATA); + if (ret == 0) + ret = -EINVAL; if (ret < 0) goto exit_err; - ret = i2c_smbus_write_byte_data(data->client, - STK8312_REG_AFECTRL, ret); + ret = i2c_smbus_write_byte_data(data->client, STK8312_REG_AFECTRL, ret); if (ret < 0) goto exit_err; msleep(150); - return ret; + return 0; exit_err: dev_err(&client->dev, "failed to initialize sensor\n"); @@ -203,8 +206,11 @@ static int stk8312_set_interrupts(struct stk8312_data *data, u8 int_mask) return ret; ret = i2c_smbus_write_byte_data(client, STK8312_REG_INTSU, int_mask); - if (ret < 0) + if (ret < 0) { dev_err(&client->dev, "failed to set interrupts\n"); + stk8312_set_mode(data, mode); + return ret; + } return stk8312_set_mode(data, mode); } @@ -228,7 +234,7 @@ static int stk8312_data_rdy_trigger_set_state(struct iio_trigger *trig, data->dready_trigger_on = state; - return ret; + return 0; } static const struct iio_trigger_ops stk8312_trigger_ops = { @@ -236,7 +242,7 @@ static const struct iio_trigger_ops stk8312_trigger_ops = { .owner = THIS_MODULE, }; -static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) +static int stk8312_set_sample_rate(struct stk8312_data *data, u8 rate) { int ret; u8 masked_reg; @@ -253,20 +259,24 @@ static int stk8312_set_sample_rate(struct stk8312_data *data, int rate) return ret; ret = i2c_smbus_read_byte_data(client, STK8312_REG_SR); - if (ret < 0) { - dev_err(&client->dev, "failed to set sampling rate\n"); - return ret; - } + if (ret < 0) + goto err_activate; masked_reg = (ret & (~STK8312_SR_MASK)) | rate; ret = i2c_smbus_write_byte_data(client, STK8312_REG_SR, masked_reg); if (ret < 0) - dev_err(&client->dev, "failed to set sampling rate\n"); - else - data->sample_rate_idx = rate; + goto err_activate; + + data->sample_rate_idx = rate; return stk8312_set_mode(data, mode); + +err_activate: + dev_err(&client->dev, "failed to set sampling rate\n"); + stk8312_set_mode(data, mode); + + return ret; } static int stk8312_set_range(struct stk8312_data *data, u8 range) @@ -288,21 +298,25 @@ static int stk8312_set_range(struct stk8312_data *data, u8 range) return ret; ret = i2c_smbus_read_byte_data(client, STK8312_REG_STH); - if (ret < 0) { - dev_err(&client->dev, "failed to change sensor range\n"); - return ret; - } + if (ret < 0) + goto err_activate; masked_reg = ret & (~STK8312_RNG_MASK); masked_reg |= range << STK8312_RNG_SHIFT; ret = i2c_smbus_write_byte_data(client, STK8312_REG_STH, masked_reg); if (ret < 0) - dev_err(&client->dev, "failed to change sensor range\n"); - else - data->range = range; + goto err_activate; + + data->range = range; return stk8312_set_mode(data, mode); + +err_activate: + dev_err(&client->dev, "failed to change sensor range\n"); + stk8312_set_mode(data, mode); + + return ret; } static int stk8312_read_accel(struct stk8312_data *data, u8 address) @@ -335,18 +349,21 @@ static int stk8312_read_raw(struct iio_dev *indio_dev, ret = stk8312_set_mode(data, data->mode | STK8312_MODE_ACTIVE); if (ret < 0) { mutex_unlock(&data->lock); - return -EINVAL; + return ret; } ret = stk8312_read_accel(data, chan->address); if (ret < 0) { stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); - return -EINVAL; + return ret; } *val = sign_extend32(ret, 7); - stk8312_set_mode(data, data->mode & (~STK8312_MODE_ACTIVE)); + ret = stk8312_set_mode(data, + data->mode & (~STK8312_MODE_ACTIVE)); mutex_unlock(&data->lock); + if (ret < 0) + return ret; return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = stk8312_scale_table[data->range - 1][0]; @@ -418,7 +435,6 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct stk8312_data *data = iio_priv(indio_dev); int bit, ret, i = 0; - u8 buffer[STK8312_ALL_CHANNEL_SIZE]; mutex_lock(&data->lock); /* @@ -429,18 +445,15 @@ static irqreturn_t stk8312_trigger_handler(int irq, void *p) ret = i2c_smbus_read_i2c_block_data(data->client, STK8312_REG_XOUT, STK8312_ALL_CHANNEL_SIZE, - buffer); + data->buffer); if (ret < STK8312_ALL_CHANNEL_SIZE) { dev_err(&data->client->dev, "register read failed\n"); mutex_unlock(&data->lock); goto err; } - data->buffer[0] = buffer[0]; - data->buffer[1] = buffer[1]; - data->buffer[2] = buffer[2]; } else { for_each_set_bit(bit, indio_dev->active_scan_mask, - indio_dev->masklength) { + indio_dev->masklength) { ret = stk8312_read_accel(data, bit); if (ret < 0) { mutex_unlock(&data->lock); @@ -547,11 +560,12 @@ static int stk8312_probe(struct i2c_client *client, return ret; } data->sample_rate_idx = STK8312_SR_400HZ_IDX; - ret = stk8312_set_range(data, 1); + ret = stk8312_set_range(data, STK8312_RNG_6G); if (ret < 0) return ret; - ret = stk8312_set_mode(data, STK8312_INT_MODE | STK8312_MODE_ACTIVE); + ret = stk8312_set_mode(data, + STK8312_MODE_INT_AH_PP | STK8312_MODE_ACTIVE); if (ret < 0) return ret; @@ -606,7 +620,7 @@ static int stk8312_probe(struct i2c_client *client, goto err_buffer_cleanup; } - return ret; + return 0; err_buffer_cleanup: iio_triggered_buffer_cleanup(indio_dev); @@ -662,6 +676,7 @@ static const struct i2c_device_id stk8312_i2c_id[] = { {"STK8312", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk8312_i2c_id); static const struct acpi_device_id stk8312_acpi_id[] = { {"STK8312", 0}, @@ -672,7 +687,7 @@ MODULE_DEVICE_TABLE(acpi, stk8312_acpi_id); static struct i2c_driver stk8312_driver = { .driver = { - .name = "stk8312", + .name = STK8312_DRIVER_NAME, .pm = STK8312_PM_OPS, .acpi_match_table = ACPI_PTR(stk8312_acpi_id), }, diff --git a/drivers/iio/accel/stk8ba50.c b/drivers/iio/accel/stk8ba50.c index 16cee637109b..80f77d8704b5 100644 --- a/drivers/iio/accel/stk8ba50.c +++ b/drivers/iio/accel/stk8ba50.c @@ -572,6 +572,7 @@ static const struct i2c_device_id stk8ba50_i2c_id[] = { {"stk8ba50", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk8ba50_i2c_id); static const struct acpi_device_id stk8ba50_acpi_id[] = { {"STK8BA50", 0}, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 233d47b7dea8..50c103d75af9 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -228,8 +228,8 @@ config MCP320X depends on SPI help Say yes here to build support for Microchip Technology's - MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or - MCP3208 analog to digital converter. + MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, + MCP3208 or MCP3301 analog to digital converter. This driver can also be built as a module. If so, the module will be called mcp320x. diff --git a/drivers/iio/adc/berlin2-adc.c b/drivers/iio/adc/berlin2-adc.c index aecc9ad995ad..4946d9bf1764 100644 --- a/drivers/iio/adc/berlin2-adc.c +++ b/drivers/iio/adc/berlin2-adc.c @@ -26,7 +26,7 @@ #define BERLIN2_SM_CTRL 0x14 #define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1) #define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2) -#define BERLIN2_SM_CTRL_ADC_SEL(x) (BIT(x) << 5) /* 0-15 */ +#define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */ #define BERLIN2_SM_CTRL_ADC_SEL_MASK (0xf << 5) #define BERLIN2_SM_CTRL_ADC_POWER BIT(9) #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10) @@ -53,14 +53,14 @@ #define BERLIN2_SM_ADC_MASK 0x3ff #define BERLIN2_SM_ADC_STATUS 0x1c #define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */ -#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK 0xf +#define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0) #define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */ -#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK (0xf << 16) +#define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16) #define BERLIN2_SM_TSEN_STATUS 0x24 #define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0) #define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1) #define BERLIN2_SM_TSEN_DATA 0x28 -#define BERLIN2_SM_TSEN_MASK 0xfff +#define BERLIN2_SM_TSEN_MASK GENMASK(9, 0) #define BERLIN2_SM_TSEN_CTRL 0x74 #define BERLIN2_SM_TSEN_CTRL_START BIT(8) #define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */ @@ -86,7 +86,7 @@ struct berlin2_adc_priv { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ } -static struct iio_chan_spec berlin2_adc_channels[] = { +static const struct iio_chan_spec berlin2_adc_channels[] = { BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */ BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */ BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */ @@ -103,7 +103,6 @@ static struct iio_chan_spec berlin2_adc_channels[] = { BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */ IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */ }; -#define BERLIN2_N_CHANNELS ARRAY_SIZE(berlin2_adc_channels) static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) { @@ -221,7 +220,7 @@ static int berlin2_adc_read_raw(struct iio_dev *indio_dev, return temp; if (temp > 2047) - temp = -(4096 - temp); + temp -= 4096; /* Convert to milli Celsius */ *val = ((temp * 100000) / 264 - 270000); @@ -286,8 +285,7 @@ static int berlin2_adc_probe(struct platform_device *pdev) int irq, tsen_irq; int ret; - indio_dev = devm_iio_device_alloc(&pdev->dev, - sizeof(struct berlin2_adc_priv)); + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); if (!indio_dev) return -ENOMEM; @@ -301,11 +299,11 @@ static int berlin2_adc_probe(struct platform_device *pdev) irq = platform_get_irq_byname(pdev, "adc"); if (irq < 0) - return -ENODEV; + return irq; tsen_irq = platform_get_irq_byname(pdev, "tsen"); if (tsen_irq < 0) - return -ENODEV; + return tsen_irq; ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0, pdev->dev.driver->name, indio_dev); @@ -325,8 +323,8 @@ static int berlin2_adc_probe(struct platform_device *pdev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &berlin2_adc_info; - indio_dev->num_channels = BERLIN2_N_CHANNELS; indio_dev->channels = berlin2_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels); /* Power up the ADC */ regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index d819823f7257..b19e4f9d16e0 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -25,6 +25,7 @@ * http://ww1.microchip.com/downloads/en/DeviceDoc/21290D.pdf mcp3201 * 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 * * 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 @@ -47,6 +48,7 @@ enum { mcp3202, mcp3204, mcp3208, + mcp3301, }; struct mcp320x_chip_info { @@ -76,6 +78,7 @@ static int mcp320x_channel_to_tx_data(int device_index, switch (device_index) { case mcp3001: case mcp3201: + case mcp3301: return 0; case mcp3002: case mcp3202: @@ -102,7 +105,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, adc->tx_buf = mcp320x_channel_to_tx_data(device_index, channel, differential); - if (device_index != mcp3001 && device_index != mcp3201) { + if (device_index != mcp3001 && device_index != mcp3201 && device_index != mcp3301) { ret = spi_sync(adc->spi, &adc->msg); if (ret < 0) return ret; @@ -125,6 +128,8 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, case mcp3204: case mcp3208: return (adc->rx_buf[0] << 4 | adc->rx_buf[1] >> 4); + case mcp3301: + return sign_extend32((adc->rx_buf[0] & 0x1f) << 8 | adc->rx_buf[1], 12); default: return -EINVAL; } @@ -274,6 +279,11 @@ static const struct mcp320x_chip_info mcp320x_chip_infos[] = { .num_channels = ARRAY_SIZE(mcp3208_channels), .resolution = 12 }, + [mcp3301] = { + .channels = mcp3201_channels, + .num_channels = ARRAY_SIZE(mcp3201_channels), + .resolution = 13 + }, }; static int mcp320x_probe(struct spi_device *spi) @@ -369,6 +379,9 @@ static const struct of_device_id mcp320x_dt_ids[] = { .compatible = "mcp3208", .data = &mcp320x_chip_infos[mcp3208], }, { + .compatible = "mcp3301", + .data = &mcp320x_chip_infos[mcp3301], + }, { } }; MODULE_DEVICE_TABLE(of, mcp320x_dt_ids); @@ -383,6 +396,7 @@ static const struct spi_device_id mcp320x_id[] = { { "mcp3202", mcp3202 }, { "mcp3204", mcp3204 }, { "mcp3208", mcp3208 }, + { "mcp3301", mcp3301 }, { } }; MODULE_DEVICE_TABLE(spi, mcp320x_id); diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 819632bf1fda..6bf4c20eb231 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -68,6 +68,9 @@ #define VF610_ADC_CLK_DIV8 0x60 #define VF610_ADC_CLK_MASK 0x60 #define VF610_ADC_ADLSMP_LONG 0x10 +#define VF610_ADC_ADSTS_SHORT 0x100 +#define VF610_ADC_ADSTS_NORMAL 0x200 +#define VF610_ADC_ADSTS_LONG 0x300 #define VF610_ADC_ADSTS_MASK 0x300 #define VF610_ADC_ADLPC_EN 0x80 #define VF610_ADC_ADHSC_EN 0x400 @@ -98,6 +101,8 @@ #define VF610_ADC_CALF 0x2 #define VF610_ADC_TIMEOUT msecs_to_jiffies(100) +#define DEFAULT_SAMPLE_TIME 1000 + enum clk_sel { VF610_ADCIOC_BUSCLK_SET, VF610_ADCIOC_ALTCLK_SET, @@ -124,6 +129,17 @@ enum conversion_mode_sel { VF610_ADC_CONV_LOW_POWER, }; +enum lst_adder_sel { + VF610_ADCK_CYCLES_3, + VF610_ADCK_CYCLES_5, + VF610_ADCK_CYCLES_7, + VF610_ADCK_CYCLES_9, + VF610_ADCK_CYCLES_13, + VF610_ADCK_CYCLES_17, + VF610_ADCK_CYCLES_21, + VF610_ADCK_CYCLES_25, +}; + struct vf610_adc_feature { enum clk_sel clk_sel; enum vol_ref vol_ref; @@ -132,6 +148,8 @@ struct vf610_adc_feature { int clk_div; int sample_rate; int res_mode; + u32 lst_adder_index; + u32 default_sample_time; bool calibration; bool ovwren; @@ -155,11 +173,13 @@ struct vf610_adc { }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; +static const u32 vf610_lst_adder[] = { 3, 5, 7, 9, 13, 17, 21, 25 }; static inline void vf610_adc_calculate_rates(struct vf610_adc *info) { struct vf610_adc_feature *adc_feature = &info->adc_feature; unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk); + u32 adck_period, lst_addr_min; int divisor, i; adck_rate = info->max_adck_rate[adc_feature->conv_mode]; @@ -174,6 +194,19 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) } /* + * Determine the long sample time adder value to be used based + * on the default minimum sample time provided. + */ + adck_period = NSEC_PER_SEC / adck_rate; + lst_addr_min = adc_feature->default_sample_time / adck_period; + for (i = 0; i < ARRAY_SIZE(vf610_lst_adder); i++) { + if (vf610_lst_adder[i] > lst_addr_min) { + adc_feature->lst_adder_index = i; + break; + } + } + + /* * Calculate ADC sample frequencies * Sample time unit is ADCK cycles. ADCK clk source is ipg clock, * which is the same as bus clock. @@ -182,12 +215,13 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info) * SFCAdder: fixed to 6 ADCK cycles * AverageNum: 1, 4, 8, 16, 32 samples for hardware average. * BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode - * LSTAdder(Long Sample Time): fixed to 3 ADCK cycles + * LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles */ adck_rate = ipg_rate / info->adc_feature.clk_div; for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++) info->sample_freq_avail[i] = - adck_rate / (6 + vf610_hw_avgs[i] * (25 + 3)); + adck_rate / (6 + vf610_hw_avgs[i] * + (25 + vf610_lst_adder[adc_feature->lst_adder_index])); } static inline void vf610_adc_cfg_init(struct vf610_adc *info) @@ -347,8 +381,40 @@ static void vf610_adc_sample_set(struct vf610_adc *info) break; } - /* Use the short sample mode */ - cfg_data &= ~(VF610_ADC_ADLSMP_LONG | VF610_ADC_ADSTS_MASK); + /* + * Set ADLSMP and ADSTS based on the Long Sample Time Adder value + * determined. + */ + switch (adc_feature->lst_adder_index) { + case VF610_ADCK_CYCLES_3: + break; + case VF610_ADCK_CYCLES_5: + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_7: + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_9: + cfg_data |= VF610_ADC_ADSTS_LONG; + break; + case VF610_ADCK_CYCLES_13: + cfg_data |= VF610_ADC_ADLSMP_LONG; + break; + case VF610_ADCK_CYCLES_17: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_SHORT; + break; + case VF610_ADCK_CYCLES_21: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + case VF610_ADCK_CYCLES_25: + cfg_data |= VF610_ADC_ADLSMP_LONG; + cfg_data |= VF610_ADC_ADSTS_NORMAL; + break; + default: + dev_err(info->dev, "error in sample time select\n"); + } /* update hardware average selection */ cfg_data &= ~VF610_ADC_AVGS_MASK; @@ -713,6 +779,11 @@ static int vf610_adc_probe(struct platform_device *pdev) of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency", info->max_adck_rate, 3); + ret = of_property_read_u32(pdev->dev.of_node, "min-sample-time", + &info->adc_feature.default_sample_time); + if (ret) + info->adc_feature.default_sample_time = DEFAULT_SAMPLE_TIME; + platform_set_drvdata(pdev, indio_dev); init_completion(&info->completion); diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 8086cbcff87d..2e7fdb502645 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -126,6 +126,9 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) int err, i = 0; struct st_sensor_data *sdata = iio_priv(indio_dev); + if (sdata->sensor_settings->fs.addr == 0) + return 0; + err = st_sensors_match_fs(sdata->sensor_settings, fs, &i); if (err < 0) goto st_accel_set_fullscale_error; @@ -479,46 +482,43 @@ int st_sensors_check_device_support(struct iio_dev *indio_dev, int num_sensors_list, const struct st_sensor_settings *sensor_settings) { - u8 wai; int i, n, err; + u8 wai; struct st_sensor_data *sdata = iio_priv(indio_dev); - err = sdata->tf->read_byte(&sdata->tb, sdata->dev, - ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai); - if (err < 0) { - dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); - goto read_wai_error; - } - for (i = 0; i < num_sensors_list; i++) { - if (sensor_settings[i].wai == wai) + for (n = 0; n < ST_SENSORS_MAX_4WAI; n++) { + if (strcmp(indio_dev->name, + sensor_settings[i].sensors_supported[n]) == 0) { + break; + } + } + if (n < ST_SENSORS_MAX_4WAI) break; } - if (i == num_sensors_list) - goto device_not_supported; + if (i == num_sensors_list) { + dev_err(&indio_dev->dev, "device name %s not recognized.\n", + indio_dev->name); + return -ENODEV; + } - for (n = 0; n < ARRAY_SIZE(sensor_settings[i].sensors_supported); n++) { - if (strcmp(indio_dev->name, - &sensor_settings[i].sensors_supported[n][0]) == 0) - break; + err = sdata->tf->read_byte(&sdata->tb, sdata->dev, + sensor_settings[i].wai_addr, &wai); + if (err < 0) { + dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); + return err; } - if (n == ARRAY_SIZE(sensor_settings[i].sensors_supported)) { - dev_err(&indio_dev->dev, "device name \"%s\" and WhoAmI (0x%02x) mismatch", - indio_dev->name, wai); - goto sensor_name_mismatch; + + if (sensor_settings[i].wai != wai) { + dev_err(&indio_dev->dev, "%s: WhoAmI mismatch (0x%x).\n", + indio_dev->name, wai); + return -EINVAL; } sdata->sensor_settings = (struct st_sensor_settings *)&sensor_settings[i]; return i; - -device_not_supported: - dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai); -sensor_name_mismatch: - err = -ENODEV; -read_wai_error: - return err; } EXPORT_SYMBOL(st_sensors_check_device_support); diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index b3d0e94f72eb..8d2439345673 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -53,7 +53,8 @@ config ADXRS450 config BMG160 tristate "BOSCH BMG160 Gyro Sensor" depends on I2C - select IIO_TRIGGERED_BUFFER if IIO_BUFFER + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for Bosch BMG160 Tri-axis Gyro Sensor driver. This driver also supports BMI055 gyroscope. diff --git a/drivers/iio/gyro/adis16136.c b/drivers/iio/gyro/adis16136.c index 591bd555e1f3..26de876b223d 100644 --- a/drivers/iio/gyro/adis16136.c +++ b/drivers/iio/gyro/adis16136.c @@ -473,6 +473,7 @@ enum adis16136_id { ID_ADIS16133, ID_ADIS16135, ID_ADIS16136, + ID_ADIS16137, }; static const struct adis16136_chip_info adis16136_chip_info[] = { @@ -488,6 +489,10 @@ static const struct adis16136_chip_info adis16136_chip_info[] = { .precision = IIO_DEGREE_TO_RAD(450), .fullscale = 24623, }, + [ID_ADIS16137] = { + .precision = IIO_DEGREE_TO_RAD(1000), + .fullscale = 24609, + }, }; static int adis16136_probe(struct spi_device *spi) @@ -557,6 +562,7 @@ static const struct spi_device_id adis16136_ids[] = { { "adis16133", ID_ADIS16133 }, { "adis16135", ID_ADIS16135 }, { "adis16136", ID_ADIS16136 }, + { "adis16137", ID_ADIS16137 }, { } }; MODULE_DEVICE_TABLE(spi, adis16136_ids); diff --git a/drivers/iio/gyro/adis16260.c b/drivers/iio/gyro/adis16260.c index 75fe0edd3d0f..00c6ad9bf35f 100644 --- a/drivers/iio/gyro/adis16260.c +++ b/drivers/iio/gyro/adis16260.c @@ -101,19 +101,24 @@ #define ADIS16260_SCAN_TEMP 3 #define ADIS16260_SCAN_ANGL 4 -/* Power down the device */ -static int adis16260_stop_device(struct iio_dev *indio_dev) -{ - struct adis *adis = iio_priv(indio_dev); - int ret; - u16 val = ADIS16260_SLP_CNT_POWER_OFF; +struct adis16260_chip_info { + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + const struct iio_chan_spec *channels; + unsigned int num_channels; +}; - ret = adis_write_reg_16(adis, ADIS16260_SLP_CNT, val); - if (ret) - dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); +struct adis16260 { + const struct adis16260_chip_info *info; - return ret; -} + struct adis adis; +}; + +enum adis16260_type { + ADIS16251, + ADIS16260, + ADIS16266, +}; static const struct iio_chan_spec adis16260_channels[] = { ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, @@ -131,6 +136,55 @@ static const struct iio_chan_spec adis16260_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(5), }; +static const struct iio_chan_spec adis16266_channels[] = { + ADIS_GYRO_CHAN(X, ADIS16260_GYRO_OUT, ADIS16260_SCAN_GYRO, + BIT(IIO_CHAN_INFO_CALIBBIAS) | + BIT(IIO_CHAN_INFO_CALIBSCALE), + BIT(IIO_CHAN_INFO_SAMP_FREQ), 14), + ADIS_TEMP_CHAN(ADIS16260_TEMP_OUT, ADIS16260_SCAN_TEMP, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_SUPPLY_CHAN(ADIS16260_SUPPLY_OUT, ADIS16260_SCAN_SUPPLY, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + ADIS_AUX_ADC_CHAN(ADIS16260_AUX_ADC, ADIS16260_SCAN_AUX_ADC, + BIT(IIO_CHAN_INFO_SAMP_FREQ), 12), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct adis16260_chip_info adis16260_chip_info_table[] = { + [ADIS16251] = { + .gyro_max_scale = 80, + .gyro_max_val = IIO_RAD_TO_DEGREE(4368), + .channels = adis16260_channels, + .num_channels = ARRAY_SIZE(adis16260_channels), + }, + [ADIS16260] = { + .gyro_max_scale = 320, + .gyro_max_val = IIO_RAD_TO_DEGREE(4368), + .channels = adis16260_channels, + .num_channels = ARRAY_SIZE(adis16260_channels), + }, + [ADIS16266] = { + .gyro_max_scale = 14000, + .gyro_max_val = IIO_RAD_TO_DEGREE(3357), + .channels = adis16266_channels, + .num_channels = ARRAY_SIZE(adis16266_channels), + }, +}; + +/* Power down the device */ +static int adis16260_stop_device(struct iio_dev *indio_dev) +{ + struct adis16260 *adis16260 = iio_priv(indio_dev); + int ret; + u16 val = ADIS16260_SLP_CNT_POWER_OFF; + + ret = adis_write_reg_16(&adis16260->adis, ADIS16260_SLP_CNT, val); + if (ret) + dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); + + return ret; +} + static const u8 adis16260_addresses[][2] = { [ADIS16260_SCAN_GYRO] = { ADIS16260_GYRO_OFF, ADIS16260_GYRO_SCALE }, }; @@ -140,7 +194,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); + const struct adis16260_chip_info *info = adis16260->info; + struct adis *adis = &adis16260->adis; int ret; u8 addr; s16 val16; @@ -152,15 +208,9 @@ static int adis16260_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - if (spi_get_device_id(adis->spi)->driver_data) { - /* 0.01832 degree / sec */ - *val2 = IIO_DEGREE_TO_RAD(18320); - } else { - /* 0.07326 degree / sec */ - *val2 = IIO_DEGREE_TO_RAD(73260); - } - return IIO_VAL_INT_PLUS_MICRO; + *val = info->gyro_max_scale; + *val2 = info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_INCLI: *val = 0; *val2 = IIO_DEGREE_TO_RAD(36630); @@ -224,7 +274,8 @@ static int adis16260_write_raw(struct iio_dev *indio_dev, int val2, long mask) { - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); + struct adis *adis = &adis16260->adis; int ret; u8 addr; u8 t; @@ -305,35 +356,42 @@ static const struct adis_data adis16260_data = { static int adis16260_probe(struct spi_device *spi) { + const struct spi_device_id *id; + struct adis16260 *adis16260; struct iio_dev *indio_dev; - struct adis *adis; int ret; + id = spi_get_device_id(spi); + if (!id) + return -ENODEV; + /* setup the industrialio driver allocated elements */ - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis)); + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adis16260)); if (!indio_dev) return -ENOMEM; - adis = iio_priv(indio_dev); + adis16260 = iio_priv(indio_dev); /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); - indio_dev->name = spi_get_device_id(spi)->name; + adis16260->info = &adis16260_chip_info_table[id->driver_data]; + + indio_dev->name = id->name; indio_dev->dev.parent = &spi->dev; indio_dev->info = &adis16260_info; - indio_dev->channels = adis16260_channels; - indio_dev->num_channels = ARRAY_SIZE(adis16260_channels); + indio_dev->channels = adis16260->info->channels; + indio_dev->num_channels = adis16260->info->num_channels; indio_dev->modes = INDIO_DIRECT_MODE; - ret = adis_init(adis, indio_dev, spi, &adis16260_data); + ret = adis_init(&adis16260->adis, indio_dev, spi, &adis16260_data); if (ret) return ret; - ret = adis_setup_buffer_and_trigger(adis, indio_dev, NULL); + ret = adis_setup_buffer_and_trigger(&adis16260->adis, indio_dev, NULL); if (ret) return ret; /* Get the device into a sane initial state */ - ret = adis_initial_startup(adis); + ret = adis_initial_startup(&adis16260->adis); if (ret) goto error_cleanup_buffer_trigger; ret = iio_device_register(indio_dev); @@ -343,18 +401,18 @@ static int adis16260_probe(struct spi_device *spi) return 0; error_cleanup_buffer_trigger: - adis_cleanup_buffer_and_trigger(adis, indio_dev); + adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev); return ret; } static int adis16260_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct adis *adis = iio_priv(indio_dev); + struct adis16260 *adis16260 = iio_priv(indio_dev); iio_device_unregister(indio_dev); adis16260_stop_device(indio_dev); - adis_cleanup_buffer_and_trigger(adis, indio_dev); + adis_cleanup_buffer_and_trigger(&adis16260->adis, indio_dev); return 0; } @@ -364,11 +422,12 @@ static int adis16260_remove(struct spi_device *spi) * support for the on chip filtering. */ static const struct spi_device_id adis16260_id[] = { - {"adis16260", 0}, - {"adis16265", 0}, - {"adis16250", 0}, - {"adis16255", 0}, - {"adis16251", 1}, + {"adis16260", ADIS16260}, + {"adis16265", ADIS16260}, + {"adis16266", ADIS16266}, + {"adis16250", ADIS16260}, + {"adis16255", ADIS16260}, + {"adis16251", ADIS16251}, {} }; MODULE_DEVICE_TABLE(spi, adis16260_id); diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index ffe96642b6d0..4b993a5bc9a1 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -131,6 +131,7 @@ static const struct iio_chan_spec st_gyro_16bit_channels[] = { static const struct st_sensor_settings st_gyro_sensors_settings[] = { { .wai = ST_GYRO_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3G4200D_GYRO_DEV_NAME, [1] = LSM330DL_GYRO_DEV_NAME, @@ -190,6 +191,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, { .wai = ST_GYRO_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, [1] = LSM330D_GYRO_DEV_NAME, @@ -252,6 +254,7 @@ static const struct st_sensor_settings st_gyro_sensors_settings[] = { }, { .wai = ST_GYRO_3_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, }, diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 7d79a1ac5f5f..1165b1c4f9d6 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -33,6 +33,7 @@ #include <linux/delay.h> #include <linux/gpio.h> #include <linux/of_gpio.h> +#include <linux/timekeeping.h> #include <linux/iio/iio.h> @@ -46,7 +47,8 @@ * Note that when reading the sensor actually 84 edges are detected, but * since the last edge is not significant, we only store 83: */ -#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1) +#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \ + DHT11_EDGES_PREAMBLE + 1) /* Data transmission timing (nano seconds) */ #define DHT11_START_TRANSMISSION 18 /* ms */ @@ -62,6 +64,7 @@ struct dht11 { int irq; struct completion completion; + /* The iio sysfs interface doesn't prevent concurrent reads: */ struct mutex lock; s64 timestamp; @@ -87,32 +90,20 @@ static unsigned char dht11_decode_byte(int *timing, int threshold) return ret; } -static int dht11_decode(struct dht11 *dht11, int offset) +static int dht11_decode(struct dht11 *dht11, int offset, int timeres) { - int i, t, timing[DHT11_BITS_PER_READ], threshold, - timeres = DHT11_SENSOR_RESPONSE; + int i, t, timing[DHT11_BITS_PER_READ], threshold; unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; - /* Calculate timestamp resolution */ - for (i = 1; i < dht11->num_edges; ++i) { - t = dht11->edges[i].ts - dht11->edges[i-1].ts; - if (t > 0 && t < timeres) - timeres = t; - } - if (2*timeres > DHT11_DATA_BIT_HIGH) { - pr_err("dht11: timeresolution %d too bad for decoding\n", - timeres); - return -EIO; - } threshold = DHT11_DATA_BIT_HIGH / timeres; - if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold) + if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold) pr_err("dht11: WARNING: decoding ambiguous\n"); /* scale down with timeres and check validity */ for (i = 0; i < DHT11_BITS_PER_READ; ++i) { - t = dht11->edges[offset + 2*i + 2].ts - - dht11->edges[offset + 2*i + 1].ts; - if (!dht11->edges[offset + 2*i + 1].value) + t = dht11->edges[offset + 2 * i + 2].ts - + dht11->edges[offset + 2 * i + 1].ts; + if (!dht11->edges[offset + 2 * i + 1].value) return -EIO; /* lost synchronisation */ timing[i] = t / timeres; } @@ -126,7 +117,7 @@ static int dht11_decode(struct dht11 *dht11, int offset) if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) return -EIO; - dht11->timestamp = iio_get_time_ns(); + dht11->timestamp = ktime_get_real_ns(); if (hum_int < 20) { /* DHT22 */ dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * ((temp_int & 0x80) ? -100 : 100); @@ -154,7 +145,7 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) /* TODO: Consider making the handler safe for IRQ sharing */ if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { - dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges].ts = ktime_get_real_ns(); dht11->edges[dht11->num_edges++].value = gpio_get_value(dht11->gpio); @@ -166,14 +157,26 @@ static irqreturn_t dht11_handle_irq(int irq, void *data) } static int dht11_read_raw(struct iio_dev *iio_dev, - const struct iio_chan_spec *chan, + const struct iio_chan_spec *chan, int *val, int *val2, long m) { struct dht11 *dht11 = iio_priv(iio_dev); - int ret; + int ret, timeres; mutex_lock(&dht11->lock); - if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { + if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) { + timeres = ktime_get_resolution_ns(); + if (DHT11_DATA_BIT_HIGH < 2 * timeres) { + dev_err(dht11->dev, "timeresolution %dns too low\n", + timeres); + /* In theory a better clock could become available + * at some point ... and there is no error code + * that really fits better. + */ + ret = -EAGAIN; + goto err; + } + reinit_completion(&dht11->completion); dht11->num_edges = 0; @@ -192,13 +195,13 @@ static int dht11_read_raw(struct iio_dev *iio_dev, goto err; ret = wait_for_completion_killable_timeout(&dht11->completion, - HZ); + HZ); free_irq(dht11->irq, iio_dev); if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) { dev_err(&iio_dev->dev, - "Only %d signal edges detected\n", + "Only %d signal edges detected\n", dht11->num_edges); ret = -ETIMEDOUT; } @@ -206,9 +209,10 @@ static int dht11_read_raw(struct iio_dev *iio_dev, goto err; ret = dht11_decode(dht11, - dht11->num_edges == DHT11_EDGES_PER_READ ? + dht11->num_edges == DHT11_EDGES_PER_READ ? DHT11_EDGES_PREAMBLE : - DHT11_EDGES_PREAMBLE - 2); + DHT11_EDGES_PREAMBLE - 2, + timeres); if (ret) goto err; } @@ -261,9 +265,10 @@ static int dht11_probe(struct platform_device *pdev) dht11 = iio_priv(iio); dht11->dev = dev; - dht11->gpio = ret = of_get_gpio(node, 0); + ret = of_get_gpio(node, 0); if (ret < 0) return ret; + dht11->gpio = ret; ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name); if (ret) return ret; @@ -274,7 +279,7 @@ static int dht11_probe(struct platform_device *pdev) return -EINVAL; } - dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1; dht11->num_edges = -1; platform_set_drvdata(pdev, iio); diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 2fd68f2219a7..abc4c50de9e8 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -139,7 +139,9 @@ enum adis16400_chip_variant { ADIS16360, ADIS16362, ADIS16364, + ADIS16367, ADIS16400, + ADIS16445, ADIS16448, }; @@ -622,6 +624,17 @@ static const struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; +static const struct iio_chan_spec adis16445_channels[] = { + ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), + ADIS16400_GYRO_CHAN(Z, ADIS16400_ZGYRO_OUT, 16), + ADIS16400_ACCEL_CHAN(X, ADIS16400_XACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 16), + ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 16), + ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), +}; + static const struct iio_chan_spec adis16448_channels[] = { ADIS16400_GYRO_CHAN(X, ADIS16400_XGYRO_OUT, 16), ADIS16400_GYRO_CHAN(Y, ADIS16400_YGYRO_OUT, 16), @@ -696,7 +709,8 @@ static struct adis16400_chip_info adis16400_chips[] = { [ADIS16300] = { .channels = adis16300_channels, .num_channels = ARRAY_SIZE(adis16300_channels), - .flags = ADIS16400_HAS_SLOW_MODE, + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, .gyro_scale_micro = IIO_DEGREE_TO_RAD(50000), /* 0.05 deg/s */ .accel_scale_micro = 5884, .temp_scale_nano = 140000000, /* 0.14 C */ @@ -763,6 +777,18 @@ static struct adis16400_chip_info adis16400_chips[] = { .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, + [ADIS16367] = { + .channels = adis16350_channels, + .num_channels = ARRAY_SIZE(adis16350_channels), + .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SLOW_MODE | + ADIS16400_HAS_SERIAL_NUMBER, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(2000), /* 0.2 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(3333), /* 3.333 mg */ + .temp_scale_nano = 136000000, /* 0.136 C */ + .temp_offset = 25000000 / 136000, /* 25 C = 0x00 */ + .set_freq = adis16400_set_freq, + .get_freq = adis16400_get_freq, + }, [ADIS16400] = { .channels = adis16400_channels, .num_channels = ARRAY_SIZE(adis16400_channels), @@ -774,13 +800,26 @@ static struct adis16400_chip_info adis16400_chips[] = { .set_freq = adis16400_set_freq, .get_freq = adis16400_get_freq, }, + [ADIS16445] = { + .channels = adis16445_channels, + .num_channels = ARRAY_SIZE(adis16445_channels), + .flags = ADIS16400_HAS_PROD_ID | + ADIS16400_HAS_SERIAL_NUMBER | + ADIS16400_BURST_DIAG_STAT, + .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .accel_scale_micro = IIO_G_TO_M_S_2(250), /* 1/4000 g */ + .temp_scale_nano = 73860000, /* 0.07386 C */ + .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ + .set_freq = adis16334_set_freq, + .get_freq = adis16334_get_freq, + }, [ADIS16448] = { .channels = adis16448_channels, .num_channels = ARRAY_SIZE(adis16448_channels), .flags = ADIS16400_HAS_PROD_ID | ADIS16400_HAS_SERIAL_NUMBER | ADIS16400_BURST_DIAG_STAT, - .gyro_scale_micro = IIO_DEGREE_TO_RAD(10000), /* 0.01 deg/s */ + .gyro_scale_micro = IIO_DEGREE_TO_RAD(40000), /* 0.04 deg/s */ .accel_scale_micro = IIO_G_TO_M_S_2(833), /* 1/1200 g */ .temp_scale_nano = 73860000, /* 0.07386 C */ .temp_offset = 31000000 / 73860, /* 31 C = 0x00 */ @@ -926,6 +965,7 @@ static int adis16400_remove(struct spi_device *spi) static const struct spi_device_id adis16400_id[] = { {"adis16300", ADIS16300}, + {"adis16305", ADIS16300}, {"adis16334", ADIS16334}, {"adis16350", ADIS16350}, {"adis16354", ADIS16350}, @@ -934,8 +974,10 @@ static const struct spi_device_id adis16400_id[] = { {"adis16362", ADIS16362}, {"adis16364", ADIS16364}, {"adis16365", ADIS16360}, + {"adis16367", ADIS16367}, {"adis16400", ADIS16400}, {"adis16405", ADIS16400}, + {"adis16445", ADIS16445}, {"adis16448", ADIS16448}, {} }; diff --git a/drivers/iio/imu/adis16480.c b/drivers/iio/imu/adis16480.c index 989605dd6f78..b94bfd3f595b 100644 --- a/drivers/iio/imu/adis16480.c +++ b/drivers/iio/imu/adis16480.c @@ -110,6 +110,10 @@ struct adis16480_chip_info { unsigned int num_channels; const struct iio_chan_spec *channels; + unsigned int gyro_max_val; + unsigned int gyro_max_scale; + unsigned int accel_max_val; + unsigned int accel_max_scale; }; struct adis16480 { @@ -497,19 +501,21 @@ static int adis16480_set_filter_freq(struct iio_dev *indio_dev, static int adis16480_read_raw(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, int *val, int *val2, long info) { + struct adis16480 *st = iio_priv(indio_dev); + switch (info) { case IIO_CHAN_INFO_RAW: return adis_single_conversion(indio_dev, chan, 0, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_ANGL_VEL: - *val = 0; - *val2 = IIO_DEGREE_TO_RAD(20000); /* 0.02 degree/sec */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->gyro_max_scale; + *val2 = st->chip_info->gyro_max_val; + return IIO_VAL_FRACTIONAL; case IIO_ACCEL: - *val = 0; - *val2 = IIO_G_TO_M_S_2(800); /* 0.8 mg */ - return IIO_VAL_INT_PLUS_MICRO; + *val = st->chip_info->accel_max_scale; + *val2 = st->chip_info->accel_max_val; + return IIO_VAL_FRACTIONAL; case IIO_MAGN: *val = 0; *val2 = 100; /* 0.0001 gauss */ @@ -674,18 +680,39 @@ static const struct adis16480_chip_info adis16480_chip_info[] = { [ADIS16375] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + /* + * storing the value in rad/degree and the scale in degree + * gives us the result in rad and better precession than + * storing the scale directly in rad. + */ + .gyro_max_val = IIO_RAD_TO_DEGREE(22887), + .gyro_max_scale = 300, + .accel_max_val = IIO_M_S_2_TO_G(21973), + .accel_max_scale = 18, }, [ADIS16480] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(12500), + .accel_max_scale = 5, }, [ADIS16485] = { .channels = adis16485_channels, .num_channels = ARRAY_SIZE(adis16485_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(20000), + .accel_max_scale = 5, }, [ADIS16488] = { .channels = adis16480_channels, .num_channels = ARRAY_SIZE(adis16480_channels), + .gyro_max_val = IIO_RAD_TO_DEGREE(22500), + .gyro_max_scale = 450, + .accel_max_val = IIO_M_S_2_TO_G(22500), + .accel_max_scale = 18, }, }; diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 462a010628cd..82cdf5090fa7 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1363,7 +1363,7 @@ static int kmx61_probe(struct i2c_client *client, if (client->irq < 0) client->irq = kmx61_gpio_probe(client, data); - if (client->irq >= 0) { + if (client->irq > 0) { ret = devm_request_threaded_irq(&client->dev, client->irq, kmx61_data_rdy_trig_poll, kmx61_event_handler, @@ -1445,10 +1445,10 @@ err_iio_unregister_mag: err_iio_unregister_acc: iio_device_unregister(data->acc_indio_dev); err_buffer_cleanup_mag: - if (client->irq >= 0) + if (client->irq > 0) iio_triggered_buffer_cleanup(data->mag_indio_dev); err_buffer_cleanup_acc: - if (client->irq >= 0) + if (client->irq > 0) iio_triggered_buffer_cleanup(data->acc_indio_dev); err_trigger_unregister_motion: iio_trigger_unregister(data->motion_trig); @@ -1472,7 +1472,7 @@ static int kmx61_remove(struct i2c_client *client) iio_device_unregister(data->acc_indio_dev); iio_device_unregister(data->mag_indio_dev); - if (client->irq >= 0) { + if (client->irq > 0) { iio_triggered_buffer_cleanup(data->acc_indio_dev); iio_triggered_buffer_cleanup(data->mag_indio_dev); iio_trigger_unregister(data->acc_dready_trig); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index f72be48e650c..d7e908acb480 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -91,9 +91,16 @@ static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf, /** * iio_buffer_read_first_n_outer() - chrdev read for buffer access + * @filp: File structure pointer for the char device + * @buf: Destination buffer for iio buffer read + * @n: First n bytes to read + * @f_ps: Long offset provided by the user as a seek position * * This function relies on all buffer implementations having an * iio_buffer as their first element. + * + * Return: negative values corresponding to error codes or ret != 0 + * for ending the reading activity **/ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, size_t n, loff_t *f_ps) @@ -143,6 +150,12 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, /** * iio_buffer_poll() - poll the buffer to find out if it has data + * @filp: File structure pointer for device access + * @wait: Poll table structure pointer for which the driver adds + * a wait queue + * + * Return: (POLLIN | POLLRDNORM) if data is available for reading + * or 0 for other cases */ unsigned int iio_buffer_poll(struct file *filp, struct poll_table_struct *wait) @@ -151,7 +164,7 @@ unsigned int iio_buffer_poll(struct file *filp, struct iio_buffer *rb = indio_dev->buffer; if (!indio_dev->info) - return -ENODEV; + return 0; poll_wait(filp, &rb->pollq, wait); if (iio_buffer_ready(indio_dev, rb, rb->watermark, 0)) @@ -1136,7 +1149,7 @@ int iio_scan_mask_query(struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(iio_scan_mask_query); /** - * struct iio_demux_table() - table describing demux memcpy ops + * struct iio_demux_table - table describing demux memcpy ops * @from: index to copy from * @to: index to copy to * @length: how many bytes to copy diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index d8051cdcbdc2..b3fcc2c449d8 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -406,10 +406,16 @@ EXPORT_SYMBOL_GPL(iio_enum_write); /** * iio_format_value() - Formats a IIO value into its string representation - * @buf: The buffer to which the formated value gets written - * @type: One of the IIO_VAL_... constants. This decides how the val and val2 - * parameters are formatted. - * @vals: pointer to the values, exact meaning depends on the type parameter. + * @buf: The buffer to which the formatted value gets written + * @type: One of the IIO_VAL_... constants. This decides how the val + * and val2 parameters are formatted. + * @size: Number of IIO value entries contained in vals + * @vals: Pointer to the values, exact meaning depends on the + * type parameter. + * + * Return: 0 by default, a negative number on failure or the + * total number of characters written for a type that belongs + * to the IIO_VAL_... constant. */ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) { @@ -1096,6 +1102,11 @@ EXPORT_SYMBOL_GPL(devm_iio_device_free); /** * iio_chrdev_open() - chrdev file open for buffer access and ioctls + * @inode: Inode structure for identifying the device in the file system + * @filp: File structure for iio device used to keep and later access + * private data + * + * Return: 0 on success or -EBUSY if the device is already opened **/ static int iio_chrdev_open(struct inode *inode, struct file *filp) { @@ -1114,7 +1125,11 @@ static int iio_chrdev_open(struct inode *inode, struct file *filp) /** * iio_chrdev_release() - chrdev file close buffer access and ioctls - **/ + * @inode: Inode structure pointer for the char device + * @filp: File structure pointer for the char device + * + * Return: 0 for successful release + */ static int iio_chrdev_release(struct inode *inode, struct file *filp) { struct iio_dev *indio_dev = container_of(inode->i_cdev, diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 894d8137c4cf..cae332b1d7ea 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -32,6 +32,7 @@ * @dev_attr_list: list of event interface sysfs attribute * @flags: file operations related flags including busy flag. * @group: event interface sysfs attribute group + * @read_lock: lock to protect kfifo read operations */ struct iio_event_interface { wait_queue_head_t wait; @@ -75,6 +76,11 @@ EXPORT_SYMBOL(iio_push_event); /** * iio_event_poll() - poll the event queue to find out if it has data + * @filep: File structure pointer to identify the device + * @wait: Poll table pointer to add the wait queue on + * + * Return: (POLLIN | POLLRDNORM) if data is available for reading + * or a negative error code on failure */ static unsigned int iio_event_poll(struct file *filep, struct poll_table_struct *wait) @@ -84,7 +90,7 @@ static unsigned int iio_event_poll(struct file *filep, unsigned int events = 0; if (!indio_dev->info) - return -ENODEV; + return events; poll_wait(filep, &ev_int->wait, wait); diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index d31098e0c43f..570606c2adbd 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -40,7 +40,14 @@ static DEFINE_MUTEX(iio_trigger_list_lock); /** * iio_trigger_read_name() - retrieve useful identifying name - **/ + * @dev: device associated with the iio_trigger + * @attr: pointer to the device_attribute structure that is + * being processed + * @buf: buffer to print the name into + * + * Return: a negative number on failure or the number of written + * characters on success. + */ static ssize_t iio_trigger_read_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -288,10 +295,17 @@ EXPORT_SYMBOL_GPL(iio_dealloc_pollfunc); /** * iio_trigger_read_current() - trigger consumer sysfs query current trigger + * @dev: device associated with an industrial I/O device + * @attr: pointer to the device_attribute structure that + * is being processed + * @buf: buffer where the current trigger name will be printed into * * For trigger consumers the current_trigger interface allows the trigger * used by the device to be queried. - **/ + * + * Return: a negative number on failure, the number of characters written + * on success or 0 if no trigger is available + */ static ssize_t iio_trigger_read_current(struct device *dev, struct device_attribute *attr, char *buf) @@ -305,11 +319,18 @@ static ssize_t iio_trigger_read_current(struct device *dev, /** * iio_trigger_write_current() - trigger consumer sysfs set current trigger + * @dev: device associated with an industrial I/O device + * @attr: device attribute that is being processed + * @buf: string buffer that holds the name of the trigger + * @len: length of the trigger name held by buf * * For trigger consumers the current_trigger interface allows the trigger * used for this device to be specified at run time based on the trigger's * name. - **/ + * + * Return: negative error code on failure or length of the buffer + * on success + */ static ssize_t iio_trigger_write_current(struct device *dev, struct device_attribute *attr, const char *buf, diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index b37e18d07630..7ed859a700c4 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -210,6 +210,27 @@ config LTR501 This driver can also be built as a module. If so, the module will be called ltr501. +config OPT3001 + tristate "Texas Instruments OPT3001 Light Sensor" + depends on I2C + help + If you say Y or M here, you get support for Texas Instruments + OPT3001 Ambient Light Sensor. + + If built as a dynamically linked module, it will be called + opt3001. + +config PA12203001 + tristate "TXC PA12203001 light and proximity sensor" + depends on I2C + select REGMAP_I2C + help + If you say yes here you get support for the TXC PA12203001 + ambient light and proximity sensor. + + This driver can also be built as a module. If so, the module + will be called pa12203001. + config STK3310 tristate "STK3310 ALS and proximity sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index adf97237db72..91c74c014b6f 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -19,6 +19,8 @@ obj-$(CONFIG_ISL29125) += isl29125.o obj-$(CONFIG_JSA1212) += jsa1212.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_LTR501) += ltr501.o +obj-$(CONFIG_OPT3001) += opt3001.o +obj-$(CONFIG_PA12203001) += pa12203001.o obj-$(CONFIG_RPR0521) += rpr0521.o obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o obj-$(CONFIG_STK3310) += stk3310.o diff --git a/drivers/iio/light/acpi-als.c b/drivers/iio/light/acpi-als.c index 1dafa0756bfa..60537ec0c923 100644 --- a/drivers/iio/light/acpi-als.c +++ b/drivers/iio/light/acpi-als.c @@ -65,20 +65,20 @@ static const struct iio_chan_spec acpi_als_channels[] = { * to acpi_als_channels[], the evt_buffer below will grow * automatically. */ -#define EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) -#define EVT_BUFFER_SIZE \ - (sizeof(s64) + (EVT_NR_SOURCES * sizeof(s32))) +#define ACPI_ALS_EVT_NR_SOURCES ARRAY_SIZE(acpi_als_channels) +#define ACPI_ALS_EVT_BUFFER_SIZE \ + (sizeof(s64) + (ACPI_ALS_EVT_NR_SOURCES * sizeof(s32))) struct acpi_als { struct acpi_device *device; struct mutex lock; - s32 evt_buffer[EVT_BUFFER_SIZE]; + s32 evt_buffer[ACPI_ALS_EVT_BUFFER_SIZE]; }; /* * All types of properties the ACPI0008 block can report. The ALI, ALC, ALT - * and ALP can all be handled by als_read_value() below, while the ALR is + * and ALP can all be handled by acpi_als_read_value() below, while the ALR is * special. * * The _ALR property returns tables that can be used to fine-tune the values @@ -93,7 +93,7 @@ struct acpi_als { #define ACPI_ALS_POLLING "_ALP" #define ACPI_ALS_TABLES "_ALR" -static int als_read_value(struct acpi_als *als, char *prop, s32 *val) +static int acpi_als_read_value(struct acpi_als *als, char *prop, s32 *val) { unsigned long long temp_val; acpi_status status; @@ -122,11 +122,11 @@ static void acpi_als_notify(struct acpi_device *device, u32 event) mutex_lock(&als->lock); - memset(buffer, 0, EVT_BUFFER_SIZE); + memset(buffer, 0, ACPI_ALS_EVT_BUFFER_SIZE); switch (event) { case ACPI_ALS_NOTIFY_ILLUMINANCE: - ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &val); if (ret < 0) goto out; *buffer++ = val; @@ -159,7 +159,7 @@ static int acpi_als_read_raw(struct iio_dev *indio_dev, if (chan->type != IIO_LIGHT) return -EINVAL; - ret = als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val); + ret = acpi_als_read_value(als, ACPI_ALS_ILLUMINANCE, &temp_val); if (ret < 0) return ret; diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 1c0de2f8885d..d6fd0dace74f 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -353,6 +353,7 @@ static const struct of_device_id cm32181_of_match[] = { { .compatible = "capella,cm32181" }, { } }; +MODULE_DEVICE_TABLE(of, cm32181_of_match); static struct i2c_driver cm32181_driver = { .driver = { diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 1b508c65877c..fe89b6823217 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -417,6 +417,7 @@ static const struct of_device_id cm3232_of_match[] = { {.compatible = "capella,cm3232"}, {} }; +MODULE_DEVICE_TABLE(of, cm3232_of_match); static struct i2c_driver cm3232_driver = { .driver = { diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 2a39e141e90c..c8d7b5ea7e78 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -731,6 +731,7 @@ static const struct of_device_id cm36651_of_match[] = { { .compatible = "capella,cm36651" }, { } }; +MODULE_DEVICE_TABLE(of, cm36651_of_match); static struct i2c_driver cm36651_driver = { .driver = { diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 0334a814b5eb..6d41086f7c64 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1634,6 +1634,7 @@ static const struct of_device_id gp2ap020a00f_of_match[] = { { .compatible = "sharp,gp2ap020a00f" }, { } }; +MODULE_DEVICE_TABLE(of, gp2ap020a00f_of_match); #endif static struct i2c_driver gp2ap020a00f_driver = { diff --git a/drivers/iio/light/opt3001.c b/drivers/iio/light/opt3001.c new file mode 100644 index 000000000000..923aa6aef0ed --- /dev/null +++ b/drivers/iio/light/opt3001.c @@ -0,0 +1,804 @@ +/** + * opt3001.c - Texas Instruments OPT3001 Light Sensor + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Andreas Dannenberg <dannenberg@ti.com> + * Based on previous work from: Felipe Balbi <balbi@ti.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 of the License + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#define OPT3001_RESULT 0x00 +#define OPT3001_CONFIGURATION 0x01 +#define OPT3001_LOW_LIMIT 0x02 +#define OPT3001_HIGH_LIMIT 0x03 +#define OPT3001_MANUFACTURER_ID 0x7e +#define OPT3001_DEVICE_ID 0x7f + +#define OPT3001_CONFIGURATION_RN_MASK (0xf << 12) +#define OPT3001_CONFIGURATION_RN_AUTO (0xc << 12) + +#define OPT3001_CONFIGURATION_CT BIT(11) + +#define OPT3001_CONFIGURATION_M_MASK (3 << 9) +#define OPT3001_CONFIGURATION_M_SHUTDOWN (0 << 9) +#define OPT3001_CONFIGURATION_M_SINGLE (1 << 9) +#define OPT3001_CONFIGURATION_M_CONTINUOUS (2 << 9) /* also 3 << 9 */ + +#define OPT3001_CONFIGURATION_OVF BIT(8) +#define OPT3001_CONFIGURATION_CRF BIT(7) +#define OPT3001_CONFIGURATION_FH BIT(6) +#define OPT3001_CONFIGURATION_FL BIT(5) +#define OPT3001_CONFIGURATION_L BIT(4) +#define OPT3001_CONFIGURATION_POL BIT(3) +#define OPT3001_CONFIGURATION_ME BIT(2) + +#define OPT3001_CONFIGURATION_FC_MASK (3 << 0) + +/* The end-of-conversion enable is located in the low-limit register */ +#define OPT3001_LOW_LIMIT_EOC_ENABLE 0xc000 + +#define OPT3001_REG_EXPONENT(n) ((n) >> 12) +#define OPT3001_REG_MANTISSA(n) ((n) & 0xfff) + +/* + * Time to wait for conversion result to be ready. The device datasheet + * worst-case max value is 880ms. Add some slack to be on the safe side. + */ +#define OPT3001_RESULT_READY_TIMEOUT msecs_to_jiffies(1000) + +struct opt3001 { + struct i2c_client *client; + struct device *dev; + + struct mutex lock; + u16 ok_to_ignore_lock:1; + u16 result_ready:1; + wait_queue_head_t result_ready_queue; + u16 result; + + u32 int_time; + u32 mode; + + u16 high_thresh_mantissa; + u16 low_thresh_mantissa; + + u8 high_thresh_exp; + u8 low_thresh_exp; +}; + +struct opt3001_scale { + int val; + int val2; +}; + +static const struct opt3001_scale opt3001_scales[] = { + { + .val = 40, + .val2 = 950000, + }, + { + .val = 81, + .val2 = 900000, + }, + { + .val = 163, + .val2 = 800000, + }, + { + .val = 327, + .val2 = 600000, + }, + { + .val = 655, + .val2 = 200000, + }, + { + .val = 1310, + .val2 = 400000, + }, + { + .val = 2620, + .val2 = 800000, + }, + { + .val = 5241, + .val2 = 600000, + }, + { + .val = 10483, + .val2 = 200000, + }, + { + .val = 20966, + .val2 = 400000, + }, + { + .val = 83865, + .val2 = 600000, + }, +}; + +static int opt3001_find_scale(const struct opt3001 *opt, int val, + int val2, u8 *exponent) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(opt3001_scales); i++) { + const struct opt3001_scale *scale = &opt3001_scales[i]; + + /* + * Combine the integer and micro parts for comparison + * purposes. Use milli lux precision to avoid 32-bit integer + * overflows. + */ + if ((val * 1000 + val2 / 1000) <= + (scale->val * 1000 + scale->val2 / 1000)) { + *exponent = i; + return 0; + } + } + + return -EINVAL; +} + +static void opt3001_to_iio_ret(struct opt3001 *opt, u8 exponent, + u16 mantissa, int *val, int *val2) +{ + int lux; + + lux = 10 * (mantissa << exponent); + *val = lux / 1000; + *val2 = (lux - (*val * 1000)) * 1000; +} + +static void opt3001_set_mode(struct opt3001 *opt, u16 *reg, u16 mode) +{ + *reg &= ~OPT3001_CONFIGURATION_M_MASK; + *reg |= mode; + opt->mode = mode; +} + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.8"); + +static struct attribute *opt3001_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group opt3001_attribute_group = { + .attrs = opt3001_attributes, +}; + +static const struct iio_event_spec opt3001_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec opt3001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME), + .event_spec = opt3001_event_spec, + .num_event_specs = ARRAY_SIZE(opt3001_event_spec), + }, + IIO_CHAN_SOFT_TIMESTAMP(1), +}; + +static int opt3001_get_lux(struct opt3001 *opt, int *val, int *val2) +{ + int ret; + u16 mantissa; + u16 reg; + u8 exponent; + u16 value; + + /* + * Enable the end-of-conversion interrupt mechanism. Note that doing + * so will overwrite the low-level limit value however we will restore + * this value later on. + */ + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT, + OPT3001_LOW_LIMIT_EOC_ENABLE); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + /* Reset data-ready indicator flag (will be set in the IRQ routine) */ + opt->result_ready = false; + + /* Allow IRQ to access the device despite lock being set */ + opt->ok_to_ignore_lock = true; + + /* Configure for single-conversion mode and start a new conversion */ + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + reg = ret; + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SINGLE); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + /* Wait for the IRQ to indicate the conversion is complete */ + ret = wait_event_timeout(opt->result_ready_queue, opt->result_ready, + OPT3001_RESULT_READY_TIMEOUT); + +err: + /* Disallow IRQ to access the device while lock is active */ + opt->ok_to_ignore_lock = false; + + if (ret == 0) + return -ETIMEDOUT; + else if (ret < 0) + return ret; + + /* + * Disable the end-of-conversion interrupt mechanism by restoring the + * low-level limit value (clearing OPT3001_LOW_LIMIT_EOC_ENABLE). Note + * that selectively clearing those enable bits would affect the actual + * limit value due to bit-overlap and therefore can't be done. + */ + value = (opt->low_thresh_exp << 12) | opt->low_thresh_mantissa; + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_LOW_LIMIT, + value); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + exponent = OPT3001_REG_EXPONENT(opt->result); + mantissa = OPT3001_REG_MANTISSA(opt->result); + + opt3001_to_iio_ret(opt, exponent, mantissa, val, val2); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int opt3001_get_int_time(struct opt3001 *opt, int *val, int *val2) +{ + *val = 0; + *val2 = opt->int_time; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int opt3001_set_int_time(struct opt3001 *opt, int time) +{ + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + + switch (time) { + case 100000: + reg &= ~OPT3001_CONFIGURATION_CT; + opt->int_time = 100000; + break; + case 800000: + reg |= OPT3001_CONFIGURATION_CT; + opt->int_time = 800000; + break; + default: + return -EINVAL; + } + + return i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); +} + +static int opt3001_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return -EBUSY; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + mutex_lock(&opt->lock); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + ret = opt3001_get_lux(opt, val, val2); + break; + case IIO_CHAN_INFO_INT_TIME: + ret = opt3001_get_int_time(opt, val, val2); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_write_raw(struct iio_dev *iio, + struct iio_chan_spec const *chan, int val, int val2, + long mask) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return -EBUSY; + + if (chan->type != IIO_LIGHT) + return -EINVAL; + + if (mask != IIO_CHAN_INFO_INT_TIME) + return -EINVAL; + + if (val != 0) + return -EINVAL; + + mutex_lock(&opt->lock); + ret = opt3001_set_int_time(opt, val2); + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_read_event_value(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int *val, int *val2) +{ + struct opt3001 *opt = iio_priv(iio); + int ret = IIO_VAL_INT_PLUS_MICRO; + + mutex_lock(&opt->lock); + + switch (dir) { + case IIO_EV_DIR_RISING: + opt3001_to_iio_ret(opt, opt->high_thresh_exp, + opt->high_thresh_mantissa, val, val2); + break; + case IIO_EV_DIR_FALLING: + opt3001_to_iio_ret(opt, opt->low_thresh_exp, + opt->low_thresh_mantissa, val, val2); + break; + default: + ret = -EINVAL; + } + + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_write_event_value(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, enum iio_event_info info, + int val, int val2) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + + u16 mantissa; + u16 value; + u16 reg; + + u8 exponent; + + if (val < 0) + return -EINVAL; + + mutex_lock(&opt->lock); + + ret = opt3001_find_scale(opt, val, val2, &exponent); + if (ret < 0) { + dev_err(opt->dev, "can't find scale for %d.%06u\n", val, val2); + goto err; + } + + mantissa = (((val * 1000) + (val2 / 1000)) / 10) >> exponent; + value = (exponent << 12) | mantissa; + + switch (dir) { + case IIO_EV_DIR_RISING: + reg = OPT3001_HIGH_LIMIT; + opt->high_thresh_mantissa = mantissa; + opt->high_thresh_exp = exponent; + break; + case IIO_EV_DIR_FALLING: + reg = OPT3001_LOW_LIMIT; + opt->low_thresh_mantissa = mantissa; + opt->low_thresh_exp = exponent; + break; + default: + ret = -EINVAL; + goto err; + } + + ret = i2c_smbus_write_word_swapped(opt->client, reg, value); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", reg); + goto err; + } + +err: + mutex_unlock(&opt->lock); + + return ret; +} + +static int opt3001_read_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir) +{ + struct opt3001 *opt = iio_priv(iio); + + return opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS; +} + +static int opt3001_write_event_config(struct iio_dev *iio, + const struct iio_chan_spec *chan, enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct opt3001 *opt = iio_priv(iio); + int ret; + u16 mode; + u16 reg; + + if (state && opt->mode == OPT3001_CONFIGURATION_M_CONTINUOUS) + return 0; + + if (!state && opt->mode == OPT3001_CONFIGURATION_M_SHUTDOWN) + return 0; + + mutex_lock(&opt->lock); + + mode = state ? OPT3001_CONFIGURATION_M_CONTINUOUS + : OPT3001_CONFIGURATION_M_SHUTDOWN; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + + reg = ret; + opt3001_set_mode(opt, ®, mode); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + goto err; + } + +err: + mutex_unlock(&opt->lock); + + return ret; +} + +static const struct iio_info opt3001_info = { + .driver_module = THIS_MODULE, + .attrs = &opt3001_attribute_group, + .read_raw = opt3001_read_raw, + .write_raw = opt3001_write_raw, + .read_event_value = opt3001_read_event_value, + .write_event_value = opt3001_write_event_value, + .read_event_config = opt3001_read_event_config, + .write_event_config = opt3001_write_event_config, +}; + +static int opt3001_read_id(struct opt3001 *opt) +{ + char manufacturer[2]; + u16 device_id; + int ret; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_MANUFACTURER_ID); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_MANUFACTURER_ID); + return ret; + } + + manufacturer[0] = ret >> 8; + manufacturer[1] = ret & 0xff; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_DEVICE_ID); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_DEVICE_ID); + return ret; + } + + device_id = ret; + + dev_info(opt->dev, "Found %c%c OPT%04x\n", manufacturer[0], + manufacturer[1], device_id); + + return 0; +} + +static int opt3001_configure(struct opt3001 *opt) +{ + int ret; + u16 reg; + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + + /* Enable automatic full-scale setting mode */ + reg &= ~OPT3001_CONFIGURATION_RN_MASK; + reg |= OPT3001_CONFIGURATION_RN_AUTO; + + /* Reflect status of the device's integration time setting */ + if (reg & OPT3001_CONFIGURATION_CT) + opt->int_time = 800000; + else + opt->int_time = 100000; + + /* Ensure device is in shutdown initially */ + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); + + /* Configure for latched window-style comparison operation */ + reg |= OPT3001_CONFIGURATION_L; + reg &= ~OPT3001_CONFIGURATION_POL; + reg &= ~OPT3001_CONFIGURATION_ME; + reg &= ~OPT3001_CONFIGURATION_FC_MASK; + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_LOW_LIMIT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_LOW_LIMIT); + return ret; + } + + opt->low_thresh_mantissa = OPT3001_REG_MANTISSA(ret); + opt->low_thresh_exp = OPT3001_REG_EXPONENT(ret); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_HIGH_LIMIT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_HIGH_LIMIT); + return ret; + } + + opt->high_thresh_mantissa = OPT3001_REG_MANTISSA(ret); + opt->high_thresh_exp = OPT3001_REG_EXPONENT(ret); + + return 0; +} + +static irqreturn_t opt3001_irq(int irq, void *_iio) +{ + struct iio_dev *iio = _iio; + struct opt3001 *opt = iio_priv(iio); + int ret; + + if (!opt->ok_to_ignore_lock) + mutex_lock(&opt->lock); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + goto out; + } + + if ((ret & OPT3001_CONFIGURATION_M_MASK) == + OPT3001_CONFIGURATION_M_CONTINUOUS) { + if (ret & OPT3001_CONFIGURATION_FH) + iio_push_event(iio, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns()); + if (ret & OPT3001_CONFIGURATION_FL) + iio_push_event(iio, + IIO_UNMOD_EVENT_CODE(IIO_LIGHT, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns()); + } else if (ret & OPT3001_CONFIGURATION_CRF) { + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_RESULT); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_RESULT); + goto out; + } + opt->result = ret; + opt->result_ready = true; + wake_up(&opt->result_ready_queue); + } + +out: + if (!opt->ok_to_ignore_lock) + mutex_unlock(&opt->lock); + + return IRQ_HANDLED; +} + +static int opt3001_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + + struct iio_dev *iio; + struct opt3001 *opt; + int irq = client->irq; + int ret; + + iio = devm_iio_device_alloc(dev, sizeof(*opt)); + if (!iio) + return -ENOMEM; + + opt = iio_priv(iio); + opt->client = client; + opt->dev = dev; + + mutex_init(&opt->lock); + init_waitqueue_head(&opt->result_ready_queue); + i2c_set_clientdata(client, iio); + + ret = opt3001_read_id(opt); + if (ret) + return ret; + + ret = opt3001_configure(opt); + if (ret) + return ret; + + iio->name = client->name; + iio->channels = opt3001_channels; + iio->num_channels = ARRAY_SIZE(opt3001_channels); + iio->dev.parent = dev; + iio->modes = INDIO_DIRECT_MODE; + iio->info = &opt3001_info; + + ret = devm_iio_device_register(dev, iio); + if (ret) { + dev_err(dev, "failed to register IIO device\n"); + return ret; + } + + ret = request_threaded_irq(irq, NULL, opt3001_irq, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "opt3001", iio); + if (ret) { + dev_err(dev, "failed to request IRQ #%d\n", irq); + return ret; + } + + return 0; +} + +static int opt3001_remove(struct i2c_client *client) +{ + struct iio_dev *iio = i2c_get_clientdata(client); + struct opt3001 *opt = iio_priv(iio); + int ret; + u16 reg; + + free_irq(client->irq, iio); + + ret = i2c_smbus_read_word_swapped(opt->client, OPT3001_CONFIGURATION); + if (ret < 0) { + dev_err(opt->dev, "failed to read register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + reg = ret; + opt3001_set_mode(opt, ®, OPT3001_CONFIGURATION_M_SHUTDOWN); + + ret = i2c_smbus_write_word_swapped(opt->client, OPT3001_CONFIGURATION, + reg); + if (ret < 0) { + dev_err(opt->dev, "failed to write register %02x\n", + OPT3001_CONFIGURATION); + return ret; + } + + return 0; +} + +static const struct i2c_device_id opt3001_id[] = { + { "opt3001", 0 }, + { } /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(i2c, opt3001_id); + +static const struct of_device_id opt3001_of_match[] = { + { .compatible = "ti,opt3001" }, + { } +}; + +static struct i2c_driver opt3001_driver = { + .probe = opt3001_probe, + .remove = opt3001_remove, + .id_table = opt3001_id, + + .driver = { + .name = "opt3001", + .of_match_table = of_match_ptr(opt3001_of_match), + .owner = THIS_MODULE, + }, +}; + +module_i2c_driver(opt3001_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>"); +MODULE_DESCRIPTION("Texas Instruments OPT3001 Light Sensor Driver"); diff --git a/drivers/iio/light/pa12203001.c b/drivers/iio/light/pa12203001.c new file mode 100644 index 000000000000..45f7bde02bbf --- /dev/null +++ b/drivers/iio/light/pa12203001.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Driver for TXC PA12203001 Proximity and Ambient Light Sensor. + * + * 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. + * To do: Interrupt support. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/mutex.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +#define PA12203001_DRIVER_NAME "pa12203001" + +#define PA12203001_REG_CFG0 0x00 +#define PA12203001_REG_CFG1 0x01 +#define PA12203001_REG_CFG2 0x02 +#define PA12203001_REG_CFG3 0x03 + +#define PA12203001_REG_ADL 0x0b +#define PA12203001_REG_PDH 0x0e + +#define PA12203001_REG_POFS 0x10 +#define PA12203001_REG_PSET 0x11 + +#define PA12203001_ALS_EN_MASK BIT(0) +#define PA12203001_PX_EN_MASK BIT(1) +#define PA12203001_PX_NORMAL_MODE_MASK GENMASK(7, 6) +#define PA12203001_AFSR_MASK GENMASK(5, 4) +#define PA12203001_AFSR_SHIFT 4 + +#define PA12203001_PSCAN 0x03 + +/* als range 31000, ps, als disabled */ +#define PA12203001_REG_CFG0_DEFAULT 0x30 + +/* led current: 100 mA */ +#define PA12203001_REG_CFG1_DEFAULT 0x20 + +/* ps mode: normal, interrupts not active */ +#define PA12203001_REG_CFG2_DEFAULT 0xcc + +#define PA12203001_REG_CFG3_DEFAULT 0x00 + +#define PA12203001_SLEEP_DELAY_MS 3000 + +#define PA12203001_CHIP_ENABLE 0xff +#define PA12203001_CHIP_DISABLE 0x00 + +/* available scales: corresponding to [500, 4000, 7000, 31000] lux */ +static const int pa12203001_scales[] = { 7629, 61036, 106813, 473029}; + +struct pa12203001_data { + struct i2c_client *client; + + /* protect device states */ + struct mutex lock; + + bool als_enabled; + bool px_enabled; + bool als_needs_enable; + bool px_needs_enable; + + struct regmap *map; +}; + +static const struct { + u8 reg; + u8 val; +} regvals[] = { + {PA12203001_REG_CFG0, PA12203001_REG_CFG0_DEFAULT}, + {PA12203001_REG_CFG1, PA12203001_REG_CFG1_DEFAULT}, + {PA12203001_REG_CFG2, PA12203001_REG_CFG2_DEFAULT}, + {PA12203001_REG_CFG3, PA12203001_REG_CFG3_DEFAULT}, + {PA12203001_REG_PSET, PA12203001_PSCAN}, +}; + +static IIO_CONST_ATTR(in_illuminance_scale_available, + "0.007629 0.061036 0.106813 0.473029"); + +static struct attribute *pa12203001_attrs[] = { + &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group pa12203001_attr_group = { + .attrs = pa12203001_attrs, +}; + +static const struct iio_chan_spec pa12203001_channels[] = { + { + .type = IIO_LIGHT, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + } +}; + +static const struct regmap_range pa12203001_volatile_regs_ranges[] = { + regmap_reg_range(PA12203001_REG_ADL, PA12203001_REG_ADL + 1), + regmap_reg_range(PA12203001_REG_PDH, PA12203001_REG_PDH), +}; + +static const struct regmap_access_table pa12203001_volatile_regs = { + .yes_ranges = pa12203001_volatile_regs_ranges, + .n_yes_ranges = ARRAY_SIZE(pa12203001_volatile_regs_ranges), +}; + +static const struct regmap_config pa12203001_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = PA12203001_REG_PSET, + .cache_type = REGCACHE_RBTREE, + .volatile_table = &pa12203001_volatile_regs, +}; + +static inline int pa12203001_als_enable(struct pa12203001_data *data, u8 enable) +{ + int ret; + + ret = regmap_update_bits(data->map, PA12203001_REG_CFG0, + PA12203001_ALS_EN_MASK, enable); + if (ret < 0) + return ret; + + data->als_enabled = !!enable; + + return 0; +} + +static inline int pa12203001_px_enable(struct pa12203001_data *data, u8 enable) +{ + int ret; + + ret = regmap_update_bits(data->map, PA12203001_REG_CFG0, + PA12203001_PX_EN_MASK, enable); + if (ret < 0) + return ret; + + data->px_enabled = !!enable; + + return 0; +} + +static int pa12203001_set_power_state(struct pa12203001_data *data, bool on, + u8 mask) +{ +#ifdef CONFIG_PM + int ret; + + if (on && (mask & PA12203001_ALS_EN_MASK)) { + mutex_lock(&data->lock); + if (data->px_enabled) { + ret = pa12203001_als_enable(data, + PA12203001_ALS_EN_MASK); + if (ret < 0) + goto err; + } else { + data->als_needs_enable = true; + } + mutex_unlock(&data->lock); + } + + if (on && (mask & PA12203001_PX_EN_MASK)) { + mutex_lock(&data->lock); + if (data->als_enabled) { + ret = pa12203001_px_enable(data, PA12203001_PX_EN_MASK); + if (ret < 0) + goto err; + } else { + data->px_needs_enable = true; + } + mutex_unlock(&data->lock); + } + + if (on) { + ret = pm_runtime_get_sync(&data->client->dev); + if (ret < 0) + pm_runtime_put_noidle(&data->client->dev); + + } else { + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); + } + + return ret; + +err: + mutex_unlock(&data->lock); + return ret; + +#endif + return 0; +} + +static int pa12203001_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int ret; + u8 dev_mask; + unsigned int reg_byte; + __le16 reg_word; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_LIGHT: + dev_mask = PA12203001_ALS_EN_MASK; + ret = pa12203001_set_power_state(data, true, dev_mask); + if (ret < 0) + return ret; + /* + * ALS ADC value is stored in registers + * PA12203001_REG_ADL and in PA12203001_REG_ADL + 1. + */ + ret = regmap_bulk_read(data->map, PA12203001_REG_ADL, + ®_word, 2); + if (ret < 0) + goto reg_err; + + *val = le16_to_cpu(reg_word); + ret = pa12203001_set_power_state(data, false, dev_mask); + if (ret < 0) + return ret; + break; + case IIO_PROXIMITY: + dev_mask = PA12203001_PX_EN_MASK; + ret = pa12203001_set_power_state(data, true, dev_mask); + if (ret < 0) + return ret; + ret = regmap_read(data->map, PA12203001_REG_PDH, + ®_byte); + if (ret < 0) + goto reg_err; + + *val = reg_byte; + ret = pa12203001_set_power_state(data, false, dev_mask); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte); + if (ret < 0) + return ret; + *val = 0; + reg_byte = (reg_byte & PA12203001_AFSR_MASK); + *val2 = pa12203001_scales[reg_byte >> 4]; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + +reg_err: + pa12203001_set_power_state(data, false, dev_mask); + return ret; +} + +static int pa12203001_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int i, ret, new_val; + unsigned int reg_byte; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + ret = regmap_read(data->map, PA12203001_REG_CFG0, ®_byte); + if (val != 0 || ret < 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(pa12203001_scales); i++) { + if (val2 == pa12203001_scales[i]) { + new_val = i << PA12203001_AFSR_SHIFT; + return regmap_update_bits(data->map, + PA12203001_REG_CFG0, + PA12203001_AFSR_MASK, + new_val); + } + } + break; + default: + break; + } + + return -EINVAL; +} + +static const struct iio_info pa12203001_info = { + .driver_module = THIS_MODULE, + .read_raw = pa12203001_read_raw, + .write_raw = pa12203001_write_raw, + .attrs = &pa12203001_attr_group, +}; + +static int pa12203001_init(struct iio_dev *indio_dev) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int i, ret; + + for (i = 0; i < ARRAY_SIZE(regvals); i++) { + ret = regmap_write(data->map, regvals[i].reg, regvals[i].val); + if (ret < 0) + return ret; + } + + return 0; +} + +static int pa12203001_power_chip(struct iio_dev *indio_dev, u8 state) +{ + struct pa12203001_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->lock); + ret = pa12203001_als_enable(data, state); + if (ret < 0) + goto out; + + ret = pa12203001_px_enable(data, state); + +out: + mutex_unlock(&data->lock); + return ret; +} + +static int pa12203001_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pa12203001_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, + sizeof(struct pa12203001_data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + data->map = devm_regmap_init_i2c(client, &pa12203001_regmap_config); + if (IS_ERR(data->map)) + return PTR_ERR(data->map); + + mutex_init(&data->lock); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &pa12203001_info; + indio_dev->name = PA12203001_DRIVER_NAME; + indio_dev->channels = pa12203001_channels; + indio_dev->num_channels = ARRAY_SIZE(pa12203001_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = pa12203001_init(indio_dev); + if (ret < 0) + return ret; + + ret = pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE); + if (ret < 0) + return ret; + + ret = pm_runtime_set_active(&client->dev); + if (ret < 0) { + pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); + return ret; + } + + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, + PA12203001_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(&client->dev); + + return iio_device_register(indio_dev); +} + +static int pa12203001_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); +} + +#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM) +static int pa12203001_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_DISABLE); +} +#endif + +#ifdef CONFIG_PM_SLEEP +static int pa12203001_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + + return pa12203001_power_chip(indio_dev, PA12203001_CHIP_ENABLE); +} +#endif + +#ifdef CONFIG_PM +static int pa12203001_runtime_resume(struct device *dev) +{ + struct pa12203001_data *data; + + data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); + + mutex_lock(&data->lock); + if (data->als_needs_enable) { + pa12203001_als_enable(data, PA12203001_ALS_EN_MASK); + data->als_needs_enable = false; + } + if (data->px_needs_enable) { + pa12203001_px_enable(data, PA12203001_PX_EN_MASK); + data->px_needs_enable = false; + } + mutex_unlock(&data->lock); + + return 0; +} +#endif + +static const struct dev_pm_ops pa12203001_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pa12203001_suspend, pa12203001_resume) + SET_RUNTIME_PM_OPS(pa12203001_suspend, pa12203001_runtime_resume, NULL) +}; + +static const struct acpi_device_id pa12203001_acpi_match[] = { + { "TXCPA122", 0}, + {} +}; + +MODULE_DEVICE_TABLE(acpi, pa12203001_acpi_match); + +static const struct i2c_device_id pa12203001_id[] = { + {"txcpa122", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pa12203001_id); + +static struct i2c_driver pa12203001_driver = { + .driver = { + .name = PA12203001_DRIVER_NAME, + .pm = &pa12203001_pm_ops, + .acpi_match_table = ACPI_PTR(pa12203001_acpi_match), + }, + .probe = pa12203001_probe, + .remove = pa12203001_remove, + .id_table = pa12203001_id, + +}; +module_i2c_driver(pa12203001_driver); + +MODULE_AUTHOR("Adriana Reus <adriana.reus@intel.com>"); +MODULE_DESCRIPTION("Driver for TXC PA12203001 Proximity and Light Sensor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index 11a027adc204..f101bb5bddc7 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -676,6 +676,7 @@ static const struct i2c_device_id stk3310_i2c_id[] = { {"STK3311", 0}, {} }; +MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); static const struct acpi_device_id stk3310_acpi_id[] = { {"STK3310", 0}, diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index 7da4ce9409e8..e330205f8194 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -85,6 +85,7 @@ #define BMC150_MAGN_REG_HIGH_THRESH 0x50 #define BMC150_MAGN_REG_REP_XY 0x51 #define BMC150_MAGN_REG_REP_Z 0x52 +#define BMC150_MAGN_REG_REP_DATAMASK GENMASK(7, 0) #define BMC150_MAGN_REG_TRIM_START 0x5D #define BMC150_MAGN_REG_TRIM_END 0x71 @@ -559,7 +560,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_XY, - 0xFF, + BMC150_MAGN_REG_REP_DATAMASK, BMC150_MAGN_REPXY_TO_REGVAL (val)); mutex_unlock(&data->mutex); @@ -575,7 +576,7 @@ static int bmc150_magn_write_raw(struct iio_dev *indio_dev, } ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_REP_Z, - 0xFF, + BMC150_MAGN_REG_REP_DATAMASK, BMC150_MAGN_REPZ_TO_REGVAL (val)); mutex_unlock(&data->mutex); @@ -651,7 +652,9 @@ static const struct iio_info bmc150_magn_info = { .driver_module = THIS_MODULE, }; -static const unsigned long bmc150_magn_scan_masks[] = {0x07, 0}; +static const unsigned long bmc150_magn_scan_masks[] = { + BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), + 0}; static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) { @@ -662,7 +665,6 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) mutex_lock(&data->mutex); ret = bmc150_magn_read_xyz(data, data->buffer); - mutex_unlock(&data->mutex); if (ret < 0) goto err; @@ -670,6 +672,7 @@ static irqreturn_t bmc150_magn_trigger_handler(int irq, void *p) pf->timestamp); err: + mutex_unlock(&data->mutex); iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; @@ -781,29 +784,23 @@ static int bmc150_magn_data_rdy_trigger_set_state(struct iio_trigger *trig, if (state == data->dready_trigger_on) goto err_unlock; - ret = bmc150_magn_set_power_state(data, state); - if (ret < 0) - goto err_unlock; - ret = regmap_update_bits(data->regmap, BMC150_MAGN_REG_INT_DRDY, BMC150_MAGN_MASK_DRDY_EN, state << BMC150_MAGN_SHIFT_DRDY_EN); if (ret < 0) - goto err_poweroff; + goto err_unlock; data->dready_trigger_on = state; if (state) { ret = bmc150_magn_reset_intr(data); if (ret < 0) - goto err_poweroff; + goto err_unlock; } mutex_unlock(&data->mutex); return 0; -err_poweroff: - bmc150_magn_set_power_state(data, false); err_unlock: mutex_unlock(&data->mutex); return ret; @@ -1041,6 +1038,9 @@ static int bmc150_magn_runtime_suspend(struct device *dev) return 0; } +/* + * Should be called with data->mutex held. + */ static int bmc150_magn_runtime_resume(struct device *dev) { struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 706ebfd6297f..176e14a61558 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -316,31 +316,31 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3]) static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index, __le16 buf[], int *val) { - int raw_x, raw_y, raw_z; - int sens_x, sens_y, sens_z; + int raw[3]; + int sens[3]; int nfo; - raw_x = le16_to_cpu(buf[AXIS_X]); - raw_y = le16_to_cpu(buf[AXIS_Y]); - raw_z = le16_to_cpu(buf[AXIS_Z]); + raw[AXIS_X] = le16_to_cpu(buf[AXIS_X]); + raw[AXIS_Y] = le16_to_cpu(buf[AXIS_Y]); + raw[AXIS_Z] = le16_to_cpu(buf[AXIS_Z]); - sens_x = mmc35240_props_table[data->res].sens[AXIS_X]; - sens_y = mmc35240_props_table[data->res].sens[AXIS_Y]; - sens_z = mmc35240_props_table[data->res].sens[AXIS_Z]; + sens[AXIS_X] = mmc35240_props_table[data->res].sens[AXIS_X]; + sens[AXIS_Y] = mmc35240_props_table[data->res].sens[AXIS_Y]; + sens[AXIS_Z] = mmc35240_props_table[data->res].sens[AXIS_Z]; nfo = mmc35240_props_table[data->res].nfo; switch (index) { case AXIS_X: - *val = (raw_x - nfo) * 1000 / sens_x; + *val = (raw[AXIS_X] - nfo) * 1000 / sens[AXIS_X]; break; case AXIS_Y: - *val = (raw_y - nfo) * 1000 / sens_y - - (raw_z - nfo) * 1000 / sens_z; + *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] - + (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z]; break; case AXIS_Z: - *val = (raw_y - nfo) * 1000 / sens_y + - (raw_z - nfo) * 1000 / sens_z; + *val = (raw[AXIS_Y] - nfo) * 1000 / sens[AXIS_Y] + + (raw[AXIS_Z] - nfo) * 1000 / sens[AXIS_Z]; break; default: return -EINVAL; @@ -559,6 +559,12 @@ static const struct dev_pm_ops mmc35240_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mmc35240_suspend, mmc35240_resume) }; +static const struct of_device_id mmc35240_of_match[] = { + { .compatible = "memsic,mmc35240", }, + { } +}; +MODULE_DEVICE_TABLE(of, mmc35240_of_match); + static const struct acpi_device_id mmc35240_acpi_match[] = { {"MMC35240", 0}, { }, @@ -574,6 +580,7 @@ MODULE_DEVICE_TABLE(i2c, mmc35240_id); static struct i2c_driver mmc35240_driver = { .driver = { .name = MMC35240_DRV_NAME, + .of_match_table = mmc35240_of_match, .pm = &mmc35240_pm_ops, .acpi_match_table = ACPI_PTR(mmc35240_acpi_match), }, diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 287691ca56c1..06a4d9c35581 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -18,6 +18,7 @@ #define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn" #define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn" #define LIS3MDL_MAGN_DEV_NAME "lis3mdl" +#define LSM303AGR_MAGN_DEV_NAME "lsm303agr_magn" int st_magn_common_probe(struct iio_dev *indio_dev); void st_magn_common_remove(struct iio_dev *indio_dev); @@ -25,6 +26,8 @@ void st_magn_common_remove(struct iio_dev *indio_dev); #ifdef CONFIG_IIO_BUFFER int st_magn_allocate_ring(struct iio_dev *indio_dev); void st_magn_deallocate_ring(struct iio_dev *indio_dev); +int st_magn_trig_set_state(struct iio_trigger *trig, bool state); +#define ST_MAGN_TRIGGER_SET_STATE (&st_magn_trig_set_state) #else /* CONFIG_IIO_BUFFER */ static inline int st_magn_probe_trigger(struct iio_dev *indio_dev, int irq) { diff --git a/drivers/iio/magnetometer/st_magn_buffer.c b/drivers/iio/magnetometer/st_magn_buffer.c index bf427dc0d226..ecd3bd0a9769 100644 --- a/drivers/iio/magnetometer/st_magn_buffer.c +++ b/drivers/iio/magnetometer/st_magn_buffer.c @@ -23,6 +23,13 @@ #include <linux/iio/common/st_sensors.h> #include "st_magn.h" +int st_magn_trig_set_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + + return st_sensors_set_dataready_irq(indio_dev, state); +} + static int st_magn_buffer_preenable(struct iio_dev *indio_dev) { return st_sensors_set_enable(indio_dev, true); diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index b4bcfb790f49..f8dc4b85d70c 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -43,6 +43,7 @@ #define ST_MAGN_FS_AVL_8000MG 8000 #define ST_MAGN_FS_AVL_8100MG 8100 #define ST_MAGN_FS_AVL_12000MG 12000 +#define ST_MAGN_FS_AVL_15000MG 15000 #define ST_MAGN_FS_AVL_16000MG 16000 /* CUSTOM VALUES FOR SENSOR 0 */ @@ -157,6 +158,29 @@ #define ST_MAGN_2_OUT_Y_L_ADDR 0x2a #define ST_MAGN_2_OUT_Z_L_ADDR 0x2c +/* CUSTOM VALUES FOR SENSOR 3 */ +#define ST_MAGN_3_WAI_ADDR 0x4f +#define ST_MAGN_3_WAI_EXP 0x40 +#define ST_MAGN_3_ODR_ADDR 0x60 +#define ST_MAGN_3_ODR_MASK 0x0c +#define ST_MAGN_3_ODR_AVL_10HZ_VAL 0x00 +#define ST_MAGN_3_ODR_AVL_20HZ_VAL 0x01 +#define ST_MAGN_3_ODR_AVL_50HZ_VAL 0x02 +#define ST_MAGN_3_ODR_AVL_100HZ_VAL 0x03 +#define ST_MAGN_3_PW_ADDR 0x60 +#define ST_MAGN_3_PW_MASK 0x03 +#define ST_MAGN_3_PW_ON 0x00 +#define ST_MAGN_3_PW_OFF 0x03 +#define ST_MAGN_3_BDU_ADDR 0x62 +#define ST_MAGN_3_BDU_MASK 0x10 +#define ST_MAGN_3_DRDY_IRQ_ADDR 0x62 +#define ST_MAGN_3_DRDY_INT_MASK 0x01 +#define ST_MAGN_3_FS_AVL_15000_GAIN 1500 +#define ST_MAGN_3_MULTIREAD_BIT false +#define ST_MAGN_3_OUT_X_L_ADDR 0x68 +#define ST_MAGN_3_OUT_Y_L_ADDR 0x6a +#define ST_MAGN_3_OUT_Z_L_ADDR 0x6c + static const struct iio_chan_spec st_magn_16bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_MAGN, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -189,9 +213,26 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(3) }; +static const struct iio_chan_spec st_magn_3_16bit_channels[] = { + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_X_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Y_L_ADDR), + ST_SENSORS_LSM_CHANNELS(IIO_MAGN, + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 16, 16, + ST_MAGN_3_OUT_Z_L_ADDR), + IIO_CHAN_SOFT_TIMESTAMP(3) +}; + static const struct st_sensor_settings st_magn_sensors_settings[] = { { .wai = 0, /* This sensor has no valid WhoAmI report 0 */ + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM303DLH_MAGN_DEV_NAME, }, @@ -268,6 +309,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, { .wai = ST_MAGN_1_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LSM303DLHC_MAGN_DEV_NAME, [1] = LSM303DLM_MAGN_DEV_NAME, @@ -346,6 +388,7 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { }, { .wai = ST_MAGN_2_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LIS3MDL_MAGN_DEV_NAME, }, @@ -399,6 +442,48 @@ static const struct st_sensor_settings st_magn_sensors_settings[] = { .multi_read_bit = ST_MAGN_2_MULTIREAD_BIT, .bootime = 2, }, + { + .wai = ST_MAGN_3_WAI_EXP, + .wai_addr = ST_MAGN_3_WAI_ADDR, + .sensors_supported = { + [0] = LSM303AGR_MAGN_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_magn_3_16bit_channels, + .odr = { + .addr = ST_MAGN_3_ODR_ADDR, + .mask = ST_MAGN_3_ODR_MASK, + .odr_avl = { + { 10, ST_MAGN_3_ODR_AVL_10HZ_VAL, }, + { 20, ST_MAGN_3_ODR_AVL_20HZ_VAL, }, + { 50, ST_MAGN_3_ODR_AVL_50HZ_VAL, }, + { 100, ST_MAGN_3_ODR_AVL_100HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_MAGN_3_PW_ADDR, + .mask = ST_MAGN_3_PW_MASK, + .value_on = ST_MAGN_3_PW_ON, + .value_off = ST_MAGN_3_PW_OFF, + }, + .fs = { + .fs_avl = { + [0] = { + .num = ST_MAGN_FS_AVL_15000MG, + .gain = ST_MAGN_3_FS_AVL_15000_GAIN, + }, + }, + }, + .bdu = { + .addr = ST_MAGN_3_BDU_ADDR, + .mask = ST_MAGN_3_BDU_MASK, + }, + .drdy_irq = { + .addr = ST_MAGN_3_DRDY_IRQ_ADDR, + .mask_int1 = ST_MAGN_3_DRDY_INT_MASK, + }, + .multi_read_bit = ST_MAGN_3_MULTIREAD_BIT, + .bootime = 2, + }, }; static int st_magn_read_raw(struct iio_dev *indio_dev, @@ -477,6 +562,16 @@ static const struct iio_info magn_info = { .write_raw = &st_magn_write_raw, }; +#ifdef CONFIG_IIO_TRIGGER +static const struct iio_trigger_ops st_magn_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = ST_MAGN_TRIGGER_SET_STATE, +}; +#define ST_MAGN_TRIGGER_OPS (&st_magn_trigger_ops) +#else +#define ST_MAGN_TRIGGER_OPS NULL +#endif + int st_magn_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *mdata = iio_priv(indio_dev); @@ -513,7 +608,8 @@ int st_magn_common_probe(struct iio_dev *indio_dev) return err; if (irq > 0) { - err = st_sensors_allocate_trigger(indio_dev, NULL); + err = st_sensors_allocate_trigger(indio_dev, + ST_MAGN_TRIGGER_OPS); if (err < 0) goto st_magn_probe_trigger_error; } diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 28aa80731cea..8aa37af306ed 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -36,6 +36,10 @@ static const struct of_device_id st_magn_of_match[] = { .compatible = "st,lis3mdl-magn", .data = LIS3MDL_MAGN_DEV_NAME, }, + { + .compatible = "st,lsm303agr-magn", + .data = LSM303AGR_MAGN_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_magn_of_match); @@ -79,6 +83,7 @@ static const struct i2c_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_magn_id_table); diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 7adacf160146..0abca2c6afa6 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -51,6 +51,7 @@ static const struct spi_device_id st_magn_id_table[] = { { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, + { LSM303AGR_MAGN_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(spi, st_magn_id_table); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index e881fa6291e9..eb41d2b92c24 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -178,6 +178,7 @@ static const struct iio_chan_spec st_press_lps001wp_channels[] = { static const struct st_sensor_settings st_press_sensors_settings[] = { { .wai = ST_PRESS_LPS331AP_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS331AP_PRESS_DEV_NAME, }, @@ -225,6 +226,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, { .wai = ST_PRESS_LPS001WP_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS001WP_PRESS_DEV_NAME, }, @@ -260,6 +262,7 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { }, { .wai = ST_PRESS_LPS25H_WAI_EXP, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, .sensors_supported = { [0] = LPS25H_PRESS_DEV_NAME, }, diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index e4ec7af4c1bf..5d033a5af615 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -65,6 +65,13 @@ #define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */ +/* Magic constants */ +#define MLX90614_CONST_OFFSET_DEC -13657 /* decimal part of the Kelvin offset */ +#define MLX90614_CONST_OFFSET_REM 500000 /* remainder of offset (273.15*50) */ +#define MLX90614_CONST_SCALE 20 /* Scale in milliKelvin (0.02 * 1000) */ +#define MLX90614_CONST_RAW_EMISSIVITY_MAX 65535 /* max value for emissivity */ +#define MLX90614_CONST_EMISSIVITY_RESOLUTION 15259 /* 1/65535 ~ 0.000015259 */ + struct mlx90614_data { struct i2c_client *client; struct mutex lock; /* for EEPROM access only */ @@ -204,11 +211,11 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, *val = ret; return IIO_VAL_INT; case IIO_CHAN_INFO_OFFSET: - *val = -13657; - *val2 = 500000; + *val = MLX90614_CONST_OFFSET_DEC; + *val2 = MLX90614_CONST_OFFSET_REM; return IIO_VAL_INT_PLUS_MICRO; case IIO_CHAN_INFO_SCALE: - *val = 20; + *val = MLX90614_CONST_SCALE; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ mlx90614_power_get(data, false); @@ -221,12 +228,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - if (ret == 65535) { + if (ret == MLX90614_CONST_RAW_EMISSIVITY_MAX) { *val = 1; *val2 = 0; } else { *val = 0; - *val2 = ret * 15259; /* 1/65535 ~ 0.000015259 */ + *val2 = ret * MLX90614_CONST_EMISSIVITY_RESOLUTION; } return IIO_VAL_INT_PLUS_NANO; default: @@ -245,7 +252,8 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ if (val < 0 || val2 < 0 || val > 1 || (val == 1 && val2 != 0)) return -EINVAL; - val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */ + val = val * MLX90614_CONST_RAW_EMISSIVITY_MAX + + val2 / MLX90614_CONST_EMISSIVITY_RESOLUTION; mlx90614_power_get(data, false); mutex_lock(&data->lock); |