* [PATCH v3 0/3] iio: sx9500: power usage and gpio changes
@ 2015-04-12 17:09 Vlad Dogaru
2015-04-12 17:09 ` [PATCH v3 1/3] iio: sx9500: optimize power usage Vlad Dogaru
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Vlad Dogaru @ 2015-04-12 17:09 UTC (permalink / raw)
To: jic23, linux-iio; +Cc: Vlad Dogaru
The meaty patch is the first one, making the chip use exactly as much
power as needed. The other two are a code cleanup and the addition of
an optional GPIO reset pin.
Changes since v2:
- don't reformat code in a patch that also changes functionality.
Changes since v1:
- having an interrupt is now optional. If none is available, raw reads
just sleep for the amount of time defined in the datasheet before
reading registers.
Vlad Dogaru (3):
iio: sx9500: optimize power usage
iio: sx9500: refactor GPIO interrupt code
iio: sx9500: add GPIO reset pin
drivers/iio/proximity/sx9500.c | 415 +++++++++++++++++++++++++++++++++--------
1 file changed, 340 insertions(+), 75 deletions(-)
--
1.9.1
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH v3 1/3] iio: sx9500: optimize power usage 2015-04-12 17:09 [PATCH v3 0/3] iio: sx9500: power usage and gpio changes Vlad Dogaru @ 2015-04-12 17:09 ` Vlad Dogaru 2015-04-18 19:12 ` Jonathan Cameron 2015-06-26 11:01 ` Hartmut Knaack 2015-04-12 17:09 ` [PATCH v3 2/3] iio: sx9500: refactor GPIO interrupt code Vlad Dogaru 2015-04-12 17:09 ` [PATCH v3 3/3] iio: sx9500: add GPIO reset pin Vlad Dogaru 2 siblings, 2 replies; 9+ messages in thread From: Vlad Dogaru @ 2015-04-12 17:09 UTC (permalink / raw) To: jic23, linux-iio; +Cc: Vlad Dogaru In the interest of lowering power usage, we only activate the proximity channels and interrupts that we are currently using. For raw reads, we activate the corresponding channel and the data ready interrupt and wait for the interrupt to trigger. If no interrupt is available, we wait for the documented scan period, as specified in the datasheet. The following types of usage patterns may overlap: * raw proximity reads (need a single data ready interrupt) * trigger usage (needs data ready interrupts as long as active) * proximity events (need near/far interrupts) * triggered buffer reads (don't need any interrupts, but are usually coupled with our own trigger. To mitigate all possible patterns, we implement usage counting for all the resources used: data ready interrupts, near/far interrupts and individual channels. The device enters sleep mode as documented in the data sheet when its buffer, trigger and events are disabled, and no raw reads are currently running. Because of this new usage pattern, it is important that we give the device a chance to perform an initial compensation for all its channels at probe time. Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com> --- drivers/iio/proximity/sx9500.c | 368 ++++++++++++++++++++++++++++++++++------- 1 file changed, 311 insertions(+), 57 deletions(-) diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 67643aa..f0f65a7 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -19,6 +19,7 @@ #include <linux/gpio/consumer.h> #include <linux/regmap.h> #include <linux/pm.h> +#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -75,6 +76,7 @@ #define SX9500_CONVDONE_IRQ BIT(3) #define SX9500_PROXSTAT_SHIFT 4 +#define SX9500_COMPSTAT_MASK GENMASK(3, 0) #define SX9500_NUM_CHANNELS 4 @@ -93,6 +95,9 @@ struct sx9500_data { u16 *buffer; /* Remember enabled channels and sample rate during suspend. */ unsigned int suspend_ctrl0; + struct completion completion; + int data_rdy_users, close_far_users; + int channel_users[SX9500_NUM_CHANNELS]; }; static const struct iio_event_spec sx9500_events[] = { @@ -143,6 +148,10 @@ static const struct { {2, 500000}, }; +static const unsigned int sx9500_scan_period_table[] = { + 30, 60, 90, 120, 150, 200, 300, 400, +}; + static const struct regmap_range sx9500_writable_reg_ranges[] = { regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK), regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8), @@ -195,7 +204,67 @@ static const struct regmap_config sx9500_regmap_config = { .volatile_table = &sx9500_volatile_regs, }; -static int sx9500_read_proximity(struct sx9500_data *data, +static int sx9500_inc_users(struct sx9500_data *data, int *counter, + unsigned int reg, unsigned int bitmask) +{ + (*counter)++; + if (*counter != 1) + /* Bit is already active, nothing to do. */ + return 0; + + return regmap_update_bits(data->regmap, reg, bitmask, bitmask); +} + +static int sx9500_dec_users(struct sx9500_data *data, int *counter, + unsigned int reg, unsigned int bitmask) +{ + (*counter)--; + if (*counter != 0) + /* There are more users, do not deactivate. */ + return 0; + + return regmap_update_bits(data->regmap, reg, bitmask, 0); +} + +static int sx9500_inc_chan_users(struct sx9500_data *data, int chan) +{ + return sx9500_inc_users(data, &data->channel_users[chan], + SX9500_REG_PROX_CTRL0, BIT(chan)); +} + +static int sx9500_dec_chan_users(struct sx9500_data *data, int chan) +{ + return sx9500_dec_users(data, &data->channel_users[chan], + SX9500_REG_PROX_CTRL0, BIT(chan)); +} + +static int sx9500_inc_data_rdy_users(struct sx9500_data *data) +{ + return sx9500_inc_users(data, &data->data_rdy_users, + SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ); +} + +static int sx9500_dec_data_rdy_users(struct sx9500_data *data) +{ + return sx9500_dec_users(data, &data->data_rdy_users, + SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ); +} + +static int sx9500_inc_close_far_users(struct sx9500_data *data) +{ + return sx9500_inc_users(data, &data->close_far_users, + SX9500_REG_IRQ_MSK, + SX9500_CLOSE_IRQ | SX9500_FAR_IRQ); +} + +static int sx9500_dec_close_far_users(struct sx9500_data *data) +{ + return sx9500_dec_users(data, &data->close_far_users, + SX9500_REG_IRQ_MSK, + SX9500_CLOSE_IRQ | SX9500_FAR_IRQ); +} + +static int sx9500_read_prox_data(struct sx9500_data *data, const struct iio_chan_spec *chan, int *val) { @@ -204,15 +273,90 @@ static int sx9500_read_proximity(struct sx9500_data *data, ret = regmap_write(data->regmap, SX9500_REG_SENSOR_SEL, chan->channel); if (ret < 0) - return ret; + goto out; ret = regmap_bulk_read(data->regmap, SX9500_REG_USE_MSB, ®val, 2); if (ret < 0) - return ret; + goto out; *val = 32767 - (s16)be16_to_cpu(regval); + ret = IIO_VAL_INT; - return IIO_VAL_INT; +out: + return ret; +} + +/* + * If we have no interrupt support, we have to wait for a scan period + * after enabling a channel to get a result. + */ +static int sx9500_wait_for_sample(struct sx9500_data *data) +{ + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &val); + if (ret < 0) + return ret; + + val = (val & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT; + + msleep(sx9500_scan_period_table[val]); + + return 0; +} + +static int sx9500_read_proximity(struct sx9500_data *data, + const struct iio_chan_spec *chan, + int *val) +{ + int ret; + + mutex_lock(&data->mutex); + + ret = sx9500_inc_chan_users(data, chan->channel); + if (ret < 0) + goto out; + + ret = sx9500_inc_data_rdy_users(data); + if (ret < 0) + goto out_dec_chan; + + mutex_unlock(&data->mutex); + + if (data->client->irq > 0) + ret = wait_for_completion_interruptible(&data->completion); + else + ret = sx9500_wait_for_sample(data); + + if (ret < 0) + return ret; + + mutex_lock(&data->mutex); + + ret = sx9500_read_prox_data(data, chan, val); + if (ret < 0) + goto out; + + ret = sx9500_dec_chan_users(data, chan->channel); + if (ret < 0) + goto out; + + ret = sx9500_dec_data_rdy_users(data); + if (ret < 0) + goto out; + + ret = IIO_VAL_INT; + + goto out; + +out_dec_chan: + sx9500_dec_chan_users(data, chan->channel); +out: + mutex_unlock(&data->mutex); + reinit_completion(&data->completion); + + return ret; } static int sx9500_read_samp_freq(struct sx9500_data *data, @@ -240,7 +384,6 @@ static int sx9500_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct sx9500_data *data = iio_priv(indio_dev); - int ret; switch (chan->type) { case IIO_PROXIMITY: @@ -248,10 +391,7 @@ static int sx9500_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: if (iio_buffer_enabled(indio_dev)) return -EBUSY; - mutex_lock(&data->mutex); - ret = sx9500_read_proximity(data, chan, val); - mutex_unlock(&data->mutex); - return ret; + return sx9500_read_proximity(data, chan, val); case IIO_CHAN_INFO_SAMP_FREQ: return sx9500_read_samp_freq(data, val, val2); default: @@ -322,28 +462,16 @@ static irqreturn_t sx9500_irq_handler(int irq, void *private) return IRQ_WAKE_THREAD; } -static irqreturn_t sx9500_irq_thread_handler(int irq, void *private) +static void sx9500_push_events(struct iio_dev *indio_dev) { - struct iio_dev *indio_dev = private; - struct sx9500_data *data = iio_priv(indio_dev); int ret; unsigned int val, chan; - - mutex_lock(&data->mutex); - - ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val); - if (ret < 0) { - dev_err(&data->client->dev, "i2c transfer error in irq\n"); - goto out; - } - - if (!(val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ))) - goto out; + struct sx9500_data *data = iio_priv(indio_dev); ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); if (ret < 0) { dev_err(&data->client->dev, "i2c transfer error in irq\n"); - goto out; + return; } val >>= SX9500_PROXSTAT_SHIFT; @@ -358,15 +486,34 @@ static irqreturn_t sx9500_irq_thread_handler(int irq, void *private) /* No change on this channel. */ continue; - dir = new_prox ? IIO_EV_DIR_FALLING : - IIO_EV_DIR_RISING; - ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, - chan, - IIO_EV_TYPE_THRESH, - dir); + dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; + ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, + IIO_EV_TYPE_THRESH, dir); iio_push_event(indio_dev, ev, iio_get_time_ns()); data->prox_stat[chan] = new_prox; } +} + +static irqreturn_t sx9500_irq_thread_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sx9500_data *data = iio_priv(indio_dev); + int ret; + unsigned int val; + + mutex_lock(&data->mutex); + + ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val); + if (ret < 0) { + dev_err(&data->client->dev, "i2c transfer error in irq\n"); + goto out; + } + + if (val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)) + sx9500_push_events(indio_dev); + + if (val & SX9500_CONVDONE_IRQ) + complete_all(&data->completion); out: mutex_unlock(&data->mutex); @@ -395,9 +542,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, int state) { struct sx9500_data *data = iio_priv(indio_dev); - int ret, i; - bool any_active = false; - unsigned int irqmask; + int ret; if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH || dir != IIO_EV_DIR_EITHER) @@ -405,24 +550,32 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, mutex_lock(&data->mutex); - data->event_enabled[chan->channel] = state; + if (state == 1) { + ret = sx9500_inc_chan_users(data, chan->channel); + if (ret < 0) + goto out_unlock; + ret = sx9500_inc_close_far_users(data); + if (ret < 0) + goto out_undo_chan; + } else { + ret = sx9500_dec_chan_users(data, chan->channel); + if (ret < 0) + goto out_unlock; + ret = sx9500_dec_close_far_users(data); + if (ret < 0) + goto out_undo_chan; + } - for (i = 0; i < SX9500_NUM_CHANNELS; i++) - if (data->event_enabled[i]) { - any_active = true; - break; - } + data->event_enabled[chan->channel] = state; + goto out_unlock; - irqmask = SX9500_CLOSE_IRQ | SX9500_FAR_IRQ; - if (any_active) - ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK, - irqmask, irqmask); +out_undo_chan: + if (state == 1) + sx9500_dec_chan_users(data, chan->channel); else - ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK, - irqmask, 0); - + sx9500_inc_chan_users(data, chan->channel); +out_unlock: mutex_unlock(&data->mutex); - return ret; } @@ -473,12 +626,16 @@ static int sx9500_set_trigger_state(struct iio_trigger *trig, mutex_lock(&data->mutex); - ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK, - SX9500_CONVDONE_IRQ, - state ? SX9500_CONVDONE_IRQ : 0); - if (ret == 0) - data->trigger_enabled = state; + if (state) + ret = sx9500_inc_data_rdy_users(data); + else + ret = sx9500_dec_data_rdy_users(data); + if (ret < 0) + goto out; + + data->trigger_enabled = state; +out: mutex_unlock(&data->mutex); return ret; @@ -500,7 +657,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { - ret = sx9500_read_proximity(data, &indio_dev->channels[bit], + ret = sx9500_read_prox_data(data, &indio_dev->channels[bit], &val); if (ret < 0) goto out; @@ -519,6 +676,62 @@ out: return IRQ_HANDLED; } +static int sx9500_buffer_preenable(struct iio_dev *indio_dev) +{ + struct sx9500_data *data = iio_priv(indio_dev); + int ret, i; + + mutex_lock(&data->mutex); + + for (i = 0; i < SX9500_NUM_CHANNELS; i++) + if (test_bit(i, indio_dev->active_scan_mask)) { + ret = sx9500_inc_chan_users(data, i); + if (ret) + break; + } + + if (ret) + for (i = i - 1; i >= 0; i--) + if (test_bit(i, indio_dev->active_scan_mask)) + sx9500_dec_chan_users(data, i); + + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9500_buffer_predisable(struct iio_dev *indio_dev) +{ + struct sx9500_data *data = iio_priv(indio_dev); + int ret, i; + + iio_triggered_buffer_predisable(indio_dev); + + mutex_lock(&data->mutex); + + for (i = 0; i < SX9500_NUM_CHANNELS; i++) + if (test_bit(i, indio_dev->active_scan_mask)) { + ret = sx9500_dec_chan_users(data, i); + if (ret) + break; + } + + if (ret) + for (i = i - 1; i >= 0; i--) + if (test_bit(i, indio_dev->active_scan_mask)) + sx9500_inc_chan_users(data, i); + + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_buffer_setup_ops sx9500_buffer_setup_ops = { + .preenable = sx9500_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = sx9500_buffer_predisable, +}; + struct sx9500_reg_default { u8 reg; u8 def; @@ -574,11 +787,44 @@ static const struct sx9500_reg_default sx9500_default_regs[] = { }, { .reg = SX9500_REG_PROX_CTRL0, - /* Scan period: 30ms, all sensors enabled. */ - .def = 0x0f, + /* Scan period: 30ms, all sensors disabled. */ + .def = 0x00, }, }; +/* Activate all channels and perform an initial compensation. */ +static int sx9500_init_compensation(struct iio_dev *indio_dev) +{ + struct sx9500_data *data = iio_priv(indio_dev); + int i, ret; + unsigned int val; + + ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, + GENMASK(SX9500_NUM_CHANNELS, 0), + GENMASK(SX9500_NUM_CHANNELS, 0)); + if (ret < 0) + return ret; + + for (i = 10; i >= 0; i--) { + usleep_range(10000, 20000); + ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); + if (ret < 0) + goto out; + if (!(val & SX9500_COMPSTAT_MASK)) + break; + } + + if (i < 0) { + dev_err(&data->client->dev, "initial compensation timed out"); + ret = -ETIMEDOUT; + } + +out: + regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, + GENMASK(SX9500_NUM_CHANNELS, 0), 0); + return ret; +} + static int sx9500_init_device(struct iio_dev *indio_dev) { struct sx9500_data *data = iio_priv(indio_dev); @@ -606,6 +852,10 @@ static int sx9500_init_device(struct iio_dev *indio_dev) return ret; } + ret = sx9500_init_compensation(indio_dev); + if (ret < 0) + return ret; + return 0; } @@ -649,6 +899,7 @@ static int sx9500_probe(struct i2c_client *client, data = iio_priv(indio_dev); data->client = client; mutex_init(&data->mutex); + init_completion(&data->completion); data->trigger_enabled = false; data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config); @@ -668,7 +919,9 @@ static int sx9500_probe(struct i2c_client *client, if (client->irq <= 0) client->irq = sx9500_gpio_probe(client, data); - if (client->irq > 0) { + if (client->irq <= 0) + dev_warn(&client->dev, "no valid irq found\n"); + else { ret = devm_request_threaded_irq(&client->dev, client->irq, sx9500_irq_handler, sx9500_irq_thread_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, @@ -691,7 +944,8 @@ static int sx9500_probe(struct i2c_client *client, } ret = iio_triggered_buffer_setup(indio_dev, NULL, - sx9500_trigger_handler, NULL); + sx9500_trigger_handler, + &sx9500_buffer_setup_ops); if (ret < 0) goto out_trigger_unregister; -- 1.9.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] iio: sx9500: optimize power usage 2015-04-12 17:09 ` [PATCH v3 1/3] iio: sx9500: optimize power usage Vlad Dogaru @ 2015-04-18 19:12 ` Jonathan Cameron 2015-06-26 11:01 ` Hartmut Knaack 1 sibling, 0 replies; 9+ messages in thread From: Jonathan Cameron @ 2015-04-18 19:12 UTC (permalink / raw) To: Vlad Dogaru, linux-iio On 12/04/15 18:09, Vlad Dogaru wrote: > In the interest of lowering power usage, we only activate the proximity > channels and interrupts that we are currently using. > > For raw reads, we activate the corresponding channel and the data ready > interrupt and wait for the interrupt to trigger. If no interrupt is > available, we wait for the documented scan period, as specified in the > datasheet. > > The following types of usage patterns may overlap: > > * raw proximity reads (need a single data ready interrupt) > * trigger usage (needs data ready interrupts as long as active) > * proximity events (need near/far interrupts) > * triggered buffer reads (don't need any interrupts, but are usually > coupled with our own trigger. > > To mitigate all possible patterns, we implement usage counting for all > the resources used: data ready interrupts, near/far interrupts and > individual channels. > > The device enters sleep mode as documented in the data sheet when its > buffer, trigger and events are disabled, and no raw reads are currently > running. > > Because of this new usage pattern, it is important that we give the > device a chance to perform an initial compensation for all its channels > at probe time. > > Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com> I only really had one query which was about a bit of nasty refactoring that snuck in here. I'll remove that in the merge rather than bouncing this back to you. > --- > drivers/iio/proximity/sx9500.c | 368 ++++++++++++++++++++++++++++++++++------- > 1 file changed, 311 insertions(+), 57 deletions(-) > > diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c > index 67643aa..f0f65a7 100644 > --- a/drivers/iio/proximity/sx9500.c > +++ b/drivers/iio/proximity/sx9500.c > @@ -19,6 +19,7 @@ > #include <linux/gpio/consumer.h> > #include <linux/regmap.h> > #include <linux/pm.h> > +#include <linux/delay.h> > > #include <linux/iio/iio.h> > #include <linux/iio/buffer.h> > @@ -75,6 +76,7 @@ > #define SX9500_CONVDONE_IRQ BIT(3) > > #define SX9500_PROXSTAT_SHIFT 4 > +#define SX9500_COMPSTAT_MASK GENMASK(3, 0) > > #define SX9500_NUM_CHANNELS 4 > > @@ -93,6 +95,9 @@ struct sx9500_data { > u16 *buffer; > /* Remember enabled channels and sample rate during suspend. */ > unsigned int suspend_ctrl0; > + struct completion completion; > + int data_rdy_users, close_far_users; > + int channel_users[SX9500_NUM_CHANNELS]; > }; > > static const struct iio_event_spec sx9500_events[] = { > @@ -143,6 +148,10 @@ static const struct { > {2, 500000}, > }; > > +static const unsigned int sx9500_scan_period_table[] = { > + 30, 60, 90, 120, 150, 200, 300, 400, > +}; > + > static const struct regmap_range sx9500_writable_reg_ranges[] = { > regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK), > regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8), > @@ -195,7 +204,67 @@ static const struct regmap_config sx9500_regmap_config = { > .volatile_table = &sx9500_volatile_regs, > }; > > -static int sx9500_read_proximity(struct sx9500_data *data, > +static int sx9500_inc_users(struct sx9500_data *data, int *counter, > + unsigned int reg, unsigned int bitmask) > +{ > + (*counter)++; > + if (*counter != 1) > + /* Bit is already active, nothing to do. */ > + return 0; > + > + return regmap_update_bits(data->regmap, reg, bitmask, bitmask); > +} > + > +static int sx9500_dec_users(struct sx9500_data *data, int *counter, > + unsigned int reg, unsigned int bitmask) > +{ > + (*counter)--; > + if (*counter != 0) > + /* There are more users, do not deactivate. */ > + return 0; > + > + return regmap_update_bits(data->regmap, reg, bitmask, 0); > +} > + > +static int sx9500_inc_chan_users(struct sx9500_data *data, int chan) > +{ > + return sx9500_inc_users(data, &data->channel_users[chan], > + SX9500_REG_PROX_CTRL0, BIT(chan)); > +} > + > +static int sx9500_dec_chan_users(struct sx9500_data *data, int chan) > +{ > + return sx9500_dec_users(data, &data->channel_users[chan], > + SX9500_REG_PROX_CTRL0, BIT(chan)); > +} > + > +static int sx9500_inc_data_rdy_users(struct sx9500_data *data) > +{ > + return sx9500_inc_users(data, &data->data_rdy_users, > + SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ); > +} > + > +static int sx9500_dec_data_rdy_users(struct sx9500_data *data) > +{ > + return sx9500_dec_users(data, &data->data_rdy_users, > + SX9500_REG_IRQ_MSK, SX9500_CONVDONE_IRQ); > +} > + > +static int sx9500_inc_close_far_users(struct sx9500_data *data) > +{ > + return sx9500_inc_users(data, &data->close_far_users, > + SX9500_REG_IRQ_MSK, > + SX9500_CLOSE_IRQ | SX9500_FAR_IRQ); > +} > + > +static int sx9500_dec_close_far_users(struct sx9500_data *data) > +{ > + return sx9500_dec_users(data, &data->close_far_users, > + SX9500_REG_IRQ_MSK, > + SX9500_CLOSE_IRQ | SX9500_FAR_IRQ); > +} > + > +static int sx9500_read_prox_data(struct sx9500_data *data, > const struct iio_chan_spec *chan, > int *val) > { > @@ -204,15 +273,90 @@ static int sx9500_read_proximity(struct sx9500_data *data, > > ret = regmap_write(data->regmap, SX9500_REG_SENSOR_SEL, chan->channel); > if (ret < 0) > - return ret; > + goto out; Why? The original code is the prefered option. Always return directly if there is no unwinding to do. > > ret = regmap_bulk_read(data->regmap, SX9500_REG_USE_MSB, ®val, 2); > if (ret < 0) > - return ret; > + goto out; > > *val = 32767 - (s16)be16_to_cpu(regval); > + ret = IIO_VAL_INT; > > - return IIO_VAL_INT; > +out: > + return ret; > +} > + > +/* > + * If we have no interrupt support, we have to wait for a scan period > + * after enabling a channel to get a result. > + */ > +static int sx9500_wait_for_sample(struct sx9500_data *data) > +{ > + int ret; > + unsigned int val; > + > + ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &val); > + if (ret < 0) > + return ret; > + > + val = (val & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT; > + > + msleep(sx9500_scan_period_table[val]); > + > + return 0; > +} > + > +static int sx9500_read_proximity(struct sx9500_data *data, > + const struct iio_chan_spec *chan, > + int *val) > +{ > + int ret; > + > + mutex_lock(&data->mutex); > + > + ret = sx9500_inc_chan_users(data, chan->channel); > + if (ret < 0) > + goto out; > + > + ret = sx9500_inc_data_rdy_users(data); > + if (ret < 0) > + goto out_dec_chan; > + > + mutex_unlock(&data->mutex); > + > + if (data->client->irq > 0) > + ret = wait_for_completion_interruptible(&data->completion); > + else > + ret = sx9500_wait_for_sample(data); > + > + if (ret < 0) > + return ret; > + > + mutex_lock(&data->mutex); > + > + ret = sx9500_read_prox_data(data, chan, val); > + if (ret < 0) > + goto out; > + > + ret = sx9500_dec_chan_users(data, chan->channel); > + if (ret < 0) > + goto out; > + > + ret = sx9500_dec_data_rdy_users(data); > + if (ret < 0) > + goto out; > + > + ret = IIO_VAL_INT; > + > + goto out; > + > +out_dec_chan: > + sx9500_dec_chan_users(data, chan->channel); > +out: > + mutex_unlock(&data->mutex); > + reinit_completion(&data->completion); > + > + return ret; > } > > static int sx9500_read_samp_freq(struct sx9500_data *data, > @@ -240,7 +384,6 @@ static int sx9500_read_raw(struct iio_dev *indio_dev, > int *val, int *val2, long mask) > { > struct sx9500_data *data = iio_priv(indio_dev); > - int ret; > > switch (chan->type) { > case IIO_PROXIMITY: > @@ -248,10 +391,7 @@ static int sx9500_read_raw(struct iio_dev *indio_dev, > case IIO_CHAN_INFO_RAW: > if (iio_buffer_enabled(indio_dev)) > return -EBUSY; > - mutex_lock(&data->mutex); > - ret = sx9500_read_proximity(data, chan, val); > - mutex_unlock(&data->mutex); > - return ret; > + return sx9500_read_proximity(data, chan, val); > case IIO_CHAN_INFO_SAMP_FREQ: > return sx9500_read_samp_freq(data, val, val2); > default: > @@ -322,28 +462,16 @@ static irqreturn_t sx9500_irq_handler(int irq, void *private) > return IRQ_WAKE_THREAD; > } > > -static irqreturn_t sx9500_irq_thread_handler(int irq, void *private) > +static void sx9500_push_events(struct iio_dev *indio_dev) > { > - struct iio_dev *indio_dev = private; > - struct sx9500_data *data = iio_priv(indio_dev); > int ret; > unsigned int val, chan; > - > - mutex_lock(&data->mutex); > - > - ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val); > - if (ret < 0) { > - dev_err(&data->client->dev, "i2c transfer error in irq\n"); > - goto out; > - } > - > - if (!(val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ))) > - goto out; > + struct sx9500_data *data = iio_priv(indio_dev); > > ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); > if (ret < 0) { > dev_err(&data->client->dev, "i2c transfer error in irq\n"); > - goto out; > + return; > } > > val >>= SX9500_PROXSTAT_SHIFT; > @@ -358,15 +486,34 @@ static irqreturn_t sx9500_irq_thread_handler(int irq, void *private) > /* No change on this channel. */ > continue; > > - dir = new_prox ? IIO_EV_DIR_FALLING : > - IIO_EV_DIR_RISING; > - ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, > - chan, > - IIO_EV_TYPE_THRESH, > - dir); > + dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; > + ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, > + IIO_EV_TYPE_THRESH, dir); > iio_push_event(indio_dev, ev, iio_get_time_ns()); > data->prox_stat[chan] = new_prox; > } > +} > + > +static irqreturn_t sx9500_irq_thread_handler(int irq, void *private) > +{ > + struct iio_dev *indio_dev = private; > + struct sx9500_data *data = iio_priv(indio_dev); > + int ret; > + unsigned int val; > + > + mutex_lock(&data->mutex); > + > + ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val); > + if (ret < 0) { > + dev_err(&data->client->dev, "i2c transfer error in irq\n"); > + goto out; > + } > + > + if (val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)) > + sx9500_push_events(indio_dev); > + > + if (val & SX9500_CONVDONE_IRQ) > + complete_all(&data->completion); > > out: > mutex_unlock(&data->mutex); > @@ -395,9 +542,7 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, > int state) > { > struct sx9500_data *data = iio_priv(indio_dev); > - int ret, i; > - bool any_active = false; > - unsigned int irqmask; > + int ret; > > if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH || > dir != IIO_EV_DIR_EITHER) > @@ -405,24 +550,32 @@ static int sx9500_write_event_config(struct iio_dev *indio_dev, > > mutex_lock(&data->mutex); > > - data->event_enabled[chan->channel] = state; > + if (state == 1) { > + ret = sx9500_inc_chan_users(data, chan->channel); > + if (ret < 0) > + goto out_unlock; > + ret = sx9500_inc_close_far_users(data); > + if (ret < 0) > + goto out_undo_chan; > + } else { > + ret = sx9500_dec_chan_users(data, chan->channel); > + if (ret < 0) > + goto out_unlock; > + ret = sx9500_dec_close_far_users(data); > + if (ret < 0) > + goto out_undo_chan; > + } > > - for (i = 0; i < SX9500_NUM_CHANNELS; i++) > - if (data->event_enabled[i]) { > - any_active = true; > - break; > - } > + data->event_enabled[chan->channel] = state; > + goto out_unlock; > > - irqmask = SX9500_CLOSE_IRQ | SX9500_FAR_IRQ; > - if (any_active) > - ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK, > - irqmask, irqmask); > +out_undo_chan: > + if (state == 1) > + sx9500_dec_chan_users(data, chan->channel); > else > - ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK, > - irqmask, 0); > - > + sx9500_inc_chan_users(data, chan->channel); > +out_unlock: > mutex_unlock(&data->mutex); > - > return ret; > } > > @@ -473,12 +626,16 @@ static int sx9500_set_trigger_state(struct iio_trigger *trig, > > mutex_lock(&data->mutex); > > - ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK, > - SX9500_CONVDONE_IRQ, > - state ? SX9500_CONVDONE_IRQ : 0); > - if (ret == 0) > - data->trigger_enabled = state; > + if (state) > + ret = sx9500_inc_data_rdy_users(data); > + else > + ret = sx9500_dec_data_rdy_users(data); > + if (ret < 0) > + goto out; > + > + data->trigger_enabled = state; > > +out: > mutex_unlock(&data->mutex); > > return ret; > @@ -500,7 +657,7 @@ static irqreturn_t sx9500_trigger_handler(int irq, void *private) > > for_each_set_bit(bit, indio_dev->active_scan_mask, > indio_dev->masklength) { > - ret = sx9500_read_proximity(data, &indio_dev->channels[bit], > + ret = sx9500_read_prox_data(data, &indio_dev->channels[bit], > &val); > if (ret < 0) > goto out; > @@ -519,6 +676,62 @@ out: > return IRQ_HANDLED; > } > > +static int sx9500_buffer_preenable(struct iio_dev *indio_dev) > +{ > + struct sx9500_data *data = iio_priv(indio_dev); > + int ret, i; > + > + mutex_lock(&data->mutex); > + > + for (i = 0; i < SX9500_NUM_CHANNELS; i++) > + if (test_bit(i, indio_dev->active_scan_mask)) { > + ret = sx9500_inc_chan_users(data, i); > + if (ret) > + break; > + } > + > + if (ret) > + for (i = i - 1; i >= 0; i--) > + if (test_bit(i, indio_dev->active_scan_mask)) > + sx9500_dec_chan_users(data, i); > + > + mutex_unlock(&data->mutex); > + > + return ret; > +} > + > +static int sx9500_buffer_predisable(struct iio_dev *indio_dev) > +{ > + struct sx9500_data *data = iio_priv(indio_dev); > + int ret, i; > + > + iio_triggered_buffer_predisable(indio_dev); > + > + mutex_lock(&data->mutex); > + > + for (i = 0; i < SX9500_NUM_CHANNELS; i++) > + if (test_bit(i, indio_dev->active_scan_mask)) { > + ret = sx9500_dec_chan_users(data, i); > + if (ret) > + break; > + } > + > + if (ret) > + for (i = i - 1; i >= 0; i--) > + if (test_bit(i, indio_dev->active_scan_mask)) > + sx9500_inc_chan_users(data, i); > + > + mutex_unlock(&data->mutex); > + > + return ret; > +} > + > +static const struct iio_buffer_setup_ops sx9500_buffer_setup_ops = { > + .preenable = sx9500_buffer_preenable, > + .postenable = iio_triggered_buffer_postenable, > + .predisable = sx9500_buffer_predisable, > +}; > + > struct sx9500_reg_default { > u8 reg; > u8 def; > @@ -574,11 +787,44 @@ static const struct sx9500_reg_default sx9500_default_regs[] = { > }, > { > .reg = SX9500_REG_PROX_CTRL0, > - /* Scan period: 30ms, all sensors enabled. */ > - .def = 0x0f, > + /* Scan period: 30ms, all sensors disabled. */ > + .def = 0x00, > }, > }; > > +/* Activate all channels and perform an initial compensation. */ > +static int sx9500_init_compensation(struct iio_dev *indio_dev) > +{ > + struct sx9500_data *data = iio_priv(indio_dev); > + int i, ret; > + unsigned int val; > + > + ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, > + GENMASK(SX9500_NUM_CHANNELS, 0), > + GENMASK(SX9500_NUM_CHANNELS, 0)); > + if (ret < 0) > + return ret; > + > + for (i = 10; i >= 0; i--) { > + usleep_range(10000, 20000); > + ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); > + if (ret < 0) > + goto out; > + if (!(val & SX9500_COMPSTAT_MASK)) > + break; > + } > + > + if (i < 0) { > + dev_err(&data->client->dev, "initial compensation timed out"); > + ret = -ETIMEDOUT; > + } > + > +out: > + regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, > + GENMASK(SX9500_NUM_CHANNELS, 0), 0); > + return ret; > +} > + > static int sx9500_init_device(struct iio_dev *indio_dev) > { > struct sx9500_data *data = iio_priv(indio_dev); > @@ -606,6 +852,10 @@ static int sx9500_init_device(struct iio_dev *indio_dev) > return ret; > } > > + ret = sx9500_init_compensation(indio_dev); > + if (ret < 0) > + return ret; > + > return 0; > } > > @@ -649,6 +899,7 @@ static int sx9500_probe(struct i2c_client *client, > data = iio_priv(indio_dev); > data->client = client; > mutex_init(&data->mutex); > + init_completion(&data->completion); > data->trigger_enabled = false; > > data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config); > @@ -668,7 +919,9 @@ static int sx9500_probe(struct i2c_client *client, > if (client->irq <= 0) > client->irq = sx9500_gpio_probe(client, data); > > - if (client->irq > 0) { > + if (client->irq <= 0) > + dev_warn(&client->dev, "no valid irq found\n"); > + else { > ret = devm_request_threaded_irq(&client->dev, client->irq, > sx9500_irq_handler, sx9500_irq_thread_handler, > IRQF_TRIGGER_FALLING | IRQF_ONESHOT, > @@ -691,7 +944,8 @@ static int sx9500_probe(struct i2c_client *client, > } > > ret = iio_triggered_buffer_setup(indio_dev, NULL, > - sx9500_trigger_handler, NULL); > + sx9500_trigger_handler, > + &sx9500_buffer_setup_ops); > if (ret < 0) > goto out_trigger_unregister; > > ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] iio: sx9500: optimize power usage 2015-04-12 17:09 ` [PATCH v3 1/3] iio: sx9500: optimize power usage Vlad Dogaru 2015-04-18 19:12 ` Jonathan Cameron @ 2015-06-26 11:01 ` Hartmut Knaack 2015-06-29 7:42 ` Vlad Dogaru 1 sibling, 1 reply; 9+ messages in thread From: Hartmut Knaack @ 2015-06-26 11:01 UTC (permalink / raw) To: Vlad Dogaru, jic23, linux-iio Vlad Dogaru schrieb am 12.04.2015 um 19:09: > In the interest of lowering power usage, we only activate the proximity > channels and interrupts that we are currently using. > > For raw reads, we activate the corresponding channel and the data ready > interrupt and wait for the interrupt to trigger. If no interrupt is > available, we wait for the documented scan period, as specified in the > datasheet. > Hi, I have a question inline, and also spotted a bug. <...> > +static int sx9500_read_proximity(struct sx9500_data *data, > + const struct iio_chan_spec *chan, > + int *val) > +{ > + int ret; > + > + mutex_lock(&data->mutex); > + > + ret = sx9500_inc_chan_users(data, chan->channel); > + if (ret < 0) > + goto out; > + > + ret = sx9500_inc_data_rdy_users(data); > + if (ret < 0) > + goto out_dec_chan; > + > + mutex_unlock(&data->mutex); > + > + if (data->client->irq > 0) > + ret = wait_for_completion_interruptible(&data->completion); > + else > + ret = sx9500_wait_for_sample(data); > + > + if (ret < 0) > + return ret; If an error is encountered from here on, the device won't be able to enter a low power mode again, since you don't decrease the chan_users[chan] and data_rdy_users elements of sx9500_data. Is this intended? > + > + mutex_lock(&data->mutex); > + > + ret = sx9500_read_prox_data(data, chan, val); > + if (ret < 0) > + goto out; > + > + ret = sx9500_dec_chan_users(data, chan->channel); > + if (ret < 0) > + goto out; > + > + ret = sx9500_dec_data_rdy_users(data); > + if (ret < 0) > + goto out; > + > + ret = IIO_VAL_INT; > + > + goto out; > + > +out_dec_chan: > + sx9500_dec_chan_users(data, chan->channel); > +out: > + mutex_unlock(&data->mutex); > + reinit_completion(&data->completion); > + > + return ret; > } <...> > +/* Activate all channels and perform an initial compensation. */ > +static int sx9500_init_compensation(struct iio_dev *indio_dev) > +{ > + struct sx9500_data *data = iio_priv(indio_dev); > + int i, ret; > + unsigned int val; > + > + ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, > + GENMASK(SX9500_NUM_CHANNELS, 0), > + GENMASK(SX9500_NUM_CHANNELS, 0)); This mask should just reach until SX9500_NUM_CHANNELS - 1. Right now it messes with the lowest bit of SCANPERIOD. Why not define the channel mask with all other definitions and use a catchy name here? Thanks, Hartmut > + if (ret < 0) > + return ret; > + > + for (i = 10; i >= 0; i--) { > + usleep_range(10000, 20000); > + ret = regmap_read(data->regmap, SX9500_REG_STAT, &val); > + if (ret < 0) > + goto out; > + if (!(val & SX9500_COMPSTAT_MASK)) > + break; > + } > + > + if (i < 0) { > + dev_err(&data->client->dev, "initial compensation timed out"); > + ret = -ETIMEDOUT; > + } > + > +out: > + regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, > + GENMASK(SX9500_NUM_CHANNELS, 0), 0); > + return ret; > +} > + ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v3 1/3] iio: sx9500: optimize power usage 2015-06-26 11:01 ` Hartmut Knaack @ 2015-06-29 7:42 ` Vlad Dogaru 0 siblings, 0 replies; 9+ messages in thread From: Vlad Dogaru @ 2015-06-29 7:42 UTC (permalink / raw) To: Hartmut Knaack; +Cc: jic23, linux-iio On Fri, Jun 26, 2015 at 01:01:42PM +0200, Hartmut Knaack wrote: > Vlad Dogaru schrieb am 12.04.2015 um 19:09: > > In the interest of lowering power usage, we only activate the proximity > > channels and interrupts that we are currently using. > > > > For raw reads, we activate the corresponding channel and the data ready > > interrupt and wait for the interrupt to trigger. If no interrupt is > > available, we wait for the documented scan period, as specified in the > > datasheet. > > > > Hi, > I have a question inline, and also spotted a bug. > > <...> > > > +static int sx9500_read_proximity(struct sx9500_data *data, > > + const struct iio_chan_spec *chan, > > + int *val) > > +{ > > + int ret; > > + > > + mutex_lock(&data->mutex); > > + > > + ret = sx9500_inc_chan_users(data, chan->channel); > > + if (ret < 0) > > + goto out; > > + > > + ret = sx9500_inc_data_rdy_users(data); > > + if (ret < 0) > > + goto out_dec_chan; > > + > > + mutex_unlock(&data->mutex); > > + > > + if (data->client->irq > 0) > > + ret = wait_for_completion_interruptible(&data->completion); > > + else > > + ret = sx9500_wait_for_sample(data); > > + > > + if (ret < 0) > > + return ret; > > If an error is encountered from here on, the device won't be able to enter > a low power mode again, since you don't decrease the chan_users[chan] and > data_rdy_users elements of sx9500_data. Is this intended? No, I didn't intend that. > > > + > > + mutex_lock(&data->mutex); > > + > > + ret = sx9500_read_prox_data(data, chan, val); > > + if (ret < 0) > > + goto out; > > + > > + ret = sx9500_dec_chan_users(data, chan->channel); > > + if (ret < 0) > > + goto out; > > + > > + ret = sx9500_dec_data_rdy_users(data); > > + if (ret < 0) > > + goto out; > > + > > + ret = IIO_VAL_INT; > > + > > + goto out; > > + > > +out_dec_chan: > > + sx9500_dec_chan_users(data, chan->channel); > > +out: > > + mutex_unlock(&data->mutex); > > + reinit_completion(&data->completion); > > + > > + return ret; > > } > > <...> > > > > +/* Activate all channels and perform an initial compensation. */ > > +static int sx9500_init_compensation(struct iio_dev *indio_dev) > > +{ > > + struct sx9500_data *data = iio_priv(indio_dev); > > + int i, ret; > > + unsigned int val; > > + > > + ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0, > > + GENMASK(SX9500_NUM_CHANNELS, 0), > > + GENMASK(SX9500_NUM_CHANNELS, 0)); > > This mask should just reach until SX9500_NUM_CHANNELS - 1. Right now it > messes with the lowest bit of SCANPERIOD. Why not define the channel mask > with all other definitions and use a catchy name here? You are correct, thanks for pointing this out. Will send patches for both shortly. Thanks, Vlad ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 2/3] iio: sx9500: refactor GPIO interrupt code 2015-04-12 17:09 [PATCH v3 0/3] iio: sx9500: power usage and gpio changes Vlad Dogaru 2015-04-12 17:09 ` [PATCH v3 1/3] iio: sx9500: optimize power usage Vlad Dogaru @ 2015-04-12 17:09 ` Vlad Dogaru 2015-04-18 19:14 ` Jonathan Cameron 2015-04-12 17:09 ` [PATCH v3 3/3] iio: sx9500: add GPIO reset pin Vlad Dogaru 2 siblings, 1 reply; 9+ messages in thread From: Vlad Dogaru @ 2015-04-12 17:09 UTC (permalink / raw) To: jic23, linux-iio; +Cc: Vlad Dogaru Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com> --- drivers/iio/proximity/sx9500.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index f0f65a7..72efbbc 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -859,30 +859,24 @@ static int sx9500_init_device(struct iio_dev *indio_dev) return 0; } -static int sx9500_gpio_probe(struct i2c_client *client, - struct sx9500_data *data) +static void sx9500_gpio_probe(struct i2c_client *client, + struct sx9500_data *data) { struct device *dev; struct gpio_desc *gpio; - int ret; if (!client) - return -EINVAL; + return; dev = &client->dev; - /* data ready gpio interrupt pin */ - 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); + if (client->irq <= 0) { + gpio = devm_gpiod_get_index(dev, SX9500_GPIO_INT, 0, GPIOD_IN); + if (IS_ERR(gpio)) + dev_err(dev, "gpio get irq failed\n"); + else + client->irq = gpiod_to_irq(gpio); } - - ret = gpiod_to_irq(gpio); - - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); - - return ret; } static int sx9500_probe(struct i2c_client *client, @@ -916,8 +910,7 @@ static int sx9500_probe(struct i2c_client *client, indio_dev->modes = INDIO_DIRECT_MODE; i2c_set_clientdata(client, indio_dev); - if (client->irq <= 0) - client->irq = sx9500_gpio_probe(client, data); + sx9500_gpio_probe(client, data); if (client->irq <= 0) dev_warn(&client->dev, "no valid irq found\n"); -- 1.9.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 2/3] iio: sx9500: refactor GPIO interrupt code 2015-04-12 17:09 ` [PATCH v3 2/3] iio: sx9500: refactor GPIO interrupt code Vlad Dogaru @ 2015-04-18 19:14 ` Jonathan Cameron 0 siblings, 0 replies; 9+ messages in thread From: Jonathan Cameron @ 2015-04-18 19:14 UTC (permalink / raw) To: Vlad Dogaru, linux-iio On 12/04/15 18:09, Vlad Dogaru wrote: > Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com> Applied with the define name changed as mentioned earlier... J > --- > drivers/iio/proximity/sx9500.c | 27 ++++++++++----------------- > 1 file changed, 10 insertions(+), 17 deletions(-) > > diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c > index f0f65a7..72efbbc 100644 > --- a/drivers/iio/proximity/sx9500.c > +++ b/drivers/iio/proximity/sx9500.c > @@ -859,30 +859,24 @@ static int sx9500_init_device(struct iio_dev *indio_dev) > return 0; > } > > -static int sx9500_gpio_probe(struct i2c_client *client, > - struct sx9500_data *data) > +static void sx9500_gpio_probe(struct i2c_client *client, > + struct sx9500_data *data) > { > struct device *dev; > struct gpio_desc *gpio; > - int ret; > > if (!client) > - return -EINVAL; > + return; > > dev = &client->dev; > > - /* data ready gpio interrupt pin */ > - 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); > + if (client->irq <= 0) { > + gpio = devm_gpiod_get_index(dev, SX9500_GPIO_INT, 0, GPIOD_IN); > + if (IS_ERR(gpio)) > + dev_err(dev, "gpio get irq failed\n"); > + else > + client->irq = gpiod_to_irq(gpio); > } > - > - ret = gpiod_to_irq(gpio); > - > - dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); > - > - return ret; > } > > static int sx9500_probe(struct i2c_client *client, > @@ -916,8 +910,7 @@ static int sx9500_probe(struct i2c_client *client, > indio_dev->modes = INDIO_DIRECT_MODE; > i2c_set_clientdata(client, indio_dev); > > - if (client->irq <= 0) > - client->irq = sx9500_gpio_probe(client, data); > + sx9500_gpio_probe(client, data); > > if (client->irq <= 0) > dev_warn(&client->dev, "no valid irq found\n"); > ^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v3 3/3] iio: sx9500: add GPIO reset pin 2015-04-12 17:09 [PATCH v3 0/3] iio: sx9500: power usage and gpio changes Vlad Dogaru 2015-04-12 17:09 ` [PATCH v3 1/3] iio: sx9500: optimize power usage Vlad Dogaru 2015-04-12 17:09 ` [PATCH v3 2/3] iio: sx9500: refactor GPIO interrupt code Vlad Dogaru @ 2015-04-12 17:09 ` Vlad Dogaru 2015-04-18 19:16 ` Jonathan Cameron 2 siblings, 1 reply; 9+ messages in thread From: Vlad Dogaru @ 2015-04-12 17:09 UTC (permalink / raw) To: jic23, linux-iio; +Cc: Vlad Dogaru If a GPIO reset pin is listed in ACPI or Device Tree, use it to reset the device on initialization. Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com> --- drivers/iio/proximity/sx9500.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 72efbbc..a32fa2e 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -33,6 +33,7 @@ #define SX9500_IRQ_NAME "sx9500_event" #define SX9500_GPIO_INT "interrupt" +#define SX9500_GPIO_RESET "reset" /* Register definitions. */ #define SX9500_REG_IRQ_SRC 0x00 @@ -85,6 +86,7 @@ struct sx9500_data { struct i2c_client *client; struct iio_trigger *trig; struct regmap *regmap; + struct gpio_desc *gpiod_rst; /* * Last reading of the proximity status for each channel. We * only send an event to user space when this changes. @@ -831,6 +833,13 @@ static int sx9500_init_device(struct iio_dev *indio_dev) int ret, i; unsigned int val; + if (data->gpiod_rst) { + gpiod_set_value_cansleep(data->gpiod_rst, 0); + usleep_range(1000, 2000); + gpiod_set_value_cansleep(data->gpiod_rst, 1); + usleep_range(1000, 2000); + } + ret = regmap_write(data->regmap, SX9500_REG_IRQ_MSK, 0); if (ret < 0) return ret; @@ -877,6 +886,13 @@ static void sx9500_gpio_probe(struct i2c_client *client, else client->irq = gpiod_to_irq(gpio); } + + data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET, + 0, GPIOD_OUT_HIGH); + if (IS_ERR(data->gpiod_rst)) { + dev_warn(dev, "gpio get reset pin failed\n"); + data->gpiod_rst = NULL; + } } static int sx9500_probe(struct i2c_client *client, @@ -900,8 +916,6 @@ static int sx9500_probe(struct i2c_client *client, if (IS_ERR(data->regmap)) return PTR_ERR(data->regmap); - sx9500_init_device(indio_dev); - indio_dev->dev.parent = &client->dev; indio_dev->name = SX9500_DRIVER_NAME; indio_dev->channels = sx9500_channels; @@ -912,6 +926,10 @@ static int sx9500_probe(struct i2c_client *client, sx9500_gpio_probe(client, data); + ret = sx9500_init_device(indio_dev); + if (ret < 0) + return ret; + if (client->irq <= 0) dev_warn(&client->dev, "no valid irq found\n"); else { -- 1.9.1 ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v3 3/3] iio: sx9500: add GPIO reset pin 2015-04-12 17:09 ` [PATCH v3 3/3] iio: sx9500: add GPIO reset pin Vlad Dogaru @ 2015-04-18 19:16 ` Jonathan Cameron 0 siblings, 0 replies; 9+ messages in thread From: Jonathan Cameron @ 2015-04-18 19:16 UTC (permalink / raw) To: Vlad Dogaru, linux-iio On 12/04/15 18:09, Vlad Dogaru wrote: > If a GPIO reset pin is listed in ACPI or Device Tree, use it to reset > the device on initialization. > > Signed-off-by: Vlad Dogaru <vlad.dogaru@intel.com> Applied. Thanks for this series. The power optimization patch in particular raised some questions in my mind about whether there is a better way to handle these inter dependencies between different uses of a channel. No particular ideas yet though :) Anyhow, in the togreg branch, initially pushed out as testing to see what I've missed today. J > --- > drivers/iio/proximity/sx9500.c | 22 ++++++++++++++++++++-- > 1 file changed, 20 insertions(+), 2 deletions(-) > > diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c > index 72efbbc..a32fa2e 100644 > --- a/drivers/iio/proximity/sx9500.c > +++ b/drivers/iio/proximity/sx9500.c > @@ -33,6 +33,7 @@ > #define SX9500_IRQ_NAME "sx9500_event" > > #define SX9500_GPIO_INT "interrupt" > +#define SX9500_GPIO_RESET "reset" > > /* Register definitions. */ > #define SX9500_REG_IRQ_SRC 0x00 > @@ -85,6 +86,7 @@ struct sx9500_data { > struct i2c_client *client; > struct iio_trigger *trig; > struct regmap *regmap; > + struct gpio_desc *gpiod_rst; > /* > * Last reading of the proximity status for each channel. We > * only send an event to user space when this changes. > @@ -831,6 +833,13 @@ static int sx9500_init_device(struct iio_dev *indio_dev) > int ret, i; > unsigned int val; > > + if (data->gpiod_rst) { > + gpiod_set_value_cansleep(data->gpiod_rst, 0); > + usleep_range(1000, 2000); > + gpiod_set_value_cansleep(data->gpiod_rst, 1); > + usleep_range(1000, 2000); > + } > + > ret = regmap_write(data->regmap, SX9500_REG_IRQ_MSK, 0); > if (ret < 0) > return ret; > @@ -877,6 +886,13 @@ static void sx9500_gpio_probe(struct i2c_client *client, > else > client->irq = gpiod_to_irq(gpio); > } > + > + data->gpiod_rst = devm_gpiod_get_index(dev, SX9500_GPIO_RESET, > + 0, GPIOD_OUT_HIGH); > + if (IS_ERR(data->gpiod_rst)) { > + dev_warn(dev, "gpio get reset pin failed\n"); > + data->gpiod_rst = NULL; > + } > } > > static int sx9500_probe(struct i2c_client *client, > @@ -900,8 +916,6 @@ static int sx9500_probe(struct i2c_client *client, > if (IS_ERR(data->regmap)) > return PTR_ERR(data->regmap); > > - sx9500_init_device(indio_dev); > - > indio_dev->dev.parent = &client->dev; > indio_dev->name = SX9500_DRIVER_NAME; > indio_dev->channels = sx9500_channels; > @@ -912,6 +926,10 @@ static int sx9500_probe(struct i2c_client *client, > > sx9500_gpio_probe(client, data); > > + ret = sx9500_init_device(indio_dev); > + if (ret < 0) > + return ret; > + > if (client->irq <= 0) > dev_warn(&client->dev, "no valid irq found\n"); > else { > ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2015-06-29 7:42 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-04-12 17:09 [PATCH v3 0/3] iio: sx9500: power usage and gpio changes Vlad Dogaru 2015-04-12 17:09 ` [PATCH v3 1/3] iio: sx9500: optimize power usage Vlad Dogaru 2015-04-18 19:12 ` Jonathan Cameron 2015-06-26 11:01 ` Hartmut Knaack 2015-06-29 7:42 ` Vlad Dogaru 2015-04-12 17:09 ` [PATCH v3 2/3] iio: sx9500: refactor GPIO interrupt code Vlad Dogaru 2015-04-18 19:14 ` Jonathan Cameron 2015-04-12 17:09 ` [PATCH v3 3/3] iio: sx9500: add GPIO reset pin Vlad Dogaru 2015-04-18 19:16 ` Jonathan Cameron
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox