9
9
#include <linux/irqreturn.h>
10
10
#include <linux/pci.h>
11
11
#include <linux/sizes.h>
12
+ #include <linux/pm_runtime.h>
12
13
13
14
#include "intel-thc-dev.h"
14
15
#include "intel-thc-hw.h"
@@ -289,10 +290,15 @@ static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id)
289
290
struct quicki2c_device * qcdev = dev_id ;
290
291
int err_recover = 0 ;
291
292
int int_mask ;
293
+ int ret ;
292
294
293
295
if (qcdev -> state == QUICKI2C_DISABLED )
294
296
return IRQ_HANDLED ;
295
297
298
+ ret = pm_runtime_resume_and_get (qcdev -> dev );
299
+ if (ret )
300
+ return IRQ_HANDLED ;
301
+
296
302
int_mask = thc_interrupt_handler (qcdev -> thc_hw );
297
303
298
304
if (int_mask & BIT (THC_FATAL_ERR_INT ) || int_mask & BIT (THC_TXN_ERR_INT ) ||
@@ -314,6 +320,9 @@ static irqreturn_t quicki2c_irq_thread_handler(int irq, void *dev_id)
314
320
if (try_recover (qcdev ))
315
321
qcdev -> state = QUICKI2C_DISABLED ;
316
322
323
+ pm_runtime_mark_last_busy (qcdev -> dev );
324
+ pm_runtime_put_autosuspend (qcdev -> dev );
325
+
317
326
return IRQ_HANDLED ;
318
327
}
319
328
@@ -639,6 +648,13 @@ static int quicki2c_probe(struct pci_dev *pdev,
639
648
640
649
qcdev -> state = QUICKI2C_ENABLED ;
641
650
651
+ /* Enable runtime power management */
652
+ pm_runtime_use_autosuspend (qcdev -> dev );
653
+ pm_runtime_set_autosuspend_delay (qcdev -> dev , DEFAULT_AUTO_SUSPEND_DELAY_MS );
654
+ pm_runtime_mark_last_busy (qcdev -> dev );
655
+ pm_runtime_put_noidle (qcdev -> dev );
656
+ pm_runtime_put_autosuspend (qcdev -> dev );
657
+
642
658
dev_dbg (& pdev -> dev , "QuickI2C probe success\n" );
643
659
644
660
return 0 ;
@@ -674,6 +690,8 @@ static void quicki2c_remove(struct pci_dev *pdev)
674
690
quicki2c_hid_remove (qcdev );
675
691
quicki2c_dma_deinit (qcdev );
676
692
693
+ pm_runtime_get_noresume (qcdev -> dev );
694
+
677
695
quicki2c_dev_deinit (qcdev );
678
696
679
697
pcim_iounmap_regions (pdev , BIT (0 ));
@@ -703,6 +721,220 @@ static void quicki2c_shutdown(struct pci_dev *pdev)
703
721
quicki2c_dev_deinit (qcdev );
704
722
}
705
723
724
+ static int quicki2c_suspend (struct device * device )
725
+ {
726
+ struct pci_dev * pdev = to_pci_dev (device );
727
+ struct quicki2c_device * qcdev ;
728
+ int ret ;
729
+
730
+ qcdev = pci_get_drvdata (pdev );
731
+ if (!qcdev )
732
+ return - ENODEV ;
733
+
734
+ /*
735
+ * As I2C is THC subsystem, no register auto save/restore support,
736
+ * need driver to do that explicitly for every D3 case.
737
+ */
738
+ ret = thc_i2c_subip_regs_save (qcdev -> thc_hw );
739
+ if (ret )
740
+ return ret ;
741
+
742
+ ret = thc_interrupt_quiesce (qcdev -> thc_hw , true);
743
+ if (ret )
744
+ return ret ;
745
+
746
+ thc_interrupt_enable (qcdev -> thc_hw , false);
747
+
748
+ thc_dma_unconfigure (qcdev -> thc_hw );
749
+
750
+ return 0 ;
751
+ }
752
+
753
+ static int quicki2c_resume (struct device * device )
754
+ {
755
+ struct pci_dev * pdev = to_pci_dev (device );
756
+ struct quicki2c_device * qcdev ;
757
+ int ret ;
758
+
759
+ qcdev = pci_get_drvdata (pdev );
760
+ if (!qcdev )
761
+ return - ENODEV ;
762
+
763
+ ret = thc_port_select (qcdev -> thc_hw , THC_PORT_TYPE_I2C );
764
+ if (ret )
765
+ return ret ;
766
+
767
+ ret = thc_i2c_subip_regs_restore (qcdev -> thc_hw );
768
+ if (ret )
769
+ return ret ;
770
+
771
+ thc_interrupt_config (qcdev -> thc_hw );
772
+
773
+ thc_interrupt_enable (qcdev -> thc_hw , true);
774
+
775
+ ret = thc_dma_configure (qcdev -> thc_hw );
776
+ if (ret )
777
+ return ret ;
778
+
779
+ ret = thc_interrupt_quiesce (qcdev -> thc_hw , false);
780
+ if (ret )
781
+ return ret ;
782
+
783
+ return 0 ;
784
+ }
785
+
786
+ static int quicki2c_freeze (struct device * device )
787
+ {
788
+ struct pci_dev * pdev = to_pci_dev (device );
789
+ struct quicki2c_device * qcdev ;
790
+ int ret ;
791
+
792
+ qcdev = pci_get_drvdata (pdev );
793
+ if (!qcdev )
794
+ return - ENODEV ;
795
+
796
+ ret = thc_interrupt_quiesce (qcdev -> thc_hw , true);
797
+ if (ret )
798
+ return ret ;
799
+
800
+ thc_interrupt_enable (qcdev -> thc_hw , false);
801
+
802
+ thc_dma_unconfigure (qcdev -> thc_hw );
803
+
804
+ return 0 ;
805
+ }
806
+
807
+ static int quicki2c_thaw (struct device * device )
808
+ {
809
+ struct pci_dev * pdev = to_pci_dev (device );
810
+ struct quicki2c_device * qcdev ;
811
+ int ret ;
812
+
813
+ qcdev = pci_get_drvdata (pdev );
814
+ if (!qcdev )
815
+ return - ENODEV ;
816
+
817
+ ret = thc_dma_configure (qcdev -> thc_hw );
818
+ if (ret )
819
+ return ret ;
820
+
821
+ thc_interrupt_enable (qcdev -> thc_hw , true);
822
+
823
+ ret = thc_interrupt_quiesce (qcdev -> thc_hw , false);
824
+ if (ret )
825
+ return ret ;
826
+
827
+ return 0 ;
828
+ }
829
+
830
+ static int quicki2c_poweroff (struct device * device )
831
+ {
832
+ struct pci_dev * pdev = to_pci_dev (device );
833
+ struct quicki2c_device * qcdev ;
834
+ int ret ;
835
+
836
+ qcdev = pci_get_drvdata (pdev );
837
+ if (!qcdev )
838
+ return - ENODEV ;
839
+
840
+ ret = thc_interrupt_quiesce (qcdev -> thc_hw , true);
841
+ if (ret )
842
+ return ret ;
843
+
844
+ thc_interrupt_enable (qcdev -> thc_hw , false);
845
+
846
+ thc_ltr_unconfig (qcdev -> thc_hw );
847
+
848
+ quicki2c_dma_deinit (qcdev );
849
+
850
+ return 0 ;
851
+ }
852
+
853
+ static int quicki2c_restore (struct device * device )
854
+ {
855
+ struct pci_dev * pdev = to_pci_dev (device );
856
+ struct quicki2c_device * qcdev ;
857
+ int ret ;
858
+
859
+ qcdev = pci_get_drvdata (pdev );
860
+ if (!qcdev )
861
+ return - ENODEV ;
862
+
863
+ /* Reconfig THC HW when back from hibernate */
864
+ ret = thc_port_select (qcdev -> thc_hw , THC_PORT_TYPE_I2C );
865
+ if (ret )
866
+ return ret ;
867
+
868
+ ret = thc_i2c_subip_init (qcdev -> thc_hw , qcdev -> i2c_slave_addr ,
869
+ qcdev -> i2c_speed_mode ,
870
+ qcdev -> i2c_clock_hcnt ,
871
+ qcdev -> i2c_clock_lcnt );
872
+ if (ret )
873
+ return ret ;
874
+
875
+ thc_interrupt_config (qcdev -> thc_hw );
876
+
877
+ thc_interrupt_enable (qcdev -> thc_hw , true);
878
+
879
+ ret = thc_interrupt_quiesce (qcdev -> thc_hw , false);
880
+ if (ret )
881
+ return ret ;
882
+
883
+ ret = thc_dma_configure (qcdev -> thc_hw );
884
+ if (ret )
885
+ return ret ;
886
+
887
+ thc_ltr_config (qcdev -> thc_hw ,
888
+ qcdev -> active_ltr_val ,
889
+ qcdev -> low_power_ltr_val );
890
+
891
+ thc_change_ltr_mode (qcdev -> thc_hw , THC_LTR_MODE_ACTIVE );
892
+
893
+ return 0 ;
894
+ }
895
+
896
+ static int quicki2c_runtime_suspend (struct device * device )
897
+ {
898
+ struct pci_dev * pdev = to_pci_dev (device );
899
+ struct quicki2c_device * qcdev ;
900
+
901
+ qcdev = pci_get_drvdata (pdev );
902
+ if (!qcdev )
903
+ return - ENODEV ;
904
+
905
+ thc_change_ltr_mode (qcdev -> thc_hw , THC_LTR_MODE_LP );
906
+
907
+ pci_save_state (pdev );
908
+
909
+ return 0 ;
910
+ }
911
+
912
+ static int quicki2c_runtime_resume (struct device * device )
913
+ {
914
+ struct pci_dev * pdev = to_pci_dev (device );
915
+ struct quicki2c_device * qcdev ;
916
+
917
+ qcdev = pci_get_drvdata (pdev );
918
+ if (!qcdev )
919
+ return - ENODEV ;
920
+
921
+ thc_change_ltr_mode (qcdev -> thc_hw , THC_LTR_MODE_ACTIVE );
922
+
923
+ return 0 ;
924
+ }
925
+
926
+ static const struct dev_pm_ops quicki2c_pm_ops = {
927
+ .suspend = quicki2c_suspend ,
928
+ .resume = quicki2c_resume ,
929
+ .freeze = quicki2c_freeze ,
930
+ .thaw = quicki2c_thaw ,
931
+ .poweroff = quicki2c_poweroff ,
932
+ .restore = quicki2c_restore ,
933
+ .runtime_suspend = quicki2c_runtime_suspend ,
934
+ .runtime_resume = quicki2c_runtime_resume ,
935
+ .runtime_idle = NULL ,
936
+ };
937
+
706
938
static const struct pci_device_id quicki2c_pci_tbl [] = {
707
939
{PCI_VDEVICE (INTEL , THC_LNL_DEVICE_ID_I2C_PORT1 ), },
708
940
{PCI_VDEVICE (INTEL , THC_LNL_DEVICE_ID_I2C_PORT2 ), },
@@ -720,6 +952,7 @@ static struct pci_driver quicki2c_driver = {
720
952
.probe = quicki2c_probe ,
721
953
.remove = quicki2c_remove ,
722
954
.shutdown = quicki2c_shutdown ,
955
+ .driver .pm = & quicki2c_pm_ops ,
723
956
.driver .probe_type = PROBE_PREFER_ASYNCHRONOUS ,
724
957
};
725
958
0 commit comments