18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Probe for F81216A LPC to 4 UART
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/pci.h>
98c2ecf20Sopenharmony_ci#include <linux/pnp.h>
108c2ecf20Sopenharmony_ci#include <linux/kernel.h>
118c2ecf20Sopenharmony_ci#include <linux/serial_core.h>
128c2ecf20Sopenharmony_ci#include <linux/irq.h>
138c2ecf20Sopenharmony_ci#include  "8250.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define ADDR_PORT 0
168c2ecf20Sopenharmony_ci#define DATA_PORT 1
178c2ecf20Sopenharmony_ci#define EXIT_KEY 0xAA
188c2ecf20Sopenharmony_ci#define CHIP_ID1  0x20
198c2ecf20Sopenharmony_ci#define CHIP_ID2  0x21
208c2ecf20Sopenharmony_ci#define CHIP_ID_F81865 0x0407
218c2ecf20Sopenharmony_ci#define CHIP_ID_F81866 0x1010
228c2ecf20Sopenharmony_ci#define CHIP_ID_F81966 0x0215
238c2ecf20Sopenharmony_ci#define CHIP_ID_F81216AD 0x1602
248c2ecf20Sopenharmony_ci#define CHIP_ID_F81216H 0x0501
258c2ecf20Sopenharmony_ci#define CHIP_ID_F81216 0x0802
268c2ecf20Sopenharmony_ci#define VENDOR_ID1 0x23
278c2ecf20Sopenharmony_ci#define VENDOR_ID1_VAL 0x19
288c2ecf20Sopenharmony_ci#define VENDOR_ID2 0x24
298c2ecf20Sopenharmony_ci#define VENDOR_ID2_VAL 0x34
308c2ecf20Sopenharmony_ci#define IO_ADDR1 0x61
318c2ecf20Sopenharmony_ci#define IO_ADDR2 0x60
328c2ecf20Sopenharmony_ci#define LDN 0x7
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define FINTEK_IRQ_MODE	0x70
358c2ecf20Sopenharmony_ci#define IRQ_SHARE	BIT(4)
368c2ecf20Sopenharmony_ci#define IRQ_MODE_MASK	(BIT(6) | BIT(5))
378c2ecf20Sopenharmony_ci#define IRQ_LEVEL_LOW	0
388c2ecf20Sopenharmony_ci#define IRQ_EDGE_HIGH	BIT(5)
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci/*
418c2ecf20Sopenharmony_ci * F81216H clock source register, the value and mask is the same with F81866,
428c2ecf20Sopenharmony_ci * but it's on F0h.
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * Clock speeds for UART (register F0h)
458c2ecf20Sopenharmony_ci * 00: 1.8432MHz.
468c2ecf20Sopenharmony_ci * 01: 18.432MHz.
478c2ecf20Sopenharmony_ci * 10: 24MHz.
488c2ecf20Sopenharmony_ci * 11: 14.769MHz.
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_ci#define RS485  0xF0
518c2ecf20Sopenharmony_ci#define RTS_INVERT BIT(5)
528c2ecf20Sopenharmony_ci#define RS485_URA BIT(4)
538c2ecf20Sopenharmony_ci#define RXW4C_IRA BIT(3)
548c2ecf20Sopenharmony_ci#define TXW4C_IRA BIT(2)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define FIFO_CTRL		0xF6
578c2ecf20Sopenharmony_ci#define FIFO_MODE_MASK		(BIT(1) | BIT(0))
588c2ecf20Sopenharmony_ci#define FIFO_MODE_128		(BIT(1) | BIT(0))
598c2ecf20Sopenharmony_ci#define RXFTHR_MODE_MASK	(BIT(5) | BIT(4))
608c2ecf20Sopenharmony_ci#define RXFTHR_MODE_4X		BIT(5)
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci#define F81216_LDN_LOW	0x0
638c2ecf20Sopenharmony_ci#define F81216_LDN_HIGH	0x4
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * F81866/966 registers
678c2ecf20Sopenharmony_ci *
688c2ecf20Sopenharmony_ci * The IRQ setting mode of F81866/966 is not the same with F81216 series.
698c2ecf20Sopenharmony_ci *	Level/Low: IRQ_MODE0:0, IRQ_MODE1:0
708c2ecf20Sopenharmony_ci *	Edge/High: IRQ_MODE0:1, IRQ_MODE1:0
718c2ecf20Sopenharmony_ci *
728c2ecf20Sopenharmony_ci * Clock speeds for UART (register F2h)
738c2ecf20Sopenharmony_ci * 00: 1.8432MHz.
748c2ecf20Sopenharmony_ci * 01: 18.432MHz.
758c2ecf20Sopenharmony_ci * 10: 24MHz.
768c2ecf20Sopenharmony_ci * 11: 14.769MHz.
778c2ecf20Sopenharmony_ci */
788c2ecf20Sopenharmony_ci#define F81866_IRQ_MODE		0xf0
798c2ecf20Sopenharmony_ci#define F81866_IRQ_SHARE	BIT(0)
808c2ecf20Sopenharmony_ci#define F81866_IRQ_MODE0	BIT(1)
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#define F81866_FIFO_CTRL	FIFO_CTRL
838c2ecf20Sopenharmony_ci#define F81866_IRQ_MODE1	BIT(3)
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define F81866_LDN_LOW		0x10
868c2ecf20Sopenharmony_ci#define F81866_LDN_HIGH		0x16
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci#define F81866_UART_CLK 0xF2
898c2ecf20Sopenharmony_ci#define F81866_UART_CLK_MASK (BIT(1) | BIT(0))
908c2ecf20Sopenharmony_ci#define F81866_UART_CLK_1_8432MHZ 0
918c2ecf20Sopenharmony_ci#define F81866_UART_CLK_14_769MHZ (BIT(1) | BIT(0))
928c2ecf20Sopenharmony_ci#define F81866_UART_CLK_18_432MHZ BIT(0)
938c2ecf20Sopenharmony_ci#define F81866_UART_CLK_24MHZ BIT(1)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistruct fintek_8250 {
968c2ecf20Sopenharmony_ci	u16 pid;
978c2ecf20Sopenharmony_ci	u16 base_port;
988c2ecf20Sopenharmony_ci	u8 index;
998c2ecf20Sopenharmony_ci	u8 key;
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic u8 sio_read_reg(struct fintek_8250 *pdata, u8 reg)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	outb(reg, pdata->base_port + ADDR_PORT);
1058c2ecf20Sopenharmony_ci	return inb(pdata->base_port + DATA_PORT);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic void sio_write_reg(struct fintek_8250 *pdata, u8 reg, u8 data)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	outb(reg, pdata->base_port + ADDR_PORT);
1118c2ecf20Sopenharmony_ci	outb(data, pdata->base_port + DATA_PORT);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic void sio_write_mask_reg(struct fintek_8250 *pdata, u8 reg, u8 mask,
1158c2ecf20Sopenharmony_ci			       u8 data)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	u8 tmp;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	tmp = (sio_read_reg(pdata, reg) & ~mask) | (mask & data);
1208c2ecf20Sopenharmony_ci	sio_write_reg(pdata, reg, tmp);
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic int fintek_8250_enter_key(u16 base_port, u8 key)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	if (!request_muxed_region(base_port, 2, "8250_fintek"))
1268c2ecf20Sopenharmony_ci		return -EBUSY;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* Force to deactive all SuperIO in this base_port */
1298c2ecf20Sopenharmony_ci	outb(EXIT_KEY, base_port + ADDR_PORT);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	outb(key, base_port + ADDR_PORT);
1328c2ecf20Sopenharmony_ci	outb(key, base_port + ADDR_PORT);
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic void fintek_8250_exit_key(u16 base_port)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	outb(EXIT_KEY, base_port + ADDR_PORT);
1408c2ecf20Sopenharmony_ci	release_region(base_port + ADDR_PORT, 2);
1418c2ecf20Sopenharmony_ci}
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int fintek_8250_check_id(struct fintek_8250 *pdata)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	u16 chip;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (sio_read_reg(pdata, VENDOR_ID1) != VENDOR_ID1_VAL)
1488c2ecf20Sopenharmony_ci		return -ENODEV;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	if (sio_read_reg(pdata, VENDOR_ID2) != VENDOR_ID2_VAL)
1518c2ecf20Sopenharmony_ci		return -ENODEV;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	chip = sio_read_reg(pdata, CHIP_ID1);
1548c2ecf20Sopenharmony_ci	chip |= sio_read_reg(pdata, CHIP_ID2) << 8;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	switch (chip) {
1578c2ecf20Sopenharmony_ci	case CHIP_ID_F81865:
1588c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
1598c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
1608c2ecf20Sopenharmony_ci	case CHIP_ID_F81216AD:
1618c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H:
1628c2ecf20Sopenharmony_ci	case CHIP_ID_F81216:
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	default:
1658c2ecf20Sopenharmony_ci		return -ENODEV;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	pdata->pid = chip;
1698c2ecf20Sopenharmony_ci	return 0;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
1738c2ecf20Sopenharmony_ci				     int *max)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	switch (pdata->pid) {
1768c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
1778c2ecf20Sopenharmony_ci	case CHIP_ID_F81865:
1788c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
1798c2ecf20Sopenharmony_ci		*min = F81866_LDN_LOW;
1808c2ecf20Sopenharmony_ci		*max = F81866_LDN_HIGH;
1818c2ecf20Sopenharmony_ci		return 0;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	case CHIP_ID_F81216AD:
1848c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H:
1858c2ecf20Sopenharmony_ci	case CHIP_ID_F81216:
1868c2ecf20Sopenharmony_ci		*min = F81216_LDN_LOW;
1878c2ecf20Sopenharmony_ci		*max = F81216_LDN_HIGH;
1888c2ecf20Sopenharmony_ci		return 0;
1898c2ecf20Sopenharmony_ci	}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return -ENODEV;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int fintek_8250_rs485_config(struct uart_port *port,
1958c2ecf20Sopenharmony_ci			      struct serial_rs485 *rs485)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	uint8_t config = 0;
1988c2ecf20Sopenharmony_ci	struct fintek_8250 *pdata = port->private_data;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	if (!pdata)
2018c2ecf20Sopenharmony_ci		return -EINVAL;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	if (rs485->flags & SER_RS485_ENABLED) {
2058c2ecf20Sopenharmony_ci		/* Hardware do not support same RTS level on send and receive */
2068c2ecf20Sopenharmony_ci		if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
2078c2ecf20Sopenharmony_ci		    !(rs485->flags & SER_RS485_RTS_AFTER_SEND))
2088c2ecf20Sopenharmony_ci			return -EINVAL;
2098c2ecf20Sopenharmony_ci		memset(rs485->padding, 0, sizeof(rs485->padding));
2108c2ecf20Sopenharmony_ci		config |= RS485_URA;
2118c2ecf20Sopenharmony_ci	} else {
2128c2ecf20Sopenharmony_ci		memset(rs485, 0, sizeof(*rs485));
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
2168c2ecf20Sopenharmony_ci			SER_RS485_RTS_AFTER_SEND;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	/* Only the first port supports delays */
2198c2ecf20Sopenharmony_ci	if (pdata->index) {
2208c2ecf20Sopenharmony_ci		rs485->delay_rts_before_send = 0;
2218c2ecf20Sopenharmony_ci		rs485->delay_rts_after_send = 0;
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (rs485->delay_rts_before_send) {
2258c2ecf20Sopenharmony_ci		rs485->delay_rts_before_send = 1;
2268c2ecf20Sopenharmony_ci		config |= TXW4C_IRA;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	if (rs485->delay_rts_after_send) {
2308c2ecf20Sopenharmony_ci		rs485->delay_rts_after_send = 1;
2318c2ecf20Sopenharmony_ci		config |= RXW4C_IRA;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (rs485->flags & SER_RS485_RTS_ON_SEND)
2358c2ecf20Sopenharmony_ci		config |= RTS_INVERT;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (fintek_8250_enter_key(pdata->base_port, pdata->key))
2388c2ecf20Sopenharmony_ci		return -EBUSY;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	sio_write_reg(pdata, LDN, pdata->index);
2418c2ecf20Sopenharmony_ci	sio_write_reg(pdata, RS485, config);
2428c2ecf20Sopenharmony_ci	fintek_8250_exit_key(pdata->base_port);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	port->rs485 = *rs485;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	sio_write_reg(pdata, LDN, pdata->index);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	switch (pdata->pid) {
2548c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
2558c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
2568c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1,
2578c2ecf20Sopenharmony_ci				   0);
2588c2ecf20Sopenharmony_ci		fallthrough;
2598c2ecf20Sopenharmony_ci	case CHIP_ID_F81865:
2608c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE,
2618c2ecf20Sopenharmony_ci				   F81866_IRQ_SHARE);
2628c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_MODE0,
2638c2ecf20Sopenharmony_ci				   is_level ? 0 : F81866_IRQ_MODE0);
2648c2ecf20Sopenharmony_ci		break;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	case CHIP_ID_F81216AD:
2678c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H:
2688c2ecf20Sopenharmony_ci	case CHIP_ID_F81216:
2698c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE,
2708c2ecf20Sopenharmony_ci				   IRQ_SHARE);
2718c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_MODE_MASK,
2728c2ecf20Sopenharmony_ci				   is_level ? IRQ_LEVEL_LOW : IRQ_EDGE_HIGH);
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci	}
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	switch (pdata->pid) {
2808c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H: /* 128Bytes FIFO */
2818c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
2828c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
2838c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, FIFO_CTRL,
2848c2ecf20Sopenharmony_ci				   FIFO_MODE_MASK | RXFTHR_MODE_MASK,
2858c2ecf20Sopenharmony_ci				   FIFO_MODE_128 | RXFTHR_MODE_4X);
2868c2ecf20Sopenharmony_ci		break;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	default: /* Default 16Bytes FIFO */
2898c2ecf20Sopenharmony_ci		break;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic void fintek_8250_set_termios(struct uart_port *port,
2948c2ecf20Sopenharmony_ci				    struct ktermios *termios,
2958c2ecf20Sopenharmony_ci				    struct ktermios *old)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	struct fintek_8250 *pdata = port->private_data;
2988c2ecf20Sopenharmony_ci	unsigned int baud = tty_termios_baud_rate(termios);
2998c2ecf20Sopenharmony_ci	int i;
3008c2ecf20Sopenharmony_ci	u8 reg;
3018c2ecf20Sopenharmony_ci	static u32 baudrate_table[] = {115200, 921600, 1152000, 1500000};
3028c2ecf20Sopenharmony_ci	static u8 clock_table[] = { F81866_UART_CLK_1_8432MHZ,
3038c2ecf20Sopenharmony_ci			F81866_UART_CLK_14_769MHZ, F81866_UART_CLK_18_432MHZ,
3048c2ecf20Sopenharmony_ci			F81866_UART_CLK_24MHZ };
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	/*
3078c2ecf20Sopenharmony_ci	 * We'll use serial8250_do_set_termios() for baud = 0, otherwise It'll
3088c2ecf20Sopenharmony_ci	 * crash on baudrate_table[i] % baud with "division by zero".
3098c2ecf20Sopenharmony_ci	 */
3108c2ecf20Sopenharmony_ci	if (!baud)
3118c2ecf20Sopenharmony_ci		goto exit;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	switch (pdata->pid) {
3148c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H:
3158c2ecf20Sopenharmony_ci		reg = RS485;
3168c2ecf20Sopenharmony_ci		break;
3178c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
3188c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
3198c2ecf20Sopenharmony_ci		reg = F81866_UART_CLK;
3208c2ecf20Sopenharmony_ci		break;
3218c2ecf20Sopenharmony_ci	default:
3228c2ecf20Sopenharmony_ci		/* Don't change clocksource with unknown PID */
3238c2ecf20Sopenharmony_ci		dev_warn(port->dev,
3248c2ecf20Sopenharmony_ci			"%s: pid: %x Not support. use default set_termios.\n",
3258c2ecf20Sopenharmony_ci			__func__, pdata->pid);
3268c2ecf20Sopenharmony_ci		goto exit;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
3308c2ecf20Sopenharmony_ci		if (baud > baudrate_table[i] || baudrate_table[i] % baud != 0)
3318c2ecf20Sopenharmony_ci			continue;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		if (port->uartclk == baudrate_table[i] * 16)
3348c2ecf20Sopenharmony_ci			break;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci		if (fintek_8250_enter_key(pdata->base_port, pdata->key))
3378c2ecf20Sopenharmony_ci			continue;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		port->uartclk = baudrate_table[i] * 16;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		sio_write_reg(pdata, LDN, pdata->index);
3428c2ecf20Sopenharmony_ci		sio_write_mask_reg(pdata, reg, F81866_UART_CLK_MASK,
3438c2ecf20Sopenharmony_ci				clock_table[i]);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci		fintek_8250_exit_key(pdata->base_port);
3468c2ecf20Sopenharmony_ci		break;
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	if (i == ARRAY_SIZE(baudrate_table)) {
3508c2ecf20Sopenharmony_ci		baud = tty_termios_baud_rate(old);
3518c2ecf20Sopenharmony_ci		tty_termios_encode_baud_rate(termios, baud, baud);
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ciexit:
3558c2ecf20Sopenharmony_ci	serial8250_do_set_termios(port, termios, old);
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic void fintek_8250_set_termios_handler(struct uart_8250_port *uart)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct fintek_8250 *pdata = uart->port.private_data;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	switch (pdata->pid) {
3638c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H:
3648c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
3658c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
3668c2ecf20Sopenharmony_ci		uart->port.set_termios = fintek_8250_set_termios;
3678c2ecf20Sopenharmony_ci		break;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	default:
3708c2ecf20Sopenharmony_ci		break;
3718c2ecf20Sopenharmony_ci	}
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic int probe_setup_port(struct fintek_8250 *pdata,
3758c2ecf20Sopenharmony_ci					struct uart_8250_port *uart)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	static const u16 addr[] = {0x4e, 0x2e};
3788c2ecf20Sopenharmony_ci	static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
3798c2ecf20Sopenharmony_ci	struct irq_data *irq_data;
3808c2ecf20Sopenharmony_ci	bool level_mode = false;
3818c2ecf20Sopenharmony_ci	int i, j, k, min, max;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(addr); i++) {
3848c2ecf20Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(keys); j++) {
3858c2ecf20Sopenharmony_ci			pdata->base_port = addr[i];
3868c2ecf20Sopenharmony_ci			pdata->key = keys[j];
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci			if (fintek_8250_enter_key(addr[i], keys[j]))
3898c2ecf20Sopenharmony_ci				continue;
3908c2ecf20Sopenharmony_ci			if (fintek_8250_check_id(pdata) ||
3918c2ecf20Sopenharmony_ci			    fintek_8250_get_ldn_range(pdata, &min, &max)) {
3928c2ecf20Sopenharmony_ci				fintek_8250_exit_key(addr[i]);
3938c2ecf20Sopenharmony_ci				continue;
3948c2ecf20Sopenharmony_ci			}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci			for (k = min; k < max; k++) {
3978c2ecf20Sopenharmony_ci				u16 aux;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci				sio_write_reg(pdata, LDN, k);
4008c2ecf20Sopenharmony_ci				aux = sio_read_reg(pdata, IO_ADDR1);
4018c2ecf20Sopenharmony_ci				aux |= sio_read_reg(pdata, IO_ADDR2) << 8;
4028c2ecf20Sopenharmony_ci				if (aux != uart->port.iobase)
4038c2ecf20Sopenharmony_ci					continue;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci				pdata->index = k;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci				irq_data = irq_get_irq_data(uart->port.irq);
4088c2ecf20Sopenharmony_ci				if (irq_data)
4098c2ecf20Sopenharmony_ci					level_mode =
4108c2ecf20Sopenharmony_ci						irqd_is_level_type(irq_data);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci				fintek_8250_set_irq_mode(pdata, level_mode);
4138c2ecf20Sopenharmony_ci				fintek_8250_set_max_fifo(pdata);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci				fintek_8250_exit_key(addr[i]);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci				return 0;
4188c2ecf20Sopenharmony_ci			}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci			fintek_8250_exit_key(addr[i]);
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	return -ENODEV;
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	struct fintek_8250 *pdata = uart->port.private_data;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	switch (pdata->pid) {
4328c2ecf20Sopenharmony_ci	case CHIP_ID_F81216AD:
4338c2ecf20Sopenharmony_ci	case CHIP_ID_F81216H:
4348c2ecf20Sopenharmony_ci	case CHIP_ID_F81966:
4358c2ecf20Sopenharmony_ci	case CHIP_ID_F81866:
4368c2ecf20Sopenharmony_ci	case CHIP_ID_F81865:
4378c2ecf20Sopenharmony_ci		uart->port.rs485_config = fintek_8250_rs485_config;
4388c2ecf20Sopenharmony_ci		break;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	default: /* No RS485 Auto direction functional */
4418c2ecf20Sopenharmony_ci		break;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ciint fintek_8250_probe(struct uart_8250_port *uart)
4468c2ecf20Sopenharmony_ci{
4478c2ecf20Sopenharmony_ci	struct fintek_8250 *pdata;
4488c2ecf20Sopenharmony_ci	struct fintek_8250 probe_data;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (probe_setup_port(&probe_data, uart))
4518c2ecf20Sopenharmony_ci		return -ENODEV;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
4548c2ecf20Sopenharmony_ci	if (!pdata)
4558c2ecf20Sopenharmony_ci		return -ENOMEM;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	memcpy(pdata, &probe_data, sizeof(probe_data));
4588c2ecf20Sopenharmony_ci	uart->port.private_data = pdata;
4598c2ecf20Sopenharmony_ci	fintek_8250_set_rs485_handler(uart);
4608c2ecf20Sopenharmony_ci	fintek_8250_set_termios_handler(uart);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return 0;
4638c2ecf20Sopenharmony_ci}
464