1 /*
2 * Copyright (c) 2022 Jiangsu Hoperun Software Co., Ltd.
3 *
4 * This file is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include "hdf_log.h"
12 #include "spi_core.h"
13 #include "spi_if.h"
14 #include "device_resource_if.h"
15 #include "wm_gpio_afsel.h"
16 #include "osal_mutex.h"
17 #include "osal_sem.h"
18 #include "wm_hostspi.h"
19
20 #define SPI_DMA_MAX 4095
21 #define MAX_SPI_NUMBER 1
22 #define TIMEOUT 1000
23
24 struct SpiResource {
25 uint32_t num;
26 uint32_t speed;
27 enum SpiTransferMode transmode;
28 uint32_t mode; // TLS_SPI_MODE_x
29 uint32_t dataSize;
30 uint32_t spiCsSoft;
31 uint32_t spiClkPin;
32 uint32_t spiMosiPin;
33 uint32_t spiMisoPin;
34 uint32_t spiCsPin;
35 };
36
37 struct SpiDevice {
38 uint32_t spiId;
39 struct SpiResource resource;
40 struct OsalMutex mutex;
41 };
42
SpiIomuxInit(const struct SpiDevice * spiDevice)43 static void SpiIomuxInit(const struct SpiDevice *spiDevice)
44 {
45 struct SpiResource *resource = NULL;
46 uint32_t spiPort;
47 HDF_LOGI("%s: Enter\r\n", __func__);
48
49 if (spiDevice == NULL) {
50 HDF_LOGE("%s: invalid parameter\r\n", __func__);
51 return;
52 }
53
54 resource = &spiDevice->resource;
55 if (resource == NULL) {
56 HDF_LOGE("resource is null\r\n");
57 return HDF_ERR_INVALID_OBJECT;
58 }
59
60 spiPort = spiDevice->spiId;
61
62 if (resource->spiCsSoft) {
63 tls_gpio_cfg(WM_IO_PB_00 + resource->spiCsPin, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);
64 }
65 wm_spi_cs_config(WM_IO_PB_04);
66 wm_spi_ck_config(WM_IO_PB_02);
67 wm_spi_di_config(WM_IO_PB_03);
68 wm_spi_do_config(WM_IO_PB_05);
69 }
70
71 /**
72 * Spi send
73 *
74 * @param[in] spiId the spi bus id
75 * @param[in] data spi send data
76 * @param[in] size spi send data size
77 * @param[in] timeOut timeOut in milisecond, set this value to HAL_WAIT_FOREVER
78 * if you want to wait forever
79 *
80 * @return 0 : on success, EIO : if the SPI device could not be initialised
81 */
HalSpiSend(struct SpiDevice * spiDevice,const uint8_t * data,uint16_t size,uint32_t timeOut)82 static int32_t HalSpiSend(struct SpiDevice *spiDevice, const uint8_t *data, uint16_t size, uint32_t timeOut)
83 {
84 int32_t ret = 0;
85 uint32_t spiId;
86 uint32_t len = size;
87 struct SpiResource *resource = NULL;
88 int32_t status = HDF_FAILURE;
89
90 if (spiDevice == NULL || data == NULL || size == 0) {
91 HDF_LOGE("spi input para err\r\n");
92 return HDF_ERR_INVALID_PARAM;
93 }
94
95 spiId = spiDevice->spiId;
96 resource = &spiDevice->resource;
97 if (resource == NULL) {
98 HDF_LOGE("resource is null\r\n");
99 return HDF_ERR_INVALID_OBJECT;
100 }
101 status = OsalMutexLock(&spiDevice->mutex);
102 if (HDF_SUCCESS != status) {
103 HDF_LOGE("%s spi_mutex wait error = 0x%X!\r\n", __func__, status);
104 return HDF_ERR_TIMEOUT;
105 }
106 ret = tls_spi_write(data, (uint32_t)size);
107 if (ret != 0) {
108 HDF_LOGE("spi tail send fail %ld, size %ld\r\n", ret, len);
109 }
110 OsalMutexUnlock(&spiDevice->mutex);
111 return ret;
112 }
113
114 /**
115 * SpiRecv
116 *
117 * @param[in] spiId the spi bus id
118 * @param[out] data spi recv data
119 * @param[in] size spi recv data size
120 * @param[in] timeOut timeOut in milisecond, set this value to HAL_WAIT_FOREVER
121 * if you want to wait forever
122 *
123 * @return 0 : on success, EIO : if the SPI device could not be initialised
124 */
HalSpiRecv(struct SpiDevice * spiDevice,uint8_t * data,uint16_t size,uint32_t timeOut)125 static int32_t HalSpiRecv(struct SpiDevice *spiDevice, uint8_t *data, uint16_t size, uint32_t timeOut)
126 {
127 int32_t ret = 0;
128 uint32_t len = size;
129 uint32_t remainder = 0;
130 int32_t status = HDF_FAILURE;
131 uint8_t *cmd = NULL;
132 uint32_t spiId;
133 struct SpiResource *resource = NULL;
134
135 if (spiDevice == NULL || data == NULL || size == 0) {
136 HDF_LOGE("spi input para err\r\n");
137 return HDF_ERR_INVALID_PARAM;
138 }
139
140 spiId = spiDevice->spiId;
141 resource = &spiDevice->resource;
142 if (resource == NULL) {
143 HDF_LOGE("resource is null\r\n");
144 return HDF_ERR_INVALID_OBJECT;
145 }
146 cmd = (uint8_t *)OsalMemAlloc(len);
147 if (cmd == NULL) {
148 HDF_LOGE("%s OsalMemAlloc size %ld error\r\n", __FUNCTION__, len);
149 return HDF_ERR_MALLOC_FAIL;
150 }
151
152 (void)memset_s(cmd, len, 0, len);
153
154 status = OsalMutexLock(&spiDevice->mutex);
155 if (HDF_SUCCESS != status) {
156 HDF_LOGE("%s spi_mutex wait error = 0x%X!\r\n", __func__, status);
157 OsalMemFree(cmd);
158 return HDF_ERR_TIMEOUT;
159 }
160 remainder = len <= SPI_DMA_MAX ? len : SPI_DMA_MAX;
161
162 ret = tls_spi_read(data, remainder);
163
164 len -= remainder;
165 data += remainder;
166
167 if (ret != 0) {
168 HDF_LOGE("spi tail fail %ld, size %ld\r\n", ret, len);
169 }
170 OsalMutexUnlock(&spiDevice->mutex);
171 OsalMemFree(cmd);
172 return ret;
173 }
174
HalSpiSendRecv(struct SpiDevice * spiDevice,uint8_t * txData,uint16_t txSize,uint8_t * rxData,uint16_t rxSize)175 static int32_t HalSpiSendRecv(struct SpiDevice *spiDevice, uint8_t *txData, uint16_t txSize, uint8_t *rxData,
176 uint16_t rxSize)
177 {
178 int32_t ret;
179 int32_t status;
180 uint32_t spiId;
181 struct SpiResource *resource = NULL;
182
183 if (spiDevice == NULL || txData == NULL || txSize == 0 || rxData == NULL || rxSize == 0) {
184 HDF_LOGE("spi input para err\r\n");
185 return HDF_ERR_INVALID_PARAM;
186 }
187 spiId = spiDevice->spiId;
188 resource = &spiDevice->resource;
189 status = OsalMutexLock(&spiDevice->mutex);
190 if (HDF_SUCCESS != status) {
191 HDF_LOGE("%s spi_mutex wait error = 0x%X!\r\n", __func__, status);
192 return HDF_ERR_TIMEOUT;
193 }
194 ret = tls_spi_xfer(txData, rxData, txSize, rxSize);
195 if (ret != 0) {
196 HDF_LOGE("spi dma tail fail %d\r\n", ret);
197 }
198 OsalMutexUnlock(&spiDevice->mutex);
199 return ret;
200 }
201
InitSpiDevice(struct SpiDevice * spiDevice)202 static int32_t InitSpiDevice(struct SpiDevice *spiDevice)
203 {
204 uint32_t spiPort;
205 struct SpiResource *resource = NULL;
206
207 if (spiDevice == NULL) {
208 HDF_LOGE("%s: invalid parameter\r\n", __func__);
209 return HDF_ERR_INVALID_PARAM;
210 }
211
212 resource = &spiDevice->resource;
213 spiPort = spiDevice->spiId;
214
215 SpiIomuxInit(spiDevice);
216
217 if (spiDevice->mutex.realMutex == NULL) {
218 if (OsalMutexInit(&spiDevice->mutex) != HDF_SUCCESS) {
219 HDF_LOGE("spi Mutex create failed!\r\n");
220 return HDF_FAILURE;
221 }
222 }
223 tls_spi_init();
224 return HDF_SUCCESS;
225 }
226
227 /* get spi config from hcs file */
GetSpiDeviceResource(struct SpiDevice * spiDevice,const struct DeviceResourceNode * resourceNode)228 static int32_t GetSpiDeviceResource(struct SpiDevice *spiDevice, const struct DeviceResourceNode *resourceNode)
229 {
230 struct SpiResource *resource = NULL;
231 struct DeviceResourceIface *dri = NULL;
232
233 if (spiDevice == NULL || resourceNode == NULL) {
234 HDF_LOGE("%s: PARAM is NULL\r\n", __func__);
235 return HDF_ERR_INVALID_PARAM;
236 }
237 resource = &spiDevice->resource;
238 if (resource == NULL) {
239 HDF_LOGE("%s: resource is NULL\r\n", __func__);
240 return HDF_ERR_INVALID_OBJECT;
241 }
242 dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE); // open HDF
243 if (dri == NULL || dri->GetUint32 == NULL) {
244 HDF_LOGE("DeviceResourceIface is invalid\r\n");
245 return HDF_ERR_INVALID_PARAM;
246 }
247
248 if (dri->GetUint32(resourceNode, "num", &resource->num, 0) != HDF_SUCCESS) {
249 HDF_LOGE("spi config read num fail\r\n");
250 return HDF_FAILURE;
251 }
252 spiDevice->spiId = resource->num;
253
254 if (dri->GetUint32(resourceNode, "speed", &resource->speed, 0) != HDF_SUCCESS) {
255 HDF_LOGE("spi config read base fail\r\n");
256 return HDF_FAILURE;
257 }
258
259 if (dri->GetUint32(resourceNode, "transmode", &resource->transmode, 0) != HDF_SUCCESS) {
260 HDF_LOGE("spi config read transmode fail\r\n");
261 return HDF_FAILURE;
262 }
263
264 return HDF_SUCCESS;
265 }
266
AttachSpiDevice(struct SpiCntlr * spiCntlr,const struct HdfDeviceObject * device)267 static int32_t AttachSpiDevice(struct SpiCntlr *spiCntlr, const struct HdfDeviceObject *device)
268 {
269 int32_t ret;
270 struct SpiDevice *spiDevice = NULL;
271
272 if (spiCntlr == NULL || device == NULL || device->property == NULL) {
273 HDF_LOGE("%s: property is NULL\r\n", __func__);
274 return HDF_ERR_INVALID_PARAM;
275 }
276
277 spiDevice = (struct SpiDevice *)OsalMemAlloc(sizeof(struct SpiDevice));
278 if (spiDevice == NULL) {
279 HDF_LOGE("%s: OsalMemAlloc spiDevice error\r\n", __func__);
280 return HDF_ERR_MALLOC_FAIL;
281 }
282 spiDevice->mutex.realMutex = NULL;
283
284 ret = GetSpiDeviceResource(spiDevice, device->property);
285 if (ret != HDF_SUCCESS) {
286 (void)OsalMemFree(spiDevice);
287 return HDF_FAILURE;
288 }
289
290 spiCntlr->priv = spiDevice;
291 spiCntlr->busNum = spiDevice->spiId;
292 return InitSpiDevice(spiDevice);
293 }
294 /* SPI Method */
295 static int32_t SpiDevGetCfg(struct SpiCntlr *spiCntlr, struct SpiCfg *spiCfg);
296 static int32_t SpiDevSetCfg(struct SpiCntlr *spiCntlr, struct SpiCfg *spiCfg);
297 static int32_t SpiDevTransfer(struct SpiCntlr *spiCntlr, struct SpiMsg *spiMsg, uint32_t count);
298 static int32_t SpiDevOpen(struct SpiCntlr *spiCntlr);
299 static int32_t SpiDevClose(struct SpiCntlr *spiCntlr);
300
301 struct SpiCntlrMethod g_SpiCntlrMethod = {
302 .GetCfg = SpiDevGetCfg,
303 .SetCfg = SpiDevSetCfg,
304 .Transfer = SpiDevTransfer,
305 .Open = SpiDevOpen,
306 .Close = SpiDevClose,
307 };
308
309 /* HdfDriverEntry method definitions */
310 static int32_t SpiDriverBind(struct HdfDeviceObject *device);
311 static int32_t SpiDriverInit(struct HdfDeviceObject *device);
312 static void SpiDriverRelease(struct HdfDeviceObject *device);
313
314 /* HdfDriverEntry definitions */
315 struct HdfDriverEntry g_SpiDriverEntry = {
316 .moduleVersion = 1,
317 .moduleName = "W800_SPI_MODULE_HDF",
318 .Bind = SpiDriverBind,
319 .Init = SpiDriverInit,
320 .Release = SpiDriverRelease,
321 };
322
323 HDF_INIT(g_SpiDriverEntry);
324
SpiDriverBind(struct HdfDeviceObject * device)325 static int32_t SpiDriverBind(struct HdfDeviceObject *device)
326 {
327 struct SpiCntlr *spiCntlr = NULL;
328
329 if (device == NULL) {
330 HDF_LOGE("Sample device object is null!\r\n");
331 return HDF_ERR_INVALID_PARAM;
332 }
333 HDF_LOGI("Enter %s:\r\n", __func__);
334 spiCntlr = (struct SpiCntlr *)OsalMemAlloc(sizeof(struct SpiCntlr));
335 if (spiCntlr == NULL) {
336 HDF_LOGE("%s: host is NULL\r\n", __func__);
337 return HDF_FAILURE;
338 }
339 device->service = &spiCntlr->service;
340 spiCntlr->device = device;
341 spiCntlr->priv = NULL;
342 return HDF_SUCCESS;
343 }
344
SpiDriverInit(struct HdfDeviceObject * device)345 static int32_t SpiDriverInit(struct HdfDeviceObject *device)
346 {
347 int32_t ret;
348 struct SpiCntlr *spiCntlr = NULL;
349
350 if (device == NULL) {
351 HDF_LOGE("%s: device is NULL\r\n", __func__);
352 return HDF_ERR_INVALID_PARAM;
353 }
354
355 HDF_LOGI("Enter %s:", __func__);
356 spiCntlr = SpiCntlrFromDevice(device);
357 if (spiCntlr == NULL) {
358 HDF_LOGE("%s: spiCntlr is NULL", __func__);
359 return HDF_DEV_ERR_NO_DEVICE;
360 }
361
362 ret = AttachSpiDevice(spiCntlr, device); // SpiCntlr add SpiDevice to priv
363 if (ret != HDF_SUCCESS) {
364 HDF_LOGE("%s: attach error\r\n", __func__);
365 return HDF_DEV_ERR_ATTACHDEV_FAIL;
366 }
367
368 spiCntlr->method = &g_SpiCntlrMethod; // register callback
369
370 return ret;
371 }
372
SpiDriverRelease(struct HdfDeviceObject * device)373 static void SpiDriverRelease(struct HdfDeviceObject *device)
374 {
375 struct SpiCntlr *spiCntlr = NULL;
376 struct SpiDevice *spiDevice = NULL;
377
378 HDF_LOGI("Enter %s\r\n", __func__);
379
380 if (device == NULL) {
381 HDF_LOGE("%s: device is NULL\r\n", __func__);
382 return;
383 }
384
385 spiCntlr = SpiCntlrFromDevice(device);
386 if (spiCntlr == NULL || spiCntlr->priv == NULL) {
387 HDF_LOGE("%s: spiCntlr is NULL\r\n", __func__);
388 return;
389 }
390
391 spiDevice = (struct SpiDevice *)spiCntlr->priv;
392 OsalMemFree(spiDevice);
393 return;
394 }
395
SpiDevOpen(struct SpiCntlr * spiCntlr)396 static int32_t SpiDevOpen(struct SpiCntlr *spiCntlr)
397 {
398 HDF_LOGI("Enter %s\r\n", __func__);
399 struct SpiDevice *spiDevice = NULL;
400 struct SpiResource *resource = NULL;
401
402 if (spiCntlr == NULL || spiCntlr->priv == NULL) {
403 HDF_LOGE("%s: spiCntlr is NULL\r\n", __func__);
404 return HDF_ERR_INVALID_PARAM;
405 }
406 spiDevice = (struct SpiDevice *)spiCntlr->priv;
407 resource = &spiDevice->resource;
408
409 if (resource->transmode == SPI_DMA_TRANSFER) {
410 tls_spi_trans_type(SPI_USE_DMA_TRANSFER);
411 }
412 if (resource->dataSize == SPI_MASTER_FIFO_SIZE) {
413 tls_spi_trans_type(SPI_WORD_TRANSFER);
414 }
415 tls_spi_setup(resource->mode, TLS_SPI_CS_LOW, resource->speed);
416 return HDF_SUCCESS;
417 }
418
SpiDevClose(struct SpiCntlr * spiCntlr)419 static int32_t SpiDevClose(struct SpiCntlr *spiCntlr)
420 {
421 struct SpiDevice *spiDevice = NULL;
422
423 if (spiCntlr == NULL || spiCntlr->priv == NULL) {
424 HDF_LOGE("%s: spiCntlr is NULL\r\n", __func__);
425 return HDF_ERR_INVALID_PARAM;
426 }
427 spiDevice = (struct SpiDevice *)spiCntlr->priv;
428 return HDF_SUCCESS;
429 }
430
SpiDevGetCfg(struct SpiCntlr * spiCntlr,struct SpiCfg * spiCfg)431 static int32_t SpiDevGetCfg(struct SpiCntlr *spiCntlr, struct SpiCfg *spiCfg)
432 {
433 struct SpiDevice *spiDevice = NULL;
434
435 if (spiCntlr == NULL || spiCfg == NULL || spiCntlr->priv == NULL) {
436 HDF_LOGE("%s: spiCntlr is NULL\r\n", __func__);
437 return HDF_ERR_INVALID_PARAM;
438 }
439 spiDevice = (struct SpiDevice *)spiCntlr->priv;
440 spiCfg->maxSpeedHz = spiDevice->resource.speed;
441 spiCfg->mode = spiDevice->resource.mode;
442 spiCfg->transferMode = spiDevice->resource.transmode;
443 spiCfg->bitsPerWord = spiDevice->resource.dataSize;
444 return HDF_SUCCESS;
445 }
SpiDevSetCfg(struct SpiCntlr * spiCntlr,struct SpiCfg * spiCfg)446 static int32_t SpiDevSetCfg(struct SpiCntlr *spiCntlr, struct SpiCfg *spiCfg)
447 {
448 struct SpiDevice *spiDevice = NULL;
449
450 if (spiCntlr == NULL || spiCfg == NULL || spiCntlr->priv == NULL) {
451 HDF_LOGE("%s: spiCntlr is NULL\r\n", __func__);
452 return HDF_ERR_INVALID_PARAM;
453 }
454 spiDevice = (struct SpiDevice *)spiCntlr->priv;
455 spiDevice->resource.speed = spiCfg->maxSpeedHz;
456 spiDevice->resource.mode = spiCfg->mode;
457 spiDevice->resource.transmode = spiCfg->transferMode;
458 spiDevice->resource.dataSize = spiCfg->bitsPerWord;
459 return SpiDevOpen(spiCntlr);
460 }
461
SpiDevTransfer(struct SpiCntlr * spiCntlr,struct SpiMsg * spiMsg,uint32_t count)462 static int32_t SpiDevTransfer(struct SpiCntlr *spiCntlr, struct SpiMsg *spiMsg, uint32_t count)
463 {
464 uint32_t spiId;
465 struct SpiDevice *spiDevice = NULL;
466 struct SpiMsg *msg = NULL;
467
468 if (spiCntlr == NULL || spiCntlr->priv == NULL) {
469 HDF_LOGE("%s: spiCntlr is NULL\r\n", __func__);
470 return HDF_ERR_INVALID_PARAM;
471 }
472 HDF_LOGI("%s: %u Enter\r\n", __func__, spiId);
473 spiDevice = (struct SpiDevice *)spiCntlr->priv;
474 spiId = spiDevice->spiId;
475 for (size_t i = 0; i < count; i++) {
476 msg = &spiMsg[i];
477 /* pull down cs at first */
478 if (spiDevice->resource.spiCsSoft) {
479 tls_gpio_write(WM_IO_PB_00 + spiDevice->resource.spiCsPin, 0);
480 }
481
482 if ((msg->wbuf != NULL) && (msg->rbuf == NULL)) {
483 HalSpiSend(spiDevice, msg->wbuf, msg->len, TIMEOUT);
484 }
485 if ((msg->rbuf != NULL) && (msg->wbuf == NULL)) {
486 HalSpiRecv(spiDevice, msg->rbuf, msg->len, TIMEOUT);
487 }
488 if ((msg->wbuf != NULL) && (msg->rbuf != NULL)) {
489 HalSpiSendRecv(spiDevice, msg->wbuf, msg->len, msg->rbuf, msg->len);
490 }
491
492 /* pull pull up cs at the end */
493 if (msg->keepCs == 0 && spiDevice->resource.spiCsSoft) {
494 tls_gpio_write(WM_IO_PB_00 + spiDevice->resource.spiCsPin, 1);
495 }
496 }
497 return HDF_SUCCESS;
498 }
499