serial: 8250: Integrate Fintek into 8250_base

The 8250_fintek driver advertises as the PNP0501 driver; however this
conflicts with the standard 16550A uart PNP0501. The conflict causes
the 8250_fintek driver to load with _every_ PNP0501, but never probe,
and causing the entire 8250 driver stack to unload if the 8250_fintek
driver is unloaded (modprobe doesn't know that 8250_pnp rather than
8250_fintek claimed the resource).

This patch merges the Fintek driver into 8250_base. On autoconfig_16550
the device is probed to verify if it is a FINTEK device or not.

This custom probing can be disabled completely via configuration. When a
Fintek device is not probed it will behave as a standard 16550A device,
with no RS485 capabilities.

Reported-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Ricardo Ribalda Delgado 2016-04-27 10:40:10 +02:00 коммит произвёл Greg Kroah-Hartman
Родитель bd8d257fa3
Коммит fa01e2ca9f
5 изменённых файлов: 42 добавлений и 111 удалений

Просмотреть файл

@ -150,6 +150,12 @@ static inline int serial8250_pnp_init(void) { return 0; }
static inline void serial8250_pnp_exit(void) { } static inline void serial8250_pnp_exit(void) { }
#endif #endif
#ifdef CONFIG_SERIAL_8250_FINTEK
int fintek_8250_probe(struct uart_8250_port *uart);
#else
static inline int fintek_8250_probe(struct uart_8250_port *uart) { return 0; }
#endif
#ifdef CONFIG_ARCH_OMAP1 #ifdef CONFIG_ARCH_OMAP1
static inline int is_omap1_8250(struct uart_8250_port *pt) static inline int is_omap1_8250(struct uart_8250_port *pt)
{ {

Просмотреть файл

@ -1,9 +1,7 @@
/* /*
* Probe for F81216A LPC to 4 UART * Probe for F81216A LPC to 4 UART
* *
* Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al * Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S
*
* Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
* *
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -38,19 +36,15 @@
#define RXW4C_IRA BIT(3) #define RXW4C_IRA BIT(3)
#define TXW4C_IRA BIT(2) #define TXW4C_IRA BIT(2)
#define DRIVER_NAME "8250_fintek"
struct fintek_8250 { struct fintek_8250 {
u16 base_port; u16 base_port;
u8 index; u8 index;
u8 key; u8 key;
long line;
}; };
static int fintek_8250_enter_key(u16 base_port, u8 key) static int fintek_8250_enter_key(u16 base_port, u8 key)
{ {
if (!request_muxed_region(base_port, 2, "8250_fintek"))
if (!request_muxed_region(base_port, 2, DRIVER_NAME))
return -EBUSY; return -EBUSY;
outb(key, base_port + ADDR_PORT); outb(key, base_port + ADDR_PORT);
@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port,
return 0; return 0;
} }
static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) static int find_base_port(struct fintek_8250 *pdata, u16 io_address)
{ {
static const u16 addr[] = {0x4e, 0x2e}; static const u16 addr[] = {0x4e, 0x2e};
static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; static const u8 keys[] = {0x77, 0xa0, 0x87, 0x67};
@ -168,10 +162,13 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
continue; continue;
fintek_8250_exit_key(addr[i]); fintek_8250_exit_key(addr[i]);
*key = keys[j]; pdata->key = keys[j];
*index = k; pdata->base_port = addr[i];
return addr[i]; pdata->index = k;
return 0;
} }
fintek_8250_exit_key(addr[i]); fintek_8250_exit_key(addr[i]);
} }
} }
@ -179,104 +176,21 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index)
return -ENODEV; return -ENODEV;
} }
static int int fintek_8250_probe(struct uart_8250_port *uart)
fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{ {
struct uart_8250_port uart;
struct fintek_8250 *pdata; struct fintek_8250 *pdata;
int base_port; struct fintek_8250 probe_data;
u8 key;
u8 index;
if (!pnp_port_valid(dev, 0)) if (find_base_port(&probe_data, uart->port.iobase))
return -ENODEV; return -ENODEV;
base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index); pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL);
if (base_port < 0)
return -ENODEV;
memset(&uart, 0, sizeof(uart));
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return -ENOMEM; return -ENOMEM;
uart.port.private_data = pdata;
if (!pnp_irq_valid(dev, 0)) memcpy(pdata, &probe_data, sizeof(probe_data));
return -ENODEV; uart->port.rs485_config = fintek_8250_rs485_config;
uart.port.irq = pnp_irq(dev, 0); uart->port.private_data = pdata;
uart.port.iobase = pnp_port_start(dev, 0);
uart.port.iotype = UPIO_PORT;
uart.port.rs485_config = fintek_8250_rs485_config;
uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
uart.port.flags |= UPF_SHARE_IRQ;
uart.port.uartclk = 1843200;
uart.port.dev = &dev->dev;
pdata->key = key;
pdata->base_port = base_port;
pdata->index = index;
pdata->line = serial8250_register_8250_port(&uart);
if (pdata->line < 0)
return -ENODEV;
pnp_set_drvdata(dev, pdata);
return 0; return 0;
} }
static void fintek_8250_remove(struct pnp_dev *dev)
{
struct fintek_8250 *pdata = pnp_get_drvdata(dev);
if (pdata)
serial8250_unregister_port(pdata->line);
}
#ifdef CONFIG_PM
static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
{
struct fintek_8250 *pdata = pnp_get_drvdata(dev);
if (!pdata)
return -ENODEV;
serial8250_suspend_port(pdata->line);
return 0;
}
static int fintek_8250_resume(struct pnp_dev *dev)
{
struct fintek_8250 *pdata = pnp_get_drvdata(dev);
if (!pdata)
return -ENODEV;
serial8250_resume_port(pdata->line);
return 0;
}
#else
#define fintek_8250_suspend NULL
#define fintek_8250_resume NULL
#endif /* CONFIG_PM */
static const struct pnp_device_id fintek_dev_table[] = {
/* Qtechnology Panel PC / IO1000 */
{ "PNP0501"},
{}
};
MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
static struct pnp_driver fintek_8250_driver = {
.name = DRIVER_NAME,
.probe = fintek_8250_probe,
.remove = fintek_8250_remove,
.suspend = fintek_8250_suspend,
.resume = fintek_8250_resume,
.id_table = fintek_dev_table,
};
module_pnp_driver(fintek_8250_driver);
MODULE_DESCRIPTION("Fintek F812164 module");
MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
MODULE_LICENSE("GPL");

Просмотреть файл

@ -1315,6 +1315,13 @@ static void autoconfig(struct uart_8250_port *up)
out_lock: out_lock:
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);
/*
* Check if the device is a Fintek F81216A
*/
if (port->type == PORT_16550A)
fintek_8250_probe(up);
if (up->capabilities != old_capabilities) { if (up->capabilities != old_capabilities) {
pr_warn("ttyS%d: detected caps %08x should be %08x\n", pr_warn("ttyS%d: detected caps %08x should be %08x\n",
serial_index(port), old_capabilities, serial_index(port), old_capabilities,

Просмотреть файл

@ -57,6 +57,18 @@ config SERIAL_8250_PNP
This builds standard PNP serial support. You may be able to This builds standard PNP serial support. You may be able to
disable this feature if you only need legacy serial support. disable this feature if you only need legacy serial support.
config SERIAL_8250_FINTEK
bool "Support for Fintek F81216A LPC to 4 UART RS485 API"
depends on SERIAL_8250
---help---
Selecting this option will add support for the RS485 capabilities
of the Fintek F81216A LPC to 4 UART.
If this option is not selected the device will be configured as a
standard 16550A serial port.
If unsure, say N.
config SERIAL_8250_CONSOLE config SERIAL_8250_CONSOLE
bool "Console on 8250/16550 and compatible serial port" bool "Console on 8250/16550 and compatible serial port"
depends on SERIAL_8250=y depends on SERIAL_8250=y
@ -358,14 +370,6 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
not booting kernel because the serial console remains silent in case not booting kernel because the serial console remains silent in case
they forgot to update the command line. they forgot to update the command line.
config SERIAL_8250_FINTEK
tristate "Support for Fintek F81216A LPC to 4 UART"
depends on SERIAL_8250 && PNP
help
Selecting this option will add support for the Fintek F81216A
LPC to 4 UART. This device has some RS485 functionality not available
through the PNP driver. If unsure, say N.
config SERIAL_8250_LPC18XX config SERIAL_8250_LPC18XX
tristate "NXP LPC18xx/43xx serial port support" tristate "NXP LPC18xx/43xx serial port support"
depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST) depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)

Просмотреть файл

@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o 8250_base.o
8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o 8250-$(CONFIG_SERIAL_8250_PNP) += 8250_pnp.o
8250_base-y := 8250_port.o 8250_base-y := 8250_port.o
8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o 8250_base-$(CONFIG_SERIAL_8250_DMA) += 8250_dma.o
8250_base-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o obj-$(CONFIG_SERIAL_8250_GSC) += 8250_gsc.o
obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o obj-$(CONFIG_SERIAL_8250_PCI) += 8250_pci.o
obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o obj-$(CONFIG_SERIAL_8250_HP300) += 8250_hp300.o
@ -23,7 +24,6 @@ obj-$(CONFIG_SERIAL_8250_FSL) += 8250_fsl.o
obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o obj-$(CONFIG_SERIAL_8250_DW) += 8250_dw.o
obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o obj-$(CONFIG_SERIAL_8250_EM) += 8250_em.o
obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o
obj-$(CONFIG_SERIAL_8250_FINTEK) += 8250_fintek.o
obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o obj-$(CONFIG_SERIAL_8250_LPC18XX) += 8250_lpc18xx.o
obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o