162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * F81532/F81534 USB to Serial Ports Bridge 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * F81532 => 2 Serial Ports 662306a36Sopenharmony_ci * F81534 => 4 Serial Ports 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2016 Feature Integration Technology Inc., (Fintek) 962306a36Sopenharmony_ci * Copyright (C) 2016 Tom Tsai (Tom_Tsai@fintek.com.tw) 1062306a36Sopenharmony_ci * Copyright (C) 2016 Peter Hong (Peter_Hong@fintek.com.tw) 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * The F81532/F81534 had 1 control endpoint for setting, 1 endpoint bulk-out 1362306a36Sopenharmony_ci * for all serial port TX and 1 endpoint bulk-in for all serial port read in 1462306a36Sopenharmony_ci * (Read Data/MSR/LSR). 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Write URB is fixed with 512bytes, per serial port used 128Bytes. 1762306a36Sopenharmony_ci * It can be described by f81534_prepare_write_buffer() 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Read URB is 512Bytes max, per serial port used 128Bytes. 2062306a36Sopenharmony_ci * It can be described by f81534_process_read_urb() and maybe received with 2162306a36Sopenharmony_ci * 128x1,2,3,4 bytes. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_ci#include <linux/slab.h> 2562306a36Sopenharmony_ci#include <linux/tty.h> 2662306a36Sopenharmony_ci#include <linux/tty_flip.h> 2762306a36Sopenharmony_ci#include <linux/usb.h> 2862306a36Sopenharmony_ci#include <linux/usb/serial.h> 2962306a36Sopenharmony_ci#include <linux/serial_reg.h> 3062306a36Sopenharmony_ci#include <linux/module.h> 3162306a36Sopenharmony_ci#include <linux/uaccess.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Serial Port register Address */ 3462306a36Sopenharmony_ci#define F81534_UART_BASE_ADDRESS 0x1200 3562306a36Sopenharmony_ci#define F81534_UART_OFFSET 0x10 3662306a36Sopenharmony_ci#define F81534_DIVISOR_LSB_REG (0x00 + F81534_UART_BASE_ADDRESS) 3762306a36Sopenharmony_ci#define F81534_DIVISOR_MSB_REG (0x01 + F81534_UART_BASE_ADDRESS) 3862306a36Sopenharmony_ci#define F81534_INTERRUPT_ENABLE_REG (0x01 + F81534_UART_BASE_ADDRESS) 3962306a36Sopenharmony_ci#define F81534_FIFO_CONTROL_REG (0x02 + F81534_UART_BASE_ADDRESS) 4062306a36Sopenharmony_ci#define F81534_LINE_CONTROL_REG (0x03 + F81534_UART_BASE_ADDRESS) 4162306a36Sopenharmony_ci#define F81534_MODEM_CONTROL_REG (0x04 + F81534_UART_BASE_ADDRESS) 4262306a36Sopenharmony_ci#define F81534_LINE_STATUS_REG (0x05 + F81534_UART_BASE_ADDRESS) 4362306a36Sopenharmony_ci#define F81534_MODEM_STATUS_REG (0x06 + F81534_UART_BASE_ADDRESS) 4462306a36Sopenharmony_ci#define F81534_CLOCK_REG (0x08 + F81534_UART_BASE_ADDRESS) 4562306a36Sopenharmony_ci#define F81534_CONFIG1_REG (0x09 + F81534_UART_BASE_ADDRESS) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define F81534_DEF_CONF_ADDRESS_START 0x3000 4862306a36Sopenharmony_ci#define F81534_DEF_CONF_SIZE 12 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define F81534_CUSTOM_ADDRESS_START 0x2f00 5162306a36Sopenharmony_ci#define F81534_CUSTOM_DATA_SIZE 0x10 5262306a36Sopenharmony_ci#define F81534_CUSTOM_NO_CUSTOM_DATA 0xff 5362306a36Sopenharmony_ci#define F81534_CUSTOM_VALID_TOKEN 0xf0 5462306a36Sopenharmony_ci#define F81534_CONF_OFFSET 1 5562306a36Sopenharmony_ci#define F81534_CONF_INIT_GPIO_OFFSET 4 5662306a36Sopenharmony_ci#define F81534_CONF_WORK_GPIO_OFFSET 8 5762306a36Sopenharmony_ci#define F81534_CONF_GPIO_SHUTDOWN 7 5862306a36Sopenharmony_ci#define F81534_CONF_GPIO_RS232 1 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define F81534_MAX_DATA_BLOCK 64 6162306a36Sopenharmony_ci#define F81534_MAX_BUS_RETRY 20 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Default URB timeout for USB operations */ 6462306a36Sopenharmony_ci#define F81534_USB_MAX_RETRY 10 6562306a36Sopenharmony_ci#define F81534_USB_TIMEOUT 2000 6662306a36Sopenharmony_ci#define F81534_SET_GET_REGISTER 0xA0 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define F81534_NUM_PORT 4 6962306a36Sopenharmony_ci#define F81534_UNUSED_PORT 0xff 7062306a36Sopenharmony_ci#define F81534_WRITE_BUFFER_SIZE 512 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define DRIVER_DESC "Fintek F81532/F81534" 7362306a36Sopenharmony_ci#define FINTEK_VENDOR_ID_1 0x1934 7462306a36Sopenharmony_ci#define FINTEK_VENDOR_ID_2 0x2C42 7562306a36Sopenharmony_ci#define FINTEK_DEVICE_ID 0x1202 7662306a36Sopenharmony_ci#define F81534_MAX_TX_SIZE 124 7762306a36Sopenharmony_ci#define F81534_MAX_RX_SIZE 124 7862306a36Sopenharmony_ci#define F81534_RECEIVE_BLOCK_SIZE 128 7962306a36Sopenharmony_ci#define F81534_MAX_RECEIVE_BLOCK_SIZE 512 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define F81534_TOKEN_RECEIVE 0x01 8262306a36Sopenharmony_ci#define F81534_TOKEN_WRITE 0x02 8362306a36Sopenharmony_ci#define F81534_TOKEN_TX_EMPTY 0x03 8462306a36Sopenharmony_ci#define F81534_TOKEN_MSR_CHANGE 0x04 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * We used interal SPI bus to access FLASH section. We must wait the SPI bus to 8862306a36Sopenharmony_ci * idle if we performed any command. 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * SPI Bus status register: F81534_BUS_REG_STATUS 9162306a36Sopenharmony_ci * Bit 0/1 : BUSY 9262306a36Sopenharmony_ci * Bit 2 : IDLE 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci#define F81534_BUS_BUSY (BIT(0) | BIT(1)) 9562306a36Sopenharmony_ci#define F81534_BUS_IDLE BIT(2) 9662306a36Sopenharmony_ci#define F81534_BUS_READ_DATA 0x1004 9762306a36Sopenharmony_ci#define F81534_BUS_REG_STATUS 0x1003 9862306a36Sopenharmony_ci#define F81534_BUS_REG_START 0x1002 9962306a36Sopenharmony_ci#define F81534_BUS_REG_END 0x1001 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define F81534_CMD_READ 0x03 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define F81534_DEFAULT_BAUD_RATE 9600 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define F81534_PORT_CONF_RS232 0 10662306a36Sopenharmony_ci#define F81534_PORT_CONF_RS485 BIT(0) 10762306a36Sopenharmony_ci#define F81534_PORT_CONF_RS485_INVERT (BIT(0) | BIT(1)) 10862306a36Sopenharmony_ci#define F81534_PORT_CONF_MODE_MASK GENMASK(1, 0) 10962306a36Sopenharmony_ci#define F81534_PORT_CONF_DISABLE_PORT BIT(3) 11062306a36Sopenharmony_ci#define F81534_PORT_CONF_NOT_EXIST_PORT BIT(7) 11162306a36Sopenharmony_ci#define F81534_PORT_UNAVAILABLE \ 11262306a36Sopenharmony_ci (F81534_PORT_CONF_DISABLE_PORT | F81534_PORT_CONF_NOT_EXIST_PORT) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci#define F81534_1X_RXTRIGGER 0xc3 11662306a36Sopenharmony_ci#define F81534_8X_RXTRIGGER 0xcf 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/* 11962306a36Sopenharmony_ci * F81532/534 Clock registers (offset +08h) 12062306a36Sopenharmony_ci * 12162306a36Sopenharmony_ci * Bit0: UART Enable (always on) 12262306a36Sopenharmony_ci * Bit2-1: Clock source selector 12362306a36Sopenharmony_ci * 00: 1.846MHz. 12462306a36Sopenharmony_ci * 01: 18.46MHz. 12562306a36Sopenharmony_ci * 10: 24MHz. 12662306a36Sopenharmony_ci * 11: 14.77MHz. 12762306a36Sopenharmony_ci * Bit4: Auto direction(RTS) control (RTS pin Low when TX) 12862306a36Sopenharmony_ci * Bit5: Invert direction(RTS) when Bit4 enabled (RTS pin high when TX) 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define F81534_UART_EN BIT(0) 13262306a36Sopenharmony_ci#define F81534_CLK_1_846_MHZ 0 13362306a36Sopenharmony_ci#define F81534_CLK_18_46_MHZ BIT(1) 13462306a36Sopenharmony_ci#define F81534_CLK_24_MHZ BIT(2) 13562306a36Sopenharmony_ci#define F81534_CLK_14_77_MHZ (BIT(1) | BIT(2)) 13662306a36Sopenharmony_ci#define F81534_CLK_MASK GENMASK(2, 1) 13762306a36Sopenharmony_ci#define F81534_CLK_TX_DELAY_1BIT BIT(3) 13862306a36Sopenharmony_ci#define F81534_CLK_RS485_MODE BIT(4) 13962306a36Sopenharmony_ci#define F81534_CLK_RS485_INVERT BIT(5) 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct usb_device_id f81534_id_table[] = { 14262306a36Sopenharmony_ci { USB_DEVICE(FINTEK_VENDOR_ID_1, FINTEK_DEVICE_ID) }, 14362306a36Sopenharmony_ci { USB_DEVICE(FINTEK_VENDOR_ID_2, FINTEK_DEVICE_ID) }, 14462306a36Sopenharmony_ci {} /* Terminating entry */ 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci#define F81534_TX_EMPTY_BIT 0 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistruct f81534_serial_private { 15062306a36Sopenharmony_ci u8 conf_data[F81534_DEF_CONF_SIZE]; 15162306a36Sopenharmony_ci int tty_idx[F81534_NUM_PORT]; 15262306a36Sopenharmony_ci u8 setting_idx; 15362306a36Sopenharmony_ci int opened_port; 15462306a36Sopenharmony_ci struct mutex urb_mutex; 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct f81534_port_private { 15862306a36Sopenharmony_ci struct mutex mcr_mutex; 15962306a36Sopenharmony_ci struct mutex lcr_mutex; 16062306a36Sopenharmony_ci struct work_struct lsr_work; 16162306a36Sopenharmony_ci struct usb_serial_port *port; 16262306a36Sopenharmony_ci unsigned long tx_empty; 16362306a36Sopenharmony_ci spinlock_t msr_lock; 16462306a36Sopenharmony_ci u32 baud_base; 16562306a36Sopenharmony_ci u8 shadow_mcr; 16662306a36Sopenharmony_ci u8 shadow_lcr; 16762306a36Sopenharmony_ci u8 shadow_msr; 16862306a36Sopenharmony_ci u8 shadow_clk; 16962306a36Sopenharmony_ci u8 phy_num; 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistruct f81534_pin_data { 17362306a36Sopenharmony_ci const u16 reg_addr; 17462306a36Sopenharmony_ci const u8 reg_mask; 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct f81534_port_out_pin { 17862306a36Sopenharmony_ci struct f81534_pin_data pin[3]; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* Pin output value for M2/M1/M0(SD) */ 18262306a36Sopenharmony_cistatic const struct f81534_port_out_pin f81534_port_out_pins[] = { 18362306a36Sopenharmony_ci { { { 0x2ae8, BIT(7) }, { 0x2a90, BIT(5) }, { 0x2a90, BIT(4) } } }, 18462306a36Sopenharmony_ci { { { 0x2ae8, BIT(6) }, { 0x2ae8, BIT(0) }, { 0x2ae8, BIT(3) } } }, 18562306a36Sopenharmony_ci { { { 0x2a90, BIT(0) }, { 0x2ae8, BIT(2) }, { 0x2a80, BIT(6) } } }, 18662306a36Sopenharmony_ci { { { 0x2a90, BIT(3) }, { 0x2a90, BIT(2) }, { 0x2a90, BIT(1) } } }, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 }; 19062306a36Sopenharmony_cistatic u8 const clock_table[] = { F81534_CLK_1_846_MHZ, F81534_CLK_14_77_MHZ, 19162306a36Sopenharmony_ci F81534_CLK_18_46_MHZ, F81534_CLK_24_MHZ }; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int f81534_logic_to_phy_port(struct usb_serial *serial, 19462306a36Sopenharmony_ci struct usb_serial_port *port) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct f81534_serial_private *serial_priv = 19762306a36Sopenharmony_ci usb_get_serial_data(port->serial); 19862306a36Sopenharmony_ci int count = 0; 19962306a36Sopenharmony_ci int i; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci for (i = 0; i < F81534_NUM_PORT; ++i) { 20262306a36Sopenharmony_ci if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE) 20362306a36Sopenharmony_ci continue; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (port->port_number == count) 20662306a36Sopenharmony_ci return i; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ++count; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return -ENODEV; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int f81534_set_register(struct usb_serial *serial, u16 reg, u8 data) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct usb_interface *interface = serial->interface; 21762306a36Sopenharmony_ci struct usb_device *dev = serial->dev; 21862306a36Sopenharmony_ci size_t count = F81534_USB_MAX_RETRY; 21962306a36Sopenharmony_ci int status; 22062306a36Sopenharmony_ci u8 *tmp; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci tmp = kmalloc(sizeof(u8), GFP_KERNEL); 22362306a36Sopenharmony_ci if (!tmp) 22462306a36Sopenharmony_ci return -ENOMEM; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci *tmp = data; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * Our device maybe not reply when heavily loading, We'll retry for 23062306a36Sopenharmony_ci * F81534_USB_MAX_RETRY times. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci while (count--) { 23362306a36Sopenharmony_ci status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), 23462306a36Sopenharmony_ci F81534_SET_GET_REGISTER, 23562306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_DIR_OUT, 23662306a36Sopenharmony_ci reg, 0, tmp, sizeof(u8), 23762306a36Sopenharmony_ci F81534_USB_TIMEOUT); 23862306a36Sopenharmony_ci if (status == sizeof(u8)) { 23962306a36Sopenharmony_ci status = 0; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (status < 0) { 24562306a36Sopenharmony_ci dev_err(&interface->dev, "%s: reg: %x data: %x failed: %d\n", 24662306a36Sopenharmony_ci __func__, reg, data, status); 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci kfree(tmp); 25062306a36Sopenharmony_ci return status; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic int f81534_get_register(struct usb_serial *serial, u16 reg, u8 *data) 25462306a36Sopenharmony_ci{ 25562306a36Sopenharmony_ci struct usb_interface *interface = serial->interface; 25662306a36Sopenharmony_ci struct usb_device *dev = serial->dev; 25762306a36Sopenharmony_ci size_t count = F81534_USB_MAX_RETRY; 25862306a36Sopenharmony_ci int status; 25962306a36Sopenharmony_ci u8 *tmp; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci tmp = kmalloc(sizeof(u8), GFP_KERNEL); 26262306a36Sopenharmony_ci if (!tmp) 26362306a36Sopenharmony_ci return -ENOMEM; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * Our device maybe not reply when heavily loading, We'll retry for 26762306a36Sopenharmony_ci * F81534_USB_MAX_RETRY times. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci while (count--) { 27062306a36Sopenharmony_ci status = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 27162306a36Sopenharmony_ci F81534_SET_GET_REGISTER, 27262306a36Sopenharmony_ci USB_TYPE_VENDOR | USB_DIR_IN, 27362306a36Sopenharmony_ci reg, 0, tmp, sizeof(u8), 27462306a36Sopenharmony_ci F81534_USB_TIMEOUT); 27562306a36Sopenharmony_ci if (status > 0) { 27662306a36Sopenharmony_ci status = 0; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci } else if (status == 0) { 27962306a36Sopenharmony_ci status = -EIO; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (status < 0) { 28462306a36Sopenharmony_ci dev_err(&interface->dev, "%s: reg: %x failed: %d\n", __func__, 28562306a36Sopenharmony_ci reg, status); 28662306a36Sopenharmony_ci goto end; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci *data = *tmp; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ciend: 29262306a36Sopenharmony_ci kfree(tmp); 29362306a36Sopenharmony_ci return status; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic int f81534_set_mask_register(struct usb_serial *serial, u16 reg, 29762306a36Sopenharmony_ci u8 mask, u8 data) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci int status; 30062306a36Sopenharmony_ci u8 tmp; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci status = f81534_get_register(serial, reg, &tmp); 30362306a36Sopenharmony_ci if (status) 30462306a36Sopenharmony_ci return status; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci tmp &= ~mask; 30762306a36Sopenharmony_ci tmp |= (mask & data); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci return f81534_set_register(serial, reg, tmp); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic int f81534_set_phy_port_register(struct usb_serial *serial, int phy, 31362306a36Sopenharmony_ci u16 reg, u8 data) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci return f81534_set_register(serial, reg + F81534_UART_OFFSET * phy, 31662306a36Sopenharmony_ci data); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int f81534_get_phy_port_register(struct usb_serial *serial, int phy, 32062306a36Sopenharmony_ci u16 reg, u8 *data) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci return f81534_get_register(serial, reg + F81534_UART_OFFSET * phy, 32362306a36Sopenharmony_ci data); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic int f81534_set_port_register(struct usb_serial_port *port, u16 reg, 32762306a36Sopenharmony_ci u8 data) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return f81534_set_register(port->serial, 33262306a36Sopenharmony_ci reg + port_priv->phy_num * F81534_UART_OFFSET, data); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic int f81534_get_port_register(struct usb_serial_port *port, u16 reg, 33662306a36Sopenharmony_ci u8 *data) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return f81534_get_register(port->serial, 34162306a36Sopenharmony_ci reg + port_priv->phy_num * F81534_UART_OFFSET, data); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci/* 34562306a36Sopenharmony_ci * If we try to access the internal flash via SPI bus, we should check the bus 34662306a36Sopenharmony_ci * status for every command. e.g., F81534_BUS_REG_START/F81534_BUS_REG_END 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_cistatic int f81534_wait_for_spi_idle(struct usb_serial *serial) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci size_t count = F81534_MAX_BUS_RETRY; 35162306a36Sopenharmony_ci u8 tmp; 35262306a36Sopenharmony_ci int status; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci do { 35562306a36Sopenharmony_ci status = f81534_get_register(serial, F81534_BUS_REG_STATUS, 35662306a36Sopenharmony_ci &tmp); 35762306a36Sopenharmony_ci if (status) 35862306a36Sopenharmony_ci return status; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (tmp & F81534_BUS_BUSY) 36162306a36Sopenharmony_ci continue; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (tmp & F81534_BUS_IDLE) 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci } while (--count); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (!count) { 36962306a36Sopenharmony_ci dev_err(&serial->interface->dev, 37062306a36Sopenharmony_ci "%s: timed out waiting for idle SPI bus\n", 37162306a36Sopenharmony_ci __func__); 37262306a36Sopenharmony_ci return -EIO; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci return f81534_set_register(serial, F81534_BUS_REG_STATUS, 37662306a36Sopenharmony_ci tmp & ~F81534_BUS_IDLE); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic int f81534_get_spi_register(struct usb_serial *serial, u16 reg, 38062306a36Sopenharmony_ci u8 *data) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci int status; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci status = f81534_get_register(serial, reg, data); 38562306a36Sopenharmony_ci if (status) 38662306a36Sopenharmony_ci return status; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return f81534_wait_for_spi_idle(serial); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int f81534_set_spi_register(struct usb_serial *serial, u16 reg, u8 data) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci int status; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci status = f81534_set_register(serial, reg, data); 39662306a36Sopenharmony_ci if (status) 39762306a36Sopenharmony_ci return status; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return f81534_wait_for_spi_idle(serial); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int f81534_read_flash(struct usb_serial *serial, u32 address, 40362306a36Sopenharmony_ci size_t size, u8 *buf) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci u8 tmp_buf[F81534_MAX_DATA_BLOCK]; 40662306a36Sopenharmony_ci size_t block = 0; 40762306a36Sopenharmony_ci size_t read_size; 40862306a36Sopenharmony_ci size_t count; 40962306a36Sopenharmony_ci int status; 41062306a36Sopenharmony_ci int offset; 41162306a36Sopenharmony_ci u16 reg_tmp; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci status = f81534_set_spi_register(serial, F81534_BUS_REG_START, 41462306a36Sopenharmony_ci F81534_CMD_READ); 41562306a36Sopenharmony_ci if (status) 41662306a36Sopenharmony_ci return status; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci status = f81534_set_spi_register(serial, F81534_BUS_REG_START, 41962306a36Sopenharmony_ci (address >> 16) & 0xff); 42062306a36Sopenharmony_ci if (status) 42162306a36Sopenharmony_ci return status; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci status = f81534_set_spi_register(serial, F81534_BUS_REG_START, 42462306a36Sopenharmony_ci (address >> 8) & 0xff); 42562306a36Sopenharmony_ci if (status) 42662306a36Sopenharmony_ci return status; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci status = f81534_set_spi_register(serial, F81534_BUS_REG_START, 42962306a36Sopenharmony_ci (address >> 0) & 0xff); 43062306a36Sopenharmony_ci if (status) 43162306a36Sopenharmony_ci return status; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* Continuous read mode */ 43462306a36Sopenharmony_ci do { 43562306a36Sopenharmony_ci read_size = min_t(size_t, F81534_MAX_DATA_BLOCK, size); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci for (count = 0; count < read_size; ++count) { 43862306a36Sopenharmony_ci /* To write F81534_BUS_REG_END when final byte */ 43962306a36Sopenharmony_ci if (size <= F81534_MAX_DATA_BLOCK && 44062306a36Sopenharmony_ci read_size == count + 1) 44162306a36Sopenharmony_ci reg_tmp = F81534_BUS_REG_END; 44262306a36Sopenharmony_ci else 44362306a36Sopenharmony_ci reg_tmp = F81534_BUS_REG_START; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* 44662306a36Sopenharmony_ci * Dummy code, force IC to generate a read pulse, the 44762306a36Sopenharmony_ci * set of value 0xf1 is dont care (any value is ok) 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci status = f81534_set_spi_register(serial, reg_tmp, 45062306a36Sopenharmony_ci 0xf1); 45162306a36Sopenharmony_ci if (status) 45262306a36Sopenharmony_ci return status; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci status = f81534_get_spi_register(serial, 45562306a36Sopenharmony_ci F81534_BUS_READ_DATA, 45662306a36Sopenharmony_ci &tmp_buf[count]); 45762306a36Sopenharmony_ci if (status) 45862306a36Sopenharmony_ci return status; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci offset = count + block * F81534_MAX_DATA_BLOCK; 46162306a36Sopenharmony_ci buf[offset] = tmp_buf[count]; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci size -= read_size; 46562306a36Sopenharmony_ci ++block; 46662306a36Sopenharmony_ci } while (size); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic void f81534_prepare_write_buffer(struct usb_serial_port *port, u8 *buf) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 47462306a36Sopenharmony_ci int phy_num = port_priv->phy_num; 47562306a36Sopenharmony_ci u8 tx_len; 47662306a36Sopenharmony_ci int i; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* 47962306a36Sopenharmony_ci * The block layout is fixed with 4x128 Bytes, per 128 Bytes a port. 48062306a36Sopenharmony_ci * index 0: port phy idx (e.g., 0,1,2,3) 48162306a36Sopenharmony_ci * index 1: only F81534_TOKEN_WRITE 48262306a36Sopenharmony_ci * index 2: serial TX out length 48362306a36Sopenharmony_ci * index 3: fix to 0 48462306a36Sopenharmony_ci * index 4~127: serial out data block 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci for (i = 0; i < F81534_NUM_PORT; ++i) { 48762306a36Sopenharmony_ci buf[i * F81534_RECEIVE_BLOCK_SIZE] = i; 48862306a36Sopenharmony_ci buf[i * F81534_RECEIVE_BLOCK_SIZE + 1] = F81534_TOKEN_WRITE; 48962306a36Sopenharmony_ci buf[i * F81534_RECEIVE_BLOCK_SIZE + 2] = 0; 49062306a36Sopenharmony_ci buf[i * F81534_RECEIVE_BLOCK_SIZE + 3] = 0; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci tx_len = kfifo_out_locked(&port->write_fifo, 49462306a36Sopenharmony_ci &buf[phy_num * F81534_RECEIVE_BLOCK_SIZE + 4], 49562306a36Sopenharmony_ci F81534_MAX_TX_SIZE, &port->lock); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci buf[phy_num * F81534_RECEIVE_BLOCK_SIZE + 2] = tx_len; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int f81534_submit_writer(struct usb_serial_port *port, gfp_t mem_flags) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 50362306a36Sopenharmony_ci struct urb *urb; 50462306a36Sopenharmony_ci unsigned long flags; 50562306a36Sopenharmony_ci int result; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci /* Check is any data in write_fifo */ 50862306a36Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (kfifo_is_empty(&port->write_fifo)) { 51162306a36Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* Check H/W is TXEMPTY */ 51862306a36Sopenharmony_ci if (!test_and_clear_bit(F81534_TX_EMPTY_BIT, &port_priv->tx_empty)) 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci urb = port->write_urbs[0]; 52262306a36Sopenharmony_ci f81534_prepare_write_buffer(port, port->bulk_out_buffers[0]); 52362306a36Sopenharmony_ci urb->transfer_buffer_length = F81534_WRITE_BUFFER_SIZE; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci result = usb_submit_urb(urb, mem_flags); 52662306a36Sopenharmony_ci if (result) { 52762306a36Sopenharmony_ci set_bit(F81534_TX_EMPTY_BIT, &port_priv->tx_empty); 52862306a36Sopenharmony_ci dev_err(&port->dev, "%s: submit failed: %d\n", __func__, 52962306a36Sopenharmony_ci result); 53062306a36Sopenharmony_ci return result; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci usb_serial_port_softint(port); 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic u32 f81534_calc_baud_divisor(u32 baudrate, u32 clockrate) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci /* Round to nearest divisor */ 54062306a36Sopenharmony_ci return DIV_ROUND_CLOSEST(clockrate, baudrate); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int f81534_find_clk(u32 baudrate) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci int idx; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) { 54862306a36Sopenharmony_ci if (baudrate <= baudrate_table[idx] && 54962306a36Sopenharmony_ci baudrate_table[idx] % baudrate == 0) 55062306a36Sopenharmony_ci return idx; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci return -EINVAL; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int f81534_set_port_config(struct usb_serial_port *port, 55762306a36Sopenharmony_ci struct tty_struct *tty, u32 baudrate, u32 old_baudrate, u8 lcr) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 56062306a36Sopenharmony_ci u32 divisor; 56162306a36Sopenharmony_ci int status; 56262306a36Sopenharmony_ci int i; 56362306a36Sopenharmony_ci int idx; 56462306a36Sopenharmony_ci u8 value; 56562306a36Sopenharmony_ci u32 baud_list[] = {baudrate, old_baudrate, F81534_DEFAULT_BAUD_RATE}; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(baud_list); ++i) { 56862306a36Sopenharmony_ci baudrate = baud_list[i]; 56962306a36Sopenharmony_ci if (baudrate == 0) { 57062306a36Sopenharmony_ci tty_encode_baud_rate(tty, 0, 0); 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci idx = f81534_find_clk(baudrate); 57562306a36Sopenharmony_ci if (idx >= 0) { 57662306a36Sopenharmony_ci tty_encode_baud_rate(tty, baudrate, baudrate); 57762306a36Sopenharmony_ci break; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (idx < 0) 58262306a36Sopenharmony_ci return -EINVAL; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci port_priv->baud_base = baudrate_table[idx]; 58562306a36Sopenharmony_ci port_priv->shadow_clk &= ~F81534_CLK_MASK; 58662306a36Sopenharmony_ci port_priv->shadow_clk |= clock_table[idx]; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_CLOCK_REG, 58962306a36Sopenharmony_ci port_priv->shadow_clk); 59062306a36Sopenharmony_ci if (status) { 59162306a36Sopenharmony_ci dev_err(&port->dev, "CLOCK_REG setting failed\n"); 59262306a36Sopenharmony_ci return status; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (baudrate <= 1200) 59662306a36Sopenharmony_ci value = F81534_1X_RXTRIGGER; /* 128 FIFO & TL: 1x */ 59762306a36Sopenharmony_ci else 59862306a36Sopenharmony_ci value = F81534_8X_RXTRIGGER; /* 128 FIFO & TL: 8x */ 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_CONFIG1_REG, value); 60162306a36Sopenharmony_ci if (status) { 60262306a36Sopenharmony_ci dev_err(&port->dev, "%s: CONFIG1 setting failed\n", __func__); 60362306a36Sopenharmony_ci return status; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (baudrate <= 1200) 60762306a36Sopenharmony_ci value = UART_FCR_TRIGGER_1 | UART_FCR_ENABLE_FIFO; /* TL: 1 */ 60862306a36Sopenharmony_ci else 60962306a36Sopenharmony_ci value = UART_FCR_TRIGGER_8 | UART_FCR_ENABLE_FIFO; /* TL: 8 */ 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_FIFO_CONTROL_REG, 61262306a36Sopenharmony_ci value); 61362306a36Sopenharmony_ci if (status) { 61462306a36Sopenharmony_ci dev_err(&port->dev, "%s: FCR setting failed\n", __func__); 61562306a36Sopenharmony_ci return status; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci divisor = f81534_calc_baud_divisor(baudrate, port_priv->baud_base); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci mutex_lock(&port_priv->lcr_mutex); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci value = UART_LCR_DLAB; 62362306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, 62462306a36Sopenharmony_ci value); 62562306a36Sopenharmony_ci if (status) { 62662306a36Sopenharmony_ci dev_err(&port->dev, "%s: set LCR failed\n", __func__); 62762306a36Sopenharmony_ci goto out_unlock; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci value = divisor & 0xff; 63162306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_DIVISOR_LSB_REG, value); 63262306a36Sopenharmony_ci if (status) { 63362306a36Sopenharmony_ci dev_err(&port->dev, "%s: set DLAB LSB failed\n", __func__); 63462306a36Sopenharmony_ci goto out_unlock; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci value = (divisor >> 8) & 0xff; 63862306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_DIVISOR_MSB_REG, value); 63962306a36Sopenharmony_ci if (status) { 64062306a36Sopenharmony_ci dev_err(&port->dev, "%s: set DLAB MSB failed\n", __func__); 64162306a36Sopenharmony_ci goto out_unlock; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci value = lcr | (port_priv->shadow_lcr & UART_LCR_SBC); 64562306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, 64662306a36Sopenharmony_ci value); 64762306a36Sopenharmony_ci if (status) { 64862306a36Sopenharmony_ci dev_err(&port->dev, "%s: set LCR failed\n", __func__); 64962306a36Sopenharmony_ci goto out_unlock; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci port_priv->shadow_lcr = value; 65362306a36Sopenharmony_ciout_unlock: 65462306a36Sopenharmony_ci mutex_unlock(&port_priv->lcr_mutex); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return status; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_cistatic int f81534_break_ctl(struct tty_struct *tty, int break_state) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 66262306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 66362306a36Sopenharmony_ci int status; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci mutex_lock(&port_priv->lcr_mutex); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci if (break_state) 66862306a36Sopenharmony_ci port_priv->shadow_lcr |= UART_LCR_SBC; 66962306a36Sopenharmony_ci else 67062306a36Sopenharmony_ci port_priv->shadow_lcr &= ~UART_LCR_SBC; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG, 67362306a36Sopenharmony_ci port_priv->shadow_lcr); 67462306a36Sopenharmony_ci if (status) 67562306a36Sopenharmony_ci dev_err(&port->dev, "set break failed: %d\n", status); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci mutex_unlock(&port_priv->lcr_mutex); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return status; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int f81534_update_mctrl(struct usb_serial_port *port, unsigned int set, 68362306a36Sopenharmony_ci unsigned int clear) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 68662306a36Sopenharmony_ci int status; 68762306a36Sopenharmony_ci u8 tmp; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) 69062306a36Sopenharmony_ci return 0; /* no change */ 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci mutex_lock(&port_priv->mcr_mutex); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* 'Set' takes precedence over 'Clear' */ 69562306a36Sopenharmony_ci clear &= ~set; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* Always enable UART_MCR_OUT2 */ 69862306a36Sopenharmony_ci tmp = UART_MCR_OUT2 | port_priv->shadow_mcr; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (clear & TIOCM_DTR) 70162306a36Sopenharmony_ci tmp &= ~UART_MCR_DTR; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (clear & TIOCM_RTS) 70462306a36Sopenharmony_ci tmp &= ~UART_MCR_RTS; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (set & TIOCM_DTR) 70762306a36Sopenharmony_ci tmp |= UART_MCR_DTR; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (set & TIOCM_RTS) 71062306a36Sopenharmony_ci tmp |= UART_MCR_RTS; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci status = f81534_set_port_register(port, F81534_MODEM_CONTROL_REG, tmp); 71362306a36Sopenharmony_ci if (status < 0) { 71462306a36Sopenharmony_ci dev_err(&port->dev, "%s: MCR write failed\n", __func__); 71562306a36Sopenharmony_ci mutex_unlock(&port_priv->mcr_mutex); 71662306a36Sopenharmony_ci return status; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci port_priv->shadow_mcr = tmp; 72062306a36Sopenharmony_ci mutex_unlock(&port_priv->mcr_mutex); 72162306a36Sopenharmony_ci return 0; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci/* 72562306a36Sopenharmony_ci * This function will search the data area with token F81534_CUSTOM_VALID_TOKEN 72662306a36Sopenharmony_ci * for latest configuration index. If nothing found 72762306a36Sopenharmony_ci * (*index = F81534_CUSTOM_NO_CUSTOM_DATA), We'll load default configure in 72862306a36Sopenharmony_ci * F81534_DEF_CONF_ADDRESS_START section. 72962306a36Sopenharmony_ci * 73062306a36Sopenharmony_ci * Due to we only use block0 to save data, so *index should be 0 or 73162306a36Sopenharmony_ci * F81534_CUSTOM_NO_CUSTOM_DATA. 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_cistatic int f81534_find_config_idx(struct usb_serial *serial, u8 *index) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci u8 tmp; 73662306a36Sopenharmony_ci int status; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci status = f81534_read_flash(serial, F81534_CUSTOM_ADDRESS_START, 1, 73962306a36Sopenharmony_ci &tmp); 74062306a36Sopenharmony_ci if (status) { 74162306a36Sopenharmony_ci dev_err(&serial->interface->dev, "%s: read failed: %d\n", 74262306a36Sopenharmony_ci __func__, status); 74362306a36Sopenharmony_ci return status; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* We'll use the custom data when the data is valid. */ 74762306a36Sopenharmony_ci if (tmp == F81534_CUSTOM_VALID_TOKEN) 74862306a36Sopenharmony_ci *index = 0; 74962306a36Sopenharmony_ci else 75062306a36Sopenharmony_ci *index = F81534_CUSTOM_NO_CUSTOM_DATA; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return 0; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/* 75662306a36Sopenharmony_ci * The F81532/534 will not report serial port to USB serial subsystem when 75762306a36Sopenharmony_ci * H/W DCD/DSR/CTS/RI/RX pin connected to ground. 75862306a36Sopenharmony_ci * 75962306a36Sopenharmony_ci * To detect RX pin status, we'll enable MCR interal loopback, disable it and 76062306a36Sopenharmony_ci * delayed for 60ms. It connected to ground If LSR register report UART_LSR_BI. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_cistatic bool f81534_check_port_hw_disabled(struct usb_serial *serial, int phy) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci int status; 76562306a36Sopenharmony_ci u8 old_mcr; 76662306a36Sopenharmony_ci u8 msr; 76762306a36Sopenharmony_ci u8 lsr; 76862306a36Sopenharmony_ci u8 msr_mask; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci msr_mask = UART_MSR_DCD | UART_MSR_RI | UART_MSR_DSR | UART_MSR_CTS; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci status = f81534_get_phy_port_register(serial, phy, 77362306a36Sopenharmony_ci F81534_MODEM_STATUS_REG, &msr); 77462306a36Sopenharmony_ci if (status) 77562306a36Sopenharmony_ci return false; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if ((msr & msr_mask) != msr_mask) 77862306a36Sopenharmony_ci return false; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci status = f81534_set_phy_port_register(serial, phy, 78162306a36Sopenharmony_ci F81534_FIFO_CONTROL_REG, UART_FCR_ENABLE_FIFO | 78262306a36Sopenharmony_ci UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 78362306a36Sopenharmony_ci if (status) 78462306a36Sopenharmony_ci return false; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci status = f81534_get_phy_port_register(serial, phy, 78762306a36Sopenharmony_ci F81534_MODEM_CONTROL_REG, &old_mcr); 78862306a36Sopenharmony_ci if (status) 78962306a36Sopenharmony_ci return false; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci status = f81534_set_phy_port_register(serial, phy, 79262306a36Sopenharmony_ci F81534_MODEM_CONTROL_REG, UART_MCR_LOOP); 79362306a36Sopenharmony_ci if (status) 79462306a36Sopenharmony_ci return false; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci status = f81534_set_phy_port_register(serial, phy, 79762306a36Sopenharmony_ci F81534_MODEM_CONTROL_REG, 0x0); 79862306a36Sopenharmony_ci if (status) 79962306a36Sopenharmony_ci return false; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci msleep(60); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci status = f81534_get_phy_port_register(serial, phy, 80462306a36Sopenharmony_ci F81534_LINE_STATUS_REG, &lsr); 80562306a36Sopenharmony_ci if (status) 80662306a36Sopenharmony_ci return false; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci status = f81534_set_phy_port_register(serial, phy, 80962306a36Sopenharmony_ci F81534_MODEM_CONTROL_REG, old_mcr); 81062306a36Sopenharmony_ci if (status) 81162306a36Sopenharmony_ci return false; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if ((lsr & UART_LSR_BI) == UART_LSR_BI) 81462306a36Sopenharmony_ci return true; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci return false; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci/* 82062306a36Sopenharmony_ci * We had 2 generation of F81532/534 IC. All has an internal storage. 82162306a36Sopenharmony_ci * 82262306a36Sopenharmony_ci * 1st is pure USB-to-TTL RS232 IC and designed for 4 ports only, no any 82362306a36Sopenharmony_ci * internal data will used. All mode and gpio control should manually set 82462306a36Sopenharmony_ci * by AP or Driver and all storage space value are 0xff. The 82562306a36Sopenharmony_ci * f81534_calc_num_ports() will run to final we marked as "oldest version" 82662306a36Sopenharmony_ci * for this IC. 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * 2rd is designed to more generic to use any transceiver and this is our 82962306a36Sopenharmony_ci * mass production type. We'll save data in F81534_CUSTOM_ADDRESS_START 83062306a36Sopenharmony_ci * (0x2f00) with 9bytes. The 1st byte is a indicater. If the token is 83162306a36Sopenharmony_ci * F81534_CUSTOM_VALID_TOKEN(0xf0), the IC is 2nd gen type, the following 83262306a36Sopenharmony_ci * 4bytes save port mode (0:RS232/1:RS485 Invert/2:RS485), and the last 83362306a36Sopenharmony_ci * 4bytes save GPIO state(value from 0~7 to represent 3 GPIO output pin). 83462306a36Sopenharmony_ci * The f81534_calc_num_ports() will run to "new style" with checking 83562306a36Sopenharmony_ci * F81534_PORT_UNAVAILABLE section. 83662306a36Sopenharmony_ci */ 83762306a36Sopenharmony_cistatic int f81534_calc_num_ports(struct usb_serial *serial, 83862306a36Sopenharmony_ci struct usb_serial_endpoints *epds) 83962306a36Sopenharmony_ci{ 84062306a36Sopenharmony_ci struct f81534_serial_private *serial_priv; 84162306a36Sopenharmony_ci struct device *dev = &serial->interface->dev; 84262306a36Sopenharmony_ci int size_bulk_in = usb_endpoint_maxp(epds->bulk_in[0]); 84362306a36Sopenharmony_ci int size_bulk_out = usb_endpoint_maxp(epds->bulk_out[0]); 84462306a36Sopenharmony_ci u8 num_port = 0; 84562306a36Sopenharmony_ci int index = 0; 84662306a36Sopenharmony_ci int status; 84762306a36Sopenharmony_ci int i; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (size_bulk_out != F81534_WRITE_BUFFER_SIZE || 85062306a36Sopenharmony_ci size_bulk_in != F81534_MAX_RECEIVE_BLOCK_SIZE) { 85162306a36Sopenharmony_ci dev_err(dev, "unsupported endpoint max packet size\n"); 85262306a36Sopenharmony_ci return -ENODEV; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci serial_priv = devm_kzalloc(&serial->interface->dev, 85662306a36Sopenharmony_ci sizeof(*serial_priv), GFP_KERNEL); 85762306a36Sopenharmony_ci if (!serial_priv) 85862306a36Sopenharmony_ci return -ENOMEM; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci usb_set_serial_data(serial, serial_priv); 86162306a36Sopenharmony_ci mutex_init(&serial_priv->urb_mutex); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Check had custom setting */ 86462306a36Sopenharmony_ci status = f81534_find_config_idx(serial, &serial_priv->setting_idx); 86562306a36Sopenharmony_ci if (status) { 86662306a36Sopenharmony_ci dev_err(&serial->interface->dev, "%s: find idx failed: %d\n", 86762306a36Sopenharmony_ci __func__, status); 86862306a36Sopenharmony_ci return status; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* 87262306a36Sopenharmony_ci * We'll read custom data only when data available, otherwise we'll 87362306a36Sopenharmony_ci * read default value instead. 87462306a36Sopenharmony_ci */ 87562306a36Sopenharmony_ci if (serial_priv->setting_idx != F81534_CUSTOM_NO_CUSTOM_DATA) { 87662306a36Sopenharmony_ci status = f81534_read_flash(serial, 87762306a36Sopenharmony_ci F81534_CUSTOM_ADDRESS_START + 87862306a36Sopenharmony_ci F81534_CONF_OFFSET, 87962306a36Sopenharmony_ci sizeof(serial_priv->conf_data), 88062306a36Sopenharmony_ci serial_priv->conf_data); 88162306a36Sopenharmony_ci if (status) { 88262306a36Sopenharmony_ci dev_err(&serial->interface->dev, 88362306a36Sopenharmony_ci "%s: get custom data failed: %d\n", 88462306a36Sopenharmony_ci __func__, status); 88562306a36Sopenharmony_ci return status; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci dev_dbg(&serial->interface->dev, 88962306a36Sopenharmony_ci "%s: read config from block: %d\n", __func__, 89062306a36Sopenharmony_ci serial_priv->setting_idx); 89162306a36Sopenharmony_ci } else { 89262306a36Sopenharmony_ci /* Read default board setting */ 89362306a36Sopenharmony_ci status = f81534_read_flash(serial, 89462306a36Sopenharmony_ci F81534_DEF_CONF_ADDRESS_START, 89562306a36Sopenharmony_ci sizeof(serial_priv->conf_data), 89662306a36Sopenharmony_ci serial_priv->conf_data); 89762306a36Sopenharmony_ci if (status) { 89862306a36Sopenharmony_ci dev_err(&serial->interface->dev, 89962306a36Sopenharmony_ci "%s: read failed: %d\n", __func__, 90062306a36Sopenharmony_ci status); 90162306a36Sopenharmony_ci return status; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci dev_dbg(&serial->interface->dev, "%s: read default config\n", 90562306a36Sopenharmony_ci __func__); 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci /* New style, find all possible ports */ 90962306a36Sopenharmony_ci for (i = 0; i < F81534_NUM_PORT; ++i) { 91062306a36Sopenharmony_ci if (f81534_check_port_hw_disabled(serial, i)) 91162306a36Sopenharmony_ci serial_priv->conf_data[i] |= F81534_PORT_UNAVAILABLE; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE) 91462306a36Sopenharmony_ci continue; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci ++num_port; 91762306a36Sopenharmony_ci } 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (!num_port) { 92062306a36Sopenharmony_ci dev_warn(&serial->interface->dev, 92162306a36Sopenharmony_ci "no config found, assuming 4 ports\n"); 92262306a36Sopenharmony_ci num_port = 4; /* Nothing found, oldest version IC */ 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci /* Assign phy-to-logic mapping */ 92662306a36Sopenharmony_ci for (i = 0; i < F81534_NUM_PORT; ++i) { 92762306a36Sopenharmony_ci if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE) 92862306a36Sopenharmony_ci continue; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci serial_priv->tty_idx[i] = index++; 93162306a36Sopenharmony_ci dev_dbg(&serial->interface->dev, 93262306a36Sopenharmony_ci "%s: phy_num: %d, tty_idx: %d\n", __func__, i, 93362306a36Sopenharmony_ci serial_priv->tty_idx[i]); 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* 93762306a36Sopenharmony_ci * Setup bulk-out endpoint multiplexing. All ports share the same 93862306a36Sopenharmony_ci * bulk-out endpoint. 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(epds->bulk_out) < F81534_NUM_PORT); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci for (i = 1; i < num_port; ++i) 94362306a36Sopenharmony_ci epds->bulk_out[i] = epds->bulk_out[0]; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci epds->num_bulk_out = num_port; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci return num_port; 94862306a36Sopenharmony_ci} 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_cistatic void f81534_set_termios(struct tty_struct *tty, 95162306a36Sopenharmony_ci struct usb_serial_port *port, 95262306a36Sopenharmony_ci const struct ktermios *old_termios) 95362306a36Sopenharmony_ci{ 95462306a36Sopenharmony_ci u8 new_lcr = 0; 95562306a36Sopenharmony_ci int status; 95662306a36Sopenharmony_ci u32 baud; 95762306a36Sopenharmony_ci u32 old_baud; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (C_BAUD(tty) == B0) 96062306a36Sopenharmony_ci f81534_update_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); 96162306a36Sopenharmony_ci else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 96262306a36Sopenharmony_ci f81534_update_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (C_PARENB(tty)) { 96562306a36Sopenharmony_ci new_lcr |= UART_LCR_PARITY; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci if (!C_PARODD(tty)) 96862306a36Sopenharmony_ci new_lcr |= UART_LCR_EPAR; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (C_CMSPAR(tty)) 97162306a36Sopenharmony_ci new_lcr |= UART_LCR_SPAR; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (C_CSTOPB(tty)) 97562306a36Sopenharmony_ci new_lcr |= UART_LCR_STOP; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci new_lcr |= UART_LCR_WLEN(tty_get_char_size(tty->termios.c_cflag)); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci baud = tty_get_baud_rate(tty); 98062306a36Sopenharmony_ci if (!baud) 98162306a36Sopenharmony_ci return; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (old_termios) 98462306a36Sopenharmony_ci old_baud = tty_termios_baud_rate(old_termios); 98562306a36Sopenharmony_ci else 98662306a36Sopenharmony_ci old_baud = F81534_DEFAULT_BAUD_RATE; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci dev_dbg(&port->dev, "%s: baud: %d\n", __func__, baud); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci status = f81534_set_port_config(port, tty, baud, old_baud, new_lcr); 99162306a36Sopenharmony_ci if (status < 0) { 99262306a36Sopenharmony_ci dev_err(&port->dev, "%s: set port config failed: %d\n", 99362306a36Sopenharmony_ci __func__, status); 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic int f81534_submit_read_urb(struct usb_serial *serial, gfp_t flags) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci return usb_serial_generic_submit_read_urbs(serial->port[0], flags); 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic void f81534_msr_changed(struct usb_serial_port *port, u8 msr) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 100562306a36Sopenharmony_ci struct tty_struct *tty; 100662306a36Sopenharmony_ci unsigned long flags; 100762306a36Sopenharmony_ci u8 old_msr; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!(msr & UART_MSR_ANY_DELTA)) 101062306a36Sopenharmony_ci return; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->msr_lock, flags); 101362306a36Sopenharmony_ci old_msr = port_priv->shadow_msr; 101462306a36Sopenharmony_ci port_priv->shadow_msr = msr; 101562306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->msr_lock, flags); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci dev_dbg(&port->dev, "%s: MSR from %02x to %02x\n", __func__, old_msr, 101862306a36Sopenharmony_ci msr); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Update input line counters */ 102162306a36Sopenharmony_ci if (msr & UART_MSR_DCTS) 102262306a36Sopenharmony_ci port->icount.cts++; 102362306a36Sopenharmony_ci if (msr & UART_MSR_DDSR) 102462306a36Sopenharmony_ci port->icount.dsr++; 102562306a36Sopenharmony_ci if (msr & UART_MSR_DDCD) 102662306a36Sopenharmony_ci port->icount.dcd++; 102762306a36Sopenharmony_ci if (msr & UART_MSR_TERI) 102862306a36Sopenharmony_ci port->icount.rng++; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci wake_up_interruptible(&port->port.delta_msr_wait); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (!(msr & UART_MSR_DDCD)) 103362306a36Sopenharmony_ci return; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci dev_dbg(&port->dev, "%s: DCD Changed: phy_num: %d from %x to %x\n", 103662306a36Sopenharmony_ci __func__, port_priv->phy_num, old_msr, msr); 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci tty = tty_port_tty_get(&port->port); 103962306a36Sopenharmony_ci if (!tty) 104062306a36Sopenharmony_ci return; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci usb_serial_handle_dcd_change(port, tty, msr & UART_MSR_DCD); 104362306a36Sopenharmony_ci tty_kref_put(tty); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int f81534_read_msr(struct usb_serial_port *port) 104762306a36Sopenharmony_ci{ 104862306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 104962306a36Sopenharmony_ci unsigned long flags; 105062306a36Sopenharmony_ci int status; 105162306a36Sopenharmony_ci u8 msr; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* Get MSR initial value */ 105462306a36Sopenharmony_ci status = f81534_get_port_register(port, F81534_MODEM_STATUS_REG, &msr); 105562306a36Sopenharmony_ci if (status) 105662306a36Sopenharmony_ci return status; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* Force update current state */ 105962306a36Sopenharmony_ci spin_lock_irqsave(&port_priv->msr_lock, flags); 106062306a36Sopenharmony_ci port_priv->shadow_msr = msr; 106162306a36Sopenharmony_ci spin_unlock_irqrestore(&port_priv->msr_lock, flags); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci return 0; 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cistatic int f81534_open(struct tty_struct *tty, struct usb_serial_port *port) 106762306a36Sopenharmony_ci{ 106862306a36Sopenharmony_ci struct f81534_serial_private *serial_priv = 106962306a36Sopenharmony_ci usb_get_serial_data(port->serial); 107062306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 107162306a36Sopenharmony_ci int status; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci status = f81534_set_port_register(port, 107462306a36Sopenharmony_ci F81534_FIFO_CONTROL_REG, UART_FCR_ENABLE_FIFO | 107562306a36Sopenharmony_ci UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 107662306a36Sopenharmony_ci if (status) { 107762306a36Sopenharmony_ci dev_err(&port->dev, "%s: Clear FIFO failed: %d\n", __func__, 107862306a36Sopenharmony_ci status); 107962306a36Sopenharmony_ci return status; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (tty) 108362306a36Sopenharmony_ci f81534_set_termios(tty, port, NULL); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci status = f81534_read_msr(port); 108662306a36Sopenharmony_ci if (status) 108762306a36Sopenharmony_ci return status; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci mutex_lock(&serial_priv->urb_mutex); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* Submit Read URBs for first port opened */ 109262306a36Sopenharmony_ci if (!serial_priv->opened_port) { 109362306a36Sopenharmony_ci status = f81534_submit_read_urb(port->serial, GFP_KERNEL); 109462306a36Sopenharmony_ci if (status) 109562306a36Sopenharmony_ci goto exit; 109662306a36Sopenharmony_ci } 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci serial_priv->opened_port++; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ciexit: 110162306a36Sopenharmony_ci mutex_unlock(&serial_priv->urb_mutex); 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci set_bit(F81534_TX_EMPTY_BIT, &port_priv->tx_empty); 110462306a36Sopenharmony_ci return status; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic void f81534_close(struct usb_serial_port *port) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct f81534_serial_private *serial_priv = 111062306a36Sopenharmony_ci usb_get_serial_data(port->serial); 111162306a36Sopenharmony_ci struct usb_serial_port *port0 = port->serial->port[0]; 111262306a36Sopenharmony_ci unsigned long flags; 111362306a36Sopenharmony_ci size_t i; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci usb_kill_urb(port->write_urbs[0]); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci spin_lock_irqsave(&port->lock, flags); 111862306a36Sopenharmony_ci kfifo_reset_out(&port->write_fifo); 111962306a36Sopenharmony_ci spin_unlock_irqrestore(&port->lock, flags); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci /* Kill Read URBs when final port closed */ 112262306a36Sopenharmony_ci mutex_lock(&serial_priv->urb_mutex); 112362306a36Sopenharmony_ci serial_priv->opened_port--; 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci if (!serial_priv->opened_port) { 112662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(port0->read_urbs); ++i) 112762306a36Sopenharmony_ci usb_kill_urb(port0->read_urbs[i]); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci mutex_unlock(&serial_priv->urb_mutex); 113162306a36Sopenharmony_ci} 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_cistatic void f81534_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 113662306a36Sopenharmony_ci struct f81534_port_private *port_priv; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci ss->baud_base = port_priv->baud_base; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic void f81534_process_per_serial_block(struct usb_serial_port *port, 114462306a36Sopenharmony_ci u8 *data) 114562306a36Sopenharmony_ci{ 114662306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 114762306a36Sopenharmony_ci int phy_num = data[0]; 114862306a36Sopenharmony_ci size_t read_size = 0; 114962306a36Sopenharmony_ci size_t i; 115062306a36Sopenharmony_ci char tty_flag; 115162306a36Sopenharmony_ci int status; 115262306a36Sopenharmony_ci u8 lsr; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* 115562306a36Sopenharmony_ci * The block layout is 128 Bytes 115662306a36Sopenharmony_ci * index 0: port phy idx (e.g., 0,1,2,3), 115762306a36Sopenharmony_ci * index 1: It's could be 115862306a36Sopenharmony_ci * F81534_TOKEN_RECEIVE 115962306a36Sopenharmony_ci * F81534_TOKEN_TX_EMPTY 116062306a36Sopenharmony_ci * F81534_TOKEN_MSR_CHANGE 116162306a36Sopenharmony_ci * index 2: serial in size (data+lsr, must be even) 116262306a36Sopenharmony_ci * meaningful for F81534_TOKEN_RECEIVE only 116362306a36Sopenharmony_ci * index 3: current MSR with this device 116462306a36Sopenharmony_ci * index 4~127: serial in data block (data+lsr, must be even) 116562306a36Sopenharmony_ci */ 116662306a36Sopenharmony_ci switch (data[1]) { 116762306a36Sopenharmony_ci case F81534_TOKEN_TX_EMPTY: 116862306a36Sopenharmony_ci set_bit(F81534_TX_EMPTY_BIT, &port_priv->tx_empty); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* Try to submit writer */ 117162306a36Sopenharmony_ci status = f81534_submit_writer(port, GFP_ATOMIC); 117262306a36Sopenharmony_ci if (status) 117362306a36Sopenharmony_ci dev_err(&port->dev, "%s: submit failed\n", __func__); 117462306a36Sopenharmony_ci return; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci case F81534_TOKEN_MSR_CHANGE: 117762306a36Sopenharmony_ci f81534_msr_changed(port, data[3]); 117862306a36Sopenharmony_ci return; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci case F81534_TOKEN_RECEIVE: 118162306a36Sopenharmony_ci read_size = data[2]; 118262306a36Sopenharmony_ci if (read_size > F81534_MAX_RX_SIZE) { 118362306a36Sopenharmony_ci dev_err(&port->dev, 118462306a36Sopenharmony_ci "%s: phy: %d read_size: %zu larger than: %d\n", 118562306a36Sopenharmony_ci __func__, phy_num, read_size, 118662306a36Sopenharmony_ci F81534_MAX_RX_SIZE); 118762306a36Sopenharmony_ci return; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci break; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci default: 119362306a36Sopenharmony_ci dev_warn(&port->dev, "%s: unknown token: %02x\n", __func__, 119462306a36Sopenharmony_ci data[1]); 119562306a36Sopenharmony_ci return; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci for (i = 4; i < 4 + read_size; i += 2) { 119962306a36Sopenharmony_ci tty_flag = TTY_NORMAL; 120062306a36Sopenharmony_ci lsr = data[i + 1]; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (lsr & UART_LSR_BRK_ERROR_BITS) { 120362306a36Sopenharmony_ci if (lsr & UART_LSR_BI) { 120462306a36Sopenharmony_ci tty_flag = TTY_BREAK; 120562306a36Sopenharmony_ci port->icount.brk++; 120662306a36Sopenharmony_ci usb_serial_handle_break(port); 120762306a36Sopenharmony_ci } else if (lsr & UART_LSR_PE) { 120862306a36Sopenharmony_ci tty_flag = TTY_PARITY; 120962306a36Sopenharmony_ci port->icount.parity++; 121062306a36Sopenharmony_ci } else if (lsr & UART_LSR_FE) { 121162306a36Sopenharmony_ci tty_flag = TTY_FRAME; 121262306a36Sopenharmony_ci port->icount.frame++; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (lsr & UART_LSR_OE) { 121662306a36Sopenharmony_ci port->icount.overrun++; 121762306a36Sopenharmony_ci tty_insert_flip_char(&port->port, 0, 121862306a36Sopenharmony_ci TTY_OVERRUN); 121962306a36Sopenharmony_ci } 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci schedule_work(&port_priv->lsr_work); 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (port->sysrq) { 122562306a36Sopenharmony_ci if (usb_serial_handle_sysrq_char(port, data[i])) 122662306a36Sopenharmony_ci continue; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci tty_insert_flip_char(&port->port, data[i], tty_flag); 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci tty_flip_buffer_push(&port->port); 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic void f81534_process_read_urb(struct urb *urb) 123662306a36Sopenharmony_ci{ 123762306a36Sopenharmony_ci struct f81534_serial_private *serial_priv; 123862306a36Sopenharmony_ci struct usb_serial_port *port; 123962306a36Sopenharmony_ci struct usb_serial *serial; 124062306a36Sopenharmony_ci u8 *buf; 124162306a36Sopenharmony_ci int phy_port_num; 124262306a36Sopenharmony_ci int tty_port_num; 124362306a36Sopenharmony_ci size_t i; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci if (!urb->actual_length || 124662306a36Sopenharmony_ci urb->actual_length % F81534_RECEIVE_BLOCK_SIZE) { 124762306a36Sopenharmony_ci return; 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci port = urb->context; 125162306a36Sopenharmony_ci serial = port->serial; 125262306a36Sopenharmony_ci buf = urb->transfer_buffer; 125362306a36Sopenharmony_ci serial_priv = usb_get_serial_data(serial); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci for (i = 0; i < urb->actual_length; i += F81534_RECEIVE_BLOCK_SIZE) { 125662306a36Sopenharmony_ci phy_port_num = buf[i]; 125762306a36Sopenharmony_ci if (phy_port_num >= F81534_NUM_PORT) { 125862306a36Sopenharmony_ci dev_err(&port->dev, 125962306a36Sopenharmony_ci "%s: phy_port_num: %d larger than: %d\n", 126062306a36Sopenharmony_ci __func__, phy_port_num, F81534_NUM_PORT); 126162306a36Sopenharmony_ci continue; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci tty_port_num = serial_priv->tty_idx[phy_port_num]; 126562306a36Sopenharmony_ci port = serial->port[tty_port_num]; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (tty_port_initialized(&port->port)) 126862306a36Sopenharmony_ci f81534_process_per_serial_block(port, &buf[i]); 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci} 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_cistatic void f81534_write_usb_callback(struct urb *urb) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci struct usb_serial_port *port = urb->context; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci switch (urb->status) { 127762306a36Sopenharmony_ci case 0: 127862306a36Sopenharmony_ci break; 127962306a36Sopenharmony_ci case -ENOENT: 128062306a36Sopenharmony_ci case -ECONNRESET: 128162306a36Sopenharmony_ci case -ESHUTDOWN: 128262306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - urb stopped: %d\n", 128362306a36Sopenharmony_ci __func__, urb->status); 128462306a36Sopenharmony_ci return; 128562306a36Sopenharmony_ci case -EPIPE: 128662306a36Sopenharmony_ci dev_err(&port->dev, "%s - urb stopped: %d\n", 128762306a36Sopenharmony_ci __func__, urb->status); 128862306a36Sopenharmony_ci return; 128962306a36Sopenharmony_ci default: 129062306a36Sopenharmony_ci dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", 129162306a36Sopenharmony_ci __func__, urb->status); 129262306a36Sopenharmony_ci break; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic void f81534_lsr_worker(struct work_struct *work) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct f81534_port_private *port_priv; 129962306a36Sopenharmony_ci struct usb_serial_port *port; 130062306a36Sopenharmony_ci int status; 130162306a36Sopenharmony_ci u8 tmp; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci port_priv = container_of(work, struct f81534_port_private, lsr_work); 130462306a36Sopenharmony_ci port = port_priv->port; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci status = f81534_get_port_register(port, F81534_LINE_STATUS_REG, &tmp); 130762306a36Sopenharmony_ci if (status) 130862306a36Sopenharmony_ci dev_warn(&port->dev, "read LSR failed: %d\n", status); 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic int f81534_set_port_output_pin(struct usb_serial_port *port) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct f81534_serial_private *serial_priv; 131462306a36Sopenharmony_ci struct f81534_port_private *port_priv; 131562306a36Sopenharmony_ci struct usb_serial *serial; 131662306a36Sopenharmony_ci const struct f81534_port_out_pin *pins; 131762306a36Sopenharmony_ci int status; 131862306a36Sopenharmony_ci int i; 131962306a36Sopenharmony_ci u8 value; 132062306a36Sopenharmony_ci u8 idx; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci serial = port->serial; 132362306a36Sopenharmony_ci serial_priv = usb_get_serial_data(serial); 132462306a36Sopenharmony_ci port_priv = usb_get_serial_port_data(port); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci idx = F81534_CONF_INIT_GPIO_OFFSET + port_priv->phy_num; 132762306a36Sopenharmony_ci value = serial_priv->conf_data[idx]; 132862306a36Sopenharmony_ci if (value >= F81534_CONF_GPIO_SHUTDOWN) { 132962306a36Sopenharmony_ci /* 133062306a36Sopenharmony_ci * Newer IC configure will make transceiver in shutdown mode on 133162306a36Sopenharmony_ci * initial power on. We need enable it before using UARTs. 133262306a36Sopenharmony_ci */ 133362306a36Sopenharmony_ci idx = F81534_CONF_WORK_GPIO_OFFSET + port_priv->phy_num; 133462306a36Sopenharmony_ci value = serial_priv->conf_data[idx]; 133562306a36Sopenharmony_ci if (value >= F81534_CONF_GPIO_SHUTDOWN) 133662306a36Sopenharmony_ci value = F81534_CONF_GPIO_RS232; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci pins = &f81534_port_out_pins[port_priv->phy_num]; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pins->pin); ++i) { 134262306a36Sopenharmony_ci status = f81534_set_mask_register(serial, 134362306a36Sopenharmony_ci pins->pin[i].reg_addr, pins->pin[i].reg_mask, 134462306a36Sopenharmony_ci value & BIT(i) ? pins->pin[i].reg_mask : 0); 134562306a36Sopenharmony_ci if (status) 134662306a36Sopenharmony_ci return status; 134762306a36Sopenharmony_ci } 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci dev_dbg(&port->dev, "Output pin (M0/M1/M2): %d\n", value); 135062306a36Sopenharmony_ci return 0; 135162306a36Sopenharmony_ci} 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_cistatic int f81534_port_probe(struct usb_serial_port *port) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci struct f81534_serial_private *serial_priv; 135662306a36Sopenharmony_ci struct f81534_port_private *port_priv; 135762306a36Sopenharmony_ci int ret; 135862306a36Sopenharmony_ci u8 value; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci serial_priv = usb_get_serial_data(port->serial); 136162306a36Sopenharmony_ci port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL); 136262306a36Sopenharmony_ci if (!port_priv) 136362306a36Sopenharmony_ci return -ENOMEM; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci /* 136662306a36Sopenharmony_ci * We'll make tx frame error when baud rate from 384~500kps. So we'll 136762306a36Sopenharmony_ci * delay all tx data frame with 1bit. 136862306a36Sopenharmony_ci */ 136962306a36Sopenharmony_ci port_priv->shadow_clk = F81534_UART_EN | F81534_CLK_TX_DELAY_1BIT; 137062306a36Sopenharmony_ci spin_lock_init(&port_priv->msr_lock); 137162306a36Sopenharmony_ci mutex_init(&port_priv->mcr_mutex); 137262306a36Sopenharmony_ci mutex_init(&port_priv->lcr_mutex); 137362306a36Sopenharmony_ci INIT_WORK(&port_priv->lsr_work, f81534_lsr_worker); 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci /* Assign logic-to-phy mapping */ 137662306a36Sopenharmony_ci ret = f81534_logic_to_phy_port(port->serial, port); 137762306a36Sopenharmony_ci if (ret < 0) 137862306a36Sopenharmony_ci return ret; 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci port_priv->phy_num = ret; 138162306a36Sopenharmony_ci port_priv->port = port; 138262306a36Sopenharmony_ci usb_set_serial_port_data(port, port_priv); 138362306a36Sopenharmony_ci dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__, 138462306a36Sopenharmony_ci port->port_number, port_priv->phy_num); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci /* 138762306a36Sopenharmony_ci * The F81532/534 will hang-up when enable LSR interrupt in IER and 138862306a36Sopenharmony_ci * occur data overrun. So we'll disable the LSR interrupt in probe() 138962306a36Sopenharmony_ci * and submit the LSR worker to clear LSR state when reported LSR error 139062306a36Sopenharmony_ci * bit with bulk-in data in f81534_process_per_serial_block(). 139162306a36Sopenharmony_ci */ 139262306a36Sopenharmony_ci ret = f81534_set_port_register(port, F81534_INTERRUPT_ENABLE_REG, 139362306a36Sopenharmony_ci UART_IER_RDI | UART_IER_THRI | UART_IER_MSI); 139462306a36Sopenharmony_ci if (ret) 139562306a36Sopenharmony_ci return ret; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci value = serial_priv->conf_data[port_priv->phy_num]; 139862306a36Sopenharmony_ci switch (value & F81534_PORT_CONF_MODE_MASK) { 139962306a36Sopenharmony_ci case F81534_PORT_CONF_RS485_INVERT: 140062306a36Sopenharmony_ci port_priv->shadow_clk |= F81534_CLK_RS485_MODE | 140162306a36Sopenharmony_ci F81534_CLK_RS485_INVERT; 140262306a36Sopenharmony_ci dev_dbg(&port->dev, "RS485 invert mode\n"); 140362306a36Sopenharmony_ci break; 140462306a36Sopenharmony_ci case F81534_PORT_CONF_RS485: 140562306a36Sopenharmony_ci port_priv->shadow_clk |= F81534_CLK_RS485_MODE; 140662306a36Sopenharmony_ci dev_dbg(&port->dev, "RS485 mode\n"); 140762306a36Sopenharmony_ci break; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci default: 141062306a36Sopenharmony_ci case F81534_PORT_CONF_RS232: 141162306a36Sopenharmony_ci dev_dbg(&port->dev, "RS232 mode\n"); 141262306a36Sopenharmony_ci break; 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci return f81534_set_port_output_pin(port); 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_cistatic void f81534_port_remove(struct usb_serial_port *port) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci flush_work(&port_priv->lsr_work); 142362306a36Sopenharmony_ci} 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistatic int f81534_tiocmget(struct tty_struct *tty) 142662306a36Sopenharmony_ci{ 142762306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 142862306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 142962306a36Sopenharmony_ci int status; 143062306a36Sopenharmony_ci int r; 143162306a36Sopenharmony_ci u8 msr; 143262306a36Sopenharmony_ci u8 mcr; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* Read current MSR from device */ 143562306a36Sopenharmony_ci status = f81534_get_port_register(port, F81534_MODEM_STATUS_REG, &msr); 143662306a36Sopenharmony_ci if (status) 143762306a36Sopenharmony_ci return status; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci mutex_lock(&port_priv->mcr_mutex); 144062306a36Sopenharmony_ci mcr = port_priv->shadow_mcr; 144162306a36Sopenharmony_ci mutex_unlock(&port_priv->mcr_mutex); 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci r = (mcr & UART_MCR_DTR ? TIOCM_DTR : 0) | 144462306a36Sopenharmony_ci (mcr & UART_MCR_RTS ? TIOCM_RTS : 0) | 144562306a36Sopenharmony_ci (msr & UART_MSR_CTS ? TIOCM_CTS : 0) | 144662306a36Sopenharmony_ci (msr & UART_MSR_DCD ? TIOCM_CAR : 0) | 144762306a36Sopenharmony_ci (msr & UART_MSR_RI ? TIOCM_RI : 0) | 144862306a36Sopenharmony_ci (msr & UART_MSR_DSR ? TIOCM_DSR : 0); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci return r; 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic int f81534_tiocmset(struct tty_struct *tty, unsigned int set, 145462306a36Sopenharmony_ci unsigned int clear) 145562306a36Sopenharmony_ci{ 145662306a36Sopenharmony_ci struct usb_serial_port *port = tty->driver_data; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci return f81534_update_mctrl(port, set, clear); 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic void f81534_dtr_rts(struct usb_serial_port *port, int on) 146262306a36Sopenharmony_ci{ 146362306a36Sopenharmony_ci if (on) 146462306a36Sopenharmony_ci f81534_update_mctrl(port, TIOCM_DTR | TIOCM_RTS, 0); 146562306a36Sopenharmony_ci else 146662306a36Sopenharmony_ci f81534_update_mctrl(port, 0, TIOCM_DTR | TIOCM_RTS); 146762306a36Sopenharmony_ci} 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_cistatic int f81534_write(struct tty_struct *tty, struct usb_serial_port *port, 147062306a36Sopenharmony_ci const u8 *buf, int count) 147162306a36Sopenharmony_ci{ 147262306a36Sopenharmony_ci int bytes_out, status; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (!count) 147562306a36Sopenharmony_ci return 0; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci bytes_out = kfifo_in_locked(&port->write_fifo, buf, count, 147862306a36Sopenharmony_ci &port->lock); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci status = f81534_submit_writer(port, GFP_ATOMIC); 148162306a36Sopenharmony_ci if (status) { 148262306a36Sopenharmony_ci dev_err(&port->dev, "%s: submit failed\n", __func__); 148362306a36Sopenharmony_ci return status; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci return bytes_out; 148762306a36Sopenharmony_ci} 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_cistatic bool f81534_tx_empty(struct usb_serial_port *port) 149062306a36Sopenharmony_ci{ 149162306a36Sopenharmony_ci struct f81534_port_private *port_priv = usb_get_serial_port_data(port); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci return test_bit(F81534_TX_EMPTY_BIT, &port_priv->tx_empty); 149462306a36Sopenharmony_ci} 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int f81534_resume(struct usb_serial *serial) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci struct f81534_serial_private *serial_priv = 149962306a36Sopenharmony_ci usb_get_serial_data(serial); 150062306a36Sopenharmony_ci struct usb_serial_port *port; 150162306a36Sopenharmony_ci int error = 0; 150262306a36Sopenharmony_ci int status; 150362306a36Sopenharmony_ci size_t i; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci /* 150662306a36Sopenharmony_ci * We'll register port 0 bulkin when port had opened, It'll take all 150762306a36Sopenharmony_ci * port received data, MSR register change and TX_EMPTY information. 150862306a36Sopenharmony_ci */ 150962306a36Sopenharmony_ci mutex_lock(&serial_priv->urb_mutex); 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci if (serial_priv->opened_port) { 151262306a36Sopenharmony_ci status = f81534_submit_read_urb(serial, GFP_NOIO); 151362306a36Sopenharmony_ci if (status) { 151462306a36Sopenharmony_ci mutex_unlock(&serial_priv->urb_mutex); 151562306a36Sopenharmony_ci return status; 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci mutex_unlock(&serial_priv->urb_mutex); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci for (i = 0; i < serial->num_ports; i++) { 152262306a36Sopenharmony_ci port = serial->port[i]; 152362306a36Sopenharmony_ci if (!tty_port_initialized(&port->port)) 152462306a36Sopenharmony_ci continue; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci status = f81534_submit_writer(port, GFP_NOIO); 152762306a36Sopenharmony_ci if (status) { 152862306a36Sopenharmony_ci dev_err(&port->dev, "%s: submit failed\n", __func__); 152962306a36Sopenharmony_ci ++error; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (error) 153462306a36Sopenharmony_ci return -EIO; 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci return 0; 153762306a36Sopenharmony_ci} 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_cistatic struct usb_serial_driver f81534_device = { 154062306a36Sopenharmony_ci .driver = { 154162306a36Sopenharmony_ci .owner = THIS_MODULE, 154262306a36Sopenharmony_ci .name = "f81534", 154362306a36Sopenharmony_ci }, 154462306a36Sopenharmony_ci .description = DRIVER_DESC, 154562306a36Sopenharmony_ci .id_table = f81534_id_table, 154662306a36Sopenharmony_ci .num_bulk_in = 1, 154762306a36Sopenharmony_ci .num_bulk_out = 1, 154862306a36Sopenharmony_ci .open = f81534_open, 154962306a36Sopenharmony_ci .close = f81534_close, 155062306a36Sopenharmony_ci .write = f81534_write, 155162306a36Sopenharmony_ci .tx_empty = f81534_tx_empty, 155262306a36Sopenharmony_ci .calc_num_ports = f81534_calc_num_ports, 155362306a36Sopenharmony_ci .port_probe = f81534_port_probe, 155462306a36Sopenharmony_ci .port_remove = f81534_port_remove, 155562306a36Sopenharmony_ci .break_ctl = f81534_break_ctl, 155662306a36Sopenharmony_ci .dtr_rts = f81534_dtr_rts, 155762306a36Sopenharmony_ci .process_read_urb = f81534_process_read_urb, 155862306a36Sopenharmony_ci .get_serial = f81534_get_serial_info, 155962306a36Sopenharmony_ci .tiocmget = f81534_tiocmget, 156062306a36Sopenharmony_ci .tiocmset = f81534_tiocmset, 156162306a36Sopenharmony_ci .write_bulk_callback = f81534_write_usb_callback, 156262306a36Sopenharmony_ci .set_termios = f81534_set_termios, 156362306a36Sopenharmony_ci .resume = f81534_resume, 156462306a36Sopenharmony_ci}; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_cistatic struct usb_serial_driver *const serial_drivers[] = { 156762306a36Sopenharmony_ci &f81534_device, NULL 156862306a36Sopenharmony_ci}; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cimodule_usb_serial_driver(serial_drivers, f81534_id_table); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, f81534_id_table); 157362306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 157462306a36Sopenharmony_ciMODULE_AUTHOR("Peter Hong <Peter_Hong@fintek.com.tw>"); 157562306a36Sopenharmony_ciMODULE_AUTHOR("Tom Tsai <Tom_Tsai@fintek.com.tw>"); 157662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1577