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

USB: serial: f81232: add control driver for F81534A

The Fintek F81534A series contains 1 HUB, 1 GPIO device and n UARTs. The
UARTs are disabled by default and need to be enabled by the GPIO device
(2c42:16F8).

When F81534A plug to host, we can only see 1 HUB and 1 GPIO device and
we write 0x8fff to GPIO device register F81534A_CTRL_CMD_ENABLE_PORT
(116h) to enable all available serial ports.

Signed-off-by: Ji-Ze Hong (Peter Hong) <hpeter+linux_kernel@gmail.com>
[johan: reword commit message and an error message slightly]
Signed-off-by: Johan Hovold <johan@kernel.org>

authored by

Ji-Ze Hong (Peter Hong) and committed by
Johan Hovold
33a6b48a 615e58cc

+134 -1
+134 -1
drivers/usb/serial/f81232.c
··· 36 36 { USB_DEVICE(0x2c42, 0x1635) }, /* 8 port UART device */ \ 37 37 { USB_DEVICE(0x2c42, 0x1636) } /* 12 port UART device */ 38 38 39 + #define F81534A_CTRL_ID \ 40 + { USB_DEVICE(0x2c42, 0x16f8) } /* Global control device */ 41 + 39 42 static const struct usb_device_id f81232_id_table[] = { 40 43 F81232_ID, 41 44 { } /* Terminating entry */ ··· 49 46 { } /* Terminating entry */ 50 47 }; 51 48 49 + static const struct usb_device_id f81534a_ctrl_id_table[] = { 50 + F81534A_CTRL_ID, 51 + { } /* Terminating entry */ 52 + }; 53 + 52 54 static const struct usb_device_id combined_id_table[] = { 53 55 F81232_ID, 54 56 F81534A_SERIES_ID, 57 + F81534A_CTRL_ID, 55 58 { } /* Terminating entry */ 56 59 }; 57 60 MODULE_DEVICE_TABLE(usb, combined_id_table); ··· 70 61 #define F81232_REGISTER_REQUEST 0xa0 71 62 #define F81232_GET_REGISTER 0xc0 72 63 #define F81232_SET_REGISTER 0x40 64 + #define F81534A_ACCESS_REG_RETRY 2 73 65 74 66 #define SERIAL_BASE_ADDRESS 0x0120 75 67 #define RECEIVE_BUFFER_REGISTER (0x00 + SERIAL_BASE_ADDRESS) ··· 110 100 #define F81534A_GPIO_MODE2_OUTPUT BIT(2) 111 101 #define F81534A_GPIO_MODE1_OUTPUT BIT(1) 112 102 #define F81534A_GPIO_MODE0_OUTPUT BIT(0) 103 + 104 + #define F81534A_CTRL_CMD_ENABLE_PORT 0x116 113 105 114 106 struct f81232_private { 115 107 struct mutex lock; ··· 860 848 dev_warn(&port->dev, "read LSR failed: %d\n", status); 861 849 } 862 850 851 + static int f81534a_ctrl_set_register(struct usb_interface *intf, u16 reg, 852 + u16 size, void *val) 853 + { 854 + struct usb_device *dev = interface_to_usbdev(intf); 855 + int retry = F81534A_ACCESS_REG_RETRY; 856 + int status; 857 + u8 *tmp; 858 + 859 + tmp = kmemdup(val, size, GFP_KERNEL); 860 + if (!tmp) 861 + return -ENOMEM; 862 + 863 + while (retry--) { 864 + status = usb_control_msg(dev, 865 + usb_sndctrlpipe(dev, 0), 866 + F81232_REGISTER_REQUEST, 867 + F81232_SET_REGISTER, 868 + reg, 869 + 0, 870 + tmp, 871 + size, 872 + USB_CTRL_SET_TIMEOUT); 873 + if (status < 0) { 874 + status = usb_translate_errors(status); 875 + if (status == -EIO) 876 + continue; 877 + } else if (status != size) { 878 + /* Retry on short transfers */ 879 + status = -EIO; 880 + continue; 881 + } else { 882 + status = 0; 883 + } 884 + 885 + break; 886 + } 887 + 888 + if (status) { 889 + dev_err(&intf->dev, "failed to set register 0x%x: %d\n", 890 + reg, status); 891 + } 892 + 893 + kfree(tmp); 894 + return status; 895 + } 896 + 897 + static int f81534a_ctrl_enable_all_ports(struct usb_interface *intf, bool en) 898 + { 899 + unsigned char enable[2] = {0}; 900 + int status; 901 + 902 + /* 903 + * Enable all available serial ports, define as following: 904 + * bit 15 : Reset behavior (when HUB got soft reset) 905 + * 0: maintain all serial port enabled state. 906 + * 1: disable all serial port. 907 + * bit 0~11 : Serial port enable bit. 908 + */ 909 + if (en) { 910 + enable[0] = 0xff; 911 + enable[1] = 0x8f; 912 + } 913 + 914 + status = f81534a_ctrl_set_register(intf, F81534A_CTRL_CMD_ENABLE_PORT, 915 + sizeof(enable), enable); 916 + if (status) 917 + dev_err(&intf->dev, "failed to enable ports: %d\n", status); 918 + 919 + return status; 920 + } 921 + 922 + static int f81534a_ctrl_probe(struct usb_interface *intf, 923 + const struct usb_device_id *id) 924 + { 925 + return f81534a_ctrl_enable_all_ports(intf, true); 926 + } 927 + 928 + static void f81534a_ctrl_disconnect(struct usb_interface *intf) 929 + { 930 + f81534a_ctrl_enable_all_ports(intf, false); 931 + } 932 + 933 + static int f81534a_ctrl_resume(struct usb_interface *intf) 934 + { 935 + return f81534a_ctrl_enable_all_ports(intf, true); 936 + } 937 + 863 938 static int f81232_port_probe(struct usb_serial_port *port) 864 939 { 865 940 struct f81232_private *priv; ··· 1074 975 NULL, 1075 976 }; 1076 977 1077 - module_usb_serial_driver(serial_drivers, combined_id_table); 978 + static struct usb_driver f81534a_ctrl_driver = { 979 + .name = "f81534a_ctrl", 980 + .id_table = f81534a_ctrl_id_table, 981 + .probe = f81534a_ctrl_probe, 982 + .disconnect = f81534a_ctrl_disconnect, 983 + .resume = f81534a_ctrl_resume, 984 + }; 985 + 986 + static int __init f81232_init(void) 987 + { 988 + int status; 989 + 990 + status = usb_register_driver(&f81534a_ctrl_driver, THIS_MODULE, 991 + KBUILD_MODNAME); 992 + if (status) 993 + return status; 994 + 995 + status = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, 996 + combined_id_table); 997 + if (status) { 998 + usb_deregister(&f81534a_ctrl_driver); 999 + return status; 1000 + } 1001 + 1002 + return 0; 1003 + } 1004 + 1005 + static void __exit f81232_exit(void) 1006 + { 1007 + usb_serial_deregister_drivers(serial_drivers); 1008 + usb_deregister(&f81534a_ctrl_driver); 1009 + } 1010 + 1011 + module_init(f81232_init); 1012 + module_exit(f81232_exit); 1078 1013 1079 1014 MODULE_DESCRIPTION("Fintek F81232/532A/534A/535/536 USB to serial driver"); 1080 1015 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org>");