From abe4e26bb7edb7b36ef99e2e78e86de79b18f922 Mon Sep 17 00:00:00 2001 From: Devendra Naga Date: Fri, 2 Jan 2015 04:02:54 -0500 Subject: iio: meter: ade7754: add error handling in _reset and _stop_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the error handling for the value returned from ade7754_spi_read_reg_8. With this patch, the following randconfig warnings get fixed automatically. drivers/staging/iio/meter/ade7754.c:222:6: warning: ‘val’ may be used uninitialized in this function [-Wmaybe-uninitialized] drivers/staging/iio/meter/ade7754.c:368:6: warning: ‘val’ may be used uninitialized in this function [-Wmaybe-uninitialized] Signed-off-by: Devendra Naga Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7754.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index 81f67318974a..746b18894ebf 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -216,9 +216,13 @@ error_ret: static int ade7754_reset(struct device *dev) { + int ret; u8 val; - ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val); + ret = ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val); + if (ret < 0) + return ret; + val |= 1 << 6; /* Software Chip Reset */ return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val); } @@ -362,9 +366,16 @@ error_ret: /* Power down the device */ static int ade7754_stop_device(struct device *dev) { + int ret; u8 val; - ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val); + ret = ade7754_spi_read_reg_8(dev, ADE7754_OPMODE, &val); + if (ret < 0) { + dev_err(dev, "unable to power down the device, error: %d", + ret); + return ret; + } + val |= 7 << 3; /* ADE7754 powered down */ return ade7754_spi_write_reg_8(dev, ADE7754_OPMODE, val); } -- cgit v1.2.3 From 1e716a15ce5e5840cac0fb4cd6ca79d70d3568a9 Mon Sep 17 00:00:00 2001 From: Devendra Naga Date: Fri, 2 Jan 2015 04:02:55 -0500 Subject: iio: meter: ade7759: add error handling in _reset and _stop_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds the error handling for the value returned from ade7759_spi_read_reg_16. With this patch, the following randconfig warnings get fixed automatically. drivers/staging/iio/meter/ade7759.c:224:6: warning: ‘val’ may be used uninitialized in this function [-Wmaybe-uninitialized] drivers/staging/iio/meter/ade7759.c:309:6: warning: ‘val’ may be used uninitialized in this function [-Wmaybe-uninitialized] Signed-off-by: Devendra Naga Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7759.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index b0c7dbc8a428..9afdb1e1a222 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -218,9 +218,12 @@ static int ade7759_reset(struct device *dev) int ret; u16 val; - ade7759_spi_read_reg_16(dev, + ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val); + if (ret < 0) + return ret; + val |= 1 << 6; /* Software Chip Reset */ ret = ade7759_spi_write_reg_16(dev, ADE7759_MODE, @@ -301,11 +304,18 @@ error_ret: /* Power down the device */ static int ade7759_stop_device(struct device *dev) { + int ret; u16 val; - ade7759_spi_read_reg_16(dev, + ret = ade7759_spi_read_reg_16(dev, ADE7759_MODE, &val); + if (ret < 0) { + dev_err(dev, "unable to power down the device, error: %d\n", + ret); + return ret; + } + val |= 1 << 4; /* AD converters can be turned off */ return ade7759_spi_write_reg_16(dev, ADE7759_MODE, val); -- cgit v1.2.3 From a36385a2613c0755164ec53e8b7a42d4d11f65b9 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Mon, 5 Jan 2015 11:21:42 +0200 Subject: iio: imu: kmx61: Drop odr_bits from kmx61_samp_freq_table odr_bits values are between 0 and 11, so we can use the index in kmx61_samp_freq_table instead of odr_bits structure member. Signed-off-by: Daniel Baluta Reviewed-by: Hartmut Knaack Signed-off-by: Jonathan Cameron --- drivers/iio/imu/kmx61.c | 64 ++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 5cc3692acf37..32e5f96a6477 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -169,19 +169,18 @@ static const u16 kmx61_uscale_table[] = {9582, 19163, 38326}; static const struct { int val; int val2; - u8 odr_bits; -} kmx61_samp_freq_table[] = { {12, 500000, 0x00}, - {25, 0, 0x01}, - {50, 0, 0x02}, - {100, 0, 0x03}, - {200, 0, 0x04}, - {400, 0, 0x05}, - {800, 0, 0x06}, - {1600, 0, 0x07}, - {0, 781000, 0x08}, - {1, 563000, 0x09}, - {3, 125000, 0x0A}, - {6, 250000, 0x0B} }; +} kmx61_samp_freq_table[] = { {12, 500000}, + {25, 0}, + {50, 0}, + {100, 0}, + {200, 0}, + {400, 0}, + {800, 0}, + {1600, 0}, + {0, 781000}, + {1, 563000}, + {3, 125000}, + {6, 250000} }; static const struct { int val; @@ -302,24 +301,10 @@ static int kmx61_convert_freq_to_bit(int val, int val2) for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++) if (val == kmx61_samp_freq_table[i].val && val2 == kmx61_samp_freq_table[i].val2) - return kmx61_samp_freq_table[i].odr_bits; - return -EINVAL; -} - -static int kmx61_convert_bit_to_freq(u8 odr_bits, int *val, int *val2) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++) - if (odr_bits == kmx61_samp_freq_table[i].odr_bits) { - *val = kmx61_samp_freq_table[i].val; - *val2 = kmx61_samp_freq_table[i].val2; - return 0; - } + return i; return -EINVAL; } - static int kmx61_convert_wake_up_odr_to_bit(int val, int val2) { int i; @@ -478,7 +463,7 @@ static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device) static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2, u8 device) -{ int i; +{ u8 lodr_bits; if (device & KMX61_ACC) @@ -490,13 +475,13 @@ static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2, else return -EINVAL; - for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++) - if (lodr_bits == kmx61_samp_freq_table[i].odr_bits) { - *val = kmx61_samp_freq_table[i].val; - *val2 = kmx61_samp_freq_table[i].val2; - return 0; - } - return -EINVAL; + if (lodr_bits >= ARRAY_SIZE(kmx61_samp_freq_table)) + return -EINVAL; + + *val = kmx61_samp_freq_table[lodr_bits].val; + *val2 = kmx61_samp_freq_table[lodr_bits].val2; + + return 0; } static int kmx61_set_range(struct kmx61_data *data, u8 range) @@ -580,8 +565,11 @@ static int kmx61_chip_init(struct kmx61_data *data) } data->odr_bits = ret; - /* set output data rate for wake up (motion detection) function */ - ret = kmx61_convert_bit_to_freq(data->odr_bits, &val, &val2); + /* + * set output data rate for wake up (motion detection) function + * to match data rate for accelerometer sampling + */ + ret = kmx61_get_odr(data, &val, &val2, KMX61_ACC); if (ret < 0) return ret; -- cgit v1.2.3 From ee3ac290e8aaa8396e697a11470703e616ab335f Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 2 Feb 2015 03:35:20 -0500 Subject: iio: vf610_adc: cleanup wait_for_completion return handling return type of wait_for_completion_timeout is unsigned long not int, this patch only fixes up the return handling. Signed-off-by: Nicholas Mc Guire Signed-off-by: Jonathan Cameron --- drivers/iio/adc/vf610_adc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c index 8ec353c01d98..5b72d170fd36 100644 --- a/drivers/iio/adc/vf610_adc.c +++ b/drivers/iio/adc/vf610_adc.c @@ -259,7 +259,6 @@ static void vf610_adc_cfg_post_set(struct vf610_adc *info) static void vf610_adc_calibration(struct vf610_adc *info) { int adc_gc, hc_cfg; - int timeout; if (!info->adc_feature.calibration) return; @@ -271,9 +270,7 @@ static void vf610_adc_calibration(struct vf610_adc *info) adc_gc = readl(info->regs + VF610_REG_ADC_GC); writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC); - timeout = wait_for_completion_timeout - (&info->completion, VF610_ADC_TIMEOUT); - if (timeout == 0) + if (!wait_for_completion_timeout(&info->completion, VF610_ADC_TIMEOUT)) dev_err(info->dev, "Timeout for adc calibration\n"); adc_gc = readl(info->regs + VF610_REG_ADC_GS); -- cgit v1.2.3 From 6da9b382bd2b6e1b910d7e3512a8a115c8c5f113 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 31 Jan 2015 02:00:00 +0200 Subject: iio: buffer: refactor buffer attributes setup Move all core (non-custom) buffer attributes to a vector to make it easier to add more of them in the future. Signed-off-by: Octavian Purdila Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 71333140d42c..c2d5440aa226 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -761,6 +761,11 @@ static struct device_attribute dev_attr_length_ro = __ATTR(length, static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, iio_buffer_show_enable, iio_buffer_store_enable); +static struct attribute *iio_buffer_attrs[] = { + &dev_attr_length.attr, + &dev_attr_enable.attr, +}; + int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) { struct iio_dev_attr *p; @@ -778,21 +783,23 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) attrcount++; } - buffer->buffer_group.name = "buffer"; - buffer->buffer_group.attrs = kcalloc(attrcount + 3, - sizeof(*buffer->buffer_group.attrs), GFP_KERNEL); - if (!buffer->buffer_group.attrs) + attr = kcalloc(attrcount + ARRAY_SIZE(iio_buffer_attrs) + 1, + sizeof(struct attribute *), GFP_KERNEL); + if (!attr) return -ENOMEM; - if (buffer->access->set_length) - buffer->buffer_group.attrs[0] = &dev_attr_length.attr; - else - buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr; - buffer->buffer_group.attrs[1] = &dev_attr_enable.attr; + memcpy(attr, iio_buffer_attrs, sizeof(iio_buffer_attrs)); + if (!buffer->access->set_length) + attr[0] = &dev_attr_length_ro.attr; + if (buffer->attrs) - memcpy(&buffer->buffer_group.attrs[2], buffer->attrs, - sizeof(*&buffer->buffer_group.attrs) * attrcount); - buffer->buffer_group.attrs[attrcount+2] = NULL; + memcpy(&attr[ARRAY_SIZE(iio_buffer_attrs)], buffer->attrs, + sizeof(struct attribute *) * attrcount); + + attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL; + + buffer->buffer_group.name = "buffer"; + buffer->buffer_group.attrs = attr; indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group; -- cgit v1.2.3 From 802a3aef30917cc20279d17fe4d0e8568d5c7814 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 31 Jan 2015 02:00:03 +0200 Subject: iio: bmc150: refactor slope duration and threshold update Move the slope duration and threshold update in a separate function to reduce code duplicate between chip init and motion interrupt setup. Also move the slope update code from the interrupt setup function to the trigger set state function so that we can later refactor the interrupt code. Signed-off-by: Octavian Purdila Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 97 +++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 066d0c04072c..2b6b80d700e4 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -269,6 +269,37 @@ static int bmc150_accel_set_bw(struct bmc150_accel_data *data, int val, return -EINVAL; } +static int bmc150_accel_update_slope(struct bmc150_accel_data *data) +{ + int ret, val; + + ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_6, + data->slope_thres); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_6\n"); + return ret; + } + + ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_5\n"); + return ret; + } + + val = (ret & ~BMC150_ACCEL_SLOPE_DUR_MASK) | data->slope_dur; + ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_5, + val); + if (ret < 0) { + dev_err(&data->client->dev, "Error write reg_int_5\n"); + return ret; + } + + dev_dbg(&data->client->dev, "%s: %x %x\n", __func__, data->slope_thres, + data->slope_dur); + + return ret; +} + static int bmc150_accel_chip_init(struct bmc150_accel_data *data) { int ret; @@ -307,32 +338,12 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) data->range = BMC150_ACCEL_DEF_RANGE_4G; - /* Set default slope duration */ - ret = i2c_smbus_read_byte_data(data->client, BMC150_ACCEL_REG_INT_5); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_5\n"); - return ret; - } - data->slope_dur |= BMC150_ACCEL_DEF_SLOPE_DURATION; - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_5, - data->slope_dur); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_5\n"); - return ret; - } - dev_dbg(&data->client->dev, "slope_dur %x\n", data->slope_dur); - - /* Set default slope thresholds */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_6, - BMC150_ACCEL_DEF_SLOPE_THRESHOLD); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_6\n"); - return ret; - } + /* Set default slope duration and thresholds */ data->slope_thres = BMC150_ACCEL_DEF_SLOPE_THRESHOLD; - dev_dbg(&data->client->dev, "slope_thres %x\n", data->slope_thres); + data->slope_dur = BMC150_ACCEL_DEF_SLOPE_DURATION; + ret = bmc150_accel_update_slope(data); + if (ret < 0) + return ret; /* Set default as latched interrupts */ ret = i2c_smbus_write_byte_data(data->client, @@ -375,24 +386,6 @@ static int bmc150_accel_setup_any_motion_interrupt( } if (status) { - /* Set slope duration (no of samples) */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_5, - data->slope_dur); - if (ret < 0) { - dev_err(&data->client->dev, "Error write reg_int_5\n"); - return ret; - } - - /* Set slope thresholds */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_6, - data->slope_thres); - if (ret < 0) { - dev_err(&data->client->dev, "Error write reg_int_6\n"); - return ret; - } - /* * New data interrupt is always non-latched, * which will have higher priority, so no need @@ -732,7 +725,7 @@ static int bmc150_accel_read_event(struct iio_dev *indio_dev, *val = data->slope_thres; break; case IIO_EV_INFO_PERIOD: - *val = data->slope_dur & BMC150_ACCEL_SLOPE_DUR_MASK; + *val = data->slope_dur; break; default: return -EINVAL; @@ -755,11 +748,10 @@ static int bmc150_accel_write_event(struct iio_dev *indio_dev, switch (info) { case IIO_EV_INFO_VALUE: - data->slope_thres = val; + data->slope_thres = val & 0xFF; break; case IIO_EV_INFO_PERIOD: - data->slope_dur &= ~BMC150_ACCEL_SLOPE_DUR_MASK; - data->slope_dur |= val & BMC150_ACCEL_SLOPE_DUR_MASK; + data->slope_dur = val & BMC150_ACCEL_SLOPE_DUR_MASK; break; default: return -EINVAL; @@ -1056,10 +1048,15 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, mutex_unlock(&data->mutex); return ret; } - if (data->motion_trig == trig) - ret = bmc150_accel_setup_any_motion_interrupt(data, state); - else + + if (data->motion_trig == trig) { + ret = bmc150_accel_update_slope(data); + if (!ret) + ret = bmc150_accel_setup_any_motion_interrupt(data, + state); + } else { ret = bmc150_accel_setup_new_data_interrupt(data, state); + } if (ret < 0) { bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); -- cgit v1.2.3 From 8e22f477e1432ace88b762f5f66e0f96631a1462 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 31 Jan 2015 02:00:04 +0200 Subject: iio: bmc150: refactor interrupt enabling This patch combines the any motion and new data interrupts function into a single, generic, interrupt enable function. On top of this, we can later refactor triggers to make it easier to add new triggers. Signed-off-by: Octavian Purdila Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 272 ++++++++++++++++----------------------- 1 file changed, 113 insertions(+), 159 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 2b6b80d700e4..087392514e54 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -359,137 +359,6 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) return 0; } -static int bmc150_accel_setup_any_motion_interrupt( - struct bmc150_accel_data *data, - bool status) -{ - int ret; - - /* Enable/Disable INT1 mapping */ - ret = i2c_smbus_read_byte_data(data->client, - BMC150_ACCEL_REG_INT_MAP_0); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_map_0\n"); - return ret; - } - if (status) - ret |= BMC150_ACCEL_INT_MAP_0_BIT_SLOPE; - else - ret &= ~BMC150_ACCEL_INT_MAP_0_BIT_SLOPE; - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_MAP_0, - ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_map_0\n"); - return ret; - } - - if (status) { - /* - * New data interrupt is always non-latched, - * which will have higher priority, so no need - * to set latched mode, we will be flooded anyway with INTR - */ - if (!data->dready_trigger_on) { - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - } - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_EN_0, - BMC150_ACCEL_INT_EN_BIT_SLP_X | - BMC150_ACCEL_INT_EN_BIT_SLP_Y | - BMC150_ACCEL_INT_EN_BIT_SLP_Z); - } else - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_EN_0, - 0); - - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_en_0\n"); - return ret; - } - - return 0; -} - -static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data, - bool status) -{ - int ret; - - /* Enable/Disable INT1 mapping */ - ret = i2c_smbus_read_byte_data(data->client, - BMC150_ACCEL_REG_INT_MAP_1); - if (ret < 0) { - dev_err(&data->client->dev, "Error reading reg_int_map_1\n"); - return ret; - } - if (status) - ret |= BMC150_ACCEL_INT_MAP_1_BIT_DATA; - else - ret &= ~BMC150_ACCEL_INT_MAP_1_BIT_DATA; - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_MAP_1, - ret); - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_map_1\n"); - return ret; - } - - if (status) { - /* - * Set non latched mode interrupt and clear any latched - * interrupt - */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_NON_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_EN_1, - BMC150_ACCEL_INT_EN_BIT_DATA_EN); - - } else { - /* Restore default interrupt mode */ - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_RST_LATCH, - BMC150_ACCEL_INT_MODE_LATCH_INT | - BMC150_ACCEL_INT_MODE_LATCH_RESET); - if (ret < 0) { - dev_err(&data->client->dev, - "Error writing reg_int_rst_latch\n"); - return ret; - } - - ret = i2c_smbus_write_byte_data(data->client, - BMC150_ACCEL_REG_INT_EN_1, - 0); - } - - if (ret < 0) { - dev_err(&data->client->dev, "Error writing reg_int_en_1\n"); - return ret; - } - - return 0; -} - static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val, int *val2) { @@ -547,6 +416,105 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) } #endif +static const struct bmc150_accel_interrupt_info { + u8 map_reg; + u8 map_bitmask; + u8 en_reg; + u8 en_bitmask; +} bmc150_accel_interrupts[] = { + { /* data ready interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_1, + .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA, + .en_reg = BMC150_ACCEL_REG_INT_EN_1, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_DATA_EN, + }, + { /* motion interrupt */ + .map_reg = BMC150_ACCEL_REG_INT_MAP_0, + .map_bitmask = BMC150_ACCEL_INT_MAP_0_BIT_SLOPE, + .en_reg = BMC150_ACCEL_REG_INT_EN_0, + .en_bitmask = BMC150_ACCEL_INT_EN_BIT_SLP_X | + BMC150_ACCEL_INT_EN_BIT_SLP_Y | + BMC150_ACCEL_INT_EN_BIT_SLP_Z + }, +}; + +static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, + const struct bmc150_accel_interrupt_info *info, + bool state) +{ + int ret; + + /* + * We will expect the enable and disable to do operation in + * in reverse order. This will happen here anyway as our + * resume operation uses sync mode runtime pm calls, the + * suspend operation will be delayed by autosuspend delay + * So the disable operation will still happen in reverse of + * enable operation. When runtime pm is disabled the mode + * is always on so sequence doesn't matter + */ + ret = bmc150_accel_set_power_state(data, state); + if (ret < 0) + return ret; + + /* map the interrupt to the appropriate pins */ + ret = i2c_smbus_read_byte_data(data->client, info->map_reg); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_map\n"); + goto out_fix_power_state; + } + if (state) + ret |= info->map_bitmask; + else + ret &= ~info->map_bitmask; + + ret = i2c_smbus_write_byte_data(data->client, info->map_reg, + ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_map\n"); + goto out_fix_power_state; + } + + /* enable/disable the interrupt */ + ret = i2c_smbus_read_byte_data(data->client, info->en_reg); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_int_en\n"); + goto out_fix_power_state; + } + + if (state) + ret |= info->en_bitmask; + else + ret &= ~info->en_bitmask; + + ret = i2c_smbus_write_byte_data(data->client, info->en_reg, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_en\n"); + goto out_fix_power_state; + } + + return 0; + +out_fix_power_state: + bmc150_accel_set_power_state(data, false); + return ret; +} + +static int bmc150_accel_setup_any_motion_interrupt( + struct bmc150_accel_data *data, + bool status) +{ + return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1], + status); +} + +static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data, + bool status) +{ + return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0], + status); +} + static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) { int ret, i; @@ -791,25 +759,8 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev, return 0; } - /* - * We will expect the enable and disable to do operation in - * in reverse order. This will happen here anyway as our - * resume operation uses sync mode runtime pm calls, the - * suspend operation will be delayed by autosuspend delay - * So the disable operation will still happen in reverse of - * enable operation. When runtime pm is disabled the mode - * is always on so sequence doesn't matter - */ - - ret = bmc150_accel_set_power_state(data, state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } - ret = bmc150_accel_setup_any_motion_interrupt(data, state); if (ret < 0) { - bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); return ret; } @@ -1039,16 +990,6 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, return 0; } - /* - * Refer to comment in bmc150_accel_write_event_config for - * enable/disable operation order - */ - ret = bmc150_accel_set_power_state(data, state); - if (ret < 0) { - mutex_unlock(&data->mutex); - return ret; - } - if (data->motion_trig == trig) { ret = bmc150_accel_update_slope(data); if (!ret) @@ -1058,7 +999,6 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, ret = bmc150_accel_setup_new_data_interrupt(data, state); } if (ret < 0) { - bmc150_accel_set_power_state(data, false); mutex_unlock(&data->mutex); return ret; } @@ -1244,6 +1184,20 @@ static int bmc150_accel_probe(struct i2c_client *client, if (ret) return ret; + /* + * Set latched mode interrupt. While certain interrupts are + * non-latched regardless of this settings (e.g. new data) we + * want to use latch mode when we can to prevent interrupt + * flooding. + */ + ret = i2c_smbus_write_byte_data(data->client, + BMC150_ACCEL_REG_INT_RST_LATCH, + BMC150_ACCEL_INT_MODE_LATCH_RESET); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_int_rst_latch\n"); + return ret; + } + data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, -- cgit v1.2.3 From 14ee64f438b8e85d1c78939d301956d9a775cc9a Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Sat, 31 Jan 2015 02:00:05 +0200 Subject: iio: bmc150: exit early if event / trigger state is not changed Previous of this patch the check was only done if we enabled the event and it was already enabled. We can do the same if the event is disabled and we want to disable it. The patch also adds the same check on the trigger code. Signed-off-by: Octavian Purdila Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 087392514e54..f040f405d826 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -748,7 +748,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev, struct bmc150_accel_data *data = iio_priv(indio_dev); int ret; - if (state && data->ev_enable_state) + if (state == data->ev_enable_state) return 0; mutex_lock(&data->mutex); @@ -984,6 +984,18 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, mutex_lock(&data->mutex); + if (data->motion_trig == trig) { + if (data->motion_trigger_on == state) { + mutex_unlock(&data->mutex); + return 0; + } + } else { + if (data->dready_trigger_on == state) { + mutex_unlock(&data->mutex); + return 0; + } + } + if (!state && data->ev_enable_state && data->motion_trigger_on) { data->motion_trigger_on = false; mutex_unlock(&data->mutex); -- cgit v1.2.3 From 98a3d2e1d57611840b0c252e718f1fc7fb32b381 Mon Sep 17 00:00:00 2001 From: Tolga Ceylan Date: Sun, 8 Feb 2015 00:04:53 -0800 Subject: Staging:iio:hmc5843:Coding Style Correction Indentation corrections in struct initializations and one line over 80 characters split into two lines Signed-off-by: Tolga Ceylan Signed-off-by: Jonathan Cameron --- drivers/staging/iio/magnetometer/hmc5843_i2c.c | 34 +++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/magnetometer/hmc5843_i2c.c b/drivers/staging/iio/magnetometer/hmc5843_i2c.c index 6acd614cdbc6..e221a58a7673 100644 --- a/drivers/staging/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/staging/iio/magnetometer/hmc5843_i2c.c @@ -19,49 +19,49 @@ #include "hmc5843.h" static const struct regmap_range hmc5843_readable_ranges[] = { - regmap_reg_range(0, HMC5843_ID_END), + regmap_reg_range(0, HMC5843_ID_END), }; static struct regmap_access_table hmc5843_readable_table = { - .yes_ranges = hmc5843_readable_ranges, - .n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges), + .yes_ranges = hmc5843_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges), }; static const struct regmap_range hmc5843_writable_ranges[] = { - regmap_reg_range(0, HMC5843_MODE_REG), + regmap_reg_range(0, HMC5843_MODE_REG), }; static struct regmap_access_table hmc5843_writable_table = { - .yes_ranges = hmc5843_writable_ranges, - .n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges), + .yes_ranges = hmc5843_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges), }; static const struct regmap_range hmc5843_volatile_ranges[] = { - regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG), + regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG), }; static struct regmap_access_table hmc5843_volatile_table = { - .yes_ranges = hmc5843_volatile_ranges, - .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), + .yes_ranges = hmc5843_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), }; static struct regmap_config hmc5843_i2c_regmap_config = { - .reg_bits = 8, - .val_bits = 8, + .reg_bits = 8, + .val_bits = 8, - .rd_table = &hmc5843_readable_table, - .wr_table = &hmc5843_writable_table, - .volatile_table = &hmc5843_volatile_table, + .rd_table = &hmc5843_readable_table, + .wr_table = &hmc5843_writable_table, + .volatile_table = &hmc5843_volatile_table, - .cache_type = REGCACHE_RBTREE, + .cache_type = REGCACHE_RBTREE, }; static int hmc5843_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { return hmc5843_common_probe(&client->dev, - devm_regmap_init_i2c(client, &hmc5843_i2c_regmap_config), - id->driver_data); + devm_regmap_init_i2c(client, &hmc5843_i2c_regmap_config), + id->driver_data); } static int hmc5843_i2c_remove(struct i2c_client *client) -- cgit v1.2.3 From c726aadd731de7b3cd2a0c2ceb2cc5ce9745c5ad Mon Sep 17 00:00:00 2001 From: Tolga Ceylan Date: Sat, 7 Feb 2015 23:40:33 -0800 Subject: Staging:iio:ade7854 Coding style correction Line over 80 characters corrected Signed-off-by: Tolga Ceylan Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7854-i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index 5b33c7f1aa91..5d0671a198fe 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -195,7 +195,8 @@ static int ade7854_i2c_read_reg_32(struct device *dev, if (ret) goto out; - *val = (st->rx[0] << 24) | (st->rx[1] << 16) | (st->rx[2] << 8) | st->rx[3]; + *val = (st->rx[0] << 24) | (st->rx[1] << 16) | + (st->rx[2] << 8) | st->rx[3]; out: mutex_unlock(&st->buf_lock); return ret; -- cgit v1.2.3 From 31a3dda6489dd68552e1e6af56abcf65405d6b5c Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Tue, 27 Jan 2015 23:22:34 +0100 Subject: staging: iio: resolver: ad2s1210: Change type in printf format string Wrong type in printf format string, requires 'int' but the argument type is 'unsigned int' This was found using a static code analysis program called cppcheck Signed-off-by: Rickard Strandqvist Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1210.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index b4c14ba5fdee..a8ecf87ef4a9 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -198,7 +198,7 @@ static ssize_t ad2s1210_show_fclkin(struct device *dev, { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - return sprintf(buf, "%d\n", st->fclkin); + return sprintf(buf, "%u\n", st->fclkin); } static ssize_t ad2s1210_store_fclkin(struct device *dev, @@ -237,7 +237,7 @@ static ssize_t ad2s1210_show_fexcit(struct device *dev, { struct ad2s1210_state *st = iio_priv(dev_to_iio_dev(dev)); - return sprintf(buf, "%d\n", st->fexcit); + return sprintf(buf, "%u\n", st->fexcit); } static ssize_t ad2s1210_store_fexcit(struct device *dev, -- cgit v1.2.3 From e257a16e680a27ddc3dcbfc9fd39ad7f9d7ea135 Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Tue, 27 Jan 2015 23:23:33 +0100 Subject: staging: iio: adc: mxs-lradc: Change type in printf format string Wrong type in printf format string, requires 'int' but the argument type is 'unsigned int' This was found using a static code analysis program called cppcheck Signed-off-by: Rickard Strandqvist Reviewed-by: Marek Vasut Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index d9d6fad7cb00..d5f8ea96f4bc 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1008,7 +1008,7 @@ static ssize_t mxs_lradc_show_scale_available_ch(struct device *dev, int i, len = 0; for (i = 0; i < ARRAY_SIZE(lradc->scale_avail[ch]); i++) - len += sprintf(buf + len, "%d.%09u ", + len += sprintf(buf + len, "%u.%09u ", lradc->scale_avail[ch][i].integer, lradc->scale_avail[ch][i].nano); -- cgit v1.2.3 From 9f59f970ec2128522a98f6826350a3bfbaf70163 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 11 Feb 2015 14:47:27 +0530 Subject: iio: gp2ap020a00f: Use put_unaligned_le32 This patch introduces the use of function put_unaligned_le32. This is done using Coccinelle and semantic patch used is as follows: @@ identifier tmp; expression ptr; expression y,e; type T; @@ - tmp = cpu_to_le32(y); <+... when != tmp - memcpy(ptr, (T)&tmp, ...); + put_unaligned_le32(y,ptr); ...+> ? tmp = e @@ type T; identifier tmp; @@ - T tmp; ...when != tmp Signed-off-by: Vaishali Thakkar Signed-off-by: Jonathan Cameron --- drivers/iio/light/gp2ap020a00f.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index 221ed16de1f7..32b6449833fa 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -966,7 +967,6 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data) struct iio_dev *indio_dev = pf->indio_dev; struct gp2ap020a00f_data *priv = iio_priv(indio_dev); size_t d_size = 0; - __le32 light_lux; int i, out_val, ret; for_each_set_bit(i, indio_dev->active_scan_mask, @@ -981,8 +981,8 @@ static irqreturn_t gp2ap020a00f_trigger_handler(int irq, void *data) i == GP2AP020A00F_SCAN_MODE_LIGHT_IR) { out_val = le16_to_cpup((__le16 *)&priv->buffer[d_size]); gp2ap020a00f_output_to_lux(priv, &out_val); - light_lux = cpu_to_le32(out_val); - memcpy(&priv->buffer[d_size], (u8 *)&light_lux, 4); + + put_unaligned_le32(out_val, &priv->buffer[d_size]); d_size += 4; } else { d_size += 2; -- cgit v1.2.3 From 1a179a14d152467da7038205af52883f38973afe Mon Sep 17 00:00:00 2001 From: Rickard Strandqvist Date: Sun, 8 Feb 2015 19:22:54 +0100 Subject: staging: iio: trigger: iio-trig-periodic-rtc: Change frequency type to unsigned int Change struct iio_prtc_trigger_info frequency type from int to unsigned int. Since it is always treated as such in the driver so they type should probably reflect this. Signed-off-by: Rickard Strandqvist Signed-off-by: Jonathan Cameron --- drivers/staging/iio/trigger/iio-trig-periodic-rtc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index a24caf73ae0b..89df1d32874d 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -24,7 +24,7 @@ static DEFINE_MUTEX(iio_prtc_trigger_list_lock); struct iio_prtc_trigger_info { struct rtc_device *rtc; - int frequency; + unsigned int frequency; struct rtc_task task; bool state; }; @@ -36,7 +36,7 @@ static int iio_trig_periodic_rtc_set_state(struct iio_trigger *trig, bool state) if (trig_info->frequency == 0 && state) return -EINVAL; - dev_dbg(&trig_info->rtc->dev, "trigger frequency is %d\n", + dev_dbg(&trig_info->rtc->dev, "trigger frequency is %u\n", trig_info->frequency); ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, state); if (ret == 0) @@ -62,10 +62,10 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct iio_prtc_trigger_info *trig_info = iio_trigger_get_drvdata(trig); - int val; + unsigned int val; int ret; - ret = kstrtoint(buf, 10, &val); + ret = kstrtouint(buf, 10, &val); if (ret) goto error_ret; @@ -74,10 +74,8 @@ static ssize_t iio_trig_periodic_write_freq(struct device *dev, if (ret == 0 && trig_info->state && trig_info->frequency == 0) ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 1); - } else if (val == 0) { - ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 0); } else - ret = -EINVAL; + ret = rtc_irq_set_state(trig_info->rtc, &trig_info->task, 0); if (ret) goto error_ret; -- cgit v1.2.3 From b457f53a2afa7de3cecdec1772fbd522b98afc49 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Wed, 18 Feb 2015 13:47:11 +0100 Subject: iio: improve usage of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for outputs. Signed-off-by: Uwe Kleine-König Reviewed-by: Linus Walleij Reviewed-by: Alexandre Courbot Reviewed-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 6 +----- drivers/iio/accel/kxcjk-1013.c | 6 +----- drivers/iio/accel/mma9551.c | 7 ++----- drivers/iio/accel/mma9553.c | 6 +----- drivers/iio/gyro/bmg160.c | 6 +----- drivers/iio/imu/kmx61.c | 6 +----- drivers/iio/proximity/sx9500.c | 6 +----- 7 files changed, 8 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index f040f405d826..46ac9659e2aa 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -1125,16 +1125,12 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client, dev = &client->dev; /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0); + gpio = devm_gpiod_get_index(dev, BMC150_ACCEL_GPIO_NAME, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "Failed: gpio get index\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 567de269cc00..a98b5d212fb3 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1169,16 +1169,12 @@ static int kxcjk1013_gpio_probe(struct i2c_client *client, dev = &client->dev; /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0); + gpio = devm_gpiod_get_index(dev, "kxcjk1013_int", 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 46c38351c6a3..1277f407cd12 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -418,16 +418,13 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev) struct device *dev = &data->client->dev; for (i = 0; i < MMA9551_GPIO_COUNT; i++) { - gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i); + gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i, + GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - data->irqs[i] = gpiod_to_irq(gpio); ret = devm_request_threaded_irq(dev, data->irqs[i], NULL, mma9551_event_handler, diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c index d23ebf192f63..2df1af7d43fc 100644 --- a/drivers/iio/accel/mma9553.c +++ b/drivers/iio/accel/mma9553.c @@ -1109,16 +1109,12 @@ static int mma9553_gpio_probe(struct i2c_client *client) dev = &client->dev; /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0); + gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c index 60451b328242..56d68e1d0987 100644 --- a/drivers/iio/gyro/bmg160.c +++ b/drivers/iio/gyro/bmg160.c @@ -1001,16 +1001,12 @@ static int bmg160_gpio_probe(struct i2c_client *client, dev = &client->dev; /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0); + gpio = devm_gpiod_get_index(dev, BMG160_GPIO_NAME, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c index 32e5f96a6477..75ab70100015 100644 --- a/drivers/iio/imu/kmx61.c +++ b/drivers/iio/imu/kmx61.c @@ -1255,16 +1255,12 @@ static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data) dev = &client->dev; /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0); + gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 74dff4e4a11a..0b4d79490b05 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -618,16 +618,12 @@ static int sx9500_gpio_probe(struct i2c_client *client, dev = &client->dev; /* data ready gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0); + gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); -- cgit v1.2.3 From 15313309cbfe0ebba7f660677d2625abe27fb077 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 24 Feb 2015 10:41:48 +0100 Subject: staging:iio:hmc5843: Constify register tables and struct regmap_config The regmap_access_table and regmap_config structures may be const because they are not modified by the driver and regmap_init() accepts pointer to const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- drivers/staging/iio/magnetometer/hmc5843_i2c.c | 8 ++++---- drivers/staging/iio/magnetometer/hmc5843_spi.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/magnetometer/hmc5843_i2c.c b/drivers/staging/iio/magnetometer/hmc5843_i2c.c index e221a58a7673..2beff253bd0d 100644 --- a/drivers/staging/iio/magnetometer/hmc5843_i2c.c +++ b/drivers/staging/iio/magnetometer/hmc5843_i2c.c @@ -22,7 +22,7 @@ static const struct regmap_range hmc5843_readable_ranges[] = { regmap_reg_range(0, HMC5843_ID_END), }; -static struct regmap_access_table hmc5843_readable_table = { +static const struct regmap_access_table hmc5843_readable_table = { .yes_ranges = hmc5843_readable_ranges, .n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges), }; @@ -31,7 +31,7 @@ static const struct regmap_range hmc5843_writable_ranges[] = { regmap_reg_range(0, HMC5843_MODE_REG), }; -static struct regmap_access_table hmc5843_writable_table = { +static const struct regmap_access_table hmc5843_writable_table = { .yes_ranges = hmc5843_writable_ranges, .n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges), }; @@ -40,12 +40,12 @@ static const struct regmap_range hmc5843_volatile_ranges[] = { regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG), }; -static struct regmap_access_table hmc5843_volatile_table = { +static const struct regmap_access_table hmc5843_volatile_table = { .yes_ranges = hmc5843_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), }; -static struct regmap_config hmc5843_i2c_regmap_config = { +static const struct regmap_config hmc5843_i2c_regmap_config = { .reg_bits = 8, .val_bits = 8, diff --git a/drivers/staging/iio/magnetometer/hmc5843_spi.c b/drivers/staging/iio/magnetometer/hmc5843_spi.c index 98c4b57101c9..8e658f736e1f 100644 --- a/drivers/staging/iio/magnetometer/hmc5843_spi.c +++ b/drivers/staging/iio/magnetometer/hmc5843_spi.c @@ -19,7 +19,7 @@ static const struct regmap_range hmc5843_readable_ranges[] = { regmap_reg_range(0, HMC5843_ID_END), }; -static struct regmap_access_table hmc5843_readable_table = { +static const struct regmap_access_table hmc5843_readable_table = { .yes_ranges = hmc5843_readable_ranges, .n_yes_ranges = ARRAY_SIZE(hmc5843_readable_ranges), }; @@ -28,7 +28,7 @@ static const struct regmap_range hmc5843_writable_ranges[] = { regmap_reg_range(0, HMC5843_MODE_REG), }; -static struct regmap_access_table hmc5843_writable_table = { +static const struct regmap_access_table hmc5843_writable_table = { .yes_ranges = hmc5843_writable_ranges, .n_yes_ranges = ARRAY_SIZE(hmc5843_writable_ranges), }; @@ -37,12 +37,12 @@ static const struct regmap_range hmc5843_volatile_ranges[] = { regmap_reg_range(HMC5843_DATA_OUT_MSB_REGS, HMC5843_STATUS_REG), }; -static struct regmap_access_table hmc5843_volatile_table = { +static const struct regmap_access_table hmc5843_volatile_table = { .yes_ranges = hmc5843_volatile_ranges, .n_yes_ranges = ARRAY_SIZE(hmc5843_volatile_ranges), }; -static struct regmap_config hmc5843_spi_regmap_config = { +static const struct regmap_config hmc5843_spi_regmap_config = { .reg_bits = 8, .val_bits = 8, -- cgit v1.2.3 From 9820d88332095bc4b5ef67799e149472fcb9aa40 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 24 Feb 2015 10:41:49 +0100 Subject: iio: jsa1212: Constify struct regmap_config The regmap_config struct may be const because it is not modified by the driver and regmap_init() accepts pointer to const. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Jonathan Cameron --- drivers/iio/light/jsa1212.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c index 29de7e7d9562..3a3af89beaf9 100644 --- a/drivers/iio/light/jsa1212.c +++ b/drivers/iio/light/jsa1212.c @@ -308,7 +308,7 @@ static bool jsa1212_is_volatile_reg(struct device *dev, unsigned int reg) } } -static struct regmap_config jsa1212_regmap_config = { +static const struct regmap_config jsa1212_regmap_config = { .name = JSA1212_REGMAP_NAME, .reg_bits = 8, .val_bits = 8, -- cgit v1.2.3 From a35c5d1aa96aa6cc70e91786cbe9be4db23f8f4a Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 30 Jan 2015 14:25:45 -0800 Subject: iio: imu: inv_mpu6050: Create mux clients for ACPI This is a follow up patches after adding i2c mux adapter for bypass mode. Potentially many different types of sensor can be attached to INVMPU6XXX device, which can be connected to main cpu i2c bus in bypass mode. Why do we need this? The system ACPI table entry will consist of only one device for INV6XXX, assuming that this driver will handle all connected sensors. That is not true for the Linux driver. There are bunch of IIO drivers for each sensors, hence we created a mux on this device. So to load these additional drivers, we need to create i2c devices for them in this driver using this mux adapter. There are multiple options: 1. Use the auto detect feature, this needs a new i2c class for the adapter as the existing HWMON class is not acceptable. Also the autodetect has overhead of executing detect method for each matching class of adapters. This is a simple implementation. This option was previously submitted with not a happy feedback. 2. Option is use ACPI magic and parse the configuration data. What we need to create a i2c device at a minimum is address and a name. Address can be obtained for secondary device in more or less in a standard way from using _CRS element. But there is no name. To get name we need to process proprietary vendor data. Not having name is not fun, as you have to create device using the device name of INVN6XXXX, respecting driver duplicate name space restriction. Also each client driver needs to have this name in the id table. Since multiple driver can be loaded, the driver should be able to detect its presence and gracefully exit for the other client driver to take it over. So we use two step process: - Use DMI to id platform and parse propritery data. This is not uncommon for many x86 platform specific driver. We will get both name and address. The change created necessary infrastructure to add more properitery vendor data parsing. - If DMI match fails, then create device on INV6XXX-client (we can't create with same name as INV6XXX as it will cause duplicate name and driver model will reject.) With this each client sensor driver which needs to get attached via INV6XXXX, need this name in the id table and detect the physical presence of sensor in probe and exit if not found. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/imu/inv_mpu6050/Makefile | 2 +- drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c | 211 +++++++++++++++++++++++++++++ drivers/iio/imu/inv_mpu6050/inv_mpu_core.c | 7 + drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h | 3 + 4 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c (limited to 'drivers') diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile index 3a677c778afb..f566f6a7b3a9 100644 --- a/drivers/iio/imu/inv_mpu6050/Makefile +++ b/drivers/iio/imu/inv_mpu6050/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o -inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o +inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o inv_mpu_acpi.o diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c new file mode 100644 index 000000000000..1c982a56acd5 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -0,0 +1,211 @@ +/* + * inv_mpu_acpi: ACPI processing for creating client devices + * Copyright (c) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifdef CONFIG_ACPI + +#include +#include +#include +#include +#include "inv_mpu_iio.h" + +enum inv_mpu_product_name { + INV_MPU_NOT_MATCHED, + INV_MPU_ASUS_T100TA, +}; + +static enum inv_mpu_product_name matched_product_name; + +static int __init asus_t100_matched(const struct dmi_system_id *d) +{ + matched_product_name = INV_MPU_ASUS_T100TA; + + return 0; +} + +static const struct dmi_system_id inv_mpu_dev_list[] = { + { + .callback = asus_t100_matched, + .ident = "Asus Transformer Book T100", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC"), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"), + }, + }, + /* Add more matching tables here..*/ + {} +}; + +static int asus_acpi_get_sensor_info(struct acpi_device *adev, + struct i2c_client *client, + struct i2c_board_info *info) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + int i; + acpi_status status; + union acpi_object *cpm; + + status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; + + cpm = buffer.pointer; + for (i = 0; i < cpm->package.count; ++i) { + union acpi_object *elem; + int j; + + elem = &(cpm->package.elements[i]); + for (j = 0; j < elem->package.count; ++j) { + union acpi_object *sub_elem; + + sub_elem = &(elem->package.elements[j]); + if (sub_elem->type == ACPI_TYPE_STRING) + strlcpy(info->type, sub_elem->string.pointer, + sizeof(info->type)); + else if (sub_elem->type == ACPI_TYPE_INTEGER) { + if (sub_elem->integer.value != client->addr) { + info->addr = sub_elem->integer.value; + break; /* Not a MPU6500 primary */ + } + } + } + } + + kfree(buffer.pointer); + + return cpm->package.count; +} + +static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data) +{ + u32 *addr = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_i2c_serialbus *sb; + + sb = &ares->data.i2c_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + if (*addr) + *addr |= (sb->slave_address << 16); + else + *addr = sb->slave_address; + } + } + + /* Tell the ACPI core that we already copied this address */ + return 1; +} + +static int inv_mpu_process_acpi_config(struct i2c_client *client, + unsigned short *primary_addr, + unsigned short *secondary_addr) +{ + const struct acpi_device_id *id; + struct acpi_device *adev; + u32 i2c_addr = 0; + LIST_HEAD(resources); + int ret; + + id = acpi_match_device(client->dev.driver->acpi_match_table, + &client->dev); + if (!id) + return -ENODEV; + + adev = ACPI_COMPANION(&client->dev); + if (!adev) + return -ENODEV; + + ret = acpi_dev_get_resources(adev, &resources, + acpi_i2c_check_resource, &i2c_addr); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&resources); + *primary_addr = i2c_addr & 0x0000ffff; + *secondary_addr = (i2c_addr & 0xffff0000) >> 16; + + return 0; +} + +int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) +{ + + st->mux_client = NULL; + if (ACPI_HANDLE(&st->client->dev)) { + struct i2c_board_info info; + struct acpi_device *adev; + int ret = -1; + + adev = ACPI_COMPANION(&st->client->dev); + memset(&info, 0, sizeof(info)); + + dmi_check_system(inv_mpu_dev_list); + switch (matched_product_name) { + case INV_MPU_ASUS_T100TA: + ret = asus_acpi_get_sensor_info(adev, st->client, + &info); + break; + /* Add more matched product processing here */ + default: + break; + } + + if (ret < 0) { + /* No matching DMI, so create device on INV6XX type */ + unsigned short primary, secondary; + + ret = inv_mpu_process_acpi_config(st->client, &primary, + &secondary); + if (!ret && secondary) { + char *name; + + info.addr = secondary; + strlcpy(info.type, dev_name(&adev->dev), + sizeof(info.type)); + name = strchr(info.type, ':'); + if (name) + *name = '\0'; + strlcat(info.type, "-client", + sizeof(info.type)); + } else + return 0; /* no secondary addr, which is OK */ + } + st->mux_client = i2c_new_device(st->mux_adapter, &info); + if (!st->mux_client) + return -ENODEV; + + } + + return 0; +} + +void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) +{ + if (st->mux_client) + i2c_unregister_device(st->mux_client); +} +#else + +#include "inv_mpu_iio.h" + +int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st) +{ + return 0; +} + +void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st) +{ +} +#endif diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index f73e60b7a796..c42e08ee92da 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -821,8 +821,14 @@ static int inv_mpu_probe(struct i2c_client *client, goto out_unreg_device; } + result = inv_mpu_acpi_create_mux_client(st); + if (result) + goto out_del_mux; + return 0; +out_del_mux: + i2c_del_mux_adapter(st->mux_adapter); out_unreg_device: iio_device_unregister(indio_dev); out_remove_trigger: @@ -837,6 +843,7 @@ static int inv_mpu_remove(struct i2c_client *client) struct iio_dev *indio_dev = i2c_get_clientdata(client); struct inv_mpu6050_state *st = iio_priv(indio_dev); + inv_mpu_acpi_delete_mux_client(st); i2c_del_mux_adapter(st->mux_adapter); iio_device_unregister(indio_dev); inv_mpu6050_remove_trigger(st); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index aa837de57079..db0a4a2758ab 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -121,6 +121,7 @@ struct inv_mpu6050_state { spinlock_t time_stamp_lock; struct i2c_client *client; struct i2c_adapter *mux_adapter; + struct i2c_client *mux_client; unsigned int powerup_count; struct inv_mpu6050_platform_data plat_data; DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); @@ -251,3 +252,5 @@ int inv_reset_fifo(struct iio_dev *indio_dev); int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask); int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 val); int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on); +int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state *st); +void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state *st); -- cgit v1.2.3 From 1672d933af196f69a69af8f1fe616750f7089592 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 4 Mar 2015 12:44:33 +0900 Subject: iio:adc: Fix typo in MODULE_DESCRIPTION in ad7793.c This patch fix spelling typo in MODULE_DESCRIPTION Signed-off-by: Masanari Iida Signed-off-by: Jonathan Cameron --- drivers/iio/adc/ad7793.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index 4dddeabdfbb0..b84922a4b32e 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -861,5 +861,5 @@ static struct spi_driver ad7793_driver = { module_spi_driver(ad7793_driver); MODULE_AUTHOR("Michael Hennerich "); -MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs"); +MODULE_DESCRIPTION("Analog Devices AD7793 and similar ADCs"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From b5c4437872de508073355e927b1fcdba4980cba7 Mon Sep 17 00:00:00 2001 From: Tolga Ceylan Date: Sat, 14 Feb 2015 20:32:43 -0800 Subject: Staging: iio: meter: ade7854-i2c: code style improvements Code reformatting based on checkpatch.pl with --strict: Alignment should match open paranthesis cases corrected Signed-off-by: Tolga Ceylan Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7854-i2c.c | 34 ++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index 5d0671a198fe..5e6fbe4c976a 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -16,8 +16,8 @@ #include "ade7854.h" static int ade7854_i2c_write_reg_8(struct device *dev, - u16 reg_address, - u8 value) + u16 reg_address, + u8 value) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -35,8 +35,8 @@ static int ade7854_i2c_write_reg_8(struct device *dev, } static int ade7854_i2c_write_reg_16(struct device *dev, - u16 reg_address, - u16 value) + u16 reg_address, + u16 value) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -55,8 +55,8 @@ static int ade7854_i2c_write_reg_16(struct device *dev, } static int ade7854_i2c_write_reg_24(struct device *dev, - u16 reg_address, - u32 value) + u16 reg_address, + u32 value) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -76,8 +76,8 @@ static int ade7854_i2c_write_reg_24(struct device *dev, } static int ade7854_i2c_write_reg_32(struct device *dev, - u16 reg_address, - u32 value) + u16 reg_address, + u32 value) { int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); @@ -98,8 +98,8 @@ static int ade7854_i2c_write_reg_32(struct device *dev, } static int ade7854_i2c_read_reg_8(struct device *dev, - u16 reg_address, - u8 *val) + u16 reg_address, + u8 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -124,8 +124,8 @@ out: } static int ade7854_i2c_read_reg_16(struct device *dev, - u16 reg_address, - u16 *val) + u16 reg_address, + u16 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -150,8 +150,8 @@ out: } static int ade7854_i2c_read_reg_24(struct device *dev, - u16 reg_address, - u32 *val) + u16 reg_address, + u32 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -176,8 +176,8 @@ out: } static int ade7854_i2c_read_reg_32(struct device *dev, - u16 reg_address, - u32 *val) + u16 reg_address, + u32 *val) { struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ade7854_state *st = iio_priv(indio_dev); @@ -203,7 +203,7 @@ out: } static int ade7854_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { int ret; struct ade7854_state *st; -- cgit v1.2.3 From 21bd23ea128d083bf8a4fd570a66a128d58465b5 Mon Sep 17 00:00:00 2001 From: Tolga Ceylan Date: Sat, 14 Feb 2015 20:32:45 -0800 Subject: Staging: iio: meter: ade7854-i2c: code style improvements Code reformatting based on checkpatch.pl with --strict: Comparison to NULL rewritten as !indio_dev Signed-off-by: Tolga Ceylan Signed-off-by: Jonathan Cameron --- drivers/staging/iio/meter/ade7854-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/meter/ade7854-i2c.c b/drivers/staging/iio/meter/ade7854-i2c.c index 5e6fbe4c976a..4e7a3829ea55 100644 --- a/drivers/staging/iio/meter/ade7854-i2c.c +++ b/drivers/staging/iio/meter/ade7854-i2c.c @@ -210,7 +210,7 @@ static int ade7854_i2c_probe(struct i2c_client *client, struct iio_dev *indio_dev; indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); - if (indio_dev == NULL) + if (!indio_dev) return -ENOMEM; st = iio_priv(indio_dev); i2c_set_clientdata(client, indio_dev); -- cgit v1.2.3 From 1ec28ce66aa4b0f7aaab0d496ee293ff2a52dd20 Mon Sep 17 00:00:00 2001 From: Kevin Tsai Date: Thu, 19 Feb 2015 15:02:51 -0800 Subject: iio: light: Added PM support for Capella CM3232 ambient light sensor driver. Added Power Management Support. Signed-off-by: Kevin Tsai Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm3232.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers') diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c index 90e3519a91de..39c8d99cc48e 100644 --- a/drivers/iio/light/cm3232.c +++ b/drivers/iio/light/cm3232.c @@ -378,6 +378,39 @@ static const struct i2c_device_id cm3232_id[] = { {} }; +#ifdef CONFIG_PM_SLEEP +static int cm3232_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct cm3232_chip *chip = iio_priv(indio_dev); + struct i2c_client *client = chip->client; + int ret; + + chip->regs_cmd |= CM3232_CMD_ALS_DISABLE; + ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD, + chip->regs_cmd); + + return ret; +} + +static int cm3232_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct cm3232_chip *chip = iio_priv(indio_dev); + struct i2c_client *client = chip->client; + int ret; + + chip->regs_cmd &= ~CM3232_CMD_ALS_DISABLE; + ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD, + chip->regs_cmd | CM3232_CMD_ALS_RESET); + + return ret; +} + +static const struct dev_pm_ops cm3232_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(cm3232_suspend, cm3232_resume)}; +#endif + MODULE_DEVICE_TABLE(i2c, cm3232_id); static const struct of_device_id cm3232_of_match[] = { @@ -390,6 +423,9 @@ static struct i2c_driver cm3232_driver = { .name = "cm3232", .owner = THIS_MODULE, .of_match_table = of_match_ptr(cm3232_of_match), +#ifdef CONFIG_PM_SLEEP + .pm = &cm3232_pm_ops, +#endif }, .id_table = cm3232_id, .probe = cm3232_probe, -- cgit v1.2.3 From debf6d843eaa3622786c45eb6edbc46f38f31a90 Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Mon, 2 Mar 2015 12:39:12 +0200 Subject: iio: accel: mma9551: Check gpiod_to_irq return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value of gpiod_to_irq should be checked before giving it to devm_request_threaded_irq in order to not pass an error code in case it fails. Signed-off-by: Roberta Dobrescu Reviewed-by: Vlad Dogaru Acked-by: Uwe Kleine-König Signed-off-by: Jonathan Cameron --- drivers/iio/accel/mma9551.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c index 1277f407cd12..7db7cc0bf362 100644 --- a/drivers/iio/accel/mma9551.c +++ b/drivers/iio/accel/mma9551.c @@ -425,7 +425,11 @@ static int mma9551_gpio_probe(struct iio_dev *indio_dev) return PTR_ERR(gpio); } - data->irqs[i] = gpiod_to_irq(gpio); + ret = gpiod_to_irq(gpio); + if (ret < 0) + return ret; + + data->irqs[i] = ret; ret = devm_request_threaded_irq(dev, data->irqs[i], NULL, mma9551_event_handler, IRQF_TRIGGER_RISING | IRQF_ONESHOT, -- cgit v1.2.3 From 60d3e3bbd5992bb4478f9f99a4e4c5748a1a1ba7 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 24 Feb 2015 13:24:41 +1100 Subject: iio: gyro: itg3200: add suspend/resume support. Unless we put the device to sleep when not it use, it wastes 6mA. If the device is asleep on probe, the 'id' register sometimes mis-reads - so reset first. If the device responds at all a command sent to the address, it is almost certainly the correct device already. Acked-by: Manuel Stahl Acked-by: Hartmut Knaack Signed-off-by: NeilBrown Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/itg3200_core.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 6a8020d48140..f0fd94055d88 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -223,6 +223,10 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev) int ret; u8 val; + ret = itg3200_reset(indio_dev); + if (ret) + goto err_ret; + ret = itg3200_read_reg_8(indio_dev, ITG3200_REG_ADDRESS, &val); if (ret) goto err_ret; @@ -233,10 +237,6 @@ static int itg3200_initial_setup(struct iio_dev *indio_dev) goto err_ret; } - ret = itg3200_reset(indio_dev); - if (ret) - goto err_ret; - ret = itg3200_enable_full_scale(indio_dev); err_ret: return ret; @@ -351,6 +351,26 @@ static int itg3200_remove(struct i2c_client *client) return 0; } +static int __maybe_unused itg3200_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct itg3200 *st = iio_priv(indio_dev); + + dev_dbg(&st->i2c->dev, "suspend device"); + + return itg3200_write_reg_8(indio_dev, ITG3200_REG_POWER_MANAGEMENT, + ITG3200_SLEEP); +} + +static int __maybe_unused itg3200_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return itg3200_initial_setup(indio_dev); +} + +static SIMPLE_DEV_PM_OPS(itg3200_pm_ops, itg3200_suspend, itg3200_resume); + static const struct i2c_device_id itg3200_id[] = { { "itg3200", 0 }, { } @@ -361,6 +381,7 @@ static struct i2c_driver itg3200_driver = { .driver = { .owner = THIS_MODULE, .name = "itg3200", + .pm = &itg3200_pm_ops, }, .id_table = itg3200_id, .probe = itg3200_probe, -- cgit v1.2.3 From c7586584c6fd4212e3eb2e83e5cf3c043ddf72be Mon Sep 17 00:00:00 2001 From: Vianney le Clément de Saint-Marcq Date: Wed, 25 Feb 2015 16:55:06 +0100 Subject: iio: mlx90614: Refactor register symbols MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The defined registers only make sense when used for accessing RAM. Make MLX90614_OP_RAM part of the symbol definition to avoid accidental access to the wrong register. Signed-off-by: Vianney le Clément de Saint-Marcq Cc: Arnout Vandecappelle (Essensium/Mind) Signed-off-by: Jonathan Cameron --- drivers/iio/temperature/mlx90614.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/temperature/mlx90614.c b/drivers/iio/temperature/mlx90614.c index c8b6ac8b2d69..e2c6f1a0d27f 100644 --- a/drivers/iio/temperature/mlx90614.c +++ b/drivers/iio/temperature/mlx90614.c @@ -23,8 +23,8 @@ #define MLX90614_OP_RAM 0x00 /* RAM offsets with 16-bit data, MSB first */ -#define MLX90614_TA 0x06 /* ambient temperature */ -#define MLX90614_TOBJ1 0x07 /* object temperature */ +#define MLX90614_TA (MLX90614_OP_RAM | 0x06) /* ambient temperature */ +#define MLX90614_TOBJ1 (MLX90614_OP_RAM | 0x07) /* object 1 temperature */ struct mlx90614_data { struct i2c_client *client; @@ -42,13 +42,13 @@ static int mlx90614_read_raw(struct iio_dev *indio_dev, switch (channel->channel2) { case IIO_MOD_TEMP_AMBIENT: ret = i2c_smbus_read_word_data(data->client, - MLX90614_OP_RAM | MLX90614_TA); + MLX90614_TA); if (ret < 0) return ret; break; case IIO_MOD_TEMP_OBJECT: ret = i2c_smbus_read_word_data(data->client, - MLX90614_OP_RAM | MLX90614_TOBJ1); + MLX90614_TOBJ1); if (ret < 0) return ret; break; -- cgit v1.2.3 From 95763859c0205417cf94966f87c3839e54a8005d Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Thu, 26 Feb 2015 10:49:23 +0200 Subject: staging: iio: Documentation: iio_event_monitor: Include linux/iio/types.h By adding this line and installing the kernel headers with make headers_install, iio_event_monitor can be compiled without any hacks. Signed-off-by: Roberta Dobrescu Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Documentation/iio_event_monitor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c index 72c96aa6e992..019a6e5cdcd8 100644 --- a/drivers/staging/iio/Documentation/iio_event_monitor.c +++ b/drivers/staging/iio/Documentation/iio_event_monitor.c @@ -28,6 +28,7 @@ #include #include "iio_utils.h" #include +#include static const char * const iio_chan_type_name_spec[] = { [IIO_VOLTAGE] = "voltage", -- cgit v1.2.3 From bdcb31d048074d82ed7c50ed45f737d7637f1224 Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Thu, 26 Feb 2015 10:49:24 +0200 Subject: staging: iio: Documentation: Introduce iio_utils.c This patch removes inline functions from iio_utils.h in order to clean the code. iio_utils.c contains the implementation of the functions used by iio_event_monitor.c, lsiio.c or generic_buffer.c and iio_utils.h contains the declarations of these functions. Since iio_utils.h is modified, generic_buffer.c and iio_event_monitor.c must include stdlib.h. Signed-off-by: Roberta Dobrescu Signed-off-by: Jonathan Cameron --- drivers/staging/iio/Documentation/generic_buffer.c | 1 + .../staging/iio/Documentation/iio_event_monitor.c | 1 + drivers/staging/iio/Documentation/iio_utils.c | 651 ++++++++++++++++++++ drivers/staging/iio/Documentation/iio_utils.h | 664 +-------------------- 4 files changed, 679 insertions(+), 638 deletions(-) create mode 100644 drivers/staging/iio/Documentation/iio_utils.c (limited to 'drivers') diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c index de4647e2495e..01266c2556da 100644 --- a/drivers/staging/iio/Documentation/generic_buffer.c +++ b/drivers/staging/iio/Documentation/generic_buffer.c @@ -21,6 +21,7 @@ #define _GNU_SOURCE #include +#include #include #include #include diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c index 019a6e5cdcd8..f19cff19900e 100644 --- a/drivers/staging/iio/Documentation/iio_event_monitor.c +++ b/drivers/staging/iio/Documentation/iio_event_monitor.c @@ -19,6 +19,7 @@ #define _GNU_SOURCE #include +#include #include #include #include diff --git a/drivers/staging/iio/Documentation/iio_utils.c b/drivers/staging/iio/Documentation/iio_utils.c new file mode 100644 index 000000000000..aea928210187 --- /dev/null +++ b/drivers/staging/iio/Documentation/iio_utils.c @@ -0,0 +1,651 @@ +/* IIO - useful set of util functionality + * + * Copyright (c) 2008 Jonathan Cameron + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + +const char *iio_dir = "/sys/bus/iio/devices/"; + +/** + * iioutils_break_up_name() - extract generic name from full channel name + * @full_name: the full channel name + * @generic_name: the output generic channel name + **/ +int iioutils_break_up_name(const char *full_name, + char **generic_name) +{ + char *current; + char *w, *r; + char *working; + + current = strdup(full_name); + working = strtok(current, "_\0"); + w = working; + r = working; + + while (*r != '\0') { + if (!isdigit(*r)) { + *w = *r; + w++; + } + r++; + } + *w = '\0'; + *generic_name = strdup(working); + free(current); + + return 0; +} + +/** + * iioutils_get_type() - find and process _type attribute data + * @is_signed: output whether channel is signed + * @bytes: output how many bytes the channel storage occupies + * @mask: output a bit mask for the raw data + * @be: big endian + * @device_dir: the iio device directory + * @name: the channel name + * @generic_name: the channel type name + **/ +int iioutils_get_type(unsigned *is_signed, + unsigned *bytes, + unsigned *bits_used, + unsigned *shift, + uint64_t *mask, + unsigned *be, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; + char signchar, endianchar; + unsigned padint; + const struct dirent *ent; + + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_scan_el_dir; + } + ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + /* + * Do we allow devices to override a generic name with + * a specific one? + */ + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", filename); + ret = -errno; + goto error_free_filename; + } + + ret = fscanf(sysfsfp, + "%ce:%c%u/%u>>%u", + &endianchar, + &signchar, + bits_used, + &padint, shift); + if (ret < 0) { + printf("failed to pass scan type description\n"); + ret = -errno; + goto error_close_sysfsfp; + } + *be = (endianchar == 'b'); + *bytes = padint / 8; + if (*bits_used == 64) + *mask = ~0; + else + *mask = (1 << *bits_used) - 1; + if (signchar == 's') + *is_signed = 1; + else + *is_signed = 0; + fclose(sysfsfp); + free(filename); + + filename = 0; + sysfsfp = 0; + } +error_close_sysfsfp: + if (sysfsfp) + fclose(sysfsfp); +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_free_scan_el_dir: + free(scan_el_dir); +error_ret: + return ret; +} + +int iioutils_get_param_float(float *output, + const char *param_name, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *builtname, *builtname_generic; + char *filename = NULL; + const struct dirent *ent; + + ret = asprintf(&builtname, "%s_%s", name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname_generic, + "%s_%s", generic_name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + dp = opendir(device_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", device_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free_filename; + } + fscanf(sysfsfp, "%f", output); + break; + } +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_ret: + return ret; +} + +/** + * bsort_channel_array_by_index() - reorder so that the array is in index order + * + **/ + +void bsort_channel_array_by_index(struct iio_channel_info **ci_array, + int cnt) +{ + + struct iio_channel_info temp; + int x, y; + + for (x = 0; x < cnt; x++) + for (y = 0; y < (cnt - 1); y++) + if ((*ci_array)[y].index > (*ci_array)[y+1].index) { + temp = (*ci_array)[y + 1]; + (*ci_array)[y + 1] = (*ci_array)[y]; + (*ci_array)[y] = temp; + } +} + +/** + * build_channel_array() - function to figure out what channels are present + * @device_dir: the IIO device directory in sysfs + * @ + **/ +int build_channel_array(const char *device_dir, + struct iio_channel_info **ci_array, + int *counter) +{ + DIR *dp; + FILE *sysfsfp; + int count, i; + struct iio_channel_info *current; + int ret; + const struct dirent *ent; + char *scan_el_dir; + char *filename; + + *counter = 0; + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_name; + } + while (ent = readdir(dp), ent != NULL) + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_close_dir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + ret = -errno; + free(filename); + goto error_close_dir; + } + fscanf(sysfsfp, "%i", &ret); + if (ret == 1) + (*counter)++; + fclose(sysfsfp); + free(filename); + } + *ci_array = malloc(sizeof(**ci_array) * (*counter)); + if (*ci_array == NULL) { + ret = -ENOMEM; + goto error_close_dir; + } + seekdir(dp, 0); + count = 0; + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + int current_enabled = 0; + + current = &(*ci_array)[count++]; + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + /* decrement count to avoid freeing name */ + count--; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + free(filename); + ret = -errno; + goto error_cleanup_array; + } + fscanf(sysfsfp, "%i", ¤t_enabled); + fclose(sysfsfp); + + if (!current_enabled) { + free(filename); + count--; + continue; + } + + current->scale = 1.0; + current->offset = 0; + current->name = strndup(ent->d_name, + strlen(ent->d_name) - + strlen("_en")); + if (current->name == NULL) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + /* Get the generic and specific name elements */ + ret = iioutils_break_up_name(current->name, + ¤t->generic_name); + if (ret) { + free(filename); + goto error_cleanup_array; + } + ret = asprintf(&filename, + "%s/%s_index", + scan_el_dir, + current->name); + if (ret < 0) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + fscanf(sysfsfp, "%u", ¤t->index); + fclose(sysfsfp); + free(filename); + /* Find the scale */ + ret = iioutils_get_param_float(¤t->scale, + "scale", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_param_float(¤t->offset, + "offset", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_type(¤t->is_signed, + ¤t->bytes, + ¤t->bits_used, + ¤t->shift, + ¤t->mask, + ¤t->be, + device_dir, + current->name, + current->generic_name); + } + } + + closedir(dp); + /* reorder so that the array is in index order */ + bsort_channel_array_by_index(ci_array, *counter); + + return 0; + +error_cleanup_array: + for (i = count - 1; i >= 0; i--) + free((*ci_array)[i].name); + free(*ci_array); +error_close_dir: + closedir(dp); +error_free_name: + free(scan_el_dir); +error_ret: + return ret; +} + +/** + * find_type_by_name() - function to match top level types by name + * @name: top level type instance name + * @type: the type of top level instance being sort + * + * Typical types this is used for are device and trigger. + **/ +int find_type_by_name(const char *name, const char *type) +{ + const struct dirent *ent; + int number, numstrlen; + + FILE *nameFile; + DIR *dp; + char thisname[IIO_MAX_NAME_LENGTH]; + char *filename; + + dp = opendir(iio_dir); + if (dp == NULL) { + printf("No industrialio devices available\n"); + return -ENODEV; + } + + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0 && + strlen(ent->d_name) > strlen(type) && + strncmp(ent->d_name, type, strlen(type)) == 0) { + numstrlen = sscanf(ent->d_name + strlen(type), + "%d", + &number); + /* verify the next character is not a colon */ + if (strncmp(ent->d_name + strlen(type) + numstrlen, + ":", + 1) != 0) { + filename = malloc(strlen(iio_dir) + + strlen(type) + + numstrlen + + 6); + if (filename == NULL) { + closedir(dp); + return -ENOMEM; + } + sprintf(filename, "%s%s%d/name", + iio_dir, + type, + number); + nameFile = fopen(filename, "r"); + if (!nameFile) { + free(filename); + continue; + } + free(filename); + fscanf(nameFile, "%s", thisname); + fclose(nameFile); + if (strcmp(name, thisname) == 0) { + closedir(dp); + return number; + } + } + } + } + closedir(dp); + return -ENODEV; +} + +int _write_sysfs_int(char *filename, char *basedir, int val, int verify) +{ + int ret = 0; + FILE *sysfsfp; + int test; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) + return -ENOMEM; + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "w"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", temp); + ret = -errno; + goto error_free; + } + fprintf(sysfsfp, "%d", val); + fclose(sysfsfp); + if (verify) { + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", temp); + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%d", &test); + fclose(sysfsfp); + if (test != val) { + printf("Possible failure in int write %d to %s%s\n", + val, + basedir, + filename); + ret = -1; + } + } +error_free: + free(temp); + return ret; +} + +int write_sysfs_int(char *filename, char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 0); +} + +int write_sysfs_int_and_verify(char *filename, char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 1); +} + +int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed\n"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "w"); + if (sysfsfp == NULL) { + printf("Could not open %s\n", temp); + ret = -errno; + goto error_free; + } + fprintf(sysfsfp, "%s", val); + fclose(sysfsfp); + if (verify) { + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + printf("could not open file to verify\n"); + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%s", temp); + fclose(sysfsfp); + if (strcmp(temp, val) != 0) { + printf("Possible failure in string write of %s " + "Should be %s " + "written to %s\%s\n", + temp, + val, + basedir, + filename); + ret = -1; + } + } +error_free: + free(temp); + + return ret; +} + +/** + * write_sysfs_string_and_verify() - string write, readback and verify + * @filename: name of file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: the string to write + **/ +int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) +{ + return _write_sysfs_string(filename, basedir, val, 1); +} + +int write_sysfs_string(char *filename, char *basedir, char *val) +{ + return _write_sysfs_string(filename, basedir, val, 0); +} + +int read_sysfs_posint(char *filename, char *basedir) +{ + int ret; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%d\n", &ret); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} + +int read_sysfs_float(char *filename, char *basedir, float *val) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%f\n", val); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} + +int read_sysfs_string(const char *filename, const char *basedir, char *str) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%s\n", str); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index 568eff06f803..1bc837b2d769 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -1,3 +1,6 @@ +#ifndef _IIO_UTILS_H_ +#define _IIO_UTILS_H_ + /* IIO - useful set of util functionality * * Copyright (c) 2008 Jonathan Cameron @@ -7,13 +10,7 @@ * the Free Software Foundation. */ -#include -#include -#include -#include #include -#include -#include /* Made up value to limit allocation sizes */ #define IIO_MAX_NAME_LENGTH 30 @@ -21,38 +18,7 @@ #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" #define FORMAT_TYPE_FILE "%s_type" -const char *iio_dir = "/sys/bus/iio/devices/"; - -/** - * iioutils_break_up_name() - extract generic name from full channel name - * @full_name: the full channel name - * @generic_name: the output generic channel name - **/ -inline int iioutils_break_up_name(const char *full_name, - char **generic_name) -{ - char *current; - char *w, *r; - char *working; - - current = strdup(full_name); - working = strtok(current, "_\0"); - w = working; - r = working; - - while (*r != '\0') { - if (!isdigit(*r)) { - *w = *r; - w++; - } - r++; - } - *w = '\0'; - *generic_name = strdup(working); - free(current); - - return 0; -} +extern const char *iio_dir; /** * struct iio_channel_info - information about a given channel @@ -81,603 +47,25 @@ struct iio_channel_info { unsigned location; }; -/** - * iioutils_get_type() - find and process _type attribute data - * @is_signed: output whether channel is signed - * @bytes: output how many bytes the channel storage occupies - * @mask: output a bit mask for the raw data - * @be: big endian - * @device_dir: the iio device directory - * @name: the channel name - * @generic_name: the channel type name - **/ -inline int iioutils_get_type(unsigned *is_signed, - unsigned *bytes, - unsigned *bits_used, - unsigned *shift, - uint64_t *mask, - unsigned *be, - const char *device_dir, - const char *name, - const char *generic_name) -{ - FILE *sysfsfp; - int ret; - DIR *dp; - char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; - char signchar, endianchar; - unsigned padint; - const struct dirent *ent; - - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_scan_el_dir; - } - ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_builtname; - } - - dp = opendir(scan_el_dir); - if (dp == NULL) { - ret = -errno; - goto error_free_builtname_generic; - } - while (ent = readdir(dp), ent != NULL) - /* - * Do we allow devices to override a generic name with - * a specific one? - */ - if ((strcmp(builtname, ent->d_name) == 0) || - (strcmp(builtname_generic, ent->d_name) == 0)) { - ret = asprintf(&filename, - "%s/%s", scan_el_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_closedir; - } - sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { - printf("failed to open %s\n", filename); - ret = -errno; - goto error_free_filename; - } - - ret = fscanf(sysfsfp, - "%ce:%c%u/%u>>%u", - &endianchar, - &signchar, - bits_used, - &padint, shift); - if (ret < 0) { - printf("failed to pass scan type description\n"); - ret = -errno; - goto error_close_sysfsfp; - } - *be = (endianchar == 'b'); - *bytes = padint / 8; - if (*bits_used == 64) - *mask = ~0; - else - *mask = (1 << *bits_used) - 1; - if (signchar == 's') - *is_signed = 1; - else - *is_signed = 0; - fclose(sysfsfp); - free(filename); - - filename = 0; - sysfsfp = 0; - } -error_close_sysfsfp: - if (sysfsfp) - fclose(sysfsfp); -error_free_filename: - if (filename) - free(filename); -error_closedir: - closedir(dp); -error_free_builtname_generic: - free(builtname_generic); -error_free_builtname: - free(builtname); -error_free_scan_el_dir: - free(scan_el_dir); -error_ret: - return ret; -} - -inline int iioutils_get_param_float(float *output, - const char *param_name, - const char *device_dir, - const char *name, - const char *generic_name) -{ - FILE *sysfsfp; - int ret; - DIR *dp; - char *builtname, *builtname_generic; - char *filename = NULL; - const struct dirent *ent; - - ret = asprintf(&builtname, "%s_%s", name, param_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - ret = asprintf(&builtname_generic, - "%s_%s", generic_name, param_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_builtname; - } - dp = opendir(device_dir); - if (dp == NULL) { - ret = -errno; - goto error_free_builtname_generic; - } - while (ent = readdir(dp), ent != NULL) - if ((strcmp(builtname, ent->d_name) == 0) || - (strcmp(builtname_generic, ent->d_name) == 0)) { - ret = asprintf(&filename, - "%s/%s", device_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_closedir; - } - sysfsfp = fopen(filename, "r"); - if (!sysfsfp) { - ret = -errno; - goto error_free_filename; - } - fscanf(sysfsfp, "%f", output); - break; - } -error_free_filename: - if (filename) - free(filename); -error_closedir: - closedir(dp); -error_free_builtname_generic: - free(builtname_generic); -error_free_builtname: - free(builtname); -error_ret: - return ret; -} - -/** - * bsort_channel_array_by_index() - reorder so that the array is in index order - * - **/ - -inline void bsort_channel_array_by_index(struct iio_channel_info **ci_array, - int cnt) -{ - - struct iio_channel_info temp; - int x, y; - - for (x = 0; x < cnt; x++) - for (y = 0; y < (cnt - 1); y++) - if ((*ci_array)[y].index > (*ci_array)[y+1].index) { - temp = (*ci_array)[y + 1]; - (*ci_array)[y + 1] = (*ci_array)[y]; - (*ci_array)[y] = temp; - } -} - -/** - * build_channel_array() - function to figure out what channels are present - * @device_dir: the IIO device directory in sysfs - * @ - **/ -inline int build_channel_array(const char *device_dir, - struct iio_channel_info **ci_array, - int *counter) -{ - DIR *dp; - FILE *sysfsfp; - int count, i; - struct iio_channel_info *current; - int ret; - const struct dirent *ent; - char *scan_el_dir; - char *filename; - - *counter = 0; - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - dp = opendir(scan_el_dir); - if (dp == NULL) { - ret = -errno; - goto error_free_name; - } - while (ent = readdir(dp), ent != NULL) - if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), - "_en") == 0) { - ret = asprintf(&filename, - "%s/%s", scan_el_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_close_dir; - } - sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { - ret = -errno; - free(filename); - goto error_close_dir; - } - fscanf(sysfsfp, "%i", &ret); - if (ret == 1) - (*counter)++; - fclose(sysfsfp); - free(filename); - } - *ci_array = malloc(sizeof(**ci_array) * (*counter)); - if (*ci_array == NULL) { - ret = -ENOMEM; - goto error_close_dir; - } - seekdir(dp, 0); - count = 0; - while (ent = readdir(dp), ent != NULL) { - if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), - "_en") == 0) { - int current_enabled = 0; - - current = &(*ci_array)[count++]; - ret = asprintf(&filename, - "%s/%s", scan_el_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - /* decrement count to avoid freeing name */ - count--; - goto error_cleanup_array; - } - sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { - free(filename); - ret = -errno; - goto error_cleanup_array; - } - fscanf(sysfsfp, "%i", ¤t_enabled); - fclose(sysfsfp); - - if (!current_enabled) { - free(filename); - count--; - continue; - } - - current->scale = 1.0; - current->offset = 0; - current->name = strndup(ent->d_name, - strlen(ent->d_name) - - strlen("_en")); - if (current->name == NULL) { - free(filename); - ret = -ENOMEM; - goto error_cleanup_array; - } - /* Get the generic and specific name elements */ - ret = iioutils_break_up_name(current->name, - ¤t->generic_name); - if (ret) { - free(filename); - goto error_cleanup_array; - } - ret = asprintf(&filename, - "%s/%s_index", - scan_el_dir, - current->name); - if (ret < 0) { - free(filename); - ret = -ENOMEM; - goto error_cleanup_array; - } - sysfsfp = fopen(filename, "r"); - fscanf(sysfsfp, "%u", ¤t->index); - fclose(sysfsfp); - free(filename); - /* Find the scale */ - ret = iioutils_get_param_float(¤t->scale, - "scale", - device_dir, - current->name, - current->generic_name); - if (ret < 0) - goto error_cleanup_array; - ret = iioutils_get_param_float(¤t->offset, - "offset", - device_dir, - current->name, - current->generic_name); - if (ret < 0) - goto error_cleanup_array; - ret = iioutils_get_type(¤t->is_signed, - ¤t->bytes, - ¤t->bits_used, - ¤t->shift, - ¤t->mask, - ¤t->be, - device_dir, - current->name, - current->generic_name); - } - } - - closedir(dp); - /* reorder so that the array is in index order */ - bsort_channel_array_by_index(ci_array, *counter); - - return 0; - -error_cleanup_array: - for (i = count - 1; i >= 0; i--) - free((*ci_array)[i].name); - free(*ci_array); -error_close_dir: - closedir(dp); -error_free_name: - free(scan_el_dir); -error_ret: - return ret; -} - -/** - * find_type_by_name() - function to match top level types by name - * @name: top level type instance name - * @type: the type of top level instance being sort - * - * Typical types this is used for are device and trigger. - **/ -inline int find_type_by_name(const char *name, const char *type) -{ - const struct dirent *ent; - int number, numstrlen; - - FILE *nameFile; - DIR *dp; - char thisname[IIO_MAX_NAME_LENGTH]; - char *filename; - - dp = opendir(iio_dir); - if (dp == NULL) { - printf("No industrialio devices available\n"); - return -ENODEV; - } - - while (ent = readdir(dp), ent != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0 && - strlen(ent->d_name) > strlen(type) && - strncmp(ent->d_name, type, strlen(type)) == 0) { - numstrlen = sscanf(ent->d_name + strlen(type), - "%d", - &number); - /* verify the next character is not a colon */ - if (strncmp(ent->d_name + strlen(type) + numstrlen, - ":", - 1) != 0) { - filename = malloc(strlen(iio_dir) - + strlen(type) - + numstrlen - + 6); - if (filename == NULL) { - closedir(dp); - return -ENOMEM; - } - sprintf(filename, "%s%s%d/name", - iio_dir, - type, - number); - nameFile = fopen(filename, "r"); - if (!nameFile) { - free(filename); - continue; - } - free(filename); - fscanf(nameFile, "%s", thisname); - fclose(nameFile); - if (strcmp(name, thisname) == 0) { - closedir(dp); - return number; - } - } - } - } - closedir(dp); - return -ENODEV; -} - -inline int _write_sysfs_int(char *filename, char *basedir, int val, int verify) -{ - int ret = 0; - FILE *sysfsfp; - int test; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) - return -ENOMEM; - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "w"); - if (sysfsfp == NULL) { - printf("failed to open %s\n", temp); - ret = -errno; - goto error_free; - } - fprintf(sysfsfp, "%d", val); - fclose(sysfsfp); - if (verify) { - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - printf("failed to open %s\n", temp); - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%d", &test); - fclose(sysfsfp); - if (test != val) { - printf("Possible failure in int write %d to %s%s\n", - val, - basedir, - filename); - ret = -1; - } - } -error_free: - free(temp); - return ret; -} - -int write_sysfs_int(char *filename, char *basedir, int val) -{ - return _write_sysfs_int(filename, basedir, val, 0); -} - -int write_sysfs_int_and_verify(char *filename, char *basedir, int val) -{ - return _write_sysfs_int(filename, basedir, val, 1); -} - -int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) -{ - int ret = 0; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed\n"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "w"); - if (sysfsfp == NULL) { - printf("Could not open %s\n", temp); - ret = -errno; - goto error_free; - } - fprintf(sysfsfp, "%s", val); - fclose(sysfsfp); - if (verify) { - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - printf("could not open file to verify\n"); - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%s", temp); - fclose(sysfsfp); - if (strcmp(temp, val) != 0) { - printf("Possible failure in string write of %s " - "Should be %s " - "written to %s\%s\n", - temp, - val, - basedir, - filename); - ret = -1; - } - } -error_free: - free(temp); - - return ret; -} - -/** - * write_sysfs_string_and_verify() - string write, readback and verify - * @filename: name of file to write to - * @basedir: the sysfs directory in which the file is to be found - * @val: the string to write - **/ -int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) -{ - return _write_sysfs_string(filename, basedir, val, 1); -} - -int write_sysfs_string(char *filename, char *basedir, char *val) -{ - return _write_sysfs_string(filename, basedir, val, 0); -} - -int read_sysfs_posint(char *filename, char *basedir) -{ - int ret; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%d\n", &ret); - fclose(sysfsfp); -error_free: - free(temp); - return ret; -} - -int read_sysfs_float(char *filename, char *basedir, float *val) -{ - int ret = 0; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%f\n", val); - fclose(sysfsfp); -error_free: - free(temp); - return ret; -} - -int read_sysfs_string(const char *filename, const char *basedir, char *str) -{ - int ret = 0; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%s\n", str); - fclose(sysfsfp); -error_free: - free(temp); - return ret; -} +int iioutils_break_up_name(const char *full_name, char **generic_name); +int iioutils_get_type(unsigned *is_signed, unsigned *bytes, + unsigned *bits_used, unsigned *shift, + uint64_t *mask, unsigned *be, + const char *device_dir, const char *name, + const char *generic_name); +int iioutils_get_param_float(float *output, const char *param_name, + const char *device_dir, const char *name, + const char *generic_name); +void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt); +int build_channel_array(const char *device_dir, + struct iio_channel_info **ci_array, int *counter); +int find_type_by_name(const char *name, const char *type); +int write_sysfs_int(char *filename, char *basedir, int val); +int write_sysfs_int_and_verify(char *filename, char *basedir, int val); +int write_sysfs_string_and_verify(char *filename, char *basedir, char *val); +int write_sysfs_string(char *filename, char *basedir, char *val); +int read_sysfs_posint(char *filename, char *basedir); +int read_sysfs_float(char *filename, char *basedir, float *val); +int read_sysfs_string(const char *filename, const char *basedir, char *str); + +#endif /* _IIO_UTILS_H_ */ -- cgit v1.2.3 From 817020cfb3a2649064a1e14e083934234e2c208d Mon Sep 17 00:00:00 2001 From: Roberta Dobrescu Date: Thu, 26 Feb 2015 10:49:25 +0200 Subject: iio: Move iio userspace applications out of staging This patch moves iio userspace applications out of staging, to tools/iio/ and adds a Makefile in order to compile them easily. It also adds tools/iio/ to MAINTAINERS file. Signed-off-by: Roberta Dobrescu Signed-off-by: Jonathan Cameron --- MAINTAINERS | 1 + drivers/staging/iio/Documentation/generic_buffer.c | 361 ------------ .../staging/iio/Documentation/iio_event_monitor.c | 310 ---------- drivers/staging/iio/Documentation/iio_utils.c | 651 --------------------- drivers/staging/iio/Documentation/iio_utils.h | 71 --- drivers/staging/iio/Documentation/lsiio.c | 163 ------ tools/iio/Makefile | 16 + tools/iio/generic_buffer.c | 361 ++++++++++++ tools/iio/iio_event_monitor.c | 310 ++++++++++ tools/iio/iio_utils.c | 651 +++++++++++++++++++++ tools/iio/iio_utils.h | 71 +++ tools/iio/lsiio.c | 163 ++++++ 12 files changed, 1573 insertions(+), 1556 deletions(-) delete mode 100644 drivers/staging/iio/Documentation/generic_buffer.c delete mode 100644 drivers/staging/iio/Documentation/iio_event_monitor.c delete mode 100644 drivers/staging/iio/Documentation/iio_utils.c delete mode 100644 drivers/staging/iio/Documentation/iio_utils.h delete mode 100644 drivers/staging/iio/Documentation/lsiio.c create mode 100644 tools/iio/Makefile create mode 100644 tools/iio/generic_buffer.c create mode 100644 tools/iio/iio_event_monitor.c create mode 100644 tools/iio/iio_utils.c create mode 100644 tools/iio/iio_utils.h create mode 100644 tools/iio/lsiio.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 873f496c6364..6fb6bdc2eb3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4871,6 +4871,7 @@ S: Maintained F: drivers/iio/ F: drivers/staging/iio/ F: include/linux/iio/ +F: tools/iio/ IKANOS/ADI EAGLE ADSL USB DRIVER M: Matthieu Castet diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c deleted file mode 100644 index 01266c2556da..000000000000 --- a/drivers/staging/iio/Documentation/generic_buffer.c +++ /dev/null @@ -1,361 +0,0 @@ -/* Industrialio buffer test code. - * - * Copyright (c) 2008 Jonathan Cameron - * - * 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 primarily intended as an example application. - * Reads the current buffer setup from sysfs and starts a short capture - * from the specified device, pretty printing the result after appropriate - * conversion. - * - * Command line parameters - * generic_buffer -n -t - * If trigger name is not specified the program assumes you want a dataready - * trigger associated with the device and goes looking for it. - * - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iio_utils.h" - -/** - * size_from_channelarray() - calculate the storage size of a scan - * @channels: the channel info array - * @num_channels: number of channels - * - * Has the side effect of filling the channels[i].location values used - * in processing the buffer output. - **/ -int size_from_channelarray(struct iio_channel_info *channels, int num_channels) -{ - int bytes = 0; - int i = 0; - - while (i < num_channels) { - if (bytes % channels[i].bytes == 0) - channels[i].location = bytes; - else - channels[i].location = bytes - bytes%channels[i].bytes - + channels[i].bytes; - bytes = channels[i].location + channels[i].bytes; - i++; - } - return bytes; -} - -void print2byte(int input, struct iio_channel_info *info) -{ - /* First swap if incorrect endian */ - if (info->be) - input = be16toh((uint16_t)input); - else - input = le16toh((uint16_t)input); - - /* - * Shift before conversion to avoid sign extension - * of left aligned data - */ - input = input >> info->shift; - if (info->is_signed) { - int16_t val = input; - - val &= (1 << info->bits_used) - 1; - val = (int16_t)(val << (16 - info->bits_used)) >> - (16 - info->bits_used); - printf("%05f ", ((float)val + info->offset)*info->scale); - } else { - uint16_t val = input; - - val &= (1 << info->bits_used) - 1; - printf("%05f ", ((float)val + info->offset)*info->scale); - } -} -/** - * process_scan() - print out the values in SI units - * @data: pointer to the start of the scan - * @channels: information about the channels. Note - * size_from_channelarray must have been called first to fill the - * location offsets. - * @num_channels: number of channels - **/ -void process_scan(char *data, - struct iio_channel_info *channels, - int num_channels) -{ - int k; - - for (k = 0; k < num_channels; k++) - switch (channels[k].bytes) { - /* only a few cases implemented so far */ - case 2: - print2byte(*(uint16_t *)(data + channels[k].location), - &channels[k]); - break; - case 4: - if (!channels[k].is_signed) { - uint32_t val = *(uint32_t *) - (data + channels[k].location); - printf("%05f ", ((float)val + - channels[k].offset)* - channels[k].scale); - - } - break; - case 8: - if (channels[k].is_signed) { - int64_t val = *(int64_t *) - (data + - channels[k].location); - if ((val >> channels[k].bits_used) & 1) - val = (val & channels[k].mask) | - ~channels[k].mask; - /* special case for timestamp */ - if (channels[k].scale == 1.0f && - channels[k].offset == 0.0f) - printf("%" PRId64 " ", val); - else - printf("%05f ", ((float)val + - channels[k].offset)* - channels[k].scale); - } - break; - default: - break; - } - printf("\n"); -} - -int main(int argc, char **argv) -{ - unsigned long num_loops = 2; - unsigned long timedelay = 1000000; - unsigned long buf_len = 128; - - int ret, c, i, j, toread; - int fp; - - int num_channels; - char *trigger_name = NULL, *device_name = NULL; - char *dev_dir_name, *buf_dir_name; - - int datardytrigger = 1; - char *data; - ssize_t read_size; - int dev_num, trig_num; - char *buffer_access; - int scan_size; - int noevents = 0; - int notrigger = 0; - char *dummy; - - struct iio_channel_info *channels; - - while ((c = getopt(argc, argv, "l:w:c:et:n:g")) != -1) { - switch (c) { - case 'n': - device_name = optarg; - break; - case 't': - trigger_name = optarg; - datardytrigger = 0; - break; - case 'e': - noevents = 1; - break; - case 'c': - num_loops = strtoul(optarg, &dummy, 10); - break; - case 'w': - timedelay = strtoul(optarg, &dummy, 10); - break; - case 'l': - buf_len = strtoul(optarg, &dummy, 10); - break; - case 'g': - notrigger = 1; - break; - case '?': - return -1; - } - } - - if (device_name == NULL) - return -1; - - /* Find the device requested */ - dev_num = find_type_by_name(device_name, "iio:device"); - if (dev_num < 0) { - printf("Failed to find the %s\n", device_name); - ret = -ENODEV; - goto error_ret; - } - printf("iio device number being used is %d\n", dev_num); - - asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); - - if (!notrigger) { - if (trigger_name == NULL) { - /* - * Build the trigger name. If it is device associated - * its name is _dev[n] where n matches - * the device number found above. - */ - ret = asprintf(&trigger_name, - "%s-dev%d", device_name, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - } - - /* Verify the trigger exists */ - trig_num = find_type_by_name(trigger_name, "trigger"); - if (trig_num < 0) { - printf("Failed to find the trigger %s\n", trigger_name); - ret = -ENODEV; - goto error_free_triggername; - } - printf("iio trigger number being used is %d\n", trig_num); - } else - printf("trigger-less mode selected\n"); - - /* - * Parse the files in scan_elements to identify what channels are - * present - */ - ret = build_channel_array(dev_dir_name, &channels, &num_channels); - if (ret) { - printf("Problem reading scan element information\n"); - printf("diag %s\n", dev_dir_name); - goto error_free_triggername; - } - - /* - * Construct the directory name for the associated buffer. - * As we know that the lis3l02dq has only one buffer this may - * be built rather than found. - */ - ret = asprintf(&buf_dir_name, - "%siio:device%d/buffer", iio_dir, dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_triggername; - } - - if (!notrigger) { - printf("%s %s\n", dev_dir_name, trigger_name); - /* Set the device trigger to be the data ready trigger found - * above */ - ret = write_sysfs_string_and_verify("trigger/current_trigger", - dev_dir_name, - trigger_name); - if (ret < 0) { - printf("Failed to write current_trigger file\n"); - goto error_free_buf_dir_name; - } - } - - /* Setup ring buffer parameters */ - ret = write_sysfs_int("length", buf_dir_name, buf_len); - if (ret < 0) - goto error_free_buf_dir_name; - - /* Enable the buffer */ - ret = write_sysfs_int("enable", buf_dir_name, 1); - if (ret < 0) - goto error_free_buf_dir_name; - scan_size = size_from_channelarray(channels, num_channels); - data = malloc(scan_size*buf_len); - if (!data) { - ret = -ENOMEM; - goto error_free_buf_dir_name; - } - - ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_data; - } - - /* Attempt to open non blocking the access dev */ - fp = open(buffer_access, O_RDONLY | O_NONBLOCK); - if (fp == -1) { /* If it isn't there make the node */ - printf("Failed to open %s\n", buffer_access); - ret = -errno; - goto error_free_buffer_access; - } - - /* Wait for events 10 times */ - for (j = 0; j < num_loops; j++) { - if (!noevents) { - struct pollfd pfd = { - .fd = fp, - .events = POLLIN, - }; - - poll(&pfd, 1, -1); - toread = buf_len; - - } else { - usleep(timedelay); - toread = 64; - } - - read_size = read(fp, - data, - toread*scan_size); - if (read_size < 0) { - if (errno == -EAGAIN) { - printf("nothing available\n"); - continue; - } else - break; - } - for (i = 0; i < read_size/scan_size; i++) - process_scan(data + scan_size*i, - channels, - num_channels); - } - - /* Stop the buffer */ - ret = write_sysfs_int("enable", buf_dir_name, 0); - if (ret < 0) - goto error_close_buffer_access; - - if (!notrigger) - /* Disconnect the trigger - just write a dummy name. */ - write_sysfs_string("trigger/current_trigger", - dev_dir_name, "NULL"); - -error_close_buffer_access: - close(fp); -error_free_data: - free(data); -error_free_buffer_access: - free(buffer_access); -error_free_buf_dir_name: - free(buf_dir_name); -error_free_triggername: - if (datardytrigger) - free(trigger_name); -error_ret: - return ret; -} diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c deleted file mode 100644 index f19cff19900e..000000000000 --- a/drivers/staging/iio/Documentation/iio_event_monitor.c +++ /dev/null @@ -1,310 +0,0 @@ -/* Industrialio event test code. - * - * Copyright (c) 2011-2012 Lars-Peter Clausen - * - * 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 primarily intended as an example application. - * Reads the current buffer setup from sysfs and starts a short capture - * from the specified device, pretty printing the result after appropriate - * conversion. - * - * Usage: - * iio_event_monitor - * - */ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iio_utils.h" -#include -#include - -static const char * const iio_chan_type_name_spec[] = { - [IIO_VOLTAGE] = "voltage", - [IIO_CURRENT] = "current", - [IIO_POWER] = "power", - [IIO_ACCEL] = "accel", - [IIO_ANGL_VEL] = "anglvel", - [IIO_MAGN] = "magn", - [IIO_LIGHT] = "illuminance", - [IIO_INTENSITY] = "intensity", - [IIO_PROXIMITY] = "proximity", - [IIO_TEMP] = "temp", - [IIO_INCLI] = "incli", - [IIO_ROT] = "rot", - [IIO_ANGL] = "angl", - [IIO_TIMESTAMP] = "timestamp", - [IIO_CAPACITANCE] = "capacitance", - [IIO_ALTVOLTAGE] = "altvoltage", - [IIO_CCT] = "cct", - [IIO_PRESSURE] = "pressure", - [IIO_HUMIDITYRELATIVE] = "humidityrelative", - [IIO_ACTIVITY] = "activity", - [IIO_STEPS] = "steps", -}; - -static const char * const iio_ev_type_text[] = { - [IIO_EV_TYPE_THRESH] = "thresh", - [IIO_EV_TYPE_MAG] = "mag", - [IIO_EV_TYPE_ROC] = "roc", - [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", - [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", - [IIO_EV_TYPE_CHANGE] = "change", -}; - -static const char * const iio_ev_dir_text[] = { - [IIO_EV_DIR_EITHER] = "either", - [IIO_EV_DIR_RISING] = "rising", - [IIO_EV_DIR_FALLING] = "falling" -}; - -static const char * const iio_modifier_names[] = { - [IIO_MOD_X] = "x", - [IIO_MOD_Y] = "y", - [IIO_MOD_Z] = "z", - [IIO_MOD_X_AND_Y] = "x&y", - [IIO_MOD_X_AND_Z] = "x&z", - [IIO_MOD_Y_AND_Z] = "y&z", - [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z", - [IIO_MOD_X_OR_Y] = "x|y", - [IIO_MOD_X_OR_Z] = "x|z", - [IIO_MOD_Y_OR_Z] = "y|z", - [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z", - [IIO_MOD_LIGHT_BOTH] = "both", - [IIO_MOD_LIGHT_IR] = "ir", - [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", - [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", - [IIO_MOD_LIGHT_CLEAR] = "clear", - [IIO_MOD_LIGHT_RED] = "red", - [IIO_MOD_LIGHT_GREEN] = "green", - [IIO_MOD_LIGHT_BLUE] = "blue", - [IIO_MOD_QUATERNION] = "quaternion", - [IIO_MOD_TEMP_AMBIENT] = "ambient", - [IIO_MOD_TEMP_OBJECT] = "object", - [IIO_MOD_NORTH_MAGN] = "from_north_magnetic", - [IIO_MOD_NORTH_TRUE] = "from_north_true", - [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp", - [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp", - [IIO_MOD_RUNNING] = "running", - [IIO_MOD_JOGGING] = "jogging", - [IIO_MOD_WALKING] = "walking", - [IIO_MOD_STILL] = "still", -}; - -static bool event_is_known(struct iio_event_data *event) -{ - enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); - enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); - enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); - enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); - - switch (type) { - case IIO_VOLTAGE: - case IIO_CURRENT: - case IIO_POWER: - case IIO_ACCEL: - case IIO_ANGL_VEL: - case IIO_MAGN: - case IIO_LIGHT: - case IIO_INTENSITY: - case IIO_PROXIMITY: - case IIO_TEMP: - case IIO_INCLI: - case IIO_ROT: - case IIO_ANGL: - case IIO_TIMESTAMP: - case IIO_CAPACITANCE: - case IIO_ALTVOLTAGE: - case IIO_CCT: - case IIO_PRESSURE: - case IIO_HUMIDITYRELATIVE: - case IIO_ACTIVITY: - case IIO_STEPS: - break; - default: - return false; - } - - switch (mod) { - case IIO_NO_MOD: - case IIO_MOD_X: - case IIO_MOD_Y: - case IIO_MOD_Z: - case IIO_MOD_X_AND_Y: - case IIO_MOD_X_AND_Z: - case IIO_MOD_Y_AND_Z: - case IIO_MOD_X_AND_Y_AND_Z: - case IIO_MOD_X_OR_Y: - case IIO_MOD_X_OR_Z: - case IIO_MOD_Y_OR_Z: - case IIO_MOD_X_OR_Y_OR_Z: - case IIO_MOD_LIGHT_BOTH: - case IIO_MOD_LIGHT_IR: - case IIO_MOD_ROOT_SUM_SQUARED_X_Y: - case IIO_MOD_SUM_SQUARED_X_Y_Z: - case IIO_MOD_LIGHT_CLEAR: - case IIO_MOD_LIGHT_RED: - case IIO_MOD_LIGHT_GREEN: - case IIO_MOD_LIGHT_BLUE: - case IIO_MOD_QUATERNION: - case IIO_MOD_TEMP_AMBIENT: - case IIO_MOD_TEMP_OBJECT: - case IIO_MOD_NORTH_MAGN: - case IIO_MOD_NORTH_TRUE: - case IIO_MOD_NORTH_MAGN_TILT_COMP: - case IIO_MOD_NORTH_TRUE_TILT_COMP: - case IIO_MOD_RUNNING: - case IIO_MOD_JOGGING: - case IIO_MOD_WALKING: - case IIO_MOD_STILL: - break; - default: - return false; - } - - switch (ev_type) { - case IIO_EV_TYPE_THRESH: - case IIO_EV_TYPE_MAG: - case IIO_EV_TYPE_ROC: - case IIO_EV_TYPE_THRESH_ADAPTIVE: - case IIO_EV_TYPE_MAG_ADAPTIVE: - case IIO_EV_TYPE_CHANGE: - break; - default: - return false; - } - - switch (dir) { - case IIO_EV_DIR_EITHER: - case IIO_EV_DIR_RISING: - case IIO_EV_DIR_FALLING: - case IIO_EV_DIR_NONE: - break; - default: - return false; - } - - return true; -} - -static void print_event(struct iio_event_data *event) -{ - enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); - enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); - enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); - enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); - int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id); - int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id); - bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id); - - if (!event_is_known(event)) { - printf("Unknown event: time: %lld, id: %llx\n", - event->timestamp, event->id); - return; - } - - printf("Event: time: %lld, ", event->timestamp); - - if (mod != IIO_NO_MOD) { - printf("type: %s(%s), ", - iio_chan_type_name_spec[type], - iio_modifier_names[mod]); - } else { - printf("type: %s, ", - iio_chan_type_name_spec[type]); - } - - if (diff && chan >= 0 && chan2 >= 0) - printf("channel: %d-%d, ", chan, chan2); - else if (chan >= 0) - printf("channel: %d, ", chan); - - printf("evtype: %s", iio_ev_type_text[ev_type]); - - if (dir != IIO_EV_DIR_NONE) - printf(", direction: %s", iio_ev_dir_text[dir]); - printf("\n"); -} - -int main(int argc, char **argv) -{ - struct iio_event_data event; - const char *device_name; - char *chrdev_name; - int ret; - int dev_num; - int fd, event_fd; - - if (argc <= 1) { - printf("Usage: %s \n", argv[0]); - return -1; - } - - device_name = argv[1]; - - dev_num = find_type_by_name(device_name, "iio:device"); - if (dev_num >= 0) { - printf("Found IIO device with name %s with device number %d\n", - device_name, dev_num); - ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - } else { - /* If we can't find a IIO device by name assume device_name is a - IIO chrdev */ - chrdev_name = strdup(device_name); - } - - fd = open(chrdev_name, 0); - if (fd == -1) { - fprintf(stdout, "Failed to open %s\n", chrdev_name); - ret = -errno; - goto error_free_chrdev_name; - } - - ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); - - close(fd); - - if (ret == -1 || event_fd == -1) { - fprintf(stdout, "Failed to retrieve event fd\n"); - ret = -errno; - goto error_free_chrdev_name; - } - - while (true) { - ret = read(event_fd, &event, sizeof(event)); - if (ret == -1) { - if (errno == EAGAIN) { - printf("nothing available\n"); - continue; - } else { - perror("Failed to read event from device"); - ret = -errno; - break; - } - } - - print_event(&event); - } - - close(event_fd); -error_free_chrdev_name: - free(chrdev_name); -error_ret: - return ret; -} diff --git a/drivers/staging/iio/Documentation/iio_utils.c b/drivers/staging/iio/Documentation/iio_utils.c deleted file mode 100644 index aea928210187..000000000000 --- a/drivers/staging/iio/Documentation/iio_utils.c +++ /dev/null @@ -1,651 +0,0 @@ -/* IIO - useful set of util functionality - * - * Copyright (c) 2008 Jonathan Cameron - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "iio_utils.h" - -const char *iio_dir = "/sys/bus/iio/devices/"; - -/** - * iioutils_break_up_name() - extract generic name from full channel name - * @full_name: the full channel name - * @generic_name: the output generic channel name - **/ -int iioutils_break_up_name(const char *full_name, - char **generic_name) -{ - char *current; - char *w, *r; - char *working; - - current = strdup(full_name); - working = strtok(current, "_\0"); - w = working; - r = working; - - while (*r != '\0') { - if (!isdigit(*r)) { - *w = *r; - w++; - } - r++; - } - *w = '\0'; - *generic_name = strdup(working); - free(current); - - return 0; -} - -/** - * iioutils_get_type() - find and process _type attribute data - * @is_signed: output whether channel is signed - * @bytes: output how many bytes the channel storage occupies - * @mask: output a bit mask for the raw data - * @be: big endian - * @device_dir: the iio device directory - * @name: the channel name - * @generic_name: the channel type name - **/ -int iioutils_get_type(unsigned *is_signed, - unsigned *bytes, - unsigned *bits_used, - unsigned *shift, - uint64_t *mask, - unsigned *be, - const char *device_dir, - const char *name, - const char *generic_name) -{ - FILE *sysfsfp; - int ret; - DIR *dp; - char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; - char signchar, endianchar; - unsigned padint; - const struct dirent *ent; - - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_scan_el_dir; - } - ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_builtname; - } - - dp = opendir(scan_el_dir); - if (dp == NULL) { - ret = -errno; - goto error_free_builtname_generic; - } - while (ent = readdir(dp), ent != NULL) - /* - * Do we allow devices to override a generic name with - * a specific one? - */ - if ((strcmp(builtname, ent->d_name) == 0) || - (strcmp(builtname_generic, ent->d_name) == 0)) { - ret = asprintf(&filename, - "%s/%s", scan_el_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_closedir; - } - sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { - printf("failed to open %s\n", filename); - ret = -errno; - goto error_free_filename; - } - - ret = fscanf(sysfsfp, - "%ce:%c%u/%u>>%u", - &endianchar, - &signchar, - bits_used, - &padint, shift); - if (ret < 0) { - printf("failed to pass scan type description\n"); - ret = -errno; - goto error_close_sysfsfp; - } - *be = (endianchar == 'b'); - *bytes = padint / 8; - if (*bits_used == 64) - *mask = ~0; - else - *mask = (1 << *bits_used) - 1; - if (signchar == 's') - *is_signed = 1; - else - *is_signed = 0; - fclose(sysfsfp); - free(filename); - - filename = 0; - sysfsfp = 0; - } -error_close_sysfsfp: - if (sysfsfp) - fclose(sysfsfp); -error_free_filename: - if (filename) - free(filename); -error_closedir: - closedir(dp); -error_free_builtname_generic: - free(builtname_generic); -error_free_builtname: - free(builtname); -error_free_scan_el_dir: - free(scan_el_dir); -error_ret: - return ret; -} - -int iioutils_get_param_float(float *output, - const char *param_name, - const char *device_dir, - const char *name, - const char *generic_name) -{ - FILE *sysfsfp; - int ret; - DIR *dp; - char *builtname, *builtname_generic; - char *filename = NULL; - const struct dirent *ent; - - ret = asprintf(&builtname, "%s_%s", name, param_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - ret = asprintf(&builtname_generic, - "%s_%s", generic_name, param_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_free_builtname; - } - dp = opendir(device_dir); - if (dp == NULL) { - ret = -errno; - goto error_free_builtname_generic; - } - while (ent = readdir(dp), ent != NULL) - if ((strcmp(builtname, ent->d_name) == 0) || - (strcmp(builtname_generic, ent->d_name) == 0)) { - ret = asprintf(&filename, - "%s/%s", device_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_closedir; - } - sysfsfp = fopen(filename, "r"); - if (!sysfsfp) { - ret = -errno; - goto error_free_filename; - } - fscanf(sysfsfp, "%f", output); - break; - } -error_free_filename: - if (filename) - free(filename); -error_closedir: - closedir(dp); -error_free_builtname_generic: - free(builtname_generic); -error_free_builtname: - free(builtname); -error_ret: - return ret; -} - -/** - * bsort_channel_array_by_index() - reorder so that the array is in index order - * - **/ - -void bsort_channel_array_by_index(struct iio_channel_info **ci_array, - int cnt) -{ - - struct iio_channel_info temp; - int x, y; - - for (x = 0; x < cnt; x++) - for (y = 0; y < (cnt - 1); y++) - if ((*ci_array)[y].index > (*ci_array)[y+1].index) { - temp = (*ci_array)[y + 1]; - (*ci_array)[y + 1] = (*ci_array)[y]; - (*ci_array)[y] = temp; - } -} - -/** - * build_channel_array() - function to figure out what channels are present - * @device_dir: the IIO device directory in sysfs - * @ - **/ -int build_channel_array(const char *device_dir, - struct iio_channel_info **ci_array, - int *counter) -{ - DIR *dp; - FILE *sysfsfp; - int count, i; - struct iio_channel_info *current; - int ret; - const struct dirent *ent; - char *scan_el_dir; - char *filename; - - *counter = 0; - ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); - if (ret < 0) { - ret = -ENOMEM; - goto error_ret; - } - dp = opendir(scan_el_dir); - if (dp == NULL) { - ret = -errno; - goto error_free_name; - } - while (ent = readdir(dp), ent != NULL) - if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), - "_en") == 0) { - ret = asprintf(&filename, - "%s/%s", scan_el_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - goto error_close_dir; - } - sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { - ret = -errno; - free(filename); - goto error_close_dir; - } - fscanf(sysfsfp, "%i", &ret); - if (ret == 1) - (*counter)++; - fclose(sysfsfp); - free(filename); - } - *ci_array = malloc(sizeof(**ci_array) * (*counter)); - if (*ci_array == NULL) { - ret = -ENOMEM; - goto error_close_dir; - } - seekdir(dp, 0); - count = 0; - while (ent = readdir(dp), ent != NULL) { - if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), - "_en") == 0) { - int current_enabled = 0; - - current = &(*ci_array)[count++]; - ret = asprintf(&filename, - "%s/%s", scan_el_dir, ent->d_name); - if (ret < 0) { - ret = -ENOMEM; - /* decrement count to avoid freeing name */ - count--; - goto error_cleanup_array; - } - sysfsfp = fopen(filename, "r"); - if (sysfsfp == NULL) { - free(filename); - ret = -errno; - goto error_cleanup_array; - } - fscanf(sysfsfp, "%i", ¤t_enabled); - fclose(sysfsfp); - - if (!current_enabled) { - free(filename); - count--; - continue; - } - - current->scale = 1.0; - current->offset = 0; - current->name = strndup(ent->d_name, - strlen(ent->d_name) - - strlen("_en")); - if (current->name == NULL) { - free(filename); - ret = -ENOMEM; - goto error_cleanup_array; - } - /* Get the generic and specific name elements */ - ret = iioutils_break_up_name(current->name, - ¤t->generic_name); - if (ret) { - free(filename); - goto error_cleanup_array; - } - ret = asprintf(&filename, - "%s/%s_index", - scan_el_dir, - current->name); - if (ret < 0) { - free(filename); - ret = -ENOMEM; - goto error_cleanup_array; - } - sysfsfp = fopen(filename, "r"); - fscanf(sysfsfp, "%u", ¤t->index); - fclose(sysfsfp); - free(filename); - /* Find the scale */ - ret = iioutils_get_param_float(¤t->scale, - "scale", - device_dir, - current->name, - current->generic_name); - if (ret < 0) - goto error_cleanup_array; - ret = iioutils_get_param_float(¤t->offset, - "offset", - device_dir, - current->name, - current->generic_name); - if (ret < 0) - goto error_cleanup_array; - ret = iioutils_get_type(¤t->is_signed, - ¤t->bytes, - ¤t->bits_used, - ¤t->shift, - ¤t->mask, - ¤t->be, - device_dir, - current->name, - current->generic_name); - } - } - - closedir(dp); - /* reorder so that the array is in index order */ - bsort_channel_array_by_index(ci_array, *counter); - - return 0; - -error_cleanup_array: - for (i = count - 1; i >= 0; i--) - free((*ci_array)[i].name); - free(*ci_array); -error_close_dir: - closedir(dp); -error_free_name: - free(scan_el_dir); -error_ret: - return ret; -} - -/** - * find_type_by_name() - function to match top level types by name - * @name: top level type instance name - * @type: the type of top level instance being sort - * - * Typical types this is used for are device and trigger. - **/ -int find_type_by_name(const char *name, const char *type) -{ - const struct dirent *ent; - int number, numstrlen; - - FILE *nameFile; - DIR *dp; - char thisname[IIO_MAX_NAME_LENGTH]; - char *filename; - - dp = opendir(iio_dir); - if (dp == NULL) { - printf("No industrialio devices available\n"); - return -ENODEV; - } - - while (ent = readdir(dp), ent != NULL) { - if (strcmp(ent->d_name, ".") != 0 && - strcmp(ent->d_name, "..") != 0 && - strlen(ent->d_name) > strlen(type) && - strncmp(ent->d_name, type, strlen(type)) == 0) { - numstrlen = sscanf(ent->d_name + strlen(type), - "%d", - &number); - /* verify the next character is not a colon */ - if (strncmp(ent->d_name + strlen(type) + numstrlen, - ":", - 1) != 0) { - filename = malloc(strlen(iio_dir) - + strlen(type) - + numstrlen - + 6); - if (filename == NULL) { - closedir(dp); - return -ENOMEM; - } - sprintf(filename, "%s%s%d/name", - iio_dir, - type, - number); - nameFile = fopen(filename, "r"); - if (!nameFile) { - free(filename); - continue; - } - free(filename); - fscanf(nameFile, "%s", thisname); - fclose(nameFile); - if (strcmp(name, thisname) == 0) { - closedir(dp); - return number; - } - } - } - } - closedir(dp); - return -ENODEV; -} - -int _write_sysfs_int(char *filename, char *basedir, int val, int verify) -{ - int ret = 0; - FILE *sysfsfp; - int test; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) - return -ENOMEM; - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "w"); - if (sysfsfp == NULL) { - printf("failed to open %s\n", temp); - ret = -errno; - goto error_free; - } - fprintf(sysfsfp, "%d", val); - fclose(sysfsfp); - if (verify) { - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - printf("failed to open %s\n", temp); - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%d", &test); - fclose(sysfsfp); - if (test != val) { - printf("Possible failure in int write %d to %s%s\n", - val, - basedir, - filename); - ret = -1; - } - } -error_free: - free(temp); - return ret; -} - -int write_sysfs_int(char *filename, char *basedir, int val) -{ - return _write_sysfs_int(filename, basedir, val, 0); -} - -int write_sysfs_int_and_verify(char *filename, char *basedir, int val) -{ - return _write_sysfs_int(filename, basedir, val, 1); -} - -int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) -{ - int ret = 0; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed\n"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "w"); - if (sysfsfp == NULL) { - printf("Could not open %s\n", temp); - ret = -errno; - goto error_free; - } - fprintf(sysfsfp, "%s", val); - fclose(sysfsfp); - if (verify) { - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - printf("could not open file to verify\n"); - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%s", temp); - fclose(sysfsfp); - if (strcmp(temp, val) != 0) { - printf("Possible failure in string write of %s " - "Should be %s " - "written to %s\%s\n", - temp, - val, - basedir, - filename); - ret = -1; - } - } -error_free: - free(temp); - - return ret; -} - -/** - * write_sysfs_string_and_verify() - string write, readback and verify - * @filename: name of file to write to - * @basedir: the sysfs directory in which the file is to be found - * @val: the string to write - **/ -int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) -{ - return _write_sysfs_string(filename, basedir, val, 1); -} - -int write_sysfs_string(char *filename, char *basedir, char *val) -{ - return _write_sysfs_string(filename, basedir, val, 0); -} - -int read_sysfs_posint(char *filename, char *basedir) -{ - int ret; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%d\n", &ret); - fclose(sysfsfp); -error_free: - free(temp); - return ret; -} - -int read_sysfs_float(char *filename, char *basedir, float *val) -{ - int ret = 0; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%f\n", val); - fclose(sysfsfp); -error_free: - free(temp); - return ret; -} - -int read_sysfs_string(const char *filename, const char *basedir, char *str) -{ - int ret = 0; - FILE *sysfsfp; - char *temp = malloc(strlen(basedir) + strlen(filename) + 2); - - if (temp == NULL) { - printf("Memory allocation failed"); - return -ENOMEM; - } - sprintf(temp, "%s/%s", basedir, filename); - sysfsfp = fopen(temp, "r"); - if (sysfsfp == NULL) { - ret = -errno; - goto error_free; - } - fscanf(sysfsfp, "%s\n", str); - fclose(sysfsfp); -error_free: - free(temp); - return ret; -} diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h deleted file mode 100644 index 1bc837b2d769..000000000000 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef _IIO_UTILS_H_ -#define _IIO_UTILS_H_ - -/* IIO - useful set of util functionality - * - * Copyright (c) 2008 Jonathan Cameron - * - * 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. - */ - -#include - -/* Made up value to limit allocation sizes */ -#define IIO_MAX_NAME_LENGTH 30 - -#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" -#define FORMAT_TYPE_FILE "%s_type" - -extern const char *iio_dir; - -/** - * struct iio_channel_info - information about a given channel - * @name: channel name - * @generic_name: general name for channel type - * @scale: scale factor to be applied for conversion to si units - * @offset: offset to be applied for conversion to si units - * @index: the channel index in the buffer output - * @bytes: number of bytes occupied in buffer output - * @mask: a bit mask for the raw output - * @is_signed: is the raw value stored signed - * @enabled: is this channel enabled - **/ -struct iio_channel_info { - char *name; - char *generic_name; - float scale; - float offset; - unsigned index; - unsigned bytes; - unsigned bits_used; - unsigned shift; - uint64_t mask; - unsigned be; - unsigned is_signed; - unsigned location; -}; - -int iioutils_break_up_name(const char *full_name, char **generic_name); -int iioutils_get_type(unsigned *is_signed, unsigned *bytes, - unsigned *bits_used, unsigned *shift, - uint64_t *mask, unsigned *be, - const char *device_dir, const char *name, - const char *generic_name); -int iioutils_get_param_float(float *output, const char *param_name, - const char *device_dir, const char *name, - const char *generic_name); -void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt); -int build_channel_array(const char *device_dir, - struct iio_channel_info **ci_array, int *counter); -int find_type_by_name(const char *name, const char *type); -int write_sysfs_int(char *filename, char *basedir, int val); -int write_sysfs_int_and_verify(char *filename, char *basedir, int val); -int write_sysfs_string_and_verify(char *filename, char *basedir, char *val); -int write_sysfs_string(char *filename, char *basedir, char *val); -int read_sysfs_posint(char *filename, char *basedir); -int read_sysfs_float(char *filename, char *basedir, float *val); -int read_sysfs_string(const char *filename, const char *basedir, char *str); - -#endif /* _IIO_UTILS_H_ */ diff --git a/drivers/staging/iio/Documentation/lsiio.c b/drivers/staging/iio/Documentation/lsiio.c deleted file mode 100644 index 98a0de098130..000000000000 --- a/drivers/staging/iio/Documentation/lsiio.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Industrial I/O utilities - lsiio.c - * - * Copyright (c) 2010 Manuel Stahl - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iio_utils.h" - - -static enum verbosity { - VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */ - VERBLEVEL_SENSORS, /* 1 lists sensors */ -} verblevel = VERBLEVEL_DEFAULT; - -const char *type_device = "iio:device"; -const char *type_trigger = "trigger"; - - -static inline int check_prefix(const char *str, const char *prefix) -{ - return strlen(str) > strlen(prefix) && - strncmp(str, prefix, strlen(prefix)) == 0; -} - -static inline int check_postfix(const char *str, const char *postfix) -{ - return strlen(str) > strlen(postfix) && - strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; -} - -static int dump_channels(const char *dev_dir_name) -{ - DIR *dp; - const struct dirent *ent; - - dp = opendir(dev_dir_name); - if (dp == NULL) - return -errno; - while (ent = readdir(dp), ent != NULL) - if (check_prefix(ent->d_name, "in_") && - check_postfix(ent->d_name, "_raw")) { - printf(" %-10s\n", ent->d_name); - } - - return 0; -} - -static int dump_one_device(const char *dev_dir_name) -{ - char name[IIO_MAX_NAME_LENGTH]; - int dev_idx; - int retval; - - retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), - "%i", &dev_idx); - if (retval != 1) - return -EINVAL; - read_sysfs_string("name", dev_dir_name, name); - printf("Device %03d: %s\n", dev_idx, name); - - if (verblevel >= VERBLEVEL_SENSORS) - return dump_channels(dev_dir_name); - return 0; -} - -static int dump_one_trigger(const char *dev_dir_name) -{ - char name[IIO_MAX_NAME_LENGTH]; - int dev_idx; - int retval; - - retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger), - "%i", &dev_idx); - if (retval != 1) - return -EINVAL; - read_sysfs_string("name", dev_dir_name, name); - printf("Trigger %03d: %s\n", dev_idx, name); - return 0; -} - -static void dump_devices(void) -{ - const struct dirent *ent; - int number, numstrlen; - - FILE *nameFile; - DIR *dp; - char thisname[IIO_MAX_NAME_LENGTH]; - char *filename; - - dp = opendir(iio_dir); - if (dp == NULL) { - printf("No industrial I/O devices available\n"); - return; - } - - while (ent = readdir(dp), ent != NULL) { - if (check_prefix(ent->d_name, type_device)) { - char *dev_dir_name; - - asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); - dump_one_device(dev_dir_name); - free(dev_dir_name); - if (verblevel >= VERBLEVEL_SENSORS) - printf("\n"); - } - } - rewinddir(dp); - while (ent = readdir(dp), ent != NULL) { - if (check_prefix(ent->d_name, type_trigger)) { - char *dev_dir_name; - - asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); - dump_one_trigger(dev_dir_name); - free(dev_dir_name); - } - } - closedir(dp); -} - -int main(int argc, char **argv) -{ - int c, err = 0; - - while ((c = getopt(argc, argv, "d:D:v")) != EOF) { - switch (c) { - case 'v': - verblevel++; - break; - - case '?': - default: - err++; - break; - } - } - if (err || argc > optind) { - fprintf(stderr, "Usage: lsiio [options]...\n" - "List industrial I/O devices\n" - " -v, --verbose\n" - " Increase verbosity (may be given multiple times)\n" - ); - exit(1); - } - - dump_devices(); - - return 0; -} diff --git a/tools/iio/Makefile b/tools/iio/Makefile new file mode 100644 index 000000000000..83813ad379f9 --- /dev/null +++ b/tools/iio/Makefile @@ -0,0 +1,16 @@ +CC = gcc +CFLAGS = -Wall -g + +all: iio_event_monitor lsiio generic_buffer + +iio_event_monitor: iio_event_monitor.o iio_utils.o + +lsiio: lsiio.o iio_utils.o + +generic_buffer: generic_buffer.o iio_utils.o + +%.o: %.c iio_utils.h + +.PHONY: clean +clean: + rm -f *.o iio_event_monitor lsiio generic_buffer diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c new file mode 100644 index 000000000000..01266c2556da --- /dev/null +++ b/tools/iio/generic_buffer.c @@ -0,0 +1,361 @@ +/* Industrialio buffer test code. + * + * Copyright (c) 2008 Jonathan Cameron + * + * 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 primarily intended as an example application. + * Reads the current buffer setup from sysfs and starts a short capture + * from the specified device, pretty printing the result after appropriate + * conversion. + * + * Command line parameters + * generic_buffer -n -t + * If trigger name is not specified the program assumes you want a dataready + * trigger associated with the device and goes looking for it. + * + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + +/** + * size_from_channelarray() - calculate the storage size of a scan + * @channels: the channel info array + * @num_channels: number of channels + * + * Has the side effect of filling the channels[i].location values used + * in processing the buffer output. + **/ +int size_from_channelarray(struct iio_channel_info *channels, int num_channels) +{ + int bytes = 0; + int i = 0; + + while (i < num_channels) { + if (bytes % channels[i].bytes == 0) + channels[i].location = bytes; + else + channels[i].location = bytes - bytes%channels[i].bytes + + channels[i].bytes; + bytes = channels[i].location + channels[i].bytes; + i++; + } + return bytes; +} + +void print2byte(int input, struct iio_channel_info *info) +{ + /* First swap if incorrect endian */ + if (info->be) + input = be16toh((uint16_t)input); + else + input = le16toh((uint16_t)input); + + /* + * Shift before conversion to avoid sign extension + * of left aligned data + */ + input = input >> info->shift; + if (info->is_signed) { + int16_t val = input; + + val &= (1 << info->bits_used) - 1; + val = (int16_t)(val << (16 - info->bits_used)) >> + (16 - info->bits_used); + printf("%05f ", ((float)val + info->offset)*info->scale); + } else { + uint16_t val = input; + + val &= (1 << info->bits_used) - 1; + printf("%05f ", ((float)val + info->offset)*info->scale); + } +} +/** + * process_scan() - print out the values in SI units + * @data: pointer to the start of the scan + * @channels: information about the channels. Note + * size_from_channelarray must have been called first to fill the + * location offsets. + * @num_channels: number of channels + **/ +void process_scan(char *data, + struct iio_channel_info *channels, + int num_channels) +{ + int k; + + for (k = 0; k < num_channels; k++) + switch (channels[k].bytes) { + /* only a few cases implemented so far */ + case 2: + print2byte(*(uint16_t *)(data + channels[k].location), + &channels[k]); + break; + case 4: + if (!channels[k].is_signed) { + uint32_t val = *(uint32_t *) + (data + channels[k].location); + printf("%05f ", ((float)val + + channels[k].offset)* + channels[k].scale); + + } + break; + case 8: + if (channels[k].is_signed) { + int64_t val = *(int64_t *) + (data + + channels[k].location); + if ((val >> channels[k].bits_used) & 1) + val = (val & channels[k].mask) | + ~channels[k].mask; + /* special case for timestamp */ + if (channels[k].scale == 1.0f && + channels[k].offset == 0.0f) + printf("%" PRId64 " ", val); + else + printf("%05f ", ((float)val + + channels[k].offset)* + channels[k].scale); + } + break; + default: + break; + } + printf("\n"); +} + +int main(int argc, char **argv) +{ + unsigned long num_loops = 2; + unsigned long timedelay = 1000000; + unsigned long buf_len = 128; + + int ret, c, i, j, toread; + int fp; + + int num_channels; + char *trigger_name = NULL, *device_name = NULL; + char *dev_dir_name, *buf_dir_name; + + int datardytrigger = 1; + char *data; + ssize_t read_size; + int dev_num, trig_num; + char *buffer_access; + int scan_size; + int noevents = 0; + int notrigger = 0; + char *dummy; + + struct iio_channel_info *channels; + + while ((c = getopt(argc, argv, "l:w:c:et:n:g")) != -1) { + switch (c) { + case 'n': + device_name = optarg; + break; + case 't': + trigger_name = optarg; + datardytrigger = 0; + break; + case 'e': + noevents = 1; + break; + case 'c': + num_loops = strtoul(optarg, &dummy, 10); + break; + case 'w': + timedelay = strtoul(optarg, &dummy, 10); + break; + case 'l': + buf_len = strtoul(optarg, &dummy, 10); + break; + case 'g': + notrigger = 1; + break; + case '?': + return -1; + } + } + + if (device_name == NULL) + return -1; + + /* Find the device requested */ + dev_num = find_type_by_name(device_name, "iio:device"); + if (dev_num < 0) { + printf("Failed to find the %s\n", device_name); + ret = -ENODEV; + goto error_ret; + } + printf("iio device number being used is %d\n", dev_num); + + asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); + + if (!notrigger) { + if (trigger_name == NULL) { + /* + * Build the trigger name. If it is device associated + * its name is _dev[n] where n matches + * the device number found above. + */ + ret = asprintf(&trigger_name, + "%s-dev%d", device_name, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + } + + /* Verify the trigger exists */ + trig_num = find_type_by_name(trigger_name, "trigger"); + if (trig_num < 0) { + printf("Failed to find the trigger %s\n", trigger_name); + ret = -ENODEV; + goto error_free_triggername; + } + printf("iio trigger number being used is %d\n", trig_num); + } else + printf("trigger-less mode selected\n"); + + /* + * Parse the files in scan_elements to identify what channels are + * present + */ + ret = build_channel_array(dev_dir_name, &channels, &num_channels); + if (ret) { + printf("Problem reading scan element information\n"); + printf("diag %s\n", dev_dir_name); + goto error_free_triggername; + } + + /* + * Construct the directory name for the associated buffer. + * As we know that the lis3l02dq has only one buffer this may + * be built rather than found. + */ + ret = asprintf(&buf_dir_name, + "%siio:device%d/buffer", iio_dir, dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_triggername; + } + + if (!notrigger) { + printf("%s %s\n", dev_dir_name, trigger_name); + /* Set the device trigger to be the data ready trigger found + * above */ + ret = write_sysfs_string_and_verify("trigger/current_trigger", + dev_dir_name, + trigger_name); + if (ret < 0) { + printf("Failed to write current_trigger file\n"); + goto error_free_buf_dir_name; + } + } + + /* Setup ring buffer parameters */ + ret = write_sysfs_int("length", buf_dir_name, buf_len); + if (ret < 0) + goto error_free_buf_dir_name; + + /* Enable the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 1); + if (ret < 0) + goto error_free_buf_dir_name; + scan_size = size_from_channelarray(channels, num_channels); + data = malloc(scan_size*buf_len); + if (!data) { + ret = -ENOMEM; + goto error_free_buf_dir_name; + } + + ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_data; + } + + /* Attempt to open non blocking the access dev */ + fp = open(buffer_access, O_RDONLY | O_NONBLOCK); + if (fp == -1) { /* If it isn't there make the node */ + printf("Failed to open %s\n", buffer_access); + ret = -errno; + goto error_free_buffer_access; + } + + /* Wait for events 10 times */ + for (j = 0; j < num_loops; j++) { + if (!noevents) { + struct pollfd pfd = { + .fd = fp, + .events = POLLIN, + }; + + poll(&pfd, 1, -1); + toread = buf_len; + + } else { + usleep(timedelay); + toread = 64; + } + + read_size = read(fp, + data, + toread*scan_size); + if (read_size < 0) { + if (errno == -EAGAIN) { + printf("nothing available\n"); + continue; + } else + break; + } + for (i = 0; i < read_size/scan_size; i++) + process_scan(data + scan_size*i, + channels, + num_channels); + } + + /* Stop the buffer */ + ret = write_sysfs_int("enable", buf_dir_name, 0); + if (ret < 0) + goto error_close_buffer_access; + + if (!notrigger) + /* Disconnect the trigger - just write a dummy name. */ + write_sysfs_string("trigger/current_trigger", + dev_dir_name, "NULL"); + +error_close_buffer_access: + close(fp); +error_free_data: + free(data); +error_free_buffer_access: + free(buffer_access); +error_free_buf_dir_name: + free(buf_dir_name); +error_free_triggername: + if (datardytrigger) + free(trigger_name); +error_ret: + return ret; +} diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c new file mode 100644 index 000000000000..f19cff19900e --- /dev/null +++ b/tools/iio/iio_event_monitor.c @@ -0,0 +1,310 @@ +/* Industrialio event test code. + * + * Copyright (c) 2011-2012 Lars-Peter Clausen + * + * 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 primarily intended as an example application. + * Reads the current buffer setup from sysfs and starts a short capture + * from the specified device, pretty printing the result after appropriate + * conversion. + * + * Usage: + * iio_event_monitor + * + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" +#include +#include + +static const char * const iio_chan_type_name_spec[] = { + [IIO_VOLTAGE] = "voltage", + [IIO_CURRENT] = "current", + [IIO_POWER] = "power", + [IIO_ACCEL] = "accel", + [IIO_ANGL_VEL] = "anglvel", + [IIO_MAGN] = "magn", + [IIO_LIGHT] = "illuminance", + [IIO_INTENSITY] = "intensity", + [IIO_PROXIMITY] = "proximity", + [IIO_TEMP] = "temp", + [IIO_INCLI] = "incli", + [IIO_ROT] = "rot", + [IIO_ANGL] = "angl", + [IIO_TIMESTAMP] = "timestamp", + [IIO_CAPACITANCE] = "capacitance", + [IIO_ALTVOLTAGE] = "altvoltage", + [IIO_CCT] = "cct", + [IIO_PRESSURE] = "pressure", + [IIO_HUMIDITYRELATIVE] = "humidityrelative", + [IIO_ACTIVITY] = "activity", + [IIO_STEPS] = "steps", +}; + +static const char * const iio_ev_type_text[] = { + [IIO_EV_TYPE_THRESH] = "thresh", + [IIO_EV_TYPE_MAG] = "mag", + [IIO_EV_TYPE_ROC] = "roc", + [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", + [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", + [IIO_EV_TYPE_CHANGE] = "change", +}; + +static const char * const iio_ev_dir_text[] = { + [IIO_EV_DIR_EITHER] = "either", + [IIO_EV_DIR_RISING] = "rising", + [IIO_EV_DIR_FALLING] = "falling" +}; + +static const char * const iio_modifier_names[] = { + [IIO_MOD_X] = "x", + [IIO_MOD_Y] = "y", + [IIO_MOD_Z] = "z", + [IIO_MOD_X_AND_Y] = "x&y", + [IIO_MOD_X_AND_Z] = "x&z", + [IIO_MOD_Y_AND_Z] = "y&z", + [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z", + [IIO_MOD_X_OR_Y] = "x|y", + [IIO_MOD_X_OR_Z] = "x|z", + [IIO_MOD_Y_OR_Z] = "y|z", + [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z", + [IIO_MOD_LIGHT_BOTH] = "both", + [IIO_MOD_LIGHT_IR] = "ir", + [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", + [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", + [IIO_MOD_LIGHT_CLEAR] = "clear", + [IIO_MOD_LIGHT_RED] = "red", + [IIO_MOD_LIGHT_GREEN] = "green", + [IIO_MOD_LIGHT_BLUE] = "blue", + [IIO_MOD_QUATERNION] = "quaternion", + [IIO_MOD_TEMP_AMBIENT] = "ambient", + [IIO_MOD_TEMP_OBJECT] = "object", + [IIO_MOD_NORTH_MAGN] = "from_north_magnetic", + [IIO_MOD_NORTH_TRUE] = "from_north_true", + [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp", + [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp", + [IIO_MOD_RUNNING] = "running", + [IIO_MOD_JOGGING] = "jogging", + [IIO_MOD_WALKING] = "walking", + [IIO_MOD_STILL] = "still", +}; + +static bool event_is_known(struct iio_event_data *event) +{ + enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); + enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); + enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); + enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); + + switch (type) { + case IIO_VOLTAGE: + case IIO_CURRENT: + case IIO_POWER: + case IIO_ACCEL: + case IIO_ANGL_VEL: + case IIO_MAGN: + case IIO_LIGHT: + case IIO_INTENSITY: + case IIO_PROXIMITY: + case IIO_TEMP: + case IIO_INCLI: + case IIO_ROT: + case IIO_ANGL: + case IIO_TIMESTAMP: + case IIO_CAPACITANCE: + case IIO_ALTVOLTAGE: + case IIO_CCT: + case IIO_PRESSURE: + case IIO_HUMIDITYRELATIVE: + case IIO_ACTIVITY: + case IIO_STEPS: + break; + default: + return false; + } + + switch (mod) { + case IIO_NO_MOD: + case IIO_MOD_X: + case IIO_MOD_Y: + case IIO_MOD_Z: + case IIO_MOD_X_AND_Y: + case IIO_MOD_X_AND_Z: + case IIO_MOD_Y_AND_Z: + case IIO_MOD_X_AND_Y_AND_Z: + case IIO_MOD_X_OR_Y: + case IIO_MOD_X_OR_Z: + case IIO_MOD_Y_OR_Z: + case IIO_MOD_X_OR_Y_OR_Z: + case IIO_MOD_LIGHT_BOTH: + case IIO_MOD_LIGHT_IR: + case IIO_MOD_ROOT_SUM_SQUARED_X_Y: + case IIO_MOD_SUM_SQUARED_X_Y_Z: + case IIO_MOD_LIGHT_CLEAR: + case IIO_MOD_LIGHT_RED: + case IIO_MOD_LIGHT_GREEN: + case IIO_MOD_LIGHT_BLUE: + case IIO_MOD_QUATERNION: + case IIO_MOD_TEMP_AMBIENT: + case IIO_MOD_TEMP_OBJECT: + case IIO_MOD_NORTH_MAGN: + case IIO_MOD_NORTH_TRUE: + case IIO_MOD_NORTH_MAGN_TILT_COMP: + case IIO_MOD_NORTH_TRUE_TILT_COMP: + case IIO_MOD_RUNNING: + case IIO_MOD_JOGGING: + case IIO_MOD_WALKING: + case IIO_MOD_STILL: + break; + default: + return false; + } + + switch (ev_type) { + case IIO_EV_TYPE_THRESH: + case IIO_EV_TYPE_MAG: + case IIO_EV_TYPE_ROC: + case IIO_EV_TYPE_THRESH_ADAPTIVE: + case IIO_EV_TYPE_MAG_ADAPTIVE: + case IIO_EV_TYPE_CHANGE: + break; + default: + return false; + } + + switch (dir) { + case IIO_EV_DIR_EITHER: + case IIO_EV_DIR_RISING: + case IIO_EV_DIR_FALLING: + case IIO_EV_DIR_NONE: + break; + default: + return false; + } + + return true; +} + +static void print_event(struct iio_event_data *event) +{ + enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); + enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); + enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); + enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); + int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id); + int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id); + bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id); + + if (!event_is_known(event)) { + printf("Unknown event: time: %lld, id: %llx\n", + event->timestamp, event->id); + return; + } + + printf("Event: time: %lld, ", event->timestamp); + + if (mod != IIO_NO_MOD) { + printf("type: %s(%s), ", + iio_chan_type_name_spec[type], + iio_modifier_names[mod]); + } else { + printf("type: %s, ", + iio_chan_type_name_spec[type]); + } + + if (diff && chan >= 0 && chan2 >= 0) + printf("channel: %d-%d, ", chan, chan2); + else if (chan >= 0) + printf("channel: %d, ", chan); + + printf("evtype: %s", iio_ev_type_text[ev_type]); + + if (dir != IIO_EV_DIR_NONE) + printf(", direction: %s", iio_ev_dir_text[dir]); + printf("\n"); +} + +int main(int argc, char **argv) +{ + struct iio_event_data event; + const char *device_name; + char *chrdev_name; + int ret; + int dev_num; + int fd, event_fd; + + if (argc <= 1) { + printf("Usage: %s \n", argv[0]); + return -1; + } + + device_name = argv[1]; + + dev_num = find_type_by_name(device_name, "iio:device"); + if (dev_num >= 0) { + printf("Found IIO device with name %s with device number %d\n", + device_name, dev_num); + ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + } else { + /* If we can't find a IIO device by name assume device_name is a + IIO chrdev */ + chrdev_name = strdup(device_name); + } + + fd = open(chrdev_name, 0); + if (fd == -1) { + fprintf(stdout, "Failed to open %s\n", chrdev_name); + ret = -errno; + goto error_free_chrdev_name; + } + + ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); + + close(fd); + + if (ret == -1 || event_fd == -1) { + fprintf(stdout, "Failed to retrieve event fd\n"); + ret = -errno; + goto error_free_chrdev_name; + } + + while (true) { + ret = read(event_fd, &event, sizeof(event)); + if (ret == -1) { + if (errno == EAGAIN) { + printf("nothing available\n"); + continue; + } else { + perror("Failed to read event from device"); + ret = -errno; + break; + } + } + + print_event(&event); + } + + close(event_fd); +error_free_chrdev_name: + free(chrdev_name); +error_ret: + return ret; +} diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c new file mode 100644 index 000000000000..aea928210187 --- /dev/null +++ b/tools/iio/iio_utils.c @@ -0,0 +1,651 @@ +/* IIO - useful set of util functionality + * + * Copyright (c) 2008 Jonathan Cameron + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + +const char *iio_dir = "/sys/bus/iio/devices/"; + +/** + * iioutils_break_up_name() - extract generic name from full channel name + * @full_name: the full channel name + * @generic_name: the output generic channel name + **/ +int iioutils_break_up_name(const char *full_name, + char **generic_name) +{ + char *current; + char *w, *r; + char *working; + + current = strdup(full_name); + working = strtok(current, "_\0"); + w = working; + r = working; + + while (*r != '\0') { + if (!isdigit(*r)) { + *w = *r; + w++; + } + r++; + } + *w = '\0'; + *generic_name = strdup(working); + free(current); + + return 0; +} + +/** + * iioutils_get_type() - find and process _type attribute data + * @is_signed: output whether channel is signed + * @bytes: output how many bytes the channel storage occupies + * @mask: output a bit mask for the raw data + * @be: big endian + * @device_dir: the iio device directory + * @name: the channel name + * @generic_name: the channel type name + **/ +int iioutils_get_type(unsigned *is_signed, + unsigned *bytes, + unsigned *bits_used, + unsigned *shift, + uint64_t *mask, + unsigned *be, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; + char signchar, endianchar; + unsigned padint; + const struct dirent *ent; + + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_scan_el_dir; + } + ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + /* + * Do we allow devices to override a generic name with + * a specific one? + */ + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", filename); + ret = -errno; + goto error_free_filename; + } + + ret = fscanf(sysfsfp, + "%ce:%c%u/%u>>%u", + &endianchar, + &signchar, + bits_used, + &padint, shift); + if (ret < 0) { + printf("failed to pass scan type description\n"); + ret = -errno; + goto error_close_sysfsfp; + } + *be = (endianchar == 'b'); + *bytes = padint / 8; + if (*bits_used == 64) + *mask = ~0; + else + *mask = (1 << *bits_used) - 1; + if (signchar == 's') + *is_signed = 1; + else + *is_signed = 0; + fclose(sysfsfp); + free(filename); + + filename = 0; + sysfsfp = 0; + } +error_close_sysfsfp: + if (sysfsfp) + fclose(sysfsfp); +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_free_scan_el_dir: + free(scan_el_dir); +error_ret: + return ret; +} + +int iioutils_get_param_float(float *output, + const char *param_name, + const char *device_dir, + const char *name, + const char *generic_name) +{ + FILE *sysfsfp; + int ret; + DIR *dp; + char *builtname, *builtname_generic; + char *filename = NULL; + const struct dirent *ent; + + ret = asprintf(&builtname, "%s_%s", name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + ret = asprintf(&builtname_generic, + "%s_%s", generic_name, param_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_free_builtname; + } + dp = opendir(device_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_builtname_generic; + } + while (ent = readdir(dp), ent != NULL) + if ((strcmp(builtname, ent->d_name) == 0) || + (strcmp(builtname_generic, ent->d_name) == 0)) { + ret = asprintf(&filename, + "%s/%s", device_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_closedir; + } + sysfsfp = fopen(filename, "r"); + if (!sysfsfp) { + ret = -errno; + goto error_free_filename; + } + fscanf(sysfsfp, "%f", output); + break; + } +error_free_filename: + if (filename) + free(filename); +error_closedir: + closedir(dp); +error_free_builtname_generic: + free(builtname_generic); +error_free_builtname: + free(builtname); +error_ret: + return ret; +} + +/** + * bsort_channel_array_by_index() - reorder so that the array is in index order + * + **/ + +void bsort_channel_array_by_index(struct iio_channel_info **ci_array, + int cnt) +{ + + struct iio_channel_info temp; + int x, y; + + for (x = 0; x < cnt; x++) + for (y = 0; y < (cnt - 1); y++) + if ((*ci_array)[y].index > (*ci_array)[y+1].index) { + temp = (*ci_array)[y + 1]; + (*ci_array)[y + 1] = (*ci_array)[y]; + (*ci_array)[y] = temp; + } +} + +/** + * build_channel_array() - function to figure out what channels are present + * @device_dir: the IIO device directory in sysfs + * @ + **/ +int build_channel_array(const char *device_dir, + struct iio_channel_info **ci_array, + int *counter) +{ + DIR *dp; + FILE *sysfsfp; + int count, i; + struct iio_channel_info *current; + int ret; + const struct dirent *ent; + char *scan_el_dir; + char *filename; + + *counter = 0; + ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); + if (ret < 0) { + ret = -ENOMEM; + goto error_ret; + } + dp = opendir(scan_el_dir); + if (dp == NULL) { + ret = -errno; + goto error_free_name; + } + while (ent = readdir(dp), ent != NULL) + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + goto error_close_dir; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + ret = -errno; + free(filename); + goto error_close_dir; + } + fscanf(sysfsfp, "%i", &ret); + if (ret == 1) + (*counter)++; + fclose(sysfsfp); + free(filename); + } + *ci_array = malloc(sizeof(**ci_array) * (*counter)); + if (*ci_array == NULL) { + ret = -ENOMEM; + goto error_close_dir; + } + seekdir(dp, 0); + count = 0; + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), + "_en") == 0) { + int current_enabled = 0; + + current = &(*ci_array)[count++]; + ret = asprintf(&filename, + "%s/%s", scan_el_dir, ent->d_name); + if (ret < 0) { + ret = -ENOMEM; + /* decrement count to avoid freeing name */ + count--; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + if (sysfsfp == NULL) { + free(filename); + ret = -errno; + goto error_cleanup_array; + } + fscanf(sysfsfp, "%i", ¤t_enabled); + fclose(sysfsfp); + + if (!current_enabled) { + free(filename); + count--; + continue; + } + + current->scale = 1.0; + current->offset = 0; + current->name = strndup(ent->d_name, + strlen(ent->d_name) - + strlen("_en")); + if (current->name == NULL) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + /* Get the generic and specific name elements */ + ret = iioutils_break_up_name(current->name, + ¤t->generic_name); + if (ret) { + free(filename); + goto error_cleanup_array; + } + ret = asprintf(&filename, + "%s/%s_index", + scan_el_dir, + current->name); + if (ret < 0) { + free(filename); + ret = -ENOMEM; + goto error_cleanup_array; + } + sysfsfp = fopen(filename, "r"); + fscanf(sysfsfp, "%u", ¤t->index); + fclose(sysfsfp); + free(filename); + /* Find the scale */ + ret = iioutils_get_param_float(¤t->scale, + "scale", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_param_float(¤t->offset, + "offset", + device_dir, + current->name, + current->generic_name); + if (ret < 0) + goto error_cleanup_array; + ret = iioutils_get_type(¤t->is_signed, + ¤t->bytes, + ¤t->bits_used, + ¤t->shift, + ¤t->mask, + ¤t->be, + device_dir, + current->name, + current->generic_name); + } + } + + closedir(dp); + /* reorder so that the array is in index order */ + bsort_channel_array_by_index(ci_array, *counter); + + return 0; + +error_cleanup_array: + for (i = count - 1; i >= 0; i--) + free((*ci_array)[i].name); + free(*ci_array); +error_close_dir: + closedir(dp); +error_free_name: + free(scan_el_dir); +error_ret: + return ret; +} + +/** + * find_type_by_name() - function to match top level types by name + * @name: top level type instance name + * @type: the type of top level instance being sort + * + * Typical types this is used for are device and trigger. + **/ +int find_type_by_name(const char *name, const char *type) +{ + const struct dirent *ent; + int number, numstrlen; + + FILE *nameFile; + DIR *dp; + char thisname[IIO_MAX_NAME_LENGTH]; + char *filename; + + dp = opendir(iio_dir); + if (dp == NULL) { + printf("No industrialio devices available\n"); + return -ENODEV; + } + + while (ent = readdir(dp), ent != NULL) { + if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0 && + strlen(ent->d_name) > strlen(type) && + strncmp(ent->d_name, type, strlen(type)) == 0) { + numstrlen = sscanf(ent->d_name + strlen(type), + "%d", + &number); + /* verify the next character is not a colon */ + if (strncmp(ent->d_name + strlen(type) + numstrlen, + ":", + 1) != 0) { + filename = malloc(strlen(iio_dir) + + strlen(type) + + numstrlen + + 6); + if (filename == NULL) { + closedir(dp); + return -ENOMEM; + } + sprintf(filename, "%s%s%d/name", + iio_dir, + type, + number); + nameFile = fopen(filename, "r"); + if (!nameFile) { + free(filename); + continue; + } + free(filename); + fscanf(nameFile, "%s", thisname); + fclose(nameFile); + if (strcmp(name, thisname) == 0) { + closedir(dp); + return number; + } + } + } + } + closedir(dp); + return -ENODEV; +} + +int _write_sysfs_int(char *filename, char *basedir, int val, int verify) +{ + int ret = 0; + FILE *sysfsfp; + int test; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) + return -ENOMEM; + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "w"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", temp); + ret = -errno; + goto error_free; + } + fprintf(sysfsfp, "%d", val); + fclose(sysfsfp); + if (verify) { + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + printf("failed to open %s\n", temp); + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%d", &test); + fclose(sysfsfp); + if (test != val) { + printf("Possible failure in int write %d to %s%s\n", + val, + basedir, + filename); + ret = -1; + } + } +error_free: + free(temp); + return ret; +} + +int write_sysfs_int(char *filename, char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 0); +} + +int write_sysfs_int_and_verify(char *filename, char *basedir, int val) +{ + return _write_sysfs_int(filename, basedir, val, 1); +} + +int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed\n"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "w"); + if (sysfsfp == NULL) { + printf("Could not open %s\n", temp); + ret = -errno; + goto error_free; + } + fprintf(sysfsfp, "%s", val); + fclose(sysfsfp); + if (verify) { + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + printf("could not open file to verify\n"); + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%s", temp); + fclose(sysfsfp); + if (strcmp(temp, val) != 0) { + printf("Possible failure in string write of %s " + "Should be %s " + "written to %s\%s\n", + temp, + val, + basedir, + filename); + ret = -1; + } + } +error_free: + free(temp); + + return ret; +} + +/** + * write_sysfs_string_and_verify() - string write, readback and verify + * @filename: name of file to write to + * @basedir: the sysfs directory in which the file is to be found + * @val: the string to write + **/ +int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) +{ + return _write_sysfs_string(filename, basedir, val, 1); +} + +int write_sysfs_string(char *filename, char *basedir, char *val) +{ + return _write_sysfs_string(filename, basedir, val, 0); +} + +int read_sysfs_posint(char *filename, char *basedir) +{ + int ret; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%d\n", &ret); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} + +int read_sysfs_float(char *filename, char *basedir, float *val) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%f\n", val); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} + +int read_sysfs_string(const char *filename, const char *basedir, char *str) +{ + int ret = 0; + FILE *sysfsfp; + char *temp = malloc(strlen(basedir) + strlen(filename) + 2); + + if (temp == NULL) { + printf("Memory allocation failed"); + return -ENOMEM; + } + sprintf(temp, "%s/%s", basedir, filename); + sysfsfp = fopen(temp, "r"); + if (sysfsfp == NULL) { + ret = -errno; + goto error_free; + } + fscanf(sysfsfp, "%s\n", str); + fclose(sysfsfp); +error_free: + free(temp); + return ret; +} diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h new file mode 100644 index 000000000000..1bc837b2d769 --- /dev/null +++ b/tools/iio/iio_utils.h @@ -0,0 +1,71 @@ +#ifndef _IIO_UTILS_H_ +#define _IIO_UTILS_H_ + +/* IIO - useful set of util functionality + * + * Copyright (c) 2008 Jonathan Cameron + * + * 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. + */ + +#include + +/* Made up value to limit allocation sizes */ +#define IIO_MAX_NAME_LENGTH 30 + +#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" +#define FORMAT_TYPE_FILE "%s_type" + +extern const char *iio_dir; + +/** + * struct iio_channel_info - information about a given channel + * @name: channel name + * @generic_name: general name for channel type + * @scale: scale factor to be applied for conversion to si units + * @offset: offset to be applied for conversion to si units + * @index: the channel index in the buffer output + * @bytes: number of bytes occupied in buffer output + * @mask: a bit mask for the raw output + * @is_signed: is the raw value stored signed + * @enabled: is this channel enabled + **/ +struct iio_channel_info { + char *name; + char *generic_name; + float scale; + float offset; + unsigned index; + unsigned bytes; + unsigned bits_used; + unsigned shift; + uint64_t mask; + unsigned be; + unsigned is_signed; + unsigned location; +}; + +int iioutils_break_up_name(const char *full_name, char **generic_name); +int iioutils_get_type(unsigned *is_signed, unsigned *bytes, + unsigned *bits_used, unsigned *shift, + uint64_t *mask, unsigned *be, + const char *device_dir, const char *name, + const char *generic_name); +int iioutils_get_param_float(float *output, const char *param_name, + const char *device_dir, const char *name, + const char *generic_name); +void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt); +int build_channel_array(const char *device_dir, + struct iio_channel_info **ci_array, int *counter); +int find_type_by_name(const char *name, const char *type); +int write_sysfs_int(char *filename, char *basedir, int val); +int write_sysfs_int_and_verify(char *filename, char *basedir, int val); +int write_sysfs_string_and_verify(char *filename, char *basedir, char *val); +int write_sysfs_string(char *filename, char *basedir, char *val); +int read_sysfs_posint(char *filename, char *basedir); +int read_sysfs_float(char *filename, char *basedir, float *val); +int read_sysfs_string(const char *filename, const char *basedir, char *str); + +#endif /* _IIO_UTILS_H_ */ diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c new file mode 100644 index 000000000000..98a0de098130 --- /dev/null +++ b/tools/iio/lsiio.c @@ -0,0 +1,163 @@ +/* + * Industrial I/O utilities - lsiio.c + * + * Copyright (c) 2010 Manuel Stahl + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iio_utils.h" + + +static enum verbosity { + VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */ + VERBLEVEL_SENSORS, /* 1 lists sensors */ +} verblevel = VERBLEVEL_DEFAULT; + +const char *type_device = "iio:device"; +const char *type_trigger = "trigger"; + + +static inline int check_prefix(const char *str, const char *prefix) +{ + return strlen(str) > strlen(prefix) && + strncmp(str, prefix, strlen(prefix)) == 0; +} + +static inline int check_postfix(const char *str, const char *postfix) +{ + return strlen(str) > strlen(postfix) && + strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; +} + +static int dump_channels(const char *dev_dir_name) +{ + DIR *dp; + const struct dirent *ent; + + dp = opendir(dev_dir_name); + if (dp == NULL) + return -errno; + while (ent = readdir(dp), ent != NULL) + if (check_prefix(ent->d_name, "in_") && + check_postfix(ent->d_name, "_raw")) { + printf(" %-10s\n", ent->d_name); + } + + return 0; +} + +static int dump_one_device(const char *dev_dir_name) +{ + char name[IIO_MAX_NAME_LENGTH]; + int dev_idx; + int retval; + + retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), + "%i", &dev_idx); + if (retval != 1) + return -EINVAL; + read_sysfs_string("name", dev_dir_name, name); + printf("Device %03d: %s\n", dev_idx, name); + + if (verblevel >= VERBLEVEL_SENSORS) + return dump_channels(dev_dir_name); + return 0; +} + +static int dump_one_trigger(const char *dev_dir_name) +{ + char name[IIO_MAX_NAME_LENGTH]; + int dev_idx; + int retval; + + retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger), + "%i", &dev_idx); + if (retval != 1) + return -EINVAL; + read_sysfs_string("name", dev_dir_name, name); + printf("Trigger %03d: %s\n", dev_idx, name); + return 0; +} + +static void dump_devices(void) +{ + const struct dirent *ent; + int number, numstrlen; + + FILE *nameFile; + DIR *dp; + char thisname[IIO_MAX_NAME_LENGTH]; + char *filename; + + dp = opendir(iio_dir); + if (dp == NULL) { + printf("No industrial I/O devices available\n"); + return; + } + + while (ent = readdir(dp), ent != NULL) { + if (check_prefix(ent->d_name, type_device)) { + char *dev_dir_name; + + asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); + dump_one_device(dev_dir_name); + free(dev_dir_name); + if (verblevel >= VERBLEVEL_SENSORS) + printf("\n"); + } + } + rewinddir(dp); + while (ent = readdir(dp), ent != NULL) { + if (check_prefix(ent->d_name, type_trigger)) { + char *dev_dir_name; + + asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); + dump_one_trigger(dev_dir_name); + free(dev_dir_name); + } + } + closedir(dp); +} + +int main(int argc, char **argv) +{ + int c, err = 0; + + while ((c = getopt(argc, argv, "d:D:v")) != EOF) { + switch (c) { + case 'v': + verblevel++; + break; + + case '?': + default: + err++; + break; + } + } + if (err || argc > optind) { + fprintf(stderr, "Usage: lsiio [options]...\n" + "List industrial I/O devices\n" + " -v, --verbose\n" + " Increase verbosity (may be given multiple times)\n" + ); + exit(1); + } + + dump_devices(); + + return 0; +} -- cgit v1.2.3 From ab280024e3c0c4633066e9698756a28a9caf26a1 Mon Sep 17 00:00:00 2001 From: Søren Andersen Date: Tue, 10 Mar 2015 22:12:07 +0100 Subject: iio: adc: Kconfig mcp320x change description Add more ADCs Bring the Kconfig entry up to date with parts supported by the driver. Signed-off-by: Soeren Andersen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 202daf889be2..9eaa8d1e582d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -186,10 +186,11 @@ config MAX1363 data via the iio dev interface. config MCP320X - tristate "Microchip Technology MCP3204/08" + tristate "Microchip Technology MCP3x01/02/04/08" depends on SPI help - Say yes here to build support for Microchip Technology's MCP3204 or + Say yes here to build support for Microchip Technology's + MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204 or MCP3208 analog to digital converter. This driver can also be built as a module. If so, the module will be -- cgit v1.2.3 From 3e825ec98d36c8c8073024c95853389a831902e5 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Tue, 3 Mar 2015 18:17:57 +0200 Subject: iio: bmc150: introduce bmc150_accel_interrupt Since both triggers and events can share an interrupt, add a data structure that tracks the users of an interrupt so that it enables or disables it only for the first users and respectively last user. This will allows us to easily add more events or triggers. The patch also adds an interrupt enabled counter, so that we can easily know if we need to put the device in normal mode when the resume callback is issued. Signed-off-by: Octavian Purdila Reviewed-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 86 ++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 46ac9659e2aa..db95237888ae 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -147,10 +147,24 @@ struct bmc150_accel_chip_info { const struct bmc150_scale_info scale_table[4]; }; +struct bmc150_accel_interrupt { + const struct bmc150_accel_interrupt_info *info; + atomic_t users; +}; + +enum bmc150_accel_interrupt_id { + BMC150_ACCEL_INT_DATA_READY, + BMC150_ACCEL_INT_ANY_MOTION, + BMC150_ACCEL_INT_WATERMARK, + BMC150_ACCEL_INTERRUPTS, +}; + struct bmc150_accel_data { struct i2c_client *client; + struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; struct iio_trigger *dready_trig; struct iio_trigger *motion_trig; + atomic_t active_intr; struct mutex mutex; s16 buffer[8]; u8 bw_bits; @@ -421,7 +435,7 @@ static const struct bmc150_accel_interrupt_info { u8 map_bitmask; u8 en_reg; u8 en_bitmask; -} bmc150_accel_interrupts[] = { +} bmc150_accel_interrupts[BMC150_ACCEL_INTERRUPTS] = { { /* data ready interrupt */ .map_reg = BMC150_ACCEL_REG_INT_MAP_1, .map_bitmask = BMC150_ACCEL_INT_MAP_1_BIT_DATA, @@ -438,12 +452,30 @@ static const struct bmc150_accel_interrupt_info { }, }; -static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, - const struct bmc150_accel_interrupt_info *info, +static void bmc150_accel_interrupts_setup(struct iio_dev *indio_dev, + struct bmc150_accel_data *data) +{ + int i; + + for (i = 0; i < BMC150_ACCEL_INTERRUPTS; i++) + data->interrupts[i].info = &bmc150_accel_interrupts[i]; +} + +static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, int i, bool state) { + struct bmc150_accel_interrupt *intr = &data->interrupts[i]; + const struct bmc150_accel_interrupt_info *info = intr->info; int ret; + if (state) { + if (atomic_inc_return(&intr->users) > 1) + return 0; + } else { + if (atomic_dec_return(&intr->users) > 0) + return 0; + } + /* * We will expect the enable and disable to do operation in * in reverse order. This will happen here anyway as our @@ -493,6 +525,11 @@ static int bmc150_accel_set_interrupt(struct bmc150_accel_data *data, goto out_fix_power_state; } + if (state) + atomic_inc(&data->active_intr); + else + atomic_dec(&data->active_intr); + return 0; out_fix_power_state: @@ -500,20 +537,6 @@ out_fix_power_state: return ret; } -static int bmc150_accel_setup_any_motion_interrupt( - struct bmc150_accel_data *data, - bool status) -{ - return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[1], - status); -} - -static int bmc150_accel_setup_new_data_interrupt(struct bmc150_accel_data *data, - bool status) -{ - return bmc150_accel_set_interrupt(data, &bmc150_accel_interrupts[0], - status); -} static int bmc150_accel_set_scale(struct bmc150_accel_data *data, int val) { @@ -753,13 +776,8 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev, mutex_lock(&data->mutex); - if (!state && data->motion_trigger_on) { - data->ev_enable_state = 0; - mutex_unlock(&data->mutex); - return 0; - } - - ret = bmc150_accel_setup_any_motion_interrupt(data, state); + ret = bmc150_accel_set_interrupt(data, BMC150_ACCEL_INT_ANY_MOTION, + state); if (ret < 0) { mutex_unlock(&data->mutex); return ret; @@ -996,19 +1014,16 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, } } - if (!state && data->ev_enable_state && data->motion_trigger_on) { - data->motion_trigger_on = false; - mutex_unlock(&data->mutex); - return 0; - } - if (data->motion_trig == trig) { ret = bmc150_accel_update_slope(data); if (!ret) - ret = bmc150_accel_setup_any_motion_interrupt(data, - state); + ret = bmc150_accel_set_interrupt(data, + BMC150_ACCEL_INT_ANY_MOTION, + state); } else { - ret = bmc150_accel_setup_new_data_interrupt(data, state); + ret = bmc150_accel_set_interrupt(data, + BMC150_ACCEL_INT_DATA_READY, + state); } if (ret < 0) { mutex_unlock(&data->mutex); @@ -1206,6 +1221,8 @@ static int bmc150_accel_probe(struct i2c_client *client, return ret; } + bmc150_accel_interrupts_setup(indio_dev, data); + data->dready_trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", indio_dev->name, @@ -1321,8 +1338,7 @@ static int bmc150_accel_resume(struct device *dev) struct bmc150_accel_data *data = iio_priv(indio_dev); mutex_lock(&data->mutex); - if (data->dready_trigger_on || data->motion_trigger_on || - data->ev_enable_state) + if (atomic_read(&data->active_intr)) bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_NORMAL, 0); mutex_unlock(&data->mutex); -- cgit v1.2.3 From 7d963215f6bedd268fa26aadd4ca4270e1076566 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Tue, 3 Mar 2015 18:17:58 +0200 Subject: iio: bmc150: introduce bmc150_accel_trigger Add a separate structure for triggers and add the infrastructure to support an arbitrary number of triggers. Each trigger is associated with an interrupt and has an enabled/disabled state. Signed-off-by: Octavian Purdila Acked-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/bmc150-accel.c | 204 ++++++++++++++++++++++++--------------- 1 file changed, 125 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index db95237888ae..f1b80c4c0b35 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c @@ -152,6 +152,14 @@ struct bmc150_accel_interrupt { atomic_t users; }; +struct bmc150_accel_trigger { + struct bmc150_accel_data *data; + struct iio_trigger *indio_trig; + int (*setup)(struct bmc150_accel_trigger *t, bool state); + int intr; + bool enabled; +}; + enum bmc150_accel_interrupt_id { BMC150_ACCEL_INT_DATA_READY, BMC150_ACCEL_INT_ANY_MOTION, @@ -159,12 +167,17 @@ enum bmc150_accel_interrupt_id { BMC150_ACCEL_INTERRUPTS, }; +enum bmc150_accel_trigger_id { + BMC150_ACCEL_TRIGGER_DATA_READY, + BMC150_ACCEL_TRIGGER_ANY_MOTION, + BMC150_ACCEL_TRIGGERS, +}; + struct bmc150_accel_data { struct i2c_client *client; struct bmc150_accel_interrupt interrupts[BMC150_ACCEL_INTERRUPTS]; - struct iio_trigger *dready_trig; - struct iio_trigger *motion_trig; atomic_t active_intr; + struct bmc150_accel_trigger triggers[BMC150_ACCEL_TRIGGERS]; struct mutex mutex; s16 buffer[8]; u8 bw_bits; @@ -172,8 +185,6 @@ struct bmc150_accel_data { u32 slope_thres; u32 range; int ev_enable_state; - bool dready_trigger_on; - bool motion_trigger_on; int64_t timestamp; const struct bmc150_accel_chip_info *chip_info; }; @@ -314,6 +325,15 @@ static int bmc150_accel_update_slope(struct bmc150_accel_data *data) return ret; } +static int bmc150_accel_any_motion_setup(struct bmc150_accel_trigger *t, + bool state) +{ + if (state) + return bmc150_accel_update_slope(t->data); + + return 0; +} + static int bmc150_accel_chip_init(struct bmc150_accel_data *data) { int ret; @@ -793,11 +813,14 @@ static int bmc150_accel_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) { struct bmc150_accel_data *data = iio_priv(indio_dev); + int i; - if (data->dready_trig != trig && data->motion_trig != trig) - return -EINVAL; + for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { + if (data->triggers[i].indio_trig == trig) + return 0; + } - return 0; + return -EINVAL; } static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( @@ -969,12 +992,12 @@ err_read: static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) { - struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); - struct bmc150_accel_data *data = iio_priv(indio_dev); + struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = t->data; int ret; /* new data interrupts don't need ack */ - if (data->dready_trigger_on) + if (t == &t->data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY]) return 0; mutex_lock(&data->mutex); @@ -993,46 +1016,35 @@ static int bmc150_accel_trig_try_reen(struct iio_trigger *trig) return 0; } -static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, +static int bmc150_accel_trigger_set_state(struct iio_trigger *trig, bool state) { - struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); - struct bmc150_accel_data *data = iio_priv(indio_dev); + struct bmc150_accel_trigger *t = iio_trigger_get_drvdata(trig); + struct bmc150_accel_data *data = t->data; int ret; mutex_lock(&data->mutex); - if (data->motion_trig == trig) { - if (data->motion_trigger_on == state) { - mutex_unlock(&data->mutex); - return 0; - } - } else { - if (data->dready_trigger_on == state) { + if (t->enabled == state) { + mutex_unlock(&data->mutex); + return 0; + } + + if (t->setup) { + ret = t->setup(t, state); + if (ret < 0) { mutex_unlock(&data->mutex); - return 0; + return ret; } } - if (data->motion_trig == trig) { - ret = bmc150_accel_update_slope(data); - if (!ret) - ret = bmc150_accel_set_interrupt(data, - BMC150_ACCEL_INT_ANY_MOTION, - state); - } else { - ret = bmc150_accel_set_interrupt(data, - BMC150_ACCEL_INT_DATA_READY, - state); - } + ret = bmc150_accel_set_interrupt(data, t->intr, state); if (ret < 0) { mutex_unlock(&data->mutex); return ret; } - if (data->motion_trig == trig) - data->motion_trigger_on = state; - else - data->dready_trigger_on = state; + + t->enabled = state; mutex_unlock(&data->mutex); @@ -1040,7 +1052,7 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, } static const struct iio_trigger_ops bmc150_accel_trigger_ops = { - .set_trigger_state = bmc150_accel_data_rdy_trigger_set_state, + .set_trigger_state = bmc150_accel_trigger_set_state, .try_reenable = bmc150_accel_trig_try_reen, .owner = THIS_MODULE, }; @@ -1086,7 +1098,7 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private) dir), data->timestamp); ack_intr_status: - if (!data->dready_trigger_on) + if (!data->triggers[BMC150_ACCEL_TRIGGER_DATA_READY].enabled) ret = i2c_smbus_write_byte_data(data->client, BMC150_ACCEL_REG_INT_RST_LATCH, BMC150_ACCEL_INT_MODE_LATCH_INT | @@ -1099,13 +1111,16 @@ static irqreturn_t bmc150_accel_data_rdy_trig_poll(int irq, void *private) { struct iio_dev *indio_dev = private; struct bmc150_accel_data *data = iio_priv(indio_dev); + int i; data->timestamp = iio_get_time_ns(); - if (data->dready_trigger_on) - iio_trigger_poll(data->dready_trig); - else if (data->motion_trigger_on) - iio_trigger_poll(data->motion_trig); + for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { + if (data->triggers[i].enabled) { + iio_trigger_poll(data->triggers[i].indio_trig); + break; + } + } if (data->ev_enable_state) return IRQ_WAKE_THREAD; @@ -1153,6 +1168,70 @@ static int bmc150_accel_gpio_probe(struct i2c_client *client, return ret; } +static const struct { + int intr; + const char *name; + int (*setup)(struct bmc150_accel_trigger *t, bool state); +} bmc150_accel_triggers[BMC150_ACCEL_TRIGGERS] = { + { + .intr = 0, + .name = "%s-dev%d", + }, + { + .intr = 1, + .name = "%s-any-motion-dev%d", + .setup = bmc150_accel_any_motion_setup, + }, +}; + +static void bmc150_accel_unregister_triggers(struct bmc150_accel_data *data, + int from) +{ + int i; + + for (i = from; i >= 0; i++) { + if (data->triggers[i].indio_trig) { + iio_trigger_unregister(data->triggers[i].indio_trig); + data->triggers[i].indio_trig = NULL; + } + } +} + +static int bmc150_accel_triggers_setup(struct iio_dev *indio_dev, + struct bmc150_accel_data *data) +{ + int i, ret; + + for (i = 0; i < BMC150_ACCEL_TRIGGERS; i++) { + struct bmc150_accel_trigger *t = &data->triggers[i]; + + t->indio_trig = devm_iio_trigger_alloc(&data->client->dev, + bmc150_accel_triggers[i].name, + indio_dev->name, + indio_dev->id); + if (!t->indio_trig) { + ret = -ENOMEM; + break; + } + + t->indio_trig->dev.parent = &data->client->dev; + t->indio_trig->ops = &bmc150_accel_trigger_ops; + t->intr = bmc150_accel_triggers[i].intr; + t->data = data; + t->setup = bmc150_accel_triggers[i].setup; + iio_trigger_set_drvdata(t->indio_trig, t); + + ret = iio_trigger_register(t->indio_trig); + if (ret) + break; + } + + if (ret) + bmc150_accel_unregister_triggers(data, i - 1); + + return ret; +} + static int bmc150_accel_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1223,36 +1302,10 @@ static int bmc150_accel_probe(struct i2c_client *client, bmc150_accel_interrupts_setup(indio_dev, data); - data->dready_trig = devm_iio_trigger_alloc(&client->dev, - "%s-dev%d", - indio_dev->name, - indio_dev->id); - if (!data->dready_trig) - return -ENOMEM; - - data->motion_trig = devm_iio_trigger_alloc(&client->dev, - "%s-any-motion-dev%d", - indio_dev->name, - indio_dev->id); - if (!data->motion_trig) - return -ENOMEM; - - data->dready_trig->dev.parent = &client->dev; - data->dready_trig->ops = &bmc150_accel_trigger_ops; - iio_trigger_set_drvdata(data->dready_trig, indio_dev); - ret = iio_trigger_register(data->dready_trig); + ret = bmc150_accel_triggers_setup(indio_dev, data); if (ret) return ret; - data->motion_trig->dev.parent = &client->dev; - data->motion_trig->ops = &bmc150_accel_trigger_ops; - iio_trigger_set_drvdata(data->motion_trig, indio_dev); - ret = iio_trigger_register(data->motion_trig); - if (ret) { - data->motion_trig = NULL; - goto err_trigger_unregister; - } - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, bmc150_accel_trigger_handler, @@ -1284,13 +1337,10 @@ static int bmc150_accel_probe(struct i2c_client *client, err_iio_unregister: iio_device_unregister(indio_dev); err_buffer_cleanup: - if (data->dready_trig) + if (indio_dev->pollfunc) iio_triggered_buffer_cleanup(indio_dev); err_trigger_unregister: - if (data->dready_trig) - iio_trigger_unregister(data->dready_trig); - if (data->motion_trig) - iio_trigger_unregister(data->motion_trig); + bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); return ret; } @@ -1306,11 +1356,7 @@ static int bmc150_accel_remove(struct i2c_client *client) iio_device_unregister(indio_dev); - if (data->dready_trig) { - iio_triggered_buffer_cleanup(indio_dev); - iio_trigger_unregister(data->dready_trig); - iio_trigger_unregister(data->motion_trig); - } + bmc150_accel_unregister_triggers(data, BMC150_ACCEL_TRIGGERS - 1); mutex_lock(&data->mutex); bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_DEEP_SUSPEND, 0); -- cgit v1.2.3 From 8b0544263761adbc7308f6910cdcc0d601782cb1 Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Sat, 14 Mar 2015 21:11:41 +0200 Subject: iio: light: Add support for Capella CM3323 color sensor Minimal implementation providing raw light intensity and integration time attribute. Userspace applications can use GREEN channel for raw illuminance readings following this table: Integration Time | G Sensitivity ================================ 40 ms | 0.18 80 ms | 0.09 160 ms | 0.045 320 ms | 0.0225 640 ms | 0.01125 1280 ms | 0.005625 Signed-off-by: Daniel Baluta Signed-off-by: Jonathan Cameron --- drivers/iio/light/Kconfig | 10 ++ drivers/iio/light/Makefile | 1 + drivers/iio/light/cm3323.c | 286 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+) create mode 100644 drivers/iio/light/cm3323.c (limited to 'drivers') diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index ae68c64bdad3..cd937d9293ff 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -59,6 +59,16 @@ config CM3232 To compile this driver as a module, choose M here: the module will be called cm3232. +config CM3323 + depends on I2C + tristate "Capella CM3323 color light sensor" + help + Say Y here if you want to build a driver for Capela CM3323 + color sensor. + + To compile this driver as a module, choose M here: the module will + be called cm3323. + config CM36651 depends on I2C tristate "CM36651 driver" diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index b12a5160d9e0..ad7c30fe443b 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_AL3320A) += al3320a.o obj-$(CONFIG_APDS9300) += apds9300.o obj-$(CONFIG_CM32181) += cm32181.o obj-$(CONFIG_CM3232) += cm3232.o +obj-$(CONFIG_CM3323) += cm3323.o obj-$(CONFIG_CM36651) += cm36651.o obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c new file mode 100644 index 000000000000..869033e48a1f --- /dev/null +++ b/drivers/iio/light/cm3323.c @@ -0,0 +1,286 @@ +/* + * CM3323 - Capella Color Light Sensor + * + * Copyright (c) 2015, Intel Corporation. + * + * 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. + * + * IIO driver for CM3323 (7-bit I2C slave address 0x10) + * + * TODO: calibscale to correct the lens factor + */ +#include +#include +#include +#include + +#include +#include + +#define CM3323_DRV_NAME "cm3323" + +#define CM3323_CMD_CONF 0x00 +#define CM3323_CMD_RED_DATA 0x08 +#define CM3323_CMD_GREEN_DATA 0x09 +#define CM3323_CMD_BLUE_DATA 0x0A +#define CM3323_CMD_CLEAR_DATA 0x0B + +#define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */ +#define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */ +#define CM3323_CONF_IT_MASK (BIT(4) | BIT(5) | BIT(6)) +#define CM3323_CONF_IT_SHIFT 4 + +#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28" + +static const struct { + int val; + int val2; +} cm3323_int_time[] = { + {0, 40000}, /* 40 ms */ + {0, 80000}, /* 80 ms */ + {0, 160000}, /* 160 ms */ + {0, 320000}, /* 320 ms */ + {0, 640000}, /* 640 ms */ + {1, 280000}, /* 1280 ms */ +}; + +struct cm3323_data { + struct i2c_client *client; + u16 reg_conf; + struct mutex mutex; +}; + +#define CM3323_COLOR_CHANNEL(_color, _addr) { \ + .type = IIO_INTENSITY, \ + .modified = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \ + .channel2 = IIO_MOD_LIGHT_##_color, \ + .address = _addr, \ +} + +static const struct iio_chan_spec cm3323_channels[] = { + CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA), + CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA), + CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA), + CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA), +}; + +static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE); + +static struct attribute *cm3323_attributes[] = { + &iio_const_attr_integration_time_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group cm3323_attribute_group = { + .attrs = cm3323_attributes, +}; + +static int cm3323_init(struct iio_dev *indio_dev) +{ + int ret; + struct cm3323_data *data = iio_priv(indio_dev); + + ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF); + if (ret < 0) { + dev_err(&data->client->dev, "Error reading reg_conf\n"); + return ret; + } + + /* enable sensor and set auto force mode */ + ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT); + + ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret); + if (ret < 0) { + dev_err(&data->client->dev, "Error writing reg_conf\n"); + return ret; + } + + data->reg_conf = ret; + + return 0; +} + +static void cm3323_disable(struct iio_dev *indio_dev) +{ + int ret; + struct cm3323_data *data = iio_priv(indio_dev); + + ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, + CM3323_CONF_SD_BIT); + if (ret < 0) + dev_err(&data->client->dev, "Error writing reg_conf\n"); +} + +static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2) +{ + int i, ret; + u16 reg_conf; + + for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) { + if (val == cm3323_int_time[i].val && + val2 == cm3323_int_time[i].val2) { + reg_conf = data->reg_conf; + reg_conf |= i << CM3323_CONF_IT_SHIFT; + + ret = i2c_smbus_write_word_data(data->client, + CM3323_CMD_CONF, + reg_conf); + if (ret < 0) + return ret; + + data->reg_conf = reg_conf; + return 0; + } + } + return -EINVAL; +} + +static int cm3323_get_it_bits(struct cm3323_data *data) +{ + int bits; + + bits = (data->reg_conf & CM3323_CONF_IT_MASK) >> + CM3323_CONF_IT_SHIFT; + + if (bits >= ARRAY_SIZE(cm3323_int_time)) + return -EINVAL; + return bits; +} + +static int cm3323_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int *val, + int *val2, long mask) +{ + int i, ret; + struct cm3323_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&data->mutex); + ret = i2c_smbus_read_word_data(data->client, chan->address); + if (ret < 0) { + mutex_unlock(&data->mutex); + return ret; + } + *val = ret; + mutex_unlock(&data->mutex); + + return IIO_VAL_INT; + case IIO_CHAN_INFO_INT_TIME: + mutex_lock(&data->mutex); + i = cm3323_get_it_bits(data); + if (i < 0) { + mutex_unlock(&data->mutex); + return -EINVAL; + } + + *val = cm3323_int_time[i].val; + *val2 = cm3323_int_time[i].val2; + mutex_unlock(&data->mutex); + + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int cm3323_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, + int val2, long mask) +{ + struct cm3323_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_INT_TIME: + mutex_lock(&data->mutex); + ret = cm3323_set_it_bits(data, val, val2); + mutex_unlock(&data->mutex); + + return ret; + default: + return -EINVAL; + } +} + +static const struct iio_info cm3323_info = { + .driver_module = THIS_MODULE, + .read_raw = cm3323_read_raw, + .write_raw = cm3323_write_raw, + .attrs = &cm3323_attribute_group, +}; + +static int cm3323_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cm3323_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + i2c_set_clientdata(client, indio_dev); + data->client = client; + + mutex_init(&data->mutex); + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &cm3323_info; + indio_dev->name = CM3323_DRV_NAME; + indio_dev->channels = cm3323_channels; + indio_dev->num_channels = ARRAY_SIZE(cm3323_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = cm3323_init(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "cm3323 chip init failed\n"); + return ret; + } + ret = iio_device_register(indio_dev); + if (ret < 0) { + dev_err(&client->dev, "failed to register iio dev\n"); + goto err_init; + } + return 0; +err_init: + cm3323_disable(indio_dev); + return ret; +} + +static int cm3323_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + + iio_device_unregister(indio_dev); + cm3323_disable(indio_dev); + + return 0; +} + +static const struct i2c_device_id cm3323_id[] = { + {"cm3323", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cm3323_id); + +static struct i2c_driver cm3323_driver = { + .driver = { + .name = CM3323_DRV_NAME, + }, + .probe = cm3323_probe, + .remove = cm3323_remove, + .id_table = cm3323_id, +}; + +module_i2c_driver(cm3323_driver); + +MODULE_AUTHOR("Daniel Baluta "); +MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From c0644160a8b5e56b3c3896d77ac3d50d41fa9336 Mon Sep 17 00:00:00 2001 From: Tomasz Duszynski Date: Sat, 14 Mar 2015 21:29:31 +0100 Subject: iio: pressure: add support for MS5611 pressure and temperature sensor Add support for Measurement Specialities MS5611 pressure and temperature sensor. Signed-off-by: Tomasz Duszynski Signed-off-by: Jonathan Cameron --- drivers/iio/pressure/Kconfig | 27 +++++ drivers/iio/pressure/Makefile | 3 + drivers/iio/pressure/ms5611.h | 44 ++++++++ drivers/iio/pressure/ms5611_core.c | 215 +++++++++++++++++++++++++++++++++++++ drivers/iio/pressure/ms5611_i2c.c | 128 ++++++++++++++++++++++ drivers/iio/pressure/ms5611_spi.c | 127 ++++++++++++++++++++++ 6 files changed, 544 insertions(+) create mode 100644 drivers/iio/pressure/ms5611.h create mode 100644 drivers/iio/pressure/ms5611_core.c create mode 100644 drivers/iio/pressure/ms5611_i2c.c create mode 100644 drivers/iio/pressure/ms5611_spi.c (limited to 'drivers') diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index a3be53792072..fa6295041947 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -52,6 +52,33 @@ config MPL3115 To compile this driver as a module, choose M here: the module will be called mpl3115. +config MS5611 + tristate "Measurement Specialities MS5611 pressure sensor driver" + help + Say Y here to build support for the Measurement Specialities + MS5611 pressure and temperature sensor. + + To compile this driver as a module, choose M here: the module will + be called ms5611_core. + +config MS5611_I2C + tristate "support I2C bus connection" + depends on I2C && MS5611 + help + Say Y here to build I2C bus support for MS5611. + + To compile this driver as a module, choose M here: the module will + be called ms5611_i2c. + +config MS5611_SPI + tristate "support SPI bus connection" + depends on SPI_MASTER && MS5611 + help + Say Y here to build SPI bus support for MS5611. + + To compile this driver as a module, choose M here: the module will + be called ms5611_spi. + config IIO_ST_PRESS tristate "STMicroelectronics pressure sensor Driver" depends on (I2C || SPI_MASTER) && SYSFS diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 88011f2ae00e..a4f98f8d90ed 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -7,6 +7,9 @@ obj-$(CONFIG_BMP280) += bmp280.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_MPL115) += mpl115.o obj-$(CONFIG_MPL3115) += mpl3115.o +obj-$(CONFIG_MS5611) += ms5611_core.o +obj-$(CONFIG_MS5611_I2C) += ms5611_i2c.o +obj-$(CONFIG_MS5611_SPI) += ms5611_spi.o obj-$(CONFIG_IIO_ST_PRESS) += st_pressure.o st_pressure-y := st_pressure_core.o st_pressure-$(CONFIG_IIO_BUFFER) += st_pressure_buffer.o diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h new file mode 100644 index 000000000000..099c6cdea43f --- /dev/null +++ b/drivers/iio/pressure/ms5611.h @@ -0,0 +1,44 @@ +/* + * MS5611 pressure and temperature sensor driver + * + * Copyright (c) Tomasz Duszynski + * + * 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. + * + */ + +#ifndef _MS5611_H +#define _MS5611_H + +#include +#include +#include + +#define MS5611_RESET 0x1e +#define MS5611_READ_ADC 0x00 +#define MS5611_READ_PROM_WORD 0xA0 +#define MS5611_START_TEMP_CONV 0x58 +#define MS5611_START_PRESSURE_CONV 0x48 + +#define MS5611_CONV_TIME_MIN 9040 +#define MS5611_CONV_TIME_MAX 10000 + +#define MS5611_PROM_WORDS_NB 8 + +struct ms5611_state { + void *client; + struct mutex lock; + + int (*reset)(struct device *dev); + int (*read_prom_word)(struct device *dev, int index, u16 *word); + int (*read_adc_temp_and_pressure)(struct device *dev, + s32 *temp, s32 *pressure); + + u16 prom[MS5611_PROM_WORDS_NB]; +}; + +int ms5611_probe(struct iio_dev *indio_dev, struct device *dev); + +#endif /* _MS5611_H */ diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c new file mode 100644 index 000000000000..e42c8531d9b3 --- /dev/null +++ b/drivers/iio/pressure/ms5611_core.c @@ -0,0 +1,215 @@ +/* + * MS5611 pressure and temperature sensor driver + * + * Copyright (c) Tomasz Duszynski + * + * 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. + * + * Data sheet: + * http://www.meas-spec.com/downloads/MS5611-01BA03.pdf + * + */ + +#include +#include +#include + +#include "ms5611.h" + +static bool ms5611_prom_is_valid(u16 *prom, size_t len) +{ + int i, j; + uint16_t crc = 0, crc_orig = prom[7] & 0x000F; + + prom[7] &= 0xFF00; + + for (i = 0; i < len * 2; i++) { + if (i % 2 == 1) + crc ^= prom[i >> 1] & 0x00FF; + else + crc ^= prom[i >> 1] >> 8; + + for (j = 0; j < 8; j++) { + if (crc & 0x8000) + crc = (crc << 1) ^ 0x3000; + else + crc <<= 1; + } + } + + crc = (crc >> 12) & 0x000F; + + return crc_orig != 0x0000 && crc == crc_orig; +} + +static int ms5611_read_prom(struct iio_dev *indio_dev) +{ + int ret, i; + struct ms5611_state *st = iio_priv(indio_dev); + + for (i = 0; i < MS5611_PROM_WORDS_NB; i++) { + ret = st->read_prom_word(&indio_dev->dev, i, &st->prom[i]); + if (ret < 0) { + dev_err(&indio_dev->dev, + "failed to read prom at %d\n", i); + return ret; + } + } + + if (!ms5611_prom_is_valid(st->prom, MS5611_PROM_WORDS_NB)) { + dev_err(&indio_dev->dev, "PROM integrity check failed\n"); + return -ENODEV; + } + + return 0; +} + +static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev, + s32 *temp, s32 *pressure) +{ + int ret; + s32 t, p; + s64 off, sens, dt; + struct ms5611_state *st = iio_priv(indio_dev); + + ret = st->read_adc_temp_and_pressure(&indio_dev->dev, &t, &p); + if (ret < 0) { + dev_err(&indio_dev->dev, + "failed to read temperature and pressure\n"); + return ret; + } + + dt = t - (st->prom[5] << 8); + off = ((s64)st->prom[2] << 16) + ((st->prom[4] * dt) >> 7); + sens = ((s64)st->prom[1] << 15) + ((st->prom[3] * dt) >> 8); + + t = 2000 + ((st->prom[6] * dt) >> 23); + if (t < 2000) { + s64 off2, sens2, t2; + + t2 = (dt * dt) >> 31; + off2 = (5 * (t - 2000) * (t - 2000)) >> 1; + sens2 = off2 >> 1; + + if (t < -1500) { + s64 tmp = (t + 1500) * (t + 1500); + + off2 += 7 * tmp; + sens2 += (11 * tmp) >> 1; + } + + t -= t2; + off -= off2; + sens -= sens2; + } + + *temp = t; + *pressure = (((p * sens) >> 21) - off) >> 15; + + return 0; +} + +static int ms5611_reset(struct iio_dev *indio_dev) +{ + int ret; + struct ms5611_state *st = iio_priv(indio_dev); + + ret = st->reset(&indio_dev->dev); + if (ret < 0) { + dev_err(&indio_dev->dev, "failed to reset device\n"); + return ret; + } + + usleep_range(3000, 4000); + + return 0; +} + +static int ms5611_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + s32 temp, pressure; + struct ms5611_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_PROCESSED: + mutex_lock(&st->lock); + ret = ms5611_read_temp_and_pressure(indio_dev, + &temp, &pressure); + mutex_unlock(&st->lock); + if (ret < 0) + return ret; + + switch (chan->type) { + case IIO_TEMP: + *val = temp * 10; + return IIO_VAL_INT; + case IIO_PRESSURE: + *val = pressure / 1000; + *val2 = (pressure % 1000) * 1000; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +static const struct iio_chan_spec ms5611_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_SCALE) + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_SCALE) + } +}; + +static const struct iio_info ms5611_info = { + .read_raw = &ms5611_read_raw, + .driver_module = THIS_MODULE, +}; + +static int ms5611_init(struct iio_dev *indio_dev) +{ + int ret; + + ret = ms5611_reset(indio_dev); + if (ret < 0) + return ret; + + return ms5611_read_prom(indio_dev); +} + +int ms5611_probe(struct iio_dev *indio_dev, struct device *dev) +{ + int ret; + struct ms5611_state *st = iio_priv(indio_dev); + + mutex_init(&st->lock); + indio_dev->dev.parent = dev; + indio_dev->name = dev->driver->name; + indio_dev->info = &ms5611_info; + indio_dev->channels = ms5611_channels; + indio_dev->num_channels = ARRAY_SIZE(ms5611_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = ms5611_init(indio_dev); + if (ret < 0) + return ret; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL(ms5611_probe); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("MS5611 core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c new file mode 100644 index 000000000000..748fd9acaad8 --- /dev/null +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -0,0 +1,128 @@ +/* + * MS5611 pressure and temperature sensor driver (I2C bus) + * + * Copyright (c) Tomasz Duszynski + * + * 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. + * + * 7-bit I2C slave addresses: + * + * 0x77 (CSB pin low) + * 0x76 (CSB pin high) + * + */ + +#include +#include +#include + +#include "ms5611.h" + +static int ms5611_i2c_reset(struct device *dev) +{ + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + return i2c_smbus_write_byte(st->client, MS5611_RESET); +} + +static int ms5611_i2c_read_prom_word(struct device *dev, int index, u16 *word) +{ + int ret; + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + ret = i2c_smbus_read_word_swapped(st->client, + MS5611_READ_PROM_WORD + (index << 1)); + if (ret < 0) + return ret; + + *word = ret; + + return 0; +} + +static int ms5611_i2c_read_adc(struct ms5611_state *st, s32 *val) +{ + int ret; + u8 buf[3]; + + ret = i2c_smbus_read_i2c_block_data(st->client, MS5611_READ_ADC, + 3, buf); + if (ret < 0) + return ret; + + *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + + return 0; +} + +static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev, + s32 *temp, s32 *pressure) +{ + int ret; + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + ret = i2c_smbus_write_byte(st->client, MS5611_START_TEMP_CONV); + if (ret < 0) + return ret; + + usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); + + ret = ms5611_i2c_read_adc(st, temp); + if (ret < 0) + return ret; + + ret = i2c_smbus_write_byte(st->client, MS5611_START_PRESSURE_CONV); + if (ret < 0) + return ret; + + usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); + + return ms5611_i2c_read_adc(st, pressure); +} + +static int ms5611_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct ms5611_state *st; + struct iio_dev *indio_dev; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_BYTE | + I2C_FUNC_SMBUS_READ_WORD_DATA | + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) + return -ENODEV; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->reset = ms5611_i2c_reset; + st->read_prom_word = ms5611_i2c_read_prom_word; + st->read_adc_temp_and_pressure = ms5611_i2c_read_adc_temp_and_pressure; + st->client = client; + + return ms5611_probe(indio_dev, &client->dev); +} + +static const struct i2c_device_id ms5611_id[] = { + { "ms5611", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ms5611_id); + +static struct i2c_driver ms5611_driver = { + .driver = { + .name = "ms5611", + .owner = THIS_MODULE, + }, + .id_table = ms5611_id, + .probe = ms5611_i2c_probe, +}; +module_i2c_driver(ms5611_driver); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("MS5611 i2c driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c new file mode 100644 index 000000000000..976726fd4e6c --- /dev/null +++ b/drivers/iio/pressure/ms5611_spi.c @@ -0,0 +1,127 @@ +/* + * MS5611 pressure and temperature sensor driver (SPI bus) + * + * Copyright (c) Tomasz Duszynski + * + * 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. + * + */ + +#include +#include +#include + +#include "ms5611.h" + +static int ms5611_spi_reset(struct device *dev) +{ + u8 cmd = MS5611_RESET; + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + return spi_write_then_read(st->client, &cmd, 1, NULL, 0); +} + +static int ms5611_spi_read_prom_word(struct device *dev, int index, u16 *word) +{ + int ret; + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + ret = spi_w8r16be(st->client, MS5611_READ_PROM_WORD + (index << 1)); + if (ret < 0) + return ret; + + *word = ret; + + return 0; +} + +static int ms5611_spi_read_adc(struct device *dev, s32 *val) +{ + int ret; + u8 buf[3] = { MS5611_READ_ADC }; + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + ret = spi_write_then_read(st->client, buf, 1, buf, 3); + if (ret < 0) + return ret; + + *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + + return 0; +} + +static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev, + s32 *temp, s32 *pressure) +{ + u8 cmd; + int ret; + struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); + + cmd = MS5611_START_TEMP_CONV; + ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0); + if (ret < 0) + return ret; + + usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); + + ret = ms5611_spi_read_adc(dev, temp); + if (ret < 0) + return ret; + + cmd = MS5611_START_PRESSURE_CONV; + ret = spi_write_then_read(st->client, &cmd, 1, NULL, 0); + if (ret < 0) + return ret; + + usleep_range(MS5611_CONV_TIME_MIN, MS5611_CONV_TIME_MAX); + + return ms5611_spi_read_adc(dev, pressure); +} + +static int ms5611_spi_probe(struct spi_device *spi) +{ + int ret; + struct ms5611_state *st; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + spi->mode = SPI_MODE_0; + spi->max_speed_hz = 20000000; + spi->bits_per_word = 8; + ret = spi_setup(spi); + if (ret < 0) + return ret; + + st = iio_priv(indio_dev); + st->reset = ms5611_spi_reset; + st->read_prom_word = ms5611_spi_read_prom_word; + st->read_adc_temp_and_pressure = ms5611_spi_read_adc_temp_and_pressure; + st->client = spi; + + return ms5611_probe(indio_dev, &spi->dev); +} + +static const struct spi_device_id ms5611_id[] = { + { "ms5611", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, ms5611_id); + +static struct spi_driver ms5611_driver = { + .driver = { + .name = "ms5611", + .owner = THIS_MODULE, + }, + .id_table = ms5611_id, + .probe = ms5611_spi_probe, +}; +module_spi_driver(ms5611_driver); + +MODULE_AUTHOR("Tomasz Duszynski "); +MODULE_DESCRIPTION("MS5611 spi driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3