1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2020-10-28 0xcccccccccccc Initial Version
9 * 2021-01-17 0xcccccccccccc Bug Fixed : clock division cannot been adjusted as expected due to wrong register configuration.
10 */
11
12 /**
13 * @addtogroup ls2k
14 */
15 /*@{*/
16
17 #include <stdlib.h>
18 #include <ctype.h>
19 #include <stdint.h>
20 #include <rtthread.h>
21 #include "drivers/dev_spi.h"
22 #include "drv_spi.h"
23
24 #ifdef RT_USING_SPI
25 #ifdef RT_USING_SPI_GPIOCS
26 #include <drivers/dev_pin.h>
27 #endif
28
spi_init(uint8_t spre_spr,uint8_t copl,uint8_t cpha)29 static void spi_init(uint8_t spre_spr, uint8_t copl, uint8_t cpha)
30 {
31 SET_SPI(SPSR, 0xc0);
32 SET_SPI(PARAM, 0x40);
33 SET_SPI(PARAM2, 0x01);
34 SET_SPI(SPER, (spre_spr & 0b00001100) >> 2);
35 SET_SPI(SPCR, 0x50 | copl << 3 | cpha << 2 | (spre_spr & 0b00000011));
36 SET_SPI(SOFTCS, 0xff);
37 }
38
spi_set_csn(uint8_t val)39 rt_inline void spi_set_csn(uint8_t val)
40 {
41 SET_SPI(SOFTCS, val);
42 }
43
spi_set_cs(unsigned char cs,int new_status)44 static void spi_set_cs(unsigned char cs, int new_status)
45 {
46 if (cs < 4)
47 {
48 unsigned char val = 0;
49 val = GET_SPI(SOFTCS);
50 val |= 0x01 << cs ; // csen=1
51 if (new_status) // cs = 1
52 {
53 val |= (0x10 << cs); // csn=1
54 }
55 else // cs = 0
56 {
57 val &= ~(0x10 << cs); // csn=0
58 }
59 SET_SPI(SOFTCS, val);
60 return ;
61 }
62 #ifdef RT_USING_SPI_GPIOCS
63 else
64 {
65 rt_pin_mode(cs, PIN_MODE_OUTPUT); // with RT_USING_SPI_GPIOCS feature enabled, gpio will be used as csn pin.
66 rt_pin_write(cs, new_status);
67 }
68 #endif
69 }
70
spi_write_for_response(uint8_t data)71 static uint8_t spi_write_for_response(uint8_t data)
72 {
73 uint8_t val;
74 SET_SPI(TXFIFO, data);
75 while ((GET_SPI(SPSR))&RFEMPTY); //wait for echo
76 val = GET_SPI(RXFIFO);
77 return val;
78 }
79
cmd_spi_init(int argc,char * argv[])80 static int cmd_spi_init(int argc, char *argv[])
81 {
82 uint8_t spre_spr, cpol, cpha;
83 switch (argc)
84 {
85 case 2:
86 spre_spr = strtoul(argv[1], NULL, 0);
87 spi_init(spre_spr, 0, 0);
88 break;
89 case 4:
90 spre_spr = strtoul(argv[1], NULL, 0);
91 cpol = strtoul(argv[2], NULL, 0);
92 cpha = strtoul(argv[3], NULL, 0);
93 spi_init(spre_spr, 0, 0);
94 break;
95 default:
96 printf("\nusage : cmd_spi_init spre_spr <cpol> <cpha>\n(cmd_spi_init 0x4 0x0 0x0)\n0x4:div8 0xb:div4096\n");
97 break;
98 }
99 }
100 MSH_CMD_EXPORT(cmd_spi_init, cmd_spi_init);
101
cmd_spi_set_csn(int argc,char * argv[])102 static int cmd_spi_set_csn(int argc, char *argv[])
103 {
104 uint8_t val, csn;
105 switch (argc)
106 {
107 case 3:
108 csn = strtoul(argv[1], NULL, 0);
109 val = strtoul(argv[2], NULL, 0);
110 spi_set_cs(csn, val);
111 break;
112 default:
113 printf("usage:cmd_spi_set_csn csn val\n(0xbf for csn1 enable,0xff for csn1 disable)\n");
114 break;
115 }
116 }
117 MSH_CMD_EXPORT(cmd_spi_set_csn, cmd_spi_set_csn);
118
cmd_spi_write(int argc,char * argv[])119 static int cmd_spi_write(int argc, char *argv[])
120 {
121 uint8_t data, resp;
122 switch (argc)
123 {
124 case 2:
125 data = strtoul(argv[1], NULL, 0);
126 resp = spi_write_for_response(data);
127 printf("resp:%2X\n", resp);
128 break;
129 default:
130 printf("usage:cmd_spi_write data\n");
131 break;
132 }
133 }
134 MSH_CMD_EXPORT(cmd_spi_write, cmd_spi_write);
135
136 static rt_err_t configure(struct rt_spi_device *device, struct rt_spi_configuration *configuration);
137 static rt_uint32_t xfer(struct rt_spi_device *device, struct rt_spi_message *message);
138
139 const static unsigned char SPI_DIV_TABLE[] = {0b0000, 0b0001, 0b0100, 0b0010, 0b0011, 0b0101, 0b0110, 0b0111, 0b1000, 0b1001, 0b1010, 0b1011};
140 // 2 4 8 16 32 64 128 256 512 1024 2048 4096
configure(struct rt_spi_device * device,struct rt_spi_configuration * configuration)141 static rt_err_t configure(struct rt_spi_device *device,
142 struct rt_spi_configuration *configuration)
143 {
144
145 unsigned char cpol = 0;
146 unsigned char cpha = 0;
147
148 RT_ASSERT(NULL != device);
149 RT_ASSERT(NULL != configuration);
150
151 // baudrate
152 if (configuration->mode & RT_SPI_CPOL) // cpol
153 {
154 cpol = 1;
155 }
156 else
157 {
158 cpol = 0;
159 }
160 if (configuration->mode & RT_SPI_CPHA) // cpha
161 {
162 cpha = 1;
163 }
164 else
165 {
166 cpha = 0;
167 }
168
169 float spi_max_speed = ((float)APB_MAX_SPEED) / (8.0 / (float)APB_FREQSCALE);
170 uint64_t div = (uint64_t)(spi_max_speed / (float)configuration->max_hz);
171 int ctr = 0;
172 while (div != 1 && ctr < 12)
173 {
174 ctr++;
175 div = div >> 1;
176 }
177 spi_init(SPI_DIV_TABLE[ctr], cpol, cpha);
178
179 return RT_EOK;
180 }
181
xfer(struct rt_spi_device * device,struct rt_spi_message * message)182 static rt_uint32_t xfer(struct rt_spi_device *device, struct rt_spi_message *message)
183 {
184
185 unsigned char cs = 0;
186 rt_uint32_t size = 0;
187 const rt_uint8_t *send_ptr = NULL;
188 rt_uint8_t *recv_ptr = NULL;
189 rt_uint8_t data = 0;
190 RT_ASSERT(NULL != device);
191 RT_ASSERT(NULL != message);
192 cs = (unsigned char)(device->parent.user_data);
193 size = message->length;
194 if (message->cs_take)
195 {
196 spi_set_cs(cs, 0);
197 }
198 // send data
199 send_ptr = message->send_buf;
200 recv_ptr = message->recv_buf;
201 while (size--)
202 {
203 data = 0xFF;
204 if (NULL != send_ptr)
205 {
206 data = *send_ptr++;
207 }
208 if (NULL != recv_ptr)
209 {
210 *recv_ptr++ = spi_write_for_response(data);
211 }
212 else
213 {
214 spi_write_for_response(data);
215 }
216 }
217 // release cs
218 if (message->cs_release)
219 {
220 spi_set_cs(cs, 1);
221 }
222 return message->length;
223 }
224
225 static struct rt_spi_ops loongson_spi_ops =
226 {
227 .configure = configure,
228 .xfer = xfer
229 };
230 static struct rt_spi_bus loongson_spi;
231
loongson_spi_init()232 static int loongson_spi_init()
233 {
234 //rt_kprintf("spi_init\n");
235 return rt_spi_bus_register(&loongson_spi, "spi", &loongson_spi_ops);
236 }
237 INIT_BOARD_EXPORT(loongson_spi_init);
238 #endif
239 /*@}*/
240