linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jonathan Cameron <jic23@kernel.org>
To: Jeff LaBundy <jeff@labundy.com>
Cc: lee.jones@linaro.org, dmitry.torokhov@gmail.com,
	jdelvare@suse.com, linux@roeck-us.net, thierry.reding@gmail.com,
	devicetree@vger.kernel.org, linux-input@vger.kernel.org,
	linux-hwmon@vger.kernel.org, u.kleine-koenig@pengutronix.de,
	linux-pwm@vger.kernel.org, knaack.h@gmx.de, lars@metafoo.de,
	pmeerw@pmeerw.net, linux-iio@vger.kernel.org, robh+dt@kernel.org,
	mark.rutland@arm.com
Subject: Re: [PATCH 7/8] iio: proximity: Add support for Azoteq IQS622 proximity sensor
Date: Tue, 22 Oct 2019 12:23:46 +0100	[thread overview]
Message-ID: <20191022122341.32f0883f@archlinux> (raw)
In-Reply-To: <1571631083-4962-8-git-send-email-jeff@labundy.com>

On Sun, 20 Oct 2019 23:11:22 -0500
Jeff LaBundy <jeff@labundy.com> wrote:

> This patch adds support for the Azoteq IQS622 proximity sensor,
> capable of reporting a unitless measurement of a target's prox-
> imity to the sensor.
> 
> Signed-off-by: Jeff LaBundy <jeff@labundy.com>
A few trivial bits inline + that question on the dt binding and
whether it is something we ought to be deciding at device build
time or whether there are devices where it should be configurable.

Thanks,

Jonathan

