Skip to content

Commit 02e550d

Browse files
jlabundyLee Jones
authored andcommitted
mfd: iqs62x: Do not poll during ATI
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- 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@labundy.com> Signed-off-by: Lee Jones <lee.jones@linaro.org>
1 parent a3a06ea commit 02e550d

2 files changed

Lines changed: 73 additions & 63 deletions

File tree

drivers/mfd/iqs62x.c

Lines changed: 69 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
#define IQS62X_PROD_NUM 0x00
3737

3838
#define IQS62X_SYS_FLAGS 0x10
39-
#define IQS62X_SYS_FLAGS_IN_ATI BIT(2)
4039

4140
#define IQS620_HALL_FLAGS 0x16
4241
#define IQS621_HALL_FLAGS 0x19
@@ -60,6 +59,7 @@
6059
#define IQS62X_SYS_SETTINGS_ACK_RESET BIT(6)
6160
#define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5)
6261
#define IQS62X_SYS_SETTINGS_CLK_DIV BIT(4)
62+
#define IQS62X_SYS_SETTINGS_COMM_ATI BIT(3)
6363
#define IQS62X_SYS_SETTINGS_REDO_ATI BIT(1)
6464

6565
#define IQS62X_PWR_SETTINGS 0xD2
@@ -81,9 +81,7 @@
8181
#define IQS62X_FW_REC_TYPE_MASK 3
8282
#define IQS62X_FW_REC_TYPE_DATA 4
8383

84-
#define IQS62X_ATI_POLL_SLEEP_US 10000
85-
#define IQS62X_ATI_POLL_TIMEOUT_US 500000
86-
#define IQS62X_ATI_STABLE_DELAY_MS 150
84+
#define IQS62X_FILT_SETTLE_MS 250
8785

8886
struct iqs62x_fw_rec {
8987
u8 type;
@@ -111,7 +109,6 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
111109
struct iqs62x_fw_blk *fw_blk;
112110
unsigned int val;
113111
int ret;
114-
u8 clk_div = 1;
115112

116113
list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) {
117114
if (fw_blk->mask)
@@ -181,28 +178,32 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x)
181178
return ret;
182179
}
183180

184-
ret = regmap_read(iqs62x->regmap, IQS62X_SYS_SETTINGS, &val);
185-
if (ret)
186-
return ret;
187-
188-
if (val & IQS62X_SYS_SETTINGS_CLK_DIV)
189-
clk_div = iqs62x->dev_desc->clk_div;
190-
191-
ret = regmap_write(iqs62x->regmap, IQS62X_SYS_SETTINGS, val |
192-
IQS62X_SYS_SETTINGS_ACK_RESET |
193-
IQS62X_SYS_SETTINGS_EVENT_MODE |
194-
IQS62X_SYS_SETTINGS_REDO_ATI);
195-
if (ret)
196-
return ret;
197-
198-
ret = regmap_read_poll_timeout(iqs62x->regmap, IQS62X_SYS_FLAGS, val,
199-
!(val & IQS62X_SYS_FLAGS_IN_ATI),
200-
IQS62X_ATI_POLL_SLEEP_US,
201-
IQS62X_ATI_POLL_TIMEOUT_US * clk_div);
181+
/*
182+
* Place the device in streaming mode at first so as not to miss the
183+
* limited number of interrupts that would otherwise occur after ATI
184+
* completes. The device is subsequently placed in event mode by the
185+
* interrupt handler.
186+
*
187+
* In the meantime, mask interrupts during ATI to prevent the device
188+
* from soliciting I2C traffic until the noise-sensitive ATI process
189+
* is complete.
190+
*/
191+
ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,
192+
IQS62X_SYS_SETTINGS_ACK_RESET |
193+
IQS62X_SYS_SETTINGS_EVENT_MODE |
194+
IQS62X_SYS_SETTINGS_COMM_ATI |
195+
IQS62X_SYS_SETTINGS_REDO_ATI,
196+
IQS62X_SYS_SETTINGS_ACK_RESET |
197+
IQS62X_SYS_SETTINGS_REDO_ATI);
202198
if (ret)
203199
return ret;
204200

205-
msleep(IQS62X_ATI_STABLE_DELAY_MS * clk_div);
201+
/*
202+
* The following delay gives the device time to deassert its RDY output
203+
* in case a communication window was open while the REDO_ATI field was
204+
* written. This prevents an interrupt from being serviced prematurely.
205+
*/
206+
usleep_range(5000, 5100);
206207

207208
return 0;
208209
}
@@ -433,6 +434,11 @@ const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = {
433434
.mask = BIT(7),
434435
.val = BIT(7),
435436
},
437+
[IQS62X_EVENT_SYS_ATI] = {
438+
.reg = IQS62X_EVENT_SYS,
439+
.mask = BIT(2),
440+
.val = BIT(2),
441+
},
436442
};
437443
EXPORT_SYMBOL_GPL(iqs62x_events);
438444

