Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fbb18a27 authored by Russell King's avatar Russell King Committed by Russell King
Browse files

[SERIAL] amba-pl010: allow platforms to specify modem control method



The amba-pl010 hardware does not provide RTS and DTR control lines; it
is expected that these will be implemented using GPIO.  Allow platforms
to supply a function to implement manipulation of modem control lines.

Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 335bd9df
Loading
Loading
Loading
Loading
+46 −0
Original line number Original line Diff line number Diff line
@@ -15,7 +15,9 @@
#include <linux/interrupt.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp.h>
#include <linux/termios.h>
#include <linux/amba/bus.h>
#include <linux/amba/bus.h>
#include <linux/amba/serial.h>


#include <asm/hardware.h>
#include <asm/hardware.h>
#include <asm/irq.h>
#include <asm/irq.h>
@@ -28,6 +30,8 @@


#include "common.h"
#include "common.h"


static struct amba_pl010_data integrator_uart_data;

static struct amba_device rtc_device = {
static struct amba_device rtc_device = {
	.dev		= {
	.dev		= {
		.bus_id	= "mb:15",
		.bus_id	= "mb:15",
@@ -44,6 +48,7 @@ static struct amba_device rtc_device = {
static struct amba_device uart0_device = {
static struct amba_device uart0_device = {
	.dev		= {
	.dev		= {
		.bus_id	= "mb:16",
		.bus_id	= "mb:16",
		.platform_data = &integrator_uart_data,
	},
	},
	.res		= {
	.res		= {
		.start	= INTEGRATOR_UART0_BASE,
		.start	= INTEGRATOR_UART0_BASE,
@@ -57,6 +62,7 @@ static struct amba_device uart0_device = {
static struct amba_device uart1_device = {
static struct amba_device uart1_device = {
	.dev		= {
	.dev		= {
		.bus_id	= "mb:17",
		.bus_id	= "mb:17",
		.platform_data = &integrator_uart_data,
	},
	},
	.res		= {
	.res		= {
		.start	= INTEGRATOR_UART1_BASE,
		.start	= INTEGRATOR_UART1_BASE,
@@ -115,6 +121,46 @@ static int __init integrator_init(void)


arch_initcall(integrator_init);
arch_initcall(integrator_init);


/*
 * On the Integrator platform, the port RTS and DTR are provided by
 * bits in the following SC_CTRLS register bits:
 *        RTS  DTR
 *  UART0  7    6
 *  UART1  5    4
 */
#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)

static void integrator_uart_set_mctrl(struct amba_device *dev, void __iomem *base, unsigned int mctrl)
{
	unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;

	if (dev == &uart0_device) {
		rts_mask = 1 << 4;
		dtr_mask = 1 << 5;
	} else {
		rts_mask = 1 << 6;
		dtr_mask = 1 << 7;
	}

	if (mctrl & TIOCM_RTS)
		ctrlc |= rts_mask;
	else
		ctrls |= rts_mask;

	if (mctrl & TIOCM_DTR)
		ctrlc |= dtr_mask;
	else
		ctrls |= dtr_mask;

	__raw_writel(ctrls, SC_CTRLS);
	__raw_writel(ctrlc, SC_CTRLC);
}

static struct amba_pl010_data integrator_uart_data = {
	.set_mctrl = integrator_uart_set_mctrl,
};

#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
#define CM_CTRL	IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET


static DEFINE_SPINLOCK(cm_lock);
static DEFINE_SPINLOCK(cm_lock);
+67 −93
Original line number Original line Diff line number Diff line
@@ -51,8 +51,6 @@
#include <linux/amba/serial.h>
#include <linux/amba/serial.h>


#include <asm/io.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>


#define UART_NR		2
#define UART_NR		2


@@ -65,26 +63,16 @@
#define UART_RX_DATA(s)		(((s) & UART01x_FR_RXFE) == 0)
#define UART_RX_DATA(s)		(((s) & UART01x_FR_RXFE) == 0)
#define UART_TX_READY(s)	(((s) & UART01x_FR_TXFF) == 0)
#define UART_TX_READY(s)	(((s) & UART01x_FR_TXFF) == 0)


#define UART_DUMMY_RSR_RX	/*256*/0
#define UART_DUMMY_RSR_RX	256
#define UART_PORT_SIZE		64
#define UART_PORT_SIZE		64


/*
 * On the Integrator platform, the port RTS and DTR are provided by
 * bits in the following SC_CTRLS register bits:
 *        RTS  DTR
 *  UART0  7    6
 *  UART1  5    4
 */
#define SC_CTRLC	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET)
#define SC_CTRLS	(IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET)

/*
/*
 * We wrap our port structure around the generic uart_port.
 * We wrap our port structure around the generic uart_port.
 */
 */
struct uart_amba_port {
struct uart_amba_port {
	struct uart_port	port;
	struct uart_port	port;
	unsigned int		dtr_mask;
	struct amba_device	*dev;
	unsigned int		rts_mask;
	struct amba_pl010_data	*data;
	unsigned int		old_status;
	unsigned int		old_status;
};
};


@@ -300,20 +288,9 @@ static unsigned int pl010_get_mctrl(struct uart_port *port)
static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
{
	struct uart_amba_port *uap = (struct uart_amba_port *)port;
	struct uart_amba_port *uap = (struct uart_amba_port *)port;
	unsigned int ctrls = 0, ctrlc = 0;

	if (mctrl & TIOCM_RTS)
		ctrlc |= uap->rts_mask;
	else
		ctrls |= uap->rts_mask;

	if (mctrl & TIOCM_DTR)
		ctrlc |= uap->dtr_mask;
	else
		ctrls |= uap->dtr_mask;


	__raw_writel(ctrls, SC_CTRLS);
	if (uap->data)
	__raw_writel(ctrlc, SC_CTRLC);
		uap->data->set_mctrl(uap->dev, uap->port.membase, mctrl);
}
}


static void pl010_break_ctl(struct uart_port *port, int break_state)
static void pl010_break_ctl(struct uart_port *port, int break_state)
@@ -539,38 +516,7 @@ static struct uart_ops amba_pl010_pops = {
	.verify_port	= pl010_verify_port,
	.verify_port	= pl010_verify_port,
};
};


static struct uart_amba_port amba_ports[UART_NR] = {
static struct uart_amba_port *amba_ports[UART_NR];
	{
		.port	= {
			.membase	= (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE),
			.mapbase	= INTEGRATOR_UART0_BASE,
			.iotype		= UPIO_MEM,
			.irq		= IRQ_UARTINT0,
			.uartclk	= 14745600,
			.fifosize	= 16,
			.ops		= &amba_pl010_pops,
			.flags		= UPF_BOOT_AUTOCONF,
			.line		= 0,
		},
		.dtr_mask	= 1 << 5,
		.rts_mask	= 1 << 4,
	},
	{
		.port	= {
			.membase	= (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE),
			.mapbase	= INTEGRATOR_UART1_BASE,
			.iotype		= UPIO_MEM,
			.irq		= IRQ_UARTINT1,
			.uartclk	= 14745600,
			.fifosize	= 16,
			.ops		= &amba_pl010_pops,
			.flags		= UPF_BOOT_AUTOCONF,
			.line		= 1,
		},
		.dtr_mask	= 1 << 7,
		.rts_mask	= 1 << 6,
	}
};


#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE
#ifdef CONFIG_SERIAL_AMBA_PL010_CONSOLE


@@ -588,7 +534,7 @@ static void pl010_console_putchar(struct uart_port *port, int ch)
static void
static void
pl010_console_write(struct console *co, const char *s, unsigned int count)
pl010_console_write(struct console *co, const char *s, unsigned int count)
{
{
	struct uart_port *port = &amba_ports[co->index].port;
	struct uart_port *port = &amba_ports[co->index]->port;
	unsigned int status, old_cr;
	unsigned int status, old_cr;


	/*
	/*
@@ -651,7 +597,7 @@ static int __init pl010_console_setup(struct console *co, char *options)
	 */
	 */
	if (co->index >= UART_NR)
	if (co->index >= UART_NR)
		co->index = 0;
		co->index = 0;
	port = &amba_ports[co->index].port;
	port = &amba_ports[co->index]->port;


	if (options)
	if (options)
		uart_parse_options(options, &baud, &parity, &bits, &flow);
		uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -672,24 +618,6 @@ static struct console amba_console = {
	.data		= &amba_reg,
	.data		= &amba_reg,
};
};


static int __init amba_console_init(void)
{
	/*
	 * All port initializations are done statically
	 */
	register_console(&amba_console);
	return 0;
}
console_initcall(amba_console_init);

static int __init amba_late_console_init(void)
{
	if (!(amba_console.flags & CON_ENABLED))
		register_console(&amba_console);
	return 0;
}
late_initcall(amba_late_console_init);

#define AMBA_CONSOLE	&amba_console
#define AMBA_CONSOLE	&amba_console
#else
#else
#define AMBA_CONSOLE	NULL
#define AMBA_CONSOLE	NULL
@@ -707,30 +635,76 @@ static struct uart_driver amba_reg = {


static int pl010_probe(struct amba_device *dev, void *id)
static int pl010_probe(struct amba_device *dev, void *id)
{
{
	int i;
	struct uart_amba_port *port;

	void __iomem *base;
	for (i = 0; i < UART_NR; i++) {
	int i, ret;
		if (amba_ports[i].port.mapbase != dev->res.start)
			continue;


		amba_ports[i].port.dev = &dev->dev;
	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
		uart_add_one_port(&amba_reg, &amba_ports[i].port);
		if (amba_ports[i] == NULL)
		amba_set_drvdata(dev, &amba_ports[i]);
			break;
			break;

	if (i == ARRAY_SIZE(amba_ports)) {
		ret = -EBUSY;
		goto out;
	}
	}


	return 0;
	port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
	if (!port) {
		ret = -ENOMEM;
		goto out;
	}

	base = ioremap(dev->res.start, PAGE_SIZE);
	if (!base) {
		ret = -ENOMEM;
		goto free;
	}

	port->port.dev = &dev->dev;
	port->port.mapbase = dev->res.start;
	port->port.membase = base;
	port->port.iotype = UPIO_MEM;
	port->port.irq = dev->irq[0];
	port->port.uartclk = 14745600;
	port->port.fifosize = 16;
	port->port.ops = &amba_pl010_pops;
	port->port.flags = UPF_BOOT_AUTOCONF;
	port->port.line = i;
	port->dev = dev;
	port->data = dev->dev.platform_data;

	amba_ports[i] = port;

	amba_set_drvdata(dev, port);
	ret = uart_add_one_port(&amba_reg, &port->port);
	if (ret) {
		amba_set_drvdata(dev, NULL);
		amba_ports[i] = NULL;
		iounmap(base);
 free:
		kfree(port);
	}

 out:
	return ret;
}
}


static int pl010_remove(struct amba_device *dev)
static int pl010_remove(struct amba_device *dev)
{
{
	struct uart_amba_port *uap = amba_get_drvdata(dev);
	struct uart_amba_port *port = amba_get_drvdata(dev);

	int i;
	if (uap)
		uart_remove_one_port(&amba_reg, &uap->port);


	amba_set_drvdata(dev, NULL);
	amba_set_drvdata(dev, NULL);


	uart_remove_one_port(&amba_reg, &port->port);

	for (i = 0; i < ARRAY_SIZE(amba_ports); i++)
		if (amba_ports[i] == port)
			amba_ports[i] = NULL;

	iounmap(port->port.membase);
	kfree(port);

	return 0;
	return 0;
}
}


+6 −0
Original line number Original line Diff line number Diff line
@@ -158,4 +158,10 @@
#define UART01x_RSR_ANY		(UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE)
#define UART01x_RSR_ANY		(UART01x_RSR_OE|UART01x_RSR_BE|UART01x_RSR_PE|UART01x_RSR_FE)
#define UART01x_FR_MODEM_ANY	(UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS)
#define UART01x_FR_MODEM_ANY	(UART01x_FR_DCD|UART01x_FR_DSR|UART01x_FR_CTS)


#ifndef __ASSEMBLY__
struct amba_pl010_data {
	void (*set_mctrl)(struct amba_device *dev, void __iomem *base, unsigned int mctrl);
};
#endif

#endif
#endif