1 /*
2 * Copyright (c) 2022-2023 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 <securec.h>
11 #include "i2c_core.h"
12 #include "i2c_if.h"
13 #include "wm_i2c.h"
14 #include "wm_gpio_afsel.h"
15 #include "device_resource_if.h"
16 #include "osal_mutex.h"
17
18 #define DEC_NUM 10
19 #define GROUP_PIN_NUM 8
20 #define I2C_INVALID_ADDR 0xFFFF
21 #define HAL_I2C_ID_NUM 1
22
23 struct I2cResource {
24 uint32_t port;
25 uint32_t sclPin;
26 uint32_t sdaPin;
27 uint32_t speed;
28 };
29
30 struct I2cDevice {
31 uint16_t devAddr; /**< device addr */
32 uint32_t addressWidth; /**< Addressing mode: 7 bit or 10 bit */
33 struct OsalMutex mutex;
34 uint32_t port;
35 struct I2cResource resource;
36 };
37
38 /* HdfDriverEntry method definitions */
39 static int32_t i2cDriverBind(struct HdfDeviceObject *device);
40 static int32_t i2cDriverInit(struct HdfDeviceObject *device);
41 static void i2cDriverRelease(struct HdfDeviceObject *device);
42
43 /* HdfDriverEntry definitions */
44 struct HdfDriverEntry g_i2cDriverEntry = {
45 .moduleVersion = 1,
46 .moduleName = "W800_I2C_MODULE_HDF",
47 .Bind = i2cDriverBind,
48 .Init = i2cDriverInit,
49 .Release = i2cDriverRelease,
50 };
51
52 // Initialize HdfDriverEntry
53 HDF_INIT(g_i2cDriverEntry);
54
55 /* I2cHostMethod method definitions */
56 static int32_t i2cHostTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count);
57
58 struct I2cMethod g_i2cHostMethod = {
59 .transfer = i2cHostTransfer,
60 };
61
InitI2cDevice(struct I2cDevice * device)62 static int32_t InitI2cDevice(struct I2cDevice *device)
63 {
64 uint32_t i2cPort;
65 struct I2cResource *resource = NULL;
66
67 if (device == NULL) {
68 HDF_LOGE("device is NULL\r\n");
69 return HDF_ERR_INVALID_PARAM;
70 }
71
72 resource = &device->resource;
73 device->port = resource->port;
74 i2cPort = device->port;
75 if (i2cPort >= HAL_I2C_ID_NUM) {
76 HDF_LOGE("i2c port %u not support\r\n", i2cPort);
77 return HDF_ERR_NOT_SUPPORT;
78 }
79
80 if (OsalMutexInit(&device->mutex) != HDF_SUCCESS) {
81 HDF_LOGE("%s %d OsalMutexInit fail\r\n", __func__, __LINE__);
82 return HDF_FAILURE;
83 }
84
85 if (HDF_SUCCESS != OsalMutexLock(&device->mutex)) {
86 HDF_LOGE("%s %d osMutexWait fail\r\n", __func__, __LINE__);
87 return HDF_ERR_TIMEOUT;
88 }
89
90 if ((resource->sclPin == WM_IO_PA_01) && (resource->sdaPin == WM_IO_PA_04)) {
91 wm_i2c_scl_config(WM_IO_PA_01);
92 wm_i2c_sda_config(WM_IO_PA_04);
93 } else {
94 HDF_LOGE("%s %d scl sda pin fail\r\n", __func__, __LINE__);
95 OsalMutexUnlock(&device->mutex);
96 return HDF_ERR_INVALID_PARAM;
97 }
98
99 tls_i2c_init(resource->speed);
100 OsalMutexUnlock(&device->mutex);
101 return HDF_SUCCESS;
102 }
103
HostRestI2cDevice(struct I2cDevice * device)104 static int32_t HostRestI2cDevice(struct I2cDevice *device)
105 {
106 struct I2cResource *resource = NULL;
107 uint32_t i2cPort;
108
109 if (device == NULL) {
110 HDF_LOGE("%s %d device is null\r\n", __func__, __LINE__);
111 return HDF_ERR_INVALID_PARAM;
112 }
113 resource = &device->resource;
114 if (resource == NULL) {
115 HDF_LOGE("%s %d: invalid parameter\r\n", __func__, __LINE__);
116 return HDF_ERR_INVALID_OBJECT;
117 }
118 device->port = resource->port;
119 i2cPort = device->port;
120 if (i2cPort > HAL_I2C_ID_NUM) {
121 HDF_LOGE("i2c port %u not support\r\n", i2cPort);
122 return HDF_ERR_NOT_SUPPORT;
123 }
124
125 return HDF_SUCCESS;
126 }
127
GetI2cDeviceResource(struct I2cDevice * device,const struct DeviceResourceNode * resourceNode)128 static uint32_t GetI2cDeviceResource(struct I2cDevice *device,
129 const struct DeviceResourceNode *resourceNode)
130 {
131 uint32_t tempPin = 0;
132 struct I2cResource *resource = NULL;
133 struct DeviceResourceIface *dri = NULL;
134 if (device == NULL || resourceNode == NULL) {
135 HDF_LOGE("device or resourceNode is NULL\r\n");
136 return HDF_ERR_INVALID_PARAM;
137 }
138 resource = &device->resource;
139 if (resource == NULL) {
140 HDF_LOGE("%s %d: invalid parameter\r\n", __func__, __LINE__);
141 return HDF_ERR_INVALID_OBJECT;
142 }
143 dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
144 if (dri == NULL || dri->GetUint32 == NULL) {
145 HDF_LOGE("DeviceResourceIface is invalid\r\n");
146 return HDF_ERR_INVALID_OBJECT;
147 }
148
149 if (dri->GetUint32(resourceNode, "port", &resource->port, 0) != HDF_SUCCESS) {
150 HDF_LOGE("i2c config port fail\r\n");
151 return HDF_FAILURE;
152 }
153
154 if (dri->GetUint32(resourceNode, "sclPin", &tempPin, 0) != HDF_SUCCESS) {
155 HDF_LOGE("i2c config sclPin fail\r\n");
156 return HDF_FAILURE;
157 }
158 resource->sclPin = ((tempPin / DEC_NUM) * GROUP_PIN_NUM) + (tempPin % DEC_NUM);
159
160 if (dri->GetUint32(resourceNode, "sdaPin", &tempPin, 0) != HDF_SUCCESS) {
161 HDF_LOGE("i2c config sdaPin fail\r\n");
162 return HDF_FAILURE;
163 }
164 resource->sdaPin = ((tempPin / DEC_NUM) * GROUP_PIN_NUM) + (tempPin % DEC_NUM);
165
166 if (dri->GetUint32(resourceNode, "speed", &resource->speed, 0) != HDF_SUCCESS) {
167 HDF_LOGE("i2c config speed fail\r\n");
168 return HDF_FAILURE;
169 }
170
171 return HDF_SUCCESS;
172 }
173
AttachI2cDevice(struct I2cCntlr * host,const struct HdfDeviceObject * device)174 static int32_t AttachI2cDevice(struct I2cCntlr *host, const struct HdfDeviceObject *device)
175 {
176 int32_t ret;
177 struct I2cDevice *i2cDevice = NULL;
178 struct I2cResource *resource = NULL;
179
180 if (device == NULL || host == NULL) {
181 HDF_LOGE("%s: device or host is NULL\r\n", __func__);
182 return HDF_ERR_INVALID_PARAM;
183 }
184 i2cDevice = (struct I2cDevice *)OsalMemAlloc(sizeof(struct I2cDevice));
185 if (i2cDevice == NULL) {
186 HDF_LOGE("%s: OsalMemAlloc i2cDevice error\r\n", __func__);
187 return HDF_ERR_MALLOC_FAIL;
188 }
189 (void)memset_s(i2cDevice, sizeof(struct I2cDevice), 0, sizeof(struct I2cDevice));
190 ret = GetI2cDeviceResource(i2cDevice, device->property);
191 if (ret != HDF_SUCCESS) {
192 OsalMemFree(i2cDevice);
193 return HDF_FAILURE;
194 }
195 resource = &i2cDevice->resource;
196 if (resource == NULL) {
197 HDF_LOGE("%s %d: invalid parameter\r\n", __func__, __LINE__);
198 return HDF_ERR_INVALID_OBJECT;
199 }
200
201 host->priv = i2cDevice;
202 host->busId = i2cDevice->port;
203
204 return InitI2cDevice(i2cDevice);
205 }
206
i2cDriverInit(struct HdfDeviceObject * device)207 static int32_t i2cDriverInit(struct HdfDeviceObject *device)
208 {
209 int32_t ret;
210 struct I2cCntlr *host = NULL;
211 if (device == NULL) {
212 HDF_LOGE("%s: device is NULL\r\n", __func__);
213 return HDF_ERR_INVALID_PARAM;
214 }
215
216 host = (struct I2cCntlr *)OsalMemAlloc(sizeof(struct I2cCntlr));
217 if (host == NULL) {
218 HDF_LOGE("%s: host is NULL\r\n", __func__);
219 return HDF_ERR_MALLOC_FAIL;
220 }
221 (void)memset_s(host, sizeof(struct I2cCntlr), 0, sizeof(struct I2cCntlr));
222 host->ops = &g_i2cHostMethod;
223 device->priv = (void *)host;
224 ret = AttachI2cDevice(host, device);
225 if (ret != HDF_SUCCESS) {
226 HDF_LOGE("%s: attach error\r\n", __func__);
227 i2cDriverRelease(device);
228 return HDF_DEV_ERR_ATTACHDEV_FAIL;
229 }
230 ret = I2cCntlrAdd(host);
231 if (ret != HDF_SUCCESS) {
232 i2cDriverRelease(device);
233 return HDF_FAILURE;
234 }
235 return ret;
236 }
237
i2cDriverBind(struct HdfDeviceObject * device)238 static int32_t i2cDriverBind(struct HdfDeviceObject *device)
239 {
240 if (device == NULL) {
241 HDF_LOGE("%s: I2c device object is NULL\r\n", __func__);
242 return HDF_FAILURE;
243 }
244 return HDF_SUCCESS;
245 }
246
i2cDriverRelease(struct HdfDeviceObject * device)247 static void i2cDriverRelease(struct HdfDeviceObject *device)
248 {
249 struct I2cCntlr *i2cCntrl = NULL;
250 struct I2cDevice *i2cDevice = NULL;
251
252 if (device == NULL) {
253 HDF_LOGE("%s: device is NULL\r\n", __func__);
254 return;
255 }
256 i2cCntrl = device->priv;
257 if (i2cCntrl == NULL || i2cCntrl->priv == NULL) {
258 HDF_LOGE("%s: i2cCntrl is NULL\r\n", __func__);
259 return;
260 }
261 i2cCntrl->ops = NULL;
262 i2cDevice = (struct I2cDevice *)i2cCntrl->priv;
263 OsalMemFree(i2cCntrl);
264
265 if (i2cDevice != NULL) {
266 OsalMutexDestroy(&i2cDevice->mutex);
267 OsalMemFree(i2cDevice);
268 }
269 }
270
i2c_send(struct I2cMsg * msg)271 static int32_t i2c_send(struct I2cMsg *msg)
272 {
273 uint16_t len;
274 uint8_t ifack;
275 uint8_t ifstop;
276 uint8_t ifstart;
277
278 len = msg->len;
279 ifstop = 0;
280 if (msg->flags & I2C_FLAG_READ) {
281 ifack = (msg->flags & I2C_FLAG_READ_NO_ACK) ? 0 : 1;
282 for (int32_t j = 0; j < len; j++) {
283 if (((msg->flags & I2C_FLAG_STOP) && j) == (len - 1)) {
284 ifstop = 1;
285 }
286 msg->buf[j] = tls_i2c_read_byte(ifack, ifstop);
287 }
288 } else {
289 ifack = (msg->flags & I2C_FLAG_IGNORE_NO_ACK) ? 0 : 1;
290 for (int32_t j = 0; j < len; j++) {
291 if (((msg->flags & I2C_FLAG_NO_START) == 0) && (j == 0)) {
292 ifstart = 1;
293 }
294 tls_i2c_write_byte(msg->buf[j], ifstart);
295 if (ifack) {
296 tls_i2c_wait_ack();
297 }
298 }
299 }
300 }
301
i2c_transfer(struct I2cDevice * device,struct I2cMsg * msgs,int16_t count)302 static int32_t i2c_transfer(struct I2cDevice *device, struct I2cMsg *msgs, int16_t count)
303 {
304 struct I2cMsg *msg = NULL;
305
306 uint32_t i2cPort;
307 if (device == NULL || msgs == NULL) {
308 HDF_LOGE("%s: device or msgs is NULL\r\n", __func__);
309 return HDF_ERR_INVALID_PARAM;
310 }
311 i2cPort = (uint32_t)device->port;
312 if (i2cPort > HAL_I2C_ID_NUM) {
313 HDF_LOGE("i2c port %u not support\r\n", i2cPort);
314 return HDF_ERR_NOT_SUPPORT;
315 }
316 if (HDF_SUCCESS != OsalMutexLock(&device->mutex)) {
317 HDF_LOGE("%s %d OsalMutexTimedLock fail\r\n", __func__, __LINE__);
318 return HDF_ERR_TIMEOUT;
319 }
320 for (int32_t i = 0; i < count; i++) {
321 msg = &msgs[i];
322 i2c_send(msg);
323 }
324 OsalMutexUnlock(&device->mutex);
325 return count;
326 }
327
i2cHostTransfer(struct I2cCntlr * cntlr,struct I2cMsg * msgs,int16_t count)328 static int32_t i2cHostTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
329 {
330 struct I2cDevice *device = NULL;
331
332 if (cntlr == NULL || msgs == NULL || cntlr->priv == NULL) {
333 HDF_LOGE("%s: I2cCntlr or msgs is NULL\r\n", __func__);
334 return HDF_ERR_INVALID_PARAM;
335 }
336 device = (struct I2cDevice *)cntlr->priv;
337 return i2c_transfer(device, msgs, count);
338 }
339