9
9
#include <zephyr/drivers/mipi_dbi.h>
10
10
#include <zephyr/drivers/pinctrl.h>
11
11
#include <zephyr/drivers/clock_control.h>
12
+ #include <zephyr/pm/device.h>
13
+ #include <zephyr/pm/policy.h>
12
14
#include <zephyr/drivers/spi.h>
13
15
#include <zephyr/drivers/dma.h>
14
16
#include <zephyr/logging/log.h>
@@ -110,6 +112,13 @@ struct mipi_dbi_lcdic_data {
110
112
uint8_t pixel_fmt ;
111
113
/* Tracks TE edge setting we should use for pixel data */
112
114
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 ;
113
122
/* Are we starting a new display frame */
114
123
bool new_frame ;
115
124
const struct mipi_dbi_config * active_cfg ;
@@ -418,12 +427,16 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
418
427
419
428
ret = k_sem_take (& dev_data -> lock , K_FOREVER );
420
429
if (ret ) {
421
- goto out ;
430
+ goto release_sem ;
422
431
}
423
432
433
+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
434
+ pm_policy_device_power_lock_get (dev );
435
+ #endif
436
+
424
437
ret = mipi_dbi_lcdic_configure (dev , dbi_config );
425
438
if (ret ) {
426
- goto out ;
439
+ goto release_power_lock ;
427
440
}
428
441
429
442
if (dev_data -> new_frame ) {
@@ -492,7 +505,7 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
492
505
ret = mipi_dbi_lcdic_start_dma (dev );
493
506
if (ret ) {
494
507
LOG_ERR ("Could not start DMA (%d)" , ret );
495
- goto out ;
508
+ goto release_power_lock ;
496
509
}
497
510
#else
498
511
/* Enable TX FIFO threshold interrupt. This interrupt
@@ -506,8 +519,19 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
506
519
base -> IMR &= ~interrupts ;
507
520
#endif
508
521
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 ;
509
527
}
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 :
511
535
k_sem_give (& dev_data -> lock );
512
536
return ret ;
513
537
@@ -527,12 +551,16 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
527
551
528
552
ret = k_sem_take (& dev_data -> lock , K_FOREVER );
529
553
if (ret ) {
530
- goto out ;
554
+ goto release_sem ;
531
555
}
532
556
557
+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
558
+ pm_policy_device_power_lock_get (dev );
559
+ #endif
560
+
533
561
ret = mipi_dbi_lcdic_configure (dev , dbi_config );
534
562
if (ret ) {
535
- goto out ;
563
+ goto release_power_lock ;
536
564
}
537
565
538
566
/* State reset is required before transfer */
@@ -580,7 +608,7 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
580
608
ret = mipi_dbi_lcdic_start_dma (dev );
581
609
if (ret ) {
582
610
LOG_ERR ("Could not start DMA (%d)" , ret );
583
- goto out ;
611
+ goto release_power_lock ;
584
612
}
585
613
} else /* Data is not aligned */
586
614
#endif
@@ -596,8 +624,19 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
596
624
base -> IMR &= ~interrupts ;
597
625
}
598
626
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 ;
599
632
}
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 :
601
640
k_sem_give (& dev_data -> lock );
602
641
return ret ;
603
642
}
@@ -686,12 +725,15 @@ static int mipi_dbi_lcdic_configure_te(const struct device *dev,
686
725
reg |= LCDIC_TE_CTRL_TTEW (ttew );
687
726
base -> TE_CTRL = reg ;
688
727
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;
689
731
return 0 ;
690
732
}
691
733
692
734
693
735
/* 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 )
695
737
{
696
738
const struct mipi_dbi_lcdic_config * config = dev -> config ;
697
739
struct mipi_dbi_lcdic_data * data = dev -> data ;
@@ -714,14 +756,6 @@ static int mipi_dbi_lcdic_init(const struct device *dev)
714
756
if (ret ) {
715
757
return ret ;
716
758
}
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
- }
725
759
/* Clear all interrupt flags */
726
760
base -> ICR = LCDIC_ALL_INTERRUPTS ;
727
761
/* Mask all interrupts */
@@ -787,6 +821,9 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
787
821
base -> IMR |= LCDIC_ALL_INTERRUPTS ;
788
822
/* All data has been sent. */
789
823
k_sem_give (& data -> xfer_sem );
824
+ #ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
825
+ pm_policy_device_power_lock_put (dev );
826
+ #endif
790
827
} else {
791
828
/* Command done. Queue next command */
792
829
data -> cmd_bytes = MIN (data -> xfer_bytes , LCDIC_MAX_XFER );
@@ -839,6 +876,49 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
839
876
}
840
877
}
841
878
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
+
842
922
#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
843
923
#define LCDIC_DMA_CHANNELS (n ) \
844
924
.dma_stream = { \
@@ -891,7 +971,9 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
891
971
static struct mipi_dbi_lcdic_data mipi_dbi_lcdic_data_##n = { \
892
972
LCDIC_DMA_CHANNELS(n) \
893
973
}; \
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), \
895
977
&mipi_dbi_lcdic_data_##n, \
896
978
&mipi_dbi_lcdic_config_##n, \
897
979
POST_KERNEL, \
0 commit comments