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