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