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);