Skip to content

Commit

Permalink
Merge tag 'iio-fixes-for-4.7a' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/jic23/iio into staging-linus

Jonathan writes:

First round of iio fixes for the 4.7 cycle.

A slightly bumper set due to travel delaying the pull request and a fair few
issues with the recent merge window patches.  Patches all over the place.
The st-sensors one is probably the most involved, but definitly solves the
issues seen.  Note there are some other issues around that handler
(and the fact that a lot of boards tie a level interrupt chip to an
edge interrupt only irq chip).  These are not regressions however, so
will turn up the slow route.

* core
  - iio_trigger_attach_pollfunc had some really badly wrong error handling.
  Another nasty triggered whilst chasing down issues with the st sensors
  rework below.
* ad5592r
  - fix an off by one error when allocating channels.
* am2315
  - a stray mutex unlock before we ever take the lock.
* apds9960
  - missing a parent in the driver model (which should be the i2c device).
  Result is it doesn't turn up under /sys/bus/i2c/devices which some
  userspace code uses for repeatable device identification.
* as3935
  - ABI usage bug which meant a processed value was reported as raw. Now
    reporting scale as well to ensure userspace has the info it needs.
  - Don't return processed value via the buffer - it doesn't conform to
    the ABI and will overflow in some cases.
  - Fix a wrongly sized buffer which would overflow trashing part of the
    stack.  Also move it onto the heap as part of the fix.
* bh1780
  - a missing return after write in debugfs lead to an incorrect read and
    a null pointer dereference.
  - dereferencing the wrong pointer in suspend and resume leading to
    unpredictable results.
  - assign a static name to avoid accidentally ending up with no name if
    loaded via device tree.
* bmi160
  - output data rate for the accelerometer was incorrectly reported. Fix it.
  - writing the output data rate was also wrong due to reverse parameters.
* bmp280
  - error message for wrong chip ID gave the wrong expected value.
* hdc100x
  - mask for writing the integration time was wrong allowin g us to get
  'stuck' in a particular value with no way back.
  - temperature reported in celsius rather than millicelsius as per the
  ABI.
  - Get rid of some incorrect data shifting which lead to readings being
  rather incorrect.
* max44000
  - drop scale attribute for proximity as it is an unscaled value (depends
    on what is in range rather than anything knowable at the detector).
* st-pressure
  - ABI compliance fixes - units were wrong.
* st-sensors
  - We introduced some nasty issues with the recent switch over to a
  a somewhat threaded handler in that we broke using a software trigger
  with these devices.  Now do it properly.  It's a larger patch than ideal
  for a fix, but the logic is straight forward.
  - Make sure the trigger is initialized before requesting the interrupt.
  This matters now the interrupt can be shared. Before it was ugly and wrong
  but short of flakey hardware could not be triggered.
  - Hammer down the dataready pin at boot - otherwise with really
  unlucky timing things could get interestingly wedged requiring a hard power
  down of the chip.
  • Loading branch information
Greg Kroah-Hartman committed Jun 8, 2016
2 parents af8c34c + 94bef00 commit 03cce00
Show file tree
Hide file tree
Showing 23 changed files with 230 additions and 100 deletions.
2 changes: 1 addition & 1 deletion Documentation/ABI/testing/sysfs-bus-iio-proximity-as3935
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
What /sys/bus/iio/devices/iio:deviceX/in_proximity_raw
What /sys/bus/iio/devices/iio:deviceX/in_proximity_input
Date: March 2014
KernelVersion: 3.15
Contact: Matt Ranostay <mranostay@gmail.com>
Expand Down
2 changes: 1 addition & 1 deletion drivers/iio/accel/st_accel_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static const struct iio_buffer_setup_ops st_accel_buffer_setup_ops = {

int st_accel_allocate_ring(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
return iio_triggered_buffer_setup(indio_dev, NULL,
&st_sensors_trigger_handler, &st_accel_buffer_setup_ops);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/iio/accel/st_accel_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,7 @@ static const struct iio_info accel_info = {
static const struct iio_trigger_ops st_accel_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = ST_ACCEL_TRIGGER_SET_STATE,
.validate_device = st_sensors_validate_device,
};
#define ST_ACCEL_TRIGGER_OPS (&st_accel_trigger_ops)
#else
Expand Down
25 changes: 7 additions & 18 deletions drivers/iio/common/st_sensors/st_sensors_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,31 +57,20 @@ irqreturn_t st_sensors_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct st_sensor_data *sdata = iio_priv(indio_dev);
s64 timestamp;

/* If we have a status register, check if this IRQ came from us */
if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) {
u8 status;

len = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
&status);
if (len < 0)
dev_err(sdata->dev, "could not read channel status\n");

/*
* If this was not caused by any channels on this sensor,
* return IRQ_NONE
*/
if (!(status & (u8)indio_dev->active_scan_mask[0]))
return IRQ_NONE;
}
/* If we do timetamping here, do it before reading the values */
if (sdata->hw_irq_trigger)
timestamp = sdata->hw_timestamp;
else
timestamp = iio_get_time_ns();

