Re: [PATCH 1/8] dt-bindings: mfd: iqs62x: Add bindings

2019-10-22 Thread Jeff LaBundy
Hi Jonathan,

On Tue, Oct 22, 2019 at 12:00:51PM +0100, Jonathan Cameron wrote:
> On Sun, 20 Oct 2019 23:11:16 -0500
> Jeff LaBundy  wrote:
> 
> > This patch adds binding documentation for six-channel members of the
> > Azoteq ProxFusion family of sensor devices.
> > 
> > Signed-off-by: Jeff LaBundy 
> 
> I'm not sure if Lee has made the switch for mfd entirely yet, but
> mostly new dt bindings need to be in yaml format as it allows
> automated parsing of the examples + bindings using them for
> correctness.
> 

I'll wait for Lee or Rob's cue, but I'm happy to move to yaml if it's time
to make the switch here.

> One comment inline.  I'm far from an expert on most of the stuff here
> so will leave it for others!
> 
> Jonathan
> 
> 
> > ---
> >  Documentation/devicetree/bindings/mfd/iqs62x.txt | 242 
> > +++
> >  1 file changed, 242 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/mfd/iqs62x.txt
> > 
> > diff --git a/Documentation/devicetree/bindings/mfd/iqs62x.txt 
> > b/Documentation/devicetree/bindings/mfd/iqs62x.txt
> > new file mode 100644
> > index 000..089f567
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mfd/iqs62x.txt
> > @@ -0,0 +1,242 @@
> > +Azoteq IQS620A/621/622/624/625 ProxFusion Sensor Family
> > +
> > +Required properties:
> > +
> > +- compatible   : Must be equal to one of the following:
> > + "azoteq,iqs620a"
> > + "azoteq,iqs621"
> > + "azoteq,iqs622"
> > + "azoteq,iqs624"
> > + "azoteq,iqs625"
> > +
> > +- reg  : I2C slave address for the device.
> > +
> > +- interrupts   : GPIO to which the device's active-low 
> > RDY
> > + output is connected (see [0]).
> > +
> > +Optional properties:
> > +
> > +- linux,fw-file: Specifies the name of the calibration 
> > and
> > + configuration file selected by the driver.
> > + If this property is omitted, the filename
> > + is selected based on the device name with
> > + ".bin" as the extension (e.g. iqs620a.bin
> > + for IQS620A).
> > +
> > +All devices accommodate a child node (e.g. "keys") that represents touch 
> > key
> > +support. Required properties for the "keys" child node include:
> > +
> > +- compatible   : Must be equal to one of the following:
> > + "azoteq,iqs620a-keys"
> > + "azoteq,iqs621-keys"
> > + "azoteq,iqs622-keys"
> > + "azoteq,iqs624-keys"
> > + "azoteq,iqs625-keys"
> > +
> > +- linux,keycodes   : Specifies an array of up to 16 numeric key-
> > + codes corresponding to each available touch
> > + or proximity event. An 'x' in the following
> > + table indicates an event is supported for a
> > + given device; specify 0 for unused events.
> > +
> > +  
> > 
> > +  | #  | Event | IQS620A | IQS621 | IQS622 | IQS624 | 
> > IQS625 |
> > +  
> > 
> > +  | 0  | CH0 Touch |x|x   |x   |x   |x 
> >   |
> > +  || Antenna 1 Touch*  |x||||  
> >   |
> > +  
> > 
> > +  | 1  | CH0 Proximity |x|x   |x   |x   |x 
> >   |
> > +  || Antenna 1 Proximity*  |x||||  
> >   |
> > +  
> > 
> > +  | 2  | CH1 Touch |x|x   |x   |x   |x 
> >   |
>

Re: [PATCH 7/8] iio: proximity: Add support for Azoteq IQS622 proximity sensor

2019-10-22 Thread Jeff LaBundy
Hi Jonathan,

Thanks again for your prompt review here and the rest of the series.

On Tue, Oct 22, 2019 at 12:23:46PM +0100, Jonathan Cameron wrote:
> On Sun, 20 Oct 2019 23:11:22 -0500
> Jeff LaBundy  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 
> 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 000..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 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define IQS622_IR_FLAGS0x16
> > +#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_SHIFT0
> > +
> > +#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(_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, 

Re: [PATCH 6/8] iio: light: Add support for Azoteq IQS621 ambient light sensor

2019-10-22 Thread Jeff LaBundy
Hi Jonathan,

Thank you for your prompt review.

On Tue, Oct 22, 2019 at 12:23:49PM +0100, Jonathan Cameron wrote:
> On Sun, 20 Oct 2019 23:11:21 -0500
> Jeff LaBundy  wrote:
> 
> > This patch adds support for the Azoteq IQS621 ambient light sensor,
> > capable of reporting intensity directly in units of lux.
> 
> If they are in lux, should be using IIO_CHAN_INFO_PROCESSED to indicate
> that.  I was wondering why we had no scale then noticed this comment.
> 

Sure thing; will do.

