diff options
Diffstat (limited to 'drivers/iio')
38 files changed, 1042 insertions, 257 deletions
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index 90cf0cda50c4..5dd0e120a504 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -65,9 +65,11 @@ source "drivers/iio/common/Kconfig" source "drivers/iio/dac/Kconfig" source "drivers/iio/frequency/Kconfig" source "drivers/iio/gyro/Kconfig" +source "drivers/iio/humidity/Kconfig" source "drivers/iio/imu/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" +source "drivers/iio/orientation/Kconfig" if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index bcf7e9e3b053..887d39090d75 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -18,9 +18,11 @@ obj-y += common/ obj-y += dac/ obj-y += gyro/ obj-y += frequency/ +obj-y += humidity/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += orientation/ obj-y += pressure/ obj-y += temperature/ obj-y += trigger/ diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 28b39283bccf..3bec9220df04 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -455,7 +455,12 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = (_index), \ - .scan_type = IIO_ST('s', 14, 16, 2), \ + .scan_type = { \ + .sign = 's', \ + .realbits = 14, \ + .storagebits = 16, \ + .shift = 2, \ + }, \ .ext_info = bma180_ext_info, \ } diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 58e945594c7b..70f78c3062a7 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -43,19 +43,22 @@ struct ad7266_state { * The buffer needs to be large enough to hold two samples (4 bytes) and * the naturally aligned timestamp (8 bytes). */ - uint8_t data[ALIGN(4, sizeof(s64)) + sizeof(s64)] ____cacheline_aligned; + struct { + __be16 sample[2]; + s64 timestamp; + } data ____cacheline_aligned; }; static int ad7266_wakeup(struct ad7266_state *st) { /* Any read with >= 2 bytes will wake the device */ - return spi_read(st->spi, st->data, 2); + return spi_read(st->spi, &st->data.sample[0], 2); } static int ad7266_powerdown(struct ad7266_state *st) { /* Any read with < 2 bytes will powerdown the device */ - return spi_read(st->spi, st->data, 1); + return spi_read(st->spi, &st->data.sample[0], 1); } static int ad7266_preenable(struct iio_dev *indio_dev) @@ -84,9 +87,9 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p) struct ad7266_state *st = iio_priv(indio_dev); int ret; - ret = spi_read(st->spi, st->data, 4); + ret = spi_read(st->spi, st->data.sample, 4); if (ret == 0) { - iio_push_to_buffers_with_timestamp(indio_dev, st->data, + iio_push_to_buffers_with_timestamp(indio_dev, &st->data, pf->timestamp); } @@ -137,7 +140,7 @@ static int ad7266_read_single(struct ad7266_state *st, int *val, ad7266_select_input(st, address); ret = spi_sync(st->spi, &st->single_msg); - *val = be16_to_cpu(st->data[address % 2]); + *val = be16_to_cpu(st->data.sample[address % 2]); return ret; } @@ -442,15 +445,15 @@ static int ad7266_probe(struct spi_device *spi) ad7266_init_channels(indio_dev); /* wakeup */ - st->single_xfer[0].rx_buf = &st->data; + st->single_xfer[0].rx_buf = &st->data.sample[0]; st->single_xfer[0].len = 2; st->single_xfer[0].cs_change = 1; /* conversion */ - st->single_xfer[1].rx_buf = &st->data; + st->single_xfer[1].rx_buf = st->data.sample; st->single_xfer[1].len = 4; st->single_xfer[1].cs_change = 1; /* powerdown */ - st->single_xfer[2].tx_buf = &st->data; + st->single_xfer[2].tx_buf = &st->data.sample[0]; st->single_xfer[2].len = 1; spi_message_init(&st->single_msg); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 6118dced02b6..e283f2f2ee2f 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1039,10 +1039,10 @@ static const struct iio_info max1238_info = { }; static const struct iio_info max1363_info = { - .read_event_value_new = &max1363_read_thresh, - .write_event_value_new = &max1363_write_thresh, - .read_event_config_new = &max1363_read_event_config, - .write_event_config_new = &max1363_write_event_config, + .read_event_value = &max1363_read_thresh, + .write_event_value = &max1363_write_thresh, + .read_event_config = &max1363_read_event_config, + .write_event_config = &max1363_write_event_config, .read_raw = &max1363_read_raw, .update_scan_mode = &max1363_update_scan_mode, .driver_module = THIS_MODULE, diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c index cb9c6366032c..f03b92fd3803 100644 --- a/drivers/iio/dac/ad5064.c +++ b/drivers/iio/dac/ad5064.c @@ -299,7 +299,12 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ .address = addr, \ - .scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 20 - bits, \ + }, \ .ext_info = ad5064_ext_info, \ } diff --git a/drivers/iio/dac/ad5360.c b/drivers/iio/dac/ad5360.c index b968af50db0a..64634d7f578e 100644 --- a/drivers/iio/dac/ad5360.c +++ b/drivers/iio/dac/ad5360.c @@ -107,7 +107,12 @@ enum ad5360_type { BIT(IIO_CHAN_INFO_OFFSET) | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ - .scan_type = IIO_ST('u', (bits), 16, 16 - (bits)) \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 16 - (bits), \ + }, \ } static const struct ad5360_chip_info ad5360_chip_info_tbl[] = { diff --git a/drivers/iio/dac/ad5380.c b/drivers/iio/dac/ad5380.c index a59ff0e7b888..9de4c4d38280 100644 --- a/drivers/iio/dac/ad5380.c +++ b/drivers/iio/dac/ad5380.c @@ -261,7 +261,12 @@ static struct iio_chan_spec_ext_info ad5380_ext_info[] = { BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .scan_type = IIO_ST('u', (_bits), 16, 14 - (_bits)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 16, \ + .shift = 14 - (_bits), \ + }, \ .ext_info = ad5380_ext_info, \ } diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 7d1e90811c71..787ef1d859c6 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -75,7 +75,7 @@ struct ad5421_state { * transfer buffers to live in their own cache lines. */ union { - u32 d32; + __be32 d32; u8 d8[4]; } data[2] ____cacheline_aligned; }; @@ -114,7 +114,11 @@ static const struct iio_chan_spec ad5421_channels[] = { BIT(IIO_CHAN_INFO_CALIBBIAS), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_OFFSET), - .scan_type = IIO_ST('u', 16, 16, 0), + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + }, .event_spec = ad5421_current_event, .num_event_specs = ARRAY_SIZE(ad5421_current_event), }, @@ -458,9 +462,9 @@ static int ad5421_read_event_value(struct iio_dev *indio_dev, static const struct iio_info ad5421_info = { .read_raw = ad5421_read_raw, .write_raw = ad5421_write_raw, - .read_event_config_new = ad5421_read_event_config, - .write_event_config_new = ad5421_write_event_config, - .read_event_value_new = ad5421_read_event_value, + .read_event_config = ad5421_read_event_config, + .write_event_config = ad5421_write_event_config, + .read_event_value = ad5421_read_event_value, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 1263b0e5ad84..46bb62a5c1d4 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -139,14 +139,19 @@ static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { { }, }; -#define _AD5446_CHANNEL(bits, storage, shift, ext) { \ +#define _AD5446_CHANNEL(bits, storage, _shift, ext) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ .channel = 0, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .scan_type = IIO_ST('u', (bits), (storage), (shift)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = (storage), \ + .shift = (_shift), \ + }, \ .ext_info = (ext), \ } diff --git a/drivers/iio/dac/ad5449.c b/drivers/iio/dac/ad5449.c index 82e208f6cde2..64d7256cbb6d 100644 --- a/drivers/iio/dac/ad5449.c +++ b/drivers/iio/dac/ad5449.c @@ -204,7 +204,12 @@ static const struct iio_info ad5449_info = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ .address = (chan), \ - .scan_type = IIO_ST('u', (bits), 16, 12 - (bits)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = 12 - (bits), \ + }, \ } #define DECLARE_AD5449_CHANNELS(name, bits) \ diff --git a/drivers/iio/dac/ad5504.c b/drivers/iio/dac/ad5504.c index c0957a918e17..1e6449346b50 100644 --- a/drivers/iio/dac/ad5504.c +++ b/drivers/iio/dac/ad5504.c @@ -47,14 +47,16 @@ * @vref_mv: actual reference voltage used * @pwr_down_mask power down mask * @pwr_down_mode current power down mode + * @data: transfer buffer */ - struct ad5504_state { struct spi_device *spi; struct regulator *reg; unsigned short vref_mv; unsigned pwr_down_mask; unsigned pwr_down_mode; + + __be16 data[2] ____cacheline_aligned; }; /** @@ -66,31 +68,29 @@ enum ad5504_supported_device_ids { ID_AD5501, }; -static int ad5504_spi_write(struct spi_device *spi, u8 addr, u16 val) +static int ad5504_spi_write(struct ad5504_state *st, u8 addr, u16 val) { - u16 tmp = cpu_to_be16(AD5504_CMD_WRITE | - AD5504_ADDR(addr) | + st->data[0] = cpu_to_be16(AD5504_CMD_WRITE | AD5504_ADDR(addr) | (val & AD5504_RES_MASK)); - return spi_write(spi, (u8 *)&tmp, 2); + return spi_write(st->spi, &st->data[0], 2); } -static int ad5504_spi_read(struct spi_device *spi, u8 addr) +static int ad5504_spi_read(struct ad5504_state *st, u8 addr) { - u16 tmp = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); - u16 val; int ret; - struct spi_transfer t = { - .tx_buf = &tmp, - .rx_buf = &val, - .len = 2, - }; - ret = spi_sync_transfer(spi, &t, 1); - + struct spi_transfer t = { + .tx_buf = &st->data[0], + .rx_buf = &st->data[1], + .len = 2, + }; + + st->data[0] = cpu_to_be16(AD5504_CMD_READ | AD5504_ADDR(addr)); + ret = spi_sync_transfer(st->spi, &t, 1); if (ret < 0) return ret; - return be16_to_cpu(val) & AD5504_RES_MASK; + return be16_to_cpu(st->data[1]) & AD5504_RES_MASK; } static int ad5504_read_raw(struct iio_dev *indio_dev, @@ -104,7 +104,7 @@ static int ad5504_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - ret = ad5504_spi_read(st->spi, chan->address); + ret = ad5504_spi_read(st, chan->address); if (ret < 0) return ret; @@ -133,7 +133,7 @@ static int ad5504_write_raw(struct iio_dev *indio_dev, if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; - return ad5504_spi_write(st->spi, chan->address, val); + return ad5504_spi_write(st, chan->address, val); default: ret = -EINVAL; } @@ -197,12 +197,12 @@ static ssize_t ad5504_write_dac_powerdown(struct iio_dev *indio_dev, else st->pwr_down_mask &= ~(1 << chan->channel); - ret = ad5504_spi_write(st->spi, AD5504_ADDR_CTRL, + ret = ad5504_spi_write(st, AD5504_ADDR_CTRL, AD5504_DAC_PWRDWN_MODE(st->pwr_down_mode) | AD5504_DAC_PWR(st->pwr_down_mask)); /* writes to the CTRL register must be followed by a NOOP */ - ad5504_spi_write(st->spi, AD5504_ADDR_NOOP, 0); + ad5504_spi_write(st, AD5504_ADDR_NOOP, 0); return ret ? ret : len; } @@ -261,7 +261,11 @@ static const struct iio_chan_spec_ext_info ad5504_ext_info[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .address = AD5504_ADDR_DAC(_chan), \ - .scan_type = IIO_ST('u', 12, 16, 0), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 12, \ + .storagebits = 16, \ + }, \ .ext_info = ad5504_ext_info, \ } diff --git a/drivers/iio/dac/ad5624r_spi.c b/drivers/iio/dac/ad5624r_spi.c index 774dd968145b..e8199cce2aea 100644 --- a/drivers/iio/dac/ad5624r_spi.c +++ b/drivers/iio/dac/ad5624r_spi.c @@ -176,7 +176,12 @@ static const struct iio_chan_spec_ext_info ad5624r_ext_info[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .address = (_chan), \ - .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 16, \ + .shift = 16 - (_bits), \ + }, \ .ext_info = ad5624r_ext_info, \ } diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 30e506e37dd2..17aca4d9bd06 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -78,7 +78,7 @@ struct ad5686_state { */ union { - u32 d32; + __be32 d32; u8 d8[4]; } data[3] ____cacheline_aligned; }; @@ -267,7 +267,7 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { { }, }; -#define AD5868_CHANNEL(chan, bits, shift) { \ +#define AD5868_CHANNEL(chan, bits, _shift) { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ .output = 1, \ @@ -275,7 +275,12 @@ static const struct iio_chan_spec_ext_info ad5686_ext_info[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\ .address = AD5686_ADDR_DAC(chan), \ - .scan_type = IIO_ST('u', bits, 16, shift), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 16, \ + .shift = (_shift), \ + }, \ .ext_info = ad5686_ext_info, \ } diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index ee1e95a3a0c3..a7c851f62d7c 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -97,7 +97,7 @@ struct ad5755_state { */ union { - u32 d32; + __be32 d32; u8 d8[4]; } data[2] ____cacheline_aligned; }; @@ -392,7 +392,12 @@ static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { BIT(IIO_CHAN_INFO_OFFSET) | \ BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ - .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 16, \ + .shift = 16 - (_bits), \ + }, \ .ext_info = ad5755_ext_info, \ } diff --git a/drivers/iio/dac/ad5764.c b/drivers/iio/dac/ad5764.c index a8ff5b2ed13e..d0d38165339d 100644 --- a/drivers/iio/dac/ad5764.c +++ b/drivers/iio/dac/ad5764.c @@ -83,7 +83,12 @@ enum ad5764_type { BIT(IIO_CHAN_INFO_CALIBSCALE) | \ BIT(IIO_CHAN_INFO_CALIBBIAS), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET), \ - .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)) \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 16, \ + .shift = 16 - (_bits), \ + }, \ } #define DECLARE_AD5764_CHANNELS(_name, _bits) \ diff --git a/drivers/iio/dac/ad5791.c b/drivers/iio/dac/ad5791.c index d64acbd89482..ae49afe2b380 100644 --- a/drivers/iio/dac/ad5791.c +++ b/drivers/iio/dac/ad5791.c @@ -91,6 +91,11 @@ struct ad5791_state { unsigned ctrl; unsigned pwr_down_mode; bool pwr_down; + + union { + __be32 d32; + u8 d8[4]; + } data[3] ____cacheline_aligned; }; /** @@ -104,48 +109,39 @@ enum ad5791_supported_device_ids { ID_AD5791, }; -static int ad5791_spi_write(struct spi_device *spi, u8 addr, u32 val) +static int ad5791_spi_write(struct ad5791_state *st, u8 addr, u32 val) { - union { - u32 d32; - u8 d8[4]; - } data; - - data.d32 = cpu_to_be32(AD5791_CMD_WRITE | + st->data[0].d32 = cpu_to_be32(AD5791_CMD_WRITE | AD5791_ADDR(addr) | (val & AD5791_DAC_MASK)); - return spi_write(spi, &data.d8[1], 3); + return spi_write(st->spi, &st->data[0].d8[1], 3); } -static int ad5791_spi_read(struct spi_device *spi, u8 addr, u32 *val) +static int ad5791_spi_read(struct ad5791_state *st, u8 addr, u32 *val) { - union { - u32 d32; - u8 d8[4]; - } data[3]; int ret; struct spi_transfer xfers[] = { { - .tx_buf = &data[0].d8[1], + .tx_buf = &st->data[0].d8[1], .bits_per_word = 8, .len = 3, .cs_change = 1, }, { - .tx_buf = &data[1].d8[1], - .rx_buf = &data[2].d8[1], + .tx_buf = &st->data[1].d8[1], + .rx_buf = &st->data[2].d8[1], .bits_per_word = 8, .len = 3, }, }; - data[0].d32 = cpu_to_be32(AD5791_CMD_READ | + st->data[0].d32 = cpu_to_be32(AD5791_CMD_READ | AD5791_ADDR(addr)); - data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP)); + st->data[1].d32 = cpu_to_be32(AD5791_ADDR(AD5791_ADDR_NOOP)); - ret = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers)); + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers)); - *val = be32_to_cpu(data[2].d32); + *val = be32_to_cpu(st->data[2].d32); return ret; } @@ -210,7 +206,7 @@ static ssize_t ad5791_write_dac_powerdown(struct iio_dev *indio_dev, } st->pwr_down = pwr_down; - ret = ad5791_spi_write(st->spi, AD5791_ADDR_CTRL, st->ctrl); + ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl); return ret ? ret : len; } @@ -263,7 +259,7 @@ static int ad5791_read_raw(struct iio_dev *indio_dev, switch (m) { case IIO_CHAN_INFO_RAW: - ret = ad5791_spi_read(st->spi, chan->address, val); + ret = ad5791_spi_read(st, chan->address, val); if (ret) return ret; *val &= AD5791_DAC_MASK; @@ -297,7 +293,7 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { { }, }; -#define AD5791_CHAN(bits, shift) { \ +#define AD5791_CHAN(bits, _shift) { \ .type = IIO_VOLTAGE, \ .output = 1, \ .indexed = 1, \ @@ -306,7 +302,12 @@ static const struct iio_chan_spec_ext_info ad5791_ext_info[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ BIT(IIO_CHAN_INFO_OFFSET), \ - .scan_type = IIO_ST('u', bits, 24, shift), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (bits), \ + .storagebits = 24, \ + .shift = (_shift), \ + }, \ .ext_info = ad5791_ext_info, \ } @@ -330,7 +331,7 @@ static int ad5791_write_raw(struct iio_dev *indio_dev, val &= AD5791_RES_MASK(chan->scan_type.realbits); val <<= chan->scan_type.shift; - return ad5791_spi_write(st->spi, chan->address, val); + return ad5791_spi_write(st, chan->address, val); default: return -EINVAL; @@ -393,7 +394,7 @@ static int ad5791_probe(struct spi_device *spi) dev_warn(&spi->dev, "reference voltage unspecified\n"); } - ret = ad5791_spi_write(spi, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); + ret = ad5791_spi_write(st, AD5791_ADDR_SW_CTRL, AD5791_SWCTRL_RESET); if (ret) goto error_disable_reg_neg; @@ -405,7 +406,7 @@ static int ad5791_probe(struct spi_device *spi) | ((pdata && pdata->use_rbuf_gain2) ? 0 : AD5791_CTRL_RBUF) | AD5791_CTRL_BIN2SC; - ret = ad5791_spi_write(spi, AD5791_ADDR_CTRL, st->ctrl | + ret = ad5791_spi_write(st, AD5791_ADDR_CTRL, st->ctrl | AD5791_CTRL_OPGND | AD5791_CTRL_DACTRI); if (ret) goto error_disable_reg_neg; diff --git a/drivers/iio/dac/max517.c b/drivers/iio/dac/max517.c index 6e1903537950..de76e6a34c1e 100644 --- a/drivers/iio/dac/max517.c +++ b/drivers/iio/dac/max517.c @@ -146,7 +146,6 @@ static const struct iio_info max517_info = { .channel = (chan), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_SCALE), \ - .scan_type = IIO_ST('u', 8, 8, 0), \ } static const struct iio_chan_spec max517_channels[] = { diff --git a/drivers/iio/dac/mcp4725.c b/drivers/iio/dac/mcp4725.c index 9f57ae84ab89..7d9f5c31d2fc 100644 --- a/drivers/iio/dac/mcp4725.c +++ b/drivers/iio/dac/mcp4725.c @@ -209,7 +209,6 @@ static const struct iio_chan_spec mcp4725_channel = { .channel = 0, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), - .scan_type = IIO_ST('u', 12, 16, 0), .ext_info = mcp4725_ext_info, }; diff --git a/drivers/iio/humidity/Kconfig b/drivers/iio/humidity/Kconfig new file mode 100644 index 000000000000..463c4d9da79e --- /dev/null +++ b/drivers/iio/humidity/Kconfig @@ -0,0 +1,15 @@ +# +# humidity sensor drivers +# +menu "Humidity sensors" + +config DHT11 + tristate "DHT11 (and compatible sensors) driver" + depends on GPIOLIB + help + This driver supports reading data via a single interrupt + generating GPIO line. Currently tested are DHT11 and DHT22. + Other sensors should work as well as long as they speak the + same protocol. + +endmenu diff --git a/drivers/iio/humidity/Makefile b/drivers/iio/humidity/Makefile new file mode 100644 index 000000000000..d5d36c0c95f9 --- /dev/null +++ b/drivers/iio/humidity/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for IIO humidity sensor drivers +# + +obj-$(CONFIG_DHT11) += dht11.o diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c new file mode 100644 index 000000000000..d8771f546bf2 --- /dev/null +++ b/drivers/iio/humidity/dht11.c @@ -0,0 +1,294 @@ +/* + * DHT11/DHT22 bit banging GPIO driver + * + * Copyright (c) Harald Geyer <harald@ccbib.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/printk.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/sysfs.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/wait.h> +#include <linux/bitops.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> + +#include <linux/iio/iio.h> + +#define DRIVER_NAME "dht11" + +#define DHT11_DATA_VALID_TIME 2000000000 /* 2s in ns */ + +#define DHT11_EDGES_PREAMBLE 4 +#define DHT11_BITS_PER_READ 40 +#define DHT11_EDGES_PER_READ (2*DHT11_BITS_PER_READ + DHT11_EDGES_PREAMBLE + 1) + +/* Data transmission timing (nano seconds) */ +#define DHT11_START_TRANSMISSION 18 /* ms */ +#define DHT11_SENSOR_RESPONSE 80000 +#define DHT11_START_BIT 50000 +#define DHT11_DATA_BIT_LOW 27000 +#define DHT11_DATA_BIT_HIGH 70000 + +struct dht11 { + struct device *dev; + + int gpio; + int irq; + + struct completion completion; + + s64 timestamp; + int temperature; + int humidity; + + /* num_edges: -1 means "no transmission in progress" */ + int num_edges; + struct {s64 ts; int value; } edges[DHT11_EDGES_PER_READ]; +}; + +static unsigned char dht11_decode_byte(int *timing, int threshold) +{ + unsigned char ret = 0; + int i; + + for (i = 0; i < 8; ++i) { + ret <<= 1; + if (timing[i] >= threshold) + ++ret; + } + + return ret; +} + +static int dht11_decode(struct dht11 *dht11, int offset) +{ + int i, t, timing[DHT11_BITS_PER_READ], threshold, + timeres = DHT11_SENSOR_RESPONSE; + unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum; + + /* Calculate timestamp resolution */ + for (i = 0; i < dht11->num_edges; ++i) { + t = dht11->edges[i].ts - dht11->edges[i-1].ts; + if (t > 0 && t < timeres) + timeres = t; + } + if (2*timeres > DHT11_DATA_BIT_HIGH) { + pr_err("dht11: timeresolution %d too bad for decoding\n", + timeres); + return -EIO; + } + threshold = DHT11_DATA_BIT_HIGH / timeres; + if (DHT11_DATA_BIT_LOW/timeres + 1 >= threshold) + pr_err("dht11: WARNING: decoding ambiguous\n"); + + /* scale down with timeres and check validity */ + for (i = 0; i < DHT11_BITS_PER_READ; ++i) { + t = dht11->edges[offset + 2*i + 2].ts - + dht11->edges[offset + 2*i + 1].ts; + if (!dht11->edges[offset + 2*i + 1].value) + return -EIO; /* lost synchronisation */ + timing[i] = t / timeres; + } + + hum_int = dht11_decode_byte(timing, threshold); + hum_dec = dht11_decode_byte(&timing[8], threshold); + temp_int = dht11_decode_byte(&timing[16], threshold); + temp_dec = dht11_decode_byte(&timing[24], threshold); + checksum = dht11_decode_byte(&timing[32], threshold); + + if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum) + return -EIO; + + dht11->timestamp = iio_get_time_ns(); + if (hum_int < 20) { /* DHT22 */ + dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) * + ((temp_int & 0x80) ? -100 : 100); + dht11->humidity = ((hum_int << 8) + hum_dec) * 100; + } else if (temp_dec == 0 && hum_dec == 0) { /* DHT11 */ + dht11->temperature = temp_int * 1000; + dht11->humidity = hum_int * 1000; + } else { + dev_err(dht11->dev, + "Don't know how to decode data: %d %d %d %d\n", + hum_int, hum_dec, temp_int, temp_dec); + return -EIO; + } + + return 0; +} + +static int dht11_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long m) +{ + struct dht11 *dht11 = iio_priv(iio_dev); + int ret; + + if (dht11->timestamp + DHT11_DATA_VALID_TIME < iio_get_time_ns()) { + reinit_completion(&dht11->completion); + + dht11->num_edges = 0; + ret = gpio_direction_output(dht11->gpio, 0); + if (ret) + goto err; + msleep(DHT11_START_TRANSMISSION); + ret = gpio_direction_input(dht11->gpio); + if (ret) + goto err; + + ret = wait_for_completion_killable_timeout(&dht11->completion, + HZ); + if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) { + dev_err(&iio_dev->dev, + "Only %d signal edges detected\n", + dht11->num_edges); + ret = -ETIMEDOUT; + } + if (ret < 0) + goto err; + + ret = dht11_decode(dht11, + dht11->num_edges == DHT11_EDGES_PER_READ ? + DHT11_EDGES_PREAMBLE : + DHT11_EDGES_PREAMBLE - 2); + if (ret) + goto err; + } + + ret = IIO_VAL_INT; + if (chan->type == IIO_TEMP) + *val = dht11->temperature; + else if (chan->type == IIO_HUMIDITYRELATIVE) + *val = dht11->humidity; + else + ret = -EINVAL; +err: + dht11->num_edges = -1; + return ret; +} + +static const struct iio_info dht11_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = dht11_read_raw, +}; + +/* + * IRQ handler called on GPIO edges +*/ +static irqreturn_t dht11_handle_irq(int irq, void *data) +{ + struct iio_dev *iio = data; + struct dht11 *dht11 = iio_priv(iio); + + /* TODO: Consider making the handler safe for IRQ sharing */ + if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) { + dht11->edges[dht11->num_edges].ts = iio_get_time_ns(); + dht11->edges[dht11->num_edges++].value = + gpio_get_value(dht11->gpio); + + if (dht11->num_edges >= DHT11_EDGES_PER_READ) + complete(&dht11->completion); + } + + return IRQ_HANDLED; +} + +static const struct iio_chan_spec dht11_chan_spec[] = { + { .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }, + { .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), } +}; + +static const struct of_device_id dht11_dt_ids[] = { + { .compatible = "dht11", }, + { } +}; +MODULE_DEVICE_TABLE(of, dht11_dt_ids); + +static int dht11_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct dht11 *dht11; + struct iio_dev *iio; + int ret; + + iio = devm_iio_device_alloc(dev, sizeof(*dht11)); + if (!iio) { + dev_err(dev, "Failed to allocate IIO device\n"); + return -ENOMEM; + } + + dht11 = iio_priv(iio); + dht11->dev = dev; + + dht11->gpio = ret = of_get_gpio(node, 0); + if (ret < 0) + return ret; + ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name); + if (ret) + return ret; + + dht11->irq = gpio_to_irq(dht11->gpio); + if (dht11->irq < 0) { + dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio); + return -EINVAL; + } + ret = devm_request_irq(dev, dht11->irq, dht11_handle_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + pdev->name, iio); + if (ret) + return ret; + + dht11->timestamp = iio_get_time_ns() - DHT11_DATA_VALID_TIME - 1; + dht11->num_edges = -1; + + platform_set_drvdata(pdev, iio); + + init_completion(&dht11->completion); + iio->name = pdev->name; + iio->dev.parent = &pdev->dev; + iio->info = &dht11_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = dht11_chan_spec; + iio->num_channels = ARRAY_SIZE(dht11_chan_spec); + + return devm_iio_device_register(dev, iio); +} + +static struct platform_driver dht11_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = dht11_dt_ids, + }, + .probe = dht11_probe, +}; + +module_platform_driver(dht11_driver); + +MODULE_AUTHOR("Harald Geyer <harald@ccbib.org>"); +MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 7f9152c3c4d3..c67d83bdc8f0 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -37,6 +37,14 @@ static bool iio_buffer_is_active(struct iio_buffer *buf) return !list_empty(&buf->buffer_list); } +static bool iio_buffer_data_available(struct iio_buffer *buf) +{ + if (buf->access->data_available) + return buf->access->data_available(buf); + + return buf->stufftoread; +} + /** * iio_buffer_read_first_n_outer() - chrdev read for buffer access * @@ -48,13 +56,34 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf, { struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; + int ret; if (!indio_dev->info) return -ENODEV; if (!rb || !rb->access->read_first_n) return -EINVAL; - return rb->access->read_first_n(rb, n, buf); + + do { + if (!iio_buffer_data_available(rb)) { + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(rb->pollq, + iio_buffer_data_available(rb) || + indio_dev->info == NULL); + if (ret) + return ret; + if (indio_dev->info == NULL) + return -ENODEV; + } + + ret = rb->access->read_first_n(rb, n, buf); + if (ret == 0 && (filp->f_flags & O_NONBLOCK)) + ret = -EAGAIN; + } while (ret == 0); + + return ret; } /** @@ -70,7 +99,7 @@ unsigned int iio_buffer_poll(struct file *filp, return -ENODEV; poll_wait(filp, &rb->pollq, wait); - if (rb->stufftoread) + if (iio_buffer_data_available(rb)) return POLLIN | POLLRDNORM; /* need a way of knowing if there may be enough data... */ return 0; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2fe88c189f74..acc911a836ca 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -69,6 +69,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_ALTVOLTAGE] = "altvoltage", [IIO_CCT] = "cct", [IIO_PRESSURE] = "pressure", + [IIO_HUMIDITYRELATIVE] = "humidityrelative", }; static const char * const iio_modifier_names[] = { diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index bc043fab4cd1..c9c1419fe6e0 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -242,13 +242,9 @@ static ssize_t iio_ev_state_store(struct device *dev, if (ret < 0) return ret; - if (indio_dev->info->write_event_config) - ret = indio_dev->info->write_event_config(indio_dev, - this_attr->address, val); - else - ret = indio_dev->info->write_event_config_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr), val); + ret = indio_dev->info->write_event_config(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), val); return (ret < 0) ? ret : len; } @@ -261,13 +257,9 @@ static ssize_t iio_ev_state_show(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int val; - if (indio_dev->info->read_event_config) - val = indio_dev->info->read_event_config(indio_dev, - this_attr->address); - else - val = indio_dev->info->read_event_config_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr)); + val = indio_dev->info->read_event_config(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr)); if (val < 0) return val; else @@ -283,21 +275,13 @@ static ssize_t iio_ev_value_show(struct device *dev, int val, val2; int ret; - if (indio_dev->info->read_event_value) { - ret = indio_dev->info->read_event_value(indio_dev, - this_attr->address, &val); - if (ret < 0) - return ret; - return sprintf(buf, "%d\n", val); - } else { - ret = indio_dev->info->read_event_value_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), - &val, &val2); - if (ret < 0) - return ret; - return iio_format_value(buf, ret, val, val2); - } + ret = indio_dev->info->read_event_value(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), + &val, &val2); + if (ret < 0) + return ret; + return iio_format_value(buf, ret, val, val2); } static ssize_t iio_ev_value_store(struct device *dev, @@ -310,25 +294,16 @@ static ssize_t iio_ev_value_store(struct device *dev, int val, val2; int ret; - if (!indio_dev->info->write_event_value && - !indio_dev->info->write_event_value_new) + if (!indio_dev->info->write_event_value) return -EINVAL; - if (indio_dev->info->write_event_value) { - ret = kstrtoint(buf, 10, &val); - if (ret) - return ret; - ret = indio_dev->info->write_event_value(indio_dev, - this_attr->address, val); - } else { - ret = iio_str_to_fixpoint(buf, 100000, &val, &val2); - if (ret) - return ret; - ret = indio_dev->info->write_event_value_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), - val, val2); - } + ret = iio_str_to_fixpoint(buf, 100000, &val, &val2); + if (ret) + return ret; + ret = indio_dev->info->write_event_value(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), + val, val2); if (ret < 0) return ret; @@ -377,7 +352,7 @@ static int iio_device_add_event(struct iio_dev *indio_dev, return attrcount; } -static int iio_device_add_event_sysfs_new(struct iio_dev *indio_dev, +static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, struct iio_chan_spec const *chan) { int ret = 0, i, attrcount = 0; @@ -420,89 +395,6 @@ error_ret: return ret; } -static int iio_device_add_event_sysfs_old(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) -{ - int ret = 0, i, attrcount = 0; - u64 mask = 0; - char *postfix; - if (!chan->event_mask) - return 0; - - for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) { - postfix = kasprintf(GFP_KERNEL, "%s_%s_en", - iio_ev_type_text[i/IIO_EV_DIR_MAX], - iio_ev_dir_text[i%IIO_EV_DIR_MAX]); - if (postfix == NULL) { - ret = -ENOMEM; - goto error_ret; - } - if (chan->modified) - mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel2, - i/IIO_EV_DIR_MAX, - i%IIO_EV_DIR_MAX); - else if (chan->differential) - mask = IIO_EVENT_CODE(chan->type, - 0, 0, - i%IIO_EV_DIR_MAX, - i/IIO_EV_DIR_MAX, - 0, - chan->channel, - chan->channel2); - else - mask = IIO_UNMOD_EVENT_CODE(chan->type, - chan->channel, - i/IIO_EV_DIR_MAX, - i%IIO_EV_DIR_MAX); - - ret = __iio_add_chan_devattr(postfix, - chan, - &iio_ev_state_show, - iio_ev_state_store, - mask, - 0, - &indio_dev->dev, - &indio_dev->event_interface-> - dev_attr_list); - kfree(postfix); - if (ret) - goto error_ret; - attrcount++; - postfix = kasprintf(GFP_KERNEL, "%s_%s_value", - iio_ev_type_text[i/IIO_EV_DIR_MAX], - iio_ev_dir_text[i%IIO_EV_DIR_MAX]); - if (postfix == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = __iio_add_chan_devattr(postfix, chan, - iio_ev_value_show, - iio_ev_value_store, - mask, - 0, - &indio_dev->dev, - &indio_dev->event_interface-> - dev_attr_list); - kfree(postfix); - if (ret) - goto error_ret; - attrcount++; - } - ret = attrcount; -error_ret: - return ret; -} - - -static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) -{ - if (chan->event_mask) - return iio_device_add_event_sysfs_old(indio_dev, chan); - else - return iio_device_add_event_sysfs_new(indio_dev, chan); -} - static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) { int j, ret, attrcount = 0; @@ -523,8 +415,6 @@ static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev) int j; for (j = 0; j < indio_dev->num_channels; j++) { - if (indio_dev->channels[j].event_mask != 0) - return true; if (indio_dev->channels[j].num_event_specs != 0) return true; } diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 7ba2f002ffca..766fab24b720 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -55,15 +55,7 @@ static struct attribute *iio_trig_dev_attrs[] = { &dev_attr_name.attr, NULL, }; - -static struct attribute_group iio_trig_attr_group = { - .attrs = iio_trig_dev_attrs, -}; - -static const struct attribute_group *iio_trig_attr_groups[] = { - &iio_trig_attr_group, - NULL -}; +ATTRIBUTE_GROUPS(iio_trig_dev); int iio_trigger_register(struct iio_trigger *trig_info) { @@ -403,7 +395,7 @@ static void iio_trig_release(struct device *device) static struct device_type iio_trig_type = { .release = iio_trig_release, - .groups = iio_trig_attr_groups, + .groups = iio_trig_dev_groups, }; static void iio_trig_subirqmask(struct irq_data *d) diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index 95c6fc81c2c7..7134e8ada09a 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -42,7 +42,6 @@ static int iio_request_update_kfifo(struct iio_buffer *r) } else { kfifo_reset_out(&buf->kf); } - r->stufftoread = false; mutex_unlock(&buf->user_lock); return ret; @@ -108,7 +107,7 @@ static int iio_store_to_kfifo(struct iio_buffer *r, ret = kfifo_in(&kf->kf, data, 1); if (ret != 1) return -EBUSY; - r->stufftoread = true; + wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM); return 0; @@ -127,13 +126,6 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, ret = -EINVAL; else ret = kfifo_to_user(&kf->kf, buf, n, &copied); - - if (kfifo_is_empty(&kf->kf)) - r->stufftoread = false; - /* verify it is still empty to avoid race */ - if (!kfifo_is_empty(&kf->kf)) - r->stufftoread = true; - mutex_unlock(&kf->user_lock); if (ret < 0) return ret; @@ -141,6 +133,18 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, return copied; } +static bool iio_kfifo_buf_data_available(struct iio_buffer *r) +{ + struct iio_kfifo *kf = iio_to_kfifo(r); + bool empty; + + mutex_lock(&kf->user_lock); + empty = kfifo_is_empty(&kf->kf); + mutex_unlock(&kf->user_lock); + + return !empty; +} + static void iio_kfifo_buffer_release(struct iio_buffer *buffer) { struct iio_kfifo *kf = iio_to_kfifo(buffer); @@ -153,6 +157,7 @@ static void iio_kfifo_buffer_release(struct iio_buffer *buffer) static const struct iio_buffer_access_funcs kfifo_access_funcs = { .store_to = &iio_store_to_kfifo, .read_first_n = &iio_read_first_n_kfifo, + .data_available = iio_kfifo_buf_data_available, .request_update = &iio_request_update_kfifo, .get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo, .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo, diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 83d15c5baf64..f3068477b466 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -155,7 +155,12 @@ done: BIT(IIO_CHAN_INFO_INT_TIME), \ .channel2 = (IIO_MOD_LIGHT_##_color), \ .scan_index = (_scan_idx), \ - .scan_type = IIO_ST('u', 10, 16, 0), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 10, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ } static const struct iio_chan_spec adjd_s311_channels[] = { diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 51097bbd59c9..9ddde0ca9c34 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -344,10 +344,10 @@ static const struct iio_info apds9300_info_no_irq = { static const struct iio_info apds9300_info = { .driver_module = THIS_MODULE, .read_raw = apds9300_read_raw, - .read_event_value_new = apds9300_read_thresh, - .write_event_value_new = apds9300_write_thresh, - .read_event_config_new = apds9300_read_interrupt_config, - .write_event_config_new = apds9300_write_interrupt_config, + .read_event_value = apds9300_read_thresh, + .write_event_value = apds9300_write_thresh, + .read_event_config = apds9300_read_interrupt_config, + .write_event_config = apds9300_write_interrupt_config, }; static const struct iio_event_spec apds9300_event_spec[] = { diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 0922e39b0ea9..0a142af83e25 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -488,7 +488,11 @@ static int cm36651_write_raw(struct iio_dev *indio_dev, } static int cm36651_read_prox_thresh(struct iio_dev *indio_dev, - u64 event_code, int *val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) { struct cm36651_data *cm36651 = iio_priv(indio_dev); @@ -498,7 +502,11 @@ static int cm36651_read_prox_thresh(struct iio_dev *indio_dev, } static int cm36651_write_prox_thresh(struct iio_dev *indio_dev, - u64 event_code, int val) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) { struct cm36651_data *cm36651 = iio_priv(indio_dev); struct i2c_client *client = cm36651->client; @@ -520,7 +528,10 @@ static int cm36651_write_prox_thresh(struct iio_dev *indio_dev, } static int cm36651_write_prox_event_config(struct iio_dev *indio_dev, - u64 event_code, int state) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + int state) { struct cm36651_data *cm36651 = iio_priv(indio_dev); int cmd, ret = -EINVAL; @@ -536,7 +547,9 @@ static int cm36651_write_prox_event_config(struct iio_dev *indio_dev, } static int cm36651_read_prox_event_config(struct iio_dev *indio_dev, - u64 event_code) + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) { struct cm36651_data *cm36651 = iio_priv(indio_dev); int event_en; @@ -559,12 +572,22 @@ static int cm36651_read_prox_event_config(struct iio_dev *indio_dev, .channel2 = IIO_MOD_LIGHT_##_color, \ } \ +static const struct iio_event_spec cm36651_event_spec[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + } +}; + static const struct iio_chan_spec cm36651_channels[] = { { .type = IIO_PROXIMITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_INT_TIME), - .event_mask = IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_EITHER) + .event_spec = cm36651_event_spec, + .num_event_specs = ARRAY_SIZE(cm36651_event_spec), }, CM36651_LIGHT_CHANNEL(RED, CM36651_LIGHT_CHANNEL_IDX_RED), CM36651_LIGHT_CHANNEL(GREEN, CM36651_LIGHT_CHANNEL_IDX_GREEN), @@ -693,7 +716,7 @@ static const struct of_device_id cm36651_of_match[] = { static struct i2c_driver cm36651_driver = { .driver = { .name = "cm36651", - .of_match_table = of_match_ptr(cm36651_of_match), + .of_match_table = cm36651_of_match, .owner = THIS_MODULE, }, .probe = cm36651_probe, diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index dc79835be308..5ea4a03c7e71 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1388,10 +1388,10 @@ static const struct iio_chan_spec gp2ap020a00f_channels[] = { static const struct iio_info gp2ap020a00f_info = { .read_raw = &gp2ap020a00f_read_raw, - .read_event_value_new = &gp2ap020a00f_read_event_val, - .read_event_config_new = &gp2ap020a00f_read_event_config, - .write_event_value_new = &gp2ap020a00f_write_event_val, - .write_event_config_new = &gp2ap020a00f_write_event_config, + .read_event_value = &gp2ap020a00f_read_event_val, + .read_event_config = &gp2ap020a00f_read_event_config, + .write_event_value = &gp2ap020a00f_write_event_val, + .write_event_config = &gp2ap020a00f_write_event_config, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/light/tcs3472.c b/drivers/iio/light/tcs3472.c index 45df2204614a..887fecf1f9bb 100644 --- a/drivers/iio/light/tcs3472.c +++ b/drivers/iio/light/tcs3472.c @@ -67,7 +67,12 @@ struct tcs3472_data { .channel2 = IIO_MOD_LIGHT_##_color, \ .address = _addr, \ .scan_index = _si, \ - .scan_type = IIO_ST('u', 16, 16, 0), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ } static const int tcs3472_agains[] = { 1, 4, 16, 60 }; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 0c6e459c86b1..3d8110157f2d 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -702,10 +702,10 @@ static const struct iio_info tsl2563_info = { .driver_module = THIS_MODULE, .read_raw = &tsl2563_read_raw, .write_raw = &tsl2563_write_raw, - .read_event_value_new = &tsl2563_read_thresh, - .write_event_value_new = &tsl2563_write_thresh, - .read_event_config_new = &tsl2563_read_interrupt_config, - .write_event_config_new = &tsl2563_write_interrupt_config, + .read_event_value = &tsl2563_read_thresh, + .write_event_value = &tsl2563_write_thresh, + .read_event_config = &tsl2563_read_interrupt_config, + .write_event_config = &tsl2563_write_interrupt_config, }; static int tsl2563_probe(struct i2c_client *client, diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index 384ac23f576f..d948c4778ba6 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -56,7 +56,7 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask, u8 rdy_mask, u8 data_reg, int *val) { int tries = 20; - u16 buf; + __be16 buf; int ret; ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND, diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index becf54496967..4b65b6d3bdb1 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -266,7 +266,11 @@ static const struct iio_chan_spec mag3110_channels[] = { .type = IIO_TEMP, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .scan_index = 3, - .scan_type = IIO_ST('s', 8, 8, 0), + .scan_type = { + .sign = 's', + .realbits = 8, + .storagebits = 8, + }, }, IIO_CHAN_SOFT_TIMESTAMP(4), }; diff --git a/drivers/iio/orientation/Kconfig b/drivers/iio/orientation/Kconfig new file mode 100644 index 000000000000..58c62c837e12 --- /dev/null +++ b/drivers/iio/orientation/Kconfig @@ -0,0 +1,19 @@ +# +# Inclinometer sensors +# +# When adding new entries keep the list in alphabetical order + +menu "Inclinometer sensors" + +config HID_SENSOR_INCLINOMETER_3D + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + select HID_SENSOR_IIO_TRIGGER + tristate "HID Inclinometer 3D" + help + Say yes here to build support for the HID SENSOR + Inclinometer 3D. + +endmenu diff --git a/drivers/iio/orientation/Makefile b/drivers/iio/orientation/Makefile new file mode 100644 index 000000000000..2c97572ee919 --- /dev/null +++ b/drivers/iio/orientation/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for industrial I/O Inclinometer sensor drivers +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_HID_SENSOR_INCLINOMETER_3D) += hid-sensor-incl-3d.o diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c new file mode 100644 index 000000000000..070feab08faa --- /dev/null +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -0,0 +1,428 @@ +/* + * HID Sensors Driver + * Copyright (c) 2013, 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. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc. + * + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/slab.h> +#include <linux/hid-sensor-hub.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include "../common/hid-sensors/hid-sensor-trigger.h" + +enum incl_3d_channel { + CHANNEL_SCAN_INDEX_X, + CHANNEL_SCAN_INDEX_Y, + CHANNEL_SCAN_INDEX_Z, + INCLI_3D_CHANNEL_MAX, +}; + +struct incl_3d_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; + u32 incl_val[INCLI_3D_CHANNEL_MAX]; +}; + +static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { + HID_USAGE_SENSOR_ORIENT_TILT_X, + HID_USAGE_SENSOR_ORIENT_TILT_Y, + HID_USAGE_SENSOR_ORIENT_TILT_Z +}; + +/* Channel definitions */ +static const struct iio_chan_spec incl_3d_channels[] = { + { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_X, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_Y, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_Z, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, + int size) +{ + chan->scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + chan->scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + chan->scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int incl_3d_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct incl_3d_state *incl_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case IIO_CHAN_INFO_RAW: + report_id = + incl_state->incl[chan->scan_index].report_id; + address = incl_3d_addresses[chan->scan_index]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + incl_state->common_attributes.hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, address, + report_id); + else { + return -EINVAL; + } + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = incl_state->incl[CHANNEL_SCAN_INDEX_X].units; + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + incl_state->incl[CHANNEL_SCAN_INDEX_X].unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret_type = hid_sensor_read_samp_freq_value( + &incl_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret_type = hid_sensor_read_raw_hyst_value( + &incl_state->common_attributes, val, val2); + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int incl_3d_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct incl_3d_state *incl_state = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &incl_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &incl_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct iio_info incl_3d_info = { + .driver_module = THIS_MODULE, + .read_raw = &incl_3d_read_raw, + .write_raw = &incl_3d_write_raw, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + iio_push_to_buffers(indio_dev, (u8 *)data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct incl_3d_state *incl_state = iio_priv(indio_dev); + + dev_dbg(&indio_dev->dev, "incl_3d_proc_event [%d]\n", + incl_state->common_attributes.data_ready); + if (incl_state->common_attributes.data_ready) + hid_sensor_push_data(indio_dev, + (u8 *)incl_state->incl_val, + sizeof(incl_state->incl_val)); + + return 0; +} + +/* Capture samples in local storage */ +static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + size_t raw_len, char *raw_data, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct incl_3d_state *incl_state = iio_priv(indio_dev); + int ret = 0; + + switch (usage_id) { + case HID_USAGE_SENSOR_ORIENT_TILT_X: + incl_state->incl_val[CHANNEL_SCAN_INDEX_X] = *(u32 *)raw_data; + break; + case HID_USAGE_SENSOR_ORIENT_TILT_Y: + incl_state->incl_val[CHANNEL_SCAN_INDEX_Y] = *(u32 *)raw_data; + break; + case HID_USAGE_SENSOR_ORIENT_TILT_Z: + incl_state->incl_val[CHANNEL_SCAN_INDEX_Z] = *(u32 *)raw_data; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int incl_3d_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct incl_3d_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_TILT_X, + &st->incl[CHANNEL_SCAN_INDEX_X]); + if (ret) + return ret; + incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_X], + st->incl[CHANNEL_SCAN_INDEX_X].size); + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_TILT_Y, + &st->incl[CHANNEL_SCAN_INDEX_Y]); + if (ret) + return ret; + incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Y], + st->incl[CHANNEL_SCAN_INDEX_Y].size); + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_TILT_Z, + &st->incl[CHANNEL_SCAN_INDEX_Z]); + if (ret) + return ret; + incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Z], + st->incl[CHANNEL_SCAN_INDEX_Z].size); + + dev_dbg(&pdev->dev, "incl_3d %x:%x, %x:%x, %x:%x\n", + st->incl[0].index, + st->incl[0].report_id, + st->incl[1].index, st->incl[1].report_id, + st->incl[2].index, st->incl[2].report_id); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ORIENTATION, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + return ret; +} + +/* Function to initialize the processing for usage id */ +static int hid_incl_3d_probe(struct platform_device *pdev) +{ + int ret; + static char *name = "incli_3d"; + struct iio_dev *indio_dev; + struct incl_3d_state *incl_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(struct incl_3d_state)); + if (indio_dev == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + + incl_state = iio_priv(indio_dev); + incl_state->common_attributes.hsdev = hsdev; + incl_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, + &incl_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + return ret; + } + + channels = kmemdup(incl_3d_channels, sizeof(incl_3d_channels), + GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + return -ENOMEM; + } + + ret = incl_3d_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_INCLINOMETER_3D, incl_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &incl_3d_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + incl_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &incl_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "trigger setup failed\n"); + goto error_unreg_buffer_funcs; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_trigger; + } + + incl_state->callbacks.send_event = incl_3d_proc_event; + incl_state->callbacks.capture_sample = incl_3d_capture_sample; + incl_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, + &incl_state->callbacks); + if (ret) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return 0; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(&incl_state->common_attributes); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int hid_incl_3d_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct incl_3d_state *incl_state = iio_priv(indio_dev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(&incl_state->common_attributes); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + + return 0; +} + +static struct platform_device_id hid_incl_3d_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200086", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_incl_3d_ids); + +static struct platform_driver hid_incl_3d_platform_driver = { + .id_table = hid_incl_3d_ids, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = hid_incl_3d_probe, + .remove = hid_incl_3d_remove, +}; +module_platform_driver(hid_incl_3d_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Inclinometer 3D"); +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); +MODULE_LICENSE("GPL"); |