len = st_sensors_get_buffer_element(indio_dev, sdata->buffer_data);
if (len < 0)
goto st_sensors_get_buffer_element_error;

iio_push_to_buffers_with_timestamp(indio_dev, sdata->buffer_data,
pf->timestamp);
timestamp);

st_sensors_get_buffer_element_error:
iio_trigger_notify_done(indio_dev->trig);
Expand Down
8 changes: 8 additions & 0 deletions drivers/iio/common/st_sensors/st_sensors_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,11 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
if (err < 0)
return err;

/* Disable DRDY, this might be still be enabled after reboot. */
err = st_sensors_set_dataready_irq(indio_dev, false);
if (err < 0)
return err;

if (sdata->current_fullscale) {
err = st_sensors_set_fullscale(indio_dev,
sdata->current_fullscale->num);
Expand Down Expand Up @@ -424,6 +429,9 @@ int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable)
else
drdy_mask = sdata->sensor_settings->drdy_irq.mask_int2;

/* Flag to the poll function that the hardware trigger is in use */
sdata->hw_irq_trigger = enable;

/* Enable/Disable the interrupt generator for data ready. */
err = st_sensors_write_data_with_mask(indio_dev,
sdata->sensor_settings->drdy_irq.addr,
Expand Down
96 changes: 89 additions & 7 deletions drivers/iio/common/st_sensors/st_sensors_trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,73 @@
#include <linux/iio/common/st_sensors.h>
#include "st_sensors_core.h"

/**
* st_sensors_irq_handler() - top half of the IRQ-based triggers
* @irq: irq number
* @p: private handler data
*/
irqreturn_t st_sensors_irq_handler(int irq, void *p)
{
struct iio_trigger *trig = p;
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct st_sensor_data *sdata = iio_priv(indio_dev);

/* Get the time stamp as close in time as possible */
sdata->hw_timestamp = iio_get_time_ns();
return IRQ_WAKE_THREAD;
}

/**
* st_sensors_irq_thread() - bottom half of the IRQ-based triggers
* @irq: irq number
* @p: private handler data
*/
irqreturn_t st_sensors_irq_thread(int irq, void *p)
{
struct iio_trigger *trig = p;
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
struct st_sensor_data *sdata = iio_priv(indio_dev);
int ret;

/*
* If this trigger is backed by a hardware interrupt and we have a
* status register, check if this IRQ came from us
*/
if (sdata->sensor_settings->drdy_irq.addr_stat_drdy) {
u8 status;

ret = sdata->tf->read_byte(&sdata->tb, sdata->dev,
sdata->sensor_settings->drdy_irq.addr_stat_drdy,
&status);
if (ret < 0) {
dev_err(sdata->dev, "could not read channel status\n");
goto out_poll;
}
/*
* the lower bits of .active_scan_mask[0] is directly mapped
* to the channels on the sensor: either bit 0 for
* one-dimensional sensors, or e.g. x,y,z for accelerometers,
* gyroscopes or magnetometers. No sensor use more than 3
* channels, so cut the other status bits here.
*/
status &= 0x07;

/*
* If this was not caused by any channels on this sensor,
* return IRQ_NONE
*/
if (!indio_dev->active_scan_mask)
return IRQ_NONE;
if (!(status & (u8)indio_dev->active_scan_mask[0]))
return IRQ_NONE;
}

out_poll:
/* It's our IRQ: proceed to handle the register polling */
iio_trigger_poll_chained(p);
return IRQ_HANDLED;
}

int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
const struct iio_trigger_ops *trigger_ops)
{
Expand All @@ -30,6 +97,10 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
return -ENOMEM;
}