@@ -521,12 +527,39 @@ static irqreturn_t iqs62x_irq(int irq, void *context)
521527
"Failed to re-initialize device: %d\n", ret);
522528
return IRQ_NONE;
523529
}
530+
531+
iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_RESET);
532+
reinit_completion(&iqs62x->ati_done);
533+
} else if (event_flags & BIT(IQS62X_EVENT_SYS_ATI)) {
534+
iqs62x->event_cache |= BIT(IQS62X_EVENT_SYS_ATI);
535+
reinit_completion(&iqs62x->ati_done);
536+
} else if (!completion_done(&iqs62x->ati_done)) {
537+
ret = regmap_update_bits(iqs62x->regmap, IQS62X_SYS_SETTINGS,
538+
IQS62X_SYS_SETTINGS_EVENT_MODE, 0xFF);
539+
if (ret) {
540+
dev_err(&client->dev,
541+
"Failed to enable event mode: %d\n", ret);
542+
return IRQ_NONE;
543+
}
544+
545+
msleep(IQS62X_FILT_SETTLE_MS);
546+
complete_all(&iqs62x->ati_done);
524547
}
525548

526-
ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
527-
&event_data);
528-
if (ret & NOTIFY_STOP_MASK)
529-
return IRQ_NONE;
549+
/*
550+
* Reset and ATI events are not broadcast to the sub-device drivers
551+
* until ATI has completed. Any other events that may have occurred
552+
* during ATI are ignored.
553+
*/
554+
if (completion_done(&iqs62x->ati_done)) {
555+
event_flags |= iqs62x->event_cache;
556+
ret = blocking_notifier_call_chain(&iqs62x->nh, event_flags,
557+
&event_data);
558+
if (ret & NOTIFY_STOP_MASK)
559+
return IRQ_NONE;
560+
561+
iqs62x->event_cache = 0;
562+
}
530563

