|
36 | 36 | #define IQS62X_PROD_NUM 0x00 |
37 | 37 |
|
38 | 38 | #define IQS62X_SYS_FLAGS 0x10 |
39 | | -#define IQS62X_SYS_FLAGS_IN_ATI BIT(2) |
40 | 39 |
|
41 | 40 | #define IQS620_HALL_FLAGS 0x16 |
42 | 41 | #define IQS621_HALL_FLAGS 0x19 |
|
60 | 59 | #define IQS62X_SYS_SETTINGS_ACK_RESET BIT(6) |
61 | 60 | #define IQS62X_SYS_SETTINGS_EVENT_MODE BIT(5) |
62 | 61 | #define IQS62X_SYS_SETTINGS_CLK_DIV BIT(4) |
| 62 | +#define IQS62X_SYS_SETTINGS_COMM_ATI BIT(3) |
63 | 63 | #define IQS62X_SYS_SETTINGS_REDO_ATI BIT(1) |
64 | 64 |
|
65 | 65 | #define IQS62X_PWR_SETTINGS 0xD2 |
|
81 | 81 | #define IQS62X_FW_REC_TYPE_MASK 3 |
82 | 82 | #define IQS62X_FW_REC_TYPE_DATA 4 |
83 | 83 |
|
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 |
87 | 85 |
|
88 | 86 | struct iqs62x_fw_rec { |
89 | 87 | u8 type; |
@@ -111,7 +109,6 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x) |
111 | 109 | struct iqs62x_fw_blk *fw_blk; |
112 | 110 | unsigned int val; |
113 | 111 | int ret; |
114 | | - u8 clk_div = 1; |
115 | 112 |
|
116 | 113 | list_for_each_entry(fw_blk, &iqs62x->fw_blk_head, list) { |
117 | 114 | if (fw_blk->mask) |
@@ -181,28 +178,32 @@ static int iqs62x_dev_init(struct iqs62x_core *iqs62x) |
181 | 178 | return ret; |
182 | 179 | } |
183 | 180 |
|
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); |
202 | 198 | if (ret) |
203 | 199 | return ret; |
204 | 200 |
|
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); |
206 | 207 |
|
207 | 208 | return 0; |
208 | 209 | } |
@@ -433,6 +434,11 @@ const struct iqs62x_event_desc iqs62x_events[IQS62X_NUM_EVENTS] = { |
433 | 434 | .mask = BIT(7), |
434 | 435 | .val = BIT(7), |
435 | 436 | }, |
| 437 | + [IQS62X_EVENT_SYS_ATI] = { |
| 438 | + .reg = IQS62X_EVENT_SYS, |
| 439 | + .mask = BIT(2), |
| 440 | + .val = BIT(2), |
| 441 | + }, |
436 | 442 | }; |
437 | 443 | EXPORT_SYMBOL_GPL(iqs62x_events); |
438 | 444 |
|
@@ -521,12 +527,39 @@ static irqreturn_t iqs62x_irq(int irq, void *context) |
521 | 527 | "Failed to re-initialize device: %d\n", ret); |
522 | 528 | return IRQ_NONE; |
523 | 529 | } |
| 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); |
524 | 547 | } |
525 | 548 |
|
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 | + } |
530 | 563 |
|
531 | 564 | /* |
532 | 565 | * 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) |
567 | 600 | goto err_out; |
568 | 601 | } |
569 | 602 |
|
| 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 | + |
570 | 609 | ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE, |
571 | 610 | iqs62x->dev_desc->sub_devs, |
572 | 611 | iqs62x->dev_desc->num_sub_devs, |
@@ -748,119 +787,91 @@ static const struct iqs62x_dev_desc iqs62x_devs[] = { |
748 | 787 | .dev_name = "iqs620at", |
749 | 788 | .sub_devs = iqs620at_sub_devs, |
750 | 789 | .num_sub_devs = ARRAY_SIZE(iqs620at_sub_devs), |
751 | | - |
752 | 790 | .prod_num = IQS620_PROD_NUM, |
753 | 791 | .sw_num = 0x08, |
754 | 792 | .cal_regs = iqs620at_cal_regs, |
755 | 793 | .num_cal_regs = ARRAY_SIZE(iqs620at_cal_regs), |
756 | | - |
757 | 794 | .prox_mask = BIT(0), |
758 | 795 | .sar_mask = BIT(1) | BIT(7), |
759 | 796 | .hall_mask = BIT(2), |
760 | 797 | .hyst_mask = BIT(3), |
761 | 798 | .temp_mask = BIT(4), |
762 | | - |
763 | 799 | .prox_settings = IQS620_PROX_SETTINGS_4, |
764 | 800 | .hall_flags = IQS620_HALL_FLAGS, |
765 | | - |
766 | | - .clk_div = 4, |
767 | 801 | .fw_name = "iqs620a.bin", |
768 | 802 | .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX], |
769 | 803 | }, |
770 | 804 | { |
771 | 805 | .dev_name = "iqs620a", |
772 | 806 | .sub_devs = iqs620a_sub_devs, |
773 | 807 | .num_sub_devs = ARRAY_SIZE(iqs620a_sub_devs), |
774 | | - |
775 | 808 | .prod_num = IQS620_PROD_NUM, |
776 | 809 | .sw_num = 0x08, |
777 | | - |
778 | 810 | .prox_mask = BIT(0), |
779 | 811 | .sar_mask = BIT(1) | BIT(7), |
780 | 812 | .hall_mask = BIT(2), |
781 | 813 | .hyst_mask = BIT(3), |
782 | 814 | .temp_mask = BIT(4), |
783 | | - |
784 | 815 | .prox_settings = IQS620_PROX_SETTINGS_4, |
785 | 816 | .hall_flags = IQS620_HALL_FLAGS, |
786 | | - |
787 | | - .clk_div = 4, |
788 | 817 | .fw_name = "iqs620a.bin", |
789 | 818 | .event_regs = &iqs620a_event_regs[IQS62X_UI_PROX], |
790 | 819 | }, |
791 | 820 | { |
792 | 821 | .dev_name = "iqs621", |
793 | 822 | .sub_devs = iqs621_sub_devs, |
794 | 823 | .num_sub_devs = ARRAY_SIZE(iqs621_sub_devs), |
795 | | - |
796 | 824 | .prod_num = IQS621_PROD_NUM, |
797 | 825 | .sw_num = 0x09, |
798 | 826 | .cal_regs = iqs621_cal_regs, |
799 | 827 | .num_cal_regs = ARRAY_SIZE(iqs621_cal_regs), |
800 | | - |
801 | 828 | .prox_mask = BIT(0), |
802 | 829 | .hall_mask = BIT(1), |
803 | 830 | .als_mask = BIT(2), |
804 | 831 | .hyst_mask = BIT(3), |
805 | 832 | .temp_mask = BIT(4), |
806 | | - |
807 | 833 | .als_flags = IQS621_ALS_FLAGS, |
808 | 834 | .hall_flags = IQS621_HALL_FLAGS, |
809 | 835 | .hyst_shift = 5, |
810 | | - |
811 | | - .clk_div = 2, |
812 | 836 | .fw_name = "iqs621.bin", |
813 | 837 | .event_regs = &iqs621_event_regs[IQS62X_UI_PROX], |
814 | 838 | }, |
815 | 839 | { |
816 | 840 | .dev_name = "iqs622", |
817 | 841 | .sub_devs = iqs622_sub_devs, |
818 | 842 | .num_sub_devs = ARRAY_SIZE(iqs622_sub_devs), |
819 | | - |
820 | 843 | .prod_num = IQS622_PROD_NUM, |
821 | 844 | .sw_num = 0x06, |
822 | | - |
823 | 845 | .prox_mask = BIT(0), |
824 | 846 | .sar_mask = BIT(1), |
825 | 847 | .hall_mask = BIT(2), |
826 | 848 | .als_mask = BIT(3), |
827 | 849 | .ir_mask = BIT(4), |
828 | | - |
829 | 850 | .prox_settings = IQS622_PROX_SETTINGS_4, |
830 | 851 | .als_flags = IQS622_ALS_FLAGS, |
831 | 852 | .hall_flags = IQS622_HALL_FLAGS, |
832 | | - |
833 | | - .clk_div = 2, |
834 | 853 | .fw_name = "iqs622.bin", |
835 | 854 | .event_regs = &iqs622_event_regs[IQS62X_UI_PROX], |
836 | 855 | }, |
837 | 856 | { |
838 | 857 | .dev_name = "iqs624", |
839 | 858 | .sub_devs = iqs624_sub_devs, |
840 | 859 | .num_sub_devs = ARRAY_SIZE(iqs624_sub_devs), |
841 | | - |
842 | 860 | .prod_num = IQS624_PROD_NUM, |
843 | 861 | .sw_num = 0x0B, |
844 | | - |
845 | 862 | .interval = IQS624_INTERVAL_NUM, |
846 | 863 | .interval_div = 3, |
847 | | - |
848 | | - .clk_div = 2, |
849 | 864 | .fw_name = "iqs624.bin", |
850 | 865 | .event_regs = &iqs624_event_regs[IQS62X_UI_PROX], |
851 | 866 | }, |
852 | 867 | { |
853 | 868 | .dev_name = "iqs625", |
854 | 869 | .sub_devs = iqs625_sub_devs, |
855 | 870 | .num_sub_devs = ARRAY_SIZE(iqs625_sub_devs), |
856 | | - |
857 | 871 | .prod_num = IQS625_PROD_NUM, |
858 | 872 | .sw_num = 0x0B, |
859 | | - |
860 | 873 | .interval = IQS625_INTERVAL_NUM, |
861 | 874 | .interval_div = 10, |
862 | | - |
863 | | - .clk_div = 2, |
864 | 875 | .fw_name = "iqs625.bin", |
865 | 876 | .event_regs = &iqs625_event_regs[IQS62X_UI_PROX], |
866 | 877 | }, |
@@ -890,6 +901,8 @@ static int iqs62x_probe(struct i2c_client *client) |
890 | 901 |
|
891 | 902 | BLOCKING_INIT_NOTIFIER_HEAD(&iqs62x->nh); |
892 | 903 | INIT_LIST_HEAD(&iqs62x->fw_blk_head); |
| 904 | + |
| 905 | + init_completion(&iqs62x->ati_done); |
893 | 906 | init_completion(&iqs62x->fw_done); |
894 | 907 |
|
895 | 908 | iqs62x->regmap = devm_regmap_init_i2c(client, &iqs62x_regmap_config); |
|
0 commit comments