iio_trigger_set_drvdata(sdata->trig, indio_dev);
sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev;

irq = sdata->get_irq_data_ready(indio_dev);
irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq));
/*
Expand Down Expand Up @@ -77,9 +148,12 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
sdata->sensor_settings->drdy_irq.addr_stat_drdy)
irq_trig |= IRQF_SHARED;

err = request_threaded_irq(irq,
iio_trigger_generic_data_rdy_poll,
NULL,
/* Let's create an interrupt thread masking the hard IRQ here */
irq_trig |= IRQF_ONESHOT;

err = request_threaded_irq(sdata->get_irq_data_ready(indio_dev),
st_sensors_irq_handler,
st_sensors_irq_thread,
irq_trig,
sdata->trig->name,
sdata->trig);
Expand All @@ -88,10 +162,6 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
goto iio_trigger_free;
}

iio_trigger_set_drvdata(sdata->trig, indio_dev);
sdata->trig->ops = trigger_ops;
sdata->trig->dev.parent = sdata->dev;

err = iio_trigger_register(sdata->trig);
if (err < 0) {
dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
Expand Down Expand Up @@ -119,6 +189,18 @@ void st_sensors_deallocate_trigger(struct iio_dev *indio_dev)
}
EXPORT_SYMBOL(st_sensors_deallocate_trigger);

int st_sensors_validate_device(struct iio_trigger *trig,
struct iio_dev *indio_dev)
{
struct iio_dev *indio = iio_trigger_get_drvdata(trig);

if (indio != indio_dev)
return -EINVAL;

return 0;
}
EXPORT_SYMBOL(st_sensors_validate_device);

MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors trigger");
MODULE_LICENSE("GPL v2");
2 changes: 1 addition & 1 deletion drivers/iio/dac/ad5592r-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ static int ad5592r_alloc_channels(struct ad5592r_state *st)

device_for_each_child_node(st->dev, child) {
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret || reg > ARRAY_SIZE(st->channel_modes))
if (ret || reg >= ARRAY_SIZE(st->channel_modes))
continue;

ret = fwnode_property_read_u32(child, "adi,mode", &tmp);
Expand Down
2 changes: 1 addition & 1 deletion drivers/iio/gyro/st_gyro_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ static const struct iio_buffer_setup_ops st_gyro_buffer_setup_ops = {

int st_gyro_allocate_ring(struct iio_dev *indio_dev)
{
return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time,
return iio_triggered_buffer_setup(indio_dev, NULL,
&st_sensors_trigger_handler, &st_gyro_buffer_setup_ops);
}

Expand Down
1 change: 1 addition & 0 deletions drivers/iio/gyro/st_gyro_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ static const struct iio_info gyro_info = {
static const struct iio_trigger_ops st_gyro_trigger_ops = {
.owner = THIS_MODULE,
.set_trigger_state = ST_GYRO_TRIGGER_SET_STATE,
.validate_device = st_sensors_validate_device,
};
#define ST_GYRO_TRIGGER_OPS (&st_gyro_trigger_ops)
#else
Expand Down
4 changes: 1 addition & 3 deletions drivers/iio/humidity/am2315.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,8 @@ static irqreturn_t am2315_trigger_handler(int irq, void *p)
struct am2315_sensor_data sensor_data;

ret = am2315_read_data(data, &sensor_data);
if (ret < 0) {
mutex_unlock(&data->lock);
if (ret < 0)
goto err;
}

mutex_lock(&data->lock);
if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) {
Expand Down
20 changes: 10 additions & 10 deletions drivers/iio/humidity/hdc100x.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static const struct {
},
{ /* IIO_HUMIDITYRELATIVE channel */
.shift = 8,
.mask = 2,
.mask = 3,
},
};

Expand Down Expand Up @@ -164,14 +164,14 @@ static int hdc100x_get_measurement(struct hdc100x_data *data,
dev_err(&client->dev, "cannot read high byte measurement");
return ret;
}
val = ret << 6;
val = ret << 8;

ret = i2c_smbus_read_byte(client);
if (ret < 0) {
dev_err(&client->dev, "cannot read low byte measurement");
return ret;
}
val |= ret >> 2;
val |= ret;

return val;
}
Expand Down Expand Up @@ -211,18 +211,18 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_SCALE:
if (chan->type == IIO_TEMP) {
*val = 165;
*val2 = 65536 >> 2;
*val = 165000;
*val2 = 65536;
return IIO_VAL_FRACTIONAL;
} else {
*val = 0;
*val2 = 10000;
return IIO_VAL_INT_PLUS_MICRO;
*val = 100;
*val2 = 65536;
return IIO_VAL_FRACTIONAL;
}
break;
case IIO_CHAN_INFO_OFFSET:
*val = -3971;
*val2 = 879096;
*val = -15887;
*val2 = 515151;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
Expand Down
16 changes: 8 additions & 8 deletions drivers/iio/imu/bmi160/bmi160_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,11 @@ static const struct bmi160_scale_item bmi160_scale_table[] = {
};

