Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: serial: mos7840: add support for MCS7810 devices

This patch added the support of MCS7810 device for the mos7840 driver.
The MCS7810 device supports single USB2.0-to-Serial port with
a LED indicator for reflecting transmission or reception activity.

Signed-off-by: Donald Lee <donald@asix.com.tw>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Donald and committed by
Greg Kroah-Hartman
0eafe4de c256667f

+188 -14
+188 -14
drivers/usb/serial/mos7840.c
··· 114 114 #define USB_VENDOR_ID_MOSCHIP 0x9710 115 115 #define MOSCHIP_DEVICE_ID_7840 0x7840 116 116 #define MOSCHIP_DEVICE_ID_7820 0x7820 117 + #define MOSCHIP_DEVICE_ID_7810 0x7810 117 118 /* The native component can have its vendor/device id's overridden 118 119 * in vendor-specific implementations. Such devices can be handled 119 120 * by making a change here, in moschip_port_id_table, and in ··· 185 184 #define NUM_URBS 16 /* URB Count */ 186 185 #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ 187 186 187 + /* LED on/off milliseconds*/ 188 + #define LED_ON_MS 500 189 + #define LED_OFF_MS 500 190 + 191 + static int device_type; 188 192 189 193 static const struct usb_device_id moschip_port_id_table[] = { 190 194 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, 191 195 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, 196 + {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, 192 197 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, 193 198 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, 194 199 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, ··· 216 209 static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { 217 210 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, 218 211 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, 212 + {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, 219 213 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, 220 214 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, 221 215 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, ··· 269 261 struct urb *write_urb_pool[NUM_URBS]; 270 262 char busy[NUM_URBS]; 271 263 bool read_urb_busy; 272 - }; 273 264 265 + /* For device(s) with LED indicator */ 266 + bool has_led; 267 + bool led_flag; 268 + struct timer_list led_timer1; /* Timer for LED on */ 269 + struct timer_list led_timer2; /* Timer for LED off */ 270 + }; 274 271 275 272 static bool debug; 276 273 ··· 585 572 return ret; 586 573 } 587 574 575 + static void mos7840_set_led_callback(struct urb *urb) 576 + { 577 + switch (urb->status) { 578 + case 0: 579 + /* Success */ 580 + break; 581 + case -ECONNRESET: 582 + case -ENOENT: 583 + case -ESHUTDOWN: 584 + /* This urb is terminated, clean up */ 585 + dbg("%s - urb shutting down with status: %d", __func__, 586 + urb->status); 587 + break; 588 + default: 589 + dbg("%s - nonzero urb status received: %d", __func__, 590 + urb->status); 591 + } 592 + } 593 + 594 + static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, 595 + __u16 reg) 596 + { 597 + struct usb_device *dev = mcs->port->serial->dev; 598 + struct usb_ctrlrequest *dr = mcs->dr; 599 + 600 + dr->bRequestType = MCS_WR_RTYPE; 601 + dr->bRequest = MCS_WRREQ; 602 + dr->wValue = cpu_to_le16(wval); 603 + dr->wIndex = cpu_to_le16(reg); 604 + dr->wLength = cpu_to_le16(0); 605 + 606 + usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0), 607 + (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); 608 + 609 + usb_submit_urb(mcs->control_urb, GFP_ATOMIC); 610 + } 611 + 612 + static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, 613 + __u16 val) 614 + { 615 + struct usb_device *dev = port->serial->dev; 616 + 617 + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, 618 + val, reg, NULL, 0, MOS_WDR_TIMEOUT); 619 + } 620 + 621 + static void mos7840_led_off(unsigned long arg) 622 + { 623 + struct moschip_port *mcs = (struct moschip_port *) arg; 624 + 625 + /* Turn off LED */ 626 + mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER); 627 + mod_timer(&mcs->led_timer2, 628 + jiffies + msecs_to_jiffies(LED_OFF_MS)); 629 + } 630 + 631 + static void mos7840_led_flag_off(unsigned long arg) 632 + { 633 + struct moschip_port *mcs = (struct moschip_port *) arg; 634 + 635 + mcs->led_flag = false; 636 + } 637 + 588 638 /***************************************************************************** 589 639 * mos7840_interrupt_callback 590 640 * this is the callback function for when we have received data on the ··· 868 792 return; 869 793 } 870 794 795 + /* Turn on LED */ 796 + if (mos7840_port->has_led && !mos7840_port->led_flag) { 797 + mos7840_port->led_flag = true; 798 + mos7840_set_led_async(mos7840_port, 0x0301, 799 + MODEM_CONTROL_REGISTER); 800 + mod_timer(&mos7840_port->led_timer1, 801 + jiffies + msecs_to_jiffies(LED_ON_MS)); 802 + } 871 803 872 804 mos7840_port->read_urb_busy = true; 873 805 retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); ··· 1637 1553 1638 1554 data1 = urb->transfer_buffer; 1639 1555 dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); 1556 + 1557 + /* Turn on LED */ 1558 + if (mos7840_port->has_led && !mos7840_port->led_flag) { 1559 + mos7840_port->led_flag = true; 1560 + mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301); 1561 + mod_timer(&mos7840_port->led_timer1, 1562 + jiffies + msecs_to_jiffies(LED_ON_MS)); 1563 + } 1640 1564 1641 1565 /* send it down the pipe */ 1642 1566 status = usb_submit_urb(urb, GFP_ATOMIC); ··· 2419 2327 return -ENOIOCTLCMD; 2420 2328 } 2421 2329 2330 + static int mos7810_check(struct usb_serial *serial) 2331 + { 2332 + int i, pass_count = 0; 2333 + __u16 data = 0, mcr_data = 0; 2334 + __u16 test_pattern = 0x55AA; 2335 + 2336 + /* Store MCR setting */ 2337 + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2338 + MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER, 2339 + &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); 2340 + 2341 + for (i = 0; i < 16; i++) { 2342 + /* Send the 1-bit test pattern out to MCS7810 test pin */ 2343 + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), 2344 + MCS_WRREQ, MCS_WR_RTYPE, 2345 + (0x0300 | (((test_pattern >> i) & 0x0001) << 1)), 2346 + MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT); 2347 + 2348 + /* Read the test pattern back */ 2349 + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2350 + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, 2351 + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); 2352 + 2353 + /* If this is a MCS7810 device, both test patterns must match */ 2354 + if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001) 2355 + break; 2356 + 2357 + pass_count++; 2358 + } 2359 + 2360 + /* Restore MCR setting */ 2361 + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ, 2362 + MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL, 2363 + 0, MOS_WDR_TIMEOUT); 2364 + 2365 + if (pass_count == 16) 2366 + return 1; 2367 + 2368 + return 0; 2369 + } 2370 + 2422 2371 static int mos7840_calc_num_ports(struct usb_serial *serial) 2423 2372 { 2424 - __u16 Data = 0x00; 2425 - int ret = 0; 2373 + __u16 data = 0x00; 2426 2374 int mos7840_num_ports; 2427 2375 2428 - ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2429 - MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, 2376 + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2377 + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, 2430 2378 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); 2431 2379 2432 - if ((Data & 0x01) == 0) { 2433 - mos7840_num_ports = 2; 2434 - serial->num_bulk_in = 2; 2435 - serial->num_bulk_out = 2; 2436 - serial->num_ports = 2; 2380 + if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || 2381 + serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { 2382 + device_type = serial->dev->descriptor.idProduct; 2437 2383 } else { 2438 - mos7840_num_ports = 4; 2439 - serial->num_bulk_in = 4; 2440 - serial->num_bulk_out = 4; 2441 - serial->num_ports = 4; 2384 + /* For a MCS7840 device GPIO0 must be set to 1 */ 2385 + if ((data & 0x01) == 1) 2386 + device_type = MOSCHIP_DEVICE_ID_7840; 2387 + else if (mos7810_check(serial)) 2388 + device_type = MOSCHIP_DEVICE_ID_7810; 2389 + else 2390 + device_type = MOSCHIP_DEVICE_ID_7820; 2442 2391 } 2392 + 2393 + mos7840_num_ports = (device_type >> 4) & 0x000F; 2394 + serial->num_bulk_in = mos7840_num_ports; 2395 + serial->num_bulk_out = mos7840_num_ports; 2396 + serial->num_ports = mos7840_num_ports; 2443 2397 2444 2398 return mos7840_num_ports; 2445 2399 } ··· 2701 2563 status = -ENOMEM; 2702 2564 goto error; 2703 2565 } 2566 + 2567 + mos7840_port->has_led = false; 2568 + 2569 + /* Initialize LED timers */ 2570 + if (device_type == MOSCHIP_DEVICE_ID_7810) { 2571 + mos7840_port->has_led = true; 2572 + 2573 + init_timer(&mos7840_port->led_timer1); 2574 + mos7840_port->led_timer1.function = mos7840_led_off; 2575 + mos7840_port->led_timer1.expires = 2576 + jiffies + msecs_to_jiffies(LED_ON_MS); 2577 + mos7840_port->led_timer1.data = 2578 + (unsigned long)mos7840_port; 2579 + 2580 + init_timer(&mos7840_port->led_timer2); 2581 + mos7840_port->led_timer2.function = 2582 + mos7840_led_flag_off; 2583 + mos7840_port->led_timer2.expires = 2584 + jiffies + msecs_to_jiffies(LED_OFF_MS); 2585 + mos7840_port->led_timer2.data = 2586 + (unsigned long)mos7840_port; 2587 + 2588 + mos7840_port->led_flag = false; 2589 + 2590 + /* Turn off LED */ 2591 + mos7840_set_led_sync(serial->port[i], 2592 + MODEM_CONTROL_REGISTER, 0x0300); 2593 + } 2704 2594 } 2705 2595 dbg ("mos7840_startup: all ports configured..........."); 2706 2596 ··· 2820 2654 mos7840_port = mos7840_get_port_private(serial->port[i]); 2821 2655 dbg("mos7840_port %d = %p", i, mos7840_port); 2822 2656 if (mos7840_port) { 2657 + if (mos7840_port->has_led) { 2658 + /* Turn off LED */ 2659 + mos7840_set_led_sync(mos7840_port->port, 2660 + MODEM_CONTROL_REGISTER, 0x0300); 2661 + 2662 + del_timer_sync(&mos7840_port->led_timer1); 2663 + del_timer_sync(&mos7840_port->led_timer2); 2664 + } 2823 2665 kfree(mos7840_port->ctrl_buf); 2824 2666 kfree(mos7840_port->dr); 2825 2667 kfree(mos7840_port);