1
0
Fork 0

8250-men-mcb: add support for 16z025 and 16z057

Add support for two MEN UARTs (16z025 and 16z057) to the
8250_men_mcb driver.
The 16z025 consists of up to four ports, the 16z057 has
exactly four ports. Apart from that, all of them share the
Port settings.

Signed-off-by: Michael Moese <mmoese@suse.de>
Reported-by: Ben Turner <ben.turner@21net.com>
Tested-by: Ben Turner <ben.turner@21net.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
hifive-unleashed-5.1
Michael Moese 2018-03-05 16:24:21 +01:00 committed by Greg Kroah-Hartman
parent 219c7b06f3
commit e2fea54e45
2 changed files with 93 additions and 35 deletions

View File

@ -1,12 +1,19 @@
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/io.h>
#include <linux/mcb.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_8250.h>
#include <uapi/linux/serial_core.h>
#define MEN_UART_ID_Z025 0x19
#define MEN_UART_ID_Z057 0x39
#define MEN_UART_ID_Z125 0x7d
#define MEN_UART_MEM_SIZE 0x10
struct serial_8250_men_mcb_data {
struct uart_8250_port uart;
int line;
@ -18,7 +25,7 @@ struct serial_8250_men_mcb_data {
* parameter in order to really set the correct baudrate, and
* do so if possible without user interaction
*/
static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
static u32 men_lookup_uartclk(struct mcb_device *mdev)
{
/* use default value if board is not available below */
u32 clkval = 1041666;
@ -28,10 +35,12 @@ static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
mdev->bus->name);
if (strncmp(mdev->bus->name, "F075", 4) == 0)
clkval = 1041666;
else if (strncmp(mdev->bus->name, "F216", 4) == 0)
else if (strncmp(mdev->bus->name, "F216", 4) == 0)
clkval = 1843200;
else if (strncmp(mdev->bus->name, "G215", 4) == 0)
clkval = 1843200;
else if (strncmp(mdev->bus->name, "F210", 4) == 0)
clkval = 115200;
else
dev_info(&mdev->dev,
"board not detected, using default uartclk\n");
@ -41,62 +50,108 @@ static u32 men_z125_lookup_uartclk(struct mcb_device *mdev)
return clkval;
}
static unsigned int get_num_ports(struct mcb_device *mdev,
void __iomem *membase)
{
switch (mdev->id) {
case MEN_UART_ID_Z125:
return 1U;
case MEN_UART_ID_Z025:
return readb(membase) >> 4;
case MEN_UART_ID_Z057:
return 4U;
default:
dev_err(&mdev->dev, "no supported device!\n");
return -ENODEV;
}
}
static int serial_8250_men_mcb_probe(struct mcb_device *mdev,
const struct mcb_device_id *id)
{
struct serial_8250_men_mcb_data *data;
struct resource *mem;
unsigned int num_ports;
unsigned int i;
void __iomem *membase;
data = devm_kzalloc(&mdev->dev,
mem = mcb_get_resource(mdev, IORESOURCE_MEM);
if (mem == NULL)
return -ENXIO;
membase = devm_ioremap_resource(&mdev->dev, mem);
if (IS_ERR(membase))
return PTR_ERR_OR_ZERO(membase);
num_ports = get_num_ports(mdev, membase);
dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n",
mdev->id, num_ports);
if (num_ports == 0 || num_ports > 4) {
dev_err(&mdev->dev, "unexpected number of ports: %u\n",
num_ports);
return -ENODEV;
}
data = devm_kcalloc(&mdev->dev, num_ports,
sizeof(struct serial_8250_men_mcb_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
mcb_set_drvdata(mdev, data);
data->uart.port.dev = mdev->dma_dev;
spin_lock_init(&data->uart.port.lock);
data->uart.port.type = PORT_16550;
data->uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
data->uart.port.iotype = UPIO_MEM;
data->uart.port.uartclk = men_z125_lookup_uartclk(mdev);
data->uart.port.regshift = 0;
data->uart.port.fifosize = 60;
for (i = 0; i < num_ports; i++) {
data[i].uart.port.dev = mdev->dma_dev;
spin_lock_init(&data[i].uart.port.lock);
mem = mcb_get_resource(mdev, IORESOURCE_MEM);
if (mem == NULL)
return -ENXIO;
data[i].uart.port.type = PORT_16550;
data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ
| UPF_FIXED_TYPE;
data[i].uart.port.iotype = UPIO_MEM;
data[i].uart.port.uartclk = men_lookup_uartclk(mdev);
data[i].uart.port.regshift = 0;
data[i].uart.port.irq = mcb_get_irq(mdev);
data[i].uart.port.membase = membase;
data[i].uart.port.fifosize = 60;
data[i].uart.port.mapbase = (unsigned long) mem->start
+ i * MEN_UART_MEM_SIZE;
data[i].uart.port.iobase = data[i].uart.port.mapbase;
data->uart.port.irq = mcb_get_irq(mdev);
data->uart.port.membase = devm_ioremap_resource(&mdev->dev, mem);
if (IS_ERR(data->uart.port.membase))
return PTR_ERR_OR_ZERO(data->uart.port.membase);
data->uart.port.mapbase = (unsigned long) mem->start;
data->uart.port.iobase = data->uart.port.mapbase;
/* ok, register the port */
data->line = serial8250_register_8250_port(&data->uart);
if (data->line < 0)
return data->line;
dev_info(&mdev->dev, "found 16Z125 UART: ttyS%d\n", data->line);
/* ok, register the port */
data[i].line = serial8250_register_8250_port(&data[i].uart);
if (data[i].line < 0) {
dev_err(&mdev->dev, "unable to register UART port\n");
return data[i].line;
}
dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line);
}
return 0;
}
static void serial_8250_men_mcb_remove(struct mcb_device *mdev)
{
unsigned int num_ports, i;
struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev);
if (data)
serial8250_unregister_port(data->line);
if (!data)
return;
num_ports = get_num_ports(mdev, data[0].uart.port.membase);
if (num_ports < 0 || num_ports > 4) {
dev_err(&mdev->dev, "error retrieving number of ports!\n");
return;
}
for (i = 0; i < num_ports; i++)
serial8250_unregister_port(data[i].line);
}
static const struct mcb_device_id serial_8250_men_mcb_ids[] = {
{ .device = 0x7d },
{ .device = MEN_UART_ID_Z025 },
{ .device = MEN_UART_ID_Z057 },
{ .device = MEN_UART_ID_Z125 },
{ }
};
MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids);
@ -113,6 +168,8 @@ static struct mcb_driver mcb_driver = {
module_mcb_driver(mcb_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MEN 16z125 8250 UART driver");
MODULE_DESCRIPTION("MEN 8250 UART driver");
MODULE_AUTHOR("Michael Moese <michael.moese@men.de");
MODULE_ALIAS("mcb:16z125");
MODULE_ALIAS("mcb:16z025");
MODULE_ALIAS("mcb:16z057");

View File

@ -157,11 +157,12 @@ config SERIAL_8250_CS
If unsure, say N.
config SERIAL_8250_MEN_MCB
tristate "MEN Z125 UART device support"
tristate "MEN MCB UART device support"
depends on MCB && SERIAL_8250
help
This enables support for FPGA based UARTs found on many MEN
boards. This driver enables support for the Z125 UARTs.
boards. This driver enables support for the 16z025, 16z057
and 16z125 UARTs.
To compile this driver as a module, chose M here: the
module will be called 8250_men_mcb.