static const struct bmi160_odr bmi160_accel_odr[] = {
{0x01, 0, 78125},
{0x02, 1, 5625},
{0x03, 3, 125},
{0x04, 6, 25},
{0x05, 12, 5},
{0x01, 0, 781250},
{0x02, 1, 562500},
{0x03, 3, 125000},
{0x04, 6, 250000},
{0x05, 12, 500000},
{0x06, 25, 0},
{0x07, 50, 0},
{0x08, 100, 0},
Expand All @@ -229,7 +229,7 @@ static const struct bmi160_odr bmi160_gyro_odr[] = {
{0x08, 100, 0},
{0x09, 200, 0},
{0x0A, 400, 0},
{0x0B, 8000, 0},
{0x0B, 800, 0},
{0x0C, 1600, 0},
{0x0D, 3200, 0},
};
Expand Down Expand Up @@ -364,8 +364,8 @@ int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t,

return regmap_update_bits(data->regmap,
bmi160_regs[t].config,
bmi160_odr_table[t].tbl[i].bits,
bmi160_regs[t].config_odr_mask);
bmi160_regs[t].config_odr_mask,
bmi160_odr_table[t].tbl[i].bits);
}

static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t,
Expand Down
23 changes: 18 additions & 5 deletions drivers/iio/industrialio-trigger.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,22 +210,35 @@ static int iio_trigger_attach_poll_func(struct iio_trigger *trig,

/* Prevent the module from being removed whilst attached to a trigger */
__module_get(pf->indio_dev->info->driver_module);

/* Get irq number */
pf->irq = iio_trigger_get_irq(trig);
if (pf->irq < 0)
goto out_put_module;

/* Request irq */
ret = request_threaded_irq(pf->irq, pf->h, pf->thread,
pf->type, pf->name,
pf);
if (ret < 0) {
module_put(pf->indio_dev->info->driver_module);
return ret;
}
if (ret < 0)
goto out_put_irq;

/* Enable trigger in driver */
if (trig->ops && trig->ops->set_trigger_state && notinuse) {
ret = trig->ops->set_trigger_state(trig, true);
if (ret < 0)
module_put(pf->indio_dev->info->driver_module);
goto out_free_irq;
}

return ret;

out_free_irq:
free_irq(pf->irq, pf);
out_put_irq:
iio_trigger_put_irq(trig, pf->irq);
out_put_module:
module_put(pf->indio_dev->info->driver_module);
return ret;
}

static int iio_trigger_detach_poll_func(struct iio_trigger *trig,
Expand Down
1 change: 1 addition & 0 deletions drivers/iio/light/apds9960.c
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,7 @@ static int apds9960_probe(struct i2c_client *client,

iio_device_attach_buffer(indio_dev, buffer);

indio_dev->dev.parent = &client->dev;
indio_dev->info = &apds9960_info;
indio_dev->name = APDS9960_DRV_NAME;
indio_dev->channels = apds9960_channels;
Expand Down
Loading

0 comments on commit 03cce00

Please sign in to comment.