99#include <zephyr/drivers/mipi_dbi.h>
1010#include <zephyr/drivers/pinctrl.h>
1111#include <zephyr/drivers/clock_control.h>
12+ #include <zephyr/pm/device.h>
13+ #include <zephyr/pm/policy.h>
1214#include <zephyr/drivers/spi.h>
1315#include <zephyr/drivers/dma.h>
1416#include <zephyr/logging/log.h>
@@ -110,6 +112,13 @@ struct mipi_dbi_lcdic_data {
110112 uint8_t pixel_fmt ;
111113 /* Tracks TE edge setting we should use for pixel data */
112114 uint8_t te_edge ;
115+ /* Tracks TE delay setting we should use */
116+ k_timeout_t te_delay ;
117+ /* Flag indicates we need to reconfigure TE signal.
118+ * This is the case when we exit low power modes where we
119+ * need to configure the hardware registers.
120+ */
121+ bool reconfigure_te ;
113122 /* Are we starting a new display frame */
114123 bool new_frame ;
115124 const struct mipi_dbi_config * active_cfg ;
@@ -418,12 +427,16 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
418427
419428 ret = k_sem_take (& dev_data -> lock , K_FOREVER );
420429 if (ret ) {
421- goto out ;
430+ goto release_sem ;
422431 }
423432
433+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
434+ pm_policy_device_power_lock_get (dev );
435+ #endif
436+
424437 ret = mipi_dbi_lcdic_configure (dev , dbi_config );
425438 if (ret ) {
426- goto out ;
439+ goto release_power_lock ;
427440 }
428441
429442 if (dev_data -> new_frame ) {
@@ -492,7 +505,7 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
492505 ret = mipi_dbi_lcdic_start_dma (dev );
493506 if (ret ) {
494507 LOG_ERR ("Could not start DMA (%d)" , ret );
495- goto out ;
508+ goto release_power_lock ;
496509 }
497510#else
498511 /* Enable TX FIFO threshold interrupt. This interrupt
@@ -506,8 +519,19 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
506519 base -> IMR &= ~interrupts ;
507520#endif
508521 ret = k_sem_take (& dev_data -> xfer_sem , K_FOREVER );
522+ /* Do not release the lock from the power states.
523+ * This is released in the ISR after the transfer
524+ * is complete.
525+ */
526+ goto release_sem ;
509527 }
510- out :
528+
529+ release_power_lock :
530+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
531+ pm_policy_device_power_lock_put (dev );
532+ #endif
533+
534+ release_sem :
511535 k_sem_give (& dev_data -> lock );
512536 return ret ;
513537
@@ -527,12 +551,16 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
527551
528552 ret = k_sem_take (& dev_data -> lock , K_FOREVER );
529553 if (ret ) {
530- goto out ;
554+ goto release_sem ;
531555 }
532556
557+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
558+ pm_policy_device_power_lock_get (dev );
559+ #endif
560+
533561 ret = mipi_dbi_lcdic_configure (dev , dbi_config );
534562 if (ret ) {
535- goto out ;
563+ goto release_power_lock ;
536564 }
537565
538566 /* State reset is required before transfer */
@@ -580,7 +608,7 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
580608 ret = mipi_dbi_lcdic_start_dma (dev );
581609 if (ret ) {
582610 LOG_ERR ("Could not start DMA (%d)" , ret );
583- goto out ;
611+ goto release_power_lock ;
584612 }
585613 } else /* Data is not aligned */
586614#endif
@@ -596,8 +624,19 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
596624 base -> IMR &= ~interrupts ;
597625 }
598626 ret = k_sem_take (& dev_data -> xfer_sem , K_FOREVER );
627+ /* Do not release the lock from the power states.
628+ * This is released in the ISR after the transfer
629+ * is complete.
630+ */
631+ goto release_sem ;
599632 }
600- out :
633+
634+ release_power_lock :
635+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
636+ pm_policy_device_power_lock_put (dev );
637+ #endif
638+
639+ release_sem :
601640 k_sem_give (& dev_data -> lock );
602641 return ret ;
603642}
@@ -686,12 +725,15 @@ static int mipi_dbi_lcdic_configure_te(const struct device *dev,
686725 reg |= LCDIC_TE_CTRL_TTEW (ttew );
687726 base -> TE_CTRL = reg ;
688727 data -> te_edge = edge ;
728+ data -> te_delay = delay ;
729+ /* We should re-configure te signal when coming out of PM mode */
730+ data -> reconfigure_te = true;
689731 return 0 ;
690732}
691733
692734
693735/* Initializes LCDIC peripheral */
694- static int mipi_dbi_lcdic_init (const struct device * dev )
736+ static int mipi_dbi_lcdic_init_common (const struct device * dev )
695737{
696738 const struct mipi_dbi_lcdic_config * config = dev -> config ;
697739 struct mipi_dbi_lcdic_data * data = dev -> data ;
@@ -714,14 +756,6 @@ static int mipi_dbi_lcdic_init(const struct device *dev)
714756 if (ret ) {
715757 return ret ;
716758 }
717- ret = k_sem_init (& data -> xfer_sem , 0 , 1 );
718- if (ret ) {
719- return ret ;
720- }
721- ret = k_sem_init (& data -> lock , 1 , 1 );
722- if (ret ) {
723- return ret ;
724- }
725759 /* Clear all interrupt flags */
726760 base -> ICR = LCDIC_ALL_INTERRUPTS ;
727761 /* Mask all interrupts */
@@ -787,6 +821,9 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
787821 base -> IMR |= LCDIC_ALL_INTERRUPTS ;
788822 /* All data has been sent. */
789823 k_sem_give (& data -> xfer_sem );
824+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
825+ pm_policy_device_power_lock_put (dev );
826+ #endif
790827 } else {
791828 /* Command done. Queue next command */
792829 data -> cmd_bytes = MIN (data -> xfer_bytes , LCDIC_MAX_XFER );
@@ -839,6 +876,49 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
839876 }
840877}
841878
879+ static int mipi_dbi_lcdic_pm_action (const struct device * dev , enum pm_device_action action )
880+ {
881+ struct mipi_dbi_lcdic_data * data = dev -> data ;
882+
883+ switch (action ) {
884+ case PM_DEVICE_ACTION_RESUME :
885+ break ;
886+ case PM_DEVICE_ACTION_SUSPEND :
887+ break ;
888+ case PM_DEVICE_ACTION_TURN_OFF :
889+ break ;
890+ case PM_DEVICE_ACTION_TURN_ON :
891+ mipi_dbi_lcdic_init_common (dev );
892+ data -> active_cfg = NULL ;
893+ if (data -> reconfigure_te ) {
894+ mipi_dbi_lcdic_configure_te (dev , data -> te_edge , data -> te_delay );
895+ }
896+ break ;
897+ default :
898+ return - ENOTSUP ;
899+ }
900+ return 0 ;
901+ }
902+
903+ static int mipi_dbi_lcdic_init (const struct device * dev )
904+ {
905+ struct mipi_dbi_lcdic_data * data = dev -> data ;
906+ int ret ;
907+
908+ ret = k_sem_init (& data -> xfer_sem , 0 , 1 );
909+ if (ret ) {
910+ return ret ;
911+ }
912+ ret = k_sem_init (& data -> lock , 1 , 1 );
913+ if (ret ) {
914+ return ret ;
915+ }
916+ /* Rest of the init is done from the PM_DEVICE_TURN_ON action
917+ * which is invoked by pm_device_driver_init().
918+ */
919+ return pm_device_driver_init (dev , mipi_dbi_lcdic_pm_action );
920+ }
921+
842922#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
843923#define LCDIC_DMA_CHANNELS (n ) \
844924 .dma_stream = { \
@@ -891,7 +971,9 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
891971 static struct mipi_dbi_lcdic_data mipi_dbi_lcdic_data_##n = { \
892972 LCDIC_DMA_CHANNELS(n) \
893973 }; \
894- DEVICE_DT_INST_DEFINE(n, mipi_dbi_lcdic_init, NULL, \
974+ PM_DEVICE_DT_INST_DEFINE(n, mipi_dbi_lcdic_pm_action); \
975+ DEVICE_DT_INST_DEFINE(n, mipi_dbi_lcdic_init, \
976+ PM_DEVICE_DT_INST_GET(n), \
895977 &mipi_dbi_lcdic_data_##n, \
896978 &mipi_dbi_lcdic_config_##n, \
897979 POST_KERNEL, \
0 commit comments