9
9
#include <linux/interrupt.h>
10
10
#include <linux/irqreturn.h>
11
11
#include <linux/pci.h>
12
+ #include <linux/pm_runtime.h>
12
13
13
14
#include "intel-thc-dev.h"
14
15
#include "intel-thc-hw.h"
@@ -281,6 +282,10 @@ static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id)
281
282
if (qsdev -> state == QUICKSPI_DISABLED )
282
283
return IRQ_HANDLED ;
283
284
285
+ ret = pm_runtime_resume_and_get (qsdev -> dev );
286
+ if (ret )
287
+ return IRQ_HANDLED ;
288
+
284
289
int_mask = thc_interrupt_handler (qsdev -> thc_hw );
285
290
286
291
if (int_mask & BIT (THC_FATAL_ERR_INT ) || int_mask & BIT (THC_TXN_ERR_INT )) {
@@ -318,6 +323,9 @@ static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id)
318
323
if (try_recover (qsdev ))
319
324
qsdev -> state = QUICKSPI_DISABLED ;
320
325
326
+ pm_runtime_mark_last_busy (qsdev -> dev );
327
+ pm_runtime_put_autosuspend (qsdev -> dev );
328
+
321
329
return IRQ_HANDLED ;
322
330
}
323
331
@@ -645,6 +653,13 @@ static int quickspi_probe(struct pci_dev *pdev,
645
653
646
654
qsdev -> state = QUICKSPI_ENABLED ;
647
655
656
+ /* Enable runtime power management */
657
+ pm_runtime_use_autosuspend (qsdev -> dev );
658
+ pm_runtime_set_autosuspend_delay (qsdev -> dev , DEFAULT_AUTO_SUSPEND_DELAY_MS );
659
+ pm_runtime_mark_last_busy (qsdev -> dev );
660
+ pm_runtime_put_noidle (qsdev -> dev );
661
+ pm_runtime_put_autosuspend (qsdev -> dev );
662
+
648
663
dev_dbg (& pdev -> dev , "QuickSPI probe success\n" );
649
664
650
665
return 0 ;
@@ -680,6 +695,8 @@ static void quickspi_remove(struct pci_dev *pdev)
680
695
quickspi_hid_remove (qsdev );
681
696
quickspi_dma_deinit (qsdev );
682
697
698
+ pm_runtime_get_noresume (qsdev -> dev );
699
+
683
700
quickspi_dev_deinit (qsdev );
684
701
685
702
pcim_iounmap_regions (pdev , BIT (0 ));
@@ -709,6 +726,234 @@ static void quickspi_shutdown(struct pci_dev *pdev)
709
726
quickspi_dev_deinit (qsdev );
710
727
}
711
728
729
+ static int quickspi_suspend (struct device * device )
730
+ {
731
+ struct pci_dev * pdev = to_pci_dev (device );
732
+ struct quickspi_device * qsdev ;
733
+ int ret ;
734
+
735
+ qsdev = pci_get_drvdata (pdev );
736
+ if (!qsdev )
737
+ return - ENODEV ;
738
+
739
+ ret = quickspi_set_power (qsdev , HIDSPI_SLEEP );
740
+ if (ret )
741
+ return ret ;
742
+
743
+ ret = thc_interrupt_quiesce (qsdev -> thc_hw , true);
744
+ if (ret )
745
+ return ret ;
746
+
747
+ thc_interrupt_enable (qsdev -> thc_hw , false);
748
+
749
+ thc_dma_unconfigure (qsdev -> thc_hw );
750
+
751
+ return 0 ;
752
+ }
753
+
754
+ static int quickspi_resume (struct device * device )
755
+ {
756
+ struct pci_dev * pdev = to_pci_dev (device );
757
+ struct quickspi_device * qsdev ;
758
+ int ret ;
759
+
760
+ qsdev = pci_get_drvdata (pdev );
761
+ if (!qsdev )
762
+ return - ENODEV ;
763
+
764
+ ret = thc_port_select (qsdev -> thc_hw , THC_PORT_TYPE_SPI );
765
+ if (ret )
766
+ return ret ;
767
+
768
+ thc_interrupt_config (qsdev -> thc_hw );
769
+
770
+ thc_interrupt_enable (qsdev -> thc_hw , true);
771
+
772
+ ret = thc_dma_configure (qsdev -> thc_hw );
773
+ if (ret )
774
+ return ret ;
775
+
776
+ ret = thc_interrupt_quiesce (qsdev -> thc_hw , false);
777
+ if (ret )
778
+ return ret ;
779
+
780
+ ret = quickspi_set_power (qsdev , HIDSPI_ON );
781
+ if (ret )
782
+ return ret ;
783
+
784
+ return 0 ;
785
+ }
786
+
787
+ static int quickspi_freeze (struct device * device )
788
+ {
789
+ struct pci_dev * pdev = to_pci_dev (device );
790
+ struct quickspi_device * qsdev ;
791
+ int ret ;
792
+
793
+ qsdev = pci_get_drvdata (pdev );
794
+ if (!qsdev )
795
+ return - ENODEV ;
796
+
797
+ ret = thc_interrupt_quiesce (qsdev -> thc_hw , true);
798
+ if (ret )
799
+ return ret ;
800
+
801
+ thc_interrupt_enable (qsdev -> thc_hw , false);
802
+
803
+ thc_dma_unconfigure (qsdev -> thc_hw );
804
+
805
+ return 0 ;
806
+ }
807
+
808
+ static int quickspi_thaw (struct device * device )
809
+ {
810
+ struct pci_dev * pdev = to_pci_dev (device );
811
+ struct quickspi_device * qsdev ;
812
+ int ret ;
813
+
814
+ qsdev = pci_get_drvdata (pdev );
815
+ if (!qsdev )
816
+ return - ENODEV ;
817
+
818
+ ret = thc_dma_configure (qsdev -> thc_hw );
819
+ if (ret )
820
+ return ret ;
821
+
822
+ thc_interrupt_enable (qsdev -> thc_hw , true);
823
+
824
+ ret = thc_interrupt_quiesce (qsdev -> thc_hw , false);
825
+ if (ret )
826
+ return ret ;
827
+
828
+ return 0 ;
829
+ }
830
+
831
+ static int quickspi_poweroff (struct device * device )
832
+ {
833
+ struct pci_dev * pdev = to_pci_dev (device );
834
+ struct quickspi_device * qsdev ;
835
+ int ret ;
836
+
837
+ qsdev = pci_get_drvdata (pdev );
838
+ if (!qsdev )
839
+ return - ENODEV ;
840
+
841
+ ret = thc_interrupt_quiesce (qsdev -> thc_hw , true);
842
+ if (ret )
843
+ return ret ;
844
+
845
+ thc_interrupt_enable (qsdev -> thc_hw , false);
846
+
847
+ thc_ltr_unconfig (qsdev -> thc_hw );
848
+
849
+ quickspi_dma_deinit (qsdev );
850
+
851
+ return 0 ;
852
+ }
853
+
854
+ static int quickspi_restore (struct device * device )
855
+ {
856
+ struct pci_dev * pdev = to_pci_dev (device );
857
+ struct quickspi_device * qsdev ;
858
+ int ret ;
859
+
860
+ qsdev = pci_get_drvdata (pdev );
861
+ if (!qsdev )
862
+ return - ENODEV ;
863
+
864
+ ret = thc_interrupt_quiesce (qsdev -> thc_hw , true);
865
+ if (ret )
866
+ return ret ;
867
+
868
+ /* Reconfig THC HW when back from hibernate */
869
+ ret = thc_port_select (qsdev -> thc_hw , THC_PORT_TYPE_SPI );
870
+ if (ret )
871
+ return ret ;
872
+
873
+ thc_spi_input_output_address_config (qsdev -> thc_hw ,
874
+ qsdev -> input_report_hdr_addr ,
875
+ qsdev -> input_report_bdy_addr ,
876
+ qsdev -> output_report_addr );
877
+
878
+ ret = thc_spi_read_config (qsdev -> thc_hw , qsdev -> spi_freq_val ,
879
+ qsdev -> spi_read_io_mode ,
880
+ qsdev -> spi_read_opcode ,
881
+ qsdev -> spi_packet_size );
882
+ if (ret )
883
+ return ret ;
884
+
885
+ ret = thc_spi_write_config (qsdev -> thc_hw , qsdev -> spi_freq_val ,
886
+ qsdev -> spi_write_io_mode ,
887
+ qsdev -> spi_write_opcode ,
888
+ qsdev -> spi_packet_size ,
889
+ qsdev -> performance_limit );
890
+ if (ret )
891
+ return ret ;
892
+
893
+ thc_interrupt_config (qsdev -> thc_hw );
894
+
895
+ thc_interrupt_enable (qsdev -> thc_hw , true);
896
+
897
+ /* TIC may lose power, needs go through reset flow */
898
+ ret = reset_tic (qsdev );
899
+ if (ret )
900
+ return ret ;
901
+
902
+ ret = thc_dma_configure (qsdev -> thc_hw );
903
+ if (ret )
904
+ return ret ;
905
+
906
+ thc_ltr_config (qsdev -> thc_hw ,
907
+ qsdev -> active_ltr_val ,
908
+ qsdev -> low_power_ltr_val );
909
+
910
+ thc_change_ltr_mode (qsdev -> thc_hw , THC_LTR_MODE_ACTIVE );
911
+
912
+ return 0 ;
913
+ }
914
+
915
+ static int quickspi_runtime_suspend (struct device * device )
916
+ {
917
+ struct pci_dev * pdev = to_pci_dev (device );
918
+ struct quickspi_device * qsdev ;
919
+
920
+ qsdev = pci_get_drvdata (pdev );
921
+ if (!qsdev )
922
+ return - ENODEV ;
923
+
924
+ thc_change_ltr_mode (qsdev -> thc_hw , THC_LTR_MODE_LP );
925
+
926
+ pci_save_state (pdev );
927
+
928
+ return 0 ;
929
+ }
930
+
931
+ static int quickspi_runtime_resume (struct device * device )
932
+ {
933
+ struct pci_dev * pdev = to_pci_dev (device );
934
+ struct quickspi_device * qsdev ;
935
+
936
+ qsdev = pci_get_drvdata (pdev );
937
+ if (!qsdev )
938
+ return - ENODEV ;
939
+
940
+ thc_change_ltr_mode (qsdev -> thc_hw , THC_LTR_MODE_ACTIVE );
941
+
942
+ return 0 ;
943
+ }
944
+
945
+ static const struct dev_pm_ops quickspi_pm_ops = {
946
+ .suspend = quickspi_suspend ,
947
+ .resume = quickspi_resume ,
948
+ .freeze = quickspi_freeze ,
949
+ .thaw = quickspi_thaw ,
950
+ .poweroff = quickspi_poweroff ,
951
+ .restore = quickspi_restore ,
952
+ .runtime_suspend = quickspi_runtime_suspend ,
953
+ .runtime_resume = quickspi_runtime_resume ,
954
+ .runtime_idle = NULL ,
955
+ };
956
+
712
957
static const struct pci_device_id quickspi_pci_tbl [] = {
713
958
{PCI_DEVICE_DATA (INTEL , THC_MTL_DEVICE_ID_SPI_PORT1 , & mtl ), },
714
959
{PCI_DEVICE_DATA (INTEL , THC_MTL_DEVICE_ID_SPI_PORT2 , & mtl ), },
@@ -728,6 +973,7 @@ static struct pci_driver quickspi_driver = {
728
973
.probe = quickspi_probe ,
729
974
.remove = quickspi_remove ,
730
975
.shutdown = quickspi_shutdown ,
976
+ .driver .pm = & quickspi_pm_ops ,
731
977
.driver .probe_type = PROBE_PREFER_ASYNCHRONOUS ,
732
978
};
733
979
0 commit comments