Commit 881b1ea4 authored by Mahesh Mahadevan's avatar Mahesh Mahadevan Committed by Benjamin Cabé
Browse files

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: default avatarMahesh Mahadevan <mahesh.mahadevan@nxp.com>
parent 79b0e066
Loading
Loading
Loading
Loading
+100 −18
Changes for drivers/mipi_dbi/mipi_dbi_nxp_lcdic.c: 100 added lines, 18 removed lines.
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@
#include <zephyr/drivers/mipi_dbi.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/pm/device.h>
#include <zephyr/pm/policy.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/dma.h>
#include <zephyr/logging/log.h>
@@ -110,6 +112,13 @@ struct mipi_dbi_lcdic_data {
	uint8_t pixel_fmt;
	/* Tracks TE edge setting we should use for pixel data */
	uint8_t te_edge;
	/* Tracks TE delay setting we should use */
	k_timeout_t te_delay;
	/* Flag indicates we need to reconfigure TE signal.
	 * This is the case when we exit low power modes where we
	 * need to configure the hardware registers.
	 */
	bool reconfigure_te;
	/* Are we starting a new display frame */
	bool new_frame;
	const struct mipi_dbi_config *active_cfg;
@@ -418,12 +427,16 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,

	ret = k_sem_take(&dev_data->lock, K_FOREVER);
	if (ret) {
		goto out;
		goto release_sem;
	}

#ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
	pm_policy_device_power_lock_get(dev);
#endif

	ret = mipi_dbi_lcdic_configure(dev, dbi_config);
	if (ret) {
		goto out;
		goto release_power_lock;
	}

	if (dev_data->new_frame) {
@@ -492,7 +505,7 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
		ret = mipi_dbi_lcdic_start_dma(dev);
		if (ret) {
			LOG_ERR("Could not start DMA (%d)", ret);
			goto out;
			goto release_power_lock;
		}
#else
		/* Enable TX FIFO threshold interrupt. This interrupt
@@ -506,8 +519,19 @@ static int mipi_dbi_lcdic_write_display(const struct device *dev,
		base->IMR &= ~interrupts;
#endif
		ret = k_sem_take(&dev_data->xfer_sem, K_FOREVER);
		/* Do not release the lock from the power states.
		 * This is released in the ISR after the transfer
		 * is complete.
		 */
		goto release_sem;
	}
out:

release_power_lock:
#ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
	pm_policy_device_power_lock_put(dev);
#endif

release_sem:
	k_sem_give(&dev_data->lock);
	return ret;

@@ -527,12 +551,16 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,

	ret = k_sem_take(&dev_data->lock, K_FOREVER);
	if (ret) {
		goto out;
		goto release_sem;
	}

#ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
	pm_policy_device_power_lock_get(dev);
#endif

	ret = mipi_dbi_lcdic_configure(dev, dbi_config);
	if (ret) {
		goto out;
		goto release_power_lock;
	}

	/* State reset is required before transfer */
@@ -580,7 +608,7 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
			ret = mipi_dbi_lcdic_start_dma(dev);
			if (ret) {
				LOG_ERR("Could not start DMA (%d)", ret);
				goto out;
				goto release_power_lock;
			}
		} else /* Data is not aligned */
#endif
@@ -596,8 +624,19 @@ static int mipi_dbi_lcdic_write_cmd(const struct device *dev,
			base->IMR &= ~interrupts;
		}
		ret = k_sem_take(&dev_data->xfer_sem, K_FOREVER);
		/* Do not release the lock from the power states.
		 * This is released in the ISR after the transfer
		 * is complete.
		 */
		goto release_sem;
	}
out:

release_power_lock:
#ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
	pm_policy_device_power_lock_put(dev);
#endif

release_sem:
	k_sem_give(&dev_data->lock);
	return ret;
}
@@ -686,12 +725,15 @@ static int mipi_dbi_lcdic_configure_te(const struct device *dev,
	reg |= LCDIC_TE_CTRL_TTEW(ttew);
	base->TE_CTRL = reg;
	data->te_edge = edge;
	data->te_delay = delay;
	/* We should re-configure te signal when coming out of PM mode */
	data->reconfigure_te = true;
	return 0;
}


