1 /*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 *
4 * HDF 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 "device_resource_if.h"
10 #include "hdf_base.h"
11 #include "hdf_log.h"
12 #include "osal_mem.h"
13 #include "osal_sem.h"
14 #include "osal_spinlock.h"
15 #include "spi/spi_core.h"
16
17 #define HDF_LOG_TAG spi_virtual
18 #define DEFAULT_BUS_NUM 255
19 #define FIFO_SIZE_MAX 256
20 #define WAIT_TIMEOUT 1000 // ms
21 #define DEFAULT_SPEED 2000000U
22 #define BYTES_PER_WORD 2U
23 #define BITS_PER_WORD_MIN 4U
24 #define BITS_PER_WORD_EIGHT 8U
25 #define BITS_PER_WORD_MAX 16U
26
27 struct VirtualSpi {
28 struct SpiCntlr *cntlr;
29 struct OsalSem sem;
30 OsalSpinlock lock;
31 uint32_t busNum;
32 uint32_t speed;
33 uint32_t fifoSize;
34 uint32_t numCs;
35 uint16_t waterline;
36 uint16_t wp;
37 uint16_t rp;
38 uint16_t validSize;
39 uint16_t *ringBuffer;
40 struct SpiCfg cfg;
41 };
42
NextByte(uint32_t fifoSize,uint16_t curByte)43 static inline uint16_t NextByte(uint32_t fifoSize, uint16_t curByte)
44 {
45 if (curByte >= fifoSize - 1) {
46 return 0;
47 } else {
48 return ++curByte;
49 }
50 }
51
RingBufferReadWord(struct VirtualSpi * virtual,uint16_t * word)52 static bool RingBufferReadWord(struct VirtualSpi *virtual, uint16_t *word)
53 {
54 uint16_t pos = NextByte(virtual->fifoSize, virtual->rp);
55
56 (void)OsalSpinLock(&virtual->lock);
57 if (pos == virtual->wp || virtual->validSize == 0) {
58 (void)OsalSpinUnlock(&virtual->lock);
59 return false;
60 }
61 *word = virtual->ringBuffer[pos];
62 virtual->rp = pos;
63 virtual->validSize--;
64 (void)OsalSpinUnlock(&virtual->lock);
65 return true;
66 }
67
RingBufferWriteWord(struct VirtualSpi * virtual,uint16_t word)68 static bool RingBufferWriteWord(struct VirtualSpi *virtual, uint16_t word)
69 {
70 (void)OsalSpinLock(&virtual->lock);
71 if (virtual->wp == virtual->rp || virtual->validSize == virtual->fifoSize - 1) {
72 (void)OsalSpinUnlock(&virtual->lock);
73 return false;
74 }
75 virtual->ringBuffer[virtual->wp] = word;
76 virtual->wp = NextByte(virtual->fifoSize, virtual->wp);
77 virtual->validSize++;
78 if (virtual->validSize == virtual->waterline) {
79 (void)OsalSemPost(&virtual->sem);
80 }
81 (void)OsalSpinUnlock(&virtual->lock);
82 return true;
83 }
84
RingBufferFlush(struct VirtualSpi * virtual)85 static void RingBufferFlush(struct VirtualSpi *virtual)
86 {
87 (void)OsalSpinLock(&virtual->lock);
88 virtual->wp = 0;
89 virtual->rp = virtual->fifoSize - 1;
90 virtual->validSize = 0;
91 (void)OsalSpinUnlock(&virtual->lock);
92 }
93
RingBufferConfig(struct VirtualSpi * virtual)94 static int32_t RingBufferConfig(struct VirtualSpi *virtual)
95 {
96 if (virtual->fifoSize == 0 || virtual->fifoSize > FIFO_SIZE_MAX) {
97 HDF_LOGE("RingBufferConfig, invalid fifoSize!");
98 return HDF_ERR_INVALID_PARAM;
99 }
100
101 if ((virtual->cfg.mode & SPI_MODE_LOOP) != 0 && virtual->ringBuffer == NULL) {
102 virtual->ringBuffer = OsalMemAlloc(virtual->fifoSize * BYTES_PER_WORD);
103 if (virtual->ringBuffer == NULL) {
104 HDF_LOGE("RingBufferConfig: malloc ringBuffer fail!");
105 return HDF_ERR_MALLOC_FAIL;
106 }
107 } else if ((virtual->cfg.mode & SPI_MODE_LOOP) == 0) {
108 OsalMemFree(virtual->ringBuffer);
109 virtual->ringBuffer = NULL;
110 }
111 RingBufferFlush(virtual);
112 return HDF_SUCCESS;
113 }
114
115 #define ONE_BYTE 1
116 #define TWO_BYTE 2
117
VirtualSpiToByteWidth(uint8_t bitsPerWord)118 static inline uint8_t VirtualSpiToByteWidth(uint8_t bitsPerWord)
119 {
120 if (bitsPerWord <= BITS_PER_WORD_EIGHT) {
121 return ONE_BYTE;
122 } else {
123 return TWO_BYTE;
124 }
125 }
126
VirtualSpiWriteFifo(struct VirtualSpi * virtual,const uint8_t * tx,uint32_t count)127 static bool VirtualSpiWriteFifo(struct VirtualSpi *virtual, const uint8_t *tx, uint32_t count)
128 {
129 uint16_t value;
130 uint8_t bytes = VirtualSpiToByteWidth(virtual->cfg.bitsPerWord);
131
132 if ((virtual->cfg.mode & SPI_MODE_LOOP) == 0 || virtual->ringBuffer == NULL) {
133 /* open loop mode */
134 return true;
135 }
136
137 for (value = 0; count >= bytes; count -= bytes) {
138 if (tx != NULL) {
139 value = (bytes == ONE_BYTE) ? *tx : *((uint16_t *)tx);
140 tx += bytes;
141 }
142 if (!RingBufferWriteWord(virtual, value)) {
143 return false;
144 }
145 }
146 return true;
147 }
148
VirtualSpiReadFifo(struct VirtualSpi * virtual,uint8_t * rx,uint32_t count)149 static bool VirtualSpiReadFifo(struct VirtualSpi *virtual, uint8_t *rx, uint32_t count)
150 {
151 uint16_t value;
152 uint8_t bytes = VirtualSpiToByteWidth(virtual->cfg.bitsPerWord);
153
154 if ((virtual->cfg.mode & SPI_MODE_LOOP) == 0 || virtual->ringBuffer == NULL) {
155 /* open loop mode */
156 return true;
157 }
158
159 for (value = 0; count >= bytes; count -= bytes) {
160 if (!RingBufferReadWord(virtual, &value)) {
161 return false;
162 }
163
164 if (rx == NULL) {
165 continue;
166 }
167 if (bytes == ONE_BYTE) {
168 *rx = (uint8_t)value;
169 } else {
170 *((uint16_t *)rx) = value;
171 }
172 rx += bytes;
173 }
174 return true;
175 }
176
VirtualSpiTxRx(struct VirtualSpi * virtual,const struct SpiMsg * msg)177 static int32_t VirtualSpiTxRx(struct VirtualSpi *virtual, const struct SpiMsg *msg)
178 {
179 int32_t ret;
180 uint32_t tmpLen;
181 uint32_t len;
182 const uint8_t *tx = msg->wbuf;
183 uint8_t *rx = msg->rbuf;
184 uint32_t burstSize = virtual->fifoSize >> 1; // burstSize = fifoSzie / 2
185
186 if (tx == NULL && rx == NULL) {
187 return HDF_ERR_INVALID_PARAM;
188 }
189
190 for (tmpLen = 0, len = msg->len; len > 0; len -= tmpLen) {
191 tmpLen = (len > burstSize) ? burstSize : len;
192 if (!VirtualSpiWriteFifo(virtual, tx, tmpLen)) {
193 HDF_LOGE("VirtualSpiTxRx: write fifo fail!");
194 return HDF_FAILURE;
195 }
196 tx = (tx == NULL) ? NULL : (tx + tmpLen);
197 if (tmpLen == burstSize) {
198 ret = OsalSemWait((struct OsalSem *)(&virtual->sem), WAIT_TIMEOUT);
199 if (ret != HDF_SUCCESS) {
200 HDF_LOGE("VirtualSpiTxRx: sem wait timeout, ret: %d!", ret);
201 return ret;
202 }
203 }
204
205 if (!VirtualSpiReadFifo(virtual, rx, tmpLen)) {
206 HDF_LOGE("VirtualSpiTxRx: read fifo fail!");
207 return HDF_FAILURE;
208 }
209 rx = (rx == NULL) ? NULL : (rx + tmpLen);
210 }
211 return HDF_SUCCESS;
212 }
213
VirtualSpiFindDeviceByCsNum(const struct VirtualSpi * virtual,uint32_t cs)214 static inline bool VirtualSpiFindDeviceByCsNum(const struct VirtualSpi *virtual, uint32_t cs)
215 {
216 if (virtual == NULL || virtual->numCs <= cs) {
217 return false;
218 }
219
220 return true;
221 }
222
VirtualSpiSetCfg(struct SpiCntlr * cntlr,struct SpiCfg * cfg)223 static int32_t VirtualSpiSetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
224 {
225 struct VirtualSpi *virtual = NULL;
226
227 if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
228 HDF_LOGE("VirtualSpiSetCfg: cntlr priv or cfg is null!");
229 return HDF_ERR_INVALID_PARAM;
230 }
231 virtual = (struct VirtualSpi *)cntlr->priv;
232 if (!VirtualSpiFindDeviceByCsNum(virtual, cntlr->curCs)) {
233 HDF_LOGE("VirtualSpiSetCfg: invalid cs %u!", cntlr->curCs);
234 return HDF_ERR_INVALID_PARAM;
235 }
236 virtual->cfg = *cfg;
237 return HDF_SUCCESS;
238 }
239
VirtualSpiGetCfg(struct SpiCntlr * cntlr,struct SpiCfg * cfg)240 static int32_t VirtualSpiGetCfg(struct SpiCntlr *cntlr, struct SpiCfg *cfg)
241 {
242 struct VirtualSpi *virtual = NULL;
243
244 if (cntlr == NULL || cntlr->priv == NULL || cfg == NULL) {
245 HDF_LOGE("VirtualSpiGetCfg: cntlr priv or cfg is null!");
246 return HDF_ERR_INVALID_PARAM;
247 }
248 virtual = (struct VirtualSpi *)cntlr->priv;
249 if (!VirtualSpiFindDeviceByCsNum(virtual, cntlr->curCs)) {
250 HDF_LOGE("VirtualSpiGetCfg: invalid cs %u!", cntlr->curCs);
251 return HDF_ERR_INVALID_PARAM;
252 }
253 *cfg = virtual->cfg;
254 return HDF_SUCCESS;
255 }
256
VirtualSpiTransferOneMessage(struct VirtualSpi * virtual,struct SpiMsg * msg)257 static int32_t VirtualSpiTransferOneMessage(struct VirtualSpi *virtual, struct SpiMsg *msg)
258 {
259 int32_t ret;
260
261 if (msg == NULL || (msg->rbuf == NULL && msg->wbuf == NULL)) {
262 HDF_LOGE("VirtualSpiTransferOneMessage: invalid parameter!");
263 return HDF_ERR_INVALID_PARAM;
264 }
265 virtual->speed = (msg->speed) == 0 ? DEFAULT_SPEED : msg->speed;
266
267 ret = RingBufferConfig(virtual);
268 if (ret != HDF_SUCCESS) {
269 return ret;
270 }
271
272 return VirtualSpiTxRx(virtual, msg);
273 }
274
VirtualSpiTransfer(struct SpiCntlr * cntlr,struct SpiMsg * msg,uint32_t count)275 static int32_t VirtualSpiTransfer(struct SpiCntlr *cntlr, struct SpiMsg *msg, uint32_t count)
276 {
277 int32_t ret;
278 uint32_t i;
279 struct VirtualSpi *virtual = NULL;
280
281 if (cntlr == NULL || cntlr->priv == NULL) {
282 HDF_LOGE("VirtualSpiTransfer: invalid controller!");
283 return HDF_ERR_INVALID_OBJECT;
284 }
285 if (msg == NULL || count == 0) {
286 HDF_LOGE("VirtualSpiTransfer: invalid parameter!");
287 return HDF_ERR_INVALID_PARAM;
288 }
289
290 virtual = (struct VirtualSpi *)cntlr->priv;
291 if (!VirtualSpiFindDeviceByCsNum(virtual, cntlr->curCs)) {
292 HDF_LOGE("VirtualSpiTransfer: invalid cs %u!", cntlr->curCs);
293 return HDF_FAILURE;
294 }
295 for (i = 0; i < count; i++) {
296 ret = VirtualSpiTransferOneMessage(virtual, &(msg[i]));
297 if (ret != 0) {
298 HDF_LOGE("VirtualSpiTransfer: transfer error, ret: %d!", ret);
299 return ret;
300 }
301 }
302 return HDF_SUCCESS;
303 }
304
VirtualSpiOpen(struct SpiCntlr * cntlr)305 int32_t VirtualSpiOpen(struct SpiCntlr *cntlr)
306 {
307 (void)cntlr;
308 return HDF_SUCCESS;
309 }
310
VirtualSpiClose(struct SpiCntlr * cntlr)311 int32_t VirtualSpiClose(struct SpiCntlr *cntlr)
312 {
313 (void)cntlr;
314 return HDF_SUCCESS;
315 }
316
317 static struct SpiCntlrMethod g_method = {
318 .Transfer = VirtualSpiTransfer,
319 .SetCfg = VirtualSpiSetCfg,
320 .GetCfg = VirtualSpiGetCfg,
321 .Open = VirtualSpiOpen,
322 .Close = VirtualSpiClose,
323 };
324
SpiGetCfgFromHcs(struct VirtualSpi * virtual,const struct DeviceResourceNode * node)325 static int32_t SpiGetCfgFromHcs(struct VirtualSpi *virtual, const struct DeviceResourceNode *node)
326 {
327 struct DeviceResourceIface *iface = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
328
329 if (iface == NULL || iface->GetUint32 == NULL || iface->GetUint16 == NULL || iface->GetUint8 == NULL) {
330 HDF_LOGE("SpiGetCfgFromHcs: face is invalid!");
331 return HDF_FAILURE;
332 }
333 if (iface->GetUint32(node, "busNum", &virtual->busNum, DEFAULT_BUS_NUM) != HDF_SUCCESS) {
334 HDF_LOGE("SpiGetCfgFromHcs: read busNum fail!");
335 return HDF_FAILURE;
336 }
337 if (iface->GetUint32(node, "numCs", &virtual->numCs, 0) != HDF_SUCCESS) {
338 HDF_LOGE("SpiGetCfgFromHcs: read numCs fail!");
339 return HDF_FAILURE;
340 }
341 if (iface->GetUint32(node, "speed", &virtual->speed, 0) != HDF_SUCCESS) {
342 HDF_LOGE("SpiGetCfgFromHcs: read speed fail!");
343 return HDF_FAILURE;
344 }
345 if (iface->GetUint32(node, "fifoSize", &virtual->fifoSize, 0) != HDF_SUCCESS) {
346 HDF_LOGE("SpiGetCfgFromHcs: read fifoSize fail!");
347 return HDF_FAILURE;
348 }
349 if (iface->GetUint16(node, "mode", &virtual->cfg.mode, 0) != HDF_SUCCESS) {
350 HDF_LOGE("SpiGetCfgFromHcs: read mode fail!");
351 return HDF_FAILURE;
352 }
353 if (iface->GetUint8(node, "bitsPerWord", &virtual->cfg.bitsPerWord, 0) != HDF_SUCCESS) {
354 HDF_LOGE("SpiGetCfgFromHcs: read bitsPerWord fail!");
355 return HDF_FAILURE;
356 }
357 if (iface->GetUint8(node, "transferMode", &virtual->cfg.transferMode, 0) != HDF_SUCCESS) {
358 HDF_LOGE("SpiGetCfgFromHcs: read transferMode fail!");
359 return HDF_FAILURE;
360 }
361 if (iface->GetUint32(node, "maxSpeedHz", &virtual->cfg.maxSpeedHz, 0) != HDF_SUCCESS) {
362 HDF_LOGE("SpiGetCfgFromHcs: read maxSpeedHz fail!");
363 return HDF_FAILURE;
364 }
365 if (iface->GetUint16(node, "waterline", &virtual->waterline, 0) != HDF_SUCCESS) {
366 HDF_LOGE("SpiGetCfgFromHcs: read waterline fail!");
367 return HDF_FAILURE;
368 }
369 return HDF_SUCCESS;
370 }
371
VirtualSpiInit(struct SpiCntlr * cntlr,const struct HdfDeviceObject * device)372 static int32_t VirtualSpiInit(struct SpiCntlr *cntlr, const struct HdfDeviceObject *device)
373 {
374 int32_t ret;
375 struct VirtualSpi *virtual = NULL;
376
377 if (device->property == NULL) {
378 HDF_LOGE("VirtualSpiInit: property is null!");
379 return HDF_ERR_INVALID_PARAM;
380 }
381
382 virtual = (struct VirtualSpi *)OsalMemCalloc(sizeof(*virtual));
383 if (virtual == NULL) {
384 HDF_LOGE("VirtualSpiInit: OsalMemCalloc error!");
385 return HDF_FAILURE;
386 }
387 ret = SpiGetCfgFromHcs(virtual, device->property);
388 if (ret != HDF_SUCCESS) {
389 HDF_LOGE("VirtualSpiInit: SpiGetCfgFromHcs error, ret: %d!", ret);
390 OsalMemFree(virtual);
391 return ret;
392 }
393
394 virtual->cntlr = cntlr;
395 cntlr->priv = (void *)virtual;
396 cntlr->method = &g_method;
397 ret = OsalSemInit(&virtual->sem, 0);
398 if (ret != HDF_SUCCESS) {
399 return ret;
400 }
401 if (OsalSpinInit(&virtual->lock) != HDF_SUCCESS) {
402 HDF_LOGE("VirtualSpiInit: init lock fail!");
403 return HDF_FAILURE;
404 }
405
406 return HDF_SUCCESS;
407 }
408
VirtualSpiDeviceBind(struct HdfDeviceObject * device)409 static int32_t VirtualSpiDeviceBind(struct HdfDeviceObject *device)
410 {
411 HDF_LOGI("VirtualSpiDeviceBind: entry!");
412 if (device == NULL) {
413 return HDF_ERR_INVALID_OBJECT;
414 }
415 return (SpiCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
416 }
417
VirtualSpiDeviceInit(struct HdfDeviceObject * device)418 static int32_t VirtualSpiDeviceInit(struct HdfDeviceObject *device)
419 {
420 int32_t ret;
421 struct SpiCntlr *cntlr = NULL;
422
423 if (device == NULL) {
424 HDF_LOGE("VirtualSpiDeviceInit: device is null!");
425 return HDF_ERR_INVALID_OBJECT;
426 }
427 cntlr = SpiCntlrFromDevice(device);
428 if (cntlr == NULL) {
429 HDF_LOGE("VirtualSpiDeviceInit: cntlr is null!");
430 return HDF_FAILURE;
431 }
432
433 ret = VirtualSpiInit(cntlr, device);
434 if (ret != HDF_SUCCESS) {
435 HDF_LOGE("VirtualSpiDeviceInit: error init, ret: %d!", ret);
436 return ret;
437 }
438 ret = RingBufferConfig((struct VirtualSpi *)cntlr->priv);
439 if (ret != HDF_SUCCESS) {
440 HDF_LOGE("VirtualSpiDeviceInit: RingBufferConfig error!");
441 } else {
442 HDF_LOGI("VirtualSpiDeviceInit: spi device init success!");
443 }
444
445 return ret;
446 }
447
VirtualSpiDeviceRelease(struct HdfDeviceObject * device)448 static void VirtualSpiDeviceRelease(struct HdfDeviceObject *device)
449 {
450 struct SpiCntlr *cntlr = NULL;
451 struct VirtualSpi *virtual = NULL;
452
453 HDF_LOGI("VirtualSpiDeviceRelease: entry!");
454 if (device == NULL) {
455 HDF_LOGE("VirtualSpiDeviceRelease: device is null!");
456 return;
457 }
458 cntlr = SpiCntlrFromDevice(device);
459 if (cntlr == NULL || cntlr->priv == NULL) {
460 HDF_LOGE("VirtualSpiDeviceRelease: cntlr or priv is null!");
461 return;
462 }
463 SpiCntlrDestroy(cntlr);
464 virtual = (struct VirtualSpi *)cntlr->priv;
465 (void)OsalSpinDestroy(&(virtual->lock));
466 (void)OsalSemDestroy(&virtual->sem);
467 OsalMemFree(virtual->ringBuffer);
468 OsalMemFree(virtual);
469 }
470
471 static const struct HdfDriverEntry g_virtualSpiDevice = {
472 .moduleVersion = 1,
473 .moduleName = "virtual_spi_driver",
474 .Bind = VirtualSpiDeviceBind,
475 .Init = VirtualSpiDeviceInit,
476 .Release = VirtualSpiDeviceRelease,
477 };
478
479 HDF_INIT(g_virtualSpiDevice);
480