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