> Other than that, this looks good to me.  So with that tidied up in V2.
> Acked-by: Jonathan Cameron 
> 
> One trivial comment to perhaps drop an error print as overly verbose inline.
> 
> > 
> > Signed-off-by: Jeff LaBundy 
> > ---
> >  drivers/iio/light/Kconfig  |  10 ++
> >  drivers/iio/light/Makefile |   1 +
> >  drivers/iio/light/iqs621-als.c | 361 
> > +
> >  3 files changed, 372 insertions(+)
> >  create mode 100644 drivers/iio/light/iqs621-als.c
> > 
> > diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
> > index 4a1a883..aad26dc 100644
> > --- a/drivers/iio/light/Kconfig
> > +++ b/drivers/iio/light/Kconfig
> > @@ -162,6 +162,16 @@ config GP2AP020A00F
> >   To compile this driver as a module, choose M here: the
> >   module will be called gp2ap020a00f.
> >  
> > +config IQS621_ALS
> > +   tristate "Azoteq IQS621 ambient light sensor"
> > +   depends on MFD_IQS62X
> > +   help
> > + Say Y here if you want to build support for the Azoteq IQS621
> > + ambient light sensor.
> > +
> > + To compile this driver as a module, choose M here: the module
> > + will be called iqs621-als.
> > +
> >  config SENSORS_ISL29018
> > tristate "Intersil 29018 light and proximity sensor"
> > depends on I2C
> > diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
> > index 00d1f9b..aa34358 100644
> > --- a/drivers/iio/light/Makefile
> > +++ b/drivers/iio/light/Makefile
> > @@ -20,6 +20,7 @@ obj-$(CONFIG_IIO_CROS_EC_LIGHT_PROX) += 
> > cros_ec_light_prox.o
> >  obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
> >  obj-$(CONFIG_HID_SENSOR_ALS)   += hid-sensor-als.o
> >  obj-$(CONFIG_HID_SENSOR_PROX)  += hid-sensor-prox.o
> > +obj-$(CONFIG_IQS621_ALS)   += iqs621-als.o
> >  obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
> >  obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
> >  obj-$(CONFIG_ISL29125) += isl29125.o
> > diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c
> > new file mode 100644
> > index 000..92a6173
> > --- /dev/null
> > +++ b/drivers/iio/light/iqs621-als.c
> > @@ -0,0 +1,361 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Azoteq IQS621 Ambient Light Sensor
> > + *
> > + * Copyright (C) 2019
> > + * Author: Jeff LaBundy 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define IQS621_ALS_FLAGS   0x16
> > +#define IQS621_ALS_FLAGS_LIGHT BIT(7)
> > +
> > +#define IQS621_ALS_UI_OUT  0x17
> > +
> > +#define IQS621_ALS_THRESH_DARK 0x80
> > +#define IQS621_ALS_THRESH_DARK_MAX 1020
> > +#define IQS621_ALS_THRESH_DARK_SHIFT   2
> > +
> > +#define IQS621_ALS_THRESH_LIGHT0x81
> > +#define IQS621_ALS_THRESH_LIGHT_MAX4080
> > +#define IQS621_ALS_THRESH_LIGHT_SHIFT  4
> > +
> > +struct iqs621_als_private {
> > +   struct iqs62x_core *iqs62x;
> > +   struct notifier_block notifier;
> > +   struct mutex lock;
> > +   bool event_en;
> > +   u8 thresh_light;
> > +   u8 thresh_dark;
> > +   u8 flags;
> > +};
> > +
> > +static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
> > +{
> > +   struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
> > +   unsigned int val;
> > +   int error;
> > +
> > +   mutex_lock(_als->lock);
> > +
> > +   error = regmap_write(iqs62x->map, IQS621_ALS_THRESH_LIGHT,
> > +iqs621_als->thresh_light);
> > +   if (error)
> > +   goto err_mutex;
> > +
> > +   error = regmap_write(iqs62x->map, IQS621_ALS_THRESH_DARK,
> > +

Re: [PATCH 5/8] pwm: Add support for Azoteq IQS620A PWM generator

2019-10-22 Thread Jeff LaBundy
Hi Uwe,

On Tue, Oct 22, 2019 at 08:54:15AM +0200, Uwe Kleine-König wrote:
> Hello Jeff,
> 
> On Mon, Oct 21, 2019 at 11:36:49PM -0500, Jeff LaBundy wrote:
> > On Mon, Oct 21, 2019 at 09:34:19AM +0200, Uwe Kleine-König wrote:
> > > > +struct iqs620_pwm_private {
> > > > +   struct iqs62x_core *iqs62x;
> > > > +   struct pwm_chip chip;
> > > > +   struct notifier_block notifier;
> > > > +   bool ready;
> > > 
> > > This is always true, so you can drop it.
> > > 
> > 
> > This is here because iqs620_pwm_notifier references chip.pwms, which is
> > not allocated until after the notifier is registered and pwmchip_add is
> > called. So it protects against this (albeit unlikely) race condition:
> > 
> > 1. iqs620_pwm_notifier is registered
> > 2. Device immediately suffers an asynchronous reset and notifier chain
> >is called (more on that in a bit)
> > 3. iqs620_pwm_notifier evaluates chips.pwms (NULL)
> > 
> > I felt this was simpler than calling pwmchip_add before registering the
> > notifier and adding an error/tear-down path in iqs620_pwm_probe in case
> > of failure. I would be happy to add a comment or two to explain the not-
> > so-obvious purpose of this flag.
> 
> Ah, understood. A comment is definitively necessary here.
> 

Sure thing; will do.

> > > > +};
> > > > +
> > > > +static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device 
> > > > *pwm,
> > > > +   struct pwm_state *state)
> > > 
> > > Since
> > > 
> > >   71523d1812ac ("pwm: Ensure pwm_apply_state() doesn't modify the state 
> > > argument")
> > > 
> > > this isn't the right prototype.
> > > 
> > 
> > Sure thing; I will add the 'const' qualifier and remove the two changes
> > to the state argument.
> > 
> > > > +{
> > > > +   struct iqs620_pwm_private *iqs620_pwm;
> > > > +   struct iqs62x_core *iqs62x;
> > > > +   int error;
> > > > +   int duty_calc = state->duty_cycle * 256 / IQS620_PWM_PERIOD_NS 
> > > > - 1;
> > > > +   u8 duty_clamp = clamp(duty_calc, 0, 0xFF);
> 
> Another problem that we have here is that the period is fixed to 1 ms
> and if a consumer requests for example:
> 
>   .period = 500,
>   .duty_cycle = 100,
> 
> the hardware is actually configured for
> 
>   .period = 100,
>   .duty_cycle = 100,
> 
> . I don't have a good suggestion how to fix this. We'd need to
> draw a line somewhere and decline a request that is too far from the
> result. But where this line should be is not obvious, it should
> definitively not be implemented in the driver itself IMHO.
> 
> (The only halfway sane approach would be to let lowlevel drivers
> implement a .round_state callback and then let the framework judge. But
> we're a long way from having that, so that's not a solution for today.)
> 

Agreed on all counts. For now, I will mention in the 'Limitations' heading that
the period cannot be adjusted.

> > > > +   iqs620_pwm = container_of(chip, struct iqs620_pwm_private, 
> > > > chip);
> > > > +   iqs62x = iqs620_pwm->iqs62x;
> > > > +
> > > > +   error = regmap_write(iqs62x->map, IQS620_PWM_DUTY_CYCLE, 
> > > > duty_clamp);
> > > > +   if (error)
> > > > +   return error;
> > > > +
> > > > +   state->period = IQS620_PWM_PERIOD_NS;
> > > > +   state->duty_cycle = (duty_clamp + 1) * IQS620_PWM_PERIOD_NS / 
> > > > 256;
> > > 
> > > This suggests that if the value in the IQS620_PWM_DUTY_CYCLE is 0 the
> > > duty cycle is 1/256 ms with a period of 1 ms and the output cannot be
> > > constant inactive. If this is right please add a paragraph in the
> > > driver's comment at the top:
> > > 
> > >   * Limitations:
> > >   * - The hardware cannot generate a 0% duty cycle
> > > 
> > > (Please stick to this format, other drivers use it, too.)
> > 
> > That's correct; the lowest duty cycle that can be achieved using only the
> > IQS620_PWM_DUTY_CYCLE register is 0.4%. We can, however, generate 0% duty
> > cycle by disabling the output altogether using a separate register. Would
> > that be better than flat-out saying it's impossible?
> 
> There is (maybe) a small difference between disabled and 0% duty cycle,
> at least from 

Re: [PATCH 4/8] hwmon: Add support for Azoteq IQS620AT temperature sensor

2019-10-22 Thread Jeff LaBundy
Hi Jonathan and Guenter,

On Tue, Oct 22, 2019 at 12:38:38PM +0100, Jonathan Cameron wrote:
> On Mon, 21 Oct 2019 20:22:44 -0700
> Guenter Roeck  wrote:
> 
> > On 10/21/19 7:26 PM, Jeff LaBundy wrote:
> > > Hi Guenter,
> > > 
> > > Thank you for your prompt review.
> > > 
> > > On Mon, Oct 21, 2019 at 08:38:25AM -0700, Guenter Roeck wrote:  
> > >> On Sun, Oct 20, 2019 at 11:11:19PM -0500, Jeff LaBundy wrote:  
> > >>> This patch adds support for the Azoteq IQS620AT temperature sensor,
> > >>> capable of reporting its absolute die temperature.
> > >>>
> > >>> Signed-off-by: Jeff LaBundy   
> > >>
> > >> Seems to me this might be more feasible as iio driver.
> > >> Jonathan, what do you think ?
> > >>  
> > > 
> > > Interestingly enough, this actually started as an iio driver; however the
> > > "When to Use" slide of [0] made me suspect that conventional devices with
> > > the temperature sensing element integrated on the die belong in hwmon.
> > > 
> > > I then found the highly similar ad7314, which Jonathan himself appears to
> > > have converted from iio to hwmon. Therefore, I placed this where existing
> > > drivers seemed to match the most, especially since the temperature sensors
> > > in iio generally use IR or a thermocouple.
> > > 
> > > That being said, I would be happy to move this into iio so long as 
> > > Jonathan
> > > does not mind, as it would limit the blast radius of this patch series.
> > >   
> > 
> > I don't recall why the ad7314 driver was moved. With a conversion time of 
> > 40uS
> > it is most definitely not a typical use case for a hwmon sensor.
> 
> I'll be honest, I can't remember either ;)
> > 
> > Anyway, not worth arguing about. Just don't complain later. There is an
> > iio->hwmon bridge, but no hwmon->iio bridge, so the decision does have some
> > impact. Specifically, userspace will have to implement both hwmon and iio
> > access to handle the chip.
> 
> So I had a very quick look at one of the data sheets.  The temperature sensor
> here is described as: 
> 
> "The IQS620(A) provides temperature monitoring capabilities which can be used 
> for temperature
> change detection in order to ensure the integrity of other sensing 
> technology".
> 
> Superficially this sounds like it's probably inappropriate for any sort
> of system temperature monitoring.  It's really just there to allow
> for clever compensation algorithms for the other bits on this chip
> (much like the temperature sensors we almost always get on a decent
> IMU).
> 

Correct on all counts. The "charge transfer" sensing mechanism employed by these
devices is sensitive to temperature, and they employ a compensation algorithm to
account for drift.

Of the five devices in the series, the IQS620A and IQS621 expose the output of
the temperature monitoring network to the outside world. However, the values are
purely relative. The IQS620AT, however, is calibrated at the factory such that
it can apply an internal scaling factor and offset in order to provide absolute
measurements.

The MFD driver checks these calibration values to determine if this driver can
be loaded, or if the device is a plain IQS620A (no 'T') in which case only the
input and PWM drivers are loaded.

> Normally we'd just tack an extra channel for the temperature sensor on
> to the the the sensor it is integrated with.  This is a bit more
> complex though as we have 3 different IIO sensors that are present
> in particular part numbers and for some cases we have no IIO device
> at all, but do have a temperature sensor.
> 
> So if people are going to actually use this to compensate outputs
> (not sure which ones are actually temperature sensitive btw ;)
> then if those are IIO supported devices, then probably makes sense
> for this to be an IIO device.  It may make sense anyway if there
> is any chance of adding temperature compensation to the drivers
> in kernel.  I suspect the only use that would actually be made
> is as a trip point if something has gone horribly wrong, but
> I might be wrong!
> 

Correct again; in my opinion this device is unlikely to be chosen for any sort
of system-level temperature monitoring. It's really meant for contactless key/
button/switch sensing and PWM control; a subset of the devices simply offer the
internal temperature measurement to the outside world as a bonus in case it is
useful. Hence, this patch.

> Conclusion. I also don't feel strongly on this one as it kind of
> sits between IIO and hwmon, but probably ever so slightly on the
> IIO side as monitoring a sensor chip, not some other device.
> 

Agreed on all counts; I'll move this to iio. Thank you both for the discussion.

> Thanks,
> 
> Jonathan
> 
> > 
> > Guenter
> 
> 

Kind regards,
Jeff LaBundy


Re: [PATCH 3/8] input: keyboard: Add support for Azoteq IQS620A/621/622/624/625

2019-10-22 Thread Jeff LaBundy
Hi Dmitry,

Thank you for your prompt review.

On Tue, Oct 22, 2019 at 05:22:54PM -0700, Dmitry Torokhov wrote:
> Hi Jeff,
> 
> On Sun, Oct 20, 2019 at 11:11:18PM -0500, Jeff LaBundy wrote:
> > This patch adds touch key support for six-channel members of the
> > Azoteq ProxFusion family of sensor devices.
> > 
> > Signed-off-by: Jeff LaBundy 
> > ---
> >  drivers/input/keyboard/Kconfig   |  10 ++
> >  drivers/input/keyboard/Makefile  |   1 +
> >  drivers/input/keyboard/iqs62x-keys.c | 340 
> > +++
> >  3 files changed, 351 insertions(+)
> >  create mode 100644 drivers/input/keyboard/iqs62x-keys.c
> > 
> > diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> > index 8911bc2..ab10aff 100644
> > --- a/drivers/input/keyboard/Kconfig
> > +++ b/drivers/input/keyboard/Kconfig
> > @@ -657,6 +657,16 @@ config KEYBOARD_IPAQ_MICRO
> >   To compile this driver as a module, choose M here: the
> >   module will be called ipaq-micro-keys.
> >  
> > +config KEYBOARD_IQS62X
> > +   tristate "Azoteq IQS620A/621/622/624/625 touch keys"
> > +   depends on MFD_IQS62X
> > +   help
> > + Say Y here to enable touch-key support for six-channel members of
> > + the Azoteq ProxFusion family of sensor devices.
> > +
> > + To compile this driver as a module, choose M here: the module will
> > + be called iqs62x-keys.
> > +
> >  config KEYBOARD_OMAP
> > tristate "TI OMAP keypad support"
> > depends on ARCH_OMAP1
> > diff --git a/drivers/input/keyboard/Makefile 
> > b/drivers/input/keyboard/Makefile
> > index 9510325..ee85b7f 100644
> > --- a/drivers/input/keyboard/Makefile
> > +++ b/drivers/input/keyboard/Makefile
> > @@ -28,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_TCA8418)+= 
> > tca8418_keypad.o
> >  obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
> >  obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
> >  obj-$(CONFIG_KEYBOARD_IPAQ_MICRO)  += ipaq-micro-keys.o
> > +obj-$(CONFIG_KEYBOARD_IQS62X)  += iqs62x-keys.o
> >  obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
> >  obj-$(CONFIG_KEYBOARD_HP6XX)   += jornada680_kbd.o
> >  obj-$(CONFIG_KEYBOARD_HP7XX)   += jornada720_kbd.o
> > diff --git a/drivers/input/keyboard/iqs62x-keys.c 
> > b/drivers/input/keyboard/iqs62x-keys.c
> > new file mode 100644
> > index 000..9d929f1
> > --- /dev/null
> > +++ b/drivers/input/keyboard/iqs62x-keys.c
> > @@ -0,0 +1,340 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Azoteq IQS620A/621/622/624/625 Touch Keys
> > + *
> > + * Copyright (C) 2019
> > + * Author: Jeff LaBundy 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +enum {
> > +   IQS62X_SW_HALL_N,
> > +   IQS62X_SW_HALL_S,
> > +};
> > +
> > +static const char * const iqs62x_switch_names[] = {
> > +   [IQS62X_SW_HALL_N] = "hall_switch_north",
> > +   [IQS62X_SW_HALL_S] = "hall_switch_south",
> > +};
> > +
> > +struct iqs62x_switch_desc {
> > +   enum iqs62x_event_flag flag;
> > +   unsigned int code;
> > +   bool enabled;
> > +};
> > +
> > +struct iqs62x_keys_private {
> > +   struct iqs62x_core *iqs62x;
> > +   struct input_dev *input;
> > +   struct notifier_block notifier;
> > +   struct iqs62x_switch_desc switches[ARRAY_SIZE(iqs62x_switch_names)];
> > +   unsigned int keycode[IQS62X_NUM_KEYS];
> > +   unsigned int keycodemax;
> > +   u8 interval;
> > +};
> > +
> > +static int iqs62x_keys_parse_prop(struct platform_device *pdev,
> > + struct iqs62x_keys_private *iqs62x_keys)
> > +{
> > +   struct device_node *keys_node = pdev->dev.of_node;
> > +   struct device_node *hall_node;
> > +   unsigned int val;
> > +   int ret, i;
> > +
> > +   if (!keys_node)
> > +   return 0;
> > +
> > +   ret = of_property_read_variable_u32_array(keys_node, "linux,keycodes",
> > + iqs62x_keys->keycode, 0,
> > + IQS62X_NUM_KEYS);
> 
> I do not think this has to be OF-specific, so please use
> device_property_*() API.
> 

Sure thing

Re: [PATCH 5/8] pwm: Add support for Azoteq IQS620A PWM generator

2019-10-21 Thread Jeff LaBundy
Hi Uwe,

Thank you for your prompt review.

On Mon, Oct 21, 2019 at 09:34:19AM +0200, Uwe Kleine-König wrote:
> Hello Jeff,
> 
> On Sun, Oct 20, 2019 at 11:11:20PM -0500, Jeff LaBundy wrote:
> > This patch adds support for the Azoteq IQS620A, capable of generating
> > a 1-kHz PWM output with duty cycle between 0.4% and 100% (inclusive).
> > 
> > Signed-off-by: Jeff LaBundy 
> > ---
> >  drivers/pwm/Kconfig   |  10 +++
> >  drivers/pwm/Makefile  |   1 +
> >  drivers/pwm/pwm-iqs620a.c | 167 
> > ++
> >  3 files changed, 178 insertions(+)
> >  create mode 100644 drivers/pwm/pwm-iqs620a.c
> > 
> > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> > index e3a2518..712445e 100644
> > --- a/drivers/pwm/Kconfig
> > +++ b/drivers/pwm/Kconfig
> > @@ -222,6 +222,16 @@ config PWM_IMX_TPM
> >   To compile this driver as a module, choose M here: the module
> >   will be called pwm-imx-tpm.
> >  
> > +config PWM_IQS620A
> > +   tristate "Azoteq IQS620A PWM support"
> > +   depends on MFD_IQS62X
> 
> This is only a runtime dependency if I'm not mistaken, so it would be
> great to have
> 
>   depends on MFD_IQS62X || COMPILE_TEST
>   depends on REGMAP
> 
> here.
> 

Sure thing; will do. Actually, it seems I can add this to all but the input
driver, as that one relies on iqs62x_events exported from the MFD.

> > +   help
> > + Generic PWM framework driver for the Azoteq IQS620A multi-function
> > + sensor.
> > +
> > + To compile this driver as a module, choose M here: the module will
> > + be called pwm-iqs620a.
> > +
> >  config PWM_JZ4740
> > tristate "Ingenic JZ47xx PWM support"
> > depends on MACH_INGENIC
> > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> > index 26326ad..27c9bfa 100644
> > --- a/drivers/pwm/Makefile
> > +++ b/drivers/pwm/Makefile
> > @@ -20,6 +20,7 @@ obj-$(CONFIG_PWM_IMG) += pwm-img.o
> >  obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o
> >  obj-$(CONFIG_PWM_IMX27)+= pwm-imx27.o
> >  obj-$(CONFIG_PWM_IMX_TPM)  += pwm-imx-tpm.o
> > +obj-$(CONFIG_PWM_IQS620A)  += pwm-iqs620a.o
> >  obj-$(CONFIG_PWM_JZ4740)   += pwm-jz4740.o
> >  obj-$(CONFIG_PWM_LP3943)   += pwm-lp3943.o
> >  obj-$(CONFIG_PWM_LPC18XX_SCT)  += pwm-lpc18xx-sct.o
> > diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
> > new file mode 100644
> > index 000..6451eb1
> > --- /dev/null
> > +++ b/drivers/pwm/pwm-iqs620a.c
> > @@ -0,0 +1,167 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Azoteq IQS620A PWM Generator
> > + *
> > + * Copyright (C) 2019
> > + * Author: Jeff LaBundy 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define IQS620_PWR_SETTINGS0xD2
> > +#define IQS620_PWR_SETTINGS_PWM_OUTBIT(7)
> > +
> > +#define IQS620_PWM_DUTY_CYCLE  0xD8
> > +
> > +#define IQS620_PWM_PERIOD_NS   100
> > +
> > +struct iqs620_pwm_private {
> > +   struct iqs62x_core *iqs62x;
> > +   struct pwm_chip chip;
> > +   struct notifier_block notifier;
> > +   bool ready;
> 
> This is always true, so you can drop it.
> 

This is here because iqs620_pwm_notifier references chip.pwms, which is
not allocated until after the notifier is registered and pwmchip_add is
called. So it protects against this (albeit unlikely) race condition:

1. iqs620_pwm_notifier is registered
2. Device immediately suffers an asynchronous reset and notifier chain
   is called (more on that in a bit)
3. iqs620_pwm_notifier evaluates chips.pwms (NULL)

I felt this was simpler than calling pwmchip_add before registering the
notifier and adding an error/tear-down path in iqs620_pwm_probe in case
of failure. I would be happy to add a comment or two to explain the not-
so-obvious purpose of this flag.

> > +};
> > +
> > +static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> > +   struct pwm_state *state)
> 
> Since
> 
>   71523d1812ac ("pwm: Ensure pwm_apply_state() doesn't modify the state 
> argument")
> 
> this isn't the right prototype.
> 

Sure thing; I will add the 'const' qualifier and remove the two changes
to the state argument.

> > +{
> > +   struct iqs620_pwm_p

Re: [PATCH 4/8] hwmon: Add support for Azoteq IQS620AT temperature sensor

2019-10-21 Thread Jeff LaBundy
Hi Guenter,

Thank you for your prompt review.

On Mon, Oct 21, 2019 at 08:38:25AM -0700, Guenter Roeck wrote:
> On Sun, Oct 20, 2019 at 11:11:19PM -0500, Jeff LaBundy wrote:
> > This patch adds support for the Azoteq IQS620AT temperature sensor,
> > capable of reporting its absolute die temperature.
> > 
> > Signed-off-by: Jeff LaBundy 
> 
> Seems to me this might be more feasible as iio driver.
> Jonathan, what do you think ?
> 

Interestingly enough, this actually started as an iio driver; however the
"When to Use" slide of [0] made me suspect that conventional devices with
the temperature sensing element integrated on the die belong in hwmon.

I then found the highly similar ad7314, which Jonathan himself appears to
have converted from iio to hwmon. Therefore, I placed this where existing
drivers seemed to match the most, especially since the temperature sensors
in iio generally use IR or a thermocouple.

That being said, I would be happy to move this into iio so long as Jonathan
does not mind, as it would limit the blast radius of this patch series.

> > ---
> >  drivers/hwmon/Kconfig | 12 +-
> >  drivers/hwmon/Makefile|  1 +
> >  drivers/hwmon/iqs620at-temp.c | 96 
> > +++
> >  3 files changed, 108 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/hwmon/iqs620at-temp.c
> > 
> > diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> > index 13a6b4a..3e56be6 100644
> > --- a/drivers/hwmon/Kconfig
> > +++ b/drivers/hwmon/Kconfig
> > @@ -385,6 +385,16 @@ config SENSORS_ATXP1
> >   This driver can also be built as a module. If so, the module
> >   will be called atxp1.
> >  
> > +config SENSORS_IQS620AT
> > +   tristate "Azoteq IQS620AT temperature sensor"
> > +   depends on MFD_IQS62X
> > +   help
> > + Say Y here if you want to build support for the Azoteq IQS620AT
> > + temperature sensor.
> > +
> > + To compile this driver as a module, choose M here: the module
> > + will be called iqs620at-temp.
> > +
> >  config SENSORS_DS620
> > tristate "Dallas Semiconductor DS620"
> > depends on I2C
> > @@ -1593,7 +1603,7 @@ config SENSORS_ADS7871
> >  
> >  config SENSORS_AMC6821
> > tristate "Texas Instruments AMC6821"
> > -   depends on I2C 
> > +   depends on I2C
> 
> No unrelated changes, please, and most definitely no
> unrelated whitespace changes.
> 

Sorry about that; it seems the original file had some trailing whitespace
here and my editor cropped it automatically. Unfortunately I didn't catch
it until after I sent out the series.

> > help
> >   If you say yes here you get support for the Texas Instruments
> >   AMC6821 hardware monitoring chips.
> > diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> > index 40c036e..2360add 100644
> > --- a/drivers/hwmon/Makefile
> > +++ b/drivers/hwmon/Makefile
> > @@ -83,6 +83,7 @@ obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
> >  obj-$(CONFIG_SENSORS_INA209)   += ina209.o
> >  obj-$(CONFIG_SENSORS_INA2XX)   += ina2xx.o
> >  obj-$(CONFIG_SENSORS_INA3221)  += ina3221.o
> > +obj-$(CONFIG_SENSORS_IQS620AT) += iqs620at-temp.o
> >  obj-$(CONFIG_SENSORS_IT87) += it87.o
> >  obj-$(CONFIG_SENSORS_JC42) += jc42.o
> >  obj-$(CONFIG_SENSORS_K8TEMP)   += k8temp.o
> > diff --git a/drivers/hwmon/iqs620at-temp.c b/drivers/hwmon/iqs620at-temp.c
> > new file mode 100644
> > index 000..0af49b6
> > --- /dev/null
> > +++ b/drivers/hwmon/iqs620at-temp.c
> > @@ -0,0 +1,96 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Azoteq IQS620AT Temperature Sensor
> > + *
> > + * Copyright (C) 2019
> > + * Author: Jeff LaBundy 
> > + */
> > +
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +#include 
> > +
> > +#define IQS620_TEMP_UI_OUT 0x1A
> > +
> > +static umode_t iqs620_temp_is_visible(const void *drvdata,
> > + enum hwmon_sensor_types type,
> > + u32 attr, int channel)
> > +{
> > +   if (type != hwmon_temp || attr != hwmon_temp_input)
> > +   return 0;
> > +
> > +   return 0444;
> > +}
> > +
> > +static int iqs620_temp_read(struct device *dev, enum hwmon_sensor_types 
> > type,
> > +   u32 attr, int channel, long *val)
> > +{
> &g

[PATCH 2/8] mfd: Add support for Azoteq IQS620A/621/622/624/625

2019-10-20 Thread Jeff LaBundy
This patch adds support for core functions common to all six-channel
members of the Azoteq ProxFusion family of sensor devices.

Signed-off-by: Jeff LaBundy 
---
 drivers/mfd/Kconfig |  13 +
 drivers/mfd/Makefile|   2 +
 drivers/mfd/iqs62x-core.c   | 638 
 drivers/mfd/iqs62x-tables.c | 424 +
 include/linux/mfd/iqs62x.h  | 148 ++
 5 files changed, 1225 insertions(+)
 create mode 100644 drivers/mfd/iqs62x-core.c
 create mode 100644 drivers/mfd/iqs62x-tables.c
 create mode 100644 include/linux/mfd/iqs62x.h

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index ae24d3e..df391f7 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -642,6 +642,19 @@ config MFD_IPAQ_MICRO
  AT90LS8535 microcontroller flashed with a special iPAQ
  firmware using the custom protocol implemented in this driver.
 
+config MFD_IQS62X
+   tristate "Azoteq IQS620A/621/622/624/625 core support"
+   depends on I2C
+   select MFD_CORE
+   select REGMAP_I2C
+   help
+ Say Y here if you want to build support for six-channel members of
+ the Azoteq ProxFusion family of sensor devices. Additional options
+ must be selected to enable device-specific functions.
+
+ To compile this driver as a module, choose M here: the module will
+ be called iqs62x.
+
 config MFD_JANZ_CMODIO
tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c1067ea..23dd71c6 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -256,3 +256,5 @@ obj-$(CONFIG_MFD_ROHM_BD70528)  += rohm-bd70528.o
 obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o
 obj-$(CONFIG_MFD_STMFX)+= stmfx.o
 
+iqs62x-objs:= iqs62x-core.o iqs62x-tables.o
+obj-$(CONFIG_MFD_IQS62X)   += iqs62x.o
diff --git a/drivers/mfd/iqs62x-core.c b/drivers/mfd/iqs62x-core.c
new file mode 100644
index 000..e2200c8
--- /dev/null
+++ b/drivers/mfd/iqs62x-core.c
@@ -0,0 +1,638 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620A/621/622/624/625 ProxFusion Sensor Family
+ *
+ * Copyright (C) 2019
+ * Author: Jeff LaBundy 
+ *
+ * These devices rely on application-specific register settings and calibration
+ * data developed in and exported from a suite of GUIs offered by the vendor. A
+ * separate tool converts the GUIs' ASCII-based output into a standard firmware
+ * file parsed by the driver.
+ *
+ * Link to data sheets and GUIs: https://www.azoteq.com/products/proxfusion/
+ *
+ * Link to conversion tool: https://github.com/jlabundy/iqs62x-h2bin.git
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#define IQS62X_PROD_NUM0x00
+
+#define IQS62X_SYS_FLAGS   0x10
+#define IQS62X_SYS_FLAGS_IN_ATIBIT(2)
+
+#define IQS622_PROX_SETTINGS_4 0x48
+#define IQS620_PROX_SETTINGS_4 0x50
+#define IQS620_PROX_SETTINGS_4_SAR_EN  BIT(7)
+
+#define IQS62X_SYS_SETTINGS0xD0
+#define IQS62X_SYS_SETTINGS_SOFT_RESET BIT(7)
+#define IQS62X_SYS_SETTINGS_ACK_RESET  BIT(6)
+#define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5)
+#define IQS62X_SYS_SETTINGS_REDO_ATI   BIT(1)
+
+#define IQS62X_PWR_SETTINGS0xD2
+#define IQS62X_PWR_SETTINGS_DIS_AUTO   BIT(5)
+#define IQS62X_PWR_SETTINGS_PWR_MODE_MASK  (BIT(4) | BIT(3))
+#define IQS62X_PWR_SETTINGS_PWR_MODE_HALT  (BIT(4) | BIT(3))
+#define IQS62X_PWR_SETTINGS_PWR_MODE_NORM  0
+
+#define IQS62X_OTP_CMD 0xF0
+#define IQS62X_OTP_CMD_FG3 0x13
+#define IQS62X_OTP_DATA0xF1
+#define IQS62X_MAX_REG 0xFF
+
+#define IQS62X_HALL_CAL_MASK   0x0F
+
+#define IQS62X_ATI_TIMEOUT 10
+
+#define IQS62X_FW_REC_TYPE_INFO0
+#define IQS62X_FW_REC_TYPE_PROD1
+#define IQS62X_FW_REC_TYPE_HALL2
+#define IQS62X_FW_REC_TYPE_MASK3
+#define IQS62X_FW_REC_TYPE_DATA4
+
+struct iqs62x_fw_rec {
+   u8 type;
+   u8 addr;
+   u8 len;
+   u8 data;
+} __packed;
+
+struct iqs62x_fw_blk {
+   struct list_head list;
+   u8 addr;
+   u8 mask;
+   u8 len;
+   u8 data[];
+};
+
+struct iqs62x_info {
+   u8 prod_num;
+   u8 sw_num;
+   u8 hw_num;
+} __packed;
+
+static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
+{
+   struct iqs62x_fw_blk *fw_blk;
+   unsigned int val;
+   int error, i;
+
+   list_for_each_entry(fw_blk

[PATCH 5/8] pwm: Add support for Azoteq IQS620A PWM generator

2019-10-20 Thread Jeff LaBundy
This patch adds support for the Azoteq IQS620A, capable of generating
a 1-kHz PWM output with duty cycle between 0.4% and 100% (inclusive).

Signed-off-by: Jeff LaBundy 
---
 drivers/pwm/Kconfig   |  10 +++
 drivers/pwm/Makefile  |   1 +
 drivers/pwm/pwm-iqs620a.c | 167 ++
 3 files changed, 178 insertions(+)
 create mode 100644 drivers/pwm/pwm-iqs620a.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index e3a2518..712445e 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -222,6 +222,16 @@ config PWM_IMX_TPM
  To compile this driver as a module, choose M here: the module
  will be called pwm-imx-tpm.
 
+config PWM_IQS620A
+   tristate "Azoteq IQS620A PWM support"
+   depends on MFD_IQS62X
+   help
+ Generic PWM framework driver for the Azoteq IQS620A multi-function
+ sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called pwm-iqs620a.
+
 config PWM_JZ4740
tristate "Ingenic JZ47xx PWM support"
depends on MACH_INGENIC
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 26326ad..27c9bfa 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PWM_IMG) += pwm-img.o
 obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o
 obj-$(CONFIG_PWM_IMX27)+= pwm-imx27.o
 obj-$(CONFIG_PWM_IMX_TPM)  += pwm-imx-tpm.o
+obj-$(CONFIG_PWM_IQS620A)  += pwm-iqs620a.o
 obj-$(CONFIG_PWM_JZ4740)   += pwm-jz4740.o
 obj-$(CONFIG_PWM_LP3943)   += pwm-lp3943.o
 obj-$(CONFIG_PWM_LPC18XX_SCT)  += pwm-lpc18xx-sct.o
diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c
new file mode 100644
index 000..6451eb1
--- /dev/null
+++ b/drivers/pwm/pwm-iqs620a.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620A PWM Generator
+ *
+ * Copyright (C) 2019
+ * Author: Jeff LaBundy 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define IQS620_PWR_SETTINGS0xD2
+#define IQS620_PWR_SETTINGS_PWM_OUTBIT(7)
+
+#define IQS620_PWM_DUTY_CYCLE  0xD8
+
+#define IQS620_PWM_PERIOD_NS   100
+
+struct iqs620_pwm_private {
+   struct iqs62x_core *iqs62x;
+   struct pwm_chip chip;
+   struct notifier_block notifier;
+   bool ready;
+};
+
+static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+   struct pwm_state *state)
+{
+   struct iqs620_pwm_private *iqs620_pwm;
+   struct iqs62x_core *iqs62x;
+   int error;
+   int duty_calc = state->duty_cycle * 256 / IQS620_PWM_PERIOD_NS - 1;
+   u8 duty_clamp = clamp(duty_calc, 0, 0xFF);
+
+   iqs620_pwm = container_of(chip, struct iqs620_pwm_private, chip);
+   iqs62x = iqs620_pwm->iqs62x;
+
+   error = regmap_write(iqs62x->map, IQS620_PWM_DUTY_CYCLE, duty_clamp);
+   if (error)
+   return error;
+
+   state->period = IQS620_PWM_PERIOD_NS;
+   state->duty_cycle = (duty_clamp + 1) * IQS620_PWM_PERIOD_NS / 256;
+
+   return regmap_update_bits(iqs62x->map, IQS620_PWR_SETTINGS,
+ IQS620_PWR_SETTINGS_PWM_OUT,
+ state->enabled ? 0xFF : 0);
+}
+
+static int iqs620_pwm_notifier(struct notifier_block *notifier,
+  unsigned long event_flags, void *context)
+{
+   struct iqs620_pwm_private *iqs620_pwm;
+   struct pwm_state state;
+   int error;
+
+   iqs620_pwm = container_of(notifier, struct iqs620_pwm_private,
+ notifier);
+
+   if (!iqs620_pwm->ready || !(event_flags & BIT(IQS62X_EVENT_SYS_RESET)))
+   return NOTIFY_DONE;
+
+   pwm_get_state(_pwm->chip.pwms[0], );
+
+   error = iqs620_pwm_apply(_pwm->chip,
+_pwm->chip.pwms[0], );
+   if (error) {
+   dev_err(iqs620_pwm->chip.dev,
+   "Failed to re-initialize device: %d\n", error);
+   return NOTIFY_BAD;
+   }
+
+   return NOTIFY_OK;
+}
+
+static void iqs620_pwm_notifier_unregister(void *context)
+{
+   struct iqs620_pwm_private *iqs620_pwm = context;
+   int error;
+
+   error = blocking_notifier_chain_unregister(_pwm->iqs62x->nh,
+  _pwm->notifier);
+   if (error)
+   dev_err(iqs620_pwm->chip.dev,
+   "Failed to unregister notifier: %d\n", error);
+}
+
+static const struct pwm_ops iqs620_pwm_ops = {
+   .apply  = iqs620_pwm_apply,
+   .owner  = THIS_MODULE,
+};
+
+static int iqs620_pwm_probe(struct platform_device *pdev)
+{
+   struct iqs620_pwm_private *iqs620_pwm;
+   int error;
+
+

[PATCH 0/8] Add support for Azoteq IQS620A/621/622/624/625

2019-10-20 Thread Jeff LaBundy
This series adds support for six-channel members of the Azoteq ProxFusion
family of sensor devices: IQS620A, IQS621, IQS622, IQS624 and IQS625. Each
device integrates multiple sensor technologies in a single package.

A multi-function device (MFD) driver supports core functions common to all
devices, including device identification, firmware, interrupt handling and
runtime power management. The MFD driver is also responsible for adding all
product-specific sub-devices.

Each device supports self-capacitive, Hall-effect, and (in some cases) mutual-
inductive sensing. These functions represent keys or switches and are supported
by an input driver that covers all five devices. An assortment of pwm, hwmon
and iio drivers support device-specific functions.

This series was tested using the following development hardware: IQS620AEV04,
IQS621EV04, IQS622EV04 and IQS624/5EV04.

Jeff LaBundy (8):
  dt-bindings: mfd: iqs62x: Add bindings
  mfd: Add support for Azoteq IQS620A/621/622/624/625
  input: keyboard: Add support for Azoteq IQS620A/621/622/624/625
  hwmon: Add support for Azoteq IQS620AT temperature sensor
  pwm: Add support for Azoteq IQS620A PWM generator
  iio: light: Add support for Azoteq IQS621 ambient light sensor
  iio: proximity: Add support for Azoteq IQS622 proximity sensor
  iio: position: Add support for Azoteq IQS624/625 angle sensor

 Documentation/devicetree/bindings/mfd/iqs62x.txt | 242 +
 drivers/hwmon/Kconfig|  12 +-
 drivers/hwmon/Makefile   |   1 +
 drivers/hwmon/iqs620at-temp.c|  96 
 drivers/iio/Kconfig  |   1 +
 drivers/iio/Makefile |   1 +
 drivers/iio/light/Kconfig|  10 +
 drivers/iio/light/Makefile   |   1 +
 drivers/iio/light/iqs621-als.c   | 361 +
 drivers/iio/position/Kconfig |  19 +
 drivers/iio/position/Makefile|   7 +
 drivers/iio/position/iqs624-pos.c| 302 +++
 drivers/iio/proximity/Kconfig|  10 +
 drivers/iio/proximity/Makefile   |   1 +
 drivers/iio/proximity/iqs622-prox.c  | 334 
 drivers/input/keyboard/Kconfig   |  10 +
 drivers/input/keyboard/Makefile  |   1 +
 drivers/input/keyboard/iqs62x-keys.c | 340 
 drivers/mfd/Kconfig  |  13 +
 drivers/mfd/Makefile |   2 +
 drivers/mfd/iqs62x-core.c| 638 +++
 drivers/mfd/iqs62x-tables.c  | 424 +++
 drivers/pwm/Kconfig  |  10 +
 drivers/pwm/Makefile |   1 +
 drivers/pwm/pwm-iqs620a.c| 167 ++
 include/linux/mfd/iqs62x.h   | 148 ++
 26 files changed, 3151 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/mfd/iqs62x.txt
 create mode 100644 drivers/hwmon/iqs620at-temp.c
 create mode 100644 drivers/iio/light/iqs621-als.c
 create mode 100644 drivers/iio/position/Kconfig
 create mode 100644 drivers/iio/position/Makefile
 create mode 100644 drivers/iio/position/iqs624-pos.c
 create mode 100644 drivers/iio/proximity/iqs622-prox.c
 create mode 100644 drivers/input/keyboard/iqs62x-keys.c
 create mode 100644 drivers/mfd/iqs62x-core.c
 create mode 100644 drivers/mfd/iqs62x-tables.c
 create mode 100644 drivers/pwm/pwm-iqs620a.c
 create mode 100644 include/linux/mfd/iqs62x.h

--
2.7.4



[PATCH 7/8] iio: proximity: Add support for Azoteq IQS622 proximity sensor

2019-10-20 Thread Jeff LaBundy
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 
---
 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 000..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 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define IQS622_IR_FLAGS0x16
+#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_SHIFT0
+
+#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(_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, );
+   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(_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_

[PATCH 1/8] dt-bindings: mfd: iqs62x: Add bindings

2019-10-20 Thread Jeff LaBundy
This patch adds binding documentation for six-channel members of the
Azoteq ProxFusion family of sensor devices.

Signed-off-by: Jeff LaBundy 
---
 Documentation/devicetree/bindings/mfd/iqs62x.txt | 242 +++
 1 file changed, 242 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/mfd/iqs62x.txt

diff --git a/Documentation/devicetree/bindings/mfd/iqs62x.txt 
b/Documentation/devicetree/bindings/mfd/iqs62x.txt
new file mode 100644
index 000..089f567
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/iqs62x.txt
@@ -0,0 +1,242 @@
+Azoteq IQS620A/621/622/624/625 ProxFusion Sensor Family
+
+Required properties:
+
+- compatible   : Must be equal to one of the following:
+ "azoteq,iqs620a"
+ "azoteq,iqs621"
+ "azoteq,iqs622"
+ "azoteq,iqs624"
+ "azoteq,iqs625"
+
+- reg  : I2C slave address for the device.
+
+- interrupts   : GPIO to which the device's active-low RDY
+ output is connected (see [0]).
+
+Optional properties:
+
+- linux,fw-file: Specifies the name of the calibration 
and
+ configuration file selected by the driver.
+ If this property is omitted, the filename
+ is selected based on the device name with
+ ".bin" as the extension (e.g. iqs620a.bin
+ for IQS620A).
+
+All devices accommodate a child node (e.g. "keys") that represents touch key
+support. Required properties for the "keys" child node include:
+
+- compatible   : Must be equal to one of the following:
+ "azoteq,iqs620a-keys"
+ "azoteq,iqs621-keys"
+ "azoteq,iqs622-keys"
+ "azoteq,iqs624-keys"
+ "azoteq,iqs625-keys"
+
+- linux,keycodes   : Specifies an array of up to 16 numeric key-
+ codes corresponding to each available touch
+ or proximity event. An 'x' in the following
+ table indicates an event is supported for a
+ given device; specify 0 for unused events.
+
+  
+  | #  | Event | IQS620A | IQS621 | IQS622 | IQS624 | IQS625 |
+  
+  | 0  | CH0 Touch |x|x   |x   |x   |x   |
+  || Antenna 1 Touch*  |x|||||
+  
+  | 1  | CH0 Proximity |x|x   |x   |x   |x   |
+  || Antenna 1 Proximity*  |x|||||
+  
+  | 2  | CH1 Touch |x|x   |x   |x   |x   |
+  || Antenna 1 Deep Touch* |x|||||
+  
+  | 3  | CH1 Proximity |x|x   |x   |x   |x   |
+  
+  | 4  | CH2 Touch |x|||||
+  
+  | 5  | CH2 Proximity |x|||||
+  || Antenna 2 Proximity*  |x|||||
+  
+  | 6  | Metal (+) Touch** |x|x   ||||
+  || Antenna 2 Deep Touch* |x|||||
+  
+  | 7  | Metal (+) Proximity** |x|x   ||||
+  || Antenna 2 Touch*  |x|||||
+  
+  | 8  | Metal (-) Touch** |x|x   ||||
+  
+  | 9  | Metal (-) Proximity** |x|x   ||||
+  

[PATCH 8/8] iio: position: Add support for Azoteq IQS624/625 angle sensor

2019-10-20 Thread Jeff LaBundy
This patch adds support for the Azoteq IQS624 and IQS625 angular position
sensors, capable of reporting the angle of a rotating shaft down to 1 and
10 degrees of accuracy, respectively.

This patch also introduces a home for linear and angular position sensors.
Unlike resolvers, they are typically contactless and use the Hall effect.

Signed-off-by: Jeff LaBundy 
---
 drivers/iio/Kconfig   |   1 +
 drivers/iio/Makefile  |   1 +
 drivers/iio/position/Kconfig  |  19 +++
 drivers/iio/position/Makefile |   7 +
 drivers/iio/position/iqs624-pos.c | 302 ++
 5 files changed, 330 insertions(+)
 create mode 100644 drivers/iio/position/Kconfig
 create mode 100644 drivers/iio/position/Makefile
 create mode 100644 drivers/iio/position/iqs624-pos.c

diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 5bd5185..d5c073a 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -88,6 +88,7 @@ source "drivers/iio/orientation/Kconfig"
 if IIO_TRIGGER
source "drivers/iio/trigger/Kconfig"
 endif #IIO_TRIGGER
+source "drivers/iio/position/Kconfig"
 source "drivers/iio/potentiometer/Kconfig"
 source "drivers/iio/potentiostat/Kconfig"
 source "drivers/iio/pressure/Kconfig"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index bff682a..1712011 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -31,6 +31,7 @@ obj-y += light/
 obj-y += magnetometer/
 obj-y += multiplexer/
 obj-y += orientation/
+obj-y += position/
 obj-y += potentiometer/
 obj-y += potentiostat/
 obj-y += pressure/
diff --git a/drivers/iio/position/Kconfig b/drivers/iio/position/Kconfig
new file mode 100644
index 000..ed9f975
--- /dev/null
+++ b/drivers/iio/position/Kconfig
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Linear and angular position sensors
+#
+# When adding new entries keep the list in alphabetical order
+
+menu "Linear and angular position sensors"
+
+config IQS624_POS
+   tristate "Azoteq IQS624/625 angular position sensor"
+   depends on MFD_IQS62X
+   help
+ Say Y here if you want to build support for the Azoteq IQS624
+ and IQS625 angular position sensors.
+
+ To compile this driver as a module, choose M here: the module
+ will be called iqs624-pos.
+
+endmenu
diff --git a/drivers/iio/position/Makefile b/drivers/iio/position/Makefile
new file mode 100644
index 000..3cbe7a7
--- /dev/null
+++ b/drivers/iio/position/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for IIO linear and angular position sensors
+#
+
+# When adding new entries keep the list in alphabetical order
+
+obj-$(CONFIG_IQS624_POS)   += iqs624-pos.o
diff --git a/drivers/iio/position/iqs624-pos.c 
b/drivers/iio/position/iqs624-pos.c
new file mode 100644
index 000..d975065
--- /dev/null
+++ b/drivers/iio/position/iqs624-pos.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS624/625 Angular Position Sensor
+ *
+ * Copyright (C) 2019
+ * Author: Jeff LaBundy 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define IQS624_POS_DEG_OUT 0x16
+
+#define IQS624_POS_SCALE1  (314159 / 180)
+#define IQS624_POS_SCALE2  10
+
+struct iqs624_pos_private {
+   struct iqs62x_core *iqs62x;
+   struct notifier_block notifier;
+   struct mutex lock;
+   bool event_en;
+   union {
+   u16 angle;
+   u8 interval;
+   };
+};
+
+static int iqs624_pos_init(struct iqs624_pos_private *iqs624_pos)
+{
+   struct iqs62x_core *iqs62x = iqs624_pos->iqs62x;
+   unsigned int val;
+   int error;
+   __le16 val_buf;
+
+   if (iqs62x->dev_desc->prod_num == IQS624_PROD_NUM) {
+   error = regmap_raw_read(iqs62x->map, IQS624_POS_DEG_OUT,
+   _buf, sizeof(val_buf));
+   if (error)
+   return error;
+
+   iqs624_pos->angle = le16_to_cpu(val_buf);
+   } else {
+   error = regmap_read(iqs62x->map, iqs62x->dev_desc->interval,
+   );
+   if (error)
+   return error;
+
+   iqs624_pos->interval = val;
+   }
+
+   mutex_lock(_pos->lock);
+
+   /*
+* The IQS625 reports angular position in the form of coarse intervals,
+* so only interval change events are unmasked. Conversely, the IQS624
+* reports angular position down to one degree of resolution, so wheel
+* movement events are unmasked instead.
+*/
+   error = regmap_update_bits(iqs62x->map, IQS624_HALL_UI,
+  iqs62x->dev_desc->prod_num ==
+  IQS

[PATCH 6/8] iio: light: Add support for Azoteq IQS621 ambient light sensor

2019-10-20 Thread Jeff LaBundy
This patch adds support for the Azoteq IQS621 ambient light sensor,
capable of reporting intensity directly in units of lux.

Signed-off-by: Jeff LaBundy 
---
 drivers/iio/light/Kconfig  |  10 ++
 drivers/iio/light/Makefile |   1 +
 drivers/iio/light/iqs621-als.c | 361 +
 3 files changed, 372 insertions(+)
 create mode 100644 drivers/iio/light/iqs621-als.c

diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 4a1a883..aad26dc 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -162,6 +162,16 @@ config GP2AP020A00F
  To compile this driver as a module, choose M here: the
  module will be called gp2ap020a00f.
 
+config IQS621_ALS
+   tristate "Azoteq IQS621 ambient light sensor"
+   depends on MFD_IQS62X
+   help
+ Say Y here if you want to build support for the Azoteq IQS621
+ ambient light sensor.
+
+ To compile this driver as a module, choose M here: the module
+ will be called iqs621-als.
+
 config SENSORS_ISL29018
tristate "Intersil 29018 light and proximity sensor"
depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 00d1f9b..aa34358 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_IIO_CROS_EC_LIGHT_PROX) += cros_ec_light_prox.o
 obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
 obj-$(CONFIG_HID_SENSOR_ALS)   += hid-sensor-als.o
 obj-$(CONFIG_HID_SENSOR_PROX)  += hid-sensor-prox.o
+obj-$(CONFIG_IQS621_ALS)   += iqs621-als.o
 obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
 obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
 obj-$(CONFIG_ISL29125) += isl29125.o
diff --git a/drivers/iio/light/iqs621-als.c b/drivers/iio/light/iqs621-als.c
new file mode 100644
index 000..92a6173
--- /dev/null
+++ b/drivers/iio/light/iqs621-als.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS621 Ambient Light Sensor
+ *
+ * Copyright (C) 2019
+ * Author: Jeff LaBundy 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define IQS621_ALS_FLAGS   0x16
+#define IQS621_ALS_FLAGS_LIGHT BIT(7)
+
+#define IQS621_ALS_UI_OUT  0x17
+
+#define IQS621_ALS_THRESH_DARK 0x80
+#define IQS621_ALS_THRESH_DARK_MAX 1020
+#define IQS621_ALS_THRESH_DARK_SHIFT   2
+
+#define IQS621_ALS_THRESH_LIGHT0x81
+#define IQS621_ALS_THRESH_LIGHT_MAX4080
+#define IQS621_ALS_THRESH_LIGHT_SHIFT  4
+
+struct iqs621_als_private {
+   struct iqs62x_core *iqs62x;
+   struct notifier_block notifier;
+   struct mutex lock;
+   bool event_en;
+   u8 thresh_light;
+   u8 thresh_dark;
+   u8 flags;
+};
+
+static int iqs621_als_init(struct iqs621_als_private *iqs621_als)
+{
+   struct iqs62x_core *iqs62x = iqs621_als->iqs62x;
+   unsigned int val;
+   int error;
+
+   mutex_lock(_als->lock);
+
+   error = regmap_write(iqs62x->map, IQS621_ALS_THRESH_LIGHT,
+iqs621_als->thresh_light);
+   if (error)
+   goto err_mutex;
+
+   error = regmap_write(iqs62x->map, IQS621_ALS_THRESH_DARK,
+iqs621_als->thresh_dark);
+   if (error)
+   goto err_mutex;
+
+   error = regmap_read(iqs62x->map, IQS621_ALS_FLAGS, );
+   if (error)
+   goto err_mutex;
+   iqs621_als->flags = val;
+
+   error = regmap_update_bits(iqs62x->map, IQS620_GLBL_EVENT_MASK,
+  iqs62x->dev_desc->als_mask,
+  iqs621_als->event_en ? 0 : 0xFF);
+
+err_mutex:
+   mutex_unlock(_als->lock);
+
+   return error;
+}
+
+static int iqs621_als_notifier(struct notifier_block *notifier,
+  unsigned long event_flags, void *context)
+{
+   struct iqs62x_event_data *event_data = context;
+   struct iqs621_als_private *iqs621_als;
+   struct iio_dev *indio_dev;
+   enum iio_event_direction dir;
+   int error;
+
+   iqs621_als = container_of(notifier, struct iqs621_als_private,
+ notifier);
+   indio_dev = iio_priv_to_dev(iqs621_als);
+
+   if (event_flags & BIT(IQS62X_EVENT_SYS_RESET)) {
+   error = iqs621_als_init(iqs621_als);
+   if (error) {
+   dev_err(indio_dev->dev.parent,
+   "Failed to re-initialize device: %d\n", error);
+   return NOTIFY_BAD;
+   }
+
+   return NOTIFY_OK;
+   }
+
+   if (!((event_data->als_flags ^ iqs621_als->flags) &
+   IQS621_ALS_FLAGS_LIGHT))
+   return NOTIF

[PATCH 3/8] input: keyboard: Add support for Azoteq IQS620A/621/622/624/625

2019-10-20 Thread Jeff LaBundy
This patch adds touch key support for six-channel members of the
Azoteq ProxFusion family of sensor devices.

Signed-off-by: Jeff LaBundy 
---
 drivers/input/keyboard/Kconfig   |  10 ++
 drivers/input/keyboard/Makefile  |   1 +
 drivers/input/keyboard/iqs62x-keys.c | 340 +++
 3 files changed, 351 insertions(+)
 create mode 100644 drivers/input/keyboard/iqs62x-keys.c

diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 8911bc2..ab10aff 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -657,6 +657,16 @@ config KEYBOARD_IPAQ_MICRO
  To compile this driver as a module, choose M here: the
  module will be called ipaq-micro-keys.
 
+config KEYBOARD_IQS62X
+   tristate "Azoteq IQS620A/621/622/624/625 touch keys"
+   depends on MFD_IQS62X
+   help
+ Say Y here to enable touch-key support for six-channel members of
+ the Azoteq ProxFusion family of sensor devices.
+
+ To compile this driver as a module, choose M here: the module will
+ be called iqs62x-keys.
+
 config KEYBOARD_OMAP
tristate "TI OMAP keypad support"
depends on ARCH_OMAP1
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 9510325..ee85b7f 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_KEYBOARD_TCA8418)+= 
tca8418_keypad.o
 obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
 obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
 obj-$(CONFIG_KEYBOARD_IPAQ_MICRO)  += ipaq-micro-keys.o
+obj-$(CONFIG_KEYBOARD_IQS62X)  += iqs62x-keys.o
 obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
 obj-$(CONFIG_KEYBOARD_HP6XX)   += jornada680_kbd.o
 obj-$(CONFIG_KEYBOARD_HP7XX)   += jornada720_kbd.o
diff --git a/drivers/input/keyboard/iqs62x-keys.c 
b/drivers/input/keyboard/iqs62x-keys.c
new file mode 100644
index 000..9d929f1
--- /dev/null
+++ b/drivers/input/keyboard/iqs62x-keys.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Azoteq IQS620A/621/622/624/625 Touch Keys
+ *
+ * Copyright (C) 2019
+ * Author: Jeff LaBundy 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+enum {
+   IQS62X_SW_HALL_N,
+   IQS62X_SW_HALL_S,
+};
+
+static const char * const iqs62x_switch_names[] = {
+   [IQS62X_SW_HALL_N] = "hall_switch_north",
+   [IQS62X_SW_HALL_S] = "hall_switch_south",
+};
+
+struct iqs62x_switch_desc {
+   enum iqs62x_event_flag flag;
+   unsigned int code;
+   bool enabled;
+};
+
+struct iqs62x_keys_private {
+   struct iqs62x_core *iqs62x;
+   struct input_dev *input;
+   struct notifier_block notifier;
+   struct iqs62x_switch_desc switches[ARRAY_SIZE(iqs62x_switch_names)];
+   unsigned int keycode[IQS62X_NUM_KEYS];
+   unsigned int keycodemax;
+   u8 interval;
+};
+
+static int iqs62x_keys_parse_prop(struct platform_device *pdev,
+ struct iqs62x_keys_private *iqs62x_keys)
+{
+   struct device_node *keys_node = pdev->dev.of_node;
+   struct device_node *hall_node;
+   unsigned int val;
+   int ret, i;
+
+   if (!keys_node)
+   return 0;
+
+   ret = of_property_read_variable_u32_array(keys_node, "linux,keycodes",
+ iqs62x_keys->keycode, 0,
+ IQS62X_NUM_KEYS);
+   if (ret < 0) {
+   dev_err(>dev, "Failed to read keycodes: %d\n", ret);
+   return ret;
+   }
+   iqs62x_keys->keycodemax = ret;
+
+   for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
+   hall_node = of_get_child_by_name(keys_node,
+iqs62x_switch_names[i]);
+   if (!hall_node)
+   continue;
+
+   ret = of_property_read_u32(hall_node, "linux,code", );
+   if (ret < 0) {
+   dev_err(>dev, "Failed to read switch code: %d\n",
+   ret);
+   of_node_put(hall_node);
+   return ret;
+   }
+
+   if (of_property_read_bool(hall_node, "azoteq,use-prox"))
+   iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
+IQS62X_EVENT_HALL_N_P :
+IQS62X_EVENT_HALL_S_P);
+   else
+   iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
+IQS62X_EVENT_HALL_N_T :
+