1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Email: opensource_embedded@phytium.com.cn
7 *
8 * Change Logs:
9 * Date Author Notes
10 * 2022-11-10 liqiaozhong first commit
11 * 2023-03-08 liqiaozhong support 4 spis and qspi working together
12 *
13 */
14 #include "rtconfig.h"
15 #include <rtthread.h>
16 #include <rtdevice.h>
17 #include "interrupt.h"
18 #define LOG_TAG "spi_msg_drv"
19 #include "drv_log.h"
20 #include <string.h>
21 #include "fparameters.h"
22 #include "fcpu_info.h"
23 #include "fkernel.h"
24 #include "ftypes.h"
25 #ifdef RT_USING_SMART
26 #include <ioremap.h>
27 #endif
28
29 #include <dfs_file.h>
30 #include "fspim_msg.h"
31 #include "fspim_msg_hw.h" /* include low-level header file for internal probe */
32 #include "drv_spi_msg.h"
33 /************************** Constant Definitions *****************************/
34 /**************************** Type Definitions *******************************/
35 /************************** Variable Definitions *****************************/
36 typedef struct
37 {
38 struct rt_spi_bus spi_bus;
39 FSpiMsgCtrl spim_msg_instance;
40 const char *name;
41 } phytium_spi_bus;
42 /***************** Macros (Inline Functions) Definitions *********************/
43 #define EVENT_RX_DONE (1 << 1)
44 /*******************************Api Functions*********************************/
45 static rt_err_t spim_configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
46 static rt_ssize_t spim_xfer(struct rt_spi_device *device, struct rt_spi_message *message);
47
48 static const struct rt_spi_ops spim_ops =
49 {
50 .configure = spim_configure,
51 .xfer = spim_xfer
52 };
53
spim_configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)54 static rt_err_t spim_configure(struct rt_spi_device *device,
55 struct rt_spi_configuration *configuration)
56 {
57 FError ret = 0;
58 RT_ASSERT(device != RT_NULL);
59 RT_ASSERT(configuration != RT_NULL);
60 phytium_spi_bus *user_data_cfg = device->parent.user_data;
61 FSpiMsgConfig *set_input_cfg = &user_data_cfg->spim_msg_instance.spi_msg_config;
62
63 /* set fspim device according to configuration */
64 /* Modifying the CPOL and CPHA parameters requires support from relevant documentation*/
65 if (configuration->data_width == 8)
66 {
67 set_input_cfg->n_bytes = FSPIM_1_BYTE;
68 }
69
70 /* send spi_cfg to RT-Thread sys */
71 ret = FSpiMsgCfgInitialize(&user_data_cfg->spim_msg_instance, set_input_cfg);
72 if (0 != ret)
73 {
74 return -RT_ERROR;
75 }
76
77 return ret;
78 }
79
spim_xfer(struct rt_spi_device * device,struct rt_spi_message * message)80 static rt_ssize_t spim_xfer(struct rt_spi_device *device, struct rt_spi_message *message)
81 {
82 RT_ASSERT(device != RT_NULL);
83 RT_ASSERT(device->parent.user_data != RT_NULL);
84 RT_ASSERT(message != RT_NULL);
85 rt_ssize_t message_length;
86 rt_uint8_t *recv_buf;
87 const rt_uint8_t *send_buf;
88
89 /* recv spi_cfg from RT-Thread sys */
90 phytium_spi_bus *user_data_xfer = device->parent.user_data;
91 FSpiMsgCtrl *xfer_spim_msg_instance = &user_data_xfer->spim_msg_instance;
92
93 FError tx_rx_result = 0;
94 message_length = message->length;
95 recv_buf = message->recv_buf;
96 send_buf = message->send_buf;
97
98 if (message->cs_take)
99 {
100 FSpiMsgSetChipSelection(xfer_spim_msg_instance, 1);
101 }
102
103 if (message_length > 0)
104 {
105 if (send_buf == RT_NULL && recv_buf != RT_NULL)
106 {
107 /* receive message */
108 tx_rx_result = FSpiMsgTransfer(xfer_spim_msg_instance, RT_NULL, recv_buf, message_length);
109 }
110 else if (send_buf != RT_NULL && recv_buf == RT_NULL)
111 {
112 /* send message */
113 tx_rx_result = FSpiMsgTransfer(xfer_spim_msg_instance, send_buf, RT_NULL, message_length);
114 }
115 else if (send_buf != RT_NULL && recv_buf != RT_NULL)
116 {
117 /* send and recv */
118 tx_rx_result = FSpiMsgTransfer(xfer_spim_msg_instance, send_buf, recv_buf, message_length);
119 }
120 }
121
122 if (0 != tx_rx_result)
123 {
124 rt_kprintf("FSpimTransferByInterrupt() fail!!!");
125 message_length = 0;
126 }
127
128 if (message->cs_release)
129 {
130 FSpiMsgSetChipSelection(xfer_spim_msg_instance, 0);
131 }
132
133 return message_length;
134 }
135
FSpiMsgIntrInit(FSpiMsgCtrl * ctrl,const FSpiMsgConfig * config)136 static void FSpiMsgIntrInit(FSpiMsgCtrl *ctrl, const FSpiMsgConfig *config)
137 {
138 rt_uint32_t cpu_id = rt_hw_cpu_id();
139 rt_hw_interrupt_set_target_cpus(config->irq_num, cpu_id);
140 rt_hw_interrupt_set_priority(config->irq_num, config->irq_priority);
141
142 ctrl->cmd_completion = CMD_MSG_NOT_COMPLETION;
143
144 rt_hw_interrupt_install(config->irq_num, FSpiMsgInterruptHandler, ctrl, NULL);
145 rt_hw_interrupt_umask(config->irq_num);
146 }
147
spi_init(phytium_spi_bus * spi_bus)148 static int spi_init(phytium_spi_bus *spi_bus)
149 {
150 FError ret = 0;
151 FSpiMsgConfig input_cfg = *FSpiMsgLookupConfig(spi_bus->spim_msg_instance.spi_msg_config.instance_id);
152 #ifdef RT_USING_SMART
153 input_cfg.spi_msg.regfile = (uintptr)rt_ioremap((void *)input_cfg.spi_msg.regfile, 0x1000);
154 input_cfg.spi_msg.shmem = (uintptr)rt_ioremap((void *)input_cfg.spi_msg.shmem, 0x1000);
155 #endif
156
157 FSpiMsgIntrInit(&spi_bus->spim_msg_instance, &input_cfg);
158
159 /* send spi_cfg to RT-Thread sys */
160 ret = FSpiMsgCfgInitialize(&spi_bus->spim_msg_instance, &input_cfg);
161 if (0 != ret)
162 {
163 return -RT_ERROR;
164 }
165
166 rt_spi_bus_register(&spi_bus->spi_bus, spi_bus->name, &spim_ops);
167 RT_ASSERT((struct rt_spi_device *)rt_device_find(spi_bus->name));
168
169 return 0;
170 }
171
172 #ifdef RT_USING_SPIM0_MSG
173 static phytium_spi_bus spi0_bus;
174 #endif
175 #ifdef RT_USING_SPIM1_MSG
176 static phytium_spi_bus spi1_bus;
177 #endif
178 #ifdef RT_USING_SPIM2_MSG
179 static phytium_spi_bus spi2_bus;
180 #endif
181 #ifdef RT_USING_SPIM3_MSG
182 static phytium_spi_bus spi3_bus;
183 #endif
184
rt_hw_spi_init(void)185 int rt_hw_spi_init(void)
186 {
187 #ifdef RT_USING_SPIM0_MSG
188 spi0_bus.name = "SPI0";
189 spi0_bus.spim_msg_instance.spi_msg_config.instance_id = FSPI0_MSG_ID;
190 FIOPadSetSpimMux(FSPI0_MSG_ID);
191 spi_init(&spi0_bus);
192 #endif
193 #ifdef RT_USING_SPIM1_MSG
194 spi1_bus.name = "SPI1";
195 spi1_bus.spim_msg_instance.spi_msg_config.instance_id = FSPI1_MSG_ID;
196 FIOPadSetSpimMux(FSPI1_MSG_ID);
197 spi_init(&spi1_bus);
198 #endif
199
200 return 0;
201 }
202 INIT_DEVICE_EXPORT(rt_hw_spi_init);