> ---
>  drivers/iio/proximity/Kconfig       |  10 ++
>  drivers/iio/proximity/Makefile      |   1 +
>  drivers/iio/proximity/iqs622-prox.c | 334 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 345 insertions(+)
>  create mode 100644 drivers/iio/proximity/iqs622-prox.c
> 
> diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
> index d536014..2366fd7 100644
> --- a/drivers/iio/proximity/Kconfig
> +++ b/drivers/iio/proximity/Kconfig
> @@ -21,6 +21,16 @@ endmenu
>  
>  menu "Proximity and distance sensors"
>  
> +config IQS622_PROX
> +	tristate "Azoteq IQS622 proximity sensor"
> +	depends on MFD_IQS62X
> +	help
> +	  Say Y here if you want to build support for the Azoteq IQS622
> +	  proximity sensor.
> +
> +	  To compile this driver as a module, choose M here: the module
> +	  will be called iqs622-prox.
> +
>  config ISL29501
>  	tristate "Intersil ISL29501 Time Of Flight sensor"
>  	depends on I2C
> diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
> index 0bb5f9d..802ba9d 100644
> --- a/drivers/iio/proximity/Makefile
> +++ b/drivers/iio/proximity/Makefile
> @@ -5,6 +5,7 @@
>  
>  # When adding new entries keep the list in alphabetical order
>  obj-$(CONFIG_AS3935)		+= as3935.o
> +obj-$(CONFIG_IQS622_PROX)	+= iqs622-prox.o
>  obj-$(CONFIG_ISL29501)		+= isl29501.o
>  obj-$(CONFIG_LIDAR_LITE_V2)	+= pulsedlight-lidar-lite-v2.o
>  obj-$(CONFIG_MB1232)		+= mb1232.o
> diff --git a/drivers/iio/proximity/iqs622-prox.c b/drivers/iio/proximity/iqs622-prox.c
> new file mode 100644
> index 0000000..a805fb21
> --- /dev/null
> +++ b/drivers/iio/proximity/iqs622-prox.c
> @@ -0,0 +1,334 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Azoteq IQS622 Proximity Sensor
> + *
> + * Copyright (C) 2019
> + * Author: Jeff LaBundy <jeff@labundy.com>
> + */
> +
> +#include <linux/device.h>
> +#include <linux/iio/events.h>
> +#include <linux/iio/iio.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/iqs62x.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/notifier.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#define IQS622_IR_FLAGS				0x16
> +#define IQS622_IR_FLAGS_TOUCH			BIT(1)
> +#define IQS622_IR_FLAGS_PROX			BIT(0)
> +
> +#define IQS622_IR_UI_OUT			0x17
> +
> +#define IQS622_IR_THRESH_PROX			0x91
> +#define IQS622_IR_THRESH_PROX_MAX		255
> +#define IQS622_IR_THRESH_PROX_SHIFT		0
> +
> +#define IQS622_IR_THRESH_TOUCH			0x92
> +#define IQS622_IR_THRESH_TOUCH_MAX		1020
> +#define IQS622_IR_THRESH_TOUCH_SHIFT		2
> +
> +struct iqs622_prox_private {
> +	struct iqs62x_core *iqs62x;
> +	struct notifier_block notifier;
> +	struct mutex lock;
> +	bool thresh_prox;
> +	bool event_en;
> +	u8 thresh;
> +	u8 flags;
> +};
> +
> +static int iqs622_prox_init(struct iqs622_prox_private *iqs622_prox)
> +{
> +	struct iqs62x_core *iqs62x = iqs622_prox->iqs62x;
> +	unsigned int val;
> +	int error;
> +
> +	mutex_lock(&iqs622_prox->lock);
> +
> +	error = regmap_write(iqs62x->map,
> +			     iqs622_prox->thresh_prox ? IQS622_IR_THRESH_PROX :
> +							IQS622_IR_THRESH_TOUCH,
> +			     iqs622_prox->thresh);
> +	if (error)
> +		goto err_mutex;
> +
> +	error = regmap_read(iqs62x->map, IQS622_IR_FLAGS, &val);
> +	if (error)
> +		goto err_mutex;
> +	iqs622_prox->flags = val;
> +
> +	error = regmap_update_bits(iqs62x->map, IQS620_GLBL_EVENT_MASK,
> +				   iqs62x->dev_desc->ir_mask,
> +				   iqs622_prox->event_en ? 0 : 0xFF);
> +
> +err_mutex:
> +	mutex_unlock(&iqs622_prox->lock);
> +
> +	return error;
> +}
> +
> +static int iqs622_prox_notifier(struct notifier_block *notifier,
> +				unsigned long event_flags, void *context)
> +{
> +	struct iqs62x_event_data *event_data = context;
> +	struct iqs622_prox_private *iqs622_prox;
> +	struct iio_dev *indio_dev;
> +	enum iio_event_direction dir;
> +	int error;
> +	u8 flags_mask;
> +
> +	iqs622_prox = container_of(notifier, struct iqs622_prox_private,
> +				   notifier);
> +	indio_dev = iio_priv_to_dev(iqs622_prox);
> +
> +	if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
> +		error = iqs622_prox_init(iqs622_prox);
> +		if (error) {
> +			dev_err(indio_dev->dev.parent,
> +				"Failed to re-initialize device: %d\n", error);
> +			return NOTIFY_BAD;
> +		}
> +
> +		return NOTIFY_OK;
> +	}
> +
> +	flags_mask = iqs622_prox->thresh_prox ? IQS622_IR_FLAGS_PROX :
> +						IQS622_IR_FLAGS_TOUCH;
> +
> +	if (!((event_data->ir_flags ^ iqs622_prox->flags) & flags_mask))
> +		return NOTIFY_DONE;
> +
> +	iqs622_prox->flags = event_data->ir_flags;
> +
> +	if (!iqs622_prox->event_en)
> +		return NOTIFY_OK;
> +
> +	dir = iqs622_prox->flags & flags_mask ? IIO_EV_DIR_RISING :
> +						IIO_EV_DIR_FALLING;
> +
> +	iio_push_event(indio_dev,
> +		       IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
> +					    IIO_EV_TYPE_THRESH, dir),
> +		       iio_get_time_ns(indio_dev));
> +
> +	return NOTIFY_OK;
> +}
> +
> +static void iqs622_prox_notifier_unregister(void *context)
> +{
> +	struct iqs622_prox_private *iqs622_prox = context;
> +	struct iio_dev *indio_dev = iio_priv_to_dev(iqs622_prox);
> +	int error;
> +
> +	error = blocking_notifier_chain_unregister(&iqs622_prox->iqs62x->nh,
> +						   &iqs622_prox->notifier);
> +	if (error)
> +		dev_err(indio_dev->dev.parent,
> +			"Failed to unregister notifier: %d\n", error);
> +}
> +
> +static int iqs622_prox_read_raw(struct iio_dev *indio_dev,
> +				struct iio_chan_spec const *chan,
> +				int *val, int *val2, long mask)
> +{
> +	struct iqs622_prox_private *iqs622_prox = iio_priv(indio_dev);
> +	struct iqs62x_core *iqs62x = iqs622_prox->iqs62x;
> +	int error;
> +	__le16 val_buf;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		error = regmap_raw_read(iqs62x->map, IQS622_IR_UI_OUT,
> +					&val_buf, sizeof(val_buf));
> +		if (error)
> +			return error;
> +
> +		*val = le16_to_cpu(val_buf);
> +		return IIO_VAL_INT;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int iqs622_prox_read_event_config(struct iio_dev *indio_dev,
> +					 const struct iio_chan_spec *chan,
> +					 enum iio_event_type type,
> +					 enum iio_event_direction dir)
> +{
> +	struct iqs622_prox_private *iqs622_prox = iio_priv(indio_dev);
> +
> +	return iqs622_prox->event_en;
> +}
> +
> +static int iqs622_prox_write_event_config(struct iio_dev *indio_dev,
> +					  const struct iio_chan_spec *chan,
> +					  enum iio_event_type type,
> +					  enum iio_event_direction dir,
> +					  int state)
> +{
> +	struct iqs622_prox_private *iqs622_prox = iio_priv(indio_dev);
> +	struct iqs62x_core *iqs62x = iqs622_prox->iqs62x;
> +	int error;
> +
> +	mutex_lock(&iqs622_prox->lock);
> +
> +	error = regmap_update_bits(iqs62x->map, IQS620_GLBL_EVENT_MASK,
> +				   iqs62x->dev_desc->ir_mask, state ? 0 : 0xFF);
> +	if (!error)
> +		iqs622_prox->event_en = state;
> +
> +	mutex_unlock(&iqs622_prox->lock);
> +
> +	return error;
> +}
> +
> +static int iqs622_prox_read_event_value(struct iio_dev *indio_dev,
> +					const struct iio_chan_spec *chan,
> +					enum iio_event_type type,
> +					enum iio_event_direction dir,
> +					enum iio_event_info info,
> +					int *val, int *val2)
> +{
> +	struct iqs622_prox_private *iqs622_prox = iio_priv(indio_dev);
> +
> +	*val = iqs622_prox->thresh;
> +	*val <<= (iqs622_prox->thresh_prox ? IQS622_IR_THRESH_PROX_SHIFT :
> +					     IQS622_IR_THRESH_TOUCH_SHIFT);
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int iqs622_prox_write_event_value(struct iio_dev *indio_dev,
> +					 const struct iio_chan_spec *chan,
> +					 enum iio_event_type type,
> +					 enum iio_event_direction dir,
> +					 enum iio_event_info info,
> +					 int val, int val2)
> +{
> +	struct iqs622_prox_private *iqs622_prox = iio_priv(indio_dev);
> +	struct iqs62x_core *iqs62x = iqs622_prox->iqs62x;
> +	int error = -EINVAL;
> +
> +	mutex_lock(&iqs622_prox->lock);

The ternary operators in here are bit messy, perhaps better to just
have an if else block and some local variables?

> +
> +	if (val > (iqs622_prox->thresh_prox ? IQS622_IR_THRESH_PROX_MAX :
> +					      IQS622_IR_THRESH_TOUCH_MAX))
> +		goto err_mutex;
> +	val >>= (iqs622_prox->thresh_prox ? IQS622_IR_THRESH_PROX_SHIFT :
> +					    IQS622_IR_THRESH_TOUCH_SHIFT);
> +
> +	error = regmap_write(iqs62x->map,
> +			     iqs622_prox->thresh_prox ? IQS622_IR_THRESH_PROX :
> +							IQS622_IR_THRESH_TOUCH,
> +			     val);
> +	if (!error)
> +		iqs622_prox->thresh = val;
> +
> +err_mutex:
> +	mutex_unlock(&iqs622_prox->lock);
> +
> +	return error;
> +}
> +
> +static const struct iio_info iqs622_prox_info = {
> +	.read_raw = &iqs622_prox_read_raw,
> +	.read_event_config = iqs622_prox_read_event_config,
> +	.write_event_config = iqs622_prox_write_event_config,
> +	.read_event_value = iqs622_prox_read_event_value,
> +	.write_event_value = iqs622_prox_write_event_value,
> +};
> +
> +static const struct iio_event_spec iqs622_prox_events[] = {
> +	{
> +		.type = IIO_EV_TYPE_THRESH,
> +		.dir = IIO_EV_DIR_EITHER,
> +		.mask_separate = BIT(IIO_EV_INFO_ENABLE) |
> +				 BIT(IIO_EV_INFO_VALUE),
> +	},
> +};
> +
> +static const struct iio_chan_spec iqs622_prox_channels[] = {
> +	{
> +		.type = IIO_PROXIMITY,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
> +		.event_spec = iqs622_prox_events,
> +		.num_event_specs = ARRAY_SIZE(iqs622_prox_events),
> +	},
> +};
> +
> +static int iqs622_prox_probe(struct platform_device *pdev)
> +{
> +	struct iqs62x_core *iqs62x = dev_get_drvdata(pdev->dev.parent);
> +	struct iqs622_prox_private *iqs622_prox;
> +	struct iio_dev *indio_dev;
> +	unsigned int val;
> +	int error;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*iqs622_prox));
> +	if (!indio_dev)
> +		return -ENOMEM;
> +
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->channels = iqs622_prox_channels;
> +	indio_dev->num_channels = ARRAY_SIZE(iqs622_prox_channels);
> +	indio_dev->name = iqs62x->dev_desc->dev_name;
> +	indio_dev->info = &iqs622_prox_info;
> +
> +	iqs622_prox = iio_priv(indio_dev);
> +	iqs622_prox->iqs62x = iqs62x;
> +
> +	iqs622_prox->thresh_prox = device_property_read_bool(&pdev->dev,
> +							     "azoteq,use-prox");

Outstanding question on this in the binding patch.

> +
> +	error = regmap_read(iqs62x->map,
> +			    iqs622_prox->thresh_prox ? IQS622_IR_THRESH_PROX :
> +						       IQS622_IR_THRESH_TOUCH,
> +			    &val);
> +	if (error)
> +		return error;
> +	iqs622_prox->thresh = val;
> +
> +	mutex_init(&iqs622_prox->lock);
> +
> +	error = iqs622_prox_init(iqs622_prox);
> +	if (error)
> +		return error;
> +
> +	iqs622_prox->notifier.notifier_call = iqs622_prox_notifier;
> +	error = blocking_notifier_chain_register(&iqs622_prox->iqs62x->nh,
> +						 &iqs622_prox->notifier);
> +	if (error) {
> +		dev_err(&pdev->dev, "Failed to register notifier: %d\n", error);
> +		return error;
> +	}
> +
> +	error = devm_add_action_or_reset(&pdev->dev,
> +					 iqs622_prox_notifier_unregister,
> +					 iqs622_prox);
> +	if (error) {

As in previous, feels a little verbose.

> +		dev_err(&pdev->dev, "Failed to add action: %d\n", error);
> +		return error;
> +	}
> +
> +	return devm_iio_device_register(&pdev->dev, indio_dev);
> +}
> +
> +static struct platform_driver iqs622_prox_platform_driver = {
> +	.driver = {
> +		.name	= IQS622_DRV_NAME_PROX,
> +	},
> +	.probe		= iqs622_prox_probe,
> +};
> +module_platform_driver(iqs622_prox_platform_driver);
> +
> +MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
> +MODULE_DESCRIPTION("Azoteq IQS622 Proximity Sensor");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("platform:" IQS622_DRV_NAME_PROX);


  reply	other threads:[~2019-10-22 11:39 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-21  4:11 [PATCH 0/8] Add support for Azoteq IQS620A/621/622/624/625 Jeff LaBundy
2019-10-21  4:11 ` [PATCH 1/8] dt-bindings: mfd: iqs62x: Add bindings Jeff LaBundy
2019-10-22 11:00   ` Jonathan Cameron
2019-10-23  3:36     ` Jeff LaBundy
2019-10-23  9:30       ` Lee Jones
2019-10-24  2:38         ` Jeff LaBundy
2019-10-21  4:11 ` [PATCH 2/8] mfd: Add support for Azoteq IQS620A/621/622/624/625 Jeff LaBundy
2019-10-31 13:44   ` Lee Jones
2019-10-31 18:42     ` Dmitry Torokhov
2019-11-01  4:59     ` Jeff LaBundy
2019-11-01  8:56       ` Lee Jones
2019-11-02  2:49         ` Jeff LaBundy
2019-10-21  4:11 ` [PATCH 3/8] input: keyboard: " Jeff LaBundy
2019-10-23  0:22   ` Dmitry Torokhov
2019-10-23  1:29     ` Jeff LaBundy
2019-10-23 23:08       ` Dmitry Torokhov
2019-10-21  4:11 ` [PATCH 4/8] hwmon: Add support for Azoteq IQS620AT temperature sensor Jeff LaBundy
2019-10-21 15:38   ` Guenter Roeck
2019-10-22  2:26     ` Jeff LaBundy
2019-10-22  3:22       ` Guenter Roeck
2019-10-22 11:38         ` Jonathan Cameron
2019-10-23  2:04           ` Jeff LaBundy
2019-10-21  4:11 ` [PATCH 5/8] pwm: Add support for Azoteq IQS620A PWM generator Jeff LaBundy
2019-10-21  7:34   ` Uwe Kleine-König
2019-10-22  4:36     ` Jeff LaBundy
2019-10-22  6:54       ` Uwe Kleine-König
2019-10-23  2:45         ` Jeff LaBundy
2019-10-23  7:23           ` Uwe Kleine-König
2019-10-24  3:02             ` Jeff LaBundy
2019-10-21  4:11 ` [PATCH 6/8] iio: light: Add support for Azoteq IQS621 ambient light sensor Jeff LaBundy
2019-10-22 11:23   ` Jonathan Cameron
2019-10-23  2:59     ` Jeff LaBundy
2019-10-21  4:11 ` [PATCH 7/8] iio: proximity: Add support for Azoteq IQS622 proximity sensor Jeff LaBundy
2019-10-22 11:23   ` Jonathan Cameron [this message]
2019-10-23  3:09     ` Jeff LaBundy
2019-10-21  4:11 ` [PATCH 8/8] iio: position: Add support for Azoteq IQS624/625 angle sensor Jeff LaBundy
2019-10-22 11:28   ` Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191022122341.32f0883f@archlinux \
    --to=jic23@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dmitry.torokhov@gmail.com \
    --cc=jdelvare@suse.com \
    --cc=jeff@labundy.com \
    --cc=knaack.h@gmx.de \
    --cc=lars@metafoo.de \
    --cc=lee.jones@linaro.org \
    --cc=linux-hwmon@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-pwm@vger.kernel.org \
    --cc=linux@roeck-us.net \
    --cc=mark.rutland@arm.com \
    --cc=pmeerw@pmeerw.net \
    --cc=robh+dt@kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=u.kleine-koenig@pengutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).