1 /*
2  * Copyright 2018, 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/spi.h>
8 #include <zephyr/drivers/spi/rtio.h>
9 #include <zephyr/drivers/pinctrl.h>
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/irq.h>
12 
13 #include "../spi_context.h"
14 
15 #if CONFIG_NXP_LP_FLEXCOMM
16 #include <zephyr/drivers/mfd/nxp_lp_flexcomm.h>
17 #endif
18 
19 #include <fsl_lpspi.h>
20 
21 /* If any hardware revisions change this, make it into a DT property.
22  * DONT'T make #ifdefs here by platform.
23  */
24 #define LPSPI_CHIP_SELECT_COUNT   4
25 #define LPSPI_MIN_FRAME_SIZE_BITS 8
26 
27 /* Required by DEVICE_MMIO_NAMED_* macros */
28 #define DEV_CFG(_dev)  ((const struct spi_mcux_config *)(_dev)->config)
29 #define DEV_DATA(_dev) ((struct spi_mcux_data *)(_dev)->data)
30 
31 /* flag for SDK API for master transfers */
32 #define LPSPI_MASTER_XFER_CFG_FLAGS(slave)                                                         \
33 	kLPSPI_MasterPcsContinuous | (slave << LPSPI_MASTER_PCS_SHIFT)
34 
35 struct spi_mcux_config {
36 	DEVICE_MMIO_NAMED_ROM(reg_base);
37 	const struct device *clock_dev;
38 	clock_control_subsys_t clock_subsys;
39 	void (*irq_config_func)(const struct device *dev);
40 	uint32_t pcs_sck_delay;
41 	uint32_t sck_pcs_delay;
42 	uint32_t transfer_delay;
43 	const struct pinctrl_dev_config *pincfg;
44 	lpspi_pin_config_t data_pin_config;
45 	bool output_config;
46 	uint8_t tx_fifo_size;
47 	uint8_t rx_fifo_size;
48 	uint8_t irqn;
49 };
50 
51 struct spi_mcux_data {
52 	DEVICE_MMIO_NAMED_RAM(reg_base);
53 	const struct device *dev;
54 	struct spi_context ctx;
55 	void *driver_data;
56 	size_t transfer_len;
57 };
58 
59 /* common configure function that verifies spi_cfg validity and set up configuration parameters */
60 int spi_mcux_configure(const struct device *dev, const struct spi_config *spi_cfg);
61 
62 /* Does these things:
63  * Set data.dev
64  * Check clocks device is ready
65  * Configure cs gpio pin if needed
66  * Mux pinctrl to lpspi
67  * Enable LPSPI IRQ at system level
68  */
69 int spi_nxp_init_common(const struct device *dev);
70 
71 /* common api function for now */
72 int spi_mcux_release(const struct device *dev, const struct spi_config *spi_cfg);
73 
74 void lpspi_wait_tx_fifo_empty(const struct device *dev);
75 
76 /* Argument to MCUX SDK IRQ handler */
77 #define LPSPI_IRQ_HANDLE_ARG COND_CODE_1(CONFIG_NXP_LP_FLEXCOMM, (LPSPI_GetInstance(base)), (base))
78 
79 #define SPI_MCUX_LPSPI_IRQ_FUNC_LP_FLEXCOMM(n)                                                     \
80 	nxp_lp_flexcomm_setirqhandler(DEVICE_DT_GET(DT_INST_PARENT(n)), DEVICE_DT_INST_GET(n),     \
81 				      LP_FLEXCOMM_PERIPH_LPSPI, lpspi_isr);
82 
83 #define SPI_MCUX_LPSPI_IRQ_FUNC_DISTINCT(n)                                                        \
84 	IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), lpspi_isr, DEVICE_DT_INST_GET(n),   \
85 		    0);                                                                            \
86 	irq_enable(DT_INST_IRQN(n));
87 
88 #define SPI_MCUX_LPSPI_IRQ_FUNC(n) COND_CODE_1(DT_NODE_HAS_COMPAT(DT_INST_PARENT(n),		   \
89 								  nxp_lp_flexcomm),		   \
90 						(SPI_MCUX_LPSPI_IRQ_FUNC_LP_FLEXCOMM(n)),	   \
91 						(SPI_MCUX_LPSPI_IRQ_FUNC_DISTINCT(n)))
92 
93 #define LPSPI_IRQN(n) COND_CODE_1(DT_NODE_HAS_COMPAT(DT_INST_PARENT(n), nxp_lp_flexcomm),	   \
94 					(DT_IRQN(DT_INST_PARENT(n))), (DT_INST_IRQN(n)))
95 
96 #define SPI_MCUX_LPSPI_CONFIG_INIT(n)                                                              \
97 	static const struct spi_mcux_config spi_mcux_config_##n = {                                \
98 		DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)),                              \
99 		.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)),                                \
100 		.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(n, name),              \
101 		.irq_config_func = spi_mcux_config_func_##n,                                       \
102 		.pcs_sck_delay = UTIL_AND(DT_INST_NODE_HAS_PROP(n, pcs_sck_delay),                 \
103 					  DT_INST_PROP(n, pcs_sck_delay)),                         \
104 		.sck_pcs_delay = UTIL_AND(DT_INST_NODE_HAS_PROP(n, sck_pcs_delay),                 \
105 					  DT_INST_PROP(n, sck_pcs_delay)),                         \
106 		.transfer_delay = UTIL_AND(DT_INST_NODE_HAS_PROP(n, transfer_delay),               \
107 					   DT_INST_PROP(n, transfer_delay)),                       \
108 		.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),                                       \
109 		.data_pin_config = DT_INST_ENUM_IDX(n, data_pin_config),                           \
110 		.output_config = DT_INST_PROP(n, tristate_output),                                 \
111 		.rx_fifo_size = (uint8_t)DT_INST_PROP(n, rx_fifo_size),                            \
112 		.tx_fifo_size = (uint8_t)DT_INST_PROP(n, tx_fifo_size),                            \
113 		.irqn = (uint8_t)LPSPI_IRQN(n),                                                    \
114 	};
115 
116 #define SPI_NXP_LPSPI_COMMON_INIT(n)                                                               \
117 	PINCTRL_DT_INST_DEFINE(n);                                                                 \
118                                                                                                    \
119 	static void spi_mcux_config_func_##n(const struct device *dev)                             \
120 	{                                                                                          \
121 		SPI_MCUX_LPSPI_IRQ_FUNC(n)                                                         \
122 	}
123 
124 #define SPI_NXP_LPSPI_COMMON_DATA_INIT(n)                                                          \
125 	SPI_CONTEXT_INIT_LOCK(spi_mcux_data_##n, ctx),                                             \
126 		SPI_CONTEXT_INIT_SYNC(spi_mcux_data_##n, ctx),                                     \
127 		SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)
128 
129 #define SPI_NXP_LPSPI_HAS_DMAS(n)                                                                  \
130 	UTIL_AND(DT_INST_DMAS_HAS_NAME(n, tx), DT_INST_DMAS_HAS_NAME(n, rx))
131