// SPDX-License-Identifier: GPL-2.0+ /* * F81532/F81534 USB to Serial Ports Bridge * * F81532 => 2 Serial Ports * F81534 => 4 Serial Ports * * Copyright (C) 2016 Feature Integration Technology Inc., (Fintek) * Copyright (C) 2016 Tom Tsai (Tom_Tsai@fintek.com.tw) * Copyright (C) 2016 Peter Hong (Peter_Hong@fintek.com.tw) * * The F81532/F81534 had 1 control endpoint for setting, 1 endpoint bulk-out * for all serial port TX and 1 endpoint bulk-in for all serial port read in * (Read Data/MSR/LSR). * * Write URB is fixed with 512bytes, per serial port used 128Bytes. * It can be described by f81534_prepare_write_buffer() * * Read URB is 512Bytes max, per serial port used 128Bytes. * It can be described by f81534_process_read_urb() and maybe received with * 128x1,2,3,4 bytes. *
*/ #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/serial_reg.h> #include <linux/module.h> #include <linux/uaccess.h>
/* * We used interal SPI bus to access FLASH section. We must wait the SPI bus to * idle if we performed any command. * * SPI Bus status register: F81534_BUS_REG_STATUS * Bit 0/1 : BUSY * Bit 2 : IDLE
*/ #define F81534_BUS_BUSY (BIT(0) | BIT(1)) #define F81534_BUS_IDLE BIT(2) #define F81534_BUS_READ_DATA 0x1004 #define F81534_BUS_REG_STATUS 0x1003 #define F81534_BUS_REG_START 0x1002 #define F81534_BUS_REG_END 0x1001
/* * If we try to access the internal flash via SPI bus, we should check the bus * status for every command. e.g., F81534_BUS_REG_START/F81534_BUS_REG_END
*/ staticint f81534_wait_for_spi_idle(struct usb_serial *serial)
{
size_t count = F81534_MAX_BUS_RETRY;
u8 tmp; int status;
do {
status = f81534_get_register(serial, F81534_BUS_REG_STATUS,
&tmp); if (status) return status;
if (tmp & F81534_BUS_BUSY) continue;
if (tmp & F81534_BUS_IDLE) break;
} while (--count);
if (!count) {
dev_err(&serial->interface->dev, "%s: timed out waiting for idle SPI bus\n",
__func__); return -EIO;
}
for (count = 0; count < read_size; ++count) { /* To write F81534_BUS_REG_END when final byte */ if (size <= F81534_MAX_DATA_BLOCK &&
read_size == count + 1)
reg_tmp = F81534_BUS_REG_END; else
reg_tmp = F81534_BUS_REG_START;
/* * Dummy code, force IC to generate a read pulse, the * set of value 0xf1 is dont care (any value is ok)
*/
status = f81534_set_spi_register(serial, reg_tmp,
0xf1); if (status) return status;
status = f81534_get_spi_register(serial,
F81534_BUS_READ_DATA,
&tmp_buf[count]); if (status) return status;
staticvoid f81534_prepare_write_buffer(struct usb_serial_port *port, u8 *buf)
{ struct f81534_port_private *port_priv = usb_get_serial_port_data(port); int phy_num = port_priv->phy_num;
u8 tx_len; int i;
/* * The block layout is fixed with 4x128 Bytes, per 128 Bytes a port. * index 0: port phy idx (e.g., 0,1,2,3) * index 1: only F81534_TOKEN_WRITE * index 2: serial TX out length * index 3: fix to 0 * index 4~127: serial out data block
*/ for (i = 0; i < F81534_NUM_PORT; ++i) {
buf[i * F81534_RECEIVE_BLOCK_SIZE] = i;
buf[i * F81534_RECEIVE_BLOCK_SIZE + 1] = F81534_TOKEN_WRITE;
buf[i * F81534_RECEIVE_BLOCK_SIZE + 2] = 0;
buf[i * F81534_RECEIVE_BLOCK_SIZE + 3] = 0;
}
value = UART_LCR_DLAB;
status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG,
value); if (status) {
dev_err(&port->dev, "%s: set LCR failed\n", __func__); goto out_unlock;
}
value = divisor & 0xff;
status = f81534_set_port_register(port, F81534_DIVISOR_LSB_REG, value); if (status) {
dev_err(&port->dev, "%s: set DLAB LSB failed\n", __func__); goto out_unlock;
}
value = (divisor >> 8) & 0xff;
status = f81534_set_port_register(port, F81534_DIVISOR_MSB_REG, value); if (status) {
dev_err(&port->dev, "%s: set DLAB MSB failed\n", __func__); goto out_unlock;
}
value = lcr | (port_priv->shadow_lcr & UART_LCR_SBC);
status = f81534_set_port_register(port, F81534_LINE_CONTROL_REG,
value); if (status) {
dev_err(&port->dev, "%s: set LCR failed\n", __func__); goto out_unlock;
}
/* * This function will search the data area with token F81534_CUSTOM_VALID_TOKEN * for latest configuration index. If nothing found * (*index = F81534_CUSTOM_NO_CUSTOM_DATA), We'll load default configure in * F81534_DEF_CONF_ADDRESS_START section. * * Due to we only use block0 to save data, so *index should be 0 or * F81534_CUSTOM_NO_CUSTOM_DATA.
*/ staticint f81534_find_config_idx(struct usb_serial *serial, u8 *index)
{
u8 tmp; int status;
status = f81534_read_flash(serial, F81534_CUSTOM_ADDRESS_START, 1,
&tmp); if (status) {
dev_err(&serial->interface->dev, "%s: read failed: %d\n",
__func__, status); return status;
}
/* We'll use the custom data when the data is valid. */ if (tmp == F81534_CUSTOM_VALID_TOKEN)
*index = 0; else
*index = F81534_CUSTOM_NO_CUSTOM_DATA;
return 0;
}
/* * The F81532/534 will not report serial port to USB serial subsystem when * H/W DCD/DSR/CTS/RI/RX pin connected to ground. * * To detect RX pin status, we'll enable MCR interal loopback, disable it and * delayed for 60ms. It connected to ground If LSR register report UART_LSR_BI.
*/ staticbool f81534_check_port_hw_disabled(struct usb_serial *serial, int phy)
{ int status;
u8 old_mcr;
u8 msr;
u8 lsr;
u8 msr_mask;
status = f81534_get_phy_port_register(serial, phy,
F81534_MODEM_STATUS_REG, &msr); if (status) returnfalse;
if ((msr & msr_mask) != msr_mask) returnfalse;
status = f81534_set_phy_port_register(serial, phy,
F81534_FIFO_CONTROL_REG, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); if (status) returnfalse;
status = f81534_get_phy_port_register(serial, phy,
F81534_MODEM_CONTROL_REG, &old_mcr); if (status) returnfalse;
status = f81534_set_phy_port_register(serial, phy,
F81534_MODEM_CONTROL_REG, UART_MCR_LOOP); if (status) returnfalse;
status = f81534_set_phy_port_register(serial, phy,
F81534_MODEM_CONTROL_REG, 0x0); if (status) returnfalse;
msleep(60);
status = f81534_get_phy_port_register(serial, phy,
F81534_LINE_STATUS_REG, &lsr); if (status) returnfalse;
status = f81534_set_phy_port_register(serial, phy,
F81534_MODEM_CONTROL_REG, old_mcr); if (status) returnfalse;
if ((lsr & UART_LSR_BI) == UART_LSR_BI) returntrue;
returnfalse;
}
/* * We had 2 generation of F81532/534 IC. All has an internal storage. * * 1st is pure USB-to-TTL RS232 IC and designed for 4 ports only, no any * internal data will used. All mode and gpio control should manually set * by AP or Driver and all storage space value are 0xff. The * f81534_calc_num_ports() will run to final we marked as "oldest version" * for this IC. * * 2rd is designed to more generic to use any transceiver and this is our * mass production type. We'll save data in F81534_CUSTOM_ADDRESS_START * (0x2f00) with 9bytes. The 1st byte is a indicater. If the token is * F81534_CUSTOM_VALID_TOKEN(0xf0), the IC is 2nd gen type, the following * 4bytes save port mode (0:RS232/1:RS485 Invert/2:RS485), and the last * 4bytes save GPIO state(value from 0~7 to represent 3 GPIO output pin). * The f81534_calc_num_ports() will run to "new style" with checking * F81534_PORT_UNAVAILABLE section.
*/ staticint f81534_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds)
{ struct f81534_serial_private *serial_priv; struct device *dev = &serial->interface->dev; int size_bulk_in = usb_endpoint_maxp(epds->bulk_in[0]); int size_bulk_out = usb_endpoint_maxp(epds->bulk_out[0]);
u8 num_port = 0; int index = 0; int status; int i;
if (size_bulk_out != F81534_WRITE_BUFFER_SIZE ||
size_bulk_in != F81534_MAX_RECEIVE_BLOCK_SIZE) {
dev_err(dev, "unsupported endpoint max packet size\n"); return -ENODEV;
}
serial_priv = devm_kzalloc(&serial->interface->dev, sizeof(*serial_priv), GFP_KERNEL); if (!serial_priv) return -ENOMEM;
/* Check had custom setting */
status = f81534_find_config_idx(serial, &serial_priv->setting_idx); if (status) {
dev_err(&serial->interface->dev, "%s: find idx failed: %d\n",
__func__, status); return status;
}
/* * We'll read custom data only when data available, otherwise we'll * read default value instead.
*/ if (serial_priv->setting_idx != F81534_CUSTOM_NO_CUSTOM_DATA) {
status = f81534_read_flash(serial,
F81534_CUSTOM_ADDRESS_START +
F81534_CONF_OFFSET, sizeof(serial_priv->conf_data),
serial_priv->conf_data); if (status) {
dev_err(&serial->interface->dev, "%s: get custom data failed: %d\n",
__func__, status); return status;
}
/* New style, find all possible ports */ for (i = 0; i < F81534_NUM_PORT; ++i) { if (f81534_check_port_hw_disabled(serial, i))
serial_priv->conf_data[i] |= F81534_PORT_UNAVAILABLE;
if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE) continue;
++num_port;
}
if (!num_port) {
dev_warn(&serial->interface->dev, "no config found, assuming 4 ports\n");
num_port = 4; /* Nothing found, oldest version IC */
}
/* Assign phy-to-logic mapping */ for (i = 0; i < F81534_NUM_PORT; ++i) { if (serial_priv->conf_data[i] & F81534_PORT_UNAVAILABLE) continue;
/* Get MSR initial value */
status = f81534_get_port_register(port, F81534_MODEM_STATUS_REG, &msr); if (status) return status;
/* Force update current state */
spin_lock_irqsave(&port_priv->msr_lock, flags);
port_priv->shadow_msr = msr;
spin_unlock_irqrestore(&port_priv->msr_lock, flags);
status = f81534_read_msr(port); if (status) return status;
mutex_lock(&serial_priv->urb_mutex);
/* Submit Read URBs for first port opened */ if (!serial_priv->opened_port) {
status = f81534_submit_read_urb(port->serial, GFP_KERNEL); if (status) gotoexit;
}
/* * The block layout is 128 Bytes * index 0: port phy idx (e.g., 0,1,2,3), * index 1: It's could be * F81534_TOKEN_RECEIVE * F81534_TOKEN_TX_EMPTY * F81534_TOKEN_MSR_CHANGE * index 2: serial in size (data+lsr, must be even) * meaningful for F81534_TOKEN_RECEIVE only * index 3: current MSR with this device * index 4~127: serial in data block (data+lsr, must be even)
*/ switch (data[1]) { case F81534_TOKEN_TX_EMPTY:
set_bit(F81534_TX_EMPTY_BIT, &port_priv->tx_empty);
/* Try to submit writer */
status = f81534_submit_writer(port, GFP_ATOMIC); if (status)
dev_err(&port->dev, "%s: submit failed\n", __func__); return;
case F81534_TOKEN_MSR_CHANGE:
f81534_msr_changed(port, data[3]); return;
serial = port->serial;
serial_priv = usb_get_serial_data(serial);
port_priv = usb_get_serial_port_data(port);
idx = F81534_CONF_INIT_GPIO_OFFSET + port_priv->phy_num;
value = serial_priv->conf_data[idx]; if (value >= F81534_CONF_GPIO_SHUTDOWN) { /* * Newer IC configure will make transceiver in shutdown mode on * initial power on. We need enable it before using UARTs.
*/
idx = F81534_CONF_WORK_GPIO_OFFSET + port_priv->phy_num;
value = serial_priv->conf_data[idx]; if (value >= F81534_CONF_GPIO_SHUTDOWN)
value = F81534_CONF_GPIO_RS232;
}
pins = &f81534_port_out_pins[port_priv->phy_num];
for (i = 0; i < ARRAY_SIZE(pins->pin); ++i) {
status = f81534_set_mask_register(serial,
pins->pin[i].reg_addr, pins->pin[i].reg_mask,
value & BIT(i) ? pins->pin[i].reg_mask : 0); if (status) return status;
}
/* * We'll make tx frame error when baud rate from 384~500kps. So we'll * delay all tx data frame with 1bit.
*/
port_priv->shadow_clk = F81534_UART_EN | F81534_CLK_TX_DELAY_1BIT;
spin_lock_init(&port_priv->msr_lock);
mutex_init(&port_priv->mcr_mutex);
mutex_init(&port_priv->lcr_mutex);
INIT_WORK(&port_priv->lsr_work, f81534_lsr_worker);
/* Assign logic-to-phy mapping */
ret = f81534_logic_to_phy_port(port->serial, port); if (ret < 0) return ret;
/* * The F81532/534 will hang-up when enable LSR interrupt in IER and * occur data overrun. So we'll disable the LSR interrupt in probe() * and submit the LSR worker to clear LSR state when reported LSR error * bit with bulk-in data in f81534_process_per_serial_block().
*/
ret = f81534_set_port_register(port, F81534_INTERRUPT_ENABLE_REG,
UART_IER_RDI | UART_IER_THRI | UART_IER_MSI); if (ret) return ret;
value = serial_priv->conf_data[port_priv->phy_num]; switch (value & F81534_PORT_CONF_MODE_MASK) { case F81534_PORT_CONF_RS485_INVERT:
port_priv->shadow_clk |= F81534_CLK_RS485_MODE |
F81534_CLK_RS485_INVERT;
dev_dbg(&port->dev, "RS485 invert mode\n"); break; case F81534_PORT_CONF_RS485:
port_priv->shadow_clk |= F81534_CLK_RS485_MODE;
dev_dbg(&port->dev, "RS485 mode\n"); break;
default: case F81534_PORT_CONF_RS232:
dev_dbg(&port->dev, "RS232 mode\n"); break;
}
/* * We'll register port 0 bulkin when port had opened, It'll take all * port received data, MSR register change and TX_EMPTY information.
*/
mutex_lock(&serial_priv->urb_mutex);
if (serial_priv->opened_port) {
status = f81534_submit_read_urb(serial, GFP_NOIO); if (status) {
mutex_unlock(&serial_priv->urb_mutex); return status;
}
}
mutex_unlock(&serial_priv->urb_mutex);
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i]; if (!tty_port_initialized(&port->port)) continue;
status = f81534_submit_writer(port, GFP_NOIO); if (status) {
dev_err(&port->dev, "%s: submit failed\n", __func__);
++error;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.