531564
/*
532565
* Once the communication window is closed, a small delay is added to
@@ -567,6 +600,12 @@ static void iqs62x_firmware_load(const struct firmware *fw, void *context)
567600
goto err_out;
568601
}
569602

603+
if (!wait_for_completion_timeout(&iqs62x->ati_done,
604+
msecs_to_jiffies(2000))) {
605+
dev_err(&client->dev, "Failed to complete ATI\n");
606+
goto err_out;
607+
}
608+
570609
ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
571610
iqs62x->dev_desc->sub_devs,
572611
iqs62x->dev_desc->num_sub_devs,
@@ -748,119 +787,91 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = {
748787
.dev_name = "iqs620at",
749788
.sub_devs = iqs620at_sub_devs,
750789
.num_sub_devs = ARRAY_SIZE(iqs620at_sub_devs),
751-
752790
.prod_num = IQS620_PROD_NUM,
753791
.sw_num = 0x08,
754792
.cal_regs = iqs620at_cal_regs,
755793
.num_cal_regs = ARRAY_SIZE(iqs620at_cal_regs),
756-
757794
.prox_mask = BIT(0),
758795
.sar_mask = BIT(1) | BIT(7),
759796
.hall_mask = BIT(2),
760797
.hyst_mask = BIT(3),
761798
.temp_mask = BIT(4),
762-
763799
.prox_settings = IQS620_PROX_SETTINGS_4,
764800
.hall_flags = IQS620_HALL_FLAGS,
765-
766-
.clk_div = 4,
767801
.fw_name = "iqs620a.bin",
768802
.event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
769803
},
770804
{
771805
.dev_name = "iqs620a",
772806
.sub_devs = iqs620a_sub_devs,
773807
.num_sub_devs = ARRAY_SIZE(iqs620a_sub_devs),
774-
775808
.prod_num = IQS620_PROD_NUM,
776809
.sw_num = 0x08,
777-
778810
.prox_mask = BIT(0),
779811
.sar_mask = BIT(1) | BIT(7),
780812
.hall_mask = BIT(2),
781813
.hyst_mask = BIT(3),
782814
.temp_mask = BIT(4),
783-
784815
.prox_settings = IQS620_PROX_SETTINGS_4,
785816
.hall_flags = IQS620_HALL_FLAGS,
786-
787-
.clk_div = 4,
788817
.fw_name = "iqs620a.bin",
789818
.event_regs = &iqs620a_event_regs[IQS62X_UI_PROX],
790819
},
791820
{
792821
.dev_name = "iqs621",
793822
.sub_devs = iqs621_sub_devs,
794823
.num_sub_devs = ARRAY_SIZE(iqs621_sub_devs),
795-
796824
.prod_num = IQS621_PROD_NUM,
797825
.sw_num = 0x09,
798826
.cal_regs = iqs621_cal_regs,
799827
.num_cal_regs = ARRAY_SIZE(iqs621_cal_regs),
800-
801828
.prox_mask = BIT(0),
802829
.hall_mask = BIT(1),
803830
.als_mask = BIT(2),
804831
.hyst_mask = BIT(3),
805832
.temp_mask = BIT(4),
806-
807833
.als_flags = IQS621_ALS_FLAGS,
808834
.hall_flags = IQS621_HALL_FLAGS,
809835
.hyst_shift = 5,
810-
811-
.clk_div = 2,
812836
.fw_name = "iqs621.bin",
813837
.event_regs = &iqs621_event_regs[IQS62X_UI_PROX],
814838
},
815839
{
816840
.dev_name = "iqs622",
817841
.sub_devs = iqs622_sub_devs,
818842
.num_sub_devs = ARRAY_SIZE(iqs622_sub_devs),
819-
820843
.prod_num = IQS622_PROD_NUM,
821844
.sw_num = 0x06,
822-
823845
.prox_mask = BIT(0),
824846
.sar_mask = BIT(1),
825847
.hall_mask = BIT(2),
826848
.als_mask = BIT(3),
827849
.ir_mask = BIT(4),
828-
829850
.prox_settings = IQS622_PROX_SETTINGS_4,
830851
.als_flags = IQS622_ALS_FLAGS,
831852
.hall_flags = IQS622_HALL_FLAGS,
832-
833-
.clk_div = 2,
834853
.fw_name = "iqs622.bin",
835854
.event_regs = &iqs622_event_regs[IQS62X_UI_PROX],
836855
},
837856
{
838857
.dev_name = "iqs624",
839858
.sub_devs = iqs624_sub_devs,
840859
.num_sub_devs = ARRAY_SIZE(iqs624_sub_devs),
841-
842860
.prod_num = IQS624_PROD_NUM,
843861
.sw_num = 0x0B,
844-
845862
.interval = IQS624_INTERVAL_NUM,
846863
.interval_div = 3,
847-
848-
.clk_div = 2,
849864
.fw_name = "iqs624.bin",
850865
.event_regs = &iqs624_event_regs[IQS62X_UI_PROX],
851866
},
852867
{
853868
.dev_name = "iqs625",
854869
.sub_devs = iqs625_sub_devs,
855870
.num_sub_devs = ARRAY_SIZE(iqs625_sub_devs),
856-
857871
.prod_num = IQS625_PROD_NUM,
858872
.sw_num = 0x0B,
859-
860873
.interval = IQS625_INTERVAL_NUM,
861874
.interval_div = 10,
862-
863-
.clk_div = 2,
864875
.fw_name = "iqs625.bin",
865876
.event_regs = &iqs625_event_regs[IQS62X_UI_PROX],
866877
},
@@ -890,6 +901,8 @@ static int iqs62x_probe(struct i2c_client *client)
890901

891902
BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh);
892903
INIT_LIST_HEAD(&iqs62x->fw_blk_head);
904+
905+
init_completion(&iqs62x->ati_done);
893906
init_completion(&iqs62x->fw_done);
894907

895908
iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config);

include/linux/mfd/iqs62x.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#define IQS620_GLBL_EVENT_MASK_PMU BIT(6)
2929

3030
#define IQS62X_NUM_KEYS 16
31-
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 5)
31+
#define IQS62X_NUM_EVENTS (IQS62X_NUM_KEYS + 6)
3232

3333
#define IQS62X_EVENT_SIZE 10
3434

@@ -78,6 +78,7 @@ enum iqs62x_event_flag {
7878

7979
/* everything else */
8080
IQS62X_EVENT_SYS_RESET,
81+
IQS62X_EVENT_SYS_ATI,
8182
};
8283

8384
struct iqs62x_event_data {
@@ -97,29 +98,23 @@ struct iqs62x_dev_desc {
9798
const char *dev_name;
9899
const struct mfd_cell *sub_devs;
99100
int num_sub_devs;
100-
101101
u8 prod_num;
102102
u8 sw_num;
103103
const u8 *cal_regs;
104104
int num_cal_regs;
105-
106105
u8 prox_mask;
107106
u8 sar_mask;
108107
u8 hall_mask;
109108
u8 hyst_mask;
110109
u8 temp_mask;
111110
u8 als_mask;
112111
u8 ir_mask;
113-
114112
u8 prox_settings;
115113
u8 als_flags;
116114
u8 hall_flags;
117115
u8 hyst_shift;
118-
119116
u8 interval;
120117
u8 interval_div;
121-
122-
u8 clk_div;
123118
const char *fw_name;
124119
const enum iqs62x_event_reg (*event_regs)[IQS62X_EVENT_SIZE];
125120
};
@@ -130,8 +125,10 @@ struct iqs62x_core {
130125
struct regmap *regmap;
131126
struct blocking_notifier_head nh;
132127
struct list_head fw_blk_head;
128+
struct completion ati_done;
133129
struct completion fw_done;
134130
enum iqs62x_ui_sel ui_sel;
131+
unsigned long event_cache;
135132
};
136133

137134
extern const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS];

0 commit comments

Comments
 (0)