From 9d47964bfd471f0dd4c89f28556aec68bffa0020 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 25 Jul 2016 23:40:01 +0100 Subject: iio: ad5755: fix off-by-one on devnr limit check The comparison for devnr limits is off-by-one, the current check allows 0 to AD5755_NUM_CHANNELS and the limit should be in fact 0 to AD5755_NUM_CHANNELS - 1. This can lead to an out of bounds write to pdata->dac[devnr]. Fix this by replacing > with >= on the comparison. Signed-off-by: Colin Ian King Fixes: c947459979c6 ("iio: ad5755: add support for dt bindings") Signed-off-by: Jonathan Cameron --- drivers/iio/dac/ad5755.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c index 0fde593ec0d9..5f7968232564 100644 --- a/drivers/iio/dac/ad5755.c +++ b/drivers/iio/dac/ad5755.c @@ -655,7 +655,7 @@ static struct ad5755_platform_data *ad5755_parse_dt(struct device *dev) devnr = 0; for_each_child_of_node(np, pp) { - if (devnr > AD5755_NUM_CHANNELS) { + if (devnr >= AD5755_NUM_CHANNELS) { dev_err(dev, "There is to many channels defined in DT\n"); goto error_out; -- cgit v1.2.3 From 8c9e7b1bf42af845f83350e5141fbc4181dc7f98 Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Wed, 24 Aug 2016 22:48:43 -0700 Subject: iio: adc: ltc2485: add support for Linear Technology LTC2485 ADC Adds basic support for the LTC2485 ADC - a delta-sigma analog-to-digital converter with an I2C interface that operates in single shot conversion mode. The driver supports an on board 5V reference and the power-on default configuration which rejects both 50hz & 60hz line frequencies and operates in 1x speed mode. Signed-off-by: Alison Schofield Cc: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 9 +++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ltc2485.c | 148 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 drivers/iio/adc/ltc2485.c (limited to 'drivers/iio') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index e4022fd89393..6eac9236dff1 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -264,6 +264,15 @@ config LPC18XX_ADC To compile this driver as a module, choose M here: the module will be called lpc18xx_adc. +config LTC2485 + tristate "Linear Technology LTC2485 ADC driver" + depends on I2C + help + Say yes here to build support for Linear Technology LTC2485 ADC. + + To compile this driver as a module, choose M here: the module will be + called ltc2485. + config MAX1027 tristate "Maxim max1027 ADC driver" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 33254eb96bec..f46dd1fdebae 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o +obj-$(CONFIG_LTC2485) += ltc2485.o obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MCP320X) += mcp320x.o diff --git a/drivers/iio/adc/ltc2485.c b/drivers/iio/adc/ltc2485.c new file mode 100644 index 000000000000..eab91f12454a --- /dev/null +++ b/drivers/iio/adc/ltc2485.c @@ -0,0 +1,148 @@ +/* + * ltc2485.c - Driver for Linear Technology LTC2485 ADC + * + * Copyright (C) 2016 Alison Schofield + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Datasheet: http://cds.linear.com/docs/en/datasheet/2485fd.pdf + */ + +#include +#include +#include + +#include +#include + +/* Power-on configuration: rejects both 50/60Hz, operates at 1x speed */ +#define LTC2485_CONFIG_DEFAULT 0 + +struct ltc2485_data { + struct i2c_client *client; + ktime_t time_prev; /* last conversion */ +}; + +static void ltc2485_wait_conv(struct ltc2485_data *data) +{ + const unsigned int conv_time = 147; /* conversion time ms */ + unsigned int time_elapsed; + + /* delay if conversion time not passed since last read or write */ + time_elapsed = ktime_ms_delta(ktime_get(), data->time_prev); + + if (time_elapsed < conv_time) + msleep(conv_time - time_elapsed); +} + +static int ltc2485_read(struct ltc2485_data *data, int *val) +{ + struct i2c_client *client = data->client; + __be32 buf = 0; + int ret; + + ltc2485_wait_conv(data); + + ret = i2c_master_recv(client, (char *)&buf, 4); + if (ret < 0) { + dev_err(&client->dev, "i2c_master_recv failed\n"); + return ret; + } + data->time_prev = ktime_get(); + *val = sign_extend32(be32_to_cpu(buf) >> 6, 24); + + return ret; +} + +static int ltc2485_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ltc2485_data *data = iio_priv(indio_dev); + int ret; + + if (mask == IIO_CHAN_INFO_RAW) { + ret = ltc2485_read(data, val); + if (ret < 0) + return ret; + + return IIO_VAL_INT; + + } else if (mask == IIO_CHAN_INFO_SCALE) { + *val = 5000; /* on board vref millivolts */ + *val2 = 25; /* 25 (24 + sign) data bits */ + return IIO_VAL_FRACTIONAL_LOG2; + + } else { + return -EINVAL; + } +} + +static const struct iio_chan_spec ltc2485_channel[] = { + { + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) + }, +}; + +static const struct iio_info ltc2485_info = { + .read_raw = ltc2485_read_raw, + .driver_module = THIS_MODULE, +}; + +static int ltc2485_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct ltc2485_data *data; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | + I2C_FUNC_SMBUS_WRITE_BYTE)) + return -EOPNOTSUPP; + + 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; + + indio_dev->dev.parent = &client->dev; + indio_dev->name = id->name; + indio_dev->info = <c2485_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ltc2485_channel; + indio_dev->num_channels = ARRAY_SIZE(ltc2485_channel); + + ret = i2c_smbus_write_byte(data->client, LTC2485_CONFIG_DEFAULT); + if (ret < 0) + return ret; + + data->time_prev = ktime_get(); + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id ltc2485_id[] = { + { "ltc2485", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ltc2485_id); + +static struct i2c_driver ltc2485_driver = { + .driver = { + .name = "ltc2485", + }, + .probe = ltc2485_probe, + .id_table = ltc2485_id, +}; +module_i2c_driver(ltc2485_driver); + +MODULE_AUTHOR("Alison Schofield "); +MODULE_DESCRIPTION("Linear Technology LTC2485 ADC driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8376882f167be87aa44acc105020417532ac3c51 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 24 Aug 2016 23:44:47 -0700 Subject: iio: chemical: vz89x: abstract chip configuration Abstract chip configuration data to allow supporting multiple variants of the VZ89 chemical sensor line. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/vz89x.c | 80 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 18 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 652649da500f..aa6ebc084e19 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -19,25 +19,45 @@ #include #include #include +#include +#include #include #include #define VZ89X_REG_MEASUREMENT 0x09 -#define VZ89X_REG_MEASUREMENT_SIZE 6 +#define VZ89X_REG_MEASUREMENT_RD_SIZE 6 +#define VZ89X_REG_MEASUREMENT_WR_SIZE 3 #define VZ89X_VOC_CO2_IDX 0 #define VZ89X_VOC_SHORT_IDX 1 #define VZ89X_VOC_TVOC_IDX 2 #define VZ89X_VOC_RESISTANCE_IDX 3 +enum { + VZ89X, +}; + +struct vz89x_chip_data; + struct vz89x_data { struct i2c_client *client; + const struct vz89x_chip_data *chip; struct mutex lock; int (*xfer)(struct vz89x_data *data, u8 cmd); unsigned long last_update; - u8 buffer[VZ89X_REG_MEASUREMENT_SIZE]; + u8 buffer[VZ89X_REG_MEASUREMENT_RD_SIZE]; +}; + +struct vz89x_chip_data { + bool (*valid)(struct vz89x_data *data); + const struct iio_chan_spec *channels; + u8 num_channels; + + u8 cmd; + u8 read_size; + u8 write_size; }; static const struct iio_chan_spec vz89x_channels[] = { @@ -93,16 +113,17 @@ static const struct attribute_group vz89x_attrs_group = { * always zero, and by also confirming the VOC_short isn't zero. */ -static int vz89x_measurement_is_valid(struct vz89x_data *data) +static bool vz89x_measurement_is_valid(struct vz89x_data *data) { if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0) return 1; - return !!(data->buffer[VZ89X_REG_MEASUREMENT_SIZE - 1] > 0); + return !!(data->buffer[data->chip->read_size - 1] > 0); } static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) { + const struct vz89x_chip_data *chip = data->chip; struct i2c_client *client = data->client; struct i2c_msg msg[2]; int ret; @@ -110,12 +131,12 @@ static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) msg[0].addr = client->addr; msg[0].flags = client->flags; - msg[0].len = 3; + msg[0].len = chip->write_size; msg[0].buf = (char *) &buf; msg[1].addr = client->addr; msg[1].flags = client->flags | I2C_M_RD; - msg[1].len = VZ89X_REG_MEASUREMENT_SIZE; + msg[1].len = chip->read_size; msg[1].buf = (char *) &data->buffer; ret = i2c_transfer(client->adapter, msg, 2); @@ -133,7 +154,7 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd) if (ret < 0) return ret; - for (i = 0; i < VZ89X_REG_MEASUREMENT_SIZE; i++) { + for (i = 0; i < data->chip->read_size; i++) { ret = i2c_smbus_read_byte(client); if (ret < 0) return ret; @@ -145,17 +166,18 @@ static int vz89x_smbus_xfer(struct vz89x_data *data, u8 cmd) static int vz89x_get_measurement(struct vz89x_data *data) { + const struct vz89x_chip_data *chip = data->chip; int ret; /* sensor can only be polled once a second max per datasheet */ if (!time_after(jiffies, data->last_update + HZ)) return 0; - ret = data->xfer(data, VZ89X_REG_MEASUREMENT); + ret = data->xfer(data, chip->cmd); if (ret < 0) return ret; - ret = vz89x_measurement_is_valid(data); + ret = chip->valid(data); if (ret) return -EAGAIN; @@ -232,11 +254,32 @@ static const struct iio_info vz89x_info = { .driver_module = THIS_MODULE, }; +static const struct vz89x_chip_data vz89x_chips[] = { + { + .valid = vz89x_measurement_is_valid, + + .cmd = VZ89X_REG_MEASUREMENT, + .read_size = VZ89X_REG_MEASUREMENT_RD_SIZE, + .write_size = VZ89X_REG_MEASUREMENT_WR_SIZE, + + .channels = vz89x_channels, + .num_channels = ARRAY_SIZE(vz89x_channels), + }, +}; + +static const struct of_device_id vz89x_dt_ids[] = { + { .compatible = "sgx,vz89x", .data = (void *) VZ89X }, + { } +}; +MODULE_DEVICE_TABLE(of, vz89x_dt_ids); + static int vz89x_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct iio_dev *indio_dev; struct vz89x_data *data; + const struct of_device_id *of_id; + int chip_id; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!indio_dev) @@ -251,8 +294,15 @@ static int vz89x_probe(struct i2c_client *client, else return -EOPNOTSUPP; + of_id = of_match_device(vz89x_dt_ids, &client->dev); + if (!of_id) + chip_id = id->driver_data; + else + chip_id = (unsigned long)of_id->data; + i2c_set_clientdata(client, indio_dev); data->client = client; + data->chip = &vz89x_chips[chip_id]; data->last_update = jiffies - HZ; mutex_init(&data->lock); @@ -261,24 +311,18 @@ static int vz89x_probe(struct i2c_client *client, indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = vz89x_channels; - indio_dev->num_channels = ARRAY_SIZE(vz89x_channels); + indio_dev->channels = data->chip->channels; + indio_dev->num_channels = data->chip->num_channels; return devm_iio_device_register(&client->dev, indio_dev); } static const struct i2c_device_id vz89x_id[] = { - { "vz89x", 0 }, + { "vz89x", VZ89X }, { } }; MODULE_DEVICE_TABLE(i2c, vz89x_id); -static const struct of_device_id vz89x_dt_ids[] = { - { .compatible = "sgx,vz89x" }, - { } -}; -MODULE_DEVICE_TABLE(of, vz89x_dt_ids); - static struct i2c_driver vz89x_driver = { .driver = { .name = "vz89x", -- cgit v1.2.3 From 0a735aa07f2eb5bcb04fb022b463c70cd1cf1399 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 24 Aug 2016 23:44:48 -0700 Subject: iio: chemical: vz89x: add support for VZ89TE part Add support the VZ89TE variant which removes the voc_short channel, and has CRC check for data transactions. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/vz89x.c | 113 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 98 insertions(+), 15 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index aa6ebc084e19..289d2919deea 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -34,8 +34,17 @@ #define VZ89X_VOC_TVOC_IDX 2 #define VZ89X_VOC_RESISTANCE_IDX 3 +#define VZ89TE_REG_MEASUREMENT 0x0c +#define VZ89TE_REG_MEASUREMENT_RD_SIZE 7 +#define VZ89TE_REG_MEASUREMENT_WR_SIZE 6 + +#define VZ89TE_VOC_TVOC_IDX 0 +#define VZ89TE_VOC_CO2_IDX 1 +#define VZ89TE_VOC_RESISTANCE_IDX 2 + enum { VZ89X, + VZ89TE, }; struct vz89x_chip_data; @@ -47,7 +56,7 @@ struct vz89x_data { int (*xfer)(struct vz89x_data *data, u8 cmd); unsigned long last_update; - u8 buffer[VZ89X_REG_MEASUREMENT_RD_SIZE]; + u8 buffer[VZ89TE_REG_MEASUREMENT_RD_SIZE]; }; struct vz89x_chip_data { @@ -90,6 +99,40 @@ static const struct iio_chan_spec vz89x_channels[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), .address = VZ89X_VOC_RESISTANCE_IDX, + .scan_index = -1, + .scan_type = { + .endianness = IIO_LE, + }, + }, +}; + +static const struct iio_chan_spec vz89te_channels[] = { + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_VOC, + .modified = 1, + .info_mask_separate = + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW), + .address = VZ89TE_VOC_TVOC_IDX, + }, + + { + .type = IIO_CONCENTRATION, + .channel2 = IIO_MOD_CO2, + .modified = 1, + .info_mask_separate = + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_RAW), + .address = VZ89TE_VOC_CO2_IDX, + }, + { + .type = IIO_RESISTANCE, + .info_mask_separate = + BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), + .address = VZ89TE_VOC_RESISTANCE_IDX, + .scan_index = -1, + .scan_type = { + .endianness = IIO_BE, + }, }, }; @@ -121,13 +164,28 @@ static bool vz89x_measurement_is_valid(struct vz89x_data *data) return !!(data->buffer[data->chip->read_size - 1] > 0); } +/* VZ89TE device has a modified CRC-8 two complement check */ +static bool vz89te_measurement_is_valid(struct vz89x_data *data) +{ + u8 crc = 0; + int i, sum = 0; + + for (i = 0; i < (data->chip->read_size - 1); i++) { + sum = crc + data->buffer[i]; + crc = sum; + crc += sum / 256; + } + + return !((0xff - crc) == data->buffer[data->chip->read_size - 1]); +} + static int vz89x_i2c_xfer(struct vz89x_data *data, u8 cmd) { const struct vz89x_chip_data *chip = data->chip; struct i2c_client *client = data->client; struct i2c_msg msg[2]; int ret; - u8 buf[3] = { cmd, 0, 0}; + u8 buf[6] = { cmd, 0, 0, 0, 0, 0xf3 }; msg[0].addr = client->addr; msg[0].flags = client->flags; @@ -186,11 +244,24 @@ static int vz89x_get_measurement(struct vz89x_data *data) return 0; } -static int vz89x_get_resistance_reading(struct vz89x_data *data) +static int vz89x_get_resistance_reading(struct vz89x_data *data, + struct iio_chan_spec const *chan, + int *val) { - u8 *buf = &data->buffer[VZ89X_VOC_RESISTANCE_IDX]; + u8 *tmp = (u8 *) &data->buffer[chan->address]; - return buf[0] | (buf[1] << 8); + switch (chan->scan_type.endianness) { + case IIO_LE: + *val = le32_to_cpup((__le32 *) tmp) & GENMASK(23, 0); + break; + case IIO_BE: + *val = be32_to_cpup((__be32 *) tmp) >> 8; + break; + default: + return -EINVAL; + } + + return 0; } static int vz89x_read_raw(struct iio_dev *indio_dev, @@ -209,15 +280,15 @@ static int vz89x_read_raw(struct iio_dev *indio_dev, if (ret) return ret; - switch (chan->address) { - case VZ89X_VOC_CO2_IDX: - case VZ89X_VOC_SHORT_IDX: - case VZ89X_VOC_TVOC_IDX: + switch (chan->type) { + case IIO_CONCENTRATION: *val = data->buffer[chan->address]; return IIO_VAL_INT; - case VZ89X_VOC_RESISTANCE_IDX: - *val = vz89x_get_resistance_reading(data); - return IIO_VAL_INT; + case IIO_RESISTANCE: + ret = vz89x_get_resistance_reading(data, chan, val); + if (!ret) + return IIO_VAL_INT; + break; default: return -EINVAL; } @@ -232,12 +303,12 @@ static int vz89x_read_raw(struct iio_dev *indio_dev, } break; case IIO_CHAN_INFO_OFFSET: - switch (chan->address) { - case VZ89X_VOC_CO2_IDX: + switch (chan->channel2) { + case IIO_MOD_CO2: *val = 44; *val2 = 250000; return IIO_VAL_INT_PLUS_MICRO; - case VZ89X_VOC_TVOC_IDX: + case IIO_MOD_VOC: *val = -13; return IIO_VAL_INT; default: @@ -265,10 +336,21 @@ static const struct vz89x_chip_data vz89x_chips[] = { .channels = vz89x_channels, .num_channels = ARRAY_SIZE(vz89x_channels), }, + { + .valid = vz89te_measurement_is_valid, + + .cmd = VZ89TE_REG_MEASUREMENT, + .read_size = VZ89TE_REG_MEASUREMENT_RD_SIZE, + .write_size = VZ89TE_REG_MEASUREMENT_WR_SIZE, + + .channels = vz89te_channels, + .num_channels = ARRAY_SIZE(vz89te_channels), + }, }; static const struct of_device_id vz89x_dt_ids[] = { { .compatible = "sgx,vz89x", .data = (void *) VZ89X }, + { .compatible = "sgx,vz89te", .data = (void *) VZ89TE }, { } }; MODULE_DEVICE_TABLE(of, vz89x_dt_ids); @@ -319,6 +401,7 @@ static int vz89x_probe(struct i2c_client *client, static const struct i2c_device_id vz89x_id[] = { { "vz89x", VZ89X }, + { "vz89te", VZ89TE }, { } }; MODULE_DEVICE_TABLE(i2c, vz89x_id); -- cgit v1.2.3 From 9d1894cd197e297c9ced5393fde6416324b7706d Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Wed, 24 Aug 2016 23:44:49 -0700 Subject: iio: chemical: vz89x: prevent corrupted buffer from being read Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/vz89x.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index 289d2919deea..cd3870ead3fd 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -55,6 +55,7 @@ struct vz89x_data { struct mutex lock; int (*xfer)(struct vz89x_data *data, u8 cmd); + bool is_valid; unsigned long last_update; u8 buffer[VZ89TE_REG_MEASUREMENT_RD_SIZE]; }; @@ -229,7 +230,10 @@ static int vz89x_get_measurement(struct vz89x_data *data) /* sensor can only be polled once a second max per datasheet */ if (!time_after(jiffies, data->last_update + HZ)) - return 0; + return data->is_valid ? 0 : -EAGAIN; + + data->is_valid = false; + data->last_update = jiffies; ret = data->xfer(data, chip->cmd); if (ret < 0) @@ -239,7 +243,7 @@ static int vz89x_get_measurement(struct vz89x_data *data) if (ret) return -EAGAIN; - data->last_update = jiffies; + data->is_valid = true; return 0; } -- cgit v1.2.3 From 7f270bc9a2d95967c09e759776a28a8d2a345c74 Mon Sep 17 00:00:00 2001 From: Gwenhael Goavec-Merou Date: Wed, 24 Aug 2016 16:44:20 +0200 Subject: iio: dac: AD8801: add Analog Devices AD8801/AD8803 support Add support for Analog Devices AD8801/AD8803, 8 channels 8bits, Digital to Analog converters. Signed-off-by: Gwenhael Goavec-Merou Signed-off-by: Jonathan Cameron --- drivers/iio/dac/Kconfig | 10 ++ drivers/iio/dac/Makefile | 1 + drivers/iio/dac/ad8801.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 drivers/iio/dac/ad8801.c (limited to 'drivers/iio') diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index b9f044249194..e8656ba9bbb8 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -190,6 +190,16 @@ config CIO_DAC base port addresses for the devices may be configured via the base array module parameter. +config AD8801 + tristate "Analog Devices AD8801/AD8803 DAC driver" + depends on SPI_MASTER + help + Say yes here to build support for Analog Devices AD8801, AD8803 Digital to + Analog Converters (DAC). + + To compile this driver as a module choose M here: the module will be called + ad8801. + config LPC18XX_DAC tristate "NXP LPC18xx DAC driver" depends on ARCH_LPC18XX || COMPILE_TEST diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index b1a120612462..c50dbe082a70 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o obj-$(CONFIG_AD7303) += ad7303.o +obj-$(CONFIG_AD8801) += ad8801.o obj-$(CONFIG_CIO_DAC) += cio-dac.o obj-$(CONFIG_LPC18XX_DAC) += lpc18xx_dac.o obj-$(CONFIG_M62332) += m62332.o diff --git a/drivers/iio/dac/ad8801.c b/drivers/iio/dac/ad8801.c new file mode 100644 index 000000000000..f06faa1aec09 --- /dev/null +++ b/drivers/iio/dac/ad8801.c @@ -0,0 +1,239 @@ +/* + * IIO DAC driver for Analog Devices AD8801 DAC + * + * Copyright (C) 2016 Gwenhael Goavec-Merou + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include + +#define AD8801_CFG_ADDR_OFFSET 8 + +enum ad8801_device_ids { + ID_AD8801, + ID_AD8803, +}; + +struct ad8801_state { + struct spi_device *spi; + unsigned char dac_cache[8]; /* Value write on each channel */ + unsigned int vrefh_mv; + unsigned int vrefl_mv; + struct regulator *vrefh_reg; + struct regulator *vrefl_reg; + + __be16 data ____cacheline_aligned; +}; + +static int ad8801_spi_write(struct ad8801_state *state, + u8 channel, unsigned char value) +{ + state->data = cpu_to_be16((channel << AD8801_CFG_ADDR_OFFSET) | value); + return spi_write(state->spi, &state->data, sizeof(state->data)); +} + +static int ad8801_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct ad8801_state *state = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + if (val >= 256 || val < 0) + return -EINVAL; + + ret = ad8801_spi_write(state, chan->channel, val); + if (ret == 0) + state->dac_cache[chan->channel] = val; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int ad8801_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long info) +{ + struct ad8801_state *state = iio_priv(indio_dev); + + switch (info) { + case IIO_CHAN_INFO_RAW: + *val = state->dac_cache[chan->channel]; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = state->vrefh_mv - state->vrefl_mv; + *val2 = 8; + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + *val = state->vrefl_mv; + return IIO_VAL_INT; + default: + return -EINVAL; + } + + return -EINVAL; +} + +static const struct iio_info ad8801_info = { + .read_raw = ad8801_read_raw, + .write_raw = ad8801_write_raw, + .driver_module = THIS_MODULE, +}; + +#define AD8801_CHANNEL(chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .output = 1, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ +} + +static const struct iio_chan_spec ad8801_channels[] = { + AD8801_CHANNEL(0), + AD8801_CHANNEL(1), + AD8801_CHANNEL(2), + AD8801_CHANNEL(3), + AD8801_CHANNEL(4), + AD8801_CHANNEL(5), + AD8801_CHANNEL(6), + AD8801_CHANNEL(7), +}; + +static int ad8801_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct ad8801_state *state; + const struct spi_device_id *id; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state)); + if (indio_dev == NULL) + return -ENOMEM; + + state = iio_priv(indio_dev); + state->spi = spi; + id = spi_get_device_id(spi); + + state->vrefh_reg = devm_regulator_get(&spi->dev, "vrefh"); + if (IS_ERR(state->vrefh_reg)) { + dev_err(&spi->dev, "Vrefh regulator not specified\n"); + return PTR_ERR(state->vrefh_reg); + } + + ret = regulator_enable(state->vrefh_reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable vrefh regulator: %d\n", + ret); + return ret; + } + + ret = regulator_get_voltage(state->vrefh_reg); + if (ret < 0) { + dev_err(&spi->dev, "Failed to read vrefh regulator: %d\n", + ret); + goto error_disable_vrefh_reg; + } + state->vrefh_mv = ret / 1000; + + if (id->driver_data == ID_AD8803) { + state->vrefl_reg = devm_regulator_get(&spi->dev, "vrefl"); + if (IS_ERR(state->vrefl_reg)) { + dev_err(&spi->dev, "Vrefl regulator not specified\n"); + ret = PTR_ERR(state->vrefl_reg); + goto error_disable_vrefh_reg; + } + + ret = regulator_enable(state->vrefl_reg); + if (ret) { + dev_err(&spi->dev, "Failed to enable vrefl regulator: %d\n", + ret); + goto error_disable_vrefh_reg; + } + + ret = regulator_get_voltage(state->vrefl_reg); + if (ret < 0) { + dev_err(&spi->dev, "Failed to read vrefl regulator: %d\n", + ret); + goto error_disable_vrefl_reg; + } + state->vrefl_mv = ret / 1000; + } else { + state->vrefl_mv = 0; + state->vrefl_reg = NULL; + } + + spi_set_drvdata(spi, indio_dev); + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &ad8801_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = ad8801_channels; + indio_dev->num_channels = ARRAY_SIZE(ad8801_channels); + indio_dev->name = id->name; + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device: %d\n", + ret); + goto error_disable_vrefl_reg; + } + + return 0; + +error_disable_vrefl_reg: + if (state->vrefl_reg) + regulator_disable(state->vrefl_reg); +error_disable_vrefh_reg: + regulator_disable(state->vrefh_reg); + return ret; +} + +static int ad8801_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad8801_state *state = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + if (state->vrefl_reg) + regulator_disable(state->vrefl_reg); + regulator_disable(state->vrefh_reg); + + return 0; +} + +static const struct spi_device_id ad8801_ids[] = { + {"ad8801", ID_AD8801}, + {"ad8803", ID_AD8803}, + {} +}; +MODULE_DEVICE_TABLE(spi, ad8801_ids); + +static struct spi_driver ad8801_driver = { + .driver = { + .name = "ad8801", + }, + .probe = ad8801_probe, + .remove = ad8801_remove, + .id_table = ad8801_ids, +}; +module_spi_driver(ad8801_driver); + +MODULE_AUTHOR("Gwenhael Goavec-Merou "); +MODULE_DESCRIPTION("Analog Devices AD8801/AD8803 DAC"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From aeb55fff3891834e07a3144159a7298a19696af8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 26 Aug 2016 00:10:08 +0200 Subject: iio: st_sensors: fetch and enable regulators unconditionally These sensors all have Vdd and Vdd_IO lines. This means the supplies are *not* optional (optional means that the supply is optional in the electrical sense, not the software sense) so we need to get the and enable them at all times. If the device tree or board file does not define suitable regulators for the component, it will be substituted by a dummy regulator, or, if regulators are disabled altogether, by stubs. There is no need to use the IS_ERR_OR_NULL() check that is considered harmful. Cc: Giuseppe Barba Cc: Denis Ciocca Cc: Crestez Dan Leonard Cc: Gregor Boirie Cc: Mark Brown Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 55 +++++++++++-------------- 1 file changed, 24 insertions(+), 31 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 2d5282e05482..41bfe1c5f4e9 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -234,39 +234,35 @@ int st_sensors_power_enable(struct iio_dev *indio_dev) int err; /* Regulators not mandatory, but if requested we should enable them. */ - pdata->vdd = devm_regulator_get_optional(indio_dev->dev.parent, "vdd"); - if (!IS_ERR(pdata->vdd)) { - err = regulator_enable(pdata->vdd); - if (err != 0) { - dev_warn(&indio_dev->dev, - "Failed to enable specified Vdd supply\n"); - return err; - } - } else { - err = PTR_ERR(pdata->vdd); - if (err != -ENODEV) - return err; + pdata->vdd = devm_regulator_get(indio_dev->dev.parent, "vdd"); + if (IS_ERR(pdata->vdd)) { + dev_err(&indio_dev->dev, "unable to get Vdd supply\n"); + return PTR_ERR(pdata->vdd); + } + err = regulator_enable(pdata->vdd); + if (err != 0) { + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd supply\n"); + return err; } - pdata->vdd_io = devm_regulator_get_optional(indio_dev->dev.parent, "vddio"); - if (!IS_ERR(pdata->vdd_io)) { - err = regulator_enable(pdata->vdd_io); - if (err != 0) { - dev_warn(&indio_dev->dev, - "Failed to enable specified Vdd_IO supply\n"); - goto st_sensors_disable_vdd; - } - } else { - err = PTR_ERR(pdata->vdd_io); - if (err != -ENODEV) - goto st_sensors_disable_vdd; + pdata->vdd_io = devm_regulator_get(indio_dev->dev.parent, "vddio"); + if (IS_ERR(pdata->vdd)) { + dev_err(&indio_dev->dev, "unable to get Vdd_IO supply\n"); + err = PTR_ERR(pdata->vdd); + goto st_sensors_disable_vdd; + } + err = regulator_enable(pdata->vdd_io); + if (err != 0) { + dev_warn(&indio_dev->dev, + "Failed to enable specified Vdd_IO supply\n"); + goto st_sensors_disable_vdd; } return 0; st_sensors_disable_vdd: - if (!IS_ERR_OR_NULL(pdata->vdd)) - regulator_disable(pdata->vdd); + regulator_disable(pdata->vdd); return err; } EXPORT_SYMBOL(st_sensors_power_enable); @@ -275,11 +271,8 @@ void st_sensors_power_disable(struct iio_dev *indio_dev) { struct st_sensor_data *pdata = iio_priv(indio_dev); - if (!IS_ERR_OR_NULL(pdata->vdd)) - regulator_disable(pdata->vdd); - - if (!IS_ERR_OR_NULL(pdata->vdd_io)) - regulator_disable(pdata->vdd_io); + regulator_disable(pdata->vdd); + regulator_disable(pdata->vdd_io); } EXPORT_SYMBOL(st_sensors_power_disable); -- cgit v1.2.3 From 16335bcbf920d9903778d942ec5e579b25984b4b Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 26 Aug 2016 14:33:20 +0000 Subject: iio: temperature: fix non static symbol warnings Fixes the following sparse warnings: drivers/iio/temperature/maxim_thermocouple.c:35:28: warning: symbol 'max6675_channels' was not declared. Should it be static? drivers/iio/temperature/maxim_thermocouple.c:52:28: warning: symbol 'max31855_channels' was not declared. Should it be static? drivers/iio/temperature/maxim_thermocouple.c:98:38: warning: symbol 'maxim_thermocouple_chips' was not declared. Should it be static? Signed-off-by: Wei Yongjun Reviewed-By: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/maxim_thermocouple.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 030827ec8f3a..39dd2026ccc9 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -32,7 +32,7 @@ enum { MAX31855, }; -const struct iio_chan_spec max6675_channels[] = { +static const struct iio_chan_spec max6675_channels[] = { { /* thermocouple temperature */ .type = IIO_TEMP, .info_mask_separate = @@ -49,7 +49,7 @@ const struct iio_chan_spec max6675_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(1), }; -const struct iio_chan_spec max31855_channels[] = { +static const struct iio_chan_spec max31855_channels[] = { { /* thermocouple temperature */ .type = IIO_TEMP, .address = 2, @@ -95,7 +95,7 @@ struct maxim_thermocouple_chip { u32 status_bit; }; -const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = { +static const struct maxim_thermocouple_chip maxim_thermocouple_chips[] = { [MAX6675] = { .channels = max6675_channels, .num_channels = ARRAY_SIZE(max6675_channels), -- cgit v1.2.3 From 943bbe743ce4c2846c41812186411841b0c9d7a1 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 26 Aug 2016 14:31:50 +0000 Subject: iio: adc: ti-ads1015: add missing of_node_put() in ads1015_get_channels_config_of() When terminating for_each_child_of_node() iteration with break or return, of_node_put() should be used to prevent stale device node references from being left behind. This is detected by Coccinelle semantic patch. Signed-off-by: Wei Yongjun Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ti-ads1015.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c index 1ef398770a1f..565e843e20b0 100644 --- a/drivers/iio/adc/ti-ads1015.c +++ b/drivers/iio/adc/ti-ads1015.c @@ -521,6 +521,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client) if (pga > 6) { dev_err(&client->dev, "invalid gain on %s\n", node->full_name); + of_node_put(node); return -EINVAL; } } @@ -531,6 +532,7 @@ static int ads1015_get_channels_config_of(struct i2c_client *client) dev_err(&client->dev, "invalid data_rate on %s\n", node->full_name); + of_node_put(node); return -EINVAL; } } -- cgit v1.2.3 From 2e1f44d8a7724e889f1a4f211aad13320cb80f1f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 26 Aug 2016 17:29:35 +0200 Subject: iio: hid-sensors: avoid unused function warning A small rework of the PM code in this driver introduced a harmless warning when CONFIG_PM_SLEEP is not set: drivers/iio/common/hid-sensors/hid-sensor-trigger.c:212:12: error: 'hid_sensor_resume' defined but not used [-Werror=unused-function] This removes the #ifdef and instead marks all three PM functions as __maybe_unused, which covers all possible cases and is harder to get wrong. Signed-off-by: Arnd Bergmann Fixes: 7f6cf7414538 ("iio: hid-sensors: use asynchronous resume") Signed-off-by: Jonathan Cameron --- drivers/iio/common/hid-sensors/hid-sensor-trigger.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 5264ed6e03e5..a3cce3a38300 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -199,8 +199,7 @@ error_ret: } EXPORT_SYMBOL(hid_sensor_setup_trigger); -#ifdef CONFIG_PM -static int hid_sensor_suspend(struct device *dev) +static int __maybe_unused hid_sensor_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -209,7 +208,7 @@ static int hid_sensor_suspend(struct device *dev) return _hid_sensor_power_state(attrb, false); } -static int hid_sensor_resume(struct device *dev) +static int __maybe_unused hid_sensor_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -218,7 +217,7 @@ static int hid_sensor_resume(struct device *dev) return 0; } -static int hid_sensor_runtime_resume(struct device *dev) +static int __maybe_unused hid_sensor_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct iio_dev *indio_dev = platform_get_drvdata(pdev); @@ -226,8 +225,6 @@ static int hid_sensor_runtime_resume(struct device *dev) return _hid_sensor_power_state(attrb, true); } -#endif - const struct dev_pm_ops hid_sensor_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume) SET_RUNTIME_PM_OPS(hid_sensor_suspend, -- cgit v1.2.3 From 5bc55ef31f710326f541e6a3c726526815dd48e6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 26 Aug 2016 17:31:19 +0200 Subject: iio: magn/ak8974: avoid unused function warning The ak8974_configure() function is used only from the PM code, but that can be hidden when CONFIG_PM is disabled: drivers/iio/magnetometer/ak8974.c:201:12: error: 'ak8974_configure' defined but not used [-Werror=unused-function] This replaces the #ifdef with a __maybe_unused annotation, which will work correctly in all configurations and avoid the warning, as the compiler can now see where ak8974_configure is called from. Signed-off-by: Arnd Bergmann Fixes: 7c94a8b2ee8c ("iio: magn: add a driver for AK8974") Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8974.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index e70e4e22b72c..12bd17b4cf58 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -783,8 +783,7 @@ static int __exit ak8974_remove(struct i2c_client *i2c) return 0; } -#ifdef CONFIG_PM -static int ak8974_runtime_suspend(struct device *dev) +static int __maybe_unused ak8974_runtime_suspend(struct device *dev) { struct ak8974 *ak8974 = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); @@ -795,7 +794,7 @@ static int ak8974_runtime_suspend(struct device *dev) return 0; } -static int ak8974_runtime_resume(struct device *dev) +static int __maybe_unused ak8974_runtime_resume(struct device *dev) { struct ak8974 *ak8974 = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); @@ -822,7 +821,6 @@ out_regulator_disable: return ret; } -#endif /* CONFIG_PM */ static const struct dev_pm_ops ak8974_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, -- cgit v1.2.3 From 96303e20270af6e7ac9d7d98b9c68e3288d4b6ba Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 26 Aug 2016 14:32:29 +0000 Subject: iio: magn: ak8974: remove .owner field for driver Remove .owner field if calls are used which set it automatically. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Wei Yongjun Acked-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/ak8974.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index 12bd17b4cf58..217353145676 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -845,7 +845,6 @@ MODULE_DEVICE_TABLE(of, ak8974_of_match); static struct i2c_driver ak8974_driver = { .driver = { .name = "ak8974", - .owner = THIS_MODULE, .pm = &ak8974_dev_pm_ops, .of_match_table = of_match_ptr(ak8974_of_match), }, -- cgit v1.2.3 From a565a03faff90b634bf523f104389b540cfcb226 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Sat, 27 Aug 2016 14:26:30 +0800 Subject: fix:iio:common:st_sensors:st_sensors_trigger:mark symbols static where possible We get 2 warnings when biuld kernel with W=1: drivers/iio/common/st_sensors/st_sensors_trigger.c:69:13: warning: no previous prototype for 'st_sensors_irq_handler' [-Wmissing-prototypes] drivers/iio/common/st_sensors/st_sensors_trigger.c:85:13: warning: no previous prototype for 'st_sensors_irq_thread' [-Wmissing-prototypes] In fact, these functions are only used in the file in which they are declared and don't need a declaration, but can be made static. so this patch marks these functions with 'static'. Signed-off-by: Baoyou Xie Reviewed-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_trigger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index e66f12ee8a55..fa73e6795359 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -66,7 +66,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, * @irq: irq number * @p: private handler data */ -irqreturn_t st_sensors_irq_handler(int irq, void *p) +static irqreturn_t st_sensors_irq_handler(int irq, void *p) { struct iio_trigger *trig = p; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); @@ -82,7 +82,7 @@ irqreturn_t st_sensors_irq_handler(int irq, void *p) * @irq: irq number * @p: private handler data */ -irqreturn_t st_sensors_irq_thread(int irq, void *p) +static irqreturn_t st_sensors_irq_thread(int irq, void *p) { struct iio_trigger *trig = p; struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); -- cgit v1.2.3 From 50a6edb1b6e08643442386e8f81acc8123d17931 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 28 Aug 2016 23:52:49 +0900 Subject: iio: adc: add ADC12130/ADC12132/ADC12138 ADC driver This adds Texas Instruments' ADC12130/ADC12132/ADC12138 12-bit plus sign ADC driver. I have tested with the ADC12138. The ADC12130 and ADC12132 are not tested but these are similar to ADC12138 except that the mode programming instruction is a bit different. Signed-off-by: Akinobu Mita Acked-by: Rob Herring Cc: Jonathan Cameron Cc: Hartmut Knaack Cc: Lars-Peter Clausen Cc: Peter Meerwald Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/adc/ti-adc12138.txt | 37 ++ drivers/iio/adc/Kconfig | 12 + drivers/iio/adc/Makefile | 1 + drivers/iio/adc/ti-adc12138.c | 552 +++++++++++++++++++++ 4 files changed, 602 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt create mode 100644 drivers/iio/adc/ti-adc12138.c (limited to 'drivers/iio') diff --git a/Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt b/Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt new file mode 100644 index 000000000000..049a1d36f013 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti-adc12138.txt @@ -0,0 +1,37 @@ +* Texas Instruments' ADC12130/ADC12132/ADC12138 + +Required properties: + - compatible: Should be one of + * "ti,adc12130" + * "ti,adc12132" + * "ti,adc12138" + - reg: SPI chip select number for the device + - interrupts: Should contain interrupt for EOC (end of conversion) + - clocks: phandle to conversion clock input + - spi-max-frequency: Definision as per + Documentation/devicetree/bindings/spi/spi-bus.txt + - vref-p-supply: The regulator supply for positive analog voltage reference + +Optional properties: + - vref-n-supply: The regulator supply for negative analog voltage reference + (Note that this must not go below GND or exceed vref-p) + If not specified, this is assumed to be analog ground. + - ti,acquisition-time: The number of conversion clock periods for the S/H's + acquisition time. Should be one of 6, 10, 18, 34. If not specified, + default value of 10 is used. + For high source impedances, this value can be increased to 18 or 34. + For less ADC accuracy and/or slower CCLK frequencies this value may be + decreased to 6. See section 6.0 INPUT SOURCE RESISTANCE in the + datasheet for details. + +Example: +adc@0 { + compatible = "ti,adc12138"; + reg = <0>; + interrupts = <28 IRQ_TYPE_EDGE_RISING>; + interrupt-parent = <&gpio1>; + clocks = <&cclk>; + vref-p-supply = <&ldo4_reg>; + spi-max-frequency = <5000000>; + ti,acquisition-time = <6>; +}; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 6eac9236dff1..9f8e3813930e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -438,6 +438,18 @@ config TI_ADC0832 This driver can also be built as a module. If so, the module will be called ti-adc0832. +config TI_ADC12138 + tristate "Texas Instruments ADC12130/ADC12132/ADC12138" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + If you say yes here you get support for Texas Instruments ADC12130, + ADC12132 and ADC12138 chips. + + This driver can also be built as a module. If so, the module will be + called ti-adc12138. + config TI_ADC128S052 tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021" depends on SPI diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index f46dd1fdebae..d1a20b658c9a 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o +obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o diff --git a/drivers/iio/adc/ti-adc12138.c b/drivers/iio/adc/ti-adc12138.c new file mode 100644 index 000000000000..072f03bfe6a0 --- /dev/null +++ b/drivers/iio/adc/ti-adc12138.c @@ -0,0 +1,552 @@ +/* + * ADC12130/ADC12132/ADC12138 12-bit plus sign ADC driver + * + * Copyright (c) 2016 Akinobu Mita + * + * 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. + * + * Datasheet: http://www.ti.com/lit/ds/symlink/adc12138.pdf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ADC12138_MODE_AUTO_CAL 0x08 +#define ADC12138_MODE_READ_STATUS 0x0c +#define ADC12138_MODE_ACQUISITION_TIME_6 0x0e +#define ADC12138_MODE_ACQUISITION_TIME_10 0x4e +#define ADC12138_MODE_ACQUISITION_TIME_18 0x8e +#define ADC12138_MODE_ACQUISITION_TIME_34 0xce + +#define ADC12138_STATUS_CAL BIT(6) + +enum { + adc12130, + adc12132, + adc12138, +}; + +struct adc12138 { + struct spi_device *spi; + unsigned int id; + /* conversion clock */ + struct clk *cclk; + /* positive analog voltage reference */ + struct regulator *vref_p; + /* negative analog voltage reference */ + struct regulator *vref_n; + struct mutex lock; + struct completion complete; + /* The number of cclk periods for the S/H's acquisition time */ + unsigned int acquisition_time; + + u8 tx_buf[2] ____cacheline_aligned; + u8 rx_buf[2]; +}; + +#define ADC12138_VOLTAGE_CHANNEL(chan) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = chan, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 13, \ + .storagebits = 16, \ + .shift = 3, \ + .endianness = IIO_BE, \ + }, \ + } + +#define ADC12138_VOLTAGE_CHANNEL_DIFF(chan1, chan2, si) \ + { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = (chan1), \ + .channel2 = (chan2), \ + .differential = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) \ + | BIT(IIO_CHAN_INFO_OFFSET), \ + .scan_index = si, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 13, \ + .storagebits = 16, \ + .shift = 3, \ + .endianness = IIO_BE, \ + }, \ + } + +static const struct iio_chan_spec adc12132_channels[] = { + ADC12138_VOLTAGE_CHANNEL(0), + ADC12138_VOLTAGE_CHANNEL(1), + ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 2), + ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 3), + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +static const struct iio_chan_spec adc12138_channels[] = { + ADC12138_VOLTAGE_CHANNEL(0), + ADC12138_VOLTAGE_CHANNEL(1), + ADC12138_VOLTAGE_CHANNEL(2), + ADC12138_VOLTAGE_CHANNEL(3), + ADC12138_VOLTAGE_CHANNEL(4), + ADC12138_VOLTAGE_CHANNEL(5), + ADC12138_VOLTAGE_CHANNEL(6), + ADC12138_VOLTAGE_CHANNEL(7), + ADC12138_VOLTAGE_CHANNEL_DIFF(0, 1, 8), + ADC12138_VOLTAGE_CHANNEL_DIFF(1, 0, 9), + ADC12138_VOLTAGE_CHANNEL_DIFF(2, 3, 10), + ADC12138_VOLTAGE_CHANNEL_DIFF(3, 2, 11), + ADC12138_VOLTAGE_CHANNEL_DIFF(4, 5, 12), + ADC12138_VOLTAGE_CHANNEL_DIFF(5, 4, 13), + ADC12138_VOLTAGE_CHANNEL_DIFF(6, 7, 14), + ADC12138_VOLTAGE_CHANNEL_DIFF(7, 6, 15), + IIO_CHAN_SOFT_TIMESTAMP(16), +}; + +static int adc12138_mode_programming(struct adc12138 *adc, u8 mode, + void *rx_buf, int len) +{ + struct spi_transfer xfer = { + .tx_buf = adc->tx_buf, + .rx_buf = adc->rx_buf, + .len = len, + }; + int ret; + + /* Skip unused bits for ADC12130 and ADC12132 */ + if (adc->id != adc12138) + mode = (mode & 0xc0) | ((mode & 0x0f) << 2); + + adc->tx_buf[0] = mode; + + ret = spi_sync_transfer(adc->spi, &xfer, 1); + if (ret) + return ret; + + memcpy(rx_buf, adc->rx_buf, len); + + return 0; +} + +static int adc12138_read_status(struct adc12138 *adc) +{ + u8 rx_buf[2]; + int ret; + + ret = adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS, + rx_buf, 2); + if (ret) + return ret; + + return (rx_buf[0] << 1) | (rx_buf[1] >> 7); +} + +static int __adc12138_start_conv(struct adc12138 *adc, + struct iio_chan_spec const *channel, + void *data, int len) + +{ + const u8 ch_to_mux[] = { 0, 4, 1, 5, 2, 6, 3, 7 }; + u8 mode = (ch_to_mux[channel->channel] << 4) | + (channel->differential ? 0 : 0x80); + + return adc12138_mode_programming(adc, mode, data, len); +} + +static int adc12138_start_conv(struct adc12138 *adc, + struct iio_chan_spec const *channel) +{ + u8 trash; + + return __adc12138_start_conv(adc, channel, &trash, 1); +} + +static int adc12138_start_and_read_conv(struct adc12138 *adc, + struct iio_chan_spec const *channel, + __be16 *data) +{ + return __adc12138_start_conv(adc, channel, data, 2); +} + +static int adc12138_read_conv_data(struct adc12138 *adc, __be16 *value) +{ + /* Issue a read status instruction and read previous conversion data */ + return adc12138_mode_programming(adc, ADC12138_MODE_READ_STATUS, + value, sizeof(*value)); +} + +static int adc12138_wait_eoc(struct adc12138 *adc, unsigned long timeout) +{ + if (!wait_for_completion_timeout(&adc->complete, timeout)) + return -ETIMEDOUT; + + return 0; +} + +static int adc12138_adc_conversion(struct adc12138 *adc, + struct iio_chan_spec const *channel, + __be16 *value) +{ + int ret; + + reinit_completion(&adc->complete); + + ret = adc12138_start_conv(adc, channel); + if (ret) + return ret; + + ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100)); + if (ret) + return ret; + + return adc12138_read_conv_data(adc, value); +} + +static int adc12138_read_raw(struct iio_dev *iio, + struct iio_chan_spec const *channel, int *value, + int *shift, long mask) +{ + struct adc12138 *adc = iio_priv(iio); + int ret; + __be16 data; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&adc->lock); + ret = adc12138_adc_conversion(adc, channel, &data); + mutex_unlock(&adc->lock); + if (ret) + return ret; + + *value = sign_extend32(be16_to_cpu(data) >> 3, 12); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + ret = regulator_get_voltage(adc->vref_p); + if (ret < 0) + return ret; + *value = ret; + + if (!IS_ERR(adc->vref_n)) { + ret = regulator_get_voltage(adc->vref_n); + if (ret < 0) + return ret; + *value -= ret; + } + + /* convert regulator output voltage to mV */ + *value /= 1000; + *shift = channel->scan_type.realbits - 1; + + return IIO_VAL_FRACTIONAL_LOG2; + case IIO_CHAN_INFO_OFFSET: + if (!IS_ERR(adc->vref_n)) { + *value = regulator_get_voltage(adc->vref_n); + if (*value < 0) + return *value; + } else { + *value = 0; + } + + /* convert regulator output voltage to mV */ + *value /= 1000; + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static const struct iio_info adc12138_info = { + .read_raw = adc12138_read_raw, + .driver_module = THIS_MODULE, +}; + +static int adc12138_init(struct adc12138 *adc) +{ + int ret; + int status; + u8 mode; + u8 trash; + + reinit_completion(&adc->complete); + + ret = adc12138_mode_programming(adc, ADC12138_MODE_AUTO_CAL, &trash, 1); + if (ret) + return ret; + + /* data output at this time has no significance */ + status = adc12138_read_status(adc); + if (status < 0) + return status; + + adc12138_wait_eoc(adc, msecs_to_jiffies(100)); + + status = adc12138_read_status(adc); + if (status & ADC12138_STATUS_CAL) { + dev_warn(&adc->spi->dev, + "Auto Cal sequence is still in progress: %#x\n", + status); + return -EIO; + } + + switch (adc->acquisition_time) { + case 6: + mode = ADC12138_MODE_ACQUISITION_TIME_6; + break; + case 10: + mode = ADC12138_MODE_ACQUISITION_TIME_10; + break; + case 18: + mode = ADC12138_MODE_ACQUISITION_TIME_18; + break; + case 34: + mode = ADC12138_MODE_ACQUISITION_TIME_34; + break; + default: + return -EINVAL; + } + + return adc12138_mode_programming(adc, mode, &trash, 1); +} + +static irqreturn_t adc12138_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct adc12138 *adc = iio_priv(indio_dev); + __be16 data[20] = { }; /* 16x 2 bytes ADC data + 8 bytes timestamp */ + __be16 trash; + int ret; + int scan_index; + int i = 0; + + mutex_lock(&adc->lock); + + for_each_set_bit(scan_index, indio_dev->active_scan_mask, + indio_dev->masklength) { + const struct iio_chan_spec *scan_chan = + &indio_dev->channels[scan_index]; + + reinit_completion(&adc->complete); + + ret = adc12138_start_and_read_conv(adc, scan_chan, + i ? &data[i - 1] : &trash); + if (ret) { + dev_warn(&adc->spi->dev, + "failed to start conversion\n"); + goto out; + } + + ret = adc12138_wait_eoc(adc, msecs_to_jiffies(100)); + if (ret) { + dev_warn(&adc->spi->dev, "wait eoc timeout\n"); + goto out; + } + + i++; + } + + if (i) { + ret = adc12138_read_conv_data(adc, &data[i - 1]); + if (ret) { + dev_warn(&adc->spi->dev, + "failed to get conversion data\n"); + goto out; + } + } + + iio_push_to_buffers_with_timestamp(indio_dev, data, + iio_get_time_ns(indio_dev)); +out: + mutex_unlock(&adc->lock); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static irqreturn_t adc12138_eoc_handler(int irq, void *p) +{ + struct iio_dev *indio_dev = p; + struct adc12138 *adc = iio_priv(indio_dev); + + complete(&adc->complete); + + return IRQ_HANDLED; +} + +static int adc12138_probe(struct spi_device *spi) +{ + struct iio_dev *indio_dev; + struct adc12138 *adc; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + adc->id = spi_get_device_id(spi)->driver_data; + mutex_init(&adc->lock); + init_completion(&adc->complete); + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = &spi->dev; + indio_dev->info = &adc12138_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + switch (adc->id) { + case adc12130: + case adc12132: + indio_dev->channels = adc12132_channels; + indio_dev->num_channels = ARRAY_SIZE(adc12132_channels); + break; + case adc12138: + indio_dev->channels = adc12138_channels; + indio_dev->num_channels = ARRAY_SIZE(adc12138_channels); + break; + default: + return -EINVAL; + } + + ret = of_property_read_u32(spi->dev.of_node, "ti,acquisition-time", + &adc->acquisition_time); + if (ret) + adc->acquisition_time = 10; + + adc->cclk = devm_clk_get(&spi->dev, NULL); + if (IS_ERR(adc->cclk)) + return PTR_ERR(adc->cclk); + + adc->vref_p = devm_regulator_get(&spi->dev, "vref-p"); + if (IS_ERR(adc->vref_p)) + return PTR_ERR(adc->vref_p); + + adc->vref_n = devm_regulator_get_optional(&spi->dev, "vref-n"); + if (IS_ERR(adc->vref_n)) { + /* + * Assume vref_n is 0V if an optional regulator is not + * specified, otherwise return the error code. + */ + ret = PTR_ERR(adc->vref_n); + if (ret != -ENODEV) + return ret; + } + + ret = devm_request_irq(&spi->dev, spi->irq, adc12138_eoc_handler, + IRQF_TRIGGER_RISING, indio_dev->name, indio_dev); + if (ret) + return ret; + + ret = clk_prepare_enable(adc->cclk); + if (ret) + return ret; + + ret = regulator_enable(adc->vref_p); + if (ret) + goto err_clk_disable; + + if (!IS_ERR(adc->vref_n)) { + ret = regulator_enable(adc->vref_n); + if (ret) + goto err_vref_p_disable; + } + + ret = adc12138_init(adc); + if (ret) + goto err_vref_n_disable; + + spi_set_drvdata(spi, indio_dev); + + ret = iio_triggered_buffer_setup(indio_dev, NULL, + adc12138_trigger_handler, NULL); + if (ret) + goto err_vref_n_disable; + + ret = iio_device_register(indio_dev); + if (ret) + goto err_buffer_cleanup; + + return 0; +err_buffer_cleanup: + iio_triggered_buffer_cleanup(indio_dev); +err_vref_n_disable: + if (!IS_ERR(adc->vref_n)) + regulator_disable(adc->vref_n); +err_vref_p_disable: + regulator_disable(adc->vref_p); +err_clk_disable: + clk_disable_unprepare(adc->cclk); + + return ret; +} + +static int adc12138_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adc12138 *adc = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + if (!IS_ERR(adc->vref_n)) + regulator_disable(adc->vref_n); + regulator_disable(adc->vref_p); + clk_disable_unprepare(adc->cclk); + + return 0; +} + +#ifdef CONFIG_OF + +static const struct of_device_id adc12138_dt_ids[] = { + { .compatible = "ti,adc12130", }, + { .compatible = "ti,adc12132", }, + { .compatible = "ti,adc12138", }, + {} +}; +MODULE_DEVICE_TABLE(of, adc12138_dt_ids); + +#endif + +static const struct spi_device_id adc12138_id[] = { + { "adc12130", adc12130 }, + { "adc12132", adc12132 }, + { "adc12138", adc12138 }, + {} +}; +MODULE_DEVICE_TABLE(spi, adc12138_id); + +static struct spi_driver adc12138_driver = { + .driver = { + .name = "adc12138", + .of_match_table = of_match_ptr(adc12138_dt_ids), + }, + .probe = adc12138_probe, + .remove = adc12138_remove, + .id_table = adc12138_id, +}; +module_spi_driver(adc12138_driver); + +MODULE_AUTHOR("Akinobu Mita "); +MODULE_DESCRIPTION("ADC12130/ADC12132/ADC12138 driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From a5c8b11a361065db028721c62aa880bfe0736aa6 Mon Sep 17 00:00:00 2001 From: Christoph Fritz Date: Sat, 3 Sep 2016 12:30:00 +0200 Subject: iio: sx9500: add final devicetree support This makes sx9500 driver usable on devicetree based platforms too. Signed-off-by: Christoph Fritz Reviewed-by: Fabio Estevam Reviewed-by: Vlad Dogaru Signed-off-by: Jonathan Cameron --- .../devicetree/bindings/iio/proximity/sx9500.txt | 24 ++++++++++++++++++++++ drivers/iio/proximity/sx9500.c | 7 +++++++ 2 files changed, 31 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/proximity/sx9500.txt (limited to 'drivers/iio') diff --git a/Documentation/devicetree/bindings/iio/proximity/sx9500.txt b/Documentation/devicetree/bindings/iio/proximity/sx9500.txt new file mode 100644 index 000000000000..b301dd2b35da --- /dev/null +++ b/Documentation/devicetree/bindings/iio/proximity/sx9500.txt @@ -0,0 +1,24 @@ +Semtech's SX9500 capacitive proximity button device driver + +Required properties: + - compatible: must be "semtech,sx9500" + - reg: i2c address where to find the device + - interrupt-parent : should be the phandle for the interrupt controller + - interrupts : the sole interrupt generated by the device + + Refer to interrupt-controller/interrupts.txt for generic + interrupt client node bindings. + +Optional properties: + - reset-gpios: Reference to the GPIO connected to the device's active + low reset pin. + +Example: + +sx9500@28 { + compatible = "semtech,sx9500"; + reg = <0x28>; + interrupt-parent = <&gpio2>; + interrupts = <16 IRQ_TYPE_LEVEL_LOW>; + reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>; +}; diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 6f84f53dfe54..1f06282ec793 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -1025,6 +1025,12 @@ static const struct acpi_device_id sx9500_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match); +static const struct of_device_id sx9500_of_match[] = { + { .compatible = "semtech,sx9500", }, + { } +}; +MODULE_DEVICE_TABLE(of, sx9500_of_match); + static const struct i2c_device_id sx9500_id[] = { {"sx9500", 0}, { }, @@ -1035,6 +1041,7 @@ static struct i2c_driver sx9500_driver = { .driver = { .name = SX9500_DRIVER_NAME, .acpi_match_table = ACPI_PTR(sx9500_acpi_match), + .of_match_table = of_match_ptr(sx9500_of_match), .pm = &sx9500_pm_ops, }, .probe = sx9500_probe, -- cgit v1.2.3 From c8cdf70890d89c07c9e890b103106d58999f0ce4 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 2 Sep 2016 23:36:15 -0700 Subject: iio: trigger: allow immutable triggers to be assigned There are times when an assigned trigger to a device shouldn't ever change after intialization. Examples of this being used is when an provider device has a trigger that is assigned to an ADC, which uses it populate data into a callback buffer. Signed-off-by: Matt Ranostay Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 20 ++++++++++++++++++++ include/linux/iio/iio.h | 2 ++ include/linux/iio/trigger.h | 9 +++++++++ 3 files changed, 31 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 7ad82fdd3e5b..3dde81e57e97 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -119,6 +119,22 @@ void iio_trigger_unregister(struct iio_trigger *trig_info) } EXPORT_SYMBOL(iio_trigger_unregister); +int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig) +{ + if (!indio_dev || !trig) + return -EINVAL; + + mutex_lock(&indio_dev->mlock); + WARN_ON(indio_dev->trig_readonly); + + indio_dev->trig = iio_trigger_get(trig); + indio_dev->trig_readonly = true; + mutex_unlock(&indio_dev->mlock); + + return 0; +} +EXPORT_SYMBOL(iio_trigger_set_immutable); + /* Search for trigger by name, assuming iio_trigger_list_lock held */ static struct iio_trigger *__iio_trigger_find_by_name(const char *name) { @@ -384,6 +400,10 @@ static ssize_t iio_trigger_write_current(struct device *dev, mutex_unlock(&indio_dev->mlock); return -EBUSY; } + if (indio_dev->trig_readonly) { + mutex_unlock(&indio_dev->mlock); + return -EPERM; + } mutex_unlock(&indio_dev->mlock); trig = iio_trigger_find_by_name(buf, len); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 854e2dad1e0d..786952cd509f 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -483,6 +483,7 @@ struct iio_buffer_setup_ops { * @scan_timestamp: [INTERN] set if any buffers have requested timestamp * @scan_index_timestamp:[INTERN] cache of the index to the timestamp * @trig: [INTERN] current device trigger (buffer modes) + * @trig_readonly [INTERN] mark the current trigger immutable * @pollfunc: [DRIVER] function run on trigger being received * @pollfunc_event: [DRIVER] function run on events trigger being received * @channels: [DRIVER] channel specification structure table @@ -523,6 +524,7 @@ struct iio_dev { bool scan_timestamp; unsigned scan_index_timestamp; struct iio_trigger *trig; + bool trig_readonly; struct iio_poll_func *pollfunc; struct iio_poll_func *pollfunc_event; diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index 1c9e028e0d4a..a122bdd4076c 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -131,6 +131,15 @@ int iio_trigger_register(struct iio_trigger *trig_info); **/ void iio_trigger_unregister(struct iio_trigger *trig_info); +/** + * iio_trigger_set_immutable() - set an immutable trigger on destination + * + * @indio_dev - IIO device structure containing the device + * @trig - trigger to assign to device + * + **/ +int iio_trigger_set_immutable(struct iio_dev *indio_dev, struct iio_trigger *trig); + /** * iio_trigger_poll() - called on a trigger occurring * @trig: trigger which occurred -- cgit v1.2.3 From c060991912f8e71f6214204a2019ceceb315c17b Mon Sep 17 00:00:00 2001 From: Alison Schofield Date: Fri, 2 Sep 2016 19:54:21 -0700 Subject: iio: adc: ina2xx: remove unused debug field from chip global data commit 1961bce76452 "iio: ina2xx: Remove trace_printk debug statements" removed the code that used the chip->prev_ns field. This patch cleans it up further by removing the unused field and assignments. Signed-off-by: Alison Schofield Cc: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ina2xx-adc.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ina2xx-adc.c b/drivers/iio/adc/ina2xx-adc.c index 955f3fdaf519..59b7d76e1ad2 100644 --- a/drivers/iio/adc/ina2xx-adc.c +++ b/drivers/iio/adc/ina2xx-adc.c @@ -114,7 +114,6 @@ struct ina2xx_chip_info { struct mutex state_lock; unsigned int shunt_resistor; int avg; - s64 prev_ns; /* track buffer capture time, check for underruns */ int int_time_vbus; /* Bus voltage integration time uS */ int int_time_vshunt; /* Shunt voltage integration time uS */ bool allow_async_readout; @@ -509,8 +508,6 @@ static int ina2xx_work_buffer(struct iio_dev *indio_dev) iio_push_to_buffers_with_timestamp(indio_dev, (unsigned int *)data, time_a); - chip->prev_ns = time_a; - return (unsigned long)(time_b - time_a) / 1000; }; @@ -554,8 +551,6 @@ static int ina2xx_buffer_enable(struct iio_dev *indio_dev) dev_dbg(&indio_dev->dev, "Async readout mode: %d\n", chip->allow_async_readout); - chip->prev_ns = iio_get_time_ns(indio_dev); - chip->task = kthread_run(ina2xx_capture_thread, (void *)indio_dev, "%s:%d-%uus", indio_dev->name, indio_dev->id, sampling_us); -- cgit v1.2.3 From 4075a283ae83f49f923a2a92935aa72be2c1ca85 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 29 Aug 2016 16:22:56 -0400 Subject: iio: stx104: Add IIO support for the ADC channels The Apex Embedded Systems STX104 features 16 channels of single-ended (8 channels of true differential) 16-bit analog input. Differential input configuration may be selected via a physical jumper on the device. Similarly, input polarity (unipolar/bipolar) is configured via a physical jumper on the device. Input gain selection is available to the user via software, thus allowing eight possible input ranges: +-10V, +-5V, +-2.5V, +-1.25V, 0 to 10V, 0 to 5V, 0 to 2.5V, and 0 to 1.25V. Four input gain configurations are supported: x1, x2, x4, and x8. This ADC resolution is 16-bits (1/65536 of full scale). Analog input samples are taken on software trigger; neither FIFO sampling nor interrupt triggering is supported by this driver. The Apex Embedded Systems STX104 is primarily an analog-to-digital converter device. The STX104 IIO driver was initially placed in the DAC directory because only the DAC portion of the STX104 was supported at the time. Now that ADC support has been added to the STX104 IIO driver, the driver should be moved to the more appropriate ADC directory. Signed-off-by: William Breathitt Gray Signed-off-by: Jonathan Cameron --- MAINTAINERS | 4 +- drivers/iio/adc/Kconfig | 15 ++ drivers/iio/adc/Makefile | 1 + drivers/iio/adc/stx104.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/iio/dac/Kconfig | 10 -- drivers/iio/dac/Makefile | 1 - drivers/iio/dac/stx104.c | 255 --------------------------------- 7 files changed, 378 insertions(+), 268 deletions(-) create mode 100644 drivers/iio/adc/stx104.c delete mode 100644 drivers/iio/dac/stx104.c (limited to 'drivers/iio') diff --git a/MAINTAINERS b/MAINTAINERS index ae09eb4f4a76..6f0ff7269f15 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -809,11 +809,11 @@ L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: sound/aoa/ -APEX EMBEDDED SYSTEMS STX104 DAC DRIVER +APEX EMBEDDED SYSTEMS STX104 IIO DRIVER M: William Breathitt Gray L: linux-iio@vger.kernel.org S: Maintained -F: drivers/iio/dac/stx104.c +F: drivers/iio/adc/stx104.c APM DRIVER M: Jiri Kosina diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 9f8e3813930e..ee7ab81e4cef 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -418,6 +418,21 @@ config ROCKCHIP_SARADC To compile this driver as a module, choose M here: the module will be called rockchip_saradc. +config STX104 + tristate "Apex Embedded Systems STX104 driver" + depends on X86 && ISA_BUS_API + select GPIOLIB + help + Say yes here to build support for the Apex Embedded Systems STX104 + integrated analog PC/104 card. + + This driver supports the 16 channels of single-ended (8 channels of + differential) analog inputs, 2 channels of analog output, 4 digital + inputs, and 4 digital outputs provided by the STX104. + + The base port addresses for the devices may be configured via the base + array module parameter. + config TI_ADC081C tristate "Texas Instruments ADC081C/ADC101C/ADC121C family" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index d1a20b658c9a..7a40c04c311f 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o +obj-$(CONFIG_STX104) += stx104.o obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o diff --git a/drivers/iio/adc/stx104.c b/drivers/iio/adc/stx104.c new file mode 100644 index 000000000000..7ca12d58e750 --- /dev/null +++ b/drivers/iio/adc/stx104.c @@ -0,0 +1,360 @@ +/* + * IIO driver for the Apex Embedded Systems STX104 + * Copyright (C) 2016 William Breathitt Gray + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define STX104_OUT_CHAN(chan) { \ + .type = IIO_VOLTAGE, \ + .channel = chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .indexed = 1, \ + .output = 1 \ +} +#define STX104_IN_CHAN(chan, diff) { \ + .type = IIO_VOLTAGE, \ + .channel = chan, \ + .channel2 = chan, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ + BIT(IIO_CHAN_INFO_OFFSET) | BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .indexed = 1, \ + .differential = diff \ +} + +#define STX104_NUM_OUT_CHAN 2 + +#define STX104_EXTENT 16 + +static unsigned int base[max_num_isa_dev(STX104_EXTENT)]; +static unsigned int num_stx104; +module_param_array(base, uint, &num_stx104, 0); +MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); + +/** + * struct stx104_iio - IIO device private data structure + * @chan_out_states: channels' output states + * @base: base port address of the IIO device + */ +struct stx104_iio { + unsigned int chan_out_states[STX104_NUM_OUT_CHAN]; + unsigned int base; +}; + +/** + * struct stx104_gpio - GPIO device private data structure + * @chip: instance of the gpio_chip + * @lock: synchronization lock to prevent I/O race conditions + * @base: base port address of the GPIO device + * @out_state: output bits state + */ +struct stx104_gpio { + struct gpio_chip chip; + spinlock_t lock; + unsigned int base; + unsigned int out_state; +}; + +static int stx104_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, int *val2, long mask) +{ + struct stx104_iio *const priv = iio_priv(indio_dev); + unsigned int adc_config; + int adbu; + int gain; + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + /* get gain configuration */ + adc_config = inb(priv->base + 11); + gain = adc_config & 0x3; + + *val = 1 << gain; + return IIO_VAL_INT; + case IIO_CHAN_INFO_RAW: + if (chan->output) { + *val = priv->chan_out_states[chan->channel]; + return IIO_VAL_INT; + } + + /* select ADC channel */ + outb(chan->channel | (chan->channel << 4), priv->base + 2); + + /* trigger ADC sample capture and wait for completion */ + outb(0, priv->base); + while (inb(priv->base + 8) & BIT(7)); + + *val = inw(priv->base); + return IIO_VAL_INT; + case IIO_CHAN_INFO_OFFSET: + /* get ADC bipolar/unipolar configuration */ + adc_config = inb(priv->base + 11); + adbu = !(adc_config & BIT(2)); + + *val = -32768 * adbu; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* get ADC bipolar/unipolar and gain configuration */ + adc_config = inb(priv->base + 11); + adbu = !(adc_config & BIT(2)); + gain = adc_config & 0x3; + + *val = 5; + *val2 = 15 - adbu + gain; + return IIO_VAL_FRACTIONAL_LOG2; + } + + return -EINVAL; +} + +static int stx104_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct stx104_iio *const priv = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + /* Only four gain states (x1, x2, x4, x8) */ + switch (val) { + case 1: + outb(0, priv->base + 11); + break; + case 2: + outb(1, priv->base + 11); + break; + case 4: + outb(2, priv->base + 11); + break; + case 8: + outb(3, priv->base + 11); + break; + default: + return -EINVAL; + } + + return 0; + case IIO_CHAN_INFO_RAW: + if (chan->output) { + /* DAC can only accept up to a 16-bit value */ + if ((unsigned int)val > 65535) + return -EINVAL; + + priv->chan_out_states[chan->channel] = val; + outw(val, priv->base + 4 + 2 * chan->channel); + + return 0; + } + return -EINVAL; + } + + return -EINVAL; +} + +static const struct iio_info stx104_info = { + .driver_module = THIS_MODULE, + .read_raw = stx104_read_raw, + .write_raw = stx104_write_raw +}; + +/* single-ended input channels configuration */ +static const struct iio_chan_spec stx104_channels_sing[] = { + STX104_OUT_CHAN(0), STX104_OUT_CHAN(1), + STX104_IN_CHAN(0, 0), STX104_IN_CHAN(1, 0), STX104_IN_CHAN(2, 0), + STX104_IN_CHAN(3, 0), STX104_IN_CHAN(4, 0), STX104_IN_CHAN(5, 0), + STX104_IN_CHAN(6, 0), STX104_IN_CHAN(7, 0), STX104_IN_CHAN(8, 0), + STX104_IN_CHAN(9, 0), STX104_IN_CHAN(10, 0), STX104_IN_CHAN(11, 0), + STX104_IN_CHAN(12, 0), STX104_IN_CHAN(13, 0), STX104_IN_CHAN(14, 0), + STX104_IN_CHAN(15, 0) +}; +/* differential input channels configuration */ +static const struct iio_chan_spec stx104_channels_diff[] = { + STX104_OUT_CHAN(0), STX104_OUT_CHAN(1), + STX104_IN_CHAN(0, 1), STX104_IN_CHAN(1, 1), STX104_IN_CHAN(2, 1), + STX104_IN_CHAN(3, 1), STX104_IN_CHAN(4, 1), STX104_IN_CHAN(5, 1), + STX104_IN_CHAN(6, 1), STX104_IN_CHAN(7, 1) +}; + +static int stx104_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset < 4) + return 1; + + return 0; +} + +static int stx104_gpio_direction_input(struct gpio_chip *chip, + unsigned int offset) +{ + if (offset >= 4) + return -EINVAL; + + return 0; +} + +static int stx104_gpio_direction_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + if (offset < 4) + return -EINVAL; + + chip->set(chip, offset, value); + return 0; +} + +static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + + if (offset >= 4) + return -EINVAL; + + return !!(inb(stx104gpio->base) & BIT(offset)); +} + +static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) +{ + struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); + const unsigned int mask = BIT(offset) >> 4; + unsigned long flags; + + if (offset < 4) + return; + + spin_lock_irqsave(&stx104gpio->lock, flags); + + if (value) + stx104gpio->out_state |= mask; + else + stx104gpio->out_state &= ~mask; + + outb(stx104gpio->out_state, stx104gpio->base); + + spin_unlock_irqrestore(&stx104gpio->lock, flags); +} + +static int stx104_probe(struct device *dev, unsigned int id) +{ + struct iio_dev *indio_dev; + struct stx104_iio *priv; + struct stx104_gpio *stx104gpio; + int err; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); + if (!indio_dev) + return -ENOMEM; + + stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL); + if (!stx104gpio) + return -ENOMEM; + + if (!devm_request_region(dev, base[id], STX104_EXTENT, + dev_name(dev))) { + dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", + base[id], base[id] + STX104_EXTENT); + return -EBUSY; + } + + indio_dev->info = &stx104_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + /* determine if differential inputs */ + if (inb(base[id] + 8) & BIT(5)) { + indio_dev->num_channels = ARRAY_SIZE(stx104_channels_diff); + indio_dev->channels = stx104_channels_diff; + } else { + indio_dev->num_channels = ARRAY_SIZE(stx104_channels_sing); + indio_dev->channels = stx104_channels_sing; + } + + indio_dev->name = dev_name(dev); + + priv = iio_priv(indio_dev); + priv->base = base[id]; + + /* configure device for software trigger operation */ + outb(0, base[id] + 9); + + /* initialize gain setting to x1 */ + outb(0, base[id] + 11); + + /* initialize DAC output to 0V */ + outw(0, base[id] + 4); + outw(0, base[id] + 6); + + err = devm_iio_device_register(dev, indio_dev); + if (err) { + dev_err(dev, "IIO device registering failed (%d)\n", err); + return err; + } + + stx104gpio->chip.label = dev_name(dev); + stx104gpio->chip.parent = dev; + stx104gpio->chip.owner = THIS_MODULE; + stx104gpio->chip.base = -1; + stx104gpio->chip.ngpio = 8; + stx104gpio->chip.get_direction = stx104_gpio_get_direction; + stx104gpio->chip.direction_input = stx104_gpio_direction_input; + stx104gpio->chip.direction_output = stx104_gpio_direction_output; + stx104gpio->chip.get = stx104_gpio_get; + stx104gpio->chip.set = stx104_gpio_set; + stx104gpio->base = base[id] + 3; + stx104gpio->out_state = 0x0; + + spin_lock_init(&stx104gpio->lock); + + dev_set_drvdata(dev, stx104gpio); + + err = gpiochip_add_data(&stx104gpio->chip, stx104gpio); + if (err) { + dev_err(dev, "GPIO registering failed (%d)\n", err); + return err; + } + + return 0; +} + +static int stx104_remove(struct device *dev, unsigned int id) +{ + struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev); + + gpiochip_remove(&stx104gpio->chip); + + return 0; +} + +static struct isa_driver stx104_driver = { + .probe = stx104_probe, + .driver = { + .name = "stx104" + }, + .remove = stx104_remove +}; + +module_isa_driver(stx104_driver, num_stx104); + +MODULE_AUTHOR("William Breathitt Gray "); +MODULE_DESCRIPTION("Apex Embedded Systems STX104 IIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index e8656ba9bbb8..120b24478469 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -264,16 +264,6 @@ config MCP4922 To compile this driver as a module, choose M here: the module will be called mcp4922. -config STX104 - tristate "Apex Embedded Systems STX104 DAC driver" - depends on X86 && ISA_BUS_API - select GPIOLIB - help - Say yes here to build support for the 2-channel DAC and GPIO on the - Apex Embedded Systems STX104 integrated analog PC/104 card. The base - port addresses for the devices may be configured via the base array - module parameter. - config VF610_DAC tristate "Vybrid vf610 DAC driver" depends on OF diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index c50dbe082a70..27642bbf75f2 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -28,5 +28,4 @@ obj-$(CONFIG_MAX517) += max517.o obj-$(CONFIG_MAX5821) += max5821.o obj-$(CONFIG_MCP4725) += mcp4725.o obj-$(CONFIG_MCP4922) += mcp4922.o -obj-$(CONFIG_STX104) += stx104.o obj-$(CONFIG_VF610_DAC) += vf610_dac.o diff --git a/drivers/iio/dac/stx104.c b/drivers/iio/dac/stx104.c deleted file mode 100644 index 792a97164cb2..000000000000 --- a/drivers/iio/dac/stx104.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * DAC driver for the Apex Embedded Systems STX104 - * Copyright (C) 2016 William Breathitt Gray - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, as - * published by the Free Software Foundation. - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define STX104_NUM_CHAN 2 - -#define STX104_CHAN(chan) { \ - .type = IIO_VOLTAGE, \ - .channel = chan, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ - .indexed = 1, \ - .output = 1 \ -} - -#define STX104_EXTENT 16 - -static unsigned int base[max_num_isa_dev(STX104_EXTENT)]; -static unsigned int num_stx104; -module_param_array(base, uint, &num_stx104, 0); -MODULE_PARM_DESC(base, "Apex Embedded Systems STX104 base addresses"); - -/** - * struct stx104_iio - IIO device private data structure - * @chan_out_states: channels' output states - * @base: base port address of the IIO device - */ -struct stx104_iio { - unsigned chan_out_states[STX104_NUM_CHAN]; - unsigned base; -}; - -/** - * struct stx104_gpio - GPIO device private data structure - * @chip: instance of the gpio_chip - * @lock: synchronization lock to prevent I/O race conditions - * @base: base port address of the GPIO device - * @out_state: output bits state - */ -struct stx104_gpio { - struct gpio_chip chip; - spinlock_t lock; - unsigned int base; - unsigned int out_state; -}; - -static int stx104_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int *val, int *val2, long mask) -{ - struct stx104_iio *const priv = iio_priv(indio_dev); - - if (mask != IIO_CHAN_INFO_RAW) - return -EINVAL; - - *val = priv->chan_out_states[chan->channel]; - - return IIO_VAL_INT; -} - -static int stx104_write_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, int val, int val2, long mask) -{ - struct stx104_iio *const priv = iio_priv(indio_dev); - const unsigned chan_addr_offset = 2 * chan->channel; - - if (mask != IIO_CHAN_INFO_RAW) - return -EINVAL; - - priv->chan_out_states[chan->channel] = val; - outw(val, priv->base + 4 + chan_addr_offset); - - return 0; -} - -static const struct iio_info stx104_info = { - .driver_module = THIS_MODULE, - .read_raw = stx104_read_raw, - .write_raw = stx104_write_raw -}; - -static const struct iio_chan_spec stx104_channels[STX104_NUM_CHAN] = { - STX104_CHAN(0), - STX104_CHAN(1) -}; - -static int stx104_gpio_get_direction(struct gpio_chip *chip, - unsigned int offset) -{ - if (offset < 4) - return 1; - - return 0; -} - -static int stx104_gpio_direction_input(struct gpio_chip *chip, - unsigned int offset) -{ - if (offset >= 4) - return -EINVAL; - - return 0; -} - -static int stx104_gpio_direction_output(struct gpio_chip *chip, - unsigned int offset, int value) -{ - if (offset < 4) - return -EINVAL; - - chip->set(chip, offset, value); - return 0; -} - -static int stx104_gpio_get(struct gpio_chip *chip, unsigned int offset) -{ - struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); - - if (offset >= 4) - return -EINVAL; - - return !!(inb(stx104gpio->base) & BIT(offset)); -} - -static void stx104_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) -{ - struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip); - const unsigned int mask = BIT(offset) >> 4; - unsigned long flags; - - if (offset < 4) - return; - - spin_lock_irqsave(&stx104gpio->lock, flags); - - if (value) - stx104gpio->out_state |= mask; - else - stx104gpio->out_state &= ~mask; - - outb(stx104gpio->out_state, stx104gpio->base); - - spin_unlock_irqrestore(&stx104gpio->lock, flags); -} - -static int stx104_probe(struct device *dev, unsigned int id) -{ - struct iio_dev *indio_dev; - struct stx104_iio *priv; - struct stx104_gpio *stx104gpio; - int err; - - indio_dev = devm_iio_device_alloc(dev, sizeof(*priv)); - if (!indio_dev) - return -ENOMEM; - - stx104gpio = devm_kzalloc(dev, sizeof(*stx104gpio), GFP_KERNEL); - if (!stx104gpio) - return -ENOMEM; - - if (!devm_request_region(dev, base[id], STX104_EXTENT, - dev_name(dev))) { - dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n", - base[id], base[id] + STX104_EXTENT); - return -EBUSY; - } - - indio_dev->info = &stx104_info; - indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = stx104_channels; - indio_dev->num_channels = STX104_NUM_CHAN; - indio_dev->name = dev_name(dev); - - priv = iio_priv(indio_dev); - priv->base = base[id]; - - /* initialize DAC output to 0V */ - outw(0, base[id] + 4); - outw(0, base[id] + 6); - - err = devm_iio_device_register(dev, indio_dev); - if (err) { - dev_err(dev, "IIO device registering failed (%d)\n", err); - return err; - } - - stx104gpio->chip.label = dev_name(dev); - stx104gpio->chip.parent = dev; - stx104gpio->chip.owner = THIS_MODULE; - stx104gpio->chip.base = -1; - stx104gpio->chip.ngpio = 8; - stx104gpio->chip.get_direction = stx104_gpio_get_direction; - stx104gpio->chip.direction_input = stx104_gpio_direction_input; - stx104gpio->chip.direction_output = stx104_gpio_direction_output; - stx104gpio->chip.get = stx104_gpio_get; - stx104gpio->chip.set = stx104_gpio_set; - stx104gpio->base = base[id] + 3; - stx104gpio->out_state = 0x0; - - spin_lock_init(&stx104gpio->lock); - - dev_set_drvdata(dev, stx104gpio); - - err = gpiochip_add_data(&stx104gpio->chip, stx104gpio); - if (err) { - dev_err(dev, "GPIO registering failed (%d)\n", err); - return err; - } - - return 0; -} - -static int stx104_remove(struct device *dev, unsigned int id) -{ - struct stx104_gpio *const stx104gpio = dev_get_drvdata(dev); - - gpiochip_remove(&stx104gpio->chip); - - return 0; -} - -static struct isa_driver stx104_driver = { - .probe = stx104_probe, - .driver = { - .name = "stx104" - }, - .remove = stx104_remove -}; - -module_isa_driver(stx104_driver, num_stx104); - -MODULE_AUTHOR("William Breathitt Gray "); -MODULE_DESCRIPTION("Apex Embedded Systems STX104 DAC driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 1b246fca4adaa0bf440b604366f2227cc4cde702 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 30 Aug 2016 10:18:39 +0200 Subject: iio: st_sensors: fix errorcheck for regulators We were checking the return code of vdd when we should be checking vdd_io. My mistake, mea culpa. Cc: Giuseppe BARBA Reported-by: Giuseppe BARBA Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 41bfe1c5f4e9..285a64a589d7 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -247,9 +247,9 @@ int st_sensors_power_enable(struct iio_dev *indio_dev) } pdata->vdd_io = devm_regulator_get(indio_dev->dev.parent, "vddio"); - if (IS_ERR(pdata->vdd)) { + if (IS_ERR(pdata->vdd_io)) { dev_err(&indio_dev->dev, "unable to get Vdd_IO supply\n"); - err = PTR_ERR(pdata->vdd); + err = PTR_ERR(pdata->vdd_io); goto st_sensors_disable_vdd; } err = regulator_enable(pdata->vdd_io); -- cgit v1.2.3 From 2535cc7ae02bc1e4dc6b6d3771ba8d18cd824e10 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 1 Sep 2016 08:38:38 +0800 Subject: iio: chemical: vz89x: fix boolreturn.cocci warnings drivers/iio/chemical/vz89x.c:119:9-10: WARNING: return of 0/1 in function 'vz89x_measurement_is_valid' with return type bool Return statements in functions returning bool should use true/false instead of 1/0. Generated by: scripts/coccinelle/misc/boolreturn.cocci CC: Matt Ranostay Signed-off-by: Fengguang Wu Signed-off-by: Jonathan Cameron --- drivers/iio/chemical/vz89x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/chemical/vz89x.c b/drivers/iio/chemical/vz89x.c index cd3870ead3fd..8e0e4415c161 100644 --- a/drivers/iio/chemical/vz89x.c +++ b/drivers/iio/chemical/vz89x.c @@ -160,7 +160,7 @@ static const struct attribute_group vz89x_attrs_group = { static bool vz89x_measurement_is_valid(struct vz89x_data *data) { if (data->buffer[VZ89X_VOC_SHORT_IDX] == 0) - return 1; + return true; return !!(data->buffer[data->chip->read_size - 1] > 0); } -- cgit v1.2.3 From 9083325f1197a6956db17809d74dbe3578dc1005 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Fri, 2 Sep 2016 20:47:54 +0200 Subject: iio:trigger: add resource managed (un)register Add resource managed devm_iio_trigger_register() and devm_iio_triger_unregister() to automatically clean up registered triggers allocated by IIO drivers, thus leading to simplified IIO drivers code. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron --- Documentation/driver-model/devres.txt | 2 ++ drivers/iio/industrialio-trigger.c | 59 +++++++++++++++++++++++++++++++++++ include/linux/iio/trigger.h | 6 ++++ 3 files changed, 67 insertions(+) (limited to 'drivers/iio') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index b0d775d28e97..6a2138a7c3ff 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -268,6 +268,8 @@ IIO devm_iio_kfifo_free() devm_iio_trigger_alloc() devm_iio_trigger_free() + devm_iio_trigger_register() + devm_iio_trigger_unregister() devm_iio_channel_get() devm_iio_channel_release() devm_iio_channel_get_all() diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 3dde81e57e97..ba584b5e71f4 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -642,6 +642,65 @@ void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig) } EXPORT_SYMBOL_GPL(devm_iio_trigger_free); +static void devm_iio_trigger_unreg(struct device *dev, void *res) +{ + iio_trigger_unregister(*(struct iio_trigger **)res); +} + +/** + * devm_iio_trigger_register - Resource-managed iio_trigger_register() + * @dev: device this trigger was allocated for + * @trig_info: trigger to register + * + * Managed iio_trigger_register(). The IIO trigger registered with this + * function is automatically unregistered on driver detach. This function + * calls iio_trigger_register() internally. Refer to that function for more + * information. + * + * If an iio_trigger registered with this function needs to be unregistered + * separately, devm_iio_trigger_unregister() must be used. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int devm_iio_trigger_register(struct device *dev, struct iio_trigger *trig_info) +{ + struct iio_trigger **ptr; + int ret; + + ptr = devres_alloc(devm_iio_trigger_unreg, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + *ptr = trig_info; + ret = iio_trigger_register(trig_info); + if (!ret) + devres_add(dev, ptr); + else + devres_free(ptr); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_iio_trigger_register); + +/** + * devm_iio_trigger_unregister - Resource-managed iio_trigger_unregister() + * @dev: device this iio_trigger belongs to + * @trig_info: the trigger associated with the device + * + * Unregister trigger registered with devm_iio_trigger_register(). + */ +void devm_iio_trigger_unregister(struct device *dev, + struct iio_trigger *trig_info) +{ + int rc; + + rc = devres_release(dev, devm_iio_trigger_unreg, devm_iio_trigger_match, + trig_info); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister); + void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { indio_dev->groups[indio_dev->groupcounter++] = diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index a122bdd4076c..f0890a5abf13 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -125,12 +125,18 @@ static inline void *iio_trigger_get_drvdata(struct iio_trigger *trig) **/ int iio_trigger_register(struct iio_trigger *trig_info); +int devm_iio_trigger_register(struct device *dev, + struct iio_trigger *trig_info); + /** * iio_trigger_unregister() - unregister a trigger from the core * @trig_info: trigger to be unregistered **/ void iio_trigger_unregister(struct iio_trigger *trig_info); +void devm_iio_trigger_unregister(struct device *dev, + struct iio_trigger *trig_info); + /** * iio_trigger_set_immutable() - set an immutable trigger on destination * -- cgit v1.2.3 From 70e483487db787b152da756d4be0fef917378142 Mon Sep 17 00:00:00 2001 From: Gregor Boirie Date: Fri, 2 Sep 2016 20:47:55 +0200 Subject: iio: add resource managed triggered buffer init helpers Add resource managed devm_iio_triggered_buffer_setup() and devm_iio_triggered_buffer_cleanup() to automatically clean up triggered buffers setup by IIO drivers, thus leading to simplified IIO drivers code. Signed-off-by: Gregor Boirie Signed-off-by: Jonathan Cameron --- Documentation/driver-model/devres.txt | 2 ++ drivers/iio/buffer/industrialio-triggered-buffer.c | 42 ++++++++++++++++++++++ drivers/iio/industrialio-core.c | 3 +- include/linux/iio/iio.h | 1 + include/linux/iio/triggered_buffer.h | 8 +++++ 5 files changed, 55 insertions(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index 6a2138a7c3ff..75bc5b8add2f 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -266,6 +266,8 @@ IIO devm_iio_device_unregister() devm_iio_kfifo_allocate() devm_iio_kfifo_free() + devm_iio_triggered_buffer_setup() + devm_iio_triggered_buffer_cleanup() devm_iio_trigger_alloc() devm_iio_trigger_free() devm_iio_trigger_register() diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index 4b2858ba1fd6..d3db1fce54d2 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -98,6 +98,48 @@ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev) } EXPORT_SYMBOL(iio_triggered_buffer_cleanup); +static void devm_iio_triggered_buffer_clean(struct device *dev, void *res) +{ + iio_triggered_buffer_cleanup(*(struct iio_dev **)res); +} + +int devm_iio_triggered_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + irqreturn_t (*h)(int irq, void *p), + irqreturn_t (*thread)(int irq, void *p), + const struct iio_buffer_setup_ops *ops) +{ + struct iio_dev **ptr; + int ret; + + ptr = devres_alloc(devm_iio_triggered_buffer_clean, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + *ptr = indio_dev; + + ret = iio_triggered_buffer_setup(indio_dev, h, thread, ops); + if (!ret) + devres_add(dev, ptr); + else + devres_free(ptr); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup); + +void devm_iio_triggered_buffer_cleanup(struct device *dev, + struct iio_dev *indio_dev) +{ + int rc; + + rc = devres_release(dev, devm_iio_triggered_buffer_clean, + devm_iio_device_match, indio_dev); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_cleanup); + MODULE_AUTHOR("Lars-Peter Clausen "); MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index f914d5d140e4..0528a0c1b964 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1309,7 +1309,7 @@ static void devm_iio_device_release(struct device *dev, void *res) iio_device_free(*(struct iio_dev **)res); } -static int devm_iio_device_match(struct device *dev, void *res, void *data) +int devm_iio_device_match(struct device *dev, void *res, void *data) { struct iio_dev **r = res; if (!r || !*r) { @@ -1318,6 +1318,7 @@ static int devm_iio_device_match(struct device *dev, void *res, void *data) } return *r == data; } +EXPORT_SYMBOL_GPL(devm_iio_device_match); /** * devm_iio_device_alloc - Resource-managed iio_device_alloc() diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 786952cd509f..b4a0679e4a49 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -644,6 +644,7 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv) } void iio_device_free(struct iio_dev *indio_dev); +int devm_iio_device_match(struct device *dev, void *res, void *data); struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv); void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev); struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, diff --git a/include/linux/iio/triggered_buffer.h b/include/linux/iio/triggered_buffer.h index f72f70d5a97b..30145616773d 100644 --- a/include/linux/iio/triggered_buffer.h +++ b/include/linux/iio/triggered_buffer.h @@ -12,4 +12,12 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev, const struct iio_buffer_setup_ops *setup_ops); void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev); +int devm_iio_triggered_buffer_setup(struct device *dev, + struct iio_dev *indio_dev, + irqreturn_t (*h)(int irq, void *p), + irqreturn_t (*thread)(int irq, void *p), + const struct iio_buffer_setup_ops *ops); +void devm_iio_triggered_buffer_cleanup(struct device *dev, + struct iio_dev *indio_dev); + #endif -- cgit v1.2.3 From 67516074884b4bde71ca8ca4724544669935cc5d Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Sep 2016 11:14:48 +0200 Subject: iio: fetch and enable regulators unconditionally This patch is inspired by a comment of Jonathan Cameron on patch of Linus Walleij commit aeb55fff3891834e07a3144159a7298a19696af8 ("iio: st_sensors: fetch and enable regulators unconditionally"). The explanation for this change is same as in that patch: "Supplies are *not* optional (optional means that the supply is optional in the electrical sense, not the software sense) so we need to get the and enable them at all times. If the device tree or board file does not define suitable regulators for the component, it will be substituted by a dummy regulator, or, if regulators are disabled altogether, by stubs. There is no need to use the IS_ERR_OR_NULL() check that is considered harmful. Reported-by: Linus Wallerij Suggested-by: Jonathan Cameron Signed-off-by: Crt Mori Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/ms5611_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index feb41f82c64a..a74ed1f0c880 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -416,8 +416,7 @@ static int ms5611_init(struct iio_dev *indio_dev) return 0; err_regulator_disable: - if (!IS_ERR_OR_NULL(st->vdd)) - regulator_disable(st->vdd); + regulator_disable(st->vdd); return ret; } @@ -425,8 +424,7 @@ static void ms5611_fini(const struct iio_dev *indio_dev) { const struct ms5611_state *st = iio_priv(indio_dev); - if (!IS_ERR_OR_NULL(st->vdd)) - regulator_disable(st->vdd); + regulator_disable(st->vdd); } int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, -- cgit v1.2.3 From fbe84bd4803eb6c96376af5530ce69e1db873b5f Mon Sep 17 00:00:00 2001 From: Crt Mori Date: Mon, 5 Sep 2016 11:14:49 +0200 Subject: iio: devm_regulator_get_optional never returns NULL This patch is inspired by a comment of Jonathan Cameron on patch of Linus Walleij commit aeb55fff3891834e07a3144159a7298a19696af8 ("iio: st_sensors: fetch and enable regulators unconditionally"). Because changes made in this patch are actually reference generators they should be using devm_regulator_get_optional, but if they do not explicitly set the reference to NULL they should not be using IS_ERR_OR_NULL, but simple IS_ERR check. Suggested-by: Lars-Peter Clausen Signed-off-by: Crt Mori Reviewed-by: Linus Walleij Acked-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7266.c | 4 ++-- drivers/iio/adc/ti-ads8688.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index c0f6a98fd9bd..b8d5cfd57ec4 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -481,7 +481,7 @@ error_free_gpios: if (!st->fixed_addr) gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios)); error_disable_reg: - if (!IS_ERR_OR_NULL(st->reg)) + if (!IS_ERR(st->reg)) regulator_disable(st->reg); return ret; @@ -496,7 +496,7 @@ static int ad7266_remove(struct spi_device *spi) iio_triggered_buffer_cleanup(indio_dev); if (!st->fixed_addr) gpio_free_array(st->gpios, ARRAY_SIZE(st->gpios)); - if (!IS_ERR_OR_NULL(st->reg)) + if (!IS_ERR(st->reg)) regulator_disable(st->reg); return 0; diff --git a/drivers/iio/adc/ti-ads8688.c b/drivers/iio/adc/ti-ads8688.c index c400439900af..4a163496d9e4 100644 --- a/drivers/iio/adc/ti-ads8688.c +++ b/drivers/iio/adc/ti-ads8688.c @@ -438,7 +438,7 @@ static int ads8688_probe(struct spi_device *spi) return 0; error_out: - if (!IS_ERR_OR_NULL(st->reg)) + if (!IS_ERR(st->reg)) regulator_disable(st->reg); return ret; @@ -451,7 +451,7 @@ static int ads8688_remove(struct spi_device *spi) iio_device_unregister(indio_dev); - if (!IS_ERR_OR_NULL(st->reg)) + if (!IS_ERR(st->reg)) regulator_disable(st->reg); return 0; -- cgit v1.2.3 From ede63aaf7cda21bc265edb928f01363784cbf3fc Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 30 Aug 2016 14:27:01 +0200 Subject: iio: adc: at91: Add support for Touchscreen Switches Closure Time On newer components compatible with the at91sam9x5, the Touchscreen Switches Closure Time or TSSCTIM value of the Touchscreen Mode Register is not filled at all. On some hardware, having no time indicated for it may lead to incoherent values and jitter. We fix this time to 10us as it is usually difficult to retrieve impedance values from LCD manufacturers. Signed-off-by: Nicolas Ferre Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 52430ba171f3..0331c7a678a6 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -113,6 +113,7 @@ #define AT91_ADC_TSMR_TSAV (3 << 4) /* Averages samples */ #define AT91_ADC_TSMR_TSAV_(x) ((x) << 4) #define AT91_ADC_TSMR_SCTIM (0x0f << 16) /* Switch closure time */ +#define AT91_ADC_TSMR_SCTIM_(x) ((x) << 16) #define AT91_ADC_TSMR_PENDBC (0x0f << 28) /* Pen Debounce time */ #define AT91_ADC_TSMR_PENDBC_(x) ((x) << 28) #define AT91_ADC_TSMR_NOTSDMA (1 << 22) /* No Touchscreen DMA */ @@ -150,6 +151,7 @@ #define MAX_RLPOS_BITS 10 #define TOUCH_SAMPLE_PERIOD_US_RL 10000 /* 10ms, the SoC can't keep up with 2ms */ #define TOUCH_SHTIM 0xa +#define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */ /** * struct at91_adc_reg_desc - Various informations relative to registers @@ -1001,7 +1003,9 @@ static void atmel_ts_close(struct input_dev *dev) static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) { + struct iio_dev *idev = iio_priv_to_dev(st); u32 reg = 0; + u32 tssctim = 0; int i = 0; /* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid @@ -1034,11 +1038,20 @@ static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz) return 0; } + /* Touchscreen Switches Closure time needed for allowing the value to + * stabilize. + * Switch Closure Time = (TSSCTIM * 4) ADCClock periods + */ + tssctim = DIV_ROUND_UP(TOUCH_SCTIM_US * adc_clk_khz / 1000, 4); + dev_dbg(&idev->dev, "adc_clk at: %d KHz, tssctim at: %d\n", + adc_clk_khz, tssctim); + if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE) reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS; else reg = AT91_ADC_TSMR_TSMODE_5WIRE; + reg |= AT91_ADC_TSMR_SCTIM_(tssctim) & AT91_ADC_TSMR_SCTIM; reg |= AT91_ADC_TSMR_TSAV_(st->caps->ts_filter_average) & AT91_ADC_TSMR_TSAV; reg |= AT91_ADC_TSMR_PENDBC_(st->ts_pendbc) & AT91_ADC_TSMR_PENDBC; -- cgit v1.2.3 From 06777c562a50a09c4a2becfb2bf63c762a45df17 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 4 Sep 2016 19:35:32 +0200 Subject: iio: accel: mxc6255 add support for the mxc6225 The mxc6225 is fully compatible with the existing mxc6255 driver, add support for it. Signed-off-by: Hans de Goede Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mxc6255.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index 97ccde722e7b..50343a7818d6 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -26,6 +26,7 @@ #define MXC6255_REG_YOUT 0x01 #define MXC6255_REG_CHIP_ID 0x08 +#define MXC6225_CHIP_ID 0xe5 #define MXC6255_CHIP_ID 0x05 /* @@ -154,7 +155,11 @@ static int mxc6255_probe(struct i2c_client *client, return ret; } - if (chip_id != MXC6255_CHIP_ID) { + switch (chip_id) { + case MXC6225_CHIP_ID: + case MXC6255_CHIP_ID: + break; + default: dev_err(&client->dev, "Invalid chip id %x\n", chip_id); return -ENODEV; } @@ -171,12 +176,14 @@ static int mxc6255_probe(struct i2c_client *client, } static const struct acpi_device_id mxc6255_acpi_match[] = { + {"MXC6225", 0}, {"MXC6255", 0}, { } }; MODULE_DEVICE_TABLE(acpi, mxc6255_acpi_match); static const struct i2c_device_id mxc6255_id[] = { + {"mxc6225", 0}, {"mxc6255", 0}, { } }; -- cgit v1.2.3 From 4b1a9380a62ae669d1ae10dc118570c276a645ea Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 8 Sep 2016 18:49:10 +0200 Subject: iio: iio_push_event(): Don't crash if the event interface is not registered iio_push_event() operates on a struct iio_dev. This struct can be allocated using iio_device_alloc() which returns a valid struct iio_dev pointer. But iio_push_event() is not safe to use on such a iio_dev until iio_device_register() for the same device has successfully completed. This restriction is not documented anywhere and most drivers are written with the assumption that this restriction does not exist. The basic pattern that is followed by all drivers looks like the following: irqreturn_t event_callback(int irq, void *devid) { struct iio_dev *indio_dev = devid; ... iio_push_event(indio_dev, ...); return IRQ_HANDLED; } int driver_probe(struct device *dev) { struct iio_dev *indio_dev; indio_dev = iio_device_alloc(...); request_irq(event_irq, event_callback, ..., indio_dev); return iio_device_register(indio_dev); } And while it is unlikely that the IRQ fires before iio_device_register() completes (e.g. because the IRQ is disabled in the device) it is not impossible and might be triggered by glitches on the signal line or incorrect hardware configuration. To avoid undefined behaviour in such a case extend iio_push_event() to check if the event has been registered and discard generated events if it has not. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-event.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 0ebfc923a997..90fac8ec63c9 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -57,6 +57,11 @@ bool iio_event_enabled(const struct iio_event_interface *ev_int) * * Note: The caller must make sure that this function is not running * concurrently for the same indio_dev more than once. + * + * This function may be safely used as soon as a valid reference to iio_dev has + * been obtained via iio_device_alloc(), but any events that are submitted + * before iio_device_register() has successfully completed will be silently + * discarded. **/ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) { @@ -64,6 +69,9 @@ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) struct iio_event_data ev; int copied; + if (!ev_int) + return 0; + /* Does anyone care? */ if (iio_event_enabled(ev_int)) { -- cgit v1.2.3 From 702a7b8e064a93df0b63e9d718b666a9851088fc Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 1 Sep 2016 10:27:17 +0200 Subject: iio: trigger: helpers to determine own trigger This adds a helper function to the IIO trigger framework: iio_trigger_using_own(): for an IIO device, this tells whether the device is using itself as a trigger. This is true if the indio device: (A) supplies a trigger and (B) has assigned its own buffer poll function to use this trigger. This helper function is good when constructing triggered, buffered drivers that can either use its own hardware *OR* an external trigger such as a HRTimer or even the trigger from a totally different sensor. Under such circumstances it is important to know for example if the timestamp from the same trigger hardware should be used when populating the buffer: if iio_trigger_using_own() is true, we can use this timestamp, else we need to pick a unique timestamp directly in the trigger handler. For this to work of course IIO devices registering hardware triggers must follow the convention to set the parent device properly, as as well as setting the parent of the IIO device itself. When a new poll function is attached, we check if the parent device of the IIO of the poll function is the same as the parent device of the trigger and in that case we conclude that the hardware is using itself as trigger. Cc: Giuseppe Barba Cc: Denis Ciocca Cc: Crestez Dan Leonard Cc: Gregor Boirie Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-trigger.c | 16 ++++++++++++++++ include/linux/iio/trigger.h | 11 +++++++++++ 2 files changed, 27 insertions(+) (limited to 'drivers/iio') diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index ba584b5e71f4..e1e104845e38 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -271,6 +271,14 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig, goto out_free_irq; } + /* + * Check if we just registered to our own trigger: we determine that + * this is the case if the IIO device and the trigger device share the + * same parent device. + */ + if (pf->indio_dev->dev.parent == trig->dev.parent) + trig->attached_own_device = true; + return ret; out_free_irq: @@ -295,6 +303,8 @@ static int iio_trigger_detach_poll_func(struct iio_trigger *trig, if (ret) return ret; } + if (pf->indio_dev->dev.parent == trig->dev.parent) + trig->attached_own_device = false; iio_trigger_put_irq(trig, pf->irq); free_irq(pf->irq, pf); module_put(pf->indio_dev->info->driver_module); @@ -701,6 +711,12 @@ void devm_iio_trigger_unregister(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister); +bool iio_trigger_using_own(struct iio_dev *indio_dev) +{ + return indio_dev->trig->attached_own_device; +} +EXPORT_SYMBOL(iio_trigger_using_own); + void iio_device_register_trigger_consumer(struct iio_dev *indio_dev) { indio_dev->groups[indio_dev->groupcounter++] = diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index f0890a5abf13..4f1154f7a33c 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -56,6 +56,9 @@ struct iio_trigger_ops { * @subirqs: [INTERN] information about the 'child' irqs. * @pool: [INTERN] bitmap of irqs currently in use. * @pool_lock: [INTERN] protection of the irq pool. + * @attached_own_device:[INTERN] if we are using our own device as trigger, + * i.e. if we registered a poll function to the same + * device as the one providing the trigger. **/ struct iio_trigger { const struct iio_trigger_ops *ops; @@ -73,6 +76,7 @@ struct iio_trigger { struct iio_subirq subirqs[CONFIG_IIO_CONSUMERS_PER_TRIGGER]; unsigned long pool[BITS_TO_LONGS(CONFIG_IIO_CONSUMERS_PER_TRIGGER)]; struct mutex pool_lock; + bool attached_own_device; }; @@ -160,6 +164,13 @@ irqreturn_t iio_trigger_generic_data_rdy_poll(int irq, void *private); __printf(1, 2) struct iio_trigger *iio_trigger_alloc(const char *fmt, ...); void iio_trigger_free(struct iio_trigger *trig); +/** + * iio_trigger_using_own() - tells us if we use our own HW trigger ourselves + * @indio_dev: device to check + */ +bool iio_trigger_using_own(struct iio_dev *indio_dev); + + #else struct iio_trigger; struct iio_trigger_ops; -- cgit v1.2.3 From 7ba4b884b7a890e240a13f5f65d607721e80396a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 1 Sep 2016 10:27:18 +0200 Subject: iio: st_sensors: use the helper function The ST sensors can be used as a trigger for its own triggered buffer but it is also possible to use an external trigger: a HRTimer or even a different sensor (!) as trigger. In that case we should not pick the timestamp from our own interrupt top half even if it is active. This could practically happen if some other sensor is using the ST sensor as trigger but the ST sensor itself is using e.g. an HRTimer as trigger. So the trigger is on, but not used by us. We used to assume that whenever the hardware interrupt is turned on, we are using it for our own trigger, but this is an oversimplification. Handle this logically by using the iio_trigger_using_own() helper. Cc: Giuseppe Barba Cc: Denis Ciocca Cc: Crestez Dan Leonard Cc: Gregor Boirie Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron --- drivers/iio/common/st_sensors/st_sensors_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/iio') diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index d06e728cea37..fe7775bb3740 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -63,7 +63,7 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p) * the hardware trigger) and the hw_timestamp may get updated. * By storing it in a local variable first, we are safe. */ - if (sdata->hw_irq_trigger) + if (iio_trigger_using_own(indio_dev)) timestamp = sdata->hw_timestamp; else timestamp = iio_get_time_ns(indio_dev); -- cgit v1.2.3 From 1696566f995cfd4ddf3f167b4097cdc83f1458f2 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 11 Sep 2016 18:29:16 +0200 Subject: iio: accel: mxc6255: Fix chip-id check The initial commit adding support for the mxc6225 assumed the mxc6225 has a chip-id of 0xe5 based on testing on a single Allwinner A23 tablet with a mxc6225. Testing on a bunch of other Allwinner tablets have shown that the chip-id for the mxc6225 is not constant. A datasheet for the MXC6255 which I've found online says that bits 7 and 6 of the chip-id register are undefined (for the mxc6255), testing on 5 different tablets with a mxc6225 has found the following ids: 0x25, 0x45, 0x65, 0x85, 0xe5. So it seems that for the mxc6225 bits 7, 6 and 5 of the chip-id register are undefined. This commit adjusts the chip-id check so that the mxc6255 driver properly recognizes the mxc6225 in all these tablets. Signed-off-by: Hans de Goede Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mxc6255.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/iio') diff --git a/drivers/iio/accel/mxc6255.c b/drivers/iio/accel/mxc6255.c index 50343a7818d6..0abad6948201 100644 --- a/drivers/iio/accel/mxc6255.c +++ b/drivers/iio/accel/mxc6255.c @@ -26,7 +26,6 @@ #define MXC6255_REG_YOUT 0x01 #define MXC6255_REG_CHIP_ID 0x08 -#define MXC6225_CHIP_ID 0xe5 #define MXC6255_CHIP_ID 0x05 /* @@ -155,11 +154,7 @@ static int mxc6255_probe(struct i2c_client *client, return ret; } - switch (chip_id) { - case MXC6225_CHIP_ID: - case MXC6255_CHIP_ID: - break; - default: + if ((chip_id & 0x1f) != MXC6255_CHIP_ID) { dev_err(&client->dev, "Invalid chip id %x\n", chip_id); return -ENODEV; } -- cgit v1.2.3