1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Intel La Jolla Cove Adapter USB-I2C driver |
4 | * |
5 | * Copyright (c) 2023, Intel Corporation. |
6 | */ |
7 | |
8 | #include <linux/acpi.h> |
9 | #include <linux/auxiliary_bus.h> |
10 | #include <linux/bitfield.h> |
11 | #include <linux/bits.h> |
12 | #include <linux/dev_printk.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/module.h> |
15 | #include <linux/usb/ljca.h> |
16 | |
17 | /* I2C init flags */ |
18 | #define LJCA_I2C_INIT_FLAG_MODE BIT(0) |
19 | #define LJCA_I2C_INIT_FLAG_MODE_POLLING FIELD_PREP(LJCA_I2C_INIT_FLAG_MODE, 0) |
20 | #define LJCA_I2C_INIT_FLAG_MODE_INTERRUPT FIELD_PREP(LJCA_I2C_INIT_FLAG_MODE, 1) |
21 | |
22 | #define LJCA_I2C_INIT_FLAG_ADDR_16BIT BIT(0) |
23 | |
24 | #define LJCA_I2C_INIT_FLAG_FREQ GENMASK(2, 1) |
25 | #define LJCA_I2C_INIT_FLAG_FREQ_100K FIELD_PREP(LJCA_I2C_INIT_FLAG_FREQ, 0) |
26 | #define LJCA_I2C_INIT_FLAG_FREQ_400K FIELD_PREP(LJCA_I2C_INIT_FLAG_FREQ, 1) |
27 | #define LJCA_I2C_INIT_FLAG_FREQ_1M FIELD_PREP(LJCA_I2C_INIT_FLAG_FREQ, 2) |
28 | |
29 | #define LJCA_I2C_BUF_SIZE 60u |
30 | #define LJCA_I2C_MAX_XFER_SIZE (LJCA_I2C_BUF_SIZE - sizeof(struct ljca_i2c_rw_packet)) |
31 | |
32 | /* I2C commands */ |
33 | enum ljca_i2c_cmd { |
34 | LJCA_I2C_INIT = 1, |
35 | LJCA_I2C_XFER, |
36 | LJCA_I2C_START, |
37 | LJCA_I2C_STOP, |
38 | LJCA_I2C_READ, |
39 | LJCA_I2C_WRITE, |
40 | }; |
41 | |
42 | enum ljca_xfer_type { |
43 | LJCA_I2C_WRITE_XFER_TYPE, |
44 | LJCA_I2C_READ_XFER_TYPE, |
45 | }; |
46 | |
47 | /* I2C raw commands: Init/Start/Read/Write/Stop */ |
48 | struct ljca_i2c_rw_packet { |
49 | u8 id; |
50 | __le16 len; |
51 | u8 data[] __counted_by(len); |
52 | } __packed; |
53 | |
54 | struct ljca_i2c_dev { |
55 | struct ljca_client *ljca; |
56 | struct ljca_i2c_info *i2c_info; |
57 | struct i2c_adapter adap; |
58 | |
59 | u8 obuf[LJCA_I2C_BUF_SIZE]; |
60 | u8 ibuf[LJCA_I2C_BUF_SIZE]; |
61 | }; |
62 | |
63 | static int ljca_i2c_init(struct ljca_i2c_dev *ljca_i2c, u8 id) |
64 | { |
65 | struct ljca_i2c_rw_packet *w_packet = |
66 | (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; |
67 | int ret; |
68 | |
69 | w_packet->id = id; |
70 | w_packet->len = cpu_to_le16(sizeof(*w_packet->data)); |
71 | w_packet->data[0] = LJCA_I2C_INIT_FLAG_FREQ_400K; |
72 | |
73 | ret = ljca_transfer(client: ljca_i2c->ljca, cmd: LJCA_I2C_INIT, obuf: (u8 *)w_packet, |
74 | struct_size(w_packet, data, 1), NULL, ibuf_len: 0); |
75 | |
76 | return ret < 0 ? ret : 0; |
77 | } |
78 | |
79 | static int ljca_i2c_start(struct ljca_i2c_dev *ljca_i2c, u8 slave_addr, |
80 | enum ljca_xfer_type type) |
81 | { |
82 | struct ljca_i2c_rw_packet *w_packet = |
83 | (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; |
84 | struct ljca_i2c_rw_packet *r_packet = |
85 | (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; |
86 | s16 rp_len; |
87 | int ret; |
88 | |
89 | w_packet->id = ljca_i2c->i2c_info->id; |
90 | w_packet->len = cpu_to_le16(sizeof(*w_packet->data)); |
91 | w_packet->data[0] = (slave_addr << 1) | type; |
92 | |
93 | ret = ljca_transfer(client: ljca_i2c->ljca, cmd: LJCA_I2C_START, obuf: (u8 *)w_packet, |
94 | struct_size(w_packet, data, 1), ibuf: (u8 *)r_packet, |
95 | LJCA_I2C_BUF_SIZE); |
96 | if (ret < 0 || ret < sizeof(*r_packet)) |
97 | return ret < 0 ? ret : -EIO; |
98 | |
99 | rp_len = le16_to_cpu(r_packet->len); |
100 | if (rp_len < 0 || r_packet->id != w_packet->id) { |
101 | dev_dbg(&ljca_i2c->adap.dev, |
102 | "i2c start failed len: %d id: %d %d\n" , |
103 | rp_len, r_packet->id, w_packet->id); |
104 | return -EIO; |
105 | } |
106 | |
107 | return 0; |
108 | } |
109 | |
110 | static void ljca_i2c_stop(struct ljca_i2c_dev *ljca_i2c, u8 slave_addr) |
111 | { |
112 | struct ljca_i2c_rw_packet *w_packet = |
113 | (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; |
114 | struct ljca_i2c_rw_packet *r_packet = |
115 | (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; |
116 | s16 rp_len; |
117 | int ret; |
118 | |
119 | w_packet->id = ljca_i2c->i2c_info->id; |
120 | w_packet->len = cpu_to_le16(sizeof(*w_packet->data)); |
121 | w_packet->data[0] = 0; |
122 | |
123 | ret = ljca_transfer(client: ljca_i2c->ljca, cmd: LJCA_I2C_STOP, obuf: (u8 *)w_packet, |
124 | struct_size(w_packet, data, 1), ibuf: (u8 *)r_packet, |
125 | LJCA_I2C_BUF_SIZE); |
126 | if (ret < 0 || ret < sizeof(*r_packet)) { |
127 | dev_dbg(&ljca_i2c->adap.dev, |
128 | "i2c stop failed ret: %d id: %d\n" , |
129 | ret, w_packet->id); |
130 | return; |
131 | } |
132 | |
133 | rp_len = le16_to_cpu(r_packet->len); |
134 | if (rp_len < 0 || r_packet->id != w_packet->id) |
135 | dev_dbg(&ljca_i2c->adap.dev, |
136 | "i2c stop failed len: %d id: %d %d\n" , |
137 | rp_len, r_packet->id, w_packet->id); |
138 | } |
139 | |
140 | static int ljca_i2c_pure_read(struct ljca_i2c_dev *ljca_i2c, u8 *data, u8 len) |
141 | { |
142 | struct ljca_i2c_rw_packet *w_packet = |
143 | (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; |
144 | struct ljca_i2c_rw_packet *r_packet = |
145 | (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; |
146 | s16 rp_len; |
147 | int ret; |
148 | |
149 | w_packet->id = ljca_i2c->i2c_info->id; |
150 | w_packet->len = cpu_to_le16(len); |
151 | w_packet->data[0] = 0; |
152 | |
153 | ret = ljca_transfer(client: ljca_i2c->ljca, cmd: LJCA_I2C_READ, obuf: (u8 *)w_packet, |
154 | struct_size(w_packet, data, 1), ibuf: (u8 *)r_packet, |
155 | LJCA_I2C_BUF_SIZE); |
156 | if (ret < 0 || ret < sizeof(*r_packet)) |
157 | return ret < 0 ? ret : -EIO; |
158 | |
159 | rp_len = le16_to_cpu(r_packet->len); |
160 | if (rp_len != len || r_packet->id != w_packet->id) { |
161 | dev_dbg(&ljca_i2c->adap.dev, |
162 | "i2c raw read failed len: %d id: %d %d\n" , |
163 | rp_len, r_packet->id, w_packet->id); |
164 | return -EIO; |
165 | } |
166 | |
167 | memcpy(data, r_packet->data, len); |
168 | |
169 | return 0; |
170 | } |
171 | |
172 | static int ljca_i2c_read(struct ljca_i2c_dev *ljca_i2c, u8 slave_addr, u8 *data, |
173 | u8 len) |
174 | { |
175 | int ret; |
176 | |
177 | ret = ljca_i2c_start(ljca_i2c, slave_addr, type: LJCA_I2C_READ_XFER_TYPE); |
178 | if (!ret) |
179 | ret = ljca_i2c_pure_read(ljca_i2c, data, len); |
180 | |
181 | ljca_i2c_stop(ljca_i2c, slave_addr); |
182 | |
183 | return ret; |
184 | } |
185 | |
186 | static int ljca_i2c_pure_write(struct ljca_i2c_dev *ljca_i2c, u8 *data, u8 len) |
187 | { |
188 | struct ljca_i2c_rw_packet *w_packet = |
189 | (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; |
190 | struct ljca_i2c_rw_packet *r_packet = |
191 | (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; |
192 | s16 rplen; |
193 | int ret; |
194 | |
195 | w_packet->id = ljca_i2c->i2c_info->id; |
196 | w_packet->len = cpu_to_le16(len); |
197 | memcpy(w_packet->data, data, len); |
198 | |
199 | ret = ljca_transfer(client: ljca_i2c->ljca, cmd: LJCA_I2C_WRITE, obuf: (u8 *)w_packet, |
200 | struct_size(w_packet, data, len), ibuf: (u8 *)r_packet, |
201 | LJCA_I2C_BUF_SIZE); |
202 | if (ret < 0 || ret < sizeof(*r_packet)) |
203 | return ret < 0 ? ret : -EIO; |
204 | |
205 | rplen = le16_to_cpu(r_packet->len); |
206 | if (rplen != len || r_packet->id != w_packet->id) { |
207 | dev_dbg(&ljca_i2c->adap.dev, |
208 | "i2c write failed len: %d id: %d/%d\n" , |
209 | rplen, r_packet->id, w_packet->id); |
210 | return -EIO; |
211 | } |
212 | |
213 | return 0; |
214 | } |
215 | |
216 | static int ljca_i2c_write(struct ljca_i2c_dev *ljca_i2c, u8 slave_addr, |
217 | u8 *data, u8 len) |
218 | { |
219 | int ret; |
220 | |
221 | ret = ljca_i2c_start(ljca_i2c, slave_addr, type: LJCA_I2C_WRITE_XFER_TYPE); |
222 | if (!ret) |
223 | ret = ljca_i2c_pure_write(ljca_i2c, data, len); |
224 | |
225 | ljca_i2c_stop(ljca_i2c, slave_addr); |
226 | |
227 | return ret; |
228 | } |
229 | |
230 | static int ljca_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, |
231 | int num) |
232 | { |
233 | struct ljca_i2c_dev *ljca_i2c; |
234 | struct i2c_msg *cur_msg; |
235 | int i, ret; |
236 | |
237 | ljca_i2c = i2c_get_adapdata(adap: adapter); |
238 | if (!ljca_i2c) |
239 | return -EINVAL; |
240 | |
241 | for (i = 0; i < num; i++) { |
242 | cur_msg = &msg[i]; |
243 | if (cur_msg->flags & I2C_M_RD) |
244 | ret = ljca_i2c_read(ljca_i2c, slave_addr: cur_msg->addr, |
245 | data: cur_msg->buf, len: cur_msg->len); |
246 | else |
247 | ret = ljca_i2c_write(ljca_i2c, slave_addr: cur_msg->addr, |
248 | data: cur_msg->buf, len: cur_msg->len); |
249 | |
250 | if (ret) |
251 | return ret; |
252 | } |
253 | |
254 | return num; |
255 | } |
256 | |
257 | static u32 ljca_i2c_func(struct i2c_adapter *adap) |
258 | { |
259 | return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); |
260 | } |
261 | |
262 | static const struct i2c_adapter_quirks ljca_i2c_quirks = { |
263 | .flags = I2C_AQ_NO_ZERO_LEN, |
264 | .max_read_len = LJCA_I2C_MAX_XFER_SIZE, |
265 | .max_write_len = LJCA_I2C_MAX_XFER_SIZE, |
266 | }; |
267 | |
268 | static const struct i2c_algorithm ljca_i2c_algo = { |
269 | .master_xfer = ljca_i2c_xfer, |
270 | .functionality = ljca_i2c_func, |
271 | }; |
272 | |
273 | static int ljca_i2c_probe(struct auxiliary_device *auxdev, |
274 | const struct auxiliary_device_id *aux_dev_id) |
275 | { |
276 | struct ljca_client *ljca = auxiliary_dev_to_ljca_client(auxdev); |
277 | struct ljca_i2c_dev *ljca_i2c; |
278 | int ret; |
279 | |
280 | ljca_i2c = devm_kzalloc(dev: &auxdev->dev, size: sizeof(*ljca_i2c), GFP_KERNEL); |
281 | if (!ljca_i2c) |
282 | return -ENOMEM; |
283 | |
284 | ljca_i2c->ljca = ljca; |
285 | ljca_i2c->i2c_info = dev_get_platdata(dev: &auxdev->dev); |
286 | |
287 | ljca_i2c->adap.owner = THIS_MODULE; |
288 | ljca_i2c->adap.class = I2C_CLASS_HWMON; |
289 | ljca_i2c->adap.algo = &ljca_i2c_algo; |
290 | ljca_i2c->adap.quirks = &ljca_i2c_quirks; |
291 | ljca_i2c->adap.dev.parent = &auxdev->dev; |
292 | |
293 | snprintf(buf: ljca_i2c->adap.name, size: sizeof(ljca_i2c->adap.name), fmt: "%s-%s-%d" , |
294 | dev_name(dev: &auxdev->dev), dev_name(dev: auxdev->dev.parent), |
295 | ljca_i2c->i2c_info->id); |
296 | |
297 | device_set_node(dev: &ljca_i2c->adap.dev, dev_fwnode(&auxdev->dev)); |
298 | |
299 | i2c_set_adapdata(adap: &ljca_i2c->adap, data: ljca_i2c); |
300 | auxiliary_set_drvdata(auxdev, data: ljca_i2c); |
301 | |
302 | ret = ljca_i2c_init(ljca_i2c, id: ljca_i2c->i2c_info->id); |
303 | if (ret) |
304 | return dev_err_probe(dev: &auxdev->dev, err: -EIO, |
305 | fmt: "i2c init failed id: %d\n" , |
306 | ljca_i2c->i2c_info->id); |
307 | |
308 | ret = devm_i2c_add_adapter(dev: &auxdev->dev, adapter: &ljca_i2c->adap); |
309 | if (ret) |
310 | return ret; |
311 | |
312 | if (has_acpi_companion(dev: &ljca_i2c->adap.dev)) |
313 | acpi_dev_clear_dependencies(ACPI_COMPANION(&ljca_i2c->adap.dev)); |
314 | |
315 | return 0; |
316 | } |
317 | |
318 | static void ljca_i2c_remove(struct auxiliary_device *auxdev) |
319 | { |
320 | struct ljca_i2c_dev *ljca_i2c = auxiliary_get_drvdata(auxdev); |
321 | |
322 | i2c_del_adapter(adap: &ljca_i2c->adap); |
323 | } |
324 | |
325 | static const struct auxiliary_device_id ljca_i2c_id_table[] = { |
326 | { "usb_ljca.ljca-i2c" , 0 }, |
327 | { /* sentinel */ } |
328 | }; |
329 | MODULE_DEVICE_TABLE(auxiliary, ljca_i2c_id_table); |
330 | |
331 | static struct auxiliary_driver ljca_i2c_driver = { |
332 | .probe = ljca_i2c_probe, |
333 | .remove = ljca_i2c_remove, |
334 | .id_table = ljca_i2c_id_table, |
335 | }; |
336 | module_auxiliary_driver(ljca_i2c_driver); |
337 | |
338 | MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>" ); |
339 | MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>" ); |
340 | MODULE_AUTHOR("Lixu Zhang <lixu.zhang@intel.com>" ); |
341 | MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-I2C driver" ); |
342 | MODULE_LICENSE("GPL" ); |
343 | MODULE_IMPORT_NS(LJCA); |
344 | |