forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <[email protected]> Signed-off-by: Ricardo Ribalda Delgado <[email protected]> Reviewed-by: Peter Hurley <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
- Loading branch information
Showing
5 changed files
with
42 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,7 @@ | ||
/* | ||
* Probe for F81216A LPC to 4 UART | ||
* | ||
* Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al | ||
* | ||
* Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S | ||
* Copyright (C) 2014-2016 Ricardo Ribalda, Qtechnology A/S | ||
* | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
|
@@ -38,19 +36,15 @@ | |
#define RXW4C_IRA BIT(3) | ||
#define TXW4C_IRA BIT(2) | ||
|
||
#define DRIVER_NAME "8250_fintek" | ||
|
||
struct fintek_8250 { | ||
u16 base_port; | ||
u8 index; | ||
u8 key; | ||
long line; | ||
}; | ||
|
||
static int fintek_8250_enter_key(u16 base_port, u8 key) | ||
{ | ||
|
||
if (!request_muxed_region(base_port, 2, DRIVER_NAME)) | ||
if (!request_muxed_region(base_port, 2, "8250_fintek")) | ||
return -EBUSY; | ||
|
||
outb(key, base_port + ADDR_PORT); | ||
|
@@ -138,7 +132,7 @@ static int fintek_8250_rs485_config(struct uart_port *port, | |
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 u8 keys[] = {0x77, 0xa0, 0x87, 0x67}; | ||
|
@@ -168,115 +162,35 @@ static int fintek_8250_base_port(u16 io_address, u8 *key, u8 *index) | |
continue; | ||
|
||
fintek_8250_exit_key(addr[i]); | ||
*key = keys[j]; | ||
*index = k; | ||
return addr[i]; | ||
pdata->key = keys[j]; | ||
pdata->base_port = addr[i]; | ||
pdata->index = k; | ||
|
||
return 0; | ||
} | ||
|
||
fintek_8250_exit_key(addr[i]); | ||
} | ||
} | ||
|
||
return -ENODEV; | ||
} | ||
|
||
static int | ||
fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) | ||
int fintek_8250_probe(struct uart_8250_port *uart) | ||
{ | ||
struct uart_8250_port uart; | ||
struct fintek_8250 *pdata; | ||
int base_port; | ||
u8 key; | ||
u8 index; | ||
|
||
if (!pnp_port_valid(dev, 0)) | ||
return -ENODEV; | ||
struct fintek_8250 probe_data; | ||
|
||
base_port = fintek_8250_base_port(pnp_port_start(dev, 0), &key, &index); | ||
if (base_port < 0) | ||
if (find_base_port(&probe_data, uart->port.iobase)) | ||
return -ENODEV; | ||
|
||
memset(&uart, 0, sizeof(uart)); | ||
|
||
pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); | ||
pdata = devm_kzalloc(uart->port.dev, sizeof(*pdata), GFP_KERNEL); | ||
if (!pdata) | ||
return -ENOMEM; | ||
uart.port.private_data = pdata; | ||
|
||
if (!pnp_irq_valid(dev, 0)) | ||
return -ENODEV; | ||
uart.port.irq = pnp_irq(dev, 0); | ||
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; | ||
memcpy(pdata, &probe_data, sizeof(probe_data)); | ||
uart->port.rs485_config = fintek_8250_rs485_config; | ||
uart->port.private_data = pdata; | ||
|
||
pnp_set_drvdata(dev, pdata); | ||
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 <[email protected]>"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters