162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Probe for F81216A LPC to 4 UART
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci#include <linux/module.h>
862306a36Sopenharmony_ci#include <linux/pci.h>
962306a36Sopenharmony_ci#include <linux/pnp.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/serial_core.h>
1262306a36Sopenharmony_ci#include <linux/irq.h>
1362306a36Sopenharmony_ci#include  "8250.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define ADDR_PORT 0
1662306a36Sopenharmony_ci#define DATA_PORT 1
1762306a36Sopenharmony_ci#define EXIT_KEY 0xAA
1862306a36Sopenharmony_ci#define CHIP_ID1  0x20
1962306a36Sopenharmony_ci#define CHIP_ID2  0x21
2062306a36Sopenharmony_ci#define CHIP_ID_F81865 0x0407
2162306a36Sopenharmony_ci#define CHIP_ID_F81866 0x1010
2262306a36Sopenharmony_ci#define CHIP_ID_F81966 0x0215
2362306a36Sopenharmony_ci#define CHIP_ID_F81216AD 0x1602
2462306a36Sopenharmony_ci#define CHIP_ID_F81216H 0x0501
2562306a36Sopenharmony_ci#define CHIP_ID_F81216 0x0802
2662306a36Sopenharmony_ci#define VENDOR_ID1 0x23
2762306a36Sopenharmony_ci#define VENDOR_ID1_VAL 0x19
2862306a36Sopenharmony_ci#define VENDOR_ID2 0x24
2962306a36Sopenharmony_ci#define VENDOR_ID2_VAL 0x34
3062306a36Sopenharmony_ci#define IO_ADDR1 0x61
3162306a36Sopenharmony_ci#define IO_ADDR2 0x60
3262306a36Sopenharmony_ci#define LDN 0x7
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#define FINTEK_IRQ_MODE	0x70
3562306a36Sopenharmony_ci#define IRQ_SHARE	BIT(4)
3662306a36Sopenharmony_ci#define IRQ_MODE_MASK	(BIT(6) | BIT(5))
3762306a36Sopenharmony_ci#define IRQ_LEVEL_LOW	0
3862306a36Sopenharmony_ci#define IRQ_EDGE_HIGH	BIT(5)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * F81216H clock source register, the value and mask is the same with F81866,
4262306a36Sopenharmony_ci * but it's on F0h.
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * Clock speeds for UART (register F0h)
4562306a36Sopenharmony_ci * 00: 1.8432MHz.
4662306a36Sopenharmony_ci * 01: 18.432MHz.
4762306a36Sopenharmony_ci * 10: 24MHz.
4862306a36Sopenharmony_ci * 11: 14.769MHz.
4962306a36Sopenharmony_ci */
5062306a36Sopenharmony_ci#define RS485  0xF0
5162306a36Sopenharmony_ci#define RTS_INVERT BIT(5)
5262306a36Sopenharmony_ci#define RS485_URA BIT(4)
5362306a36Sopenharmony_ci#define RXW4C_IRA BIT(3)
5462306a36Sopenharmony_ci#define TXW4C_IRA BIT(2)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define FIFO_CTRL		0xF6
5762306a36Sopenharmony_ci#define FIFO_MODE_MASK		(BIT(1) | BIT(0))
5862306a36Sopenharmony_ci#define FIFO_MODE_128		(BIT(1) | BIT(0))
5962306a36Sopenharmony_ci#define RXFTHR_MODE_MASK	(BIT(5) | BIT(4))
6062306a36Sopenharmony_ci#define RXFTHR_MODE_4X		BIT(5)
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define F81216_LDN_LOW	0x0
6362306a36Sopenharmony_ci#define F81216_LDN_HIGH	0x4
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * F81866/966 registers
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * The IRQ setting mode of F81866/966 is not the same with F81216 series.
6962306a36Sopenharmony_ci *	Level/Low: IRQ_MODE0:0, IRQ_MODE1:0
7062306a36Sopenharmony_ci *	Edge/High: IRQ_MODE0:1, IRQ_MODE1:0
7162306a36Sopenharmony_ci *
7262306a36Sopenharmony_ci * Clock speeds for UART (register F2h)
7362306a36Sopenharmony_ci * 00: 1.8432MHz.
7462306a36Sopenharmony_ci * 01: 18.432MHz.
7562306a36Sopenharmony_ci * 10: 24MHz.
7662306a36Sopenharmony_ci * 11: 14.769MHz.
7762306a36Sopenharmony_ci */
7862306a36Sopenharmony_ci#define F81866_IRQ_MODE		0xf0
7962306a36Sopenharmony_ci#define F81866_IRQ_SHARE	BIT(0)
8062306a36Sopenharmony_ci#define F81866_IRQ_MODE0	BIT(1)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci#define F81866_FIFO_CTRL	FIFO_CTRL
8362306a36Sopenharmony_ci#define F81866_IRQ_MODE1	BIT(3)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define F81866_LDN_LOW		0x10
8662306a36Sopenharmony_ci#define F81866_LDN_HIGH		0x16
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci#define F81866_UART_CLK 0xF2
8962306a36Sopenharmony_ci#define F81866_UART_CLK_MASK (BIT(1) | BIT(0))
9062306a36Sopenharmony_ci#define F81866_UART_CLK_1_8432MHZ 0
9162306a36Sopenharmony_ci#define F81866_UART_CLK_14_769MHZ (BIT(1) | BIT(0))
9262306a36Sopenharmony_ci#define F81866_UART_CLK_18_432MHZ BIT(0)
9362306a36Sopenharmony_ci#define F81866_UART_CLK_24MHZ BIT(1)
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistruct fintek_8250 {
9662306a36Sopenharmony_ci	u16 pid;
9762306a36Sopenharmony_ci	u16 base_port;
9862306a36Sopenharmony_ci	u8 index;
9962306a36Sopenharmony_ci	u8 key;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic u8 sio_read_reg(struct fintek_8250 *pdata, u8 reg)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	outb(reg, pdata->base_port + ADDR_PORT);
10562306a36Sopenharmony_ci	return inb(pdata->base_port + DATA_PORT);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic void sio_write_reg(struct fintek_8250 *pdata, u8 reg, u8 data)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	outb(reg, pdata->base_port + ADDR_PORT);
11162306a36Sopenharmony_ci	outb(data, pdata->base_port + DATA_PORT);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic void sio_write_mask_reg(struct fintek_8250 *pdata, u8 reg, u8 mask,
11562306a36Sopenharmony_ci			       u8 data)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	u8 tmp;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	tmp = (sio_read_reg(pdata, reg) & ~mask) | (mask & data);
12062306a36Sopenharmony_ci	sio_write_reg(pdata, reg, tmp);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int fintek_8250_enter_key(u16 base_port, u8 key)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	if (!request_muxed_region(base_port, 2, "8250_fintek"))
12662306a36Sopenharmony_ci		return -EBUSY;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* Force to deactive all SuperIO in this base_port */
12962306a36Sopenharmony_ci	outb(EXIT_KEY, base_port + ADDR_PORT);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	outb(key, base_port + ADDR_PORT);
13262306a36Sopenharmony_ci	outb(key, base_port + ADDR_PORT);
13362306a36Sopenharmony_ci	return 0;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void fintek_8250_exit_key(u16 base_port)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	outb(EXIT_KEY, base_port + ADDR_PORT);
14062306a36Sopenharmony_ci	release_region(base_port + ADDR_PORT, 2);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic int fintek_8250_check_id(struct fintek_8250 *pdata)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	u16 chip;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (sio_read_reg(pdata, VENDOR_ID1) != VENDOR_ID1_VAL)
14862306a36Sopenharmony_ci		return -ENODEV;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (sio_read_reg(pdata, VENDOR_ID2) != VENDOR_ID2_VAL)
15162306a36Sopenharmony_ci		return -ENODEV;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	chip = sio_read_reg(pdata, CHIP_ID1);
15462306a36Sopenharmony_ci	chip |= sio_read_reg(pdata, CHIP_ID2) << 8;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	switch (chip) {
15762306a36Sopenharmony_ci	case CHIP_ID_F81865:
15862306a36Sopenharmony_ci	case CHIP_ID_F81866:
15962306a36Sopenharmony_ci	case CHIP_ID_F81966:
16062306a36Sopenharmony_ci	case CHIP_ID_F81216AD:
16162306a36Sopenharmony_ci	case CHIP_ID_F81216H:
16262306a36Sopenharmony_ci	case CHIP_ID_F81216:
16362306a36Sopenharmony_ci		break;
16462306a36Sopenharmony_ci	default:
16562306a36Sopenharmony_ci		return -ENODEV;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	pdata->pid = chip;
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic int fintek_8250_get_ldn_range(struct fintek_8250 *pdata, int *min,
17362306a36Sopenharmony_ci				     int *max)
17462306a36Sopenharmony_ci{
17562306a36Sopenharmony_ci	switch (pdata->pid) {
17662306a36Sopenharmony_ci	case CHIP_ID_F81966:
17762306a36Sopenharmony_ci	case CHIP_ID_F81865:
17862306a36Sopenharmony_ci	case CHIP_ID_F81866:
17962306a36Sopenharmony_ci		*min = F81866_LDN_LOW;
18062306a36Sopenharmony_ci		*max = F81866_LDN_HIGH;
18162306a36Sopenharmony_ci		return 0;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	case CHIP_ID_F81216AD:
18462306a36Sopenharmony_ci	case CHIP_ID_F81216H:
18562306a36Sopenharmony_ci	case CHIP_ID_F81216:
18662306a36Sopenharmony_ci		*min = F81216_LDN_LOW;
18762306a36Sopenharmony_ci		*max = F81216_LDN_HIGH;
18862306a36Sopenharmony_ci		return 0;
18962306a36Sopenharmony_ci	}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	return -ENODEV;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic int fintek_8250_rs485_config(struct uart_port *port, struct ktermios *termios,
19562306a36Sopenharmony_ci			      struct serial_rs485 *rs485)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	uint8_t config = 0;
19862306a36Sopenharmony_ci	struct fintek_8250 *pdata = port->private_data;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	if (!pdata)
20162306a36Sopenharmony_ci		return -EINVAL;
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (rs485->flags & SER_RS485_ENABLED) {
20562306a36Sopenharmony_ci		/* Hardware do not support same RTS level on send and receive */
20662306a36Sopenharmony_ci		if (!(rs485->flags & SER_RS485_RTS_ON_SEND) ==
20762306a36Sopenharmony_ci		    !(rs485->flags & SER_RS485_RTS_AFTER_SEND))
20862306a36Sopenharmony_ci			return -EINVAL;
20962306a36Sopenharmony_ci		config |= RS485_URA;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (rs485->delay_rts_before_send) {
21362306a36Sopenharmony_ci		rs485->delay_rts_before_send = 1;
21462306a36Sopenharmony_ci		config |= TXW4C_IRA;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (rs485->delay_rts_after_send) {
21862306a36Sopenharmony_ci		rs485->delay_rts_after_send = 1;
21962306a36Sopenharmony_ci		config |= RXW4C_IRA;
22062306a36Sopenharmony_ci	}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	if (rs485->flags & SER_RS485_RTS_ON_SEND)
22362306a36Sopenharmony_ci		config |= RTS_INVERT;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (fintek_8250_enter_key(pdata->base_port, pdata->key))
22662306a36Sopenharmony_ci		return -EBUSY;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	sio_write_reg(pdata, LDN, pdata->index);
22962306a36Sopenharmony_ci	sio_write_reg(pdata, RS485, config);
23062306a36Sopenharmony_ci	fintek_8250_exit_key(pdata->base_port);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return 0;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic void fintek_8250_set_irq_mode(struct fintek_8250 *pdata, bool is_level)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	sio_write_reg(pdata, LDN, pdata->index);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	switch (pdata->pid) {
24062306a36Sopenharmony_ci	case CHIP_ID_F81966:
24162306a36Sopenharmony_ci	case CHIP_ID_F81866:
24262306a36Sopenharmony_ci		sio_write_mask_reg(pdata, F81866_FIFO_CTRL, F81866_IRQ_MODE1,
24362306a36Sopenharmony_ci				   0);
24462306a36Sopenharmony_ci		fallthrough;
24562306a36Sopenharmony_ci	case CHIP_ID_F81865:
24662306a36Sopenharmony_ci		sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_SHARE,
24762306a36Sopenharmony_ci				   F81866_IRQ_SHARE);
24862306a36Sopenharmony_ci		sio_write_mask_reg(pdata, F81866_IRQ_MODE, F81866_IRQ_MODE0,
24962306a36Sopenharmony_ci				   is_level ? 0 : F81866_IRQ_MODE0);
25062306a36Sopenharmony_ci		break;
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	case CHIP_ID_F81216AD:
25362306a36Sopenharmony_ci	case CHIP_ID_F81216H:
25462306a36Sopenharmony_ci	case CHIP_ID_F81216:
25562306a36Sopenharmony_ci		sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_SHARE,
25662306a36Sopenharmony_ci				   IRQ_SHARE);
25762306a36Sopenharmony_ci		sio_write_mask_reg(pdata, FINTEK_IRQ_MODE, IRQ_MODE_MASK,
25862306a36Sopenharmony_ci				   is_level ? IRQ_LEVEL_LOW : IRQ_EDGE_HIGH);
25962306a36Sopenharmony_ci		break;
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic void fintek_8250_set_max_fifo(struct fintek_8250 *pdata)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	switch (pdata->pid) {
26662306a36Sopenharmony_ci	case CHIP_ID_F81216H: /* 128Bytes FIFO */
26762306a36Sopenharmony_ci	case CHIP_ID_F81966:
26862306a36Sopenharmony_ci	case CHIP_ID_F81866:
26962306a36Sopenharmony_ci		sio_write_mask_reg(pdata, FIFO_CTRL,
27062306a36Sopenharmony_ci				   FIFO_MODE_MASK | RXFTHR_MODE_MASK,
27162306a36Sopenharmony_ci				   FIFO_MODE_128 | RXFTHR_MODE_4X);
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	default: /* Default 16Bytes FIFO */
27562306a36Sopenharmony_ci		break;
27662306a36Sopenharmony_ci	}
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void fintek_8250_set_termios(struct uart_port *port,
28062306a36Sopenharmony_ci				    struct ktermios *termios,
28162306a36Sopenharmony_ci				    const struct ktermios *old)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	struct fintek_8250 *pdata = port->private_data;
28462306a36Sopenharmony_ci	unsigned int baud = tty_termios_baud_rate(termios);
28562306a36Sopenharmony_ci	int i;
28662306a36Sopenharmony_ci	u8 reg;
28762306a36Sopenharmony_ci	static u32 baudrate_table[] = {115200, 921600, 1152000, 1500000};
28862306a36Sopenharmony_ci	static u8 clock_table[] = { F81866_UART_CLK_1_8432MHZ,
28962306a36Sopenharmony_ci			F81866_UART_CLK_14_769MHZ, F81866_UART_CLK_18_432MHZ,
29062306a36Sopenharmony_ci			F81866_UART_CLK_24MHZ };
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	/*
29362306a36Sopenharmony_ci	 * We'll use serial8250_do_set_termios() for baud = 0, otherwise It'll
29462306a36Sopenharmony_ci	 * crash on baudrate_table[i] % baud with "division by zero".
29562306a36Sopenharmony_ci	 */
29662306a36Sopenharmony_ci	if (!baud)
29762306a36Sopenharmony_ci		goto exit;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	switch (pdata->pid) {
30062306a36Sopenharmony_ci	case CHIP_ID_F81216H:
30162306a36Sopenharmony_ci		reg = RS485;
30262306a36Sopenharmony_ci		break;
30362306a36Sopenharmony_ci	case CHIP_ID_F81966:
30462306a36Sopenharmony_ci	case CHIP_ID_F81866:
30562306a36Sopenharmony_ci		reg = F81866_UART_CLK;
30662306a36Sopenharmony_ci		break;
30762306a36Sopenharmony_ci	default:
30862306a36Sopenharmony_ci		/* Don't change clocksource with unknown PID */
30962306a36Sopenharmony_ci		dev_warn(port->dev,
31062306a36Sopenharmony_ci			"%s: pid: %x Not support. use default set_termios.\n",
31162306a36Sopenharmony_ci			__func__, pdata->pid);
31262306a36Sopenharmony_ci		goto exit;
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) {
31662306a36Sopenharmony_ci		if (baud > baudrate_table[i] || baudrate_table[i] % baud != 0)
31762306a36Sopenharmony_ci			continue;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		if (port->uartclk == baudrate_table[i] * 16)
32062306a36Sopenharmony_ci			break;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		if (fintek_8250_enter_key(pdata->base_port, pdata->key))
32362306a36Sopenharmony_ci			continue;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		port->uartclk = baudrate_table[i] * 16;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci		sio_write_reg(pdata, LDN, pdata->index);
32862306a36Sopenharmony_ci		sio_write_mask_reg(pdata, reg, F81866_UART_CLK_MASK,
32962306a36Sopenharmony_ci				clock_table[i]);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		fintek_8250_exit_key(pdata->base_port);
33262306a36Sopenharmony_ci		break;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (i == ARRAY_SIZE(baudrate_table)) {
33662306a36Sopenharmony_ci		baud = tty_termios_baud_rate(old);
33762306a36Sopenharmony_ci		tty_termios_encode_baud_rate(termios, baud, baud);
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ciexit:
34162306a36Sopenharmony_ci	serial8250_do_set_termios(port, termios, old);
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cistatic void fintek_8250_set_termios_handler(struct uart_8250_port *uart)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	struct fintek_8250 *pdata = uart->port.private_data;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	switch (pdata->pid) {
34962306a36Sopenharmony_ci	case CHIP_ID_F81216H:
35062306a36Sopenharmony_ci	case CHIP_ID_F81966:
35162306a36Sopenharmony_ci	case CHIP_ID_F81866:
35262306a36Sopenharmony_ci		uart->port.set_termios = fintek_8250_set_termios;
35362306a36Sopenharmony_ci		break;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	default:
35662306a36Sopenharmony_ci		break;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_cistatic int probe_setup_port(struct fintek_8250 *pdata,
36162306a36Sopenharmony_ci					struct uart_8250_port *uart)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	static const u16 addr[] = {0x4e, 0x2e};
36462306a36Sopenharmony_ci	static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
36562306a36Sopenharmony_ci	struct irq_data *irq_data;
36662306a36Sopenharmony_ci	bool level_mode = false;
36762306a36Sopenharmony_ci	int i, j, k, min, max;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(addr); i++) {
37062306a36Sopenharmony_ci		for (j = 0; j < ARRAY_SIZE(keys); j++) {
37162306a36Sopenharmony_ci			pdata->base_port = addr[i];
37262306a36Sopenharmony_ci			pdata->key = keys[j];
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci			if (fintek_8250_enter_key(addr[i], keys[j]))
37562306a36Sopenharmony_ci				continue;
37662306a36Sopenharmony_ci			if (fintek_8250_check_id(pdata) ||
37762306a36Sopenharmony_ci			    fintek_8250_get_ldn_range(pdata, &min, &max)) {
37862306a36Sopenharmony_ci				fintek_8250_exit_key(addr[i]);
37962306a36Sopenharmony_ci				continue;
38062306a36Sopenharmony_ci			}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci			for (k = min; k < max; k++) {
38362306a36Sopenharmony_ci				u16 aux;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci				sio_write_reg(pdata, LDN, k);
38662306a36Sopenharmony_ci				aux = sio_read_reg(pdata, IO_ADDR1);
38762306a36Sopenharmony_ci				aux |= sio_read_reg(pdata, IO_ADDR2) << 8;
38862306a36Sopenharmony_ci				if (aux != uart->port.iobase)
38962306a36Sopenharmony_ci					continue;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci				pdata->index = k;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci				irq_data = irq_get_irq_data(uart->port.irq);
39462306a36Sopenharmony_ci				if (irq_data)
39562306a36Sopenharmony_ci					level_mode =
39662306a36Sopenharmony_ci						irqd_is_level_type(irq_data);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci				fintek_8250_set_irq_mode(pdata, level_mode);
39962306a36Sopenharmony_ci				fintek_8250_set_max_fifo(pdata);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci				fintek_8250_exit_key(addr[i]);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci				return 0;
40462306a36Sopenharmony_ci			}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci			fintek_8250_exit_key(addr[i]);
40762306a36Sopenharmony_ci		}
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	return -ENODEV;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/* Only the first port supports delays */
41462306a36Sopenharmony_cistatic const struct serial_rs485 fintek_8250_rs485_supported_port0 = {
41562306a36Sopenharmony_ci	.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
41662306a36Sopenharmony_ci	.delay_rts_before_send = 1,
41762306a36Sopenharmony_ci	.delay_rts_after_send = 1,
41862306a36Sopenharmony_ci};
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic const struct serial_rs485 fintek_8250_rs485_supported = {
42162306a36Sopenharmony_ci	.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND | SER_RS485_RTS_AFTER_SEND,
42262306a36Sopenharmony_ci};
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic void fintek_8250_set_rs485_handler(struct uart_8250_port *uart)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct fintek_8250 *pdata = uart->port.private_data;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	switch (pdata->pid) {
42962306a36Sopenharmony_ci	case CHIP_ID_F81216AD:
43062306a36Sopenharmony_ci	case CHIP_ID_F81216H:
43162306a36Sopenharmony_ci	case CHIP_ID_F81966:
43262306a36Sopenharmony_ci	case CHIP_ID_F81866:
43362306a36Sopenharmony_ci	case CHIP_ID_F81865:
43462306a36Sopenharmony_ci		uart->port.rs485_config = fintek_8250_rs485_config;
43562306a36Sopenharmony_ci		if (!pdata->index)
43662306a36Sopenharmony_ci			uart->port.rs485_supported = fintek_8250_rs485_supported_port0;
43762306a36Sopenharmony_ci		else
43862306a36Sopenharmony_ci			uart->port.rs485_supported = fintek_8250_rs485_supported;
43962306a36Sopenharmony_ci		break;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	default: /* No RS485 Auto direction functional */
44262306a36Sopenharmony_ci		break;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ciint fintek_8250_probe(struct uart_8250_port *uart)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct fintek_8250 *pdata;
44962306a36Sopenharmony_ci	struct fintek_8250 probe_data;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	if (probe_setup_port(&probe_data, uart))
45262306a36Sopenharmony_ci		return -ENODEV;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
45562306a36Sopenharmony_ci	if (!pdata)
45662306a36Sopenharmony_ci		return -ENOMEM;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	memcpy(pdata, &probe_data, sizeof(probe_data));
45962306a36Sopenharmony_ci	uart->port.private_data = pdata;
46062306a36Sopenharmony_ci	fintek_8250_set_rs485_handler(uart);
46162306a36Sopenharmony_ci	fintek_8250_set_termios_handler(uart);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	return 0;
46462306a36Sopenharmony_ci}
465