Skip to content

Commit 881b1ea

Browse files
mmahadevan108kartben
authored andcommitted
drivers: mipi_dbi: Add PM action for NXP driver
Add PM action for the NXP LCDIC driver so that we can recover from a lower power mode where we lose the register settings and we need to reconfigure the block. Signed-off-by: Mahesh Mahadevan <[email protected]>
1 parent 79b0e06 commit 881b1ea

File tree

2 files changed

+101
-18
lines changed

2 files changed

+101
-18
lines changed

drivers/mipi_dbi/mipi_dbi_nxp_lcdic.c

Lines changed: 100 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
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, \

dts/arm/nxp/nxp_rw6xx_common.dtsi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@
355355
#size-cells = <0>;
356356
clocks = <&clkctl1 MCUX_LCDIC_CLK>;
357357
dmas = <&dma0 0>;
358+
zephyr,disabling-power-states = <&suspend &standby>;
358359
power-domains = <&power_mode3_domain>;
359360
};
360361

0 commit comments

Comments
 (0)