99#include <linux/interrupt.h>
1010#include <linux/irqreturn.h>
1111#include <linux/pci.h>
12+ #include <linux/pm_runtime.h>
1213
1314#include "intel-thc-dev.h"
1415#include "intel-thc-hw.h"
@@ -281,6 +282,10 @@ static irqreturn_t quickspi_irq_thread_handler(int irq, void *dev_id)
281282 if (qsdev -> state == QUICKSPI_DISABLED )
282283 return IRQ_HANDLED ;
283284
285+ ret = pm_runtime_resume_and_get (qsdev -> dev );
286+ if (ret )
287+ return IRQ_HANDLED ;
288+
284289 int_mask = thc_interrupt_handler (qsdev -> thc_hw );
285290
286291 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)
318323 if (try_recover (qsdev ))
319324 qsdev -> state = QUICKSPI_DISABLED ;
320325
326+ pm_runtime_mark_last_busy (qsdev -> dev );
327+ pm_runtime_put_autosuspend (qsdev -> dev );
328+
321329 return IRQ_HANDLED ;
322330}
323331
@@ -645,6 +653,13 @@ static int quickspi_probe(struct pci_dev *pdev,
645653
646654 qsdev -> state = QUICKSPI_ENABLED ;
647655
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+
648663 dev_dbg (& pdev -> dev , "QuickSPI probe success\n" );
649664
650665 return 0 ;
@@ -680,6 +695,8 @@ static void quickspi_remove(struct pci_dev *pdev)
680695 quickspi_hid_remove (qsdev );
681696 quickspi_dma_deinit (qsdev );
682697
698+ pm_runtime_get_noresume (qsdev -> dev );
699+
683700 quickspi_dev_deinit (qsdev );
684701
685702 pcim_iounmap_regions (pdev , BIT (0 ));
@@ -709,6 +726,234 @@ static void quickspi_shutdown(struct pci_dev *pdev)
709726 quickspi_dev_deinit (qsdev );
710727}
711728
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+
712957static const struct pci_device_id quickspi_pci_tbl [] = {
713958 {PCI_DEVICE_DATA (INTEL , THC_MTL_DEVICE_ID_SPI_PORT1 , & mtl ), },
714959 {PCI_DEVICE_DATA (INTEL , THC_MTL_DEVICE_ID_SPI_PORT2 , & mtl ), },
@@ -728,6 +973,7 @@ static struct pci_driver quickspi_driver = {
728973 .probe = quickspi_probe ,
729974 .remove = quickspi_remove ,
730975 .shutdown = quickspi_shutdown ,
976+ .driver .pm = & quickspi_pm_ops ,
731977 .driver .probe_type = PROBE_PREFER_ASYNCHRONOUS ,
732978};
733979
0 commit comments