]>
Commit | Line | Data |
---|---|---|
74e656d6 GR |
1 | /* |
2 | * Copyright 2015-2017 Google, Inc | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * USB Type-C Port Controller Interface. | |
15 | */ | |
16 | ||
17 | #include <linux/delay.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <linux/module.h> | |
20 | #include <linux/i2c.h> | |
21 | #include <linux/interrupt.h> | |
22 | #include <linux/regmap.h> | |
23 | #include <linux/usb/typec.h> | |
24 | ||
25 | #include "pd.h" | |
26 | #include "tcpci.h" | |
27 | #include "tcpm.h" | |
28 | ||
29 | #define PD_RETRY_COUNT 3 | |
30 | ||
31 | struct tcpci { | |
32 | struct device *dev; | |
33 | struct i2c_client *client; | |
34 | ||
35 | struct tcpm_port *port; | |
36 | ||
37 | struct regmap *regmap; | |
38 | ||
39 | bool controls_vbus; | |
40 | ||
41 | struct tcpc_dev tcpc; | |
42 | }; | |
43 | ||
44 | static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc) | |
45 | { | |
46 | return container_of(tcpc, struct tcpci, tcpc); | |
47 | } | |
48 | ||
49 | static int tcpci_read16(struct tcpci *tcpci, unsigned int reg, | |
50 | unsigned int *val) | |
51 | { | |
52 | return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16)); | |
53 | } | |
54 | ||
55 | static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val) | |
56 | { | |
57 | return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16)); | |
58 | } | |
59 | ||
60 | static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) | |
61 | { | |
62 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
63 | unsigned int reg; | |
64 | int ret; | |
65 | ||
66 | switch (cc) { | |
67 | case TYPEC_CC_RA: | |
68 | reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) | | |
69 | (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC2_SHIFT); | |
70 | break; | |
71 | case TYPEC_CC_RD: | |
72 | reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) | | |
73 | (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT); | |
74 | break; | |
75 | case TYPEC_CC_RP_DEF: | |
76 | reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | | |
77 | (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | | |
78 | (TCPC_ROLE_CTRL_RP_VAL_DEF << | |
79 | TCPC_ROLE_CTRL_RP_VAL_SHIFT); | |
80 | break; | |
81 | case TYPEC_CC_RP_1_5: | |
82 | reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | | |
83 | (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | | |
84 | (TCPC_ROLE_CTRL_RP_VAL_1_5 << | |
85 | TCPC_ROLE_CTRL_RP_VAL_SHIFT); | |
86 | break; | |
87 | case TYPEC_CC_RP_3_0: | |
88 | reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) | | |
89 | (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) | | |
90 | (TCPC_ROLE_CTRL_RP_VAL_3_0 << | |
91 | TCPC_ROLE_CTRL_RP_VAL_SHIFT); | |
92 | break; | |
93 | case TYPEC_CC_OPEN: | |
94 | default: | |
95 | reg = (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT) | | |
96 | (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT); | |
97 | break; | |
98 | } | |
99 | ||
100 | ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); | |
101 | if (ret < 0) | |
102 | return ret; | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, | |
108 | enum typec_cc_status cc) | |
109 | { | |
110 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
111 | unsigned int reg = TCPC_ROLE_CTRL_DRP; | |
112 | ||
113 | switch (cc) { | |
114 | default: | |
115 | case TYPEC_CC_RP_DEF: | |
116 | reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF << | |
117 | TCPC_ROLE_CTRL_RP_VAL_SHIFT); | |
118 | break; | |
119 | case TYPEC_CC_RP_1_5: | |
120 | reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 << | |
121 | TCPC_ROLE_CTRL_RP_VAL_SHIFT); | |
122 | break; | |
123 | case TYPEC_CC_RP_3_0: | |
124 | reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 << | |
125 | TCPC_ROLE_CTRL_RP_VAL_SHIFT); | |
126 | break; | |
127 | } | |
128 | ||
129 | return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg); | |
130 | } | |
131 | ||
132 | static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink) | |
133 | { | |
134 | switch (cc) { | |
135 | case 0x1: | |
136 | return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA; | |
137 | case 0x2: | |
138 | return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD; | |
139 | case 0x3: | |
140 | if (sink) | |
141 | return TYPEC_CC_RP_3_0; | |
142 | case 0x0: | |
143 | default: | |
144 | return TYPEC_CC_OPEN; | |
145 | } | |
146 | } | |
147 | ||
148 | static int tcpci_get_cc(struct tcpc_dev *tcpc, | |
149 | enum typec_cc_status *cc1, enum typec_cc_status *cc2) | |
150 | { | |
151 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
152 | unsigned int reg; | |
153 | int ret; | |
154 | ||
155 | ret = regmap_read(tcpci->regmap, TCPC_CC_STATUS, ®); | |
156 | if (ret < 0) | |
157 | return ret; | |
158 | ||
159 | *cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) & | |
160 | TCPC_CC_STATUS_CC1_MASK, | |
161 | reg & TCPC_CC_STATUS_TERM); | |
162 | *cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) & | |
163 | TCPC_CC_STATUS_CC2_MASK, | |
164 | reg & TCPC_CC_STATUS_TERM); | |
165 | ||
166 | return 0; | |
167 | } | |
168 | ||
169 | static int tcpci_set_polarity(struct tcpc_dev *tcpc, | |
170 | enum typec_cc_polarity polarity) | |
171 | { | |
172 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
173 | int ret; | |
174 | ||
175 | ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL, | |
176 | (polarity == TYPEC_POLARITY_CC2) ? | |
177 | TCPC_TCPC_CTRL_ORIENTATION : 0); | |
178 | if (ret < 0) | |
179 | return ret; | |
180 | ||
181 | return 0; | |
182 | } | |
183 | ||
184 | static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable) | |
185 | { | |
186 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
187 | int ret; | |
188 | ||
189 | ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL, | |
190 | enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0); | |
191 | if (ret < 0) | |
192 | return ret; | |
193 | ||
194 | return 0; | |
195 | } | |
196 | ||
197 | static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached, | |
198 | enum typec_role role, enum typec_data_role data) | |
199 | { | |
200 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
201 | unsigned int reg; | |
202 | int ret; | |
203 | ||
204 | reg = PD_REV20 << TCPC_MSG_HDR_INFO_REV_SHIFT; | |
205 | if (role == TYPEC_SOURCE) | |
206 | reg |= TCPC_MSG_HDR_INFO_PWR_ROLE; | |
207 | if (data == TYPEC_HOST) | |
208 | reg |= TCPC_MSG_HDR_INFO_DATA_ROLE; | |
209 | ret = regmap_write(tcpci->regmap, TCPC_MSG_HDR_INFO, reg); | |
210 | if (ret < 0) | |
211 | return ret; | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | static int tcpci_set_pd_rx(struct tcpc_dev *tcpc, bool enable) | |
217 | { | |
218 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
219 | unsigned int reg = 0; | |
220 | int ret; | |
221 | ||
222 | if (enable) | |
223 | reg = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET; | |
224 | ret = regmap_write(tcpci->regmap, TCPC_RX_DETECT, reg); | |
225 | if (ret < 0) | |
226 | return ret; | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | static int tcpci_get_vbus(struct tcpc_dev *tcpc) | |
232 | { | |
233 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
234 | unsigned int reg; | |
235 | int ret; | |
236 | ||
237 | ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, ®); | |
238 | if (ret < 0) | |
239 | return ret; | |
240 | ||
241 | return !!(reg & TCPC_POWER_STATUS_VBUS_PRES); | |
242 | } | |
243 | ||
244 | static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink) | |
245 | { | |
246 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
247 | int ret; | |
248 | ||
249 | /* Disable both source and sink first before enabling anything */ | |
250 | ||
251 | if (!source) { | |
252 | ret = regmap_write(tcpci->regmap, TCPC_COMMAND, | |
253 | TCPC_CMD_DISABLE_SRC_VBUS); | |
254 | if (ret < 0) | |
255 | return ret; | |
256 | } | |
257 | ||
258 | if (!sink) { | |
259 | ret = regmap_write(tcpci->regmap, TCPC_COMMAND, | |
260 | TCPC_CMD_DISABLE_SINK_VBUS); | |
261 | if (ret < 0) | |
262 | return ret; | |
263 | } | |
264 | ||
265 | if (source) { | |
266 | ret = regmap_write(tcpci->regmap, TCPC_COMMAND, | |
267 | TCPC_CMD_SRC_VBUS_DEFAULT); | |
268 | if (ret < 0) | |
269 | return ret; | |
270 | } | |
271 | ||
272 | if (sink) { | |
273 | ret = regmap_write(tcpci->regmap, TCPC_COMMAND, | |
274 | TCPC_CMD_SINK_VBUS); | |
275 | if (ret < 0) | |
276 | return ret; | |
277 | } | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
282 | static int tcpci_pd_transmit(struct tcpc_dev *tcpc, | |
283 | enum tcpm_transmit_type type, | |
284 | const struct pd_message *msg) | |
285 | { | |
286 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
287 | unsigned int reg, cnt, header; | |
288 | int ret; | |
289 | ||
290 | cnt = msg ? pd_header_cnt(msg->header) * 4 : 0; | |
291 | ret = regmap_write(tcpci->regmap, TCPC_TX_BYTE_CNT, cnt + 2); | |
292 | if (ret < 0) | |
293 | return ret; | |
294 | ||
295 | header = msg ? msg->header : 0; | |
296 | ret = tcpci_write16(tcpci, TCPC_TX_HDR, header); | |
297 | if (ret < 0) | |
298 | return ret; | |
299 | ||
300 | if (cnt > 0) { | |
301 | ret = regmap_raw_write(tcpci->regmap, TCPC_TX_DATA, | |
302 | &msg->payload, cnt); | |
303 | if (ret < 0) | |
304 | return ret; | |
305 | } | |
306 | ||
307 | reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) | | |
308 | (type << TCPC_TRANSMIT_TYPE_SHIFT); | |
309 | ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg); | |
310 | if (ret < 0) | |
311 | return ret; | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
316 | static int tcpci_init(struct tcpc_dev *tcpc) | |
317 | { | |
318 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | |
319 | unsigned long timeout = jiffies + msecs_to_jiffies(2000); /* XXX */ | |
320 | unsigned int reg; | |
321 | int ret; | |
322 | ||
323 | while (time_before_eq(jiffies, timeout)) { | |
324 | ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, ®); | |
325 | if (ret < 0) | |
326 | return ret; | |
327 | if (!(reg & TCPC_POWER_STATUS_UNINIT)) | |
328 | break; | |
329 | usleep_range(10000, 20000); | |
330 | } | |
331 | if (time_after(jiffies, timeout)) | |
332 | return -ETIMEDOUT; | |
333 | ||
334 | /* Clear all events */ | |
335 | ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff); | |
336 | if (ret < 0) | |
337 | return ret; | |
338 | ||
339 | if (tcpci->controls_vbus) | |
340 | reg = TCPC_POWER_STATUS_VBUS_PRES; | |
341 | else | |
342 | reg = 0; | |
343 | ret = regmap_write(tcpci->regmap, TCPC_POWER_STATUS_MASK, reg); | |
344 | if (ret < 0) | |
345 | return ret; | |
346 | ||
347 | reg = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED | | |
348 | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS | | |
349 | TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS; | |
350 | if (tcpci->controls_vbus) | |
351 | reg |= TCPC_ALERT_POWER_STATUS; | |
352 | return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg); | |
353 | } | |
354 | ||
355 | static irqreturn_t tcpci_irq(int irq, void *dev_id) | |
356 | { | |
357 | struct tcpci *tcpci = dev_id; | |
358 | unsigned int status, reg; | |
359 | ||
360 | tcpci_read16(tcpci, TCPC_ALERT, &status); | |
361 | ||
362 | /* | |
363 | * Clear alert status for everything except RX_STATUS, which shouldn't | |
364 | * be cleared until we have successfully retrieved message. | |
365 | */ | |
366 | if (status & ~TCPC_ALERT_RX_STATUS) | |
367 | tcpci_write16(tcpci, TCPC_ALERT, | |
368 | status & ~TCPC_ALERT_RX_STATUS); | |
369 | ||
370 | if (status & TCPC_ALERT_CC_STATUS) | |
371 | tcpm_cc_change(tcpci->port); | |
372 | ||
373 | if (status & TCPC_ALERT_POWER_STATUS) { | |
374 | regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, ®); | |
375 | ||
376 | /* | |
377 | * If power status mask has been reset, then the TCPC | |
378 | * has reset. | |
379 | */ | |
380 | if (reg == 0xff) | |
381 | tcpm_tcpc_reset(tcpci->port); | |
382 | else | |
383 | tcpm_vbus_change(tcpci->port); | |
384 | } | |
385 | ||
386 | if (status & TCPC_ALERT_RX_STATUS) { | |
387 | struct pd_message msg; | |
388 | unsigned int cnt; | |
389 | ||
390 | regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt); | |
391 | ||
392 | tcpci_read16(tcpci, TCPC_RX_HDR, ®); | |
393 | msg.header = reg; | |
394 | ||
395 | if (WARN_ON(cnt > sizeof(msg.payload))) | |
396 | cnt = sizeof(msg.payload); | |
397 | ||
398 | if (cnt > 0) | |
399 | regmap_raw_read(tcpci->regmap, TCPC_RX_DATA, | |
400 | &msg.payload, cnt); | |
401 | ||
402 | /* Read complete, clear RX status alert bit */ | |
403 | tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS); | |
404 | ||
405 | tcpm_pd_receive(tcpci->port, &msg); | |
406 | } | |
407 | ||
408 | if (status & TCPC_ALERT_RX_HARD_RST) | |
409 | tcpm_pd_hard_reset(tcpci->port); | |
410 | ||
411 | if (status & TCPC_ALERT_TX_SUCCESS) | |
412 | tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_SUCCESS); | |
413 | else if (status & TCPC_ALERT_TX_DISCARDED) | |
414 | tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_DISCARDED); | |
415 | else if (status & TCPC_ALERT_TX_FAILED) | |
416 | tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED); | |
417 | ||
418 | return IRQ_HANDLED; | |
419 | } | |
420 | ||
421 | static const struct regmap_config tcpci_regmap_config = { | |
422 | .reg_bits = 8, | |
423 | .val_bits = 8, | |
424 | ||
425 | .max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */ | |
426 | }; | |
427 | ||
c6a9d3ea | 428 | static const struct tcpc_config tcpci_tcpc_config = { |
74e656d6 GR |
429 | .type = TYPEC_PORT_DFP, |
430 | .default_role = TYPEC_SINK, | |
431 | }; | |
432 | ||
433 | static int tcpci_parse_config(struct tcpci *tcpci) | |
434 | { | |
435 | tcpci->controls_vbus = true; /* XXX */ | |
436 | ||
437 | /* TODO: Populate struct tcpc_config from ACPI/device-tree */ | |
438 | tcpci->tcpc.config = &tcpci_tcpc_config; | |
439 | ||
440 | return 0; | |
441 | } | |
442 | ||
443 | static int tcpci_probe(struct i2c_client *client, | |
444 | const struct i2c_device_id *i2c_id) | |
445 | { | |
446 | struct tcpci *tcpci; | |
447 | int err; | |
448 | ||
449 | tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL); | |
450 | if (!tcpci) | |
451 | return -ENOMEM; | |
452 | ||
453 | tcpci->client = client; | |
454 | tcpci->dev = &client->dev; | |
455 | i2c_set_clientdata(client, tcpci); | |
456 | tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config); | |
457 | if (IS_ERR(tcpci->regmap)) | |
458 | return PTR_ERR(tcpci->regmap); | |
459 | ||
460 | tcpci->tcpc.init = tcpci_init; | |
461 | tcpci->tcpc.get_vbus = tcpci_get_vbus; | |
462 | tcpci->tcpc.set_vbus = tcpci_set_vbus; | |
463 | tcpci->tcpc.set_cc = tcpci_set_cc; | |
464 | tcpci->tcpc.get_cc = tcpci_get_cc; | |
465 | tcpci->tcpc.set_polarity = tcpci_set_polarity; | |
466 | tcpci->tcpc.set_vconn = tcpci_set_vconn; | |
467 | tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling; | |
468 | ||
469 | tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx; | |
470 | tcpci->tcpc.set_roles = tcpci_set_roles; | |
471 | tcpci->tcpc.pd_transmit = tcpci_pd_transmit; | |
472 | ||
473 | err = tcpci_parse_config(tcpci); | |
474 | if (err < 0) | |
475 | return err; | |
476 | ||
477 | /* Disable chip interrupts */ | |
478 | tcpci_write16(tcpci, TCPC_ALERT_MASK, 0); | |
479 | ||
480 | err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL, | |
481 | tcpci_irq, | |
482 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, | |
483 | dev_name(tcpci->dev), tcpci); | |
484 | if (err < 0) | |
485 | return err; | |
486 | ||
487 | tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc); | |
488 | return PTR_ERR_OR_ZERO(tcpci->port); | |
489 | } | |
490 | ||
491 | static int tcpci_remove(struct i2c_client *client) | |
492 | { | |
493 | struct tcpci *tcpci = i2c_get_clientdata(client); | |
494 | ||
495 | tcpm_unregister_port(tcpci->port); | |
496 | ||
497 | return 0; | |
498 | } | |
499 | ||
500 | static const struct i2c_device_id tcpci_id[] = { | |
501 | { "tcpci", 0 }, | |
502 | { } | |
503 | }; | |
504 | MODULE_DEVICE_TABLE(i2c, tcpci_id); | |
505 | ||
506 | #ifdef CONFIG_OF | |
507 | static const struct of_device_id tcpci_of_match[] = { | |
508 | { .compatible = "usb,tcpci", }, | |
509 | {}, | |
510 | }; | |
511 | MODULE_DEVICE_TABLE(of, tcpci_of_match); | |
512 | #endif | |
513 | ||
514 | static struct i2c_driver tcpci_i2c_driver = { | |
515 | .driver = { | |
516 | .name = "tcpci", | |
517 | .of_match_table = of_match_ptr(tcpci_of_match), | |
518 | }, | |
519 | .probe = tcpci_probe, | |
520 | .remove = tcpci_remove, | |
521 | .id_table = tcpci_id, | |
522 | }; | |
523 | module_i2c_driver(tcpci_i2c_driver); | |
524 | ||
525 | MODULE_DESCRIPTION("USB Type-C Port Controller Interface driver"); | |
526 | MODULE_LICENSE("GPL"); |