Commit 2887c5a3e3e9942614acab2aa803bf4c43b93b11
1 parent
8b3d0a5232
Exists in
v3.2_SBC_SMARTMEN
Add Silicon Lab CP210X Support
Showing 2 changed files with 323 additions and 115 deletions Side-by-side Diff
arch/arm/configs/smarc_t335x_defconfig
... | ... | @@ -2027,7 +2027,8 @@ |
2027 | 2027 | # |
2028 | 2028 | # USB port drivers |
2029 | 2029 | # |
2030 | -CONFIG_USB_SERIAL=m | |
2030 | +CONFIG_USB_SERIAL=y | |
2031 | +# CONFIG_USB_SERIAL_CONSOLE is not set | |
2031 | 2032 | # CONFIG_USB_EZUSB is not set |
2032 | 2033 | # CONFIG_USB_SERIAL_GENERIC is not set |
2033 | 2034 | # CONFIG_USB_SERIAL_AIRCABLE is not set |
... | ... | @@ -2036,7 +2037,7 @@ |
2036 | 2037 | # CONFIG_USB_SERIAL_CH341 is not set |
2037 | 2038 | # CONFIG_USB_SERIAL_WHITEHEAT is not set |
2038 | 2039 | # CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set |
2039 | -CONFIG_USB_SERIAL_CP210X=m | |
2040 | +CONFIG_USB_SERIAL_CP210X=y | |
2040 | 2041 | # CONFIG_USB_SERIAL_CYPRESS_M8 is not set |
2041 | 2042 | # CONFIG_USB_SERIAL_EMPEG is not set |
2042 | 2043 | # CONFIG_USB_SERIAL_FTDI_SIO is not set |
drivers/usb/serial/cp210x.c
... | ... | @@ -35,10 +35,14 @@ |
35 | 35 | */ |
36 | 36 | static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); |
37 | 37 | static void cp210x_close(struct usb_serial_port *); |
38 | +static int cp210x_ioctl(struct tty_struct *tty, | |
39 | + unsigned int cmd, unsigned long arg); | |
38 | 40 | static void cp210x_get_termios(struct tty_struct *, |
39 | 41 | struct usb_serial_port *port); |
40 | 42 | static void cp210x_get_termios_port(struct usb_serial_port *port, |
41 | 43 | unsigned int *cflagp, unsigned int *baudp); |
44 | +static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, | |
45 | + struct ktermios *); | |
42 | 46 | static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, |
43 | 47 | struct ktermios*); |
44 | 48 | static int cp210x_tiocmget(struct tty_struct *); |
... | ... | @@ -47,6 +51,7 @@ |
47 | 51 | unsigned int, unsigned int); |
48 | 52 | static void cp210x_break_ctl(struct tty_struct *, int); |
49 | 53 | static int cp210x_startup(struct usb_serial *); |
54 | +static void cp210x_release(struct usb_serial *); | |
50 | 55 | static void cp210x_dtr_rts(struct usb_serial_port *p, int on); |
51 | 56 | |
52 | 57 | static int debug; |
... | ... | @@ -92,6 +97,7 @@ |
92 | 97 | { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ |
93 | 98 | { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ |
94 | 99 | { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ |
100 | + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ | |
95 | 101 | { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ |
96 | 102 | { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ |
97 | 103 | { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ |
... | ... | @@ -118,6 +124,8 @@ |
118 | 124 | { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ |
119 | 125 | { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ |
120 | 126 | { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ |
127 | + { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ | |
128 | + { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */ | |
121 | 129 | { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ |
122 | 130 | { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ |
123 | 131 | { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ |
124 | 132 | |
125 | 133 | |
... | ... | @@ -133,16 +141,24 @@ |
133 | 141 | { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ |
134 | 142 | { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ |
135 | 143 | { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ |
144 | + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ | |
145 | + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ | |
136 | 146 | { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ |
137 | 147 | { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ |
138 | 148 | { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ |
139 | 149 | { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ |
150 | + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ | |
140 | 151 | { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ |
141 | 152 | { } /* Terminating Entry */ |
142 | 153 | }; |
143 | 154 | |
144 | 155 | MODULE_DEVICE_TABLE(usb, id_table); |
145 | 156 | |
157 | +struct cp210x_port_private { | |
158 | + __u8 bInterfaceNumber; | |
159 | + __u8 bPartNumber; | |
160 | +}; | |
161 | + | |
146 | 162 | static struct usb_driver cp210x_driver = { |
147 | 163 | .name = "cp210x", |
148 | 164 | .probe = usb_serial_probe, |
149 | 165 | |
150 | 166 | |
151 | 167 | |
... | ... | @@ -163,17 +179,33 @@ |
163 | 179 | .bulk_out_size = 256, |
164 | 180 | .open = cp210x_open, |
165 | 181 | .close = cp210x_close, |
182 | + .ioctl = cp210x_ioctl, | |
166 | 183 | .break_ctl = cp210x_break_ctl, |
167 | 184 | .set_termios = cp210x_set_termios, |
168 | 185 | .tiocmget = cp210x_tiocmget, |
169 | 186 | .tiocmset = cp210x_tiocmset, |
170 | 187 | .attach = cp210x_startup, |
188 | + .release = cp210x_release, | |
171 | 189 | .dtr_rts = cp210x_dtr_rts |
172 | 190 | }; |
173 | 191 | |
192 | +/* Part number definitions */ | |
193 | +#define CP2101_PARTNUM 0x01 | |
194 | +#define CP2102_PARTNUM 0x02 | |
195 | +#define CP2103_PARTNUM 0x03 | |
196 | +#define CP2104_PARTNUM 0x04 | |
197 | +#define CP2105_PARTNUM 0x05 | |
198 | +#define CP2108_PARTNUM 0x08 | |
199 | + | |
200 | +/* IOCTLs */ | |
201 | +#define IOCTL_GPIOGET 0x8000 | |
202 | +#define IOCTL_GPIOSET 0x8001 | |
203 | + | |
174 | 204 | /* Config request types */ |
175 | -#define REQTYPE_HOST_TO_DEVICE 0x41 | |
176 | -#define REQTYPE_DEVICE_TO_HOST 0xc1 | |
205 | +#define REQTYPE_HOST_TO_INTERFACE 0x41 | |
206 | +#define REQTYPE_INTERFACE_TO_HOST 0xc1 | |
207 | +#define REQTYPE_HOST_TO_DEVICE 0x40 | |
208 | +#define REQTYPE_DEVICE_TO_HOST 0xc0 | |
177 | 209 | |
178 | 210 | /* Config request codes */ |
179 | 211 | #define CP210X_IFC_ENABLE 0x00 |
180 | 212 | |
... | ... | @@ -200,11 +232,19 @@ |
200 | 232 | #define CP210X_EMBED_EVENTS 0x15 |
201 | 233 | #define CP210X_GET_EVENTSTATE 0x16 |
202 | 234 | #define CP210X_SET_CHARS 0x19 |
235 | +#define CP210X_GET_BAUDRATE 0x1D | |
236 | +#define CP210X_SET_BAUDRATE 0x1E | |
237 | +#define CP210X_VENDOR_SPECIFIC 0xFF | |
203 | 238 | |
204 | 239 | /* CP210X_IFC_ENABLE */ |
205 | 240 | #define UART_ENABLE 0x0001 |
206 | 241 | #define UART_DISABLE 0x0000 |
207 | 242 | |
243 | +/* CP210X_VENDOR_SPECIFIC */ | |
244 | +#define CP210X_WRITE_LATCH 0x37E1 | |
245 | +#define CP210X_READ_LATCH 0x00C2 | |
246 | +#define CP210X_GET_PARTNUM 0x370B | |
247 | + | |
208 | 248 | /* CP210X_(SET|GET)_BAUDDIV */ |
209 | 249 | #define BAUD_RATE_GEN_FREQ 0x384000 |
210 | 250 | |
211 | 251 | |
... | ... | @@ -249,10 +289,11 @@ |
249 | 289 | * 'data' is a pointer to a pre-allocated array of integers large |
250 | 290 | * enough to hold 'size' bytes (with 4 bytes to each integer) |
251 | 291 | */ |
252 | -static int cp210x_get_config(struct usb_serial_port *port, u8 request, | |
253 | - unsigned int *data, int size) | |
292 | +static int cp210x_get_config(struct usb_serial_port *port, u8 requestType, | |
293 | + u8 request, int value, unsigned int *data, int size) | |
254 | 294 | { |
255 | 295 | struct usb_serial *serial = port->serial; |
296 | + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); | |
256 | 297 | __le32 *buf; |
257 | 298 | int result, i, length; |
258 | 299 | |
... | ... | @@ -266,9 +307,9 @@ |
266 | 307 | } |
267 | 308 | |
268 | 309 | /* Issue the request, attempting to read 'size' bytes */ |
269 | - result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), | |
270 | - request, REQTYPE_DEVICE_TO_HOST, 0x0000, | |
271 | - 0, buf, size, 300); | |
310 | + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), | |
311 | + request, requestType, value, | |
312 | + port_priv->bInterfaceNumber, buf, size, 300); | |
272 | 313 | |
273 | 314 | /* Convert data into an array of integers */ |
274 | 315 | for (i = 0; i < length; i++) |
275 | 316 | |
... | ... | @@ -280,7 +321,10 @@ |
280 | 321 | dbg("%s - Unable to send config request, " |
281 | 322 | "request=0x%x size=%d result=%d\n", |
282 | 323 | __func__, request, size, result); |
324 | + if (result > 0) | |
283 | 325 | return -EPROTO; |
326 | + | |
327 | + return result; | |
284 | 328 | } |
285 | 329 | |
286 | 330 | return 0; |
287 | 331 | |
288 | 332 | |
... | ... | @@ -292,13 +336,17 @@ |
292 | 336 | * Values less than 16 bits wide are sent directly |
293 | 337 | * 'size' is specified in bytes. |
294 | 338 | */ |
295 | -static int cp210x_set_config(struct usb_serial_port *port, u8 request, | |
296 | - unsigned int *data, int size) | |
339 | +static int cp210x_set_config(struct usb_serial_port *port, u8 requestType, | |
340 | + u8 request, int value, unsigned int *data, int size) | |
297 | 341 | { |
298 | 342 | struct usb_serial *serial = port->serial; |
299 | - __le32 *buf; | |
300 | - int result, i, length; | |
343 | + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); | |
344 | + __le32 *buf = NULL; | |
345 | + int result, i, length = 0; | |
301 | 346 | |
347 | + if (size) | |
348 | + { | |
349 | + | |
302 | 350 | /* Number of integers required to contain the array */ |
303 | 351 | length = (((size - 1) | 3) + 1)/4; |
304 | 352 | |
305 | 353 | |
306 | 354 | |
307 | 355 | |
308 | 356 | |
309 | 357 | |
... | ... | @@ -312,40 +360,28 @@ |
312 | 360 | /* Array of integers into bytes */ |
313 | 361 | for (i = 0; i < length; i++) |
314 | 362 | buf[i] = cpu_to_le32(data[i]); |
363 | + } | |
315 | 364 | |
316 | - if (size > 2) { | |
317 | - result = usb_control_msg(serial->dev, | |
318 | - usb_sndctrlpipe(serial->dev, 0), | |
319 | - request, REQTYPE_HOST_TO_DEVICE, 0x0000, | |
320 | - 0, buf, size, 300); | |
321 | - } else { | |
322 | - result = usb_control_msg(serial->dev, | |
323 | - usb_sndctrlpipe(serial->dev, 0), | |
324 | - request, REQTYPE_HOST_TO_DEVICE, data[0], | |
325 | - 0, NULL, 0, 300); | |
326 | - } | |
365 | + result = usb_control_msg(serial->dev, | |
366 | + usb_sndctrlpipe(serial->dev, 0), | |
367 | + request, requestType, value, | |
368 | + port_priv->bInterfaceNumber, buf, size, 300); | |
327 | 369 | |
328 | - kfree(buf); | |
329 | 370 | |
330 | - if ((size > 2 && result != size) || result < 0) { | |
331 | - dbg("%s - Unable to send request, " | |
332 | - "request=0x%x size=%d result=%d\n", | |
333 | - __func__, request, size, result); | |
334 | - return -EPROTO; | |
335 | - } | |
371 | + if (buf) | |
372 | + kfree(buf); | |
336 | 373 | |
337 | - return 0; | |
338 | -} | |
374 | + if (result != size) { | |
375 | + dbg("%s - Unable to send request, " | |
376 | + "request=0x%x size=%d result=%d\n", | |
377 | + __func__, request, size, result); | |
378 | + if (result > 0) | |
379 | + result = -EPROTO; | |
339 | 380 | |
340 | -/* | |
341 | - * cp210x_set_config_single | |
342 | - * Convenience function for calling cp210x_set_config on single data values | |
343 | - * without requiring an integer pointer | |
344 | - */ | |
345 | -static inline int cp210x_set_config_single(struct usb_serial_port *port, | |
346 | - u8 request, unsigned int data) | |
347 | -{ | |
348 | - return cp210x_set_config(port, request, &data, 2); | |
381 | + return result; | |
382 | + } | |
383 | + | |
384 | + return 0; | |
349 | 385 | } |
350 | 386 | |
351 | 387 | /* |
... | ... | @@ -353,8 +389,8 @@ |
353 | 389 | * Quantises the baud rate as per AN205 Table 1 |
354 | 390 | */ |
355 | 391 | static unsigned int cp210x_quantise_baudrate(unsigned int baud) { |
356 | - if (baud <= 56) baud = 0; | |
357 | - else if (baud <= 300) baud = 300; | |
392 | + if (baud <= 300) | |
393 | + baud = 300; | |
358 | 394 | else if (baud <= 600) baud = 600; |
359 | 395 | else if (baud <= 1200) baud = 1200; |
360 | 396 | else if (baud <= 1800) baud = 1800; |
... | ... | @@ -382,11 +418,11 @@ |
382 | 418 | else if (baud <= 491520) baud = 460800; |
383 | 419 | else if (baud <= 567138) baud = 500000; |
384 | 420 | else if (baud <= 670254) baud = 576000; |
385 | - else if (baud <= 1053257) baud = 921600; | |
386 | - else if (baud <= 1474560) baud = 1228800; | |
387 | - else if (baud <= 2457600) baud = 1843200; | |
388 | - else baud = 3686400; | |
389 | - return baud; | |
421 | + else if (baud < 1000000) | |
422 | + baud = 921600; | |
423 | + else if (baud > 2000000) | |
424 | + baud = 2000000; | |
425 | + return baud; | |
390 | 426 | } |
391 | 427 | |
392 | 428 | static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) |
393 | 429 | |
394 | 430 | |
... | ... | @@ -395,19 +431,21 @@ |
395 | 431 | |
396 | 432 | dbg("%s - port %d", __func__, port->number); |
397 | 433 | |
398 | - if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { | |
399 | - dev_err(&port->dev, "%s - Unable to enable UART\n", | |
400 | - __func__); | |
401 | - return -EPROTO; | |
402 | - } | |
434 | + result = cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
435 | + CP210X_IFC_ENABLE, UART_ENABLE, NULL, 0); | |
436 | + if (result) { | |
437 | + dev_err(&port->dev, "%s - Unable to enable UART\n", __func__); | |
438 | + return result; | |
439 | + } | |
403 | 440 | |
404 | - result = usb_serial_generic_open(tty, port); | |
405 | - if (result) | |
406 | - return result; | |
407 | - | |
408 | 441 | /* Configure the termios structure */ |
409 | 442 | cp210x_get_termios(tty, port); |
410 | - return 0; | |
443 | + | |
444 | + /* The baud rate must be initialised on cp2104 */ | |
445 | + if (tty) | |
446 | + cp210x_change_speed(tty, port, NULL); | |
447 | + | |
448 | + return usb_serial_generic_open(tty, port); | |
411 | 449 | } |
412 | 450 | |
413 | 451 | static void cp210x_close(struct usb_serial_port *port) |
414 | 452 | |
... | ... | @@ -418,10 +456,82 @@ |
418 | 456 | |
419 | 457 | mutex_lock(&port->serial->disc_mutex); |
420 | 458 | if (!port->serial->disconnected) |
421 | - cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); | |
459 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
460 | + CP210X_IFC_ENABLE, UART_DISABLE, NULL, 0); | |
422 | 461 | mutex_unlock(&port->serial->disc_mutex); |
423 | 462 | } |
424 | 463 | |
464 | +static int cp210x_ioctl(struct tty_struct *tty, | |
465 | + unsigned int cmd, unsigned long arg) | |
466 | +{ | |
467 | + struct usb_serial_port *port = tty->driver_data; | |
468 | + struct cp210x_port_private *port_priv = usb_get_serial_port_data(port); | |
469 | + | |
470 | + switch (cmd) { | |
471 | + | |
472 | + case IOCTL_GPIOGET: | |
473 | + if ((port_priv->bPartNumber == CP2103_PARTNUM) || | |
474 | + (port_priv->bPartNumber == CP2104_PARTNUM)) { | |
475 | + cp210x_get_config(port, REQTYPE_DEVICE_TO_HOST, | |
476 | + CP210X_VENDOR_SPECIFIC, | |
477 | + CP210X_READ_LATCH, | |
478 | + (unsigned int*)arg, 1); | |
479 | + } | |
480 | + else if (port_priv->bPartNumber == CP2105_PARTNUM) { | |
481 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
482 | + CP210X_VENDOR_SPECIFIC, | |
483 | + CP210X_READ_LATCH, | |
484 | + (unsigned int*)arg, 1); | |
485 | + } | |
486 | + else if (port_priv->bPartNumber == CP2108_PARTNUM) { | |
487 | + cp210x_get_config(port, REQTYPE_DEVICE_TO_HOST, | |
488 | + CP210X_VENDOR_SPECIFIC, | |
489 | + CP210X_READ_LATCH, | |
490 | + (unsigned int*)arg, 2); | |
491 | + } | |
492 | + else { | |
493 | + return -ENOTSUPP; | |
494 | + } | |
495 | + break; | |
496 | + | |
497 | + case IOCTL_GPIOSET: | |
498 | + if ((port_priv->bPartNumber == CP2103_PARTNUM) || | |
499 | + (port_priv->bPartNumber == CP2104_PARTNUM)) { | |
500 | + /*cp210x_set_config(port, REQTYPE_HOST_TO_DEVICE, | |
501 | + CP210x_VENDOR_SPECIFIC, | |
502 | + CP210x_GPIO_WRITE_LATCH, &val, 2);*/ | |
503 | + usb_control_msg(port->serial->dev, | |
504 | + usb_sndctrlpipe(port->serial->dev, 0), | |
505 | + CP210X_VENDOR_SPECIFIC, | |
506 | + REQTYPE_HOST_TO_DEVICE, | |
507 | + CP210X_WRITE_LATCH, | |
508 | + *(unsigned long*)arg, | |
509 | + NULL, 0, 300); | |
510 | + } | |
511 | + else if (port_priv->bPartNumber == CP2105_PARTNUM) { | |
512 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
513 | + CP210X_VENDOR_SPECIFIC, | |
514 | + CP210X_WRITE_LATCH, | |
515 | + (unsigned int*)arg, 2); | |
516 | + } | |
517 | + else if (port_priv->bPartNumber == CP2108_PARTNUM) { | |
518 | + cp210x_set_config(port, REQTYPE_HOST_TO_DEVICE, | |
519 | + CP210X_VENDOR_SPECIFIC, | |
520 | + CP210X_WRITE_LATCH, | |
521 | + (unsigned int*)arg, 4); | |
522 | + } | |
523 | + else { | |
524 | + return -ENOTSUPP; | |
525 | + } | |
526 | + break; | |
527 | + | |
528 | + default: | |
529 | + break; | |
530 | + } | |
531 | + | |
532 | + return -ENOIOCTLCMD; | |
533 | +} | |
534 | + | |
425 | 535 | /* |
426 | 536 | * cp210x_get_termios |
427 | 537 | * Reads the baud rate, data bits, parity, stop bits and flow control mode |
428 | 538 | |
429 | 539 | |
430 | 540 | |
... | ... | @@ -459,17 +569,16 @@ |
459 | 569 | |
460 | 570 | dbg("%s - port %d", __func__, port->number); |
461 | 571 | |
462 | - cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); | |
463 | - /* Convert to baudrate */ | |
464 | - if (baud) | |
465 | - baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); | |
572 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
573 | + CP210X_GET_BAUDRATE, 0, &baud, 4); | |
466 | 574 | |
467 | - dbg("%s - baud rate = %d", __func__, baud); | |
468 | - *baudp = baud; | |
575 | + dbg("%s - baud rate = %d", __func__, baud); | |
576 | + *baudp = baud; | |
469 | 577 | |
470 | - cflag = *cflagp; | |
578 | + cflag = *cflagp; | |
471 | 579 | |
472 | - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); | |
580 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
581 | + CP210X_GET_LINE_CTL, 0, &bits, 2); | |
473 | 582 | cflag &= ~CSIZE; |
474 | 583 | switch (bits & BITS_DATA_MASK) { |
475 | 584 | case BITS_DATA_5: |
476 | 585 | |
... | ... | @@ -494,14 +603,16 @@ |
494 | 603 | cflag |= CS8; |
495 | 604 | bits &= ~BITS_DATA_MASK; |
496 | 605 | bits |= BITS_DATA_8; |
497 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
606 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
607 | + CP210X_SET_LINE_CTL, 0, &bits, 2); | |
498 | 608 | break; |
499 | 609 | default: |
500 | 610 | dbg("%s - Unknown number of data bits, using 8", __func__); |
501 | 611 | cflag |= CS8; |
502 | 612 | bits &= ~BITS_DATA_MASK; |
503 | 613 | bits |= BITS_DATA_8; |
504 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
614 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
615 | + CP210X_SET_LINE_CTL, 0, &bits, 2); | |
505 | 616 | break; |
506 | 617 | } |
507 | 618 | |
508 | 619 | |
509 | 620 | |
... | ... | @@ -520,24 +631,20 @@ |
520 | 631 | cflag |= PARENB; |
521 | 632 | break; |
522 | 633 | case BITS_PARITY_MARK: |
523 | - dbg("%s - parity = MARK (not supported, disabling parity)", | |
524 | - __func__); | |
525 | - cflag &= ~PARENB; | |
526 | - bits &= ~BITS_PARITY_MASK; | |
527 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
528 | - break; | |
634 | + dbg("%s - parity = MARK", __func__); | |
635 | + cflag |= (PARENB|PARODD|CMSPAR); | |
636 | + break; | |
529 | 637 | case BITS_PARITY_SPACE: |
530 | - dbg("%s - parity = SPACE (not supported, disabling parity)", | |
531 | - __func__); | |
532 | - cflag &= ~PARENB; | |
533 | - bits &= ~BITS_PARITY_MASK; | |
534 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
535 | - break; | |
638 | + dbg("%s - parity = SPACE", __func__); | |
639 | + cflag &= ~PARODD; | |
640 | + cflag |= (PARENB|CMSPAR); | |
641 | + break; | |
536 | 642 | default: |
537 | 643 | dbg("%s - Unknown parity mode, disabling parity", __func__); |
538 | 644 | cflag &= ~PARENB; |
539 | 645 | bits &= ~BITS_PARITY_MASK; |
540 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
646 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
647 | + CP210X_SET_LINE_CTL, 0, &bits, 2); | |
541 | 648 | break; |
542 | 649 | } |
543 | 650 | |
... | ... | @@ -550,7 +657,8 @@ |
550 | 657 | dbg("%s - stop bits = 1.5 (not supported, using 1 stop bit)", |
551 | 658 | __func__); |
552 | 659 | bits &= ~BITS_STOP_MASK; |
553 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
660 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
661 | + CP210X_SET_LINE_CTL, 0, &bits, 2); | |
554 | 662 | break; |
555 | 663 | case BITS_STOP_2: |
556 | 664 | dbg("%s - stop bits = 2", __func__); |
557 | 665 | |
... | ... | @@ -560,11 +668,13 @@ |
560 | 668 | dbg("%s - Unknown number of stop bits, using 1 stop bit", |
561 | 669 | __func__); |
562 | 670 | bits &= ~BITS_STOP_MASK; |
563 | - cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2); | |
671 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
672 | + CP210X_SET_LINE_CTL, 0, &bits, 2); | |
564 | 673 | break; |
565 | 674 | } |
566 | 675 | |
567 | - cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); | |
676 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
677 | + CP210X_GET_FLOW, 0, modem_ctl, 16); | |
568 | 678 | if (modem_ctl[0] & 0x0008) { |
569 | 679 | dbg("%s - flow control = CRTSCTS", __func__); |
570 | 680 | cflag |= CRTSCTS; |
571 | 681 | |
... | ... | @@ -576,11 +686,64 @@ |
576 | 686 | *cflagp = cflag; |
577 | 687 | } |
578 | 688 | |
689 | +/* | |
690 | + * CP2101 supports the following baud rates: | |
691 | + * | |
692 | + * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800, | |
693 | + * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600 | |
694 | + * | |
695 | + * CP2102 and CP2103 support the following additional rates: | |
696 | + * | |
697 | + * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000, | |
698 | + * 576000 | |
699 | + * | |
700 | + * The device will map a requested rate to a supported one, but the result | |
701 | + * of requests for rates greater than 1053257 is undefined (see AN205). | |
702 | + * | |
703 | + * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud, | |
704 | + * respectively, with an error less than 1%. The actual rates are determined | |
705 | + * by | |
706 | + * | |
707 | + * div = round(freq / (2 x prescale x request)) | |
708 | + * actual = freq / (2 x prescale x div) | |
709 | + * | |
710 | + * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps | |
711 | + * or 1 otherwise. | |
712 | + * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1 | |
713 | + * otherwise. | |
714 | + */ | |
715 | +static void cp210x_change_speed(struct tty_struct *tty, | |
716 | + struct usb_serial_port *port, struct ktermios *old_termios) | |
717 | +{ | |
718 | + u32 baud; | |
719 | + | |
720 | + baud = tty->termios->c_ospeed; | |
721 | + | |
722 | + /* This maps the requested rate to a rate valid on cp2102 or cp2103, | |
723 | + * or to an arbitrary rate in [1M,2M]. | |
724 | + * | |
725 | + * NOTE: B0 is not implemented. | |
726 | + */ | |
727 | + baud = cp210x_quantise_baudrate(baud); | |
728 | + | |
729 | + dbg("%s - setting baud rate to %u", __func__, baud); | |
730 | + if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
731 | + CP210X_SET_BAUDRATE, 0, &baud, sizeof(baud))) { | |
732 | + dev_warn(&port->dev, "failed to set baud rate to %u\n", baud); | |
733 | + if (old_termios) | |
734 | + baud = old_termios->c_ospeed; | |
735 | + else | |
736 | + baud = 9600; | |
737 | + } | |
738 | + | |
739 | + tty_encode_baud_rate(tty, baud, baud); | |
740 | +} | |
741 | + | |
579 | 742 | static void cp210x_set_termios(struct tty_struct *tty, |
580 | 743 | struct usb_serial_port *port, struct ktermios *old_termios) |
581 | 744 | { |
582 | 745 | unsigned int cflag, old_cflag; |
583 | - unsigned int baud = 0, bits; | |
746 | + unsigned int bits; | |
584 | 747 | unsigned int modem_ctl[4]; |
585 | 748 | |
586 | 749 | dbg("%s - port %d", __func__, port->number); |
587 | 750 | |
588 | 751 | |
589 | 752 | |
... | ... | @@ -588,27 +751,15 @@ |
588 | 751 | if (!tty) |
589 | 752 | return; |
590 | 753 | |
591 | - tty->termios->c_cflag &= ~CMSPAR; | |
592 | 754 | cflag = tty->termios->c_cflag; |
593 | 755 | old_cflag = old_termios->c_cflag; |
594 | - baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); | |
595 | 756 | |
596 | - /* If the baud rate is to be updated*/ | |
597 | - if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { | |
598 | - dbg("%s - Setting baud rate to %d baud", __func__, | |
599 | - baud); | |
600 | - if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV, | |
601 | - ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { | |
602 | - dbg("Baud rate requested not supported by device"); | |
603 | - baud = tty_termios_baud_rate(old_termios); | |
604 | - } | |
605 | - } | |
606 | - /* Report back the resulting baud rate */ | |
607 | - tty_encode_baud_rate(tty, baud, baud); | |
757 | + cp210x_change_speed(tty, port, old_termios); | |
608 | 758 | |
609 | 759 | /* If the number of data bits is to be updated */ |
610 | 760 | if ((cflag & CSIZE) != (old_cflag & CSIZE)) { |
611 | - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); | |
761 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
762 | + CP210X_GET_LINE_CTL, 0, &bits, 2); | |
612 | 763 | bits &= ~BITS_DATA_MASK; |
613 | 764 | switch (cflag & CSIZE) { |
614 | 765 | case CS5: |
615 | 766 | |
616 | 767 | |
617 | 768 | |
618 | 769 | |
619 | 770 | |
620 | 771 | |
... | ... | @@ -638,30 +789,45 @@ |
638 | 789 | bits |= BITS_DATA_8; |
639 | 790 | break; |
640 | 791 | } |
641 | - if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) | |
792 | + if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
793 | + CP210X_SET_LINE_CTL, 0, &bits, 2)) | |
642 | 794 | dbg("Number of data bits requested " |
643 | 795 | "not supported by device\n"); |
644 | 796 | } |
645 | 797 | |
646 | - if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { | |
647 | - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); | |
798 | + if ((cflag & (PARENB|PARODD|CMSPAR)) != | |
799 | + (old_cflag & (PARENB|PARODD|CMSPAR))) { | |
800 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
801 | + CP210X_GET_LINE_CTL, 0, &bits, 2); | |
648 | 802 | bits &= ~BITS_PARITY_MASK; |
649 | 803 | if (cflag & PARENB) { |
804 | + if (cflag & CMSPAR) { | |
650 | 805 | if (cflag & PARODD) { |
806 | + bits |= BITS_PARITY_MARK; | |
807 | + dbg("%s - parity = MARK", __func__); | |
808 | + } else { | |
809 | + bits |= BITS_PARITY_SPACE; | |
810 | + dbg("%s - parity = SPACE", __func__); | |
811 | + } | |
812 | + } else { | |
813 | + if (cflag & PARODD) { | |
651 | 814 | bits |= BITS_PARITY_ODD; |
652 | 815 | dbg("%s - parity = ODD", __func__); |
653 | 816 | } else { |
654 | 817 | bits |= BITS_PARITY_EVEN; |
655 | 818 | dbg("%s - parity = EVEN", __func__); |
656 | 819 | } |
820 | + } | |
657 | 821 | } |
658 | - if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) | |
822 | + if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
823 | + CP210X_SET_LINE_CTL, 0, &bits, 2)) | |
659 | 824 | dbg("Parity mode not supported " |
660 | 825 | "by device\n"); |
661 | 826 | } |
662 | 827 | |
663 | 828 | if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { |
664 | - cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); | |
829 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
830 | + CP210X_GET_LINE_CTL, 0, &bits, 2); | |
665 | 831 | bits &= ~BITS_STOP_MASK; |
666 | 832 | if (cflag & CSTOPB) { |
667 | 833 | bits |= BITS_STOP_2; |
668 | 834 | |
... | ... | @@ -670,13 +836,15 @@ |
670 | 836 | bits |= BITS_STOP_1; |
671 | 837 | dbg("%s - stop bits = 1", __func__); |
672 | 838 | } |
673 | - if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) | |
839 | + if (cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
840 | + CP210X_SET_LINE_CTL, 0, &bits, 2)) | |
674 | 841 | dbg("Number of stop bits requested " |
675 | 842 | "not supported by device\n"); |
676 | 843 | } |
677 | 844 | |
678 | 845 | if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { |
679 | - cp210x_get_config(port, CP210X_GET_FLOW, modem_ctl, 16); | |
846 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
847 | + CP210X_GET_FLOW, 0, modem_ctl, 16); | |
680 | 848 | dbg("%s - read modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", |
681 | 849 | __func__, modem_ctl[0], modem_ctl[1], |
682 | 850 | modem_ctl[2], modem_ctl[3]); |
... | ... | @@ -696,7 +864,8 @@ |
696 | 864 | dbg("%s - write modem controls = 0x%.4x 0x%.4x 0x%.4x 0x%.4x", |
697 | 865 | __func__, modem_ctl[0], modem_ctl[1], |
698 | 866 | modem_ctl[2], modem_ctl[3]); |
699 | - cp210x_set_config(port, CP210X_SET_FLOW, modem_ctl, 16); | |
867 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
868 | + CP210X_SET_FLOW, 0, modem_ctl, 16); | |
700 | 869 | } |
701 | 870 | |
702 | 871 | } |
... | ... | @@ -734,7 +903,8 @@ |
734 | 903 | |
735 | 904 | dbg("%s - control = 0x%.4x", __func__, control); |
736 | 905 | |
737 | - return cp210x_set_config(port, CP210X_SET_MHS, &control, 2); | |
906 | + return cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
907 | + CP210X_SET_MHS, 0, &control, 2); | |
738 | 908 | } |
739 | 909 | |
740 | 910 | static void cp210x_dtr_rts(struct usb_serial_port *p, int on) |
... | ... | @@ -753,7 +923,8 @@ |
753 | 923 | |
754 | 924 | dbg("%s - port %d", __func__, port->number); |
755 | 925 | |
756 | - cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1); | |
926 | + cp210x_get_config(port, REQTYPE_INTERFACE_TO_HOST, | |
927 | + CP210X_GET_MDMSTS, 0, &control, 1); | |
757 | 928 | |
758 | 929 | result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) |
759 | 930 | |((control & CONTROL_RTS) ? TIOCM_RTS : 0) |
760 | 931 | |
761 | 932 | |
... | ... | @@ -779,14 +950,50 @@ |
779 | 950 | state = BREAK_ON; |
780 | 951 | dbg("%s - turning break %s", __func__, |
781 | 952 | state == BREAK_OFF ? "off" : "on"); |
782 | - cp210x_set_config(port, CP210X_SET_BREAK, &state, 2); | |
953 | + cp210x_set_config(port, REQTYPE_HOST_TO_INTERFACE, | |
954 | + CP210X_SET_BREAK, 0, &state, 2); | |
783 | 955 | } |
784 | 956 | |
785 | 957 | static int cp210x_startup(struct usb_serial *serial) |
786 | 958 | { |
959 | + struct cp210x_port_private *port_priv; | |
960 | + int i; | |
961 | + unsigned int partNum; | |
962 | + | |
787 | 963 | /* cp210x buffers behave strangely unless device is reset */ |
788 | 964 | usb_reset_device(serial->dev); |
789 | - return 0; | |
965 | + | |
966 | + for (i = 0; i < serial->num_ports; i++) { | |
967 | + port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); | |
968 | + if (!port_priv) | |
969 | + return -ENOMEM; | |
970 | + | |
971 | + memset(port_priv, 0x00, sizeof(*port_priv)); | |
972 | + port_priv->bInterfaceNumber = | |
973 | + serial->interface->cur_altsetting->desc.bInterfaceNumber; | |
974 | + | |
975 | + usb_set_serial_port_data(serial->port[i], port_priv); | |
976 | + | |
977 | + /* Get the 1-byte part number of the cp210x device */ | |
978 | + cp210x_get_config(serial->port[i], | |
979 | + REQTYPE_DEVICE_TO_HOST, CP210X_VENDOR_SPECIFIC, | |
980 | + CP210X_GET_PARTNUM, &partNum, 1); | |
981 | + port_priv->bPartNumber = partNum & 0xFF; | |
982 | + } | |
983 | + | |
984 | + return 0; | |
985 | +} | |
986 | + | |
987 | +static void cp210x_release(struct usb_serial *serial) | |
988 | +{ | |
989 | + struct cp210x_port_private *port_priv; | |
990 | + int i; | |
991 | + | |
992 | + for (i = 0; i < serial->num_ports; i++) { | |
993 | + port_priv = usb_get_serial_port_data(serial->port[i]); | |
994 | + kfree(port_priv); | |
995 | + usb_set_serial_port_data(serial->port[i], NULL); | |
996 | + } | |
790 | 997 | } |
791 | 998 | |
792 | 999 | static int __init cp210x_init(void) |