From 52f5b683e50a9bf106c07196ffadda58f199678b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 1 Sep 2020 08:19:43 -0700 Subject: iio: sx9310: Prefer async probe On one board I found that: probe of 5-0028 returned 1 after 259547 usecs While some of this time is attributable to the pile of i2c transfers that we do at probe time, the lion's share (over 200 ms) is sitting waiting in the polling loop in sx9310_init_compensation() waiting for the hardware to indicate that it's done. There's no reason to block probe of all other devices on our probe. Turn on async probe. Signed-off-by: Douglas Anderson Reviewed-by: Stephen Boyd Reviewed-by: Daniel Campello Link: https://lore.kernel.org/r/20200901081920.v2.1.Id02b2f451b3eed71ddd580f4b8b44b3e33e84970@changeid Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/sx9310.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/iio/proximity') diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 9d72d08ab9e7..6d3f4ab8c6b2 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -1056,6 +1056,13 @@ static struct i2c_driver sx9310_driver = { .acpi_match_table = sx9310_acpi_match, .of_match_table = sx9310_of_match, .pm = &sx9310_pm_ops, + + /* + * Lots of i2c transfers in probe + over 200 ms waiting in + * sx9310_init_compensation() mean a slow probe; prefer async + * so we don't delay boot if we're builtin to the kernel. + */ + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe_new = sx9310_probe, .id_table = sx9310_id, -- cgit From c457b7efa302a8c3706176636f7f2702556f93ab Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 10 Sep 2020 18:32:35 +0100 Subject: iio:proximity:as3935: Use local struct device pointer to simplify code. This makes the existing code easier to read and will make the following patch a little simpler. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Acked-by: Matt Ranostay Link: https://lore.kernel.org/r/20200910173242.621168-32-jic23@kernel.org --- drivers/iio/proximity/as3935.c | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) (limited to 'drivers/iio/proximity') diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index c339e7339ec8..4df8d53d65fb 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -352,19 +352,20 @@ static void as3935_stop_work(void *data) static int as3935_probe(struct spi_device *spi) { + struct device *dev = &spi->dev; struct iio_dev *indio_dev; struct iio_trigger *trig; struct as3935_state *st; - struct device_node *np = spi->dev.of_node; + struct device_node *np = dev->of_node; int ret; /* Be sure lightning event interrupt is specified */ if (!spi->irq) { - dev_err(&spi->dev, "unable to get event interrupt\n"); + dev_err(dev, "unable to get event interrupt\n"); return -EINVAL; } - indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + indio_dev = devm_iio_device_alloc(dev, sizeof(*st)); if (!indio_dev) return -ENOMEM; @@ -378,14 +379,12 @@ static int as3935_probe(struct spi_device *spi) "ams,tuning-capacitor-pf", &st->tune_cap); if (ret) { st->tune_cap = 0; - dev_warn(&spi->dev, - "no tuning-capacitor-pf set, defaulting to %d", + dev_warn(dev, "no tuning-capacitor-pf set, defaulting to %d", st->tune_cap); } if (st->tune_cap > MAX_PF_CAP) { - dev_err(&spi->dev, - "wrong tuning-capacitor-pf setting of %d\n", + dev_err(dev, "wrong tuning-capacitor-pf setting of %d\n", st->tune_cap); return -EINVAL; } @@ -393,8 +392,7 @@ static int as3935_probe(struct spi_device *spi) ret = of_property_read_u32(np, "ams,nflwdth", &st->nflwdth_reg); if (!ret && st->nflwdth_reg > AS3935_NFLWDTH_MASK) { - dev_err(&spi->dev, - "invalid nflwdth setting of %d\n", + dev_err(dev, "invalid nflwdth setting of %d\n", st->nflwdth_reg); return -EINVAL; } @@ -405,7 +403,7 @@ static int as3935_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &as3935_info; - trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d", + trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name, indio_dev->id); if (!trig) @@ -417,42 +415,42 @@ static int as3935_probe(struct spi_device *spi) iio_trigger_set_drvdata(trig, indio_dev); trig->ops = &iio_interrupt_trigger_ops; - ret = devm_iio_trigger_register(&spi->dev, trig); + ret = devm_iio_trigger_register(dev, trig); if (ret) { - dev_err(&spi->dev, "failed to register trigger\n"); + dev_err(dev, "failed to register trigger\n"); return ret; } - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, iio_pollfunc_store_time, as3935_trigger_handler, NULL); if (ret) { - dev_err(&spi->dev, "cannot setup iio trigger\n"); + dev_err(dev, "cannot setup iio trigger\n"); return ret; } calibrate_as3935(st); INIT_DELAYED_WORK(&st->work, as3935_event_work); - ret = devm_add_action(&spi->dev, as3935_stop_work, indio_dev); + ret = devm_add_action(dev, as3935_stop_work, indio_dev); if (ret) return ret; - ret = devm_request_irq(&spi->dev, spi->irq, + ret = devm_request_irq(dev, spi->irq, &as3935_interrupt_handler, IRQF_TRIGGER_RISING, - dev_name(&spi->dev), + dev_name(dev), indio_dev); if (ret) { - dev_err(&spi->dev, "unable to request irq\n"); + dev_err(dev, "unable to request irq\n"); return ret; } - ret = devm_iio_device_register(&spi->dev, indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret < 0) { - dev_err(&spi->dev, "unable to register device\n"); + dev_err(dev, "unable to register device\n"); return ret; } return 0; -- cgit From 00fa493b99894b930e431c05a9dba294c5189120 Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 10 Sep 2020 18:32:36 +0100 Subject: iio:proximity:as3935: Drop of_match_ptr and use generic fw accessors This change allows the driver to be used with ACPI PRP0001 and removes an antipattern that I want to avoid being copied into new IIO drivers. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Acked-by: Matt Ranostay Link: https://lore.kernel.org/r/20200910173242.621168-33-jic23@kernel.org --- drivers/iio/proximity/as3935.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/iio/proximity') diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c index 4df8d53d65fb..b79ada839e01 100644 --- a/drivers/iio/proximity/as3935.c +++ b/drivers/iio/proximity/as3935.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -356,7 +357,6 @@ static int as3935_probe(struct spi_device *spi) struct iio_dev *indio_dev; struct iio_trigger *trig; struct as3935_state *st; - struct device_node *np = dev->of_node; int ret; /* Be sure lightning event interrupt is specified */ @@ -375,7 +375,7 @@ static int as3935_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); mutex_init(&st->lock); - ret = of_property_read_u32(np, + ret = device_property_read_u32(dev, "ams,tuning-capacitor-pf", &st->tune_cap); if (ret) { st->tune_cap = 0; @@ -389,7 +389,7 @@ static int as3935_probe(struct spi_device *spi) return -EINVAL; } - ret = of_property_read_u32(np, + ret = device_property_read_u32(dev, "ams,nflwdth", &st->nflwdth_reg); if (!ret && st->nflwdth_reg > AS3935_NFLWDTH_MASK) { dev_err(dev, "invalid nflwdth setting of %d\n", @@ -471,7 +471,7 @@ MODULE_DEVICE_TABLE(spi, as3935_id); static struct spi_driver as3935_driver = { .driver = { .name = "as3935", - .of_match_table = of_match_ptr(as3935_of_match), + .of_match_table = as3935_of_match, .pm = AS3935_PM_OPS, }, .probe = as3935_probe, -- cgit From 03303e8425436372472993f988a20262a263fbcf Mon Sep 17 00:00:00 2001 From: Jonathan Cameron Date: Thu, 10 Sep 2020 18:32:37 +0100 Subject: iio:proximity:pulsedlight: Drop of_match_ptr protection This prevents use of this driver with ACPI via PRP0001 and is an example of an anti pattern I'm trying to remove from IIO. Hence drop from this driver. Signed-off-by: Jonathan Cameron Reviewed-by: Andy Shevchenko Acked-by: Matt Ranostay Link: https://lore.kernel.org/r/20200910173242.621168-34-jic23@kernel.org --- drivers/iio/proximity/pulsedlight-lidar-lite-v2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/iio/proximity') diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index a8e716dbd24e..c685f10b5ae4 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -360,7 +361,7 @@ static const struct dev_pm_ops lidar_pm_ops = { static struct i2c_driver lidar_driver = { .driver = { .name = LIDAR_DRV_NAME, - .of_match_table = of_match_ptr(lidar_dt_ids), + .of_match_table = lidar_dt_ids, .pm = &lidar_pm_ops, }, .probe = lidar_probe, -- cgit From 3cef2e31b54b5975f45dfd7f88204bb78b03d535 Mon Sep 17 00:00:00 2001 From: Ivan Drobyshevskyi Date: Wed, 16 Sep 2020 10:44:58 +0300 Subject: iio: proximity: vl53l0x: Add IRQ support VL53L0X can be configured to use interrupt pin (GPIO1) to notify host about readiness of new measurement. If interrupt pin is not specified, driver still uses polling. Signed-off-by: Ivan Drobyshevskyi Link: https://lore.kernel.org/r/20200916074458.873359-2-drobyshevskyi@gmail.com Signed-off-by: Jonathan Cameron --- drivers/iio/proximity/vl53l0x-i2c.c | 104 ++++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 11 deletions(-) (limited to 'drivers/iio/proximity') diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 5fbda9475ba9..235e125aeb3a 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -4,18 +4,19 @@ * * Copyright (C) 2016 STMicroelectronics Imaging Division. * Copyright (C) 2018 Song Qiang + * Copyright (C) 2020 Ivan Drobyshevskyi * * Datasheet available at * * * Default 7-bit i2c slave address 0x29. * - * TODO: FIFO buffer, continuous mode, interrupts, range selection, - * sensor ID check. + * TODO: FIFO buffer, continuous mode, range selection, sensor ID check. */ #include #include +#include #include #include @@ -29,14 +30,72 @@ #define VL_REG_SYSRANGE_MODE_TIMED BIT(2) #define VL_REG_SYSRANGE_MODE_HISTOGRAM BIT(3) +#define VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x0A +#define VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY BIT(2) + +#define VL_REG_SYSTEM_INTERRUPT_CLEAR 0x0B + #define VL_REG_RESULT_INT_STATUS 0x13 #define VL_REG_RESULT_RANGE_STATUS 0x14 #define VL_REG_RESULT_RANGE_STATUS_COMPLETE BIT(0) struct vl53l0x_data { struct i2c_client *client; + struct completion completion; }; +static irqreturn_t vl53l0x_handle_irq(int irq, void *priv) +{ + struct iio_dev *indio_dev = priv; + struct vl53l0x_data *data = iio_priv(indio_dev); + + complete(&data->completion); + + return IRQ_HANDLED; +} + +static int vl53l0x_configure_irq(struct i2c_client *client, + struct iio_dev *indio_dev) +{ + struct vl53l0x_data *data = iio_priv(indio_dev); + int ret; + + ret = devm_request_irq(&client->dev, client->irq, vl53l0x_handle_irq, + IRQF_TRIGGER_FALLING, indio_dev->name, indio_dev); + if (ret) { + dev_err(&client->dev, "devm_request_irq error: %d\n", ret); + return ret; + } + + ret = i2c_smbus_write_byte_data(data->client, + VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY); + if (ret < 0) + dev_err(&client->dev, "failed to configure IRQ: %d\n", ret); + + return ret; +} + +static void vl53l0x_clear_irq(struct vl53l0x_data *data) +{ + struct device *dev = &data->client->dev; + int ret; + + ret = i2c_smbus_write_byte_data(data->client, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 1); + if (ret < 0) + dev_err(dev, "failed to clear error irq: %d\n", ret); + + ret = i2c_smbus_write_byte_data(data->client, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 0); + if (ret < 0) + dev_err(dev, "failed to clear range irq: %d\n", ret); + + ret = i2c_smbus_read_byte_data(data->client, VL_REG_RESULT_INT_STATUS); + if (ret < 0 || ret & 0x07) + dev_err(dev, "failed to clear irq: %d\n", ret); +} + static int vl53l0x_read_proximity(struct vl53l0x_data *data, const struct iio_chan_spec *chan, int *val) @@ -50,19 +109,31 @@ static int vl53l0x_read_proximity(struct vl53l0x_data *data, if (ret < 0) return ret; - do { - ret = i2c_smbus_read_byte_data(client, - VL_REG_RESULT_RANGE_STATUS); + if (data->client->irq) { + reinit_completion(&data->completion); + + ret = wait_for_completion_timeout(&data->completion, HZ/10); if (ret < 0) return ret; + else if (ret == 0) + return -ETIMEDOUT; - if (ret & VL_REG_RESULT_RANGE_STATUS_COMPLETE) - break; + vl53l0x_clear_irq(data); + } else { + do { + ret = i2c_smbus_read_byte_data(client, + VL_REG_RESULT_RANGE_STATUS); + if (ret < 0) + return ret; - usleep_range(1000, 5000); - } while (--tries); - if (!tries) - return -ETIMEDOUT; + if (ret & VL_REG_RESULT_RANGE_STATUS_COMPLETE) + break; + + usleep_range(1000, 5000); + } while (--tries); + if (!tries) + return -ETIMEDOUT; + } ret = i2c_smbus_read_i2c_block_data(client, VL_REG_RESULT_RANGE_STATUS, 12, buffer); @@ -140,6 +211,17 @@ static int vl53l0x_probe(struct i2c_client *client) indio_dev->num_channels = ARRAY_SIZE(vl53l0x_channels); indio_dev->modes = INDIO_DIRECT_MODE; + /* usage of interrupt is optional */ + if (client->irq) { + int ret; + + init_completion(&data->completion); + + ret = vl53l0x_configure_irq(client, indio_dev); + if (ret) + return ret; + } + return devm_iio_device_register(&client->dev, indio_dev); } -- cgit