/* Initializes LCDIC peripheral */
static int mipi_dbi_lcdic_init(const struct device *dev)
static int mipi_dbi_lcdic_init_common(const struct device *dev)
{
	const struct mipi_dbi_lcdic_config *config = dev->config;
	struct mipi_dbi_lcdic_data *data = dev->data;
@@ -714,14 +756,6 @@ static int mipi_dbi_lcdic_init(const struct device *dev)
	if (ret) {
		return ret;
	}
	ret = k_sem_init(&data->xfer_sem, 0, 1);
	if (ret) {
		return ret;
	}
	ret = k_sem_init(&data->lock, 1, 1);
	if (ret) {
		return ret;
	}
	/* Clear all interrupt flags */
	base->ICR = LCDIC_ALL_INTERRUPTS;
	/* Mask all interrupts */
@@ -787,6 +821,9 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
			base->IMR |= LCDIC_ALL_INTERRUPTS;
			/* All data has been sent. */
			k_sem_give(&data->xfer_sem);
#ifdef CONFIG_PM_POLICY_DEVICE_CONSTRAINTS
			pm_policy_device_power_lock_put(dev);
#endif
		} else {
			/* Command done. Queue next command */
			data->cmd_bytes = MIN(data->xfer_bytes, LCDIC_MAX_XFER);
@@ -839,6 +876,49 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
	}
}

static int mipi_dbi_lcdic_pm_action(const struct device *dev, enum pm_device_action action)
{
	struct mipi_dbi_lcdic_data *data = dev->data;

	switch (action) {
	case PM_DEVICE_ACTION_RESUME:
		break;
	case PM_DEVICE_ACTION_SUSPEND:
		break;
	case PM_DEVICE_ACTION_TURN_OFF:
		break;
	case PM_DEVICE_ACTION_TURN_ON:
		mipi_dbi_lcdic_init_common(dev);
		data->active_cfg = NULL;
		if (data->reconfigure_te) {
			mipi_dbi_lcdic_configure_te(dev, data->te_edge, data->te_delay);
		}
		break;
	default:
		return -ENOTSUP;
	}
	return 0;
}

static int mipi_dbi_lcdic_init(const struct device *dev)
{
	struct mipi_dbi_lcdic_data *data = dev->data;
	int ret;

	ret = k_sem_init(&data->xfer_sem, 0, 1);
	if (ret) {
		return ret;
	}
	ret = k_sem_init(&data->lock, 1, 1);
	if (ret) {
		return ret;
	}
	/* Rest of the init is done from the PM_DEVICE_TURN_ON action
	 * which is invoked by pm_device_driver_init().
	 */
	return pm_device_driver_init(dev, mipi_dbi_lcdic_pm_action);
}

#ifdef CONFIG_MIPI_DBI_NXP_LCDIC_DMA
#define LCDIC_DMA_CHANNELS(n)						\
	.dma_stream = {							\
@@ -891,7 +971,9 @@ static void mipi_dbi_lcdic_isr(const struct device *dev)
	static struct mipi_dbi_lcdic_data mipi_dbi_lcdic_data_##n = {	\
		LCDIC_DMA_CHANNELS(n)					\
	};								\
	DEVICE_DT_INST_DEFINE(n, mipi_dbi_lcdic_init, NULL,		\
	PM_DEVICE_DT_INST_DEFINE(n, mipi_dbi_lcdic_pm_action);		\
	DEVICE_DT_INST_DEFINE(n, mipi_dbi_lcdic_init,			\
			PM_DEVICE_DT_INST_GET(n),			\
			&mipi_dbi_lcdic_data_##n,			\
			&mipi_dbi_lcdic_config_##n,			\
			POST_KERNEL,					\
+1 −0
Changes for dts/arm/nxp/nxp_rw6xx_common.dtsi: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -355,6 +355,7 @@
		#size-cells = <0>;
		clocks = <&clkctl1 MCUX_LCDIC_CLK>;
		dmas = <&dma0 0>;
		zephyr,disabling-power-states = <&suspend &standby>;
		power-domains = <&power_mode3_domain>;
	};