Commit 78a66b00 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'iio-for-v4.2c' of...

Merge tag 'iio-for-v4.2c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

Third round of new IIO drivers, cleanups and functionality for the 4.2 cycle.

Given Linus announced a 4.8rc coming up, hopefully time for one more
lot of IIO patches this cycle.  Some of these are actually
improvements / fixes for patches earlier in the cycle.

New device support
* st_accel driver - support devices with 8 bit channels.

Cleanup
* A general cleanup of the iio tools under /tools/ from Hartmut.
  I'm more than a little embarassed by how bad some of these were! Are well,
  much more refined and less bug prone now.
  These cover lots of stuff like unhandled error returns, memory leaks as
  well as general refactoring to tidy the code up.
* iio_simple_dummy - fix memory leaks in the init functions, drop some
  pointless error returns from functions that never generate errors and
  make the module parameter explicitly unsigned.
* More buffer handling reworks from Lars-Peter, this time targetting hardware
  buffers (a little used corner that looks likely to get more use in the near
  future). Specifically:
  - Always compute the masklength as inkernel buffer users may need it.
  - Add a means of labeling which buffer modes a given buffer implementation
    supports.
  - In the case of hardware buffers, require strict scan matching rather than
    matching to a superset.  Currently the demux is bypassed by these drivers
    (this may well not change for efficiency reasons) so allowing a superset
    of channels to be selected would otherwise lead to more data than requested
    confusing userspace.

Driver funcationality improvments
* mmc35240 - adds a compensation to the raw values as borrowed form Memsic's
  own input driver.
* mma8452
  - event support
  - event debouncing
  - high  pass filter configuration
  - triggers
* vf610 - allow conversion mode to be adjusted

Fixlets
* mmc35240
  - Off by one error that by coincidence had no real effect.
  - i2c_device_name should be lowercase.
  - Lack of null terminator at end of attributes array.
  - Avoid computing the fractional part of the magnetic field by moving
    the scaling into userspace where floating point is available to simplify
    the maths.
  - Use a smaller sleep before assuming the measurement is done.  This is
    safe and improves the possible polling rate.
  - Fix sensitivity on z-axis - datasheet disagrees with Memsic's releasedd
    code and the value used in the code seems to be correct.
* stk3310 - make a local variable signed to ensure error handling works.
* twl4030
  - fix calculation of the temperature sense current - bug unlikely
    to have ever been noticed as the difference is small.
  - Fix errors in descriptions.
