// SPDX-License-Identifier: GPL-2.0
/*
* Fintek F81232 USB to serial adaptor driver
* Fintek F81532A/534A/535/536 USB to 2/4/8/12 serial adaptor driver
*
* Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org)
* Copyright (C) 2012 Linux Foundation
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial_reg.h>
#define F81232_ID \
{ USB_DEVICE(0x1934, 0x0706) } /* 1 port UART device */
#define F81534A_SERIES_ID \
{ USB_DEVICE(0x2c42, 0x1602) }, /* In-Box 2 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1604) }, /* In-Box 4 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1605) }, /* In-Box 8 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1606) }, /* In-Box 12 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1608) }, /* Non-Flash type */ \
{ USB_DEVICE(0x2c42, 0x1632) }, /* 2 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1634) }, /* 4 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1635) }, /* 8 port UART device */ \
{ USB_DEVICE(0x2c42, 0x1636) } /* 12 port UART device */
#define F81534A_CTRL_ID \
{ USB_DEVICE(0x2c42, 0x16f8) } /* Global control device */
static const struct usb_device_id f81232_id_table[] = {
F81232_ID,
{ } /* Terminating entry */
};
static const struct usb_device_id f81534a_id_table[] = {
F81534A_SERIES_ID,
{ } /* Terminating entry */
};
static const struct usb_device_id f81534a_ctrl_id_table[] = {
F81534A_CTRL_ID,
{ } /* Terminating entry */
};
static const struct usb_device_id combined_id_table[] = {
F81232_ID,
F81534A_SERIES_ID,
F81534A_CTRL_ID,
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, combined_id_table);
/* Maximum baudrate for F81232 */
#define F81232_MAX_BAUDRATE 1500000
#define F81232_DEF_BAUDRATE 9600
/* USB Control EP parameter */
#define F81232_REGISTER_REQUEST 0xa0
#define F81232_GET_REGISTER 0xc0
#define F81232_SET_REGISTER 0x40
#define F81534A_ACCESS_REG_RETRY 2
#define SERIAL_BASE_ADDRESS 0x0120
#define RECEIVE_BUFFER_REGISTER (0x00 + SERIAL_BASE_ADDRESS)
#define INTERRUPT_ENABLE_REGISTER (0x01 + SERIAL_BASE_ADDRESS)
#define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS)
#define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS)
#define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS)
#define LINE_STATUS_REGISTER (0x05 + SERIAL_BASE_ADDRESS)
#define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS)
/*
* F81232 Clock registers (106h)
*
* Bit1-0: Clock source selector
* 00: 1.846MHz.
* 01: 18.46MHz.
* 10: 24MHz.
* 11: 14.77MHz.
*/
#define F81232_CLK_REGISTER 0x106
#define F81232_CLK_1_846_MHZ 0
#define F81232_CLK_18_46_MHZ BIT(0)
#define F81232_CLK_24_MHZ BIT(1)
#define F81232_CLK_14_77_MHZ (BIT(1) | BIT(0))
#define F81232_CLK_MASK GENMASK(1, 0)
#define F81534A_MODE_REG 0x107
#define F81534A_TRIGGER_MASK GENMASK(3, 2)
#define F81534A_TRIGGER_MULTIPLE_4X BIT(3)
#define F81534A_FIFO_128BYTE (BIT(1) | BIT(0))
/* Serial port self GPIO control, 2bytes [control&output data][input data] */
#define F81534A_GPIO_REG 0x10e
#define F81534A_GPIO_MODE2_DIR BIT(6) /* 1: input, 0: output */
#define F81534A_GPIO_MODE1_DIR BIT(5)
#define F81534A_GPIO_MODE0_DIR BIT(4)
#define F81534A_GPIO_MODE2_OUTPUT BIT(2)
#define F81534A_GPIO_MODE1_OUTPUT BIT(1)
#define F81534A_GPIO_MODE0_OUTPUT BIT(0)
#define F81534A_CTRL_CMD_ENABLE_PORT 0x116
struct f81232_private {
struct mutex lock;
u8 modem_control;
u8 modem_status;
u8 shadow_lcr;
speed_t baud_base;
struct work_struct lsr_work;
struct work_struct interrupt_work;
struct usb_serial_port *port;
};
static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 };
static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ,
F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ };
static int calc_baud_divisor(speed_t baudrate, speed_t clockrate)
{
if (!baudrate)
return 0;
return DIV_ROUND_CLOSEST(clockrate, baudrate);
}
static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val)
{
int status;
u8 *tmp;
struct usb_device *dev = port->serial->dev;
tmp = kmalloc(sizeof(*val), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
status = usb_control_msg(dev,
usb_rcvctrlpipe(dev, 0),
F81232_REGISTER_REQUEST,
F81232_GET_REGISTER,
reg,
0,
tmp,
sizeof(*val),
USB_CTRL_GET_TIMEOUT);
if (status != sizeof(*val)) {
dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
if (status < 0)
status = usb_translate_errors(status);
else
status = -EIO;
} else {
status = 0;
*val = *tmp;
}
kfree(tmp);
return status;
}
static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val)
{
int status;
u8 *tmp;
struct usb_device *dev = port->serial->dev;
tmp = kmalloc(sizeof(val), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
*tmp = val;
status = usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
F81232_REGISTER_REQUEST,
F81232_SET_REGISTER,
reg,
0,
tmp,
sizeof(val),
USB_CTRL_SET_TIMEOUT);
if (status != sizeof(val)) {
dev_err(&port->dev, "%s failed status: %d\n", __func__, status);
if (status < 0