Re: [PATCH 5/6] mfd: iqs62x: Do not poll during ATI

From: Lee Jones
Date: Thu Jan 14 2021 - 05:18:00 EST


On Sun, 03 Jan 2021, Jeff LaBundy wrote:

> After loading firmware, the driver triggers ATI (calibration) with
> the newly loaded register configuration in place. Next, the driver
> polls a register field to ensure ATI completed in a timely fashion
> and that the device is ready to sense.
>
> However, communicating with the device over I2C while ATI is under-

This doesn't line-up with all of the others! ;)

> way may induce noise in the device and cause ATI to fail. As such,
> the vendor recommends not to poll the device during ATI.
>
> To solve this problem, let the device naturally signal to the host
> that ATI is complete by way of an interrupt. A completion prevents
> the sub-devices from being registered until this happens.
>
> The former logic that scaled ATI timeout and filter settling delay
> is not carried forward with the new implementation, as it produces
> overly conservative delays at lower clock rates. Instead, a single
> pair of delays that covers all cases is used.
>
> Signed-off-by: Jeff LaBundy <jeff@xxxxxxxxxxx>
> ---
> drivers/mfd/iqs62x.c | 103 ++++++++++++++++++++++++++++++---------------
> include/linux/mfd/iqs62x.h | 6 ++-
> 2 files changed, 73 insertions(+), 36 deletions(-)

[...]

> @@ -567,6 +600,12 @@ static void iqs62x_firmware_load(const struct firmware *fw, void *context)
> goto err_out;
> }
>
> + if (!wait_for_completion_timeout(&iqs62x->ati_done,
> + msecs_to_jiffies(2000))) {
> + dev_err(&client->dev, "Failed to complete ATI\n");
> + goto err_out;
> + }
> +
> ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
> iqs62x->dev_desc->sub_devs,
> iqs62x->dev_desc->num_sub_devs,
> @@ -763,7 +802,6 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
> .prox_settings = IQS620_PROX_SETTINGS_4,
> .hall_flags = IQS620_HALL_FLAGS,
>
> - .clk_div = 4,

No unnecessary double-line spacings please.

> .fw_name = "iqs620a.bin",
> .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
> },
> @@ -784,7 +822,6 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
> .prox_settings = IQS620_PROX_SETTINGS_4,
> .hall_flags = IQS620_HALL_FLAGS,
>
> - .clk_div = 4,

As above.

> .fw_name = "iqs620a.bin",
> .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
> },
> @@ -808,7 +845,6 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
> .hall_flags = IQS621_HALL_FLAGS,
> .hyst_shift = 5,
>
> - .clk_div = 2,

As above.

> .fw_name = "iqs621.bin",
> .event_regs = &iqs621_event_regs[IQS62X_UI_PROX],
> },
> @@ -830,7 +866,6 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
> .als_flags = IQS622_ALS_FLAGS,
> .hall_flags = IQS622_HALL_FLAGS,
>
> - .clk_div = 2,

As above.

> .fw_name = "iqs622.bin",
> .event_regs = &iqs622_event_regs[IQS62X_UI_PROX],
> },
> @@ -845,7 +880,6 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
> .interval = IQS624_INTERVAL_NUM,
> .interval_div = 3,
>
> - .clk_div = 2,

As above.

> .fw_name = "iqs624.bin",
> .event_regs = &iqs624_event_regs[IQS62X_UI_PROX],
> },
> @@ -860,7 +894,6 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
> .interval = IQS625_INTERVAL_NUM,
> .interval_div = 10,
>
> - .clk_div = 2,

As above.

> .fw_name = "iqs625.bin",
> .event_regs = &iqs625_event_regs[IQS62X_UI_PROX],
> },
> @@ -890,6 +923,8 @@ static int iqs62x_probe(struct i2c_client *client)
>
> BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);
> INIT_LIST_HEAD(&iqs62x->fw_blk_head);
> +
> + init_completion(&iqs62x->ati_done);
> init_completion(&iqs62x->fw_done);
>
> iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config);
> diff --git a/include/linux/mfd/iqs62x.h b/include/linux/mfd/iqs62x.h
> index 043d3b6..0b71173 100644
> --- a/include/linux/mfd/iqs62x.h
> +++ b/include/linux/mfd/iqs62x.h
> @@ -28,7 +28,7 @@
> #define IQS620_GLBL_EVENT_MASK_PMU BIT(6)
>
> #define IQS62X_NUM_KEYS 16
> -#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 5)
> +#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 6)
>
> #define IQS62X_EVENT_SIZE 10
>
> @@ -78,6 +78,7 @@ enum iqs62x_event_flag {
>
> /* everything else */
> IQS62X_EVENT_SYS_RESET,
> + IQS62X_EVENT_SYS_ATI,
> };
>
> struct iqs62x_event_data {
> @@ -119,7 +120,6 @@ struct iqs62x_dev_desc {
> u8 interval;
> u8 interval_div;
>
> - u8 clk_div;

As above.

> const char *fw_name;
> const enum iqs62x_event_reg (*event_regs)[IQS62X_EVENT_SIZE];
> };
> @@ -130,8 +130,10 @@ struct iqs62x_core {
> struct regmap *regmap;
> struct blocking_notifier_head nh;
> struct list_head fw_blk_head;
> + struct completion ati_done;
> struct completion fw_done;
> enum iqs62x_ui_sel ui_sel;
> + unsigned long event_cache;
> };
>
> extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];

--
Lee Jones [李琼斯]
Senior Technical Lead - Developer Services
Linaro.org │ Open source software for Arm SoCs
Follow Linaro: Facebook | Twitter | Blog