1 /*
2 * Copyright (c) 2020-2021 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 "spi_core.h"
10 #include "hdf_log.h"
11 #include "osal_mem.h"
12 #include "spi_if.h"
13
14 #define HDF_LOG_TAG spi_core
15
SpiCntlrOpen(struct SpiCntlr * cntlr,uint32_t csNum)16 int32_t SpiCntlrOpen(struct SpiCntlr *cntlr, uint32_t csNum)
17 {
18 int32_t ret;
19
20 if (cntlr == NULL) {
21 HDF_LOGE("%s: invalid parameter", __func__);
22 return HDF_ERR_INVALID_PARAM;
23 }
24 if (cntlr->method == NULL || cntlr->method->Open == NULL) {
25 HDF_LOGE("%s: Open not support", __func__);
26 return HDF_ERR_NOT_SUPPORT;
27 }
28 (void)OsalMutexLock(&(cntlr->lock));
29 cntlr->curCs = csNum;
30 ret = cntlr->method->Open(cntlr);
31 (void)OsalMutexUnlock(&(cntlr->lock));
32 return ret;
33 }
34
SpiCntlrClose(struct SpiCntlr * cntlr,uint32_t csNum)35 int32_t SpiCntlrClose(struct SpiCntlr *cntlr, uint32_t csNum)
36 {
37 int32_t ret;
38
39 if (cntlr == NULL) {
40 HDF_LOGE("%s: invalid parameter", __func__);
41 return HDF_ERR_INVALID_PARAM;
42 }
43 if (cntlr->method == NULL || cntlr->method->Close == NULL) {
44 HDF_LOGE("%s: Close not support", __func__);
45 return HDF_ERR_NOT_SUPPORT;
46 }
47 (void)OsalMutexLock(&(cntlr->lock));
48 cntlr->curCs = csNum;
49 ret = cntlr->method->Close(cntlr);
50 (void)OsalMutexUnlock(&(cntlr->lock));
51 return ret;
52 }
53
SpiCntlrTransfer(struct SpiCntlr * cntlr,uint32_t csNum,struct SpiMsg * msg,uint32_t count)54 int32_t SpiCntlrTransfer(struct SpiCntlr *cntlr, uint32_t csNum, struct SpiMsg *msg, uint32_t count)
55 {
56 int32_t ret;
57
58 if (cntlr == NULL) {
59 HDF_LOGE("%s: invalid parameter", __func__);
60 return HDF_ERR_INVALID_PARAM;
61 }
62 if (cntlr->method == NULL || cntlr->method->Transfer == NULL) {
63 HDF_LOGE("%s: transfer not support", __func__);
64 return HDF_ERR_NOT_SUPPORT;
65 }
66
67 (void)OsalMutexLock(&(cntlr->lock));
68 cntlr->curCs = csNum;
69 ret = cntlr->method->Transfer(cntlr, msg, count);
70 (void)OsalMutexUnlock(&(cntlr->lock));
71 return ret;
72 }
73
SpiCntlrSetCfg(struct SpiCntlr * cntlr,uint32_t csNum,struct SpiCfg * cfg)74 int32_t SpiCntlrSetCfg(struct SpiCntlr *cntlr, uint32_t csNum, struct SpiCfg *cfg)
75 {
76 int32_t ret;
77
78 if (cntlr == NULL) {
79 HDF_LOGE("%s: invalid parameter", __func__);
80 return HDF_ERR_INVALID_PARAM;
81 }
82
83 if (cntlr->method == NULL || cntlr->method->SetCfg == NULL) {
84 HDF_LOGE("%s: not support", __func__);
85 return HDF_ERR_NOT_SUPPORT;
86 }
87
88 (void)OsalMutexLock(&(cntlr->lock));
89 cntlr->curCs = csNum;
90 ret = cntlr->method->SetCfg(cntlr, cfg);
91 (void)OsalMutexUnlock(&(cntlr->lock));
92 return ret;
93 }
94
SpiCntlrGetCfg(struct SpiCntlr * cntlr,uint32_t csNum,struct SpiCfg * cfg)95 int32_t SpiCntlrGetCfg(struct SpiCntlr *cntlr, uint32_t csNum, struct SpiCfg *cfg)
96 {
97 int32_t ret;
98
99 if (cntlr == NULL) {
100 HDF_LOGE("%s: invalid parameter", __func__);
101 return HDF_ERR_INVALID_PARAM;
102 }
103
104 if (cntlr->method == NULL || cntlr->method->GetCfg == NULL) {
105 HDF_LOGE("%s: not support", __func__);
106 return HDF_ERR_NOT_SUPPORT;
107 }
108
109 (void)OsalMutexLock(&(cntlr->lock));
110 cntlr->curCs = csNum;
111 ret = cntlr->method->GetCfg(cntlr, cfg);
112 (void)OsalMutexUnlock(&(cntlr->lock));
113 return ret;
114 }
115
SpiTransferRebuildMsgs(struct HdfSBuf * data,struct SpiMsg ** ppmsgs,uint32_t * pcount,uint8_t ** ppbuf)116 static int32_t SpiTransferRebuildMsgs(struct HdfSBuf *data, struct SpiMsg **ppmsgs, uint32_t *pcount, uint8_t **ppbuf)
117 {
118 uint32_t count;
119 int32_t i;
120 uint32_t len;
121 uint32_t lenReply = 0;
122 uint8_t *buf = NULL;
123 uint8_t *bufReply = NULL;
124 struct SpiMsg *msgs = NULL;
125
126 if (!HdfSbufReadBuffer(data, (const void **)&msgs, &len) || msgs == NULL || len == 0) {
127 HDF_LOGE("%s: read msgs fail!", __func__);
128 return HDF_ERR_IO;
129 }
130
131 count = (uint32_t)len / (uint32_t)sizeof(struct SpiMsg);
132 for (i = 0; i < count; i++) {
133 if (msgs[i].rbuf != NULL) {
134 lenReply += msgs[i].len;
135 }
136 if (msgs[i].wbuf == NULL) {
137 continue;
138 }
139 if (!HdfSbufReadBuffer(data, (const void **)&buf, &len)) {
140 HDF_LOGE("%s: read msg[%d] buf fail!", __func__, i);
141 } else {
142 msgs[i].wbuf = buf;
143 }
144 }
145
146 if (lenReply > 0) {
147 bufReply = OsalMemCalloc(lenReply);
148 if (bufReply == NULL) {
149 return HDF_ERR_MALLOC_FAIL;
150 }
151 for (i = 0, buf = bufReply; i < count && buf < (bufReply + lenReply); i++) {
152 if (msgs[i].rbuf != NULL) {
153 msgs[i].rbuf = buf;
154 buf += msgs[i].len;
155 }
156 }
157 }
158
159 *ppmsgs = msgs;
160 *pcount = count;
161 *ppbuf = bufReply;
162
163 return HDF_SUCCESS;
164 }
165
SpiTransferWriteBackMsgs(struct HdfSBuf * reply,struct SpiMsg * msgs,uint32_t count)166 static int32_t SpiTransferWriteBackMsgs(struct HdfSBuf *reply, struct SpiMsg *msgs, uint32_t count)
167 {
168 uint32_t i;
169
170 for (i = 0; i < count; i++) {
171 if (msgs[i].rbuf == NULL) {
172 continue;
173 }
174
175 if (!HdfSbufWriteBuffer(reply, msgs[i].rbuf, msgs[i].len)) {
176 HDF_LOGE("%s: write msg[%d] reply failed!", __func__, i);
177 return HDF_ERR_IO;
178 }
179 }
180
181 return HDF_SUCCESS;
182 }
183
SpiIoTransfer(struct SpiCntlr * cntlr,uint32_t csNum,struct HdfSBuf * data,struct HdfSBuf * reply)184 static int32_t SpiIoTransfer(struct SpiCntlr *cntlr, uint32_t csNum, struct HdfSBuf *data, struct HdfSBuf *reply)
185 {
186 int32_t ret;
187 uint32_t count;
188 struct SpiMsg *msgs = NULL;
189 uint8_t *bufReply = NULL;
190
191 if (data == NULL || reply == NULL) {
192 return HDF_ERR_INVALID_PARAM;
193 }
194
195 ret = SpiTransferRebuildMsgs(data, &msgs, &count, &bufReply);
196 if (ret != HDF_SUCCESS) {
197 HDF_LOGE("%s: rebuild msgs fail:%d", __func__, ret);
198 goto EXIT;
199 }
200
201 ret = SpiCntlrTransfer(cntlr, csNum, msgs, count);
202 if (ret != HDF_SUCCESS) {
203 HDF_LOGE("%s: do transfer failed:%d", __func__, ret);
204 goto EXIT;
205 }
206
207 ret = SpiTransferWriteBackMsgs(reply, msgs, count);
208
209 EXIT:
210 if (bufReply != NULL) {
211 OsalMemFree(bufReply);
212 }
213 return ret;
214 }
215
SpiIoOpen(struct SpiCntlr * cntlr,uint32_t csNum)216 static int32_t SpiIoOpen(struct SpiCntlr *cntlr, uint32_t csNum)
217 {
218 return SpiCntlrOpen(cntlr, csNum);
219 }
220
SpiIoClose(struct SpiCntlr * cntlr,uint32_t csNum)221 static int32_t SpiIoClose(struct SpiCntlr *cntlr, uint32_t csNum)
222 {
223 return SpiCntlrClose(cntlr, csNum);
224 }
225
SpiIoSetConfig(struct SpiCntlr * cntlr,uint32_t csNum,struct HdfSBuf * data)226 static int32_t SpiIoSetConfig(struct SpiCntlr *cntlr, uint32_t csNum, struct HdfSBuf *data)
227 {
228 uint32_t len;
229 struct SpiCfg *cfg = NULL;
230
231 if (!HdfSbufReadBuffer(data, (const void **)&cfg, &len) || sizeof(*cfg) != len) {
232 HDF_LOGE("%s: read buffer failed!", __func__);
233 return HDF_ERR_IO;
234 }
235 return SpiCntlrSetCfg(cntlr, csNum, cfg);
236 }
237
SpiIoGetConfig(struct SpiCntlr * cntlr,uint32_t csNum,struct HdfSBuf * reply)238 static int32_t SpiIoGetConfig(struct SpiCntlr *cntlr, uint32_t csNum, struct HdfSBuf *reply)
239 {
240 int32_t ret;
241 struct SpiCfg cfg;
242
243 ret = SpiCntlrGetCfg(cntlr, csNum, &cfg);
244 if (ret != HDF_SUCCESS) {
245 HDF_LOGE("%s: get cfg failed!", __func__);
246 return ret;
247 }
248
249 if (!HdfSbufWriteBuffer(reply, &cfg, sizeof(cfg))) {
250 HDF_LOGE("%s: write buffer failed!", __func__);
251 return ret;
252 }
253 return HDF_SUCCESS;
254 }
255
SpiIoDispatch(struct HdfDeviceIoClient * client,int cmd,struct HdfSBuf * data,struct HdfSBuf * reply)256 static int32_t SpiIoDispatch(struct HdfDeviceIoClient *client, int cmd,
257 struct HdfSBuf *data, struct HdfSBuf *reply)
258 {
259 int32_t ret;
260 uint32_t csNum;
261 struct SpiCntlr *cntlr = NULL;
262
263 if (client == NULL || client->device == NULL || client->device->service == NULL) {
264 HDF_LOGE("%s: invalid client", __func__);
265 return HDF_ERR_INVALID_OBJECT;
266 }
267
268 cntlr = (struct SpiCntlr *)client->device->service;
269 if (data == NULL) {
270 HDF_LOGE("%s: data is NULL", __func__);
271 return HDF_ERR_INVALID_PARAM;
272 }
273
274 if (!HdfSbufReadUint32(data, &csNum)) {
275 HDF_LOGE("%s: read csNum failed!", __func__);
276 return HDF_ERR_IO;
277 }
278
279 switch (cmd) {
280 case SPI_IO_OPEN:
281 return SpiIoOpen(cntlr, csNum);
282 case SPI_IO_CLOSE:
283 return SpiIoClose(cntlr, csNum);
284 case SPI_IO_SET_CONFIG:
285 return SpiIoSetConfig(cntlr, csNum, data);
286 case SPI_IO_GET_CONFIG:
287 return SpiIoGetConfig(cntlr, csNum, reply);
288 case SPI_IO_TRANSFER:
289 return SpiIoTransfer(cntlr, csNum, data, reply);
290 default:
291 ret = HDF_ERR_NOT_SUPPORT;
292 break;
293 }
294 return ret;
295 }
296
SpiCntlrDestroy(struct SpiCntlr * cntlr)297 void SpiCntlrDestroy(struct SpiCntlr *cntlr)
298 {
299 if (cntlr == NULL) {
300 return;
301 }
302 (void)OsalMutexDestroy(&(cntlr->lock));
303 OsalMemFree(cntlr);
304 }
305
SpiCntlrCreate(struct HdfDeviceObject * device)306 struct SpiCntlr *SpiCntlrCreate(struct HdfDeviceObject *device)
307 {
308 struct SpiCntlr *cntlr = NULL;
309
310 if (device == NULL) {
311 HDF_LOGE("%s: invalid parameter", __func__);
312 return NULL;
313 }
314
315 cntlr = (struct SpiCntlr *)OsalMemCalloc(sizeof(*cntlr));
316 if (cntlr == NULL) {
317 HDF_LOGE("%s: OsalMemCalloc error", __func__);
318 return NULL;
319 }
320 cntlr->device = device;
321 device->service = &(cntlr->service);
322 device->service->Dispatch = SpiIoDispatch;
323 (void)OsalMutexInit(&cntlr->lock);
324 DListHeadInit(&cntlr->list);
325 cntlr->priv = NULL;
326 return cntlr;
327 }
328