parents e703f237 bbf5f037
What: /sys/bus/iio/devices/iio:deviceX/conversion_mode
KernelVersion: 4.2
Contact: linux-iio@vger.kernel.org
Description:
Specifies the hardware conversion mode used. The three
available modes are "normal", "high-speed" and "low-power",
where the last is the default mode.
...@@ -11,6 +11,13 @@ Required properties: ...@@ -11,6 +11,13 @@ Required properties:
- clock-names: Must contain "adc", matching entry in the clocks property. - clock-names: Must contain "adc", matching entry in the clocks property.
- vref-supply: The regulator supply ADC reference voltage. - vref-supply: The regulator supply ADC reference voltage.
Recommended properties:
- fsl,adck-max-frequency: Maximum frequencies according to datasheets operating
requirements. Three values are required, depending on conversion mode:
- Frequency in normal mode (ADLPC=0, ADHSC=0)
- Frequency in high-speed mode (ADLPC=0, ADHSC=1)
- Frequency in low-power mode (ADLPC=1, ADHSC=0)
Example: Example:
adc0: adc@4003b000 { adc0: adc@4003b000 {
compatible = "fsl,vf610-adc"; compatible = "fsl,vf610-adc";
...@@ -18,5 +25,7 @@ adc0: adc@4003b000 { ...@@ -18,5 +25,7 @@ adc0: adc@4003b000 {
interrupts = <0 53 0x04>; interrupts = <0 53 0x04>;
clocks = <&clks VF610_CLK_ADC0>; clocks = <&clks VF610_CLK_ADC0>;
clock-names = "adc"; clock-names = "adc";
fsl,adck-max-frequency = <30000000>, <40000000>,
<20000000>;
vref-supply = <&reg_vcc_3v3_mcu>; vref-supply = <&reg_vcc_3v3_mcu>;
}; };
...@@ -30,6 +30,7 @@ Accelerometers: ...@@ -30,6 +30,7 @@ Accelerometers:
- st,lsm330d-accel - st,lsm330d-accel
- st,lsm330dl-accel - st,lsm330dl-accel
- st,lsm330dlc-accel - st,lsm330dlc-accel
- st,lis331dl-accel
- st,lis331dlh-accel - st,lis331dlh-accel
- st,lsm303dl-accel - st,lsm303dl-accel
- st,lsm303dlm-accel - st,lsm303dlm-accel
......
This diff is collapsed.
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define LSM330D_ACCEL_DEV_NAME "lsm330d_accel" #define LSM330D_ACCEL_DEV_NAME "lsm330d_accel"
#define LSM330DL_ACCEL_DEV_NAME "lsm330dl_accel" #define LSM330DL_ACCEL_DEV_NAME "lsm330dl_accel"
#define LSM330DLC_ACCEL_DEV_NAME "lsm330dlc_accel" #define LSM330DLC_ACCEL_DEV_NAME "lsm330dlc_accel"
#define LIS331DL_ACCEL_DEV_NAME "lis331dl_accel"
#define LIS331DLH_ACCEL_DEV_NAME "lis331dlh" #define LIS331DLH_ACCEL_DEV_NAME "lis331dlh"
#define LSM303DL_ACCEL_DEV_NAME "lsm303dl_accel" #define LSM303DL_ACCEL_DEV_NAME "lsm303dl_accel"
#define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel" #define LSM303DLH_ACCEL_DEV_NAME "lsm303dlh_accel"
......
...@@ -153,6 +153,44 @@ ...@@ -153,6 +153,44 @@
#define ST_ACCEL_4_IG1_EN_MASK 0x08 #define ST_ACCEL_4_IG1_EN_MASK 0x08
#define ST_ACCEL_4_MULTIREAD_BIT true #define ST_ACCEL_4_MULTIREAD_BIT true
/* CUSTOM VALUES FOR SENSOR 5 */
#define ST_ACCEL_5_WAI_EXP 0x3b
#define ST_ACCEL_5_ODR_ADDR 0x20
#define ST_ACCEL_5_ODR_MASK 0x80
#define ST_ACCEL_5_ODR_AVL_100HZ_VAL 0x00
#define ST_ACCEL_5_ODR_AVL_400HZ_VAL 0x01
#define ST_ACCEL_5_PW_ADDR 0x20
#define ST_ACCEL_5_PW_MASK 0x40
#define ST_ACCEL_5_FS_ADDR 0x20
#define ST_ACCEL_5_FS_MASK 0x20
#define ST_ACCEL_5_FS_AVL_2_VAL 0X00
#define ST_ACCEL_5_FS_AVL_8_VAL 0X01
/* TODO: check these resulting gain settings, these are not in the datsheet */
#define ST_ACCEL_5_FS_AVL_2_GAIN IIO_G_TO_M_S_2(18000)
#define ST_ACCEL_5_FS_AVL_8_GAIN IIO_G_TO_M_S_2(72000)
#define ST_ACCEL_5_DRDY_IRQ_ADDR 0x22
#define ST_ACCEL_5_DRDY_IRQ_INT1_MASK 0x04
#define ST_ACCEL_5_DRDY_IRQ_INT2_MASK 0x20
#define ST_ACCEL_5_IG1_EN_ADDR 0x21
#define ST_ACCEL_5_IG1_EN_MASK 0x08
#define ST_ACCEL_5_MULTIREAD_BIT false
static const struct iio_chan_spec st_accel_8bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_X, 1, IIO_MOD_X, 's', IIO_LE, 8, 8,
ST_ACCEL_DEFAULT_OUT_X_L_ADDR+1),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Y, 1, IIO_MOD_Y, 's', IIO_LE, 8, 8,
ST_ACCEL_DEFAULT_OUT_Y_L_ADDR+1),
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
ST_SENSORS_SCAN_Z, 1, IIO_MOD_Z, 's', IIO_LE, 8, 8,
ST_ACCEL_DEFAULT_OUT_Z_L_ADDR+1),
IIO_CHAN_SOFT_TIMESTAMP(3)
};
static const struct iio_chan_spec st_accel_12bit_channels[] = { static const struct iio_chan_spec st_accel_12bit_channels[] = {
ST_SENSORS_LSM_CHANNELS(IIO_ACCEL, ST_SENSORS_LSM_CHANNELS(IIO_ACCEL,
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
...@@ -454,6 +492,54 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { ...@@ -454,6 +492,54 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = {
.multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT, .multi_read_bit = ST_ACCEL_4_MULTIREAD_BIT,
.bootime = 2, /* guess */ .bootime = 2, /* guess */
}, },
{
.wai = ST_ACCEL_5_WAI_EXP,
.sensors_supported = {
[0] = LIS331DL_ACCEL_DEV_NAME,
},
.ch = (struct iio_chan_spec *)st_accel_8bit_channels,
.odr = {
.addr = ST_ACCEL_5_ODR_ADDR,
.mask = ST_ACCEL_5_ODR_MASK,
.odr_avl = {
{ 100, ST_ACCEL_5_ODR_AVL_100HZ_VAL },
{ 400, ST_ACCEL_5_ODR_AVL_400HZ_VAL, },
},
},
.pw = {
.addr = ST_ACCEL_5_PW_ADDR,
.mask = ST_ACCEL_5_PW_MASK,
.value_on = ST_SENSORS_DEFAULT_POWER_ON_VALUE,
.value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE,
},
.enable_axis = {
.addr = ST_SENSORS_DEFAULT_AXIS_ADDR,
.mask = ST_SENSORS_DEFAULT_AXIS_MASK,
},
.fs = {
.addr = ST_ACCEL_5_FS_ADDR,
.mask = ST_ACCEL_5_FS_MASK,
.fs_avl = {
[0] = {
.num = ST_ACCEL_FS_AVL_2G,
.value = ST_ACCEL_5_FS_AVL_2_VAL,
.gain = ST_ACCEL_5_FS_AVL_2_GAIN,
},
[1] = {
.num = ST_ACCEL_FS_AVL_8G,
.value = ST_ACCEL_5_FS_AVL_8_VAL,
.gain = ST_ACCEL_5_FS_AVL_8_GAIN,
},
},
},
.drdy_irq = {
.addr = ST_ACCEL_5_DRDY_IRQ_ADDR,
.mask_int1 = ST_ACCEL_5_DRDY_IRQ_INT1_MASK,
.mask_int2 = ST_ACCEL_5_DRDY_IRQ_INT2_MASK,
},
.multi_read_bit = ST_ACCEL_5_MULTIREAD_BIT,
.bootime = 2, /* guess */
},
}; };
static int st_accel_read_raw(struct iio_dev *indio_dev, static int st_accel_read_raw(struct iio_dev *indio_dev,
......
...@@ -48,6 +48,10 @@ static const struct of_device_id st_accel_of_match[] = { ...@@ -48,6 +48,10 @@ static const struct of_device_id st_accel_of_match[] = {
.compatible = "st,lsm330dlc-accel", .compatible = "st,lsm330dlc-accel",
.data = LSM330DLC_ACCEL_DEV_NAME, .data = LSM330DLC_ACCEL_DEV_NAME,
}, },
{
.compatible = "st,lis331dl-accel",
.data = LIS331DL_ACCEL_DEV_NAME,
},
{ {
.compatible = "st,lis331dlh-accel", .compatible = "st,lis331dlh-accel",
.data = LIS331DLH_ACCEL_DEV_NAME, .data = LIS331DLH_ACCEL_DEV_NAME,
......
...@@ -235,7 +235,7 @@ static int twl4030battery_temperature(int raw_volt) ...@@ -235,7 +235,7 @@ static int twl4030battery_temperature(int raw_volt)
if (ret < 0) if (ret < 0)
return ret; return ret;
curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10; curr = ((val & TWL4030_BCI_ITHSENS) + 1) * 10;
/* Getting and calculating the thermistor resistance in ohms */ /* Getting and calculating the thermistor resistance in ohms */
res = volt * 1000 / curr; res = volt * 1000 / curr;
/* calculating temperature */ /* calculating temperature */
...@@ -662,10 +662,8 @@ EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion); ...@@ -662,10 +662,8 @@ EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
* *
* @madc: pointer to twl4030_madc_data struct * @madc: pointer to twl4030_madc_data struct
* @chan: can be one of the two values: * @chan: can be one of the two values:
* TWL4030_BCI_ITHEN * 0 - Enables bias current for main battery type reading
* Enables bias current for main battery type reading * 1 - Enables bias current for main battery temperature sensing
* TWL4030_BCI_TYPEN
* Enables bias current for main battery temperature sensing
* @on: enable or disable chan. * @on: enable or disable chan.
* *
* Function to enable or disable bias current for * Function to enable or disable bias current for
......
...@@ -118,15 +118,21 @@ enum average_sel { ...@@ -118,15 +118,21 @@ enum average_sel {
VF610_ADC_SAMPLE_32, VF610_ADC_SAMPLE_32,
}; };
enum conversion_mode_sel {
VF610_ADC_CONV_NORMAL,
VF610_ADC_CONV_HIGH_SPEED,
VF610_ADC_CONV_LOW_POWER,
};
struct vf610_adc_feature { struct vf610_adc_feature {
enum clk_sel clk_sel; enum clk_sel clk_sel;
enum vol_ref vol_ref; enum vol_ref vol_ref;
enum conversion_mode_sel conv_mode;
int clk_div; int clk_div;
int sample_rate; int sample_rate;
int res_mode; int res_mode;
bool lpm;
bool calibration; bool calibration;
bool ovwren; bool ovwren;
}; };
...@@ -139,6 +145,8 @@ struct vf610_adc { ...@@ -139,6 +145,8 @@ struct vf610_adc {
u32 vref_uv; u32 vref_uv;
u32 value; u32 value;
struct regulator *vref; struct regulator *vref;
u32 max_adck_rate[3];
struct vf610_adc_feature adc_feature; struct vf610_adc_feature adc_feature;
u32 sample_freq_avail[5]; u32 sample_freq_avail[5];
...@@ -148,46 +156,22 @@ struct vf610_adc { ...@@ -148,46 +156,22 @@ struct vf610_adc {
static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 }; static const u32 vf610_hw_avgs[] = { 1, 4, 8, 16, 32 };
#define VF610_ADC_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.indexed = 1, \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
}
#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(0, IIO_VOLTAGE),
VF610_ADC_CHAN(1, IIO_VOLTAGE),
VF610_ADC_CHAN(2, IIO_VOLTAGE),
VF610_ADC_CHAN(3, IIO_VOLTAGE),
VF610_ADC_CHAN(4, IIO_VOLTAGE),
VF610_ADC_CHAN(5, IIO_VOLTAGE),
VF610_ADC_CHAN(6, IIO_VOLTAGE),
VF610_ADC_CHAN(7, IIO_VOLTAGE),
VF610_ADC_CHAN(8, IIO_VOLTAGE),
VF610_ADC_CHAN(9, IIO_VOLTAGE),
VF610_ADC_CHAN(10, IIO_VOLTAGE),
VF610_ADC_CHAN(11, IIO_VOLTAGE),
VF610_ADC_CHAN(12, IIO_VOLTAGE),
VF610_ADC_CHAN(13, IIO_VOLTAGE),
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
/* sentinel */
};
static inline void vf610_adc_calculate_rates(struct vf610_adc *info) static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
{ {
struct vf610_adc_feature *adc_feature = &info->adc_feature;
unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk); unsigned long adck_rate, ipg_rate = clk_get_rate(info->clk);
int i; int divisor, i;
adck_rate = info->max_adck_rate[adc_feature->conv_mode];
if (adck_rate) {
/* calculate clk divider which is within specification */
divisor = ipg_rate / adck_rate;
adc_feature->clk_div = 1 << fls(divisor + 1);
} else {
/* fall-back value using a safe divisor */
adc_feature->clk_div = 8;
}
/* /*
* Calculate ADC sample frequencies * Calculate ADC sample frequencies
...@@ -219,10 +203,8 @@ static inline void vf610_adc_cfg_init(struct vf610_adc *info) ...@@ -219,10 +203,8 @@ static inline void vf610_adc_cfg_init(struct vf610_adc *info)
adc_feature->res_mode = 12; adc_feature->res_mode = 12;
adc_feature->sample_rate = 1; adc_feature->sample_rate = 1;
adc_feature->lpm = true;
/* Use a save ADCK which is below 20MHz on all devices */ adc_feature->conv_mode = VF610_ADC_CONV_LOW_POWER;
adc_feature->clk_div = 8;
vf610_adc_calculate_rates(info); vf610_adc_calculate_rates(info);
} }
...@@ -304,10 +286,12 @@ static void vf610_adc_cfg_set(struct vf610_adc *info) ...@@ -304,10 +286,12 @@ static void vf610_adc_cfg_set(struct vf610_adc *info)
cfg_data = readl(info->regs + VF610_REG_ADC_CFG); cfg_data = readl(info->regs + VF610_REG_ADC_CFG);
cfg_data &= ~VF610_ADC_ADLPC_EN; cfg_data &= ~VF610_ADC_ADLPC_EN;
if (adc_feature->lpm) if (adc_feature->conv_mode == VF610_ADC_CONV_LOW_POWER)
cfg_data |= VF610_ADC_ADLPC_EN; cfg_data |= VF610_ADC_ADLPC_EN;
cfg_data &= ~VF610_ADC_ADHSC_EN; cfg_data &= ~VF610_ADC_ADHSC_EN;
if (adc_feature->conv_mode == VF610_ADC_CONV_HIGH_SPEED)
cfg_data |= VF610_ADC_ADHSC_EN;
writel(cfg_data, info->regs + VF610_REG_ADC_CFG); writel(cfg_data, info->regs + VF610_REG_ADC_CFG);
} }
...@@ -409,6 +393,81 @@ static void vf610_adc_hw_init(struct vf610_adc *info) ...@@ -409,6 +393,81 @@ static void vf610_adc_hw_init(struct vf610_adc *info)
vf610_adc_cfg_set(info); vf610_adc_cfg_set(info);
} }
static int vf610_set_conversion_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
unsigned int mode)
{
struct vf610_adc *info = iio_priv(indio_dev);
mutex_lock(&indio_dev->mlock);
info->adc_feature.conv_mode = mode;
vf610_adc_calculate_rates(info);
vf610_adc_hw_init(info);
mutex_unlock(&indio_dev->mlock);
return 0;
}
static int vf610_get_conversion_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
{
struct vf610_adc *info = iio_priv(indio_dev);
return info->adc_feature.conv_mode;
}
static const char * const vf610_conv_modes[] = { "normal", "high-speed",
"low-power" };
static const struct iio_enum vf610_conversion_mode = {
.items = vf610_conv_modes,
.num_items = ARRAY_SIZE(vf610_conv_modes),
.get = vf610_get_conversion_mode,
.set = vf610_set_conversion_mode,
};
static const struct iio_chan_spec_ext_info vf610_ext_info[] = {
IIO_ENUM("conversion_mode", IIO_SHARED_BY_DIR, &vf610_conversion_mode),
{},
};
#define VF610_ADC_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.indexed = 1, \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
BIT(IIO_CHAN_INFO_SAMP_FREQ), \
.ext_info = vf610_ext_info, \
}
#define VF610_ADC_TEMPERATURE_CHAN(_idx, _chan_type) { \
.type = (_chan_type), \
.channel = (_idx), \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
}
static const struct iio_chan_spec vf610_adc_iio_channels[] = {
VF610_ADC_CHAN(0, IIO_VOLTAGE),
VF610_ADC_CHAN(1, IIO_VOLTAGE),
VF610_ADC_CHAN(2, IIO_VOLTAGE),
VF610_ADC_CHAN(3, IIO_VOLTAGE),
VF610_ADC_CHAN(4, IIO_VOLTAGE),
VF610_ADC_CHAN(5, IIO_VOLTAGE),
VF610_ADC_CHAN(6, IIO_VOLTAGE),
VF610_ADC_CHAN(7, IIO_VOLTAGE),
VF610_ADC_CHAN(8, IIO_VOLTAGE),
VF610_ADC_CHAN(9, IIO_VOLTAGE),
VF610_ADC_CHAN(10, IIO_VOLTAGE),
VF610_ADC_CHAN(11, IIO_VOLTAGE),
VF610_ADC_CHAN(12, IIO_VOLTAGE),
VF610_ADC_CHAN(13, IIO_VOLTAGE),
VF610_ADC_CHAN(14, IIO_VOLTAGE),
VF610_ADC_CHAN(15, IIO_VOLTAGE),
VF610_ADC_TEMPERATURE_CHAN(26, IIO_TEMP),
/* sentinel */
};
static int vf610_adc_read_data(struct vf610_adc *info) static int vf610_adc_read_data(struct vf610_adc *info)
{ {
int result; int result;
...@@ -651,6 +710,9 @@ static int vf610_adc_probe(struct platform_device *pdev) ...@@ -651,6 +710,9 @@ static int vf610_adc_probe(struct platform_device *pdev)
info->vref_uv = regulator_get_voltage(info->vref); info->vref_uv = regulator_get_voltage(info->vref);
of_property_read_u32_array(pdev->dev.of_node, "fsl,adck-max-frequency",
info->max_adck_rate, 3);
platform_set_drvdata(pdev, indio_dev); platform_set_drvdata(pdev, indio_dev);
init_completion(&info->completion); init_completion(&info->completion);
......
...@@ -33,6 +33,8 @@ static void iio_buffer_cb_release(struct iio_buffer *buffer) ...@@ -33,6 +33,8 @@ static void iio_buffer_cb_release(struct iio_buffer *buffer)
static const struct iio_buffer_access_funcs iio_cb_access = { static const struct iio_buffer_access_funcs iio_cb_access = {
.store_to = &iio_buffer_cb_store_to, .store_to = &iio_buffer_cb_store_to,
.release = &iio_buffer_cb_release, .release = &iio_buffer_cb_release,
.modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED,
}; };
struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev, struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
......
...@@ -431,7 +431,9 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, ...@@ -431,7 +431,9 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
if (err < 0) if (err < 0)
goto st_sensors_free_memory; goto st_sensors_free_memory;
if (byte_for_channel == 2) if (byte_for_channel == 1)
*data = (s8)*outdata;
else if (byte_for_channel == 2)
*data = (s16)get_unaligned_le16(outdata); *data = (s16)get_unaligned_le16(outdata);
else if (byte_for_channel == 3) else if (byte_for_channel == 3)
*data = (s32)st_sensors_get_unaligned_le24(outdata); *data = (s32)st_sensors_get_unaligned_le24(outdata);
......
...@@ -239,13 +239,19 @@ static ssize_t iio_scan_el_show(struct device *dev, ...@@ -239,13 +239,19 @@ static ssize_t iio_scan_el_show(struct device *dev,
/* Note NULL used as error indicator as it doesn't make sense. */ /* Note NULL used as error indicator as it doesn't make sense. */
static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks, static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
unsigned int masklength, unsigned int masklength,
const unsigned long *mask) const unsigned long *mask,
bool strict)
{ {
if (bitmap_empty(mask, masklength)) if (bitmap_empty(mask, masklength))
return NULL; return NULL;
while (*av_masks) { while (*av_masks) {
if (bitmap_subset(mask, av_masks, masklength)) if (strict) {
return av_masks; if (bitmap_equal(mask, av_masks, masklength))
return av_masks;
} else {
if (bitmap_subset(mask, av_masks, masklength))
return av_masks;
}
av_masks += BITS_TO_LONGS(masklength); av_masks += BITS_TO_LONGS(masklength);
} }
return NULL; return NULL;
...@@ -295,7 +301,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, ...@@ -295,7 +301,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
if (indio_dev->available_scan_masks) { if (indio_dev->available_scan_masks) {
mask = iio_scan_mask_match(indio_dev->available_scan_masks, mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength, indio_dev->masklength,
trialmask); trialmask, false);
if (!mask) if (!mask)
goto err_invalid_mask; goto err_invalid_mask;
} }
...@@ -602,8 +608,10 @@ static int iio_verify_update(struct iio_dev *indio_dev, ...@@ -602,8 +608,10 @@ static int iio_verify_update(struct iio_dev *indio_dev,
{ {
unsigned long *compound_mask; unsigned long *compound_mask;
const unsigned long *scan_mask; const unsigned long *scan_mask;
bool strict_scanmask = false;
struct iio_buffer *buffer; struct iio_buffer *buffer;
bool scan_timestamp; bool scan_timestamp;
unsigned int modes;
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
...@@ -615,12 +623,30 @@ static int iio_verify_update(struct iio_dev *indio_dev, ...@@ -615,12 +623,30 @@ static int iio_verify_update(struct iio_dev *indio_dev,
list_is_singular(&indio_dev->buffer_list)) list_is_singular(&indio_dev->buffer_list))
return 0; return 0;
modes = indio_dev->modes;
list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
if (buffer == remove_buffer)
continue;
modes &= buffer->access->modes;
}
if (insert_buffer)
modes &= insert_buffer->access->modes;
/* Definitely possible for devices to support both of these. */ /* Definitely possible for devices to support both of these. */
if ((indio_dev->modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) { if ((modes & INDIO_BUFFER_TRIGGERED) && indio_dev->trig) {
config->mode = INDIO_BUFFER_TRIGGERED; config->mode = INDIO_BUFFER_TRIGGERED;
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) { } else if (modes & INDIO_BUFFER_HARDWARE) {
/*
* Keep things simple for now and only allow a single buffer to
* be connected in hardware mode.
*/
if (insert_buffer && !list_empty(&indio_dev->buffer_list))
return -EINVAL;
config->mode = INDIO_BUFFER_HARDWARE; config->mode = INDIO_BUFFER_HARDWARE;
} else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) { strict_scanmask = true;
} else if (modes & INDIO_BUFFER_SOFTWARE) {
config->mode = INDIO_BUFFER_SOFTWARE; config->mode = INDIO_BUFFER_SOFTWARE;
} else { } else {
/* Can only occur on first buffer */ /* Can only occur on first buffer */
...@@ -654,7 +680,8 @@ static int iio_verify_update(struct iio_dev *indio_dev, ...@@ -654,7 +680,8 @@ static int iio_verify_update(struct iio_dev *indio_dev,
if (indio_dev->available_scan_masks) { if (indio_dev->available_scan_masks) {
scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks, scan_mask = iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength, indio_dev->masklength,
compound_mask); compound_mask,
strict_scanmask);
kfree(compound_mask); kfree(compound_mask);
if (scan_mask == NULL) if (scan_mask == NULL)
return -EINVAL; return -EINVAL;
...@@ -888,8 +915,6 @@ static ssize_t iio_buffer_store_enable(struct device *dev, ...@@ -888,8 +915,6 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
ret = __iio_update_buffers(indio_dev, ret = __iio_update_buffers(indio_dev,
NULL, indio_dev->buffer); NULL, indio_dev->buffer);
if (ret < 0)
goto done;
done: done:
mutex_unlock(&indio_dev->mlock); mutex_unlock(&indio_dev->mlock);
return (ret < 0) ? ret : len; return (ret < 0) ? ret : len;
...@@ -968,6 +993,15 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) ...@@ -968,6 +993,15 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
int ret, i, attrn, attrcount, attrcount_orig = 0; int ret, i, attrn, attrcount, attrcount_orig = 0;
const struct iio_chan_spec *channels; const struct iio_chan_spec *channels;
channels = indio_dev->channels;
if (channels) {
int ml = indio_dev->masklength;
for (i = 0; i < indio_dev->num_channels; i++)
ml = max(ml, channels[i].scan_index + 1);
indio_dev->masklength = ml;
}
if (!buffer) if (!buffer)
return 0; return 0;
...@@ -1011,12 +1045,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) ...@@ -1011,12 +1045,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
if (channels[i].scan_index < 0) if (channels[i].scan_index < 0)
continue; continue;
/* Establish necessary mask length */
if (channels[i].scan_index >
(int)indio_dev->masklength - 1)
indio_dev->masklength
= channels[i].scan_index + 1;
ret = iio_buffer_add_channel_sysfs(indio_dev, ret = iio_buffer_add_channel_sysfs(indio_dev,
&channels[i]); &channels[i]);
if (ret < 0) if (ret < 0)
......
...@@ -136,6 +136,8 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = { ...@@ -136,6 +136,8 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = {
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo, .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
.set_length = &iio_set_length_kfifo, .set_length = &iio_set_length_kfifo,
.release = &iio_kfifo_buffer_release, .release = &iio_kfifo_buffer_release,
.modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED,
}; };
struct iio_buffer *iio_kfifo_allocate(void) struct iio_buffer *iio_kfifo_allocate(void)
......
...@@ -370,7 +370,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev, ...@@ -370,7 +370,7 @@ static int stk3310_write_raw(struct iio_dev *indio_dev,
int val, int val2, long mask) int val, int val2, long mask)
{ {
int ret; int ret;
unsigned int index; int index;
struct stk3310_data *data = iio_priv(indio_dev); struct stk3310_data *data = iio_priv(indio_dev);
switch (mask) { switch (mask) {
......
...@@ -58,6 +58,31 @@ ...@@ -58,6 +58,31 @@
#define MMC35240_WAIT_CHARGE_PUMP 50000 /* us */ #define MMC35240_WAIT_CHARGE_PUMP 50000 /* us */
#define MMC53240_WAIT_SET_RESET 1000 /* us */ #define MMC53240_WAIT_SET_RESET 1000 /* us */
/*
* Memsic OTP process code piece is put here for reference:
*
* #define OTP_CONVERT(REG) ((float)((REG) >=32 ? (32 - (REG)) : (REG)) * 0.006
* 1) For X axis, the COEFFICIENT is always 1.
* 2) For Y axis, the COEFFICIENT is as below:
* f_OTP_matrix[4] = OTP_CONVERT(((reg_data[1] & 0x03) << 4) |
* (reg_data[2] >> 4)) + 1.0;
* 3) For Z axis, the COEFFICIENT is as below:
* f_OTP_matrix[8] = (OTP_CONVERT(reg_data[3] & 0x3f) + 1) * 1.35;
* We implemented the OTP logic into driver.
*/
/* scale = 1000 here for Y otp */
#define MMC35240_OTP_CONVERT_Y(REG) (((REG) >= 32 ? (32 - (REG)) : (REG)) * 6)
/* 0.6 * 1.35 = 0.81, scale 10000 for Z otp */
#define MMC35240_OTP_CONVERT_Z(REG) (((REG) >= 32 ? (32 - (REG)) : (REG)) * 81)
#define MMC35240_X_COEFF(x) (x)
#define MMC35240_Y_COEFF(y) (y + 1000)
#define MMC35240_Z_COEFF(z) (z + 13500)
#define MMC35240_OTP_START_ADDR 0x1B
enum mmc35240_resolution { enum mmc35240_resolution {
MMC35240_16_BITS_SLOW = 0, /* 100 Hz */ MMC35240_16_BITS_SLOW = 0, /* 100 Hz */
MMC35240_16_BITS_FAST, /* 200 Hz */ MMC35240_16_BITS_FAST, /* 200 Hz */
...@@ -77,7 +102,7 @@ static const struct { ...@@ -77,7 +102,7 @@ static const struct {
} mmc35240_props_table[] = { } mmc35240_props_table[] = {
/* 16 bits, 100Hz ODR */ /* 16 bits, 100Hz ODR */
{ {
{1024, 1024, 770}, {1024, 1024, 1024},
32768, 32768,
}, },
/* 16 bits, 200Hz ODR */ /* 16 bits, 200Hz ODR */
...@@ -102,6 +127,10 @@ struct mmc35240_data { ...@@ -102,6 +127,10 @@ struct mmc35240_data {
struct mutex mutex; struct mutex mutex;
struct regmap *regmap; struct regmap *regmap;
enum mmc35240_resolution res; enum mmc35240_resolution res;
/* OTP compensation */
int axis_coef[3];
int axis_scale[3];
}; };
static const int mmc35240_samp_freq[] = {100, 200, 333, 666}; static const int mmc35240_samp_freq[] = {100, 200, 333, 666};
...@@ -113,8 +142,9 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 333 666"); ...@@ -113,8 +142,9 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("100 200 333 666");
.modified = 1, \ .modified = 1, \
.channel2 = IIO_MOD_ ## _axis, \ .channel2 = IIO_MOD_ ## _axis, \
.address = AXIS_ ## _axis, \ .address = AXIS_ ## _axis, \
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
BIT(IIO_CHAN_INFO_SCALE), \
} }
static const struct iio_chan_spec mmc35240_channels[] = { static const struct iio_chan_spec mmc35240_channels[] = {
...@@ -125,6 +155,7 @@ static const struct iio_chan_spec mmc35240_channels[] = { ...@@ -125,6 +155,7 @@ static const struct iio_chan_spec mmc35240_channels[] = {
static struct attribute *mmc35240_attributes[] = { static struct attribute *mmc35240_attributes[] = {
&iio_const_attr_sampling_frequency_available.dev_attr.attr, &iio_const_attr_sampling_frequency_available.dev_attr.attr,
NULL
}; };
static const struct attribute_group mmc35240_attribute_group = { static const struct attribute_group mmc35240_attribute_group = {
...@@ -170,8 +201,9 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set) ...@@ -170,8 +201,9 @@ static int mmc35240_hw_set(struct mmc35240_data *data, bool set)
static int mmc35240_init(struct mmc35240_data *data) static int mmc35240_init(struct mmc35240_data *data)
{ {
int ret; int ret, y_convert, z_convert;
unsigned int reg_id; unsigned int reg_id;
u8 otp_data[6];
ret = regmap_read(data->regmap, MMC35240_REG_ID, &reg_id); ret = regmap_read(data->regmap, MMC35240_REG_ID, &reg_id);
if (ret < 0) { if (ret < 0) {
...@@ -195,9 +227,30 @@ static int mmc35240_init(struct mmc35240_data *data) ...@@ -195,9 +227,30 @@ static int mmc35240_init(struct mmc35240_data *data)
return ret; return ret;
/* set default sampling frequency */ /* set default sampling frequency */
return regmap_update_bits(data->regmap, MMC35240_REG_CTRL1, ret = regmap_update_bits(data->regmap, MMC35240_REG_CTRL1,
MMC35240_CTRL1_BW_MASK, MMC35240_CTRL1_BW_MASK,
data->res << MMC35240_CTRL1_BW_SHIFT); data->res << MMC35240_CTRL1_BW_SHIFT);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, MMC35240_OTP_START_ADDR,
(u8 *)otp_data, sizeof(otp_data));
if (ret < 0)
return ret;
y_convert = MMC35240_OTP_CONVERT_Y(((otp_data[1] & 0x03) << 4) |
(otp_data[2] >> 4));
z_convert = MMC35240_OTP_CONVERT_Z(otp_data[3] & 0x3f);
data->axis_coef[0] = MMC35240_X_COEFF(1);
data->axis_coef[1] = MMC35240_Y_COEFF(y_convert);
data->axis_coef[2] = MMC35240_Z_COEFF(z_convert);
data->axis_scale[0] = 1;
data->axis_scale[1] = 1000;
data->axis_scale[2] = 10000;
return 0;
} }
static int mmc35240_take_measurement(struct mmc35240_data *data) static int mmc35240_take_measurement(struct mmc35240_data *data)
...@@ -217,7 +270,8 @@ static int mmc35240_take_measurement(struct mmc35240_data *data) ...@@ -217,7 +270,8 @@ static int mmc35240_take_measurement(struct mmc35240_data *data)
return ret; return ret;
if (reg_status & MMC35240_STATUS_MEAS_DONE_BIT) if (reg_status & MMC35240_STATUS_MEAS_DONE_BIT)
break; break;
msleep(20); /* minimum wait time to complete measurement is 10 ms */
usleep_range(10000, 11000);
} }
if (tries < 0) { if (tries < 0) {
...@@ -240,9 +294,19 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3]) ...@@ -240,9 +294,19 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3])
3 * sizeof(__le16)); 3 * sizeof(__le16));
} }
static int mmc35240_raw_to_gauss(struct mmc35240_data *data, int index, /**
__le16 buf[], * mmc35240_raw_to_mgauss - convert raw readings to milli gauss. Also apply
int *val, int *val2) compensation for output value.
*
* @data: device private data
* @index: axis index for which we want the conversion
* @buf: raw data to be converted, 2 bytes in little endian format
* @val: compensated output reading (unit is milli gauss)
*
* Returns: 0 in case of success, -EINVAL when @index is not valid
*/
static int mmc35240_raw_to_mgauss(struct mmc35240_data *data, int index,
__le16 buf[], int *val)
{ {
int raw_x, raw_y, raw_z; int raw_x, raw_y, raw_z;
int sens_x, sens_y, sens_z; int sens_x, sens_y, sens_z;
...@@ -260,22 +324,22 @@ static int mmc35240_raw_to_gauss(struct mmc35240_data *data, int index, ...@@ -260,22 +324,22 @@ static int mmc35240_raw_to_gauss(struct mmc35240_data *data, int index,
switch (index) { switch (index) {
case AXIS_X: case AXIS_X:
*val = (raw_x - nfo) / sens_x; *val = (raw_x - nfo) * 1000 / sens_x;
*val2 = ((raw_x - nfo) % sens_x) * 1000000;
break; break;
case AXIS_Y: case AXIS_Y:
*val = (raw_y - nfo) / sens_y - (raw_z - nfo) / sens_z; *val = (raw_y - nfo) * 1000 / sens_y -
*val2 = (((raw_y - nfo) % sens_y - (raw_z - nfo) % sens_z)) (raw_z - nfo) * 1000 / sens_z;
* 1000000;
break; break;
case AXIS_Z: case AXIS_Z:
*val = (raw_y - nfo) / sens_y + (raw_z - nfo) / sens_z; *val = (raw_y - nfo) * 1000 / sens_y +
*val2 = (((raw_y - nfo) % sens_y + (raw_z - nfo) % sens_z)) (raw_z - nfo) * 1000 / sens_z;
* 1000000;
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
/* apply OTP compensation */
*val = (*val) * data->axis_coef[index] / data->axis_scale[index];
return 0; return 0;
} }
...@@ -289,16 +353,19 @@ static int mmc35240_read_raw(struct iio_dev *indio_dev, ...@@ -289,16 +353,19 @@ static int mmc35240_read_raw(struct iio_dev *indio_dev,
__le16 buf[3]; __le16 buf[3];
switch (mask) { switch (mask) {
case IIO_CHAN_INFO_PROCESSED: case IIO_CHAN_INFO_RAW:
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
ret = mmc35240_read_measurement(data, buf); ret = mmc35240_read_measurement(data, buf);
mutex_unlock(&data->mutex); mutex_unlock(&data->mutex);
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = mmc35240_raw_to_gauss(data, chan->address, ret = mmc35240_raw_to_mgauss(data, chan->address, buf, val);
buf, val, val2);
if (ret < 0) if (ret < 0)
return ret; return ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
*val = 0;
*val2 = 1000;
return IIO_VAL_INT_PLUS_MICRO; return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SAMP_FREQ: case IIO_CHAN_INFO_SAMP_FREQ:
mutex_lock(&data->mutex); mutex_lock(&data->mutex);
...@@ -308,7 +375,7 @@ static int mmc35240_read_raw(struct iio_dev *indio_dev, ...@@ -308,7 +375,7 @@ static int mmc35240_read_raw(struct iio_dev *indio_dev,
return ret; return ret;
i = (reg & MMC35240_CTRL1_BW_MASK) >> MMC35240_CTRL1_BW_SHIFT; i = (reg & MMC35240_CTRL1_BW_MASK) >> MMC35240_CTRL1_BW_SHIFT;
if (i < 0 || i > ARRAY_SIZE(mmc35240_samp_freq)) if (i < 0 || i >= ARRAY_SIZE(mmc35240_samp_freq))
return -EINVAL; return -EINVAL;
*val = mmc35240_samp_freq[i]; *val = mmc35240_samp_freq[i];
...@@ -490,7 +557,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = { ...@@ -490,7 +557,7 @@ static const struct acpi_device_id mmc35240_acpi_match[] = {
MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match); MODULE_DEVICE_TABLE(acpi, mmc35240_acpi_match);
static const struct i2c_device_id mmc35240_id[] = { static const struct i2c_device_id mmc35240_id[] = {
{"MMC35240", 0}, {"mmc35240", 0},
{} {}
}; };
MODULE_DEVICE_TABLE(i2c, mmc35240_id); MODULE_DEVICE_TABLE(i2c, mmc35240_id);
......
...@@ -258,6 +258,8 @@ static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = { ...@@ -258,6 +258,8 @@ static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = {
.read_first_n = &sca3000_read_first_n_hw_rb, .read_first_n = &sca3000_read_first_n_hw_rb,
.data_available = sca3000_ring_buf_data_available, .data_available = sca3000_ring_buf_data_available,
.release = sca3000_ring_release, .release = sca3000_ring_release,
.modes = INDIO_BUFFER_HARDWARE,
}; };
int sca3000_configure_ring(struct iio_dev *indio_dev) int sca3000_configure_ring(struct iio_dev *indio_dev)
......
...@@ -128,13 +128,11 @@ EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq); ...@@ -128,13 +128,11 @@ EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_irq);
* *
* Used by client driver instances to give the irqs back when they disconnect * Used by client driver instances to give the irqs back when they disconnect
*/ */
int iio_dummy_evgen_release_irq(int irq) void iio_dummy_evgen_release_irq(int irq)
{ {
mutex_lock(&iio_evgen->lock); mutex_lock(&iio_evgen->lock);
iio_evgen->inuse[irq - iio_evgen->base] = false; iio_evgen->inuse[irq - iio_evgen->base] = false;
mutex_unlock(&iio_evgen->lock); mutex_unlock(&iio_evgen->lock);
return 0;
} }
EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq); EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
......
...@@ -8,6 +8,6 @@ struct iio_dummy_regs { ...@@ -8,6 +8,6 @@ struct iio_dummy_regs {
struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq); struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq);
int iio_dummy_evgen_get_irq(void); int iio_dummy_evgen_get_irq(void);
int iio_dummy_evgen_release_irq(int irq); void iio_dummy_evgen_release_irq(int irq);
#endif /* _IIO_DUMMY_EVGEN_H_ */ #endif /* _IIO_DUMMY_EVGEN_H_ */
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
* dummy devices are registered. * dummy devices are registered.
*/ */
static unsigned instances = 1; static unsigned instances = 1;
module_param(instances, int, 0); module_param(instances, uint, 0);
/* Pointer array used to fake bus elements */ /* Pointer array used to fake bus elements */
static struct iio_dev **iio_dummy_devs; static struct iio_dev **iio_dummy_devs;
...@@ -665,9 +665,8 @@ static int iio_dummy_probe(int index) ...@@ -665,9 +665,8 @@ static int iio_dummy_probe(int index)
* *
* Parameters follow those of iio_dummy_probe for buses. * Parameters follow those of iio_dummy_probe for buses.
*/ */
static int iio_dummy_remove(int index) static void iio_dummy_remove(int index)
{ {
int ret;
/* /*
* Get a pointer to the device instance iio_dev structure * Get a pointer to the device instance iio_dev structure
* from the bus subsystem. E.g. * from the bus subsystem. E.g.
...@@ -685,15 +684,10 @@ static int iio_dummy_remove(int index) ...@@ -685,15 +684,10 @@ static int iio_dummy_remove(int index)
/* Buffered capture related cleanup */ /* Buffered capture related cleanup */
iio_simple_dummy_unconfigure_buffer(indio_dev); iio_simple_dummy_unconfigure_buffer(indio_dev);
ret = iio_simple_dummy_events_unregister(indio_dev); iio_simple_dummy_events_unregister(indio_dev);
if (ret)
goto error_ret;
/* Free all structures */ /* Free all structures */
iio_device_free(indio_dev); iio_device_free(indio_dev);
error_ret:
return ret;
} }
/** /**
...@@ -722,9 +716,16 @@ static __init int iio_dummy_init(void) ...@@ -722,9 +716,16 @@ static __init int iio_dummy_init(void)
for (i = 0; i < instances; i++) { for (i = 0; i < instances; i++) {
ret = iio_dummy_probe(i); ret = iio_dummy_probe(i);
if (ret < 0) if (ret < 0)
return ret; goto error_remove_devs;
} }
return 0; return 0;
error_remove_devs:
while (i--)
iio_dummy_remove(i);
kfree(iio_dummy_devs);
return ret;
} }
module_init(iio_dummy_init); module_init(iio_dummy_init);
......
...@@ -79,7 +79,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev, ...@@ -79,7 +79,7 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
int val2); int val2);
int iio_simple_dummy_events_register(struct iio_dev *indio_dev); int iio_simple_dummy_events_register(struct iio_dev *indio_dev);
int iio_simple_dummy_events_unregister(struct iio_dev *indio_dev); void iio_simple_dummy_events_unregister(struct iio_dev *indio_dev);
#else /* Stubs for when events are disabled at compile time */ #else /* Stubs for when events are disabled at compile time */
...@@ -89,11 +89,9 @@ iio_simple_dummy_events_register(struct iio_dev *indio_dev) ...@@ -89,11 +89,9 @@ iio_simple_dummy_events_register(struct iio_dev *indio_dev)
return 0; return 0;
}; };
static inline int static inline void
iio_simple_dummy_events_unregister(struct iio_dev *indio_dev) iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
{ { };
return 0;
};
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS*/ #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS*/
......
...@@ -257,13 +257,11 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev) ...@@ -257,13 +257,11 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
* iio_simple_dummy_events_unregister() - tidy up interrupt handling on remove * iio_simple_dummy_events_unregister() - tidy up interrupt handling on remove
* @indio_dev: device instance data * @indio_dev: device instance data
*/ */
int iio_simple_dummy_events_unregister(struct iio_dev *indio_dev) void iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
{ {
struct iio_dummy_state *st = iio_priv(indio_dev); struct iio_dummy_state *st = iio_priv(indio_dev);
free_irq(st->event_irq, indio_dev); free_irq(st->event_irq, indio_dev);
/* Not part of normal driver */ /* Not part of normal driver */
iio_dummy_evgen_release_irq(st->event_irq); iio_dummy_evgen_release_irq(st->event_irq);
return 0;
} }
...@@ -29,6 +29,7 @@ struct iio_buffer; ...@@ -29,6 +29,7 @@ struct iio_buffer;
* @set_length: set number of datums in buffer * @set_length: set number of datums in buffer
* @release: called when the last reference to the buffer is dropped, * @release: called when the last reference to the buffer is dropped,
* should free all resources allocated by the buffer. * should free all resources allocated by the buffer.
* @modes: Supported operating modes by this buffer type
* *
* The purpose of this structure is to make the buffer element * The purpose of this structure is to make the buffer element
* modular as event for a given driver, different usecases may require * modular as event for a given driver, different usecases may require
...@@ -51,6 +52,8 @@ struct iio_buffer_access_funcs { ...@@ -51,6 +52,8 @@ struct iio_buffer_access_funcs {
int (*set_length)(struct iio_buffer *buffer, int length); int (*set_length)(struct iio_buffer *buffer, int length);
void (*release)(struct iio_buffer *buffer); void (*release)(struct iio_buffer *buffer);
unsigned int modes;
}; };
/** /**
......
...@@ -59,33 +59,80 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels) ...@@ -59,33 +59,80 @@ int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
return bytes; return bytes;
} }
void print2byte(int input, struct iio_channel_info *info) void print2byte(uint16_t input, struct iio_channel_info *info)
{ {
/* First swap if incorrect endian */ /* First swap if incorrect endian */
if (info->be) if (info->be)
input = be16toh((uint16_t)input); input = be16toh(input);
else else
input = le16toh((uint16_t)input); input = le16toh(input);
/* /*
* Shift before conversion to avoid sign extension * Shift before conversion to avoid sign extension
* of left aligned data * of left aligned data
*/ */
input >>= info->shift; input >>= info->shift;
input &= info->mask;
if (info->is_signed) { if (info->is_signed) {
int16_t val = input; int16_t val = (int16_t)(input << (16 - info->bits_used)) >>
(16 - info->bits_used);
printf("%05f ", ((float)val + info->offset) * info->scale);
} else {
printf("%05f ", ((float)input + info->offset) * info->scale);
}
}
void print4byte(uint32_t input, struct iio_channel_info *info)
{
/* First swap if incorrect endian */
if (info->be)
input = be32toh(input);
else
input = le32toh(input);
val &= (1 << info->bits_used) - 1; /*
val = (int16_t)(val << (16 - info->bits_used)) >> * Shift before conversion to avoid sign extension
(16 - info->bits_used); * of left aligned data
printf("%05f ", ((float)val + info->offset)*info->scale); */
input >>= info->shift;
input &= info->mask;
if (info->is_signed) {
int32_t val = (int32_t)(input << (32 - info->bits_used)) >>
(32 - info->bits_used);
printf("%05f ", ((float)val + info->offset) * info->scale);
} else { } else {
uint16_t val = input; printf("%05f ", ((float)input + info->offset) * info->scale);
}
}
val &= (1 << info->bits_used) - 1; void print8byte(uint64_t input, struct iio_channel_info *info)
printf("%05f ", ((float)val + info->offset)*info->scale); {
/* First swap if incorrect endian */
if (info->be)
input = be64toh(input);
else
input = le64toh(input);
/*
* Shift before conversion to avoid sign extension
* of left aligned data
*/
input >>= info->shift;
input &= info->mask;
if (info->is_signed) {
int64_t val = (int64_t)(input << (64 - info->bits_used)) >>
(64 - info->bits_used);
/* special case for timestamp */
if (info->scale == 1.0f && info->offset == 0.0f)
printf("%" PRId64 " ", val);
else
printf("%05f ",
((float)val + info->offset) * info->scale);
} else {
printf("%05f ", ((float)input + info->offset) * info->scale);
} }
} }
/** /**
* process_scan() - print out the values in SI units * process_scan() - print out the values in SI units
* @data: pointer to the start of the scan * @data: pointer to the start of the scan
...@@ -108,32 +155,12 @@ void process_scan(char *data, ...@@ -108,32 +155,12 @@ void process_scan(char *data,
&channels[k]); &channels[k]);
break; break;
case 4: case 4:
if (!channels[k].is_signed) { print4byte(*(uint32_t *)(data + channels[k].location),
uint32_t val = *(uint32_t *) &channels[k]);
(data + channels[k].location);
printf("%05f ", ((float)val +
channels[k].offset)*
channels[k].scale);
}
break; break;
case 8: case 8:
if (channels[k].is_signed) { print8byte(*(uint64_t *)(data + channels[k].location),
int64_t val = *(int64_t *) &channels[k]);
(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; break;
default: default:
break; break;
...@@ -141,6 +168,19 @@ void process_scan(char *data, ...@@ -141,6 +168,19 @@ void process_scan(char *data,
printf("\n"); printf("\n");
} }
void print_usage(void)
{
printf("Usage: generic_buffer [options]...\n"
"Capture, convert and output data from IIO device buffer\n"
" -c <n> Do n conversions\n"
" -e Disable wait for event (new data)\n"
" -g Use trigger-less mode\n"
" -l <n> Set buffer length to n samples\n"
" -n <name> Set device name (mandatory)\n"
" -t <name> Set trigger name\n"
" -w <n> Set delay between reads in us (event-less mode)\n");
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
unsigned long num_loops = 2; unsigned long num_loops = 2;
...@@ -166,8 +206,26 @@ int main(int argc, char **argv) ...@@ -166,8 +206,26 @@ int main(int argc, char **argv)
struct iio_channel_info *channels; struct iio_channel_info *channels;
while ((c = getopt(argc, argv, "l:w:c:et:n:g")) != -1) { while ((c = getopt(argc, argv, "c:egl:n:t:w:")) != -1) {
switch (c) { switch (c) {
case 'c':
errno = 0;
num_loops = strtoul(optarg, &dummy, 10);
if (errno)
return -errno;
break;
case 'e':
noevents = 1;
break;
case 'g':
notrigger = 1;
break;
case 'l':
errno = 0;
buf_len = strtoul(optarg, &dummy, 10);
if (errno)
return -errno;
break;
case 'n': case 'n':
device_name = optarg; device_name = optarg;
break; break;
...@@ -175,39 +233,35 @@ int main(int argc, char **argv) ...@@ -175,39 +233,35 @@ int main(int argc, char **argv)
trigger_name = optarg; trigger_name = optarg;
datardytrigger = 0; datardytrigger = 0;
break; break;
case 'e':
noevents = 1;
break;
case 'c':
num_loops = strtoul(optarg, &dummy, 10);
break;
case 'w': case 'w':
errno = 0;
timedelay = strtoul(optarg, &dummy, 10); timedelay = strtoul(optarg, &dummy, 10);
break; if (errno)
case 'l': return -errno;
buf_len = strtoul(optarg, &dummy, 10);
break;
case 'g':
notrigger = 1;
break; break;
case '?': case '?':
print_usage();
return -1; return -1;
} }
} }
if (device_name == NULL) if (device_name == NULL) {
printf("Device name not set\n");
print_usage();
return -1; return -1;
}
/* Find the device requested */ /* Find the device requested */
dev_num = find_type_by_name(device_name, "iio:device"); dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num < 0) { if (dev_num < 0) {
printf("Failed to find the %s\n", device_name); printf("Failed to find the %s\n", device_name);
ret = -ENODEV; return dev_num;
goto error_ret;
} }
printf("iio device number being used is %d\n", dev_num); printf("iio device number being used is %d\n", dev_num);
asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
if (ret < 0)
return -ENOMEM;
if (!notrigger) { if (!notrigger) {
if (trigger_name == NULL) { if (trigger_name == NULL) {
...@@ -220,7 +274,7 @@ int main(int argc, char **argv) ...@@ -220,7 +274,7 @@ int main(int argc, char **argv)
"%s-dev%d", device_name, dev_num); "%s-dev%d", device_name, dev_num);
if (ret < 0) { if (ret < 0) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_ret; goto error_free_dev_dir_name;
} }
} }
...@@ -228,7 +282,7 @@ int main(int argc, char **argv) ...@@ -228,7 +282,7 @@ int main(int argc, char **argv)
trig_num = find_type_by_name(trigger_name, "trigger"); trig_num = find_type_by_name(trigger_name, "trigger");
if (trig_num < 0) { if (trig_num < 0) {
printf("Failed to find the trigger %s\n", trigger_name); printf("Failed to find the trigger %s\n", trigger_name);
ret = -ENODEV; ret = trig_num;
goto error_free_triggername; goto error_free_triggername;
} }
printf("iio trigger number being used is %d\n", trig_num); printf("iio trigger number being used is %d\n", trig_num);
...@@ -255,7 +309,7 @@ int main(int argc, char **argv) ...@@ -255,7 +309,7 @@ int main(int argc, char **argv)
"%siio:device%d/buffer", iio_dir, dev_num); "%siio:device%d/buffer", iio_dir, dev_num);
if (ret < 0) { if (ret < 0) {
ret = -ENOMEM; ret = -ENOMEM;
goto error_free_triggername; goto error_free_channels;
} }
if (!notrigger) { if (!notrigger) {
...@@ -296,8 +350,8 @@ int main(int argc, char **argv) ...@@ -296,8 +350,8 @@ int main(int argc, char **argv)
/* Attempt to open non blocking the access dev */ /* Attempt to open non blocking the access dev */
fp = open(buffer_access, O_RDONLY | O_NONBLOCK); fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /* If it isn't there make the node */ if (fp == -1) { /* If it isn't there make the node */
printf("Failed to open %s\n", buffer_access);
ret = -errno; ret = -errno;
printf("Failed to open %s\n", buffer_access);
goto error_free_buffer_access; goto error_free_buffer_access;
} }
...@@ -309,7 +363,14 @@ int main(int argc, char **argv) ...@@ -309,7 +363,14 @@ int main(int argc, char **argv)
.events = POLLIN, .events = POLLIN,
}; };
poll(&pfd, 1, -1); ret = poll(&pfd, 1, -1);
if (ret < 0) {
ret = -errno;
goto error_close_buffer_access;
} else if (ret == 0) {
continue;
}
toread = buf_len; toread = buf_len;
} else { } else {
...@@ -321,7 +382,7 @@ int main(int argc, char **argv) ...@@ -321,7 +382,7 @@ int main(int argc, char **argv)
data, data,
toread*scan_size); toread*scan_size);
if (read_size < 0) { if (read_size < 0) {
if (errno == -EAGAIN) { if (errno == EAGAIN) {
printf("nothing available\n"); printf("nothing available\n");
continue; continue;
} else } else
...@@ -340,20 +401,31 @@ int main(int argc, char **argv) ...@@ -340,20 +401,31 @@ int main(int argc, char **argv)
if (!notrigger) if (!notrigger)
/* Disconnect the trigger - just write a dummy name. */ /* Disconnect the trigger - just write a dummy name. */
write_sysfs_string("trigger/current_trigger", ret = write_sysfs_string("trigger/current_trigger",
dev_dir_name, "NULL"); dev_dir_name, "NULL");
if (ret < 0)
printf("Failed to write to %s\n", dev_dir_name);
error_close_buffer_access: error_close_buffer_access:
close(fp); if (close(fp) == -1)
error_free_data: perror("Failed to close buffer");
free(data);
error_free_buffer_access: error_free_buffer_access:
free(buffer_access); free(buffer_access);
error_free_data:
free(data);
error_free_buf_dir_name: error_free_buf_dir_name:
free(buf_dir_name); free(buf_dir_name);
error_free_channels:
for (i = num_channels - 1; i >= 0; i--) {
free(channels[i].name);
free(channels[i].generic_name);
}
free(channels);
error_free_triggername: error_free_triggername:
if (datardytrigger) if (datardytrigger)
free(trigger_name); free(trigger_name);
error_ret: error_free_dev_dir_name:
free(dev_dir_name);
return ret; return ret;
} }
...@@ -213,23 +213,19 @@ static void print_event(struct iio_event_data *event) ...@@ -213,23 +213,19 @@ static void print_event(struct iio_event_data *event)
return; return;
} }
printf("Event: time: %lld, ", event->timestamp); printf("Event: time: %lld, type: %s", event->timestamp,
iio_chan_type_name_spec[type]);
if (mod != IIO_NO_MOD) { if (mod != IIO_NO_MOD)
printf("type: %s(%s), ", printf("(%s)", iio_modifier_names[mod]);
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) if (chan >= 0) {
printf("channel: %d-%d, ", chan, chan2); printf(", channel: %d", chan);
else if (chan >= 0) if (diff && chan2 >= 0)
printf("channel: %d, ", chan); printf("-%d", chan2);
}
printf("evtype: %s", iio_ev_type_text[ev_type]); printf(", evtype: %s", iio_ev_type_text[ev_type]);
if (dir != IIO_EV_DIR_NONE) if (dir != IIO_EV_DIR_NONE)
printf(", direction: %s", iio_ev_dir_text[dir]); printf(", direction: %s", iio_ev_dir_text[dir]);
...@@ -258,28 +254,34 @@ int main(int argc, char **argv) ...@@ -258,28 +254,34 @@ int main(int argc, char **argv)
device_name, dev_num); device_name, dev_num);
ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
if (ret < 0) { if (ret < 0) {
ret = -ENOMEM; return -ENOMEM;
goto error_ret;
} }
} else { } else {
/* If we can't find a IIO device by name assume device_name is a /* If we can't find a IIO device by name assume device_name is a
IIO chrdev */ IIO chrdev */
chrdev_name = strdup(device_name); chrdev_name = strdup(device_name);
if (!chrdev_name)
return -ENOMEM;
} }
fd = open(chrdev_name, 0); fd = open(chrdev_name, 0);
if (fd == -1) { if (fd == -1) {
fprintf(stdout, "Failed to open %s\n", chrdev_name);
ret = -errno; ret = -errno;
fprintf(stdout, "Failed to open %s\n", chrdev_name);
goto error_free_chrdev_name; goto error_free_chrdev_name;
} }
ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
close(fd);
if (ret == -1 || event_fd == -1) { if (ret == -1 || event_fd == -1) {
ret = -errno;
fprintf(stdout, "Failed to retrieve event fd\n"); fprintf(stdout, "Failed to retrieve event fd\n");
if (close(fd) == -1)
perror("Failed to close character device file");
goto error_free_chrdev_name;
}
if (close(fd) == -1) {
ret = -errno; ret = -errno;
goto error_free_chrdev_name; goto error_free_chrdev_name;
} }
...@@ -291,8 +293,8 @@ int main(int argc, char **argv) ...@@ -291,8 +293,8 @@ int main(int argc, char **argv)
printf("nothing available\n"); printf("nothing available\n");
continue; continue;
} else { } else {
perror("Failed to read event from device");
ret = -errno; ret = -errno;
perror("Failed to read event from device");
break; break;
} }
} }
...@@ -300,9 +302,11 @@ int main(int argc, char **argv) ...@@ -300,9 +302,11 @@ int main(int argc, char **argv)
print_event(&event); print_event(&event);
} }
close(event_fd); if (close(event_fd) == -1)
perror("Failed to close event file");
error_free_chrdev_name: error_free_chrdev_name:
free(chrdev_name); free(chrdev_name);
error_ret:
return ret; return ret;
} }
This diff is collapsed.
...@@ -28,9 +28,12 @@ extern const char *iio_dir; ...@@ -28,9 +28,12 @@ extern const char *iio_dir;
* @offset: offset 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 * @index: the channel index in the buffer output
* @bytes: number of bytes occupied in buffer output * @bytes: number of bytes occupied in buffer output
* @bits_used: number of valid bits of data
* @shift: amount of bits to shift right data before applying bit mask
* @mask: a bit mask for the raw output * @mask: a bit mask for the raw output
* @be: flag if data is big endian
* @is_signed: is the raw value stored signed * @is_signed: is the raw value stored signed
* @enabled: is this channel enabled * @location: data offset for this channel inside the buffer (in bytes)
**/ **/
struct iio_channel_info { struct iio_channel_info {
char *name; char *name;
...@@ -60,12 +63,15 @@ void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt); ...@@ -60,12 +63,15 @@ void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt);
int build_channel_array(const char *device_dir, int build_channel_array(const char *device_dir,
struct iio_channel_info **ci_array, int *counter); struct iio_channel_info **ci_array, int *counter);
int find_type_by_name(const char *name, const char *type); 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(const char *filename, const char *basedir, int val);
int write_sysfs_int_and_verify(char *filename, char *basedir, int val); int write_sysfs_int_and_verify(const char *filename, const char *basedir,
int write_sysfs_string_and_verify(char *filename, char *basedir, char *val); int val);
int write_sysfs_string(char *filename, char *basedir, char *val); int write_sysfs_string_and_verify(const char *filename, const char *basedir,
int read_sysfs_posint(char *filename, char *basedir); const char *val);
int read_sysfs_float(char *filename, char *basedir, float *val); int write_sysfs_string(const char *filename, const char *basedir,
const char *val);
int read_sysfs_posint(const char *filename, const char *basedir);
int read_sysfs_float(const char *filename, const char *basedir, float *val);
int read_sysfs_string(const char *filename, const char *basedir, char *str); int read_sysfs_string(const char *filename, const char *basedir, char *str);
#endif /* _IIO_UTILS_H_ */ #endif /* _IIO_UTILS_H_ */
...@@ -56,7 +56,7 @@ static int dump_channels(const char *dev_dir_name) ...@@ -56,7 +56,7 @@ static int dump_channels(const char *dev_dir_name)
printf(" %-10s\n", ent->d_name); printf(" %-10s\n", ent->d_name);
} }
return 0; return (closedir(dp) == -1) ? -errno : 0;
} }
static int dump_one_device(const char *dev_dir_name) static int dump_one_device(const char *dev_dir_name)
...@@ -69,7 +69,10 @@ static int dump_one_device(const char *dev_dir_name) ...@@ -69,7 +69,10 @@ static int dump_one_device(const char *dev_dir_name)
"%i", &dev_idx); "%i", &dev_idx);
if (retval != 1) if (retval != 1)
return -EINVAL; return -EINVAL;
read_sysfs_string("name", dev_dir_name, name); retval = read_sysfs_string("name", dev_dir_name, name);
if (retval)
return retval;
printf("Device %03d: %s\n", dev_idx, name); printf("Device %03d: %s\n", dev_idx, name);
if (verblevel >= VERBLEVEL_SENSORS) if (verblevel >= VERBLEVEL_SENSORS)
...@@ -87,28 +90,42 @@ static int dump_one_trigger(const char *dev_dir_name) ...@@ -87,28 +90,42 @@ static int dump_one_trigger(const char *dev_dir_name)
"%i", &dev_idx); "%i", &dev_idx);
if (retval != 1) if (retval != 1)
return -EINVAL; return -EINVAL;
read_sysfs_string("name", dev_dir_name, name); retval = read_sysfs_string("name", dev_dir_name, name);
if (retval)
return retval;
printf("Trigger %03d: %s\n", dev_idx, name); printf("Trigger %03d: %s\n", dev_idx, name);
return 0; return 0;
} }
static void dump_devices(void) static int dump_devices(void)
{ {
const struct dirent *ent; const struct dirent *ent;
int ret;
DIR *dp; DIR *dp;
dp = opendir(iio_dir); dp = opendir(iio_dir);
if (dp == NULL) { if (dp == NULL) {
printf("No industrial I/O devices available\n"); printf("No industrial I/O devices available\n");
return; return -ENODEV;
} }
while (ent = readdir(dp), ent != NULL) { while (ent = readdir(dp), ent != NULL) {
if (check_prefix(ent->d_name, type_device)) { if (check_prefix(ent->d_name, type_device)) {
char *dev_dir_name; char *dev_dir_name;
asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); if (asprintf(&dev_dir_name, "%s%s", iio_dir,
dump_one_device(dev_dir_name); ent->d_name) < 0) {
ret = -ENOMEM;
goto error_close_dir;
}
ret = dump_one_device(dev_dir_name);
if (ret) {
free(dev_dir_name);
goto error_close_dir;
}
free(dev_dir_name); free(dev_dir_name);
if (verblevel >= VERBLEVEL_SENSORS) if (verblevel >= VERBLEVEL_SENSORS)
printf("\n"); printf("\n");
...@@ -119,19 +136,35 @@ static void dump_devices(void) ...@@ -119,19 +136,35 @@ static void dump_devices(void)
if (check_prefix(ent->d_name, type_trigger)) { if (check_prefix(ent->d_name, type_trigger)) {
char *dev_dir_name; char *dev_dir_name;
asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); if (asprintf(&dev_dir_name, "%s%s", iio_dir,
dump_one_trigger(dev_dir_name); ent->d_name) < 0) {
ret = -ENOMEM;
goto error_close_dir;
}
ret = dump_one_trigger(dev_dir_name);
if (ret) {
free(dev_dir_name);
goto error_close_dir;
}
free(dev_dir_name); free(dev_dir_name);
} }
} }
closedir(dp); return (closedir(dp) == -1) ? -errno : 0;
error_close_dir:
if (closedir(dp) == -1)
perror("dump_devices(): Failed to close directory");
return ret;
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int c, err = 0; int c, err = 0;
while ((c = getopt(argc, argv, "d:D:v")) != EOF) { while ((c = getopt(argc, argv, "v")) != EOF) {
switch (c) { switch (c) {
case 'v': case 'v':
verblevel++; verblevel++;
...@@ -146,13 +179,9 @@ int main(int argc, char **argv) ...@@ -146,13 +179,9 @@ int main(int argc, char **argv)
if (err || argc > optind) { if (err || argc > optind) {
fprintf(stderr, "Usage: lsiio [options]...\n" fprintf(stderr, "Usage: lsiio [options]...\n"
"List industrial I/O devices\n" "List industrial I/O devices\n"
" -v, --verbose\n" " -v Increase verbosity (may be given multiple times)\n");
" Increase verbosity (may be given multiple times)\n"
);
exit(1); exit(1);
} }
dump_devices(); return dump_devices();
return 0;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment