From 6c0690ecb682c94b958e0328c46bfcfd95c7698c Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Wed, 5 Mar 2014 11:57:00 +0000 Subject: iio: Add ABI documentation for proximity has been in use for a long time, but never documented proximity is unit-less, except otherwise stated, see e.g. the as3935 driver where it is meter Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index a9757dcf2e8..738b56f862b 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -895,6 +895,19 @@ Description: on-chip EEPROM. After power-up or chip reset the device will automatically load the saved configuration. +What: /sys/.../iio:deviceX/in_proximity_raw +What: /sys/.../iio:deviceX/in_proximity_input +What: /sys/.../iio:deviceX/in_proximityY_raw +KernelVersion: 3.4 +Contact: linux-iio@vger.kernel.org +Description: + Proximity measurement indicating that some + object is near the sensor, usually be observing + reflectivity of infrared or ultrasound emitted. + Often these sensors are unit less and as such conversion + to SI units is not possible. Where it is, the units should + be meters. + What: /sys/.../iio:deviceX/in_illuminanceY_input What: /sys/.../iio:deviceX/in_illuminanceY_raw What: /sys/.../iio:deviceX/in_illuminanceY_mean_raw -- cgit v1.2.3-70-g09d2 From a2d8be6823017ccdde8db8b0f4fbe6a29580dd40 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Thu, 6 Feb 2014 20:44:00 +0000 Subject: iio: Add t5403 barometric pressure sensor driver 16-bit pressure and temperature sensor the chip can do I2C and SPI, only the I2C interface is supported by the driver at the moment datasheet: http://www.epcos.com/inf/57/ds/T5400.pdf application note: http://www.epcos.com/blob/993154/download/1/t5403-applicationnote.pdf an out-of-tree driver targetting the input subsystem is at https://github.com/unixphere/t5400, it was rejected here: http://comments.gmane.org/gmane.linux.kernel.input/28107 v2: (thanks Hartmut Knaack) * fix MODE_HIGH, equals 2 * check INT_TIME mask in write_raw() Signed-off-by: Peter Meerwald Cc: Stefan Nilsson Reviewed-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 10 ++ drivers/iio/pressure/Makefile | 1 + drivers/iio/pressure/t5403.c | 275 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 286 insertions(+) create mode 100644 drivers/iio/pressure/t5403.c diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index ffac8ac1efc..15afbc91952 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -70,4 +70,14 @@ config IIO_ST_PRESS_SPI depends on IIO_ST_PRESS depends on IIO_ST_SENSORS_SPI +config T5403 + tristate "EPCOS T5403 digital barometric pressure sensor driver" + depends on I2C + help + Say yes here to build support for the EPCOS T5403 pressure sensor + connected via I2C. + + To compile this driver as a module, choose M here: the module + will be called t5403. + endmenu diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index c53d2500737..90a37e85cf2 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_MPL3115) += mpl3115.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o +obj-$(CONFIG_T5403) += t5403.o obj-$(CONFIG_IIO_ST_PRESS_I2C) += st_pressure_i2c.o obj-$(CONFIG_IIO_ST_PRESS_SPI) += st_pressure_spi.o diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c new file mode 100644 index 00000000000..e11cd3938d6 --- /dev/null +++ b/drivers/iio/pressure/t5403.c @@ -0,0 +1,275 @@ +/* + * t5403.c - Support for EPCOS T5403 pressure/temperature sensor + * + * Copyright (c) 2014 Peter Meerwald + * + * This file is subject to the terms and conditions of version 2 of + * the GNU General Public License. See the file COPYING in the main + * directory of this archive for more details. + * + * (7-bit I2C slave address 0x77) + * + * TODO: end-of-conversion irq + */ + +#include +#include +#include +#include +#include + +#define T5403_DATA 0xf5 /* data, LSB first, 16 bit */ +#define T5403_CALIB_DATA 0x8e /* 10 calibration coeff., LSB first, 16 bit */ +#define T5403_SLAVE_ADDR 0x88 /* I2C slave address, 0x77 */ +#define T5403_COMMAND 0xf1 + +/* command bits */ +#define T5403_MODE_SHIFT 3 /* conversion time: 2, 8, 16, 66 ms */ +#define T5403_PT BIT(1) /* 0 .. pressure, 1 .. temperature measurement */ +#define T5403_SCO BIT(0) /* start conversion */ + +#define T5403_MODE_LOW 0 +#define T5403_MODE_STANDARD 1 +#define T5403_MODE_HIGH 2 +#define T5403_MODE_ULTRA_HIGH 3 + +#define T5403_I2C_MASK (~BIT(7)) +#define T5403_I2C_ADDR 0x77 + +static const int t5403_pressure_conv_ms[] = {2, 8, 16, 66}; + +struct t5403_data { + struct i2c_client *client; + struct mutex lock; + int mode; + __le16 c[10]; +}; + +#define T5403_C_U16(i) le16_to_cpu(data->c[(i) - 1]) +#define T5403_C(i) sign_extend32(T5403_C_U16(i), 15) + +static int t5403_read(struct t5403_data *data, bool pressure) +{ + int wait_time = 3; /* wakeup time in ms */ + + int ret = i2c_smbus_write_byte_data(data->client, T5403_COMMAND, + (pressure ? (data->mode << T5403_MODE_SHIFT) : T5403_PT) | + T5403_SCO); + if (ret < 0) + return ret; + + wait_time += pressure ? t5403_pressure_conv_ms[data->mode] : 2; + + msleep(wait_time); + + return i2c_smbus_read_word_data(data->client, T5403_DATA); +} + +static int t5403_comp_pressure(struct t5403_data *data, int *val, int *val2) +{ + int ret; + s16 t_r; + u16 p_r; + s32 S, O, X; + + mutex_lock(&data->lock); + + ret = t5403_read(data, false); + if (ret < 0) + goto done; + t_r = ret; + + ret = t5403_read(data, true); + if (ret < 0) + goto done; + p_r = ret; + + /* see EPCOS application note */ + S = T5403_C_U16(3) + (s32) T5403_C_U16(4) * t_r / 0x20000 + + T5403_C(5) * t_r / 0x8000 * t_r / 0x80000 + + T5403_C(9) * t_r / 0x8000 * t_r / 0x8000 * t_r / 0x10000; + + O = T5403_C(6) * 0x4000 + T5403_C(7) * t_r / 8 + + T5403_C(8) * t_r / 0x8000 * t_r / 16 + + T5403_C(9) * t_r / 0x8000 * t_r / 0x10000 * t_r; + + X = (S * p_r + O) / 0x4000; + + X += ((X - 75000) * (X - 75000) / 0x10000 - 9537) * + T5403_C(10) / 0x10000; + + *val = X / 1000; + *val2 = (X % 1000) * 1000; + +done: + mutex_unlock(&data->lock); + return ret; +} + +static int t5403_comp_temp(struct t5403_data *data, int *val) +{ + int ret; + s16 t_r; + + mutex_lock(&data->lock); + ret = t5403_read(data, false); + if (ret < 0) + goto done; + t_r = ret; + + /* see EPCOS application note */ + *val = ((s32) T5403_C_U16(1) * t_r / 0x100 + + (s32) T5403_C_U16(2) * 0x40) * 1000 / 0x10000; + +done: + mutex_unlock(&data->lock); + return ret; +} + +static int t5403_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct t5403_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_PRESSURE: + ret = t5403_comp_pressure(data, val, val2); + if (ret < 0) + return ret; + return IIO_VAL_INT_PLUS_MICRO; + case IIO_TEMP: + ret = t5403_comp_temp(data, val); + if (ret < 0) + return ret; + return IIO_VAL_INT; + default: + return -EINVAL; + } + case IIO_CHAN_INFO_INT_TIME: + *val = 0; + *val2 = t5403_pressure_conv_ms[data->mode] * 1000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int t5403_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct t5403_data *data = iio_priv(indio_dev); + int i; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + if (val != 0) + return -EINVAL; + for (i = 0; i < ARRAY_SIZE(t5403_pressure_conv_ms); i++) + if (val2 == t5403_pressure_conv_ms[i] * 1000) { + mutex_lock(&data->lock); + data->mode = i; + mutex_unlock(&data->lock); + return 0; + } + return -EINVAL; + default: + return -EINVAL; + } +} + +static const struct iio_chan_spec t5403_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_INT_TIME), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + }, +}; + +static IIO_CONST_ATTR_INT_TIME_AVAIL("0.002 0.008 0.016 0.066"); + +static struct attribute *t5403_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group t5403_attribute_group = { + .attrs = t5403_attributes, +}; + +static const struct iio_info t5403_info = { + .read_raw = &t5403_read_raw, + .write_raw = &t5403_write_raw, + .attrs = &t5403_attribute_group, + .driver_module = THIS_MODULE, +}; + +static int t5403_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct t5403_data *data; + struct iio_dev *indio_dev; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) + return -ENODEV; + + ret = i2c_smbus_read_byte_data(client, T5403_SLAVE_ADDR); + if (ret < 0) + return ret; + if ((ret & T5403_I2C_MASK) != T5403_I2C_ADDR) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->lock); + + i2c_set_clientdata(client, indio_dev); + indio_dev->info = &t5403_info; + indio_dev->name = id->name; + indio_dev->dev.parent = &client->dev; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = t5403_channels; + indio_dev->num_channels = ARRAY_SIZE(t5403_channels); + + data->mode = T5403_MODE_STANDARD; + + ret = i2c_smbus_read_i2c_block_data(data->client, T5403_CALIB_DATA, + sizeof(data->c), (u8 *) data->c); + if (ret < 0) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id t5403_id[] = { + { "t5403", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, t5403_id); + +static struct i2c_driver t5403_driver = { + .driver = { + .name = "t5403", + }, + .probe = t5403_probe, + .id_table = t5403_id, +}; +module_i2c_driver(t5403_driver); + +MODULE_AUTHOR("Peter Meerwald "); +MODULE_DESCRIPTION("EPCOS T5403 pressure/temperature sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From a3eeb1591a464308f2d0cda183cc5d5d270d5b2e Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 05:54:00 +0000 Subject: iio:adc:ad799x: Fix ad799x_chip_info kerneldoc Signed-off-by: Peter Meerwald Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad799x.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c index 39b4cb48d73..7e08c601f66 100644 --- a/drivers/iio/adc/ad799x.c +++ b/drivers/iio/adc/ad799x.c @@ -105,9 +105,8 @@ enum { * struct ad799x_chip_info - chip specific information * @channel: channel specification * @num_channels: number of channels - * @monitor_mode: whether the chip supports monitor interrupts * @default_config: device default configuration - * @event_attrs: pointer to the monitor event attribute group + * @info: pointer to iio_info struct */ struct ad799x_chip_info { struct iio_chan_spec channel[9]; -- cgit v1.2.3-70-g09d2 From ff96bf519acdb3b99f9bfe07667a9020d5015395 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: iio:adc:ad5791: Use BIT() and GENMASK() macros Signed-off-by: Peter Meerwald Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5791.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index ae49afe2b38..5ba785f1858 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -16,17 +16,16 @@ #include #include #include +#include #include #include #include -#define AD5791_RES_MASK(x) ((1 << (x)) - 1) -#define AD5791_DAC_MASK AD5791_RES_MASK(20) -#define AD5791_DAC_MSB (1 << 19) +#define AD5791_DAC_MASK GENMASK(19, 0) -#define AD5791_CMD_READ (1 << 23) -#define AD5791_CMD_WRITE (0 << 23) +#define AD5791_CMD_READ BIT(23) +#define AD5791_CMD_WRITE 0 #define AD5791_ADDR(addr) ((addr) << 20) /* Registers */ @@ -37,11 +36,11 @@ #define AD5791_ADDR_SW_CTRL 4 /* Control Register */ -#define AD5791_CTRL_RBUF (1 << 1) -#define AD5791_CTRL_OPGND (1 << 2) -#define AD5791_CTRL_DACTRI (1 << 3) -#define AD5791_CTRL_BIN2SC (1 << 4) -#define AD5791_CTRL_SDODIS (1 << 5) +#define AD5791_CTRL_RBUF BIT(1) +#define AD5791_CTRL_OPGND BIT(2) +#define AD5791_CTRL_DACTRI BIT(3) +#define AD5791_CTRL_BIN2SC BIT(4) +#define AD5791_CTRL_SDODIS BIT(5) #define AD5761_CTRL_LINCOMP(x) ((x) << 6) #define AD5791_LINCOMP_0_10 0 @@ -54,9 +53,9 @@ #define AD5780_LINCOMP_10_20 12 /* Software Control Register */ -#define AD5791_SWCTRL_LDAC (1 << 0) -#define AD5791_SWCTRL_CLR (1 << 1) -#define AD5791_SWCTRL_RESET (1 << 2) +#define AD5791_SWCTRL_LDAC BIT(0) +#define AD5791_SWCTRL_CLR BIT(1) +#define AD5791_SWCTRL_RESET BIT(2) #define AD5791_DAC_PWRDN_6K 0 #define AD5791_DAC_PWRDN_3STATE 1 @@ -72,7 +71,7 @@ struct ad5791_chip_info { /** * struct ad5791_state - driver instance specific data - * @us: spi_device + * @spi: spi_device * @reg_vdd: positive supply regulator * @reg_vss: negative supply regulator * @chip_info: chip model specific constants @@ -328,7 +327,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - val &= AD5791_RES_MASK(chan->scan_type.realbits); + val &= GENMASK(chan->scan_type.realbits - 1, 0); val <<= chan->scan_type.shift; return ad5791_spi_write(st, chan->address, val); -- cgit v1.2.3-70-g09d2 From a476bc02eb4365d02ac71f20b5034e2437691e3f Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: iio:adc:ad5504: Use BIT() and GENMASK() macros Signed-off-by: Peter Meerwald Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5504.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index 1e6449346b5..c917dd24090 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -15,17 +15,16 @@ #include #include #include +#include #include #include #include #include -#define AD5505_BITS 12 -#define AD5504_RES_MASK ((1 << (AD5505_BITS)) - 1) - -#define AD5504_CMD_READ (1 << 15) -#define AD5504_CMD_WRITE (0 << 15) +#define AD5504_RES_MASK GENMASK(11, 0) +#define AD5504_CMD_READ BIT(15) +#define AD5504_CMD_WRITE 0 #define AD5504_ADDR(addr) ((addr) << 12) /* Registers */ @@ -42,7 +41,7 @@ /** * struct ad5446_state - driver instance specific data - * @us: spi_device + * @spi: spi_device * @reg: supply regulator * @vref_mv: actual reference voltage used * @pwr_down_mask power down mask -- cgit v1.2.3-70-g09d2 From 09a1737e5509aff28346a7225a2eae35d1c5962f Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: iio:adc:ad7887: Use BIT() and GENMASK() macros Signed-off-by: Peter Meerwald Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7887.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 749a6cadab8..2fd012ee99f 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -25,14 +26,14 @@ #include -#define AD7887_REF_DIS (1 << 5) /* on-chip reference disable */ -#define AD7887_DUAL (1 << 4) /* dual-channel mode */ -#define AD7887_CH_AIN1 (1 << 3) /* convert on channel 1, DUAL=1 */ -#define AD7887_CH_AIN0 (0 << 3) /* convert on channel 0, DUAL=0,1 */ -#define AD7887_PM_MODE1 (0) /* CS based shutdown */ -#define AD7887_PM_MODE2 (1) /* full on */ -#define AD7887_PM_MODE3 (2) /* auto shutdown after conversion */ -#define AD7887_PM_MODE4 (3) /* standby mode */ +#define AD7887_REF_DIS BIT(5) /* on-chip reference disable */ +#define AD7887_DUAL BIT(4) /* dual-channel mode */ +#define AD7887_CH_AIN1 BIT(3) /* convert on channel 1, DUAL=1 */ +#define AD7887_CH_AIN0 0 /* convert on channel 0, DUAL=0,1 */ +#define AD7887_PM_MODE1 0 /* CS based shutdown */ +#define AD7887_PM_MODE2 1 /* full on */ +#define AD7887_PM_MODE3 2 /* auto shutdown after conversion */ +#define AD7887_PM_MODE4 3 /* standby mode */ enum ad7887_channels { AD7887_CH0, @@ -40,8 +41,6 @@ enum ad7887_channels { AD7887_CH1, }; -#define RES_MASK(bits) ((1 << (bits)) - 1) - /** * struct ad7887_chip_info - chip specifc information * @int_vref_mv: the internal reference voltage @@ -167,7 +166,7 @@ static int ad7887_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; *val = ret >> chan->scan_type.shift; - *val &= RES_MASK(chan->scan_type.realbits); + *val &= GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (st->reg) { -- cgit v1.2.3-70-g09d2 From bc74fb8191c0405e17925473e940db65be1b80e7 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: iio:adc:ad7476: Use GENMASK() macro Signed-off-by: Peter Meerwald Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7476.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index d141d452c3d..ce400ec176f 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -21,8 +22,6 @@ #include #include -#define RES_MASK(bits) ((1 << (bits)) - 1) - struct ad7476_state; struct ad7476_chip_info { @@ -117,7 +116,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; *val = (ret >> st->chip_info->channel[0].scan_type.shift) & - RES_MASK(st->chip_info->channel[0].scan_type.realbits); + GENMASK(st->chip_info->channel[0].scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: if (!st->chip_info->int_vref_uv) { -- cgit v1.2.3-70-g09d2 From 488980532de968d4002262394817bf08709cab97 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: iio:adc:ad7298: Use BIT() and GENMASK() macros Signed-off-by: Peter Meerwald Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7298.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 2a3b65c74af..4a8c0a2f49b 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,23 +26,19 @@ #include -#define AD7298_WRITE (1 << 15) /* write to the control register */ -#define AD7298_REPEAT (1 << 14) /* repeated conversion enable */ -#define AD7298_CH(x) (1 << (13 - (x))) /* channel select */ -#define AD7298_TSENSE (1 << 5) /* temperature conversion enable */ -#define AD7298_EXTREF (1 << 2) /* external reference enable */ -#define AD7298_TAVG (1 << 1) /* temperature sensor averaging enable */ -#define AD7298_PDD (1 << 0) /* partial power down enable */ +#define AD7298_WRITE BIT(15) /* write to the control register */ +#define AD7298_REPEAT BIT(14) /* repeated conversion enable */ +#define AD7298_CH(x) BIT(13 - (x)) /* channel select */ +#define AD7298_TSENSE BIT(5) /* temperature conversion enable */ +#define AD7298_EXTREF BIT(2) /* external reference enable */ +#define AD7298_TAVG BIT(1) /* temperature sensor averaging enable */ +#define AD7298_PDD BIT(0) /* partial power down enable */ #define AD7298_MAX_CHAN 8 -#define AD7298_BITS 12 -#define AD7298_STORAGE_BITS 16 #define AD7298_INTREF_mV 2500 #define AD7298_CH_TEMP 9 -#define RES_MASK(bits) ((1 << (bits)) - 1) - struct ad7298_state { struct spi_device *spi; struct regulator *reg; @@ -257,7 +254,7 @@ static int ad7298_read_raw(struct iio_dev *indio_dev, return ret; if (chan->address != AD7298_CH_TEMP) - *val = ret & RES_MASK(AD7298_BITS); + *val = ret & GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: -- cgit v1.2.3-70-g09d2 From 2192c6f9496eec8b9c5c6084ee6c74f323f0297c Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: iio: Move documentation of iio-trig-sysfs to ABI/testing iio-trig-sysfs has left staging with commit e64e7d5c Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs | 11 +++++++++++ drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs delete mode 100644 drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs diff --git a/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs new file mode 100644 index 00000000000..5235e6c749a --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-iio-trigger-sysfs @@ -0,0 +1,11 @@ +What: /sys/bus/iio/devices/triggerX/trigger_now +KernelVersion: 2.6.38 +Contact: linux-iio@vger.kernel.org +Description: + This file is provided by the iio-trig-sysfs stand-alone trigger + driver. Writing this file with any value triggers an event + driven driver, associated with this trigger, to capture data + into an in kernel buffer. This approach can be valuable during + automated testing or in situations, where other trigger methods + are not applicable. For example no RTC or spare GPIOs. + X is the IIO index of the trigger. diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs b/drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs deleted file mode 100644 index 5235e6c749a..00000000000 --- a/drivers/staging/iio/Documentation/sysfs-bus-iio-trigger-sysfs +++ /dev/null @@ -1,11 +0,0 @@ -What: /sys/bus/iio/devices/triggerX/trigger_now -KernelVersion: 2.6.38 -Contact: linux-iio@vger.kernel.org -Description: - This file is provided by the iio-trig-sysfs stand-alone trigger - driver. Writing this file with any value triggers an event - driven driver, associated with this trigger, to capture data - into an in kernel buffer. This approach can be valuable during - automated testing or in situations, where other trigger methods - are not applicable. For example no RTC or spare GPIOs. - X is the IIO index of the trigger. -- cgit v1.2.3-70-g09d2 From 0378250b52ca3afb83257868448ef9d1efcbf607 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: staging:iio: Update iio_event_monitor program add types recently added Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Documentation/iio_event_monitor.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c index 3a9b0008740..cb35a97f00c 100644 --- a/drivers/staging/iio/Documentation/iio_event_monitor.c +++ b/drivers/staging/iio/Documentation/iio_event_monitor.c @@ -46,6 +46,9 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_TIMESTAMP] = "timestamp", [IIO_CAPACITANCE] = "capacitance", [IIO_ALTVOLTAGE] = "altvoltage", + [IIO_CCT] = "cct", + [IIO_PRESSURE] = "pressure", + [IIO_HUMIDITYRELATIVE] = "humidityrelative", }; static const char * const iio_ev_type_text[] = { @@ -70,6 +73,8 @@ static const char * const iio_modifier_names[] = { [IIO_MOD_LIGHT_IR] = "ir", [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", + [IIO_MOD_LIGHT_BOTH] = "both", + [IIO_MOD_LIGHT_IR] = "ir", [IIO_MOD_LIGHT_CLEAR] = "clear", [IIO_MOD_LIGHT_RED] = "red", [IIO_MOD_LIGHT_GREEN] = "green", @@ -100,6 +105,9 @@ static bool event_is_known(struct iio_event_data *event) case IIO_TIMESTAMP: case IIO_CAPACITANCE: case IIO_ALTVOLTAGE: + case IIO_CCT: + case IIO_PRESSURE: + case IIO_HUMIDITYRELATIVE: break; default: return false; @@ -114,6 +122,8 @@ static bool event_is_known(struct iio_event_data *event) case IIO_MOD_LIGHT_IR: case IIO_MOD_ROOT_SUM_SQUARED_X_Y: case IIO_MOD_SUM_SQUARED_X_Y_Z: + case IIO_MOD_LIGHT_BOTH: + case IIO_MOD_LIGHT_IR: case IIO_MOD_LIGHT_CLEAR: case IIO_MOD_LIGHT_RED: case IIO_MOD_LIGHT_GREEN: -- cgit v1.2.3-70-g09d2 From f5709d5fa966cceadc41d66117d7eed52425b67e Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: staging:iio: Fix iio_utils.h function prototypes Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Documentation/iio_utils.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index a9cfc06edb0..0973a092224 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -633,7 +633,7 @@ error_free: int read_sysfs_float(char *filename, char *basedir, float *val) { - float ret = 0; + int ret = 0; FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (temp == NULL) { @@ -653,9 +653,9 @@ error_free: return ret; } -read_sysfs_string(const char *filename, const char *basedir, char *str) +int read_sysfs_string(const char *filename, const char *basedir, char *str) { - float ret = 0; + int ret = 0; FILE *sysfsfp; char *temp = malloc(strlen(basedir) + strlen(filename) + 2); if (temp == NULL) { -- cgit v1.2.3-70-g09d2 From 723db167246ae60999699916a1563887e3adb535 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: staging:iio: Fix mention of INDIO_RING_TRIGGERED to INDIO_BUFFER_TRIGGERED Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Documentation/trigger.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/iio/Documentation/trigger.txt b/drivers/staging/iio/Documentation/trigger.txt index 64e2e08fb4d..7c0e505e4f0 100644 --- a/drivers/staging/iio/Documentation/trigger.txt +++ b/drivers/staging/iio/Documentation/trigger.txt @@ -31,5 +31,5 @@ consumers. Trigger Consumers Currently triggers are only used for the filling of software -buffers and as such any device supporting INDIO_RING_TRIGGERED has the +buffers and as such any device supporting INDIO_BUFFER_TRIGGERED has the consumer interface automatically created. -- cgit v1.2.3-70-g09d2 From 97b603a4e96565c3a3b09b9a4131d4107b0c6581 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: staging:iio: Fix error handling in generic_buffer example read() does not return -EAGAIN read() returns -1 and the errno value needs to be checked for -EAGAIN Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Documentation/generic_buffer.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c index 40d0ecac047..044ea196aa6 100644 --- a/drivers/staging/iio/Documentation/generic_buffer.c +++ b/drivers/staging/iio/Documentation/generic_buffer.c @@ -305,9 +305,12 @@ int main(int argc, char **argv) read_size = read(fp, data, toread*scan_size); - if (read_size == -EAGAIN) { - printf("nothing available\n"); - continue; + if (read_size < 0) { + if (errno == -EAGAIN) { + printf("nothing available\n"); + continue; + } else + break; } for (i = 0; i < read_size/scan_size; i++) process_scan(data + scan_size*i, -- cgit v1.2.3-70-g09d2 From 1c70f7bebce44515ffe30bf81358fe5f691656ad Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: staging:iio-trig-periodic-rtc: Cleanup Fix extra space in module description Silence output about trigger frequency when trigger gets enabled/disabled Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/staging/iio/trigger/iio-trig-periodic-rtc.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 38ecb4bb6e4..362a54a16e5 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -33,7 +33,7 @@ static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state) struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); if (trig_info->frequency == 0) return -EINVAL; - dev_info(&trig_info->rtc->dev, "trigger frequency is %d\n", + dev_dbg(&trig_info->rtc->dev, "trigger frequency is %d\n", trig_info->frequency); return rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); } @@ -128,8 +128,7 @@ static int iio_trig_periodic_rtc_probe(struct platform_device *dev) iio_trigger_set_drvdata(trig, trig_info); trig->ops = &iio_prtc_trigger_ops; /* RTC access */ - trig_info->rtc - = rtc_class_open(pdata[i]); + trig_info->rtc = rtc_class_open(pdata[i]); if (trig_info->rtc == NULL) { ret = -EINVAL; goto error_free_trig_info; @@ -199,5 +198,5 @@ static struct platform_driver iio_trig_periodic_rtc_driver = { module_platform_driver(iio_trig_periodic_rtc_driver); MODULE_AUTHOR("Jonathan Cameron "); -MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem"); +MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 9d2f79abdf8313682d7b38570de0a717b0e9baf1 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:00:00 +0000 Subject: staging:iio-trig-periodic-rtc: Allow to reset frequency to 0 periodic rtc trigger initially has frequency 0 it is possible to change trigger frequency on-the-fly, but it is not possible to set frequency back to 0 this patch allows to set trigger frequency to 0, thereby disabling the rtc interrupt Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/staging/iio/trigger/iio-trig-periodic-rtc.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 362a54a16e5..b5108a163e3 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -26,16 +26,22 @@ struct iio_prtc_trigger_info { struct rtc_device *rtc; int frequency; struct rtc_task task; + bool state; }; static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state) { struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - if (trig_info->frequency == 0) + int ret; + if (trig_info->frequency == 0 && state) return -EINVAL; dev_dbg(&trig_info->rtc->dev, "trigger frequency is %d\n", trig_info->frequency); - return rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); + ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); + if (ret == 0) + trig_info->state = state; + + return ret; } static ssize_t iio_trig_periodic_read_freq(struct device *dev, @@ -61,7 +67,14 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev, if (ret) goto error_ret; - ret = rtc_irq_set_freq(trig_info->rtc, &trig_info->task, val); + if (val > 0) { + ret = rtc_irq_set_freq(trig_info->rtc, &trig_info->task, val); + if (ret == 0 && trig_info->state && trig_info->frequency == 0) + ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 1); + } else if (val == 0) { + ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 0); + } else + ret = -EINVAL; if (ret) goto error_ret; -- cgit v1.2.3-70-g09d2 From aff8945566f0352b39244a714769b10f9f4d873a Mon Sep 17 00:00:00 2001 From: Jimmy Picard Date: Fri, 13 Jun 2014 06:56:00 +0100 Subject: staging: iio: fix coding style by adding blank lines in iio_simple_dummy This patch fixes coding style reported by checkpatch.pl that missing a blank line after declarations. Signed-off-by: Jimmy Picard Signed-off-by: Jonathan Cameron --- drivers/staging/iio/iio_simple_dummy.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index fd334a03a49..bf78e6f0311 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -550,6 +550,7 @@ error_ret: static __init int iio_dummy_init(void) { int i, ret; + if (instances > 10) { instances = 1; return -EINVAL; @@ -577,6 +578,7 @@ module_init(iio_dummy_init); static __exit void iio_dummy_exit(void) { int i; + for (i = 0; i < instances; i++) iio_dummy_remove(i); kfree(iio_dummy_devs); -- cgit v1.2.3-70-g09d2 From 398fd22b6b94cb15c1c299bceecd63644a1b17b4 Mon Sep 17 00:00:00 2001 From: Peter Meerwald Date: Sat, 6 Dec 2014 06:46:00 +0000 Subject: iio: Remove timestamp argument from iio_trigger_poll() and iio_trigger_poll_chained() argument has been ignored; adjust drivers accordingly Signed-off-by: Peter Meerwald Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad_sigma_delta.c | 2 +- drivers/iio/adc/at91_adc.c | 2 +- drivers/iio/adc/xilinx-xadc-core.c | 2 +- drivers/iio/industrialio-trigger.c | 8 ++++---- drivers/iio/light/gp2ap020a00f.c | 2 +- drivers/iio/proximity/as3935.c | 2 +- drivers/iio/trigger/iio-trig-interrupt.c | 3 +-- drivers/iio/trigger/iio-trig-sysfs.c | 2 +- drivers/staging/iio/accel/lis3l02dq_ring.c | 2 +- drivers/staging/iio/adc/mxs-lradc.c | 2 +- drivers/staging/iio/meter/ade7758_trigger.c | 2 +- drivers/staging/iio/trigger/iio-trig-bfin-timer.c | 2 +- drivers/staging/iio/trigger/iio-trig-periodic-rtc.c | 3 +-- include/linux/iio/trigger.h | 5 ++--- 14 files changed, 18 insertions(+), 21 deletions(-) diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 9a4e0e32a77..c55b81f7f97 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -410,7 +410,7 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private) complete(&sigma_delta->completion); disable_irq_nosync(irq); sigma_delta->irq_dis = true; - iio_trigger_poll(sigma_delta->trig, iio_get_time_ns()); + iio_trigger_poll(sigma_delta->trig); return IRQ_HANDLED; } diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 89777ed9abd..b9592010511 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -149,7 +149,7 @@ void handle_adc_eoc_trigger(int irq, struct iio_dev *idev) if (iio_buffer_enabled(idev)) { disable_irq_nosync(irq); - iio_trigger_poll(idev->trig, iio_get_time_ns()); + iio_trigger_poll(idev->trig); } else { st->last_value = at91_adc_readl(st, AT91_ADC_LCDR); st->done = true; diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index ab52be29141..fd2745c6294 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -486,7 +486,7 @@ static irqreturn_t xadc_axi_interrupt_handler(int irq, void *devid) return IRQ_NONE; if ((status & XADC_AXI_INT_EOS) && xadc->trigger) - iio_trigger_poll(xadc->trigger, 0); + iio_trigger_poll(xadc->trigger); if (status & XADC_AXI_INT_ALARM_MASK) { /* diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 3383b025f62..d31098e0c43 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -114,7 +114,7 @@ static struct iio_trigger *iio_trigger_find_by_name(const char *name, return trig; } -void iio_trigger_poll(struct iio_trigger *trig, s64 time) +void iio_trigger_poll(struct iio_trigger *trig) { int i; @@ -133,12 +133,12 @@ EXPORT_SYMBOL(iio_trigger_poll); irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private) { - iio_trigger_poll(private, iio_get_time_ns()); + iio_trigger_poll(private); return IRQ_HANDLED; } EXPORT_SYMBOL(iio_trigger_generic_data_rdy_poll); -void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time) +void iio_trigger_poll_chained(struct iio_trigger *trig) { int i; @@ -161,7 +161,7 @@ void iio_trigger_notify_done(struct iio_trigger *trig) trig->ops->try_reenable) if (trig->ops->try_reenable(trig)) /* Missed an interrupt so launch new poll now */ - iio_trigger_poll(trig, 0); + iio_trigger_poll(trig); } EXPORT_SYMBOL(iio_trigger_notify_done); diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 04bdb85d2d9..221ed16de1f 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -827,7 +827,7 @@ static void gp2ap020a00f_iio_trigger_work(struct irq_work *work) struct gp2ap020a00f_data *data = container_of(work, struct gp2ap020a00f_data, work); - iio_trigger_poll(data->trig, 0); + iio_trigger_poll(data->trig); } static irqreturn_t gp2ap020a00f_prox_sensing_handler(int irq, void *data) diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index bf677bfe8eb..5e780ef206f 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -232,7 +232,7 @@ static void as3935_event_work(struct work_struct *work) switch (val) { case AS3935_EVENT_INT: - iio_trigger_poll(st->trig, iio_get_time_ns()); + iio_trigger_poll(st->trig); break; case AS3935_NOISE_INT: dev_warn(&st->spi->dev, "noise level is too high"); diff --git a/drivers/iio/trigger/iio-trig-interrupt.c b/drivers/iio/trigger/iio-trig-interrupt.c index 02577ec54c6..7a149a7822b 100644 --- a/drivers/iio/trigger/iio-trig-interrupt.c +++ b/drivers/iio/trigger/iio-trig-interrupt.c @@ -24,8 +24,7 @@ struct iio_interrupt_trigger_info { static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private) { - /* Timestamp not currently provided */ - iio_trigger_poll(private, 0); + iio_trigger_poll(private); return IRQ_HANDLED; } diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c index 15e3b850f51..254c7e90612 100644 --- a/drivers/iio/trigger/iio-trig-sysfs.c +++ b/drivers/iio/trigger/iio-trig-sysfs.c @@ -96,7 +96,7 @@ static void iio_sysfs_trigger_work(struct irq_work *work) struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig, work); - iio_trigger_poll(trig->trig, 0); + iio_trigger_poll(trig->trig); } static ssize_t iio_sysfs_trigger_poll(struct device *dev, diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index 79cefe0a516..bf33fdead47 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -31,7 +31,7 @@ irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private) struct lis3l02dq_state *st = iio_priv(indio_dev); if (st->trigger_on) { - iio_trigger_poll(st->trig, iio_get_time_ns()); + iio_trigger_poll(st->trig); return IRQ_HANDLED; } else return IRQ_WAKE_THREAD; diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index dae8d1a9038..d8619993c6f 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1166,7 +1166,7 @@ static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) mxs_lradc_handle_touch(lradc); if (iio_buffer_enabled(iio)) - iio_trigger_poll(iio->trig, iio_get_time_ns()); + iio_trigger_poll(iio->trig); else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) complete(&lradc->completion); diff --git a/drivers/staging/iio/meter/ade7758_trigger.c b/drivers/staging/iio/meter/ade7758_trigger.c index 7a94ddd42f5..ea01b8f7a2c 100644 --- a/drivers/staging/iio/meter/ade7758_trigger.c +++ b/drivers/staging/iio/meter/ade7758_trigger.c @@ -21,7 +21,7 @@ static irqreturn_t ade7758_data_rdy_trig_poll(int irq, void *private) { disable_irq_nosync(irq); - iio_trigger_poll(private, iio_get_time_ns()); + iio_trigger_poll(private); return IRQ_HANDLED; } diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index 26e1ca0b780..16f1a06bcd8 100644 --- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -154,7 +154,7 @@ static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid) struct bfin_tmr_state *st = devid; clear_gptimer_intr(st->t->id); - iio_trigger_poll(st->trig, 0); + iio_trigger_poll(st->trig); return IRQ_HANDLED; } diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index b5108a163e3..b1aeb88273c 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -106,8 +106,7 @@ static const struct attribute_group *iio_trig_prtc_attr_groups[] = { static void iio_prtc_trigger_poll(void *private_data) { - /* Timestamp is not provided currently */ - iio_trigger_poll(private_data, 0); + iio_trigger_poll(private_data); } static const struct iio_trigger_ops iio_prtc_trigger_ops = { diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 369cf2cd514..4b79ffe7b18 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -129,12 +129,11 @@ void iio_trigger_unregister(struct iio_trigger *trig_info); /** * iio_trigger_poll() - called on a trigger occurring * @trig: trigger which occurred - * @time: timestamp when trigger occurred * * Typically called in relevant hardware interrupt handler. **/ -void iio_trigger_poll(struct iio_trigger *trig, s64 time); -void iio_trigger_poll_chained(struct iio_trigger *trig, s64 time); +void iio_trigger_poll(struct iio_trigger *trig); +void iio_trigger_poll_chained(struct iio_trigger *trig); irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private); -- cgit v1.2.3-70-g09d2 From 1a4fbf6a9286a6e3db497bc7bbae2024f0f1ad90 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 6 Nov 2014 23:07:00 +0000 Subject: iio: accel: kxcjk1013 3-axis accelerometer driver This patch adds IIO driver for KXCJK 1013 triaxis accelerometer sensor. The specifications for this driver is downloaded from: http://www.kionix.com/sites/default/files/KXCJK-1013%20Specifications%20Rev%202.pdf Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/Kconfig | 12 + drivers/iio/accel/Makefile | 1 + drivers/iio/accel/kxcjk-1013.c | 760 +++++++++++++++++++++++++++++++++++ include/linux/iio/accel/kxcjk_1013.h | 22 + 4 files changed, 795 insertions(+) create mode 100644 drivers/iio/accel/kxcjk-1013.c create mode 100644 include/linux/iio/accel/kxcjk_1013.h diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 1e120fa1e15..12addf272a6 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -77,4 +77,16 @@ config MMA8452 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 + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here if you want to build a driver for the Kionix KXCJK-1013 + triaxial acceleration sensor. + + To compile this driver as a module, choose M here: the module will + be called kxcjk-1013. + endmenu diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index dc0e379c259..6578ca1a8e0 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile @@ -5,6 +5,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_BMA180) += bma180.o obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o +obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o obj-$(CONFIG_KXSD9) += kxsd9.o obj-$(CONFIG_MMA8452) += mma8452.o diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c new file mode 100644 index 00000000000..2326e430c99 --- /dev/null +++ b/drivers/iio/accel/kxcjk-1013.c @@ -0,0 +1,760 @@ +/* + * KXCJK-1013 3-axis accelerometer driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define KXCJK1013_DRV_NAME "kxcjk1013" +#define KXCJK1013_IRQ_NAME "kxcjk1013_event" + +#define KXCJK1013_REG_XOUT_L 0x06 +/* + * From low byte X axis register, all the other addresses of Y and Z can be + * obtained by just applying axis offset. The following axis defines are just + * provide clarity, but not used. + */ +#define KXCJK1013_REG_XOUT_H 0x07 +#define KXCJK1013_REG_YOUT_L 0x08 +#define KXCJK1013_REG_YOUT_H 0x09 +#define KXCJK1013_REG_ZOUT_L 0x0A +#define KXCJK1013_REG_ZOUT_H 0x0B + +#define KXCJK1013_REG_DCST_RESP 0x0C +#define KXCJK1013_REG_WHO_AM_I 0x0F +#define KXCJK1013_REG_INT_SRC1 0x16 +#define KXCJK1013_REG_INT_SRC2 0x17 +#define KXCJK1013_REG_STATUS_REG 0x18 +#define KXCJK1013_REG_INT_REL 0x1A +#define KXCJK1013_REG_CTRL1 0x1B +#define KXCJK1013_REG_CTRL2 0x1D +#define KXCJK1013_REG_INT_CTRL1 0x1E +#define KXCJK1013_REG_INT_CTRL2 0x1F +#define KXCJK1013_REG_DATA_CTRL 0x21 +#define KXCJK1013_REG_WAKE_TIMER 0x29 +#define KXCJK1013_REG_SELF_TEST 0x3A +#define KXCJK1013_REG_WAKE_THRES 0x6A + +#define KXCJK1013_REG_CTRL1_BIT_PC1 BIT(7) +#define KXCJK1013_REG_CTRL1_BIT_RES BIT(6) +#define KXCJK1013_REG_CTRL1_BIT_DRDY BIT(5) +#define KXCJK1013_REG_CTRL1_BIT_GSEL1 BIT(4) +#define KXCJK1013_REG_CTRL1_BIT_GSEL0 BIT(3) +#define KXCJK1013_REG_CTRL1_BIT_WUFE BIT(1) +#define KXCJK1013_REG_INT_REG1_BIT_IEA BIT(4) +#define KXCJK1013_REG_INT_REG1_BIT_IEN BIT(5) + +#define KXCJK1013_DATA_MASK_12_BIT 0x0FFF +#define KXCJK1013_MAX_STARTUP_TIME_US 100000 + +struct kxcjk1013_data { + struct i2c_client *client; + struct iio_trigger *trig; + bool trig_mode; + struct mutex mutex; + s16 buffer[8]; + int power_state; + u8 odr_bits; + bool active_high_intr; +}; + +enum kxcjk1013_axis { + AXIS_X, + AXIS_Y, + AXIS_Z, +}; + +enum kxcjk1013_mode { + STANDBY, + OPERATION, +}; + +static const struct { + int val; + int val2; + int odr_bits; +} samp_freq_table[] = { {0, 781000, 0x08}, {1, 563000, 0x09}, + {3, 125000, 0x0A}, {6, 25000, 0x0B}, {12, 5000, 0}, + {25, 0, 0x01}, {50, 0, 0x02}, {100, 0, 0x03}, + {200, 0, 0x04}, {400, 0, 0x05}, {800, 0, 0x06}, + {1600, 0, 0x07} }; + +/* Refer to section 4 of the specification */ +static const struct { + int odr_bits; + int usec; +} odr_start_up_times[] = { {0x08, 100000}, {0x09, 100000}, {0x0A, 100000}, + {0x0B, 100000}, { 0, 80000}, {0x01, 41000}, + {0x02, 21000}, {0x03, 11000}, {0x04, 6400}, + {0x05, 3900}, {0x06, 2700}, {0x07, 2100} }; + +static int kxcjk1013_set_mode(struct kxcjk1013_data *data, + enum kxcjk1013_mode mode) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (mode == STANDBY) + ret &= ~KXCJK1013_REG_CTRL1_BIT_PC1; + else + ret |= KXCJK1013_REG_CTRL1_BIT_PC1; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_chip_ack_intr(struct kxcjk1013_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_REL); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_rel\n"); + return ret; + } + + return ret; +} + +static int kxcjk1013_chip_init(struct kxcjk1013_data *data) +{ + int ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_WHO_AM_I); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading who_am_i\n"); + return ret; + } + + dev_dbg(&data->client->dev, "KXCJK1013 Chip Id %x\n", ret); + + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + /* Setting range to 4G */ + ret |= KXCJK1013_REG_CTRL1_BIT_GSEL0; + ret &= ~KXCJK1013_REG_CTRL1_BIT_GSEL1; + + /* Set 12 bit mode */ + ret |= KXCJK1013_REG_CTRL1_BIT_RES; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_DATA_CTRL); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_data_ctrl\n"); + return ret; + } + + data->odr_bits = ret; + + /* Set up INT polarity */ + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); + return ret; + } + + if (data->active_high_intr) + ret |= KXCJK1013_REG_INT_REG1_BIT_IEA; + else + ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEA; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); + return ret; + } + + return 0; +} + +static int kxcjk1013_chip_setup_interrupt(struct kxcjk1013_data *data, + bool status) +{ + int ret; + + /* This is requirement by spec to change state to STANDBY */ + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_INT_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_INT_REG1_BIT_IEN; + else + ret &= ~KXCJK1013_REG_INT_REG1_BIT_IEN; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_INT_CTRL1, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, KXCJK1013_REG_CTRL1); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_ctrl1\n"); + return ret; + } + + if (status) + ret |= KXCJK1013_REG_CTRL1_BIT_DRDY; + else + ret &= ~KXCJK1013_REG_CTRL1_BIT_DRDY; + + ret = i2c_smbus_write_byte_data(data->client, + KXCJK1013_REG_CTRL1, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_ctrl1\n"); + return ret; + } + + return ret; +} + +static int kxcjk1013_convert_freq_to_bit(int val, int val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) { + if (samp_freq_table[i].val == val && + samp_freq_table[i].val2 == val2) { + return samp_freq_table[i].odr_bits; + } + } + + return -EINVAL; +} + +static int kxcjk1013_set_odr(struct kxcjk1013_data *data, int val, int val2) +{ + int ret; + int odr_bits; + + odr_bits = kxcjk1013_convert_freq_to_bit(val, val2); + if (odr_bits < 0) + return odr_bits; + + /* To change ODR, the chip must be set to STANDBY as per spec */ + ret = kxcjk1013_set_mode(data, STANDBY); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte_data(data->client, KXCJK1013_REG_DATA_CTRL, + odr_bits); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing data_ctrl\n"); + return ret; + } + + data->odr_bits = odr_bits; + + /* Check, if the ODR is changed after data enable */ + if (data->power_state) { + /* Set the state back to operation */ + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + } + + return 0; +} + +static int kxcjk1013_get_odr(struct kxcjk1013_data *data, int *val, int *val2) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(samp_freq_table); ++i) { + if (samp_freq_table[i].odr_bits == data->odr_bits) { + *val = samp_freq_table[i].val; + *val2 = samp_freq_table[i].val2; + return IIO_VAL_INT_PLUS_MICRO; + } + } + + return -EINVAL; +} + +static int kxcjk1013_get_acc_reg(struct kxcjk1013_data *data, int axis) +{ + u8 reg = KXCJK1013_REG_XOUT_L + axis * 2; + int ret; + + ret = i2c_smbus_read_word_data(data->client, reg); + if (ret < 0) { + dev_err(&data->client->dev, + "failed to read accel_%c registers\n", 'x' + axis); + return ret; + } + + return ret; +} + +static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(odr_start_up_times); ++i) { + if (odr_start_up_times[i].odr_bits == data->odr_bits) + return odr_start_up_times[i].usec; + } + + return KXCJK1013_MAX_STARTUP_TIME_US; +} + +static int kxcjk1013_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->mutex); + if (iio_buffer_enabled(indio_dev)) + ret = -EBUSY; + else { + int sleep_val; + + ret = kxcjk1013_set_mode(data, OPERATION); + if (ret < 0) + return ret; + ++data->power_state; + sleep_val = kxcjk1013_get_startup_times(data); + if (sleep_val < 20000) + usleep_range(sleep_val, 20000); + else + msleep_interruptible(sleep_val/1000); + ret = kxcjk1013_get_acc_reg(data, chan->scan_index); + if (--data->power_state == 0) + kxcjk1013_set_mode(data, STANDBY); + } + mutex_unlock(&data->mutex); + + if (ret < 0) + return ret; + + *val = sign_extend32(ret >> 4, 11); + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = 19163; /* range +-4g (4/2047*9.806650) */ + return IIO_VAL_INT_PLUS_MICRO; + + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = kxcjk1013_get_odr(data, val, val2); + mutex_unlock(&data->mutex); + return ret; + + default: + return -EINVAL; + } +} + +static int kxcjk1013_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + mutex_lock(&data->mutex); + ret = kxcjk1013_set_odr(data, val, val2); + mutex_unlock(&data->mutex); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int kxcjk1013_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct kxcjk1013_data *data = iio_priv(indio_dev); + + if (data->trig != trig) + return -EINVAL; + + return 0; +} + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( + "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800 1600"); + +static struct attribute *kxcjk1013_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group kxcjk1013_attrs_group = { + .attrs = kxcjk1013_attributes, +}; + +#define KXCJK1013_CHANNEL(_axis) { \ + .type = IIO_ACCEL, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = AXIS_##_axis, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .shift = 4, \ + .endianness = IIO_LE, \ + }, \ +} + +static const struct iio_chan_spec kxcjk1013_channels[] = { + KXCJK1013_CHANNEL(X), + KXCJK1013_CHANNEL(Y), + KXCJK1013_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(3), +}; + +static const struct iio_info kxcjk1013_info = { + .attrs = &kxcjk1013_attrs_group, + .read_raw = kxcjk1013_read_raw, + .write_raw = kxcjk1013_write_raw, + .validate_trigger = kxcjk1013_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static irqreturn_t kxcjk1013_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct kxcjk1013_data *data = iio_priv(indio_dev); + int bit, ret, i = 0; + + mutex_lock(&data->mutex); + + for_each_set_bit(bit, indio_dev->buffer->scan_mask, + indio_dev->masklength) { + ret = kxcjk1013_get_acc_reg(data, bit); + if (ret < 0) { + kxcjk1013_chip_ack_intr(data); + mutex_unlock(&data->mutex); + goto err; + } + data->buffer[i++] = ret; + } + + kxcjk1013_chip_ack_intr(data); + + mutex_unlock(&data->mutex); + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); +err: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + if (state) { + kxcjk1013_chip_setup_interrupt(data, true); + kxcjk1013_set_mode(data, OPERATION); + ++data->power_state; + } else { + if (--data->power_state) + return 0; + kxcjk1013_chip_setup_interrupt(data, false); + kxcjk1013_set_mode(data, STANDBY); + } + mutex_unlock(&data->mutex); + + return 0; +} + +static const struct iio_trigger_ops kxcjk1013_trigger_ops = { + .set_trigger_state = kxcjk1013_data_rdy_trigger_set_state, + .owner = THIS_MODULE, +}; + +static int kxcjk1013_acpi_gpio_probe(struct i2c_client *client, + struct kxcjk1013_data *data) +{ + const struct acpi_device_id *id; + struct device *dev; + struct gpio_desc *gpio; + int ret; + + if (!client) + return -EINVAL; + + dev = &client->dev; + if (!ACPI_HANDLE(dev)) + return -ENODEV; + + id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!id) + return -ENODEV; + + /* data ready gpio interrupt pin */ + gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0); + if (IS_ERR(gpio)) { + dev_err(dev, "acpi gpio get index failed\n"); + return PTR_ERR(gpio); + } + + ret = gpiod_direction_input(gpio); + if (ret) + return ret; + + ret = gpiod_to_irq(gpio); + + dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); + + return ret; +} + +static int kxcjk1013_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct kxcjk1013_data *data; + struct iio_dev *indio_dev; + struct iio_trigger *trig = NULL; + struct kxcjk_1013_platform_data *pdata; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + pdata = dev_get_platdata(&client->dev); + if (pdata) + data->active_high_intr = pdata->active_high_intr; + else + data->active_high_intr = true; /* default polarity */ + + ret = kxcjk1013_chip_init(data); + if (ret < 0) + return ret; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = kxcjk1013_channels; + indio_dev->num_channels = ARRAY_SIZE(kxcjk1013_channels); + indio_dev->name = KXCJK1013_DRV_NAME; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &kxcjk1013_info; + + if (client->irq < 0) + client->irq = kxcjk1013_acpi_gpio_probe(client, data); + + if (client->irq >= 0) { + trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + indio_dev->id); + if (!trig) + return -ENOMEM; + + data->trig_mode = true; + + ret = devm_request_irq(&client->dev, client->irq, + iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + KXCJK1013_IRQ_NAME, + trig); + if (ret) { + dev_err(&client->dev, "unable to request IRQ\n"); + goto err_trigger_free; + } + + trig->dev.parent = &client->dev; + trig->ops = &kxcjk1013_trigger_ops; + iio_trigger_set_drvdata(trig, indio_dev); + data->trig = trig; + indio_dev->trig = trig; + + ret = iio_trigger_register(trig); + if (ret) + goto err_trigger_free; + + ret = iio_triggered_buffer_setup(indio_dev, + &iio_pollfunc_store_time, + kxcjk1013_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&client->dev, + "iio triggered buffer setup failed\n"); + goto err_trigger_unregister; + } + } + + ret = devm_iio_device_register(&client->dev, indio_dev); + if (ret < 0) { + dev_err(&client->dev, "unable to register iio device\n"); + goto err_buffer_cleanup; + } + + return 0; + +err_buffer_cleanup: + if (data->trig_mode) + iio_triggered_buffer_cleanup(indio_dev); +err_trigger_unregister: + if (data->trig_mode) + iio_trigger_unregister(trig); +err_trigger_free: + if (data->trig_mode) + iio_trigger_free(trig); + + return ret; +} + +static int kxcjk1013_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + if (data->trig_mode) { + iio_triggered_buffer_cleanup(indio_dev); + iio_trigger_unregister(data->trig); + iio_trigger_free(data->trig); + } + + mutex_lock(&data->mutex); + kxcjk1013_set_mode(data, STANDBY); + mutex_unlock(&data->mutex); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int kxcjk1013_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + kxcjk1013_set_mode(data, STANDBY); + mutex_unlock(&data->mutex); + + return 0; +} + +static int kxcjk1013_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct kxcjk1013_data *data = iio_priv(indio_dev); + + mutex_lock(&data->mutex); + + if (data->power_state) + kxcjk1013_set_mode(data, OPERATION); + + mutex_unlock(&data->mutex); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(kxcjk1013_pm_ops, kxcjk1013_suspend, kxcjk1013_resume); +#define KXCJK1013_PM_OPS (&kxcjk1013_pm_ops) +#else +#define KXCJK1013_PM_OPS NULL +#endif + +static const struct acpi_device_id kx_acpi_match[] = { + {"KXCJ1013", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, kx_acpi_match); + +static const struct i2c_device_id kxcjk1013_id[] = { + {"kxcjk1013", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, kxcjk1013_id); + +static struct i2c_driver kxcjk1013_driver = { + .driver = { + .name = KXCJK1013_DRV_NAME, + .acpi_match_table = ACPI_PTR(kx_acpi_match), + .pm = KXCJK1013_PM_OPS, + }, + .probe = kxcjk1013_probe, + .remove = kxcjk1013_remove, + .id_table = kxcjk1013_id, +}; +module_i2c_driver(kxcjk1013_driver); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("KXCJK1013 accelerometer driver"); diff --git a/include/linux/iio/accel/kxcjk_1013.h b/include/linux/iio/accel/kxcjk_1013.h new file mode 100644 index 00000000000..fd1d540ea62 --- /dev/null +++ b/include/linux/iio/accel/kxcjk_1013.h @@ -0,0 +1,22 @@ +/* + * KXCJK-1013 3-axis accelerometer Interface + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + */ + +#ifndef __IIO_KXCJK_1013_H__ +#define __IIO_KXCJK_1013_H__ + +struct kxcjk_1013_platform_data { + bool active_high_intr; +}; + +#endif -- cgit v1.2.3-70-g09d2 From d14c0f10e71c174cc312fb77832450bd02171be5 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Thu, 6 Nov 2014 23:06:00 +0000 Subject: iio: AK09911 : 3 axis compass support Added IIO magnetometer driver for AK09911. In functionality is resembles AK8975 or AK8963. But there are several differences, so instead of modifying existing AK8975 driver and keep it clean, implemented as a separate driver. The key differences are: - Register map is different and have different indexes - AK09911 is a very compact interface with no DRDY pin. So no support of interrupt or GPIO poll - Even for polled mode no mention on ST2 register, which is required in ak8975 driver - mode values are different for fuse access Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/Kconfig | 10 ++ drivers/iio/magnetometer/Makefile | 1 + drivers/iio/magnetometer/ak09911.c | 326 +++++++++++++++++++++++++++++++++++++ 3 files changed, 337 insertions(+) create mode 100644 drivers/iio/magnetometer/ak09911.c diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index 05a364c543f..b2dba9e506a 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -17,6 +17,16 @@ config AK8975 To compile this driver as a module, choose M here: the module will be called ak8975. +config AK09911 + tristate "Asahi Kasei AK09911 3-axis Compass" + depends on I2C + help + Say yes here to build support for Asahi Kasei AK09911 3-Axis + Magnetometer. + + To compile this driver as a module, choose M here: the module + will be called ak09911. + config MAG3110 tristate "Freescale MAG3110 3-Axis Magnetometer" depends on I2C diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 0f5d3c98579..b91315e0b82 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -3,6 +3,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AK09911) += ak09911.o obj-$(CONFIG_AK8975) += ak8975.o obj-$(CONFIG_MAG3110) += mag3110.o obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c new file mode 100644 index 00000000000..b2bc942ff6b --- /dev/null +++ b/drivers/iio/magnetometer/ak09911.c @@ -0,0 +1,326 @@ +/* + * AK09911 3-axis compass driver + * Copyright (c) 2014, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define AK09911_REG_WIA1 0x00 +#define AK09911_REG_WIA2 0x01 +#define AK09911_WIA1_VALUE 0x48 +#define AK09911_WIA2_VALUE 0x05 + +#define AK09911_REG_ST1 0x10 +#define AK09911_REG_HXL 0x11 +#define AK09911_REG_HXH 0x12 +#define AK09911_REG_HYL 0x13 +#define AK09911_REG_HYH 0x14 +#define AK09911_REG_HZL 0x15 +#define AK09911_REG_HZH 0x16 + +#define AK09911_REG_ASAX 0x60 +#define AK09911_REG_ASAY 0x61 +#define AK09911_REG_ASAZ 0x62 + +#define AK09911_REG_CNTL1 0x30 +#define AK09911_REG_CNTL2 0x31 +#define AK09911_REG_CNTL3 0x32 + +#define AK09911_MODE_SNG_MEASURE 0x01 +#define AK09911_MODE_SELF_TEST 0x10 +#define AK09911_MODE_FUSE_ACCESS 0x1F +#define AK09911_MODE_POWERDOWN 0x00 +#define AK09911_RESET_DATA 0x01 + +#define AK09911_REG_CNTL1 0x30 +#define AK09911_REG_CNTL2 0x31 +#define AK09911_REG_CNTL3 0x32 + +#define AK09911_RAW_TO_GAUSS(asa) ((((asa) + 128) * 6000) / 256) + +#define AK09911_MAX_CONVERSION_TIMEOUT_MS 500 +#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10 + +struct ak09911_data { + struct i2c_client *client; + struct mutex lock; + u8 asa[3]; + long raw_to_gauss[3]; +}; + +static const int ak09911_index_to_reg[] = { + AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL, +}; + +static int ak09911_set_mode(struct i2c_client *client, u8 mode) +{ + int ret; + + switch (mode) { + case AK09911_MODE_SNG_MEASURE: + case AK09911_MODE_SELF_TEST: + case AK09911_MODE_FUSE_ACCESS: + case AK09911_MODE_POWERDOWN: + ret = i2c_smbus_write_byte_data(client, + AK09911_REG_CNTL2, mode); + if (ret < 0) { + dev_err(&client->dev, "set_mode error\n"); + return ret; + } + /* After mode change wait atleast 100us */ + usleep_range(100, 500); + break; + default: + dev_err(&client->dev, + "%s: Unknown mode(%d).", __func__, mode); + return -EINVAL; + } + + return ret; +} + +/* Get Sensitivity Adjustment value */ +static int ak09911_get_asa(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct ak09911_data *data = iio_priv(indio_dev); + int ret; + + ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS); + if (ret < 0) + return ret; + + /* Get asa data and store in the device data. */ + ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX, + 3, data->asa); + if (ret < 0) { + dev_err(&client->dev, "Not able to read asa data\n"); + return ret; + } + + ret = ak09911_set_mode(client, AK09911_MODE_POWERDOWN); + if (ret < 0) + return ret; + + data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]); + data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]); + data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]); + + return 0; +} + +static int ak09911_verify_chip_id(struct i2c_client *client) +{ + u8 wia_val[2]; + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1, + 2, wia_val); + if (ret < 0) { + dev_err(&client->dev, "Error reading WIA\n"); + return ret; + } + + dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]); + + if (wia_val[0] != AK09911_WIA1_VALUE || + wia_val[1] != AK09911_WIA2_VALUE) { + dev_err(&client->dev, "Device ak09911 not found\n"); + return -ENODEV; + } + + return 0; +} + +static int wait_conversion_complete_polled(struct ak09911_data *data) +{ + struct i2c_client *client = data->client; + u8 read_status; + u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS; + int ret; + + /* Wait for the conversion to complete. */ + while (timeout_ms) { + msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS); + ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1); + if (ret < 0) { + dev_err(&client->dev, "Error in reading ST1\n"); + return ret; + } + read_status = ret & 0x01; + if (read_status) + break; + timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS; + } + if (!timeout_ms) { + dev_err(&client->dev, "Conversion timeout happened\n"); + return -EIO; + } + + return read_status; +} + +static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val) +{ + struct ak09911_data *data = iio_priv(indio_dev); + struct i2c_client *client = data->client; + int ret; + + mutex_lock(&data->lock); + + ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE); + if (ret < 0) + goto fn_exit; + + ret = wait_conversion_complete_polled(data); + if (ret < 0) + goto fn_exit; + + /* Read data */ + ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]); + if (ret < 0) { + dev_err(&client->dev, "Read axis data fails\n"); + goto fn_exit; + } + + mutex_unlock(&data->lock); + + /* Clamp to valid range. */ + *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13); + + return IIO_VAL_INT; + +fn_exit: + mutex_unlock(&data->lock); + + return ret; +} + +static int ak09911_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct ak09911_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return ak09911_read_axis(indio_dev, chan->address, val); + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = data->raw_to_gauss[chan->address]; + return IIO_VAL_INT_PLUS_MICRO; + } + + return -EINVAL; +} + +#define AK09911_CHANNEL(axis, index) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE), \ + .address = index, \ + } + +static const struct iio_chan_spec ak09911_channels[] = { + AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2), +}; + +static const struct iio_info ak09911_info = { + .read_raw = &ak09911_read_raw, + .driver_module = THIS_MODULE, +}; + +static const struct acpi_device_id ak_acpi_match[] = { + {"AK009911", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ak_acpi_match); + +static int ak09911_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct ak09911_data *data; + const char *name; + int ret; + + ret = ak09911_verify_chip_id(client); + if (ret) { + dev_err(&client->dev, "AK00911 not detected\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + + data->client = client; + mutex_init(&data->lock); + + ret = ak09911_get_asa(client); + if (ret) + return ret; + + if (id) + name = id->name; + else if (ACPI_HANDLE(&client->dev)) + name = dev_name(&client->dev); + else + return -ENODEV; + + dev_dbg(&client->dev, "Asahi compass chip %s\n", name); + + indio_dev->dev.parent = &client->dev; + indio_dev->channels = ak09911_channels; + indio_dev->num_channels = ARRAY_SIZE(ak09911_channels); + indio_dev->info = &ak09911_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->name = name; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id ak09911_id[] = { + {"ak09911", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, ak09911_id); + +static struct i2c_driver ak09911_driver = { + .driver = { + .name = "ak09911", + .acpi_match_table = ACPI_PTR(ak_acpi_match), + }, + .probe = ak09911_probe, + .id_table = ak09911_id, +}; +module_i2c_driver(ak09911_driver); + +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("AK09911 Compass driver"); -- cgit v1.2.3-70-g09d2 From 88f6da779a37a3579e580296776ba86d6c6bd980 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Mon, 16 Jun 2014 20:00:00 +0100 Subject: iio: accel: kxcjk1013 Fix missing unlock errors Fix unlock at two places. One when i2c error occurs and other when trigger set state when raw read is in progress. kbuild test robot errors: >> >> drivers/iio/accel/kxcjk-1013.c:531:3-9: preceding lock on line 524 >> >> drivers/iio/accel/kxcjk-1013.c:376:4-10: preceding lock on line 368 Signed-off-by: Srinivas Pandruvada Reported-by: Fengguang Wu Signed-off-by: Jonathan Cameron --- drivers/iio/accel/kxcjk-1013.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 2326e430c99..72a6dbbc18d 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -372,8 +372,10 @@ static int kxcjk1013_read_raw(struct iio_dev *indio_dev, int sleep_val; ret = kxcjk1013_set_mode(data, OPERATION); - if (ret < 0) + if (ret < 0) { + mutex_unlock(&data->mutex); return ret; + } ++data->power_state; sleep_val = kxcjk1013_get_startup_times(data); if (sleep_val < 20000) @@ -527,8 +529,10 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig, kxcjk1013_set_mode(data, OPERATION); ++data->power_state; } else { - if (--data->power_state) + if (--data->power_state) { + mutex_unlock(&data->mutex); return 0; + } kxcjk1013_chip_setup_interrupt(data, false); kxcjk1013_set_mode(data, STANDBY); } -- cgit v1.2.3-70-g09d2