aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/mos7840.c
diff options
context:
space:
mode:
authorDonald <donald@asix.com.tw>2012-04-19 03:00:45 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-19 22:08:10 -0400
commit0eafe4de1a689b69d3f0ce0b5d4aa5333208fd4a (patch)
tree55a74ab881fef9320d3c4f0861993febd1158c12 /drivers/usb/serial/mos7840.c
parentc256667f0468ebb353c9b11b7feed5c5cba1bd9a (diff)
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>
Diffstat (limited to 'drivers/usb/serial/mos7840.c')
-rw-r--r--drivers/usb/serial/mos7840.c202
1 files changed, 188 insertions, 14 deletions
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c526550694a0..aaef523955e0 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -114,6 +114,7 @@
114#define USB_VENDOR_ID_MOSCHIP 0x9710 114#define USB_VENDOR_ID_MOSCHIP 0x9710
115#define MOSCHIP_DEVICE_ID_7840 0x7840 115#define MOSCHIP_DEVICE_ID_7840 0x7840
116#define MOSCHIP_DEVICE_ID_7820 0x7820 116#define MOSCHIP_DEVICE_ID_7820 0x7820
117#define MOSCHIP_DEVICE_ID_7810 0x7810
117/* The native component can have its vendor/device id's overridden 118/* The native component can have its vendor/device id's overridden
118 * in vendor-specific implementations. Such devices can be handled 119 * in vendor-specific implementations. Such devices can be handled
119 * by making a change here, in moschip_port_id_table, and in 120 * by making a change here, in moschip_port_id_table, and in
@@ -184,10 +185,16 @@
184#define NUM_URBS 16 /* URB Count */ 185#define NUM_URBS 16 /* URB Count */
185#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ 186#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
186 187
188/* LED on/off milliseconds*/
189#define LED_ON_MS 500
190#define LED_OFF_MS 500
191
192static int device_type;
187 193
188static const struct usb_device_id moschip_port_id_table[] = { 194static const struct usb_device_id moschip_port_id_table[] = {
189 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, 195 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
190 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, 196 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
197 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
191 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, 198 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
192 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, 199 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
193 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, 200 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
@@ -209,6 +216,7 @@ static const struct usb_device_id moschip_port_id_table[] = {
209static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { 216static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
210 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, 217 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
211 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, 218 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
219 {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)},
212 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, 220 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
213 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, 221 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)},
214 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, 222 {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)},
@@ -261,8 +269,13 @@ struct moschip_port {
261 struct urb *write_urb_pool[NUM_URBS]; 269 struct urb *write_urb_pool[NUM_URBS];
262 char busy[NUM_URBS]; 270 char busy[NUM_URBS];
263 bool read_urb_busy; 271 bool read_urb_busy;
264};
265 272
273 /* For device(s) with LED indicator */
274 bool has_led;
275 bool led_flag;
276 struct timer_list led_timer1; /* Timer for LED on */
277 struct timer_list led_timer2; /* Timer for LED off */
278};
266 279
267static bool debug; 280static bool debug;
268 281
@@ -572,6 +585,69 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
572 return ret; 585 return ret;
573} 586}
574 587
588static void mos7840_set_led_callback(struct urb *urb)
589{
590 switch (urb->status) {
591 case 0:
592 /* Success */
593 break;
594 case -ECONNRESET:
595 case -ENOENT:
596 case -ESHUTDOWN:
597 /* This urb is terminated, clean up */
598 dbg("%s - urb shutting down with status: %d", __func__,
599 urb->status);
600 break;
601 default:
602 dbg("%s - nonzero urb status received: %d", __func__,
603 urb->status);
604 }
605}
606
607static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval,
608 __u16 reg)
609{
610 struct usb_device *dev = mcs->port->serial->dev;
611 struct usb_ctrlrequest *dr = mcs->dr;
612
613 dr->bRequestType = MCS_WR_RTYPE;
614 dr->bRequest = MCS_WRREQ;
615 dr->wValue = cpu_to_le16(wval);
616 dr->wIndex = cpu_to_le16(reg);
617 dr->wLength = cpu_to_le16(0);
618
619 usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0),
620 (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL);
621
622 usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
623}
624
625static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg,
626 __u16 val)
627{
628 struct usb_device *dev = port->serial->dev;
629
630 usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE,
631 val, reg, NULL, 0, MOS_WDR_TIMEOUT);
632}
633
634static void mos7840_led_off(unsigned long arg)
635{
636 struct moschip_port *mcs = (struct moschip_port *) arg;
637
638 /* Turn off LED */
639 mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER);
640 mod_timer(&mcs->led_timer2,
641 jiffies + msecs_to_jiffies(LED_OFF_MS));
642}
643
644static void mos7840_led_flag_off(unsigned long arg)
645{
646 struct moschip_port *mcs = (struct moschip_port *) arg;
647
648 mcs->led_flag = false;
649}
650
575/***************************************************************************** 651/*****************************************************************************
576 * mos7840_interrupt_callback 652 * mos7840_interrupt_callback
577 * this is the callback function for when we have received data on the 653 * this is the callback function for when we have received data on the
@@ -792,6 +868,14 @@ static void mos7840_bulk_in_callback(struct urb *urb)
792 return; 868 return;
793 } 869 }
794 870
871 /* Turn on LED */
872 if (mos7840_port->has_led && !mos7840_port->led_flag) {
873 mos7840_port->led_flag = true;
874 mos7840_set_led_async(mos7840_port, 0x0301,
875 MODEM_CONTROL_REGISTER);
876 mod_timer(&mos7840_port->led_timer1,
877 jiffies + msecs_to_jiffies(LED_ON_MS));
878 }
795 879
796 mos7840_port->read_urb_busy = true; 880 mos7840_port->read_urb_busy = true;
797 retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); 881 retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
@@ -1554,6 +1638,14 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
1554 data1 = urb->transfer_buffer; 1638 data1 = urb->transfer_buffer;
1555 dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); 1639 dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
1556 1640
1641 /* Turn on LED */
1642 if (mos7840_port->has_led && !mos7840_port->led_flag) {
1643 mos7840_port->led_flag = true;
1644 mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301);
1645 mod_timer(&mos7840_port->led_timer1,
1646 jiffies + msecs_to_jiffies(LED_ON_MS));
1647 }
1648
1557 /* send it down the pipe */ 1649 /* send it down the pipe */
1558 status = usb_submit_urb(urb, GFP_ATOMIC); 1650 status = usb_submit_urb(urb, GFP_ATOMIC);
1559 1651
@@ -2327,28 +2419,74 @@ static int mos7840_ioctl(struct tty_struct *tty,
2327 return -ENOIOCTLCMD; 2419 return -ENOIOCTLCMD;
2328} 2420}
2329 2421
2422static int mos7810_check(struct usb_serial *serial)
2423{
2424 int i, pass_count = 0;
2425 __u16 data = 0, mcr_data = 0;
2426 __u16 test_pattern = 0x55AA;
2427
2428 /* Store MCR setting */
2429 usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
2430 MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER,
2431 &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2432
2433 for (i = 0; i < 16; i++) {
2434 /* Send the 1-bit test pattern out to MCS7810 test pin */
2435 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
2436 MCS_WRREQ, MCS_WR_RTYPE,
2437 (0x0300 | (((test_pattern >> i) & 0x0001) << 1)),
2438 MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT);
2439
2440 /* Read the test pattern back */
2441 usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
2442 MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
2443 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2444
2445 /* If this is a MCS7810 device, both test patterns must match */
2446 if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001)
2447 break;
2448
2449 pass_count++;
2450 }
2451
2452 /* Restore MCR setting */
2453 usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ,
2454 MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL,
2455 0, MOS_WDR_TIMEOUT);
2456
2457 if (pass_count == 16)
2458 return 1;
2459
2460 return 0;
2461}
2462
2330static int mos7840_calc_num_ports(struct usb_serial *serial) 2463static int mos7840_calc_num_ports(struct usb_serial *serial)
2331{ 2464{
2332 __u16 Data = 0x00; 2465 __u16 data = 0x00;
2333 int ret = 0;
2334 int mos7840_num_ports; 2466 int mos7840_num_ports;
2335 2467
2336 ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), 2468 usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
2337 MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, 2469 MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data,
2338 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); 2470 VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
2339 2471
2340 if ((Data & 0x01) == 0) { 2472 if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 ||
2341 mos7840_num_ports = 2; 2473 serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) {
2342 serial->num_bulk_in = 2; 2474 device_type = serial->dev->descriptor.idProduct;
2343 serial->num_bulk_out = 2;
2344 serial->num_ports = 2;
2345 } else { 2475 } else {
2346 mos7840_num_ports = 4; 2476 /* For a MCS7840 device GPIO0 must be set to 1 */
2347 serial->num_bulk_in = 4; 2477 if ((data & 0x01) == 1)
2348 serial->num_bulk_out = 4; 2478 device_type = MOSCHIP_DEVICE_ID_7840;
2349 serial->num_ports = 4; 2479 else if (mos7810_check(serial))
2480 device_type = MOSCHIP_DEVICE_ID_7810;
2481 else
2482 device_type = MOSCHIP_DEVICE_ID_7820;
2350 } 2483 }
2351 2484
2485 mos7840_num_ports = (device_type >> 4) & 0x000F;
2486 serial->num_bulk_in = mos7840_num_ports;
2487 serial->num_bulk_out = mos7840_num_ports;
2488 serial->num_ports = mos7840_num_ports;
2489
2352 return mos7840_num_ports; 2490 return mos7840_num_ports;
2353} 2491}
2354 2492
@@ -2563,6 +2701,34 @@ static int mos7840_startup(struct usb_serial *serial)
2563 status = -ENOMEM; 2701 status = -ENOMEM;
2564 goto error; 2702 goto error;
2565 } 2703 }
2704
2705 mos7840_port->has_led = false;
2706
2707 /* Initialize LED timers */
2708 if (device_type == MOSCHIP_DEVICE_ID_7810) {
2709 mos7840_port->has_led = true;
2710
2711 init_timer(&mos7840_port->led_timer1);
2712 mos7840_port->led_timer1.function = mos7840_led_off;
2713 mos7840_port->led_timer1.expires =
2714 jiffies + msecs_to_jiffies(LED_ON_MS);
2715 mos7840_port->led_timer1.data =
2716 (unsigned long)mos7840_port;
2717
2718 init_timer(&mos7840_port->led_timer2);
2719 mos7840_port->led_timer2.function =
2720 mos7840_led_flag_off;
2721 mos7840_port->led_timer2.expires =
2722 jiffies + msecs_to_jiffies(LED_OFF_MS);
2723 mos7840_port->led_timer2.data =
2724 (unsigned long)mos7840_port;
2725
2726 mos7840_port->led_flag = false;
2727
2728 /* Turn off LED */
2729 mos7840_set_led_sync(serial->port[i],
2730 MODEM_CONTROL_REGISTER, 0x0300);
2731 }
2566 } 2732 }
2567 dbg ("mos7840_startup: all ports configured..........."); 2733 dbg ("mos7840_startup: all ports configured...........");
2568 2734
@@ -2654,6 +2820,14 @@ static void mos7840_release(struct usb_serial *serial)
2654 mos7840_port = mos7840_get_port_private(serial->port[i]); 2820 mos7840_port = mos7840_get_port_private(serial->port[i]);
2655 dbg("mos7840_port %d = %p", i, mos7840_port); 2821 dbg("mos7840_port %d = %p", i, mos7840_port);
2656 if (mos7840_port) { 2822 if (mos7840_port) {
2823 if (mos7840_port->has_led) {
2824 /* Turn off LED */
2825 mos7840_set_led_sync(mos7840_port->port,
2826 MODEM_CONTROL_REGISTER, 0x0300);
2827
2828 del_timer_sync(&mos7840_port->led_timer1);
2829 del_timer_sync(&mos7840_port->led_timer2);
2830 }
2657 kfree(mos7840_port->ctrl_buf); 2831 kfree(mos7840_port->ctrl_buf);
2658 kfree(mos7840_port->dr); 2832 kfree(mos7840_port->dr);
2659 kfree(mos7840_port); 2833 kfree(mos7840_port);