1 /*
2 * i2c_adapter.h
3 *
4 * i2c driver adapter of linux
5 *
6 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19 #include <linux/i2c.h>
20 #include "hdf_device_desc.h"
21 #include "hdf_log.h"
22 #include "i2c_core.h"
23 #include "osal_mem.h"
24
25 #define HDF_LOG_TAG i2c_linux_adapter
26
CreateLinuxI2cMsgs(struct I2cMsg * msgs,int16_t count)27 static struct i2c_msg *CreateLinuxI2cMsgs(struct I2cMsg *msgs, int16_t count)
28 {
29 int16_t i;
30 struct i2c_msg *linuxMsgs = NULL;
31
32 linuxMsgs = (struct i2c_msg *)OsalMemCalloc(sizeof(*linuxMsgs) * count);
33 if (linuxMsgs == NULL) {
34 HDF_LOGE("%s: malloc linux msgs fail!", __func__);
35 return NULL;
36 }
37
38 for (i = 0; i < count; i++) {
39 linuxMsgs[i].addr = msgs[i].addr;
40 linuxMsgs[i].buf = msgs[i].buf;
41 linuxMsgs[i].len = msgs[i].len;
42 linuxMsgs[i].flags = msgs[i].flags;
43 }
44 return linuxMsgs;
45 }
46
FreeLinxI2cMsgs(struct i2c_msg * msgs,int16_t count)47 static inline void FreeLinxI2cMsgs(struct i2c_msg *msgs, int16_t count)
48 {
49 OsalMemFree(msgs);
50 (void)count;
51 }
52
LinuxI2cTransfer(struct I2cCntlr * cntlr,struct I2cMsg * msgs,int16_t count)53 static int32_t LinuxI2cTransfer(struct I2cCntlr *cntlr, struct I2cMsg *msgs, int16_t count)
54 {
55 int32_t ret;
56 struct i2c_msg *linuxMsgs = NULL;
57
58 if (cntlr == NULL || cntlr->priv == NULL) {
59 HDF_LOGE("%s: cntlr or priv is null!", __func__);
60 return HDF_ERR_INVALID_OBJECT;
61 }
62 if (msgs == NULL || count <= 0) {
63 HDF_LOGE("%s: err params! count:%d", __func__, count);
64 return HDF_ERR_INVALID_PARAM;
65 }
66
67 linuxMsgs = CreateLinuxI2cMsgs(msgs, count);
68 if (linuxMsgs == NULL) {
69 return HDF_ERR_MALLOC_FAIL;
70 }
71
72 ret = i2c_transfer((struct i2c_adapter *)cntlr->priv, linuxMsgs, count);
73 FreeLinxI2cMsgs(linuxMsgs, count);
74 return ret;
75 }
76
77 static struct I2cMethod g_method = {
78 .transfer = LinuxI2cTransfer,
79 };
80
LinuxI2cBind(struct HdfDeviceObject * device)81 static int32_t LinuxI2cBind(struct HdfDeviceObject *device)
82 {
83 (void)device;
84 return HDF_SUCCESS;
85 }
86
LinuxI2cRemove(struct device * dev,void * data)87 static int LinuxI2cRemove(struct device *dev, void *data)
88 {
89 struct I2cCntlr *cntlr = NULL;
90 struct i2c_adapter *adapter = NULL;
91
92 HDF_LOGI("%s: Enter", __func__);
93 (void)data;
94
95 if (dev == NULL) {
96 HDF_LOGE("%s: dev is null", __func__);
97 return HDF_ERR_INVALID_OBJECT;
98 }
99
100 if (dev->type != &i2c_adapter_type) {
101 return HDF_SUCCESS; // continue remove
102 }
103
104 adapter = to_i2c_adapter(dev);
105 cntlr = I2cCntlrGet(adapter->nr);
106 if (cntlr != NULL) {
107 I2cCntlrPut(cntlr);
108 I2cCntlrRemove(cntlr);
109 i2c_put_adapter(adapter);
110 OsalMemFree(cntlr);
111 }
112 return HDF_SUCCESS;
113 }
114
LinuxI2cProbe(struct device * dev,void * data)115 static int LinuxI2cProbe(struct device *dev, void *data)
116 {
117 int32_t ret;
118 struct I2cCntlr *cntlr = NULL;
119 struct i2c_adapter *adapter = NULL;
120
121 (void)data;
122
123 if (dev == NULL) {
124 HDF_LOGE("%s: dev is null", __func__);
125 return HDF_ERR_INVALID_OBJECT;
126 }
127
128 if (dev->type != &i2c_adapter_type) {
129 return HDF_SUCCESS; // continue probe
130 }
131
132 HDF_LOGI("%s: Enter", __func__);
133 adapter = to_i2c_adapter(dev);
134 cntlr = (struct I2cCntlr *)OsalMemCalloc(sizeof(*cntlr));
135 if (cntlr == NULL) {
136 HDF_LOGE("%s: malloc cntlr fail!", __func__);
137 i2c_put_adapter(adapter);
138 return HDF_ERR_MALLOC_FAIL;
139 }
140
141 cntlr->busId = adapter->nr;
142 cntlr->priv = adapter;
143 cntlr->ops = &g_method;
144 ret = I2cCntlrAdd(cntlr);
145 if (ret != HDF_SUCCESS) {
146 i2c_put_adapter(adapter);
147 OsalMemFree(cntlr);
148 cntlr = NULL;
149 HDF_LOGE("%s: add controller fail:%d", __func__, ret);
150 return ret;
151 }
152 HDF_LOGI("%s: i2c adapter %d add success", __func__, cntlr->busId);
153 return HDF_SUCCESS;
154 }
155
LinuxI2cInit(struct HdfDeviceObject * device)156 static int32_t LinuxI2cInit(struct HdfDeviceObject *device)
157 {
158 int32_t ret;
159
160 HDF_LOGI("%s: Enter", __func__);
161 if (device == NULL) {
162 HDF_LOGE("%s: device is NULL", __func__);
163 return HDF_ERR_INVALID_OBJECT;
164 }
165
166 ret = i2c_for_each_dev(NULL, LinuxI2cProbe);
167 HDF_LOGI("%s: done", __func__);
168 return ret;
169 }
170
LinuxI2cRelease(struct HdfDeviceObject * device)171 static void LinuxI2cRelease(struct HdfDeviceObject *device)
172 {
173 HDF_LOGI("%s: enter", __func__);
174 if (device == NULL) {
175 HDF_LOGE("%s: device is NULL", __func__);
176 return;
177 }
178
179 (void)i2c_for_each_dev(NULL, LinuxI2cRemove);
180 }
181
182 struct HdfDriverEntry g_i2cLinuxDriverEntry = {
183 .moduleVersion = 1,
184 .Bind = LinuxI2cBind,
185 .Init = LinuxI2cInit,
186 .Release = LinuxI2cRelease,
187 .moduleName = "linux_i2c_adapter",
188 };
189 HDF_INIT(g_i2cLinuxDriverEntry);
190