From c8a8585431efba0faaf41167f8f7c27c48307ca6 Mon Sep 17 00:00:00 2001 From: Vianney le Clément de Saint-Marcq Date: Mon, 30 Mar 2015 10:34:58 +0200 Subject: iio: core: Introduce IIO_CHAN_INFO_CALIBEMISSIVITY MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contact-less IR temperature sensors measure the temperature of an object by using its thermal radiation. Surfaces with different emissivity ratios emit different amounts of energy at the same temperature. IIO_CHAN_INFO_CALIBEMISSIVITY allows the user to inform the sensor of the emissivity of the object in front of it, in order to effectively measure its temperature. A device providing such setting is Melexis's MLX90614: http://melexis.com/Assets/IR-sensor-thermometer-MLX90614-Datasheet-5152.aspx. Signed-off-by: Vianney le Clément de Saint-Marcq Cc: Arnout Vandecappelle (Essensium/Mind) Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 3befcb19f414..866b4ec4aab6 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1364,3 +1364,14 @@ Description: hwfifo_watermak_min but not equal to any of the values in this list, the driver will chose an appropriate value for the hardware fifo watermark level. + +What: /sys/bus/iio/devices/iio:deviceX/in_temp_calibemissivity +What: /sys/bus/iio/devices/iio:deviceX/in_tempX_calibemissivity +What: /sys/bus/iio/devices/iio:deviceX/in_temp_object_calibemissivity +What: /sys/bus/iio/devices/iio:deviceX/in_tempX_object_calibemissivity +KernelVersion: 4.1 +Contact: linux-iio@vger.kernel.org +Description: + The emissivity ratio of the surface in the field of view of the + contactless temperature sensor. Emissivity varies from 0 to 1, + with 1 being the emissivity of a black body. -- cgit v1.2.3 From 5147b21a61806b0ff2c29ccb3f8bc37495d5c2ff Mon Sep 17 00:00:00 2001 From: Vianney le Clément de Saint-Marcq Date: Mon, 30 Mar 2015 10:34:59 +0200 Subject: iio: mlx90614: Add devicetree bindings documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also introduce "melexis" as a vendor prefix for device tree bindings. Signed-off-by: Vianney le Clément de Saint-Marcq Cc: Arnout Vandecappelle (Essensium/Mind) Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/temperature/mlx90614.txt | 15 +++++++++++++++ Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 2 files changed, 16 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/temperature/mlx90614.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt new file mode 100644 index 000000000000..4c959f3b8663 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt @@ -0,0 +1,15 @@ +* Melexis MLX90614 contactless IR temperature sensor + +http://melexis.com/Infrared-Thermometer-Sensors/Infrared-Thermometer-Sensors/MLX90614-615.aspx + +Required properties: + + - compatible: should be "melexis,mlx90614" + - reg: the I2C address of the sensor + +Example: + +mlx90614@5a { + compatible = "melexis,mlx90614"; + reg = <0x5a>; +}; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index fae26d014aaf..c8db30cc59a3 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -110,6 +110,7 @@ lltc Linear Technology Corporation marvell Marvell Technology Group Ltd. maxim Maxim Integrated Products mediatek MediaTek Inc. +melexis Melexis N.V. merrii Merrii Technology Co., Ltd. micrel Micrel Inc. microchip Microchip Technology Inc. -- cgit v1.2.3 From eb4b07dae4d4b7915333f687675209f677f72fc6 Mon Sep 17 00:00:00 2001 From: Vianney le Clément de Saint-Marcq Date: Mon, 30 Mar 2015 10:35:01 +0200 Subject: iio: mlx90614: Add power management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for system sleep and runtime power management. To wake up the device, the SDA line should be held low for at least 33ms while SCL is high. As this is not possible using the i2c API (and not supported by all i2c adapters), a GPIO connected to the SDA line is needed. The GPIO is named "wakeup" and can be specified in a device tree with the "wakeup-gpios" binding. If the wake-up GPIO is not given, disable power management for the device. Entering sleep requires an SMBus byte access, hence power management is also disabled if byte access is not supported by the adapter. Signed-off-by: Vianney le Clément de Saint-Marcq Cc: Arnout Vandecappelle (Essensium/Mind) Signed-off-by: Jonathan Cameron --- .../bindings/iio/temperature/mlx90614.txt | 9 + drivers/iio/temperature/mlx90614.c | 246 ++++++++++++++++++++- 2 files changed, 253 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt index 4c959f3b8663..9be57b036092 100644 --- a/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt +++ b/Documentation/devicetree/bindings/iio/temperature/mlx90614.txt @@ -7,9 +7,18 @@ Required properties: - compatible: should be "melexis,mlx90614" - reg: the I2C address of the sensor +Optional properties: + + - wakeup-gpios: device tree identifier of the GPIO connected to the SDA line + to hold low in order to wake up the device. In normal operation, the + GPIO is set as input and will not interfere in I2C communication. There + is no need for a GPIO driving the SCL line. If no GPIO is given, power + management is disabled. + Example: mlx90614@5a { compatible = "melexis,mlx90614"; reg = <0x5a>; + wakeup-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; }; diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index a307d8c9da89..73ec7677496f 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -12,13 +12,24 @@ * * (7-bit I2C slave address 0x5a, 100KHz bus speed only!) * - * TODO: sleep mode, filter configuration + * To wake up from sleep mode, the SDA line must be held low while SCL is high + * for at least 33ms. This is achieved with an extra GPIO that can be connected + * directly to the SDA line. In normal operation, the GPIO is set as input and + * will not interfere in I2C communication. While the GPIO is driven low, the + * i2c adapter is locked since it cannot be used by other clients. The SCL line + * always has a pull-up so we do not need an extra GPIO to drive it high. If + * the "wakeup" GPIO is not given, power management will be disabled. + * + * TODO: filter configuration */ #include #include #include #include +#include +#include +#include #include @@ -52,9 +63,13 @@ #define MLX90614_TIMING_WAKEUP 34 /* time to hold SDA low for wake-up */ #define MLX90614_TIMING_STARTUP 250 /* time before first data after wake-up */ +#define MLX90614_AUTOSLEEP_DELAY 5000 /* default autosleep delay */ + struct mlx90614_data { struct i2c_client *client; struct mutex lock; /* for EEPROM access only */ + struct gpio_desc *wakeup_gpio; /* NULL to disable sleep/wake-up */ + unsigned long ready_timestamp; /* in jiffies */ }; /* @@ -95,6 +110,54 @@ static s32 mlx90614_write_word(const struct i2c_client *client, u8 command, return ret; } +#ifdef CONFIG_PM +/* + * If @startup is true, make sure MLX90614_TIMING_STARTUP ms have elapsed since + * the last wake-up. This is normally only needed to get a valid temperature + * reading. EEPROM access does not need such delay. + * Return 0 on success, <0 on error. + */ +static int mlx90614_power_get(struct mlx90614_data *data, bool startup) +{ + unsigned long now; + + if (!data->wakeup_gpio) + return 0; + + pm_runtime_get_sync(&data->client->dev); + + if (startup) { + now = jiffies; + if (time_before(now, data->ready_timestamp) && + msleep_interruptible(jiffies_to_msecs( + data->ready_timestamp - now)) != 0) { + pm_runtime_put_autosuspend(&data->client->dev); + return -EINTR; + } + } + + return 0; +} + +static void mlx90614_power_put(struct mlx90614_data *data) +{ + if (!data->wakeup_gpio) + return; + + pm_runtime_mark_last_busy(&data->client->dev); + pm_runtime_put_autosuspend(&data->client->dev); +} +#else +static inline int mlx90614_power_get(struct mlx90614_data *data, bool startup) +{ + return 0; +} + +static inline void mlx90614_power_put(struct mlx90614_data *data) +{ +} +#endif + static int mlx90614_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, int *val2, long mask) @@ -125,7 +188,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, return -EINVAL; } + ret = mlx90614_power_get(data, true); + if (ret < 0) + return ret; ret = i2c_smbus_read_word_data(data->client, cmd); + mlx90614_power_put(data); + if (ret < 0) return ret; *val = ret; @@ -138,10 +206,12 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, *val = 20; return IIO_VAL_INT; case IIO_CHAN_INFO_CALIBEMISSIVITY: /* 1/65535 / LSB */ + mlx90614_power_get(data, false); mutex_lock(&data->lock); ret = i2c_smbus_read_word_data(data->client, MLX90614_EMISSIVITY); mutex_unlock(&data->lock); + mlx90614_power_put(data); if (ret < 0) return ret; @@ -172,10 +242,12 @@ static int mlx90614_write_raw(struct iio_dev *indio_dev, return -EINVAL; val = val * 65535 + val2 / 15259; /* 1/65535 ~ 0.000015259 */ + mlx90614_power_get(data, false); mutex_lock(&data->lock); ret = mlx90614_write_word(data->client, MLX90614_EMISSIVITY, val); mutex_unlock(&data->lock); + mlx90614_power_put(data); if (ret < 0) return ret; @@ -235,6 +307,98 @@ static const struct iio_info mlx90614_info = { .driver_module = THIS_MODULE, }; +#ifdef CONFIG_PM +static int mlx90614_sleep(struct mlx90614_data *data) +{ + s32 ret; + + if (!data->wakeup_gpio) { + dev_dbg(&data->client->dev, "Sleep disabled"); + return -ENOSYS; + } + + dev_dbg(&data->client->dev, "Requesting sleep"); + + mutex_lock(&data->lock); + ret = i2c_smbus_xfer(data->client->adapter, data->client->addr, + data->client->flags | I2C_CLIENT_PEC, + I2C_SMBUS_WRITE, MLX90614_OP_SLEEP, + I2C_SMBUS_BYTE, NULL); + mutex_unlock(&data->lock); + + return ret; +} + +static int mlx90614_wakeup(struct mlx90614_data *data) +{ + if (!data->wakeup_gpio) { + dev_dbg(&data->client->dev, "Wake-up disabled"); + return -ENOSYS; + } + + dev_dbg(&data->client->dev, "Requesting wake-up"); + + i2c_lock_adapter(data->client->adapter); + gpiod_direction_output(data->wakeup_gpio, 0); + msleep(MLX90614_TIMING_WAKEUP); + gpiod_direction_input(data->wakeup_gpio); + i2c_unlock_adapter(data->client->adapter); + + data->ready_timestamp = jiffies + + msecs_to_jiffies(MLX90614_TIMING_STARTUP); + + /* + * Quirk: the i2c controller may get confused right after the + * wake-up signal has been sent. As a workaround, do a dummy read. + * If the read fails, the controller will probably be reset so that + * further reads will work. + */ + i2c_smbus_read_word_data(data->client, MLX90614_CONFIG); + + return 0; +} + +/* Return wake-up GPIO or NULL if sleep functionality should be disabled. */ +static struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client) +{ + struct gpio_desc *gpio; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_BYTE)) { + dev_info(&client->dev, + "i2c adapter does not support SMBUS_WRITE_BYTE, sleep disabled"); + return NULL; + } + + gpio = devm_gpiod_get_optional(&client->dev, "wakeup", GPIOD_IN); + + if (IS_ERR(gpio)) { + dev_warn(&client->dev, + "gpio acquisition failed with error %ld, sleep disabled", + PTR_ERR(gpio)); + return NULL; + } else if (!gpio) { + dev_info(&client->dev, + "wakeup-gpio not found, sleep disabled"); + } + + return gpio; +} +#else +static inline int mlx90614_sleep(struct mlx90614_data *data) +{ + return -ENOSYS; +} +static inline int mlx90614_wakeup(struct mlx90614_data *data) +{ + return -ENOSYS; +} +static inline struct gpio_desc *mlx90614_probe_wakeup(struct i2c_client *client) +{ + return NULL; +} +#endif + /* Return 0 for single sensor, 1 for dual sensor, <0 on error. */ static int mlx90614_probe_num_ir_sensors(struct i2c_client *client) { @@ -266,6 +430,9 @@ static int mlx90614_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); data->client = client; mutex_init(&data->lock); + data->wakeup_gpio = mlx90614_probe_wakeup(client); + + mlx90614_wakeup(data); indio_dev->dev.parent = &client->dev; indio_dev->name = id->name; @@ -288,12 +455,30 @@ static int mlx90614_probe(struct i2c_client *client, return ret; } + if (data->wakeup_gpio) { + pm_runtime_set_autosuspend_delay(&client->dev, + MLX90614_AUTOSLEEP_DELAY); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + } + return iio_device_register(indio_dev); } static int mlx90614_remove(struct i2c_client *client) { - iio_device_unregister(i2c_get_clientdata(client)); + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct mlx90614_data *data = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + + if (data->wakeup_gpio) { + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + mlx90614_sleep(data); + pm_runtime_set_suspended(&client->dev); + } return 0; } @@ -304,10 +489,67 @@ static const struct i2c_device_id mlx90614_id[] = { }; MODULE_DEVICE_TABLE(i2c, mlx90614_id); +#ifdef CONFIG_PM_SLEEP +static int mlx90614_pm_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct mlx90614_data *data = iio_priv(indio_dev); + + if (data->wakeup_gpio && pm_runtime_active(dev)) + return mlx90614_sleep(data); + + return 0; +} + +static int mlx90614_pm_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct mlx90614_data *data = iio_priv(indio_dev); + int err; + + if (data->wakeup_gpio) { + err = mlx90614_wakeup(data); + if (err < 0) + return err; + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + + return 0; +} +#endif + +#ifdef CONFIG_PM +static int mlx90614_pm_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct mlx90614_data *data = iio_priv(indio_dev); + + return mlx90614_sleep(data); +} + +static int mlx90614_pm_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct mlx90614_data *data = iio_priv(indio_dev); + + return mlx90614_wakeup(data); +} +#endif + +static const struct dev_pm_ops mlx90614_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mlx90614_pm_suspend, mlx90614_pm_resume) + SET_RUNTIME_PM_OPS(mlx90614_pm_runtime_suspend, + mlx90614_pm_runtime_resume, NULL) +}; + static struct i2c_driver mlx90614_driver = { .driver = { .name = "mlx90614", .owner = THIS_MODULE, + .pm = &mlx90614_pm_ops, }, .probe = mlx90614_probe, .remove = mlx90614_remove, -- cgit v1.2.3 From 1038a6872802bb4a07f627162ff989bf49e2e5cc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 30 Apr 2015 15:15:50 +0200 Subject: iio: magnetometer: support for lsm303dlh The LSM303DLH accelerometer/magnetometer has a different device identification method than using register 0x0f, instead three registers contain a magic value. We rely on WhoAmI to be zero for this variant. Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/magnetometer/st_magn.h | 1 + drivers/iio/magnetometer/st_magn_core.c | 116 +++++++++++++++++++++ drivers/iio/magnetometer/st_magn_i2c.c | 5 + 4 files changed, 123 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index d2aaca974531..fb5e0c2d18b5 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -45,6 +45,7 @@ Gyroscopes: - st,lsm330-gyro Magnetometers: +- st,lsm303dlh-magn - st,lsm303dlhc-magn - st,lsm303dlm-magn - st,lis3mdl-magn diff --git a/drivers/iio/magnetometer/st_magn.h b/drivers/iio/magnetometer/st_magn.h index 7e81d00ef0c3..287691ca56c1 100644 --- a/drivers/iio/magnetometer/st_magn.h +++ b/drivers/iio/magnetometer/st_magn.h @@ -14,6 +14,7 @@ #include #include +#define LSM303DLH_MAGN_DEV_NAME "lsm303dlh_magn" #define LSM303DLHC_MAGN_DEV_NAME "lsm303dlhc_magn" #define LSM303DLM_MAGN_DEV_NAME "lsm303dlm_magn" #define LIS3MDL_MAGN_DEV_NAME "lis3mdl" diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index 8ade473f99fe..73574d912e7c 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -45,6 +45,46 @@ #define ST_MAGN_FS_AVL_12000MG 12000 #define ST_MAGN_FS_AVL_16000MG 16000 +/* CUSTOM VALUES FOR SENSOR 0 */ +#define ST_MAGN_0_ODR_ADDR 0x00 +#define ST_MAGN_0_ODR_MASK 0x1c +#define ST_MAGN_0_ODR_AVL_1HZ_VAL 0x00 +#define ST_MAGN_0_ODR_AVL_2HZ_VAL 0x01 +#define ST_MAGN_0_ODR_AVL_3HZ_VAL 0x02 +#define ST_MAGN_0_ODR_AVL_8HZ_VAL 0x03 +#define ST_MAGN_0_ODR_AVL_15HZ_VAL 0x04 +#define ST_MAGN_0_ODR_AVL_30HZ_VAL 0x05 +#define ST_MAGN_0_ODR_AVL_75HZ_VAL 0x06 +#define ST_MAGN_0_ODR_AVL_220HZ_VAL 0x07 +#define ST_MAGN_0_PW_ADDR 0x02 +#define ST_MAGN_0_PW_MASK 0x03 +#define ST_MAGN_0_PW_ON 0x00 +#define ST_MAGN_0_PW_OFF 0x03 +#define ST_MAGN_0_FS_ADDR 0x01 +#define ST_MAGN_0_FS_MASK 0xe0 +#define ST_MAGN_0_FS_AVL_1300_VAL 0x01 +#define ST_MAGN_0_FS_AVL_1900_VAL 0x02 +#define ST_MAGN_0_FS_AVL_2500_VAL 0x03 +#define ST_MAGN_0_FS_AVL_4000_VAL 0x04 +#define ST_MAGN_0_FS_AVL_4700_VAL 0x05 +#define ST_MAGN_0_FS_AVL_5600_VAL 0x06 +#define ST_MAGN_0_FS_AVL_8100_VAL 0x07 +#define ST_MAGN_0_FS_AVL_1300_GAIN_XY 1100 +#define ST_MAGN_0_FS_AVL_1900_GAIN_XY 855 +#define ST_MAGN_0_FS_AVL_2500_GAIN_XY 670 +#define ST_MAGN_0_FS_AVL_4000_GAIN_XY 450 +#define ST_MAGN_0_FS_AVL_4700_GAIN_XY 400 +#define ST_MAGN_0_FS_AVL_5600_GAIN_XY 330 +#define ST_MAGN_0_FS_AVL_8100_GAIN_XY 230 +#define ST_MAGN_0_FS_AVL_1300_GAIN_Z 980 +#define ST_MAGN_0_FS_AVL_1900_GAIN_Z 760 +#define ST_MAGN_0_FS_AVL_2500_GAIN_Z 600 +#define ST_MAGN_0_FS_AVL_4000_GAIN_Z 400 +#define ST_MAGN_0_FS_AVL_4700_GAIN_Z 355 +#define ST_MAGN_0_FS_AVL_5600_GAIN_Z 295 +#define ST_MAGN_0_FS_AVL_8100_GAIN_Z 205 +#define ST_MAGN_0_MULTIREAD_BIT false + /* CUSTOM VALUES FOR SENSOR 1 */ #define ST_MAGN_1_WAI_EXP 0x3c #define ST_MAGN_1_ODR_ADDR 0x00 @@ -150,6 +190,82 @@ static const struct iio_chan_spec st_magn_2_16bit_channels[] = { }; static const struct st_sensor_settings st_magn_sensors_settings[] = { + { + .wai = 0, /* This sensor has no valid WhoAmI report 0 */ + .sensors_supported = { + [0] = LSM303DLH_MAGN_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_magn_16bit_channels, + .odr = { + .addr = ST_MAGN_0_ODR_ADDR, + .mask = ST_MAGN_0_ODR_MASK, + .odr_avl = { + { 1, ST_MAGN_0_ODR_AVL_1HZ_VAL, }, + { 2, ST_MAGN_0_ODR_AVL_2HZ_VAL, }, + { 3, ST_MAGN_0_ODR_AVL_3HZ_VAL, }, + { 8, ST_MAGN_0_ODR_AVL_8HZ_VAL, }, + { 15, ST_MAGN_0_ODR_AVL_15HZ_VAL, }, + { 30, ST_MAGN_0_ODR_AVL_30HZ_VAL, }, + { 75, ST_MAGN_0_ODR_AVL_75HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_MAGN_0_PW_ADDR, + .mask = ST_MAGN_0_PW_MASK, + .value_on = ST_MAGN_0_PW_ON, + .value_off = ST_MAGN_0_PW_OFF, + }, + .fs = { + .addr = ST_MAGN_0_FS_ADDR, + .mask = ST_MAGN_0_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_MAGN_FS_AVL_1300MG, + .value = ST_MAGN_0_FS_AVL_1300_VAL, + .gain = ST_MAGN_0_FS_AVL_1300_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_1300_GAIN_Z, + }, + [1] = { + .num = ST_MAGN_FS_AVL_1900MG, + .value = ST_MAGN_0_FS_AVL_1900_VAL, + .gain = ST_MAGN_0_FS_AVL_1900_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_1900_GAIN_Z, + }, + [2] = { + .num = ST_MAGN_FS_AVL_2500MG, + .value = ST_MAGN_0_FS_AVL_2500_VAL, + .gain = ST_MAGN_0_FS_AVL_2500_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_2500_GAIN_Z, + }, + [3] = { + .num = ST_MAGN_FS_AVL_4000MG, + .value = ST_MAGN_0_FS_AVL_4000_VAL, + .gain = ST_MAGN_0_FS_AVL_4000_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_4000_GAIN_Z, + }, + [4] = { + .num = ST_MAGN_FS_AVL_4700MG, + .value = ST_MAGN_0_FS_AVL_4700_VAL, + .gain = ST_MAGN_0_FS_AVL_4700_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_4700_GAIN_Z, + }, + [5] = { + .num = ST_MAGN_FS_AVL_5600MG, + .value = ST_MAGN_0_FS_AVL_5600_VAL, + .gain = ST_MAGN_0_FS_AVL_5600_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_5600_GAIN_Z, + }, + [6] = { + .num = ST_MAGN_FS_AVL_8100MG, + .value = ST_MAGN_0_FS_AVL_8100_VAL, + .gain = ST_MAGN_0_FS_AVL_8100_GAIN_XY, + .gain2 = ST_MAGN_0_FS_AVL_8100_GAIN_Z, + }, + }, + }, + .multi_read_bit = ST_MAGN_0_MULTIREAD_BIT, + .bootime = 2, + }, { .wai = ST_MAGN_1_WAI_EXP, .sensors_supported = { diff --git a/drivers/iio/magnetometer/st_magn_i2c.c b/drivers/iio/magnetometer/st_magn_i2c.c index 92e5c15452a3..5311d8aea8cc 100644 --- a/drivers/iio/magnetometer/st_magn_i2c.c +++ b/drivers/iio/magnetometer/st_magn_i2c.c @@ -20,6 +20,10 @@ #ifdef CONFIG_OF static const struct of_device_id st_magn_of_match[] = { + { + .compatible = "st,lsm303dlh-magn", + .data = LSM303DLH_MAGN_DEV_NAME, + }, { .compatible = "st,lsm303dlhc-magn", .data = LSM303DLHC_MAGN_DEV_NAME, @@ -71,6 +75,7 @@ static int st_magn_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id st_magn_id_table[] = { + { LSM303DLH_MAGN_DEV_NAME }, { LSM303DLHC_MAGN_DEV_NAME }, { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, -- cgit v1.2.3 From 42a95584f31c5f11a669f0db72f6b6e9ff00b8d9 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Wed, 29 Apr 2015 21:16:38 +0300 Subject: iio: magn: bmc150_magn: Add devicetree binding documentation Add binding documentation for Bosch BMC150 magnetometer. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- .../bindings/iio/magnetometer/bmc150_magn.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt b/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt new file mode 100644 index 000000000000..9f263b7df162 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/magnetometer/bmc150_magn.txt @@ -0,0 +1,22 @@ +* Bosch BMC150 magnetometer sensor + +http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf + +Required properties: + + - compatible : should be "bosch,bmc150_magn" + - reg : the I2C address of the magnetometer + +Optional properties: + + - interrupt-parent : phandle to the parent interrupt controller + - interrupts : interrupt mapping for GPIO IRQ + +Example: + +bmc150_magn@12 { + compatible = "bosch,bmc150_magn"; + reg = <0x12>; + interrupt-parent = <&gpio1>; + interrupts = <0 1>; +}; -- cgit v1.2.3 From faaa44955dedc661f083636d816af90975a359ee Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Wed, 29 Apr 2015 21:16:39 +0300 Subject: iio: core: Introduce IIO_CHAN_INFO_OVERSAMPLING_RATIO Some magnetometers can perform a number of repetitions in HW for each measurement to increase accuracy. One example is Bosch BMC150: http://ae-bst.resource.bosch.com/media/products/dokumente/bmc150/BST-BMC150-DS000-04.pdf. Introduce an interface to set the oversampling ratio for these devices. Signed-off-by: Irina Tirdea Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 12 ++++++++++++ drivers/iio/industrialio-core.c | 1 + include/linux/iio/iio.h | 1 + 3 files changed, 14 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index 866b4ec4aab6..e46c71fbd047 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -1375,3 +1375,15 @@ Description: The emissivity ratio of the surface in the field of view of the contactless temperature sensor. Emissivity varies from 0 to 1, with 1 being the emissivity of a black body. + +What: /sys/bus/iio/devices/iio:deviceX/in_magn_x_oversampling_ratio +What: /sys/bus/iio/devices/iio:deviceX/in_magn_y_oversampling_ratio +What: /sys/bus/iio/devices/iio:deviceX/in_magn_z_oversampling_ratio +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + Hardware applied number of measurements for acquiring one + data point. The HW will do [_name]_oversampling_ratio + measurements and return the average value as output data. Each + value resulted from [_name]_oversampling_ratio measurements + is considered as one sample for [_name]_sampling_frequency. diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 7c98bc1504e6..dfa81db3b910 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -129,6 +129,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_DEBOUNCE_COUNT] = "debounce_count", [IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time", [IIO_CHAN_INFO_CALIBEMISSIVITY] = "calibemissivity", + [IIO_CHAN_INFO_OVERSAMPLING_RATIO] = "oversampling_ratio", }; /** diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index b1e46ae89aa7..058441da4984 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -44,6 +44,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_DEBOUNCE_COUNT, IIO_CHAN_INFO_DEBOUNCE_TIME, IIO_CHAN_INFO_CALIBEMISSIVITY, + IIO_CHAN_INFO_OVERSAMPLING_RATIO, }; enum iio_shared_by { -- cgit v1.2.3 From ee1a81f90f28a5a2c3339ec62b2a6a6d165075d2 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Fri, 24 Apr 2015 14:53:07 +0530 Subject: imu: inv_mpu6050: adds device tree bindings Signed-off-by: Varka Bhadram Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/imu/inv_mpu6050.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt new file mode 100644 index 000000000000..e4d8f1c52f4a --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/inv_mpu6050.txt @@ -0,0 +1,17 @@ +InvenSense MPU-6050 Six-Axis (Gyro + Accelerometer) MEMS MotionTracking Device + +http://www.invensense.com/mems/gyro/mpu6050.html + +Required properties: + - compatible : should be "invensense,mpu6050" + - reg : the I2C address of the sensor + - interrupt-parent : should be the phandle for the interrupt controller + - interrupts : interrupt mapping for GPIO IRQ + +Example: + mpu6050@68 { + compatible = "invensense,mpu6050"; + reg = <0x68>; + interrupt-parent = <&gpio1>; + interrupts = <18 1>; + }; -- cgit v1.2.3 From 5dc11e810676ec4a5acb4423ccd33314bf74f4e5 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 31 Mar 2015 16:42:37 +0530 Subject: iio: adc: ti_am335x_adc: make sample delay, open delay, averaging DT parameters Add optional DT properties to set open delay, sample delay and number of averages per sample for each adc step. Open delay, sample delay and averaging are some of the parameters that affect the sampling rate and accuracy of the sample. Making these parameters configurable via DT will help in balancing speed vs accuracy. Signed-off-by: Vignesh R Signed-off-by: Jonathan Cameron --- .../bindings/input/touchscreen/ti-tsc-adc.txt | 24 ++++++++++ drivers/iio/adc/ti_am335x_adc.c | 54 +++++++++++++++++++--- 2 files changed, 72 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt index 6c4fb34823d3..b1163bf97146 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt @@ -42,6 +42,27 @@ Optional properties: hardware knob for adjusting the amount of "settling time". +- child "adc" + ti,chan-step-opendelay: List of open delays for each channel of + ADC in the order of ti,adc-channels. The + value corresponds to the number of ADC + clock cycles to wait after applying the + step configuration registers and before + sending the start of ADC conversion. + Maximum value is 0x3FFFF. + ti,chan-step-sampledelay: List of sample delays for each channel + of ADC in the order of ti,adc-channels. + The value corresponds to the number of + ADC clock cycles to sample (to hold + start of conversion high). + Maximum value is 0xFF. + ti,chan-step-avg: Number of averages to be performed for each + channel of ADC. If average is 16 then input + is sampled 16 times and averaged to get more + accurate value. This increases the time taken + by ADC to generate a sample. Valid range is 0 + average to 16 averages. Maximum value is 16. + Example: tscadc: tscadc@44e0d000 { compatible = "ti,am3359-tscadc"; @@ -55,5 +76,8 @@ Example: adc { ti,adc-channels = <4 5 6 7>; + ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>; + ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>; + ti,chan-step-avg = <16 2 4 8>; }; } diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 42e444044ea5..942320e32753 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -37,6 +37,7 @@ struct tiadc_device { u8 channel_step[8]; int buffer_en_ch_steps; u16 data[8]; + u32 open_delay[8], sample_delay[8], step_avg[8]; }; static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) @@ -85,6 +86,7 @@ static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) static void tiadc_step_config(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); + struct device *dev = adc_dev->mfd_tscadc->dev; unsigned int stepconfig; int i, steps = 0; @@ -98,20 +100,47 @@ static void tiadc_step_config(struct iio_dev *indio_dev) * needs to be given to ADC to digitalize data. */ - if (iio_buffer_enabled(indio_dev)) - stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1 - | STEPCONFIG_MODE_SWCNT; - else - stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1; for (i = 0; i < adc_dev->channels; i++) { int chan; chan = adc_dev->channel_line[i]; + + if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) { + dev_warn(dev, "chan %d step_avg truncating to %d\n", + chan, STEPCONFIG_AVG_16); + adc_dev->step_avg[i] = STEPCONFIG_AVG_16; + } + + if (adc_dev->step_avg[i]) + stepconfig = + STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | + STEPCONFIG_FIFO1; + else + stepconfig = STEPCONFIG_FIFO1; + + if (iio_buffer_enabled(indio_dev)) + stepconfig |= STEPCONFIG_MODE_SWCNT; + tiadc_writel(adc_dev, REG_STEPCONFIG(steps), stepconfig | STEPCONFIG_INP(chan)); + + if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) { + dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n", + chan); + adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK; + } + + if (adc_dev->sample_delay[i] > 0xFF) { + dev_warn(dev, "chan %d sample delay truncating to 0xFF\n", + chan); + adc_dev->sample_delay[i] = 0xFF; + } + tiadc_writel(adc_dev, REG_STEPDELAY(steps), - STEPCONFIG_OPENDLY); + STEPDELAY_OPEN(adc_dev->open_delay[i]) | + STEPDELAY_SAMPLE(adc_dev->sample_delay[i])); + adc_dev->channel_step[i] = steps; steps++; } @@ -406,9 +435,22 @@ static int tiadc_parse_dt(struct platform_device *pdev, of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { adc_dev->channel_line[channels] = val; + + /* Set Default values for optional DT parameters */ + adc_dev->open_delay[channels] = STEPCONFIG_OPENDLY; + adc_dev->sample_delay[channels] = STEPCONFIG_SAMPLEDLY; + adc_dev->step_avg[channels] = 16; + channels++; } + of_property_read_u32_array(node, "ti,chan-step-avg", + adc_dev->step_avg, channels); + of_property_read_u32_array(node, "ti,chan-step-opendelay", + adc_dev->open_delay, channels); + of_property_read_u32_array(node, "ti,chan-step-sampledelay", + adc_dev->sample_delay, channels); + adc_dev->channels = channels; return 0; } -- cgit v1.2.3 From 3f7f642b9bc46453e1435e8b67f1c4f7949be7ff Mon Sep 17 00:00:00 2001 From: Martin Fuzzey Date: Wed, 13 May 2015 12:26:42 +0200 Subject: iio: core: add high pass filter attributes Add a high pass filter attribute for measurements (like the existing low pass) Also add both high and low pass attributes for events. Signed-off-by: Martin Fuzzey Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 30 ++++++++++++++++++++++++++++++ drivers/iio/industrialio-core.c | 2 ++ drivers/iio/industrialio-event.c | 2 ++ include/linux/iio/iio.h | 1 + include/linux/iio/types.h | 2 ++ 5 files changed, 37 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index e46c71fbd047..f66262c64e2f 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -420,6 +420,16 @@ Description: to the underlying data channel, then this parameter gives the 3dB frequency of the filter in Hz. +What: /sys/.../in_accel_filter_high_pass_3db_frequency +What: /sys/.../in_anglvel_filter_high_pass_3db_frequency +What: /sys/.../in_magn_filter_high_pass_3db_frequency +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + If a known or controllable high pass filter is applied + to the underlying data channel, then this parameter + gives the 3dB frequency of the filter in Hz. + What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_raw What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_raw KernelVersion: 2.6.37 @@ -880,6 +890,26 @@ Description: met before an event is generated. If direction is not specified then this period applies to both directions. +What: /sys/.../events/in_accel_thresh_rising_low_pass_filter_3db +What: /sys/.../events/in_anglvel_thresh_rising_low_pass_filter_3db +What: /sys/.../events/in_magn_thresh_rising_low_pass_filter_3db +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + If a low pass filter can be applied to the event generation + this property gives its 3db frequency in Hz. + A value of zero disables the filter. + +What: /sys/.../events/in_accel_thresh_rising_high_pass_filter_3db +What: /sys/.../events/in_anglvel_thresh_rising_high_pass_filter_3db +What: /sys/.../events/in_magn_thresh_rising_high_pass_filter_3db +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + If a high pass filter can be applied to the event generation + this property gives its 3db frequency in Hz. + A value of zero disables the filter. + What: /sys/.../events/in_activity_still_thresh_rising_en What: /sys/.../events/in_activity_still_thresh_falling_en What: /sys/.../events/in_activity_walking_thresh_rising_en diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index dfa81db3b910..9688a88b6198 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -117,6 +117,8 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_AVERAGE_RAW] = "mean_raw", [IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY] = "filter_low_pass_3db_frequency", + [IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY] + = "filter_high_pass_3db_frequency", [IIO_CHAN_INFO_SAMP_FREQ] = "sampling_frequency", [IIO_CHAN_INFO_FREQUENCY] = "frequency", [IIO_CHAN_INFO_PHASE] = "phase", diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index a99692ba91bc..894d8137c4cf 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -211,6 +211,8 @@ static const char * const iio_ev_info_text[] = { [IIO_EV_INFO_VALUE] = "value", [IIO_EV_INFO_HYSTERESIS] = "hysteresis", [IIO_EV_INFO_PERIOD] = "period", + [IIO_EV_INFO_HIGH_PASS_FILTER_3DB] = "high_pass_filter_3db", + [IIO_EV_INFO_LOW_PASS_FILTER_3DB] = "low_pass_filter_3db", }; static enum iio_event_direction iio_ev_attr_dir(struct iio_dev_attr *attr) diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 058441da4984..f79148261d16 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -32,6 +32,7 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW, IIO_CHAN_INFO_AVERAGE_RAW, IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY, + IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY, IIO_CHAN_INFO_SAMP_FREQ, IIO_CHAN_INFO_FREQUENCY, IIO_CHAN_INFO_PHASE, diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 942b6de68e2f..32b579525004 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -17,6 +17,8 @@ enum iio_event_info { IIO_EV_INFO_VALUE, IIO_EV_INFO_HYSTERESIS, IIO_EV_INFO_PERIOD, + IIO_EV_INFO_HIGH_PASS_FILTER_3DB, + IIO_EV_INFO_LOW_PASS_FILTER_3DB, }; #define IIO_VAL_INT 1 -- cgit v1.2.3 From 2f4adaeebfb6f30fd6cd7a1a1dffe31f8e93a4c9 Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Mon, 18 May 2015 11:19:19 +0200 Subject: Documentation: bindings: document the Berlin ADC driver Following the addition of a Berlin ADC driver, this patch adds the corresponding bindings documentation. Signed-off-by: Antoine Tenart Acked-by: Jonathan Cameron Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/berlin2_adc.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt b/Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt new file mode 100644 index 000000000000..908334c6b07f --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/berlin2_adc.txt @@ -0,0 +1,19 @@ +* Berlin Analog to Digital Converter (ADC) + +The Berlin ADC has 8 channels, with one connected to a temperature sensor. +It is part of the system controller register set. The ADC node should be a +sub-node of the system controller node. + +Required properties: +- compatible: must be "marvell,berlin2-adc" +- interrupts: the interrupts for the ADC and the temperature sensor +- interrupt-names: should be "adc" and "tsen" + +Example: + +adc: adc { + compatible = "marvell,berlin2-adc"; + interrupt-parent = <&sic>; + interrupts = <12>, <14>; + interrupt-names = "adc", "tsen"; +}; -- cgit v1.2.3 From 1ce87f21edf6a071a7cc6bc77d628d7c7650d0d8 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 22 May 2015 18:17:38 +0200 Subject: iio: Add I/Q modifiers I/Q modifiers can be used to denote signals which are represented by a in-phase and a quadrature component. The ABI documentation describes the I and Q modifiers for current and voltage channels for now as those will be the most likely users. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 46 +++++++++++++++++++++++++++++++++ drivers/iio/industrialio-core.c | 2 ++ include/uapi/linux/iio/types.h | 2 ++ 3 files changed, 50 insertions(+) (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index f66262c64e2f..bbed111c31b4 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -71,6 +71,8 @@ Description: What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_raw What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_raw +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_raw +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org Description: @@ -81,6 +83,11 @@ Description: unique to allow association with event codes. Units after application of scale and offset are millivolts. + Channels with 'i' and 'q' modifiers always exist in pairs and both + channels refer to the same signal. The 'i' channel contains the in-phase + component of the signal while the 'q' channel contains the quadrature + component. + What: /sys/bus/iio/devices/iio:deviceX/in_voltageY-voltageZ_raw KernelVersion: 2.6.35 Contact: linux-iio@vger.kernel.org @@ -246,8 +253,16 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_offset What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_offset What: /sys/bus/iio/devices/iio:deviceX/in_voltage_offset +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_offset +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_offset +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_offset +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_offset What: /sys/bus/iio/devices/iio:deviceX/in_currentY_offset What: /sys/bus/iio/devices/iio:deviceX/in_current_offset +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_offset +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_offset +What: /sys/bus/iio/devices/iio:deviceX/in_current_q_offset +What: /sys/bus/iio/devices/iio:deviceX/in_current_i_offset What: /sys/bus/iio/devices/iio:deviceX/in_tempY_offset What: /sys/bus/iio/devices/iio:deviceX/in_temp_offset What: /sys/bus/iio/devices/iio:deviceX/in_pressureY_offset @@ -273,14 +288,22 @@ Description: to the _raw output. What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_scale +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_scale +What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_scale What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_scale What: /sys/bus/iio/devices/iio:deviceX/in_voltage_scale +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_i_scale +What: /sys/bus/iio/devices/iio:deviceX/in_voltage_q_scale What: /sys/bus/iio/devices/iio:deviceX/in_voltage-voltage_scale What: /sys/bus/iio/devices/iio:deviceX/out_voltageY_scale What: /sys/bus/iio/devices/iio:deviceX/out_altvoltageY_scale What: /sys/bus/iio/devices/iio:deviceX/in_currentY_scale What: /sys/bus/iio/devices/iio:deviceX/in_currentY_supply_scale What: /sys/bus/iio/devices/iio:deviceX/in_current_scale +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_i_scale +What: /sys/bus/iio/devices/iio:deviceX/in_currentY_q_scale +What: /sys/bus/iio/devices/iio:deviceX/in_current_i_scale +What: /sys/bus/iio/devices/iio:deviceX/in_current_q_scale What: /sys/bus/iio/devices/iio:deviceX/in_accel_scale What: /sys/bus/iio/devices/iio:deviceX/in_accel_peak_scale What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_scale @@ -328,6 +351,10 @@ Description: What /sys/bus/iio/devices/iio:deviceX/in_voltageY_calibscale What /sys/bus/iio/devices/iio:deviceX/in_voltageY_supply_calibscale +What /sys/bus/iio/devices/iio:deviceX/in_voltageY_i_calibscale +What /sys/bus/iio/devices/iio:deviceX/in_voltageY_q_calibscale +What /sys/bus/iio/devices/iio:deviceX/in_voltage_i_calibscale +What /sys/bus/iio/devices/iio:deviceX/in_voltage_q_calibscale What /sys/bus/iio/devices/iio:deviceX/in_voltage_calibscale What /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale What /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale @@ -1046,6 +1073,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_timestamp_en What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_en What: /sys/.../iio:deviceX/scan_elements/in_voltageY_en What: /sys/.../iio:deviceX/scan_elements/in_voltageY-voltageZ_en +What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_en +What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_en +What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_en +What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_en What: /sys/.../iio:deviceX/scan_elements/in_incli_x_en What: /sys/.../iio:deviceX/scan_elements/in_incli_y_en What: /sys/.../iio:deviceX/scan_elements/in_pressureY_en @@ -1064,6 +1095,10 @@ What: /sys/.../iio:deviceX/scan_elements/in_incli_type What: /sys/.../iio:deviceX/scan_elements/in_voltageY_type What: /sys/.../iio:deviceX/scan_elements/in_voltage_type What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_type +What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_type +What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_type +What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_type +What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_type What: /sys/.../iio:deviceX/scan_elements/in_timestamp_type What: /sys/.../iio:deviceX/scan_elements/in_pressureY_type What: /sys/.../iio:deviceX/scan_elements/in_pressure_type @@ -1101,6 +1136,10 @@ Description: What: /sys/.../iio:deviceX/scan_elements/in_voltageY_index What: /sys/.../iio:deviceX/scan_elements/in_voltageY_supply_index +What: /sys/.../iio:deviceX/scan_elements/in_voltageY_i_index +What: /sys/.../iio:deviceX/scan_elements/in_voltageY_q_index +What: /sys/.../iio:deviceX/scan_elements/in_voltage_i_index +What: /sys/.../iio:deviceX/scan_elements/in_voltage_q_index What: /sys/.../iio:deviceX/scan_elements/in_accel_x_index What: /sys/.../iio:deviceX/scan_elements/in_accel_y_index What: /sys/.../iio:deviceX/scan_elements/in_accel_z_index @@ -1260,6 +1299,8 @@ Description: or without compensation from tilt sensors. What: /sys/bus/iio/devices/iio:deviceX/in_currentX_raw +What: /sys/bus/iio/devices/iio:deviceX/in_currentX_i_raw +What: /sys/bus/iio/devices/iio:deviceX/in_currentX_q_raw KernelVersion: 3.18 Contact: linux-iio@vger.kernel.org Description: @@ -1268,6 +1309,11 @@ Description: present, output should be considered as processed with the unit in milliamps. + Channels with 'i' and 'q' modifiers always exist in pairs and both + channels refer to the same signal. The 'i' channel contains the in-phase + component of the signal while the 'q' channel contains the quadrature + component. + What: /sys/.../iio:deviceX/in_energy_en What: /sys/.../iio:deviceX/in_distance_en What: /sys/.../iio:deviceX/in_velocity_sqrt(x^2+y^2+z^2)_en diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 9688a88b6198..3524b0de8721 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -101,6 +101,8 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_WALKING] = "walking", [IIO_MOD_STILL] = "still", [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)", + [IIO_MOD_I] = "i", + [IIO_MOD_Q] = "q", }; /* relies on pairs of these shared then separate */ diff --git a/include/uapi/linux/iio/types.h b/include/uapi/linux/iio/types.h index 5c4601935005..2f8b11722204 100644 --- a/include/uapi/linux/iio/types.h +++ b/include/uapi/linux/iio/types.h @@ -70,6 +70,8 @@ enum iio_modifier { IIO_MOD_WALKING, IIO_MOD_STILL, IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z, + IIO_MOD_I, + IIO_MOD_Q, }; enum iio_event_type { -- cgit v1.2.3 From 2a67dfba7fae36af0233452d19b40594f62bc019 Mon Sep 17 00:00:00 2001 From: Urs Fässler Date: Mon, 18 May 2015 15:22:44 +0200 Subject: iio:adc128s052: add support for adc122s021 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Urs Fässler Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/ti-adc128s052.txt | 4 +-- drivers/iio/adc/Kconfig | 4 +-- drivers/iio/adc/ti-adc128s052.c | 30 +++++++++++++++++----- 3 files changed, 28 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt index 42ca7deec97d..15ca6b47958e 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt +++ b/Documentation/devicetree/bindings/iio/adc/ti-adc128s052.txt @@ -1,7 +1,7 @@ -* Texas Instruments' ADC128S052 ADC chip +* Texas Instruments' ADC128S052 and ADC122S021 ADC chip Required properties: - - compatible: Should be "ti,adc128s052" + - compatible: Should be "ti,adc128s052" or "ti,adc122s021" - reg: spi chip select number for the device - vref-supply: The regulator supply for ADC reference voltage diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index cee50de76fb1..7c5565891cb8 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -292,11 +292,11 @@ config TI_ADC081C called ti-adc081c. config TI_ADC128S052 - tristate "Texas Instruments ADC128S052" + tristate "Texas Instruments ADC128S052/ADC122S021" depends on SPI help If you say yes here you get support for Texas Instruments ADC128S052 - chip. + and ADC122S021 chips. This driver can also be built as a module. If so, the module will be called ti-adc128s052. diff --git a/drivers/iio/adc/ti-adc128s052.c b/drivers/iio/adc/ti-adc128s052.c index 655cb564ec54..915be6b60097 100644 --- a/drivers/iio/adc/ti-adc128s052.c +++ b/drivers/iio/adc/ti-adc128s052.c @@ -1,9 +1,10 @@ /* * Copyright (C) 2014 Angelo Compagnucci * - * Driver for Texas Instruments' ADC128S052 ADC chip. - * Datasheet can be found here: + * Driver for Texas Instruments' ADC128S052 and ADC122S021 ADC chip. + * Datasheets can be found here: * http://www.ti.com/lit/ds/symlink/adc128s052.pdf + * http://www.ti.com/lit/ds/symlink/adc122s021.pdf * * 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 @@ -16,6 +17,11 @@ #include #include +struct adc128_configuration { + const struct iio_chan_spec *channels; + u8 num_channels; +}; + struct adc128 { struct spi_device *spi; @@ -92,7 +98,7 @@ static int adc128_read_raw(struct iio_dev *indio_dev, .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ } -static const struct iio_chan_spec adc128_channels[] = { +static const struct iio_chan_spec adc128s052_channels[] = { ADC128_VOLTAGE_CHANNEL(0), ADC128_VOLTAGE_CHANNEL(1), ADC128_VOLTAGE_CHANNEL(2), @@ -103,6 +109,16 @@ static const struct iio_chan_spec adc128_channels[] = { ADC128_VOLTAGE_CHANNEL(7), }; +static const struct iio_chan_spec adc122s021_channels[] = { + ADC128_VOLTAGE_CHANNEL(0), + ADC128_VOLTAGE_CHANNEL(1), +}; + +static const struct adc128_configuration adc128_config[] = { + { adc128s052_channels, ARRAY_SIZE(adc128s052_channels) }, + { adc122s021_channels, ARRAY_SIZE(adc122s021_channels) }, +}; + static const struct iio_info adc128_info = { .read_raw = adc128_read_raw, .driver_module = THIS_MODULE, @@ -112,6 +128,7 @@ static int adc128_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct adc128 *adc; + int config = spi_get_device_id(spi)->driver_data; int ret; indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); @@ -128,8 +145,8 @@ static int adc128_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &adc128_info; - indio_dev->channels = adc128_channels; - indio_dev->num_channels = ARRAY_SIZE(adc128_channels); + indio_dev->channels = adc128_config[config].channels; + indio_dev->num_channels = adc128_config[config].num_channels; adc->reg = devm_regulator_get(&spi->dev, "vref"); if (IS_ERR(adc->reg)) @@ -158,7 +175,8 @@ static int adc128_remove(struct spi_device *spi) } static const struct spi_device_id adc128_id[] = { - { "adc128s052", 0}, + { "adc128s052", 0}, /* index into adc128_config */ + { "adc122s021", 1}, { } }; MODULE_DEVICE_TABLE(spi, adc128_id); -- cgit v1.2.3 From bf04c1a367e3d52b2e071cc7c7047c27dc1c3c5f Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Wed, 27 May 2015 14:47:51 +0200 Subject: iio: adc: vf610: implement configurable conversion modes Support configurable conversion mode through sysfs. So far, the mode used was low-power, which is enabled by default now. Beside that, the modes normal and high-speed are selectable as well. Use the new device tree property which specifies the maximum ADC conversion clock frequencies. Depending on the mode used, the available resulting conversion frequency are calculated dynamically. Acked-by: Fugang Duan Signed-off-by: Stefan Agner Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-vf610 | 7 + .../devicetree/bindings/iio/adc/vf610-adc.txt | 9 ++ drivers/iio/adc/vf610_adc.c | 146 +++++++++++++++------ 3 files changed, 120 insertions(+), 42 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-vf610 (limited to 'Documentation') diff --git a/Documentation/ABI/testing/sysfs-bus-iio-vf610 b/Documentation/ABI/testing/sysfs-bus-iio-vf610 new file mode 100644 index 000000000000..ecbc1f4af921 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-vf610 @@ -0,0 +1,7 @@ +What: /sys/bus/iio/devices/iio:deviceX/conversion_mode +KernelVersion: 4.2 +Contact: linux-iio@vger.kernel.org +Description: + Specifies the hardware conversion mode used. The three + available modes are "normal", "high-speed" and "low-power", + where the last is the default mode. diff --git a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt index 1a4a43d5c9ea..3eb40e20c143 100644 --- a/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/vf610-adc.txt @@ -11,6 +11,13 @@ Required properties: - clock-names: Must contain "adc", matching entry in the clocks property. - vref-supply: The regulator supply ADC reference voltage. +Recommended properties: +- fsl,adck-max-frequency: Maximum frequencies according to datasheets operating + requirements. Three values are required, depending on conversion mode: + - Frequency in normal mode (ADLPC=0, ADHSC=0) + - Frequency in high-speed mode (ADLPC=0, ADHSC=1) + - Frequency in low-power mode (ADLPC=1, ADHSC=0) + Example: adc0: adc@4003b000 { compatible = "fsl,vf610-adc"; @@ -18,5 +25,7 @@ adc0: adc@4003b000 { interrupts = <0 53 0x04>; clocks = <&clks VF610_CLK_ADC0>; clock-names = "adc"; + fsl,adck-max-frequency = <30000000>, <40000000>, + <20000000>; vref-supply = <®_vcc_3v3_mcu>; }; diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 56292ae4538d..480f335a0f9f 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -118,15 +118,21 @@ enum average_sel { VF610_ADC_SAMPLE_32, }; +enum conversion_mode_sel { + VF610_ADC_CONV_NORMAL, + VF610_ADC_CONV_HIGH_SPEED, + VF610_ADC_CONV_LOW_POWER, +}; + struct vf610_adc_feature { enum clk_sel clk_sel; enum vol_ref vol_ref; + enum conversion_mode_sel conv_mode; int clk_div; int sample_rate; int res_mode; - bool lpm; bool calibration; bool ovwren; }; @@ -139,6 +145,8 @@ struct vf610_adc { u32 vref_uv; u32 value; struct regulator *vref; + + u32 max_adck_rate[3]; struct vf610_adc_feature adc_feature; u32 sample_freq_avail[5]; @@ -148,46 +156,22 @@ struct vf610_adc { static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; -#define VF610_ADC_CHAN(_idx, _chan_type) { \ - .type = (_chan_type), \ - .indexed = 1, \ - .channel = (_idx), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ - BIT(IIO_CHAN_INFO_SAMP_FREQ), \ -} - -#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \ - .type = (_chan_type), \ - .channel = (_idx), \ - .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ -} - -static const struct iio_chan_spec vf610_adc_iio_channels[] = { - VF610_ADC_CHAN(0, IIO_VOLTAGE), - VF610_ADC_CHAN(1, IIO_VOLTAGE), - VF610_ADC_CHAN(2, IIO_VOLTAGE), - VF610_ADC_CHAN(3, IIO_VOLTAGE), - VF610_ADC_CHAN(4, IIO_VOLTAGE), - VF610_ADC_CHAN(5, IIO_VOLTAGE), - VF610_ADC_CHAN(6, IIO_VOLTAGE), - VF610_ADC_CHAN(7, IIO_VOLTAGE), - VF610_ADC_CHAN(8, IIO_VOLTAGE), - VF610_ADC_CHAN(9, IIO_VOLTAGE), - VF610_ADC_CHAN(10, IIO_VOLTAGE), - VF610_ADC_CHAN(11, IIO_VOLTAGE), - VF610_ADC_CHAN(12, IIO_VOLTAGE), - VF610_ADC_CHAN(13, IIO_VOLTAGE), - VF610_ADC_CHAN(14, IIO_VOLTAGE), - VF610_ADC_CHAN(15, IIO_VOLTAGE), - VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP), - /* sentinel */ -}; - 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); - int i; + int divisor, i; + + adck_rate = info->max_adck_rate[adc_feature->conv_mode]; + + if (adck_rate) { + /* calculate clk divider which is within specification */ + divisor = ipg_rate / adck_rate; + adc_feature->clk_div = 1 << fls(divisor + 1); + } else { + /* fall-back value using a safe divisor */ + adc_feature->clk_div = 8; + } /* * Calculate ADC sample frequencies @@ -219,10 +203,8 @@ static inline void vf610_adc_cfg_init(struct vf610_adc *info) adc_feature->res_mode = 12; adc_feature->sample_rate = 1; - adc_feature->lpm = true; - /* Use a save ADCK which is below 20MHz on all devices */ - adc_feature->clk_div = 8; + adc_feature->conv_mode = VF610_ADC_CONV_LOW_POWER; vf610_adc_calculate_rates(info); } @@ -304,10 +286,12 @@ static void vf610_adc_cfg_set(struct vf610_adc *info) cfg_data = readl(info->regs + VF610_REG_ADC_CFG); cfg_data &= ~VF610_ADC_ADLPC_EN; - if (adc_feature->lpm) + if (adc_feature->conv_mode == VF610_ADC_CONV_LOW_POWER) cfg_data |= VF610_ADC_ADLPC_EN; cfg_data &= ~VF610_ADC_ADHSC_EN; + if (adc_feature->conv_mode == VF610_ADC_CONV_HIGH_SPEED) + cfg_data |= VF610_ADC_ADHSC_EN; writel(cfg_data, info->regs + VF610_REG_ADC_CFG); } @@ -409,6 +393,81 @@ static void vf610_adc_hw_init(struct vf610_adc *info) vf610_adc_cfg_set(info); } +static int vf610_set_conversion_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct vf610_adc *info = iio_priv(indio_dev); + + mutex_lock(&indio_dev->mlock); + info->adc_feature.conv_mode = mode; + vf610_adc_calculate_rates(info); + vf610_adc_hw_init(info); + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +static int vf610_get_conversion_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct vf610_adc *info = iio_priv(indio_dev); + + return info->adc_feature.conv_mode; +} + +static const char * const vf610_conv_modes[] = { "normal", "high-speed", + "low-power" }; + +static const struct iio_enum vf610_conversion_mode = { + .items = vf610_conv_modes, + .num_items = ARRAY_SIZE(vf610_conv_modes), + .get = vf610_get_conversion_mode, + .set = vf610_set_conversion_mode, +}; + +static const struct iio_chan_spec_ext_info vf610_ext_info[] = { + IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR, &vf610_conversion_mode), + {}, +}; + +#define VF610_ADC_CHAN(_idx, _chan_type) { \ + .type = (_chan_type), \ + .indexed = 1, \ + .channel = (_idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .ext_info = vf610_ext_info, \ +} + +#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \ + .type = (_chan_type), \ + .channel = (_idx), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ +} + +static const struct iio_chan_spec vf610_adc_iio_channels[] = { + VF610_ADC_CHAN(0, IIO_VOLTAGE), + VF610_ADC_CHAN(1, IIO_VOLTAGE), + VF610_ADC_CHAN(2, IIO_VOLTAGE), + VF610_ADC_CHAN(3, IIO_VOLTAGE), + VF610_ADC_CHAN(4, IIO_VOLTAGE), + VF610_ADC_CHAN(5, IIO_VOLTAGE), + VF610_ADC_CHAN(6, IIO_VOLTAGE), + VF610_ADC_CHAN(7, IIO_VOLTAGE), + VF610_ADC_CHAN(8, IIO_VOLTAGE), + VF610_ADC_CHAN(9, IIO_VOLTAGE), + VF610_ADC_CHAN(10, IIO_VOLTAGE), + VF610_ADC_CHAN(11, IIO_VOLTAGE), + VF610_ADC_CHAN(12, IIO_VOLTAGE), + VF610_ADC_CHAN(13, IIO_VOLTAGE), + VF610_ADC_CHAN(14, IIO_VOLTAGE), + VF610_ADC_CHAN(15, IIO_VOLTAGE), + VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP), + /* sentinel */ +}; + static int vf610_adc_read_data(struct vf610_adc *info) { int result; @@ -651,6 +710,9 @@ static int vf610_adc_probe(struct platform_device *pdev) info->vref_uv = regulator_get_voltage(info->vref); + of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency", + info->max_adck_rate, 3); + platform_set_drvdata(pdev, indio_dev); init_completion(&info->completion); -- cgit v1.2.3 From bbf5f037fad47e4affef6696aaf88a40b261e639 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 May 2015 15:37:18 +0200 Subject: iio: st_accel: support the LIS331DL sensor This adds support for the LIS331DL sensor version. This is a simple 8bit-only accelerometer. Signed-off-by: Linus Walleij Acked-by: Denis Ciocca Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/st-sensors.txt | 1 + drivers/iio/accel/st_accel.h | 1 + drivers/iio/accel/st_accel_core.c | 70 ++++++++++++++++++++++ drivers/iio/accel/st_accel_i2c.c | 4 ++ 4 files changed, 76 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/iio/st-sensors.txt b/Documentation/devicetree/bindings/iio/st-sensors.txt index fb5e0c2d18b5..8a6be3bdf267 100644 --- a/Documentation/devicetree/bindings/iio/st-sensors.txt +++ b/Documentation/devicetree/bindings/iio/st-sensors.txt @@ -30,6 +30,7 @@ Accelerometers: - st,lsm330d-accel - st,lsm330dl-accel - st,lsm330dlc-accel +- st,lis331dl-accel - st,lis331dlh-accel - st,lsm303dl-accel - st,lsm303dlm-accel diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 7ee9724b1428..aa1001931d0c 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -20,6 +20,7 @@ #define LSM330D_ACCEL_DEV_NAME "lsm330d_accel" #define LSM330DL_ACCEL_DEV_NAME "lsm330dl_accel" #define LSM330DLC_ACCEL_DEV_NAME "lsm330dlc_accel" +#define LIS331DL_ACCEL_DEV_NAME "lis331dl_accel" #define LIS331DLH_ACCEL_DEV_NAME "lis331dlh" #define LSM303DL_ACCEL_DEV_NAME "lsm303dl_accel" #define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel" diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index ad19fb4304df..970e9f904dde 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -153,6 +153,28 @@ #define ST_ACCEL_4_IG1_EN_MASK 0x08 #define ST_ACCEL_4_MULTIREAD_BIT true +/* CUSTOM VALUES FOR SENSOR 5 */ +#define ST_ACCEL_5_WAI_EXP 0x3b +#define ST_ACCEL_5_ODR_ADDR 0x20 +#define ST_ACCEL_5_ODR_MASK 0x80 +#define ST_ACCEL_5_ODR_AVL_100HZ_VAL 0x00 +#define ST_ACCEL_5_ODR_AVL_400HZ_VAL 0x01 +#define ST_ACCEL_5_PW_ADDR 0x20 +#define ST_ACCEL_5_PW_MASK 0x40 +#define ST_ACCEL_5_FS_ADDR 0x20 +#define ST_ACCEL_5_FS_MASK 0x20 +#define ST_ACCEL_5_FS_AVL_2_VAL 0X00 +#define ST_ACCEL_5_FS_AVL_8_VAL 0X01 +/* TODO: check these resulting gain settings, these are not in the datsheet */ +#define ST_ACCEL_5_FS_AVL_2_GAIN IIO_G_TO_M_S_2(18000) +#define ST_ACCEL_5_FS_AVL_8_GAIN IIO_G_TO_M_S_2(72000) +#define ST_ACCEL_5_DRDY_IRQ_ADDR 0x22 +#define ST_ACCEL_5_DRDY_IRQ_INT1_MASK 0x04 +#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK 0x20 +#define ST_ACCEL_5_IG1_EN_ADDR 0x21 +#define ST_ACCEL_5_IG1_EN_MASK 0x08 +#define ST_ACCEL_5_MULTIREAD_BIT false + static const struct iio_chan_spec st_accel_8bit_channels[] = { ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), @@ -470,6 +492,54 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT, .bootime = 2, /* guess */ }, + { + .wai = ST_ACCEL_5_WAI_EXP, + .sensors_supported = { + [0] = LIS331DL_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_8bit_channels, + .odr = { + .addr = ST_ACCEL_5_ODR_ADDR, + .mask = ST_ACCEL_5_ODR_MASK, + .odr_avl = { + { 100, ST_ACCEL_5_ODR_AVL_100HZ_VAL }, + { 400, ST_ACCEL_5_ODR_AVL_400HZ_VAL, }, + }, + }, + .pw = { + .addr = ST_ACCEL_5_PW_ADDR, + .mask = ST_ACCEL_5_PW_MASK, + .value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = ST_ACCEL_5_FS_ADDR, + .mask = ST_ACCEL_5_FS_MASK, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = ST_ACCEL_5_FS_AVL_2_VAL, + .gain = ST_ACCEL_5_FS_AVL_2_GAIN, + }, + [1] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = ST_ACCEL_5_FS_AVL_8_VAL, + .gain = ST_ACCEL_5_FS_AVL_8_GAIN, + }, + }, + }, + .drdy_irq = { + .addr = ST_ACCEL_5_DRDY_IRQ_ADDR, + .mask_int1 = ST_ACCEL_5_DRDY_IRQ_INT1_MASK, + .mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK, + }, + .multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT, + .bootime = 2, /* guess */ + }, }; static int st_accel_read_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 6b720c190b2d..d4ad72ca4a3d 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -48,6 +48,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lsm330dlc-accel", .data = LSM330DLC_ACCEL_DEV_NAME, }, + { + .compatible = "st,lis331dl-accel", + .data = LIS331DL_ACCEL_DEV_NAME, + }, { .compatible = "st,lis331dlh-accel", .data = LIS331DLH_ACCEL_DEV_NAME, -- cgit v1.2.3 From c5ab1f7faaba2d7f30f87bea2f0b5cf4b958fd2f Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Thu, 28 May 2015 15:06:58 +0300 Subject: Documentation: mention vme_master_mmap() in VME API Signed-off-by: Dmitry Kalinkin Cc: Igor Alekseev Signed-off-by: Greg Kroah-Hartman --- Documentation/vme_api.txt | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt index ffe6e22a2ccd..ca5b82797f6c 100644 --- a/Documentation/vme_api.txt +++ b/Documentation/vme_api.txt @@ -171,6 +171,12 @@ This functions by reading the offset, applying the mask. If the bits selected in the mask match with the values of the corresponding bits in the compare field, the value of swap is written the specified offset. +Parts of a VME window can be mapped into user space memory using the following +function: + + int vme_master_mmap(struct vme_resource *resource, + struct vm_area_struct *vma) + Slave windows ============= -- cgit v1.2.3