serial: bfin_sport_uart: add support for CTS/RTS via GPIOs

Some people need flow control on their ports, so now boards can support
that via any GPIOs.

Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
Sonic Zhang 2010-03-09 12:25:33 -05:00 committed by Greg Kroah-Hartman
parent b59588aae8
commit 1f7d1c85df
3 changed files with 135 additions and 11 deletions

View File

@ -1443,24 +1443,48 @@ config SERIAL_BFIN_SPORT0_UART
help help
Enable UART over SPORT0 Enable UART over SPORT0
config SERIAL_BFIN_SPORT0_UART_CTSRTS
bool "Enable UART over SPORT0 hardware flow control"
depends on SERIAL_BFIN_SPORT0_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT1_UART config SERIAL_BFIN_SPORT1_UART
bool "Enable UART over SPORT1" bool "Enable UART over SPORT1"
depends on SERIAL_BFIN_SPORT depends on SERIAL_BFIN_SPORT
help help
Enable UART over SPORT1 Enable UART over SPORT1
config SERIAL_BFIN_SPORT1_UART_CTSRTS
bool "Enable UART over SPORT1 hardware flow control"
depends on SERIAL_BFIN_SPORT1_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT2_UART config SERIAL_BFIN_SPORT2_UART
bool "Enable UART over SPORT2" bool "Enable UART over SPORT2"
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
help help
Enable UART over SPORT2 Enable UART over SPORT2
config SERIAL_BFIN_SPORT2_UART_CTSRTS
bool "Enable UART over SPORT2 hardware flow control"
depends on SERIAL_BFIN_SPORT2_UART
help
Enable hardware flow control in the driver.
config SERIAL_BFIN_SPORT3_UART config SERIAL_BFIN_SPORT3_UART
bool "Enable UART over SPORT3" bool "Enable UART over SPORT3"
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
help help
Enable UART over SPORT3 Enable UART over SPORT3
config SERIAL_BFIN_SPORT3_UART_CTSRTS
bool "Enable UART over SPORT3 hardware flow control"
depends on SERIAL_BFIN_SPORT3_UART
help
Enable hardware flow control in the driver.
config SERIAL_TIMBERDALE config SERIAL_TIMBERDALE
tristate "Support for timberdale UART" tristate "Support for timberdale UART"
select SERIAL_CORE select SERIAL_CORE

View File

@ -48,6 +48,10 @@ struct sport_uart_port {
unsigned short txmask2; unsigned short txmask2;
unsigned char stopb; unsigned char stopb;
/* unsigned char parib; */ /* unsigned char parib; */
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
int cts_pin;
int rts_pin;
#endif
}; };
static void sport_uart_tx_chars(struct sport_uart_port *up); static void sport_uart_tx_chars(struct sport_uart_port *up);
@ -198,6 +202,59 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
static unsigned int sport_get_mctrl(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
if (up->cts_pin < 0)
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
/* CTS PIN is negative assertive. */
if (SPORT_UART_GET_CTS(up))
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
else
return TIOCM_DSR | TIOCM_CAR;
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
if (up->rts_pin < 0)
return;
/* RTS PIN is negative assertive. */
if (mctrl & TIOCM_RTS)
SPORT_UART_ENABLE_RTS(up);
else
SPORT_UART_DISABLE_RTS(up);
}
/*
* Handle any change of modem status signal.
*/
static irqreturn_t sport_mctrl_cts_int(int irq, void *dev_id)
{
struct sport_uart_port *up = (struct sport_uart_port *)dev_id;
unsigned int status;
status = sport_get_mctrl(&up->port);
uart_handle_cts_change(&up->port, status & TIOCM_CTS);
return IRQ_HANDLED;
}
#else
static unsigned int sport_get_mctrl(struct uart_port *port)
{
pr_debug("%s enter\n", __func__);
return TIOCM_CTS | TIOCM_CD | TIOCM_DSR;
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
pr_debug("%s enter\n", __func__);
}
#endif
/* Reqeust IRQ, Setup clock */ /* Reqeust IRQ, Setup clock */
static int sport_startup(struct uart_port *port) static int sport_startup(struct uart_port *port)
{ {
@ -226,6 +283,21 @@ static int sport_startup(struct uart_port *port)
goto fail2; goto fail2;
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
if (up->cts_pin >= 0) {
if (request_irq(gpio_to_irq(up->cts_pin),
sport_mctrl_cts_int,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
IRQF_DISABLED, "BFIN_SPORT_UART_CTS", up)) {
up->cts_pin = -1;
dev_info(port->dev, "Unable to attach BlackFin UART \
over SPORT CTS interrupt. So, disable it.\n");
}
}
if (up->rts_pin >= 0)
gpio_direction_output(up->rts_pin, 0);
#endif
return 0; return 0;
fail2: fail2:
free_irq(up->port.irq+1, up); free_irq(up->port.irq+1, up);
@ -283,17 +355,6 @@ static unsigned int sport_tx_empty(struct uart_port *port)
return 0; return 0;
} }
static unsigned int sport_get_mctrl(struct uart_port *port)
{
pr_debug("%s enter\n", __func__);
return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
}
static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
pr_debug("%s enter\n", __func__);
}
static void sport_stop_tx(struct uart_port *port) static void sport_stop_tx(struct uart_port *port)
{ {
struct sport_uart_port *up = (struct sport_uart_port *)port; struct sport_uart_port *up = (struct sport_uart_port *)port;
@ -364,6 +425,10 @@ static void sport_shutdown(struct uart_port *port)
free_irq(up->port.irq, up); free_irq(up->port.irq, up);
free_irq(up->port.irq+1, up); free_irq(up->port.irq+1, up);
free_irq(up->err_irq, up); free_irq(up->err_irq, up);
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
if (up->cts_pin >= 0)
free_irq(gpio_to_irq(up->cts_pin), up);
#endif
} }
static const char *sport_type(struct uart_port *port) static const char *sport_type(struct uart_port *port)
@ -536,7 +601,11 @@ sport_uart_console_setup(struct console *co, char *options)
int baud = 57600; int baud = 57600;
int bits = 8; int bits = 8;
int parity = 'n'; int parity = 'n';
# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
int flow = 'r';
# else
int flow = 'n'; int flow = 'n';
# endif
/* Check whether an invalid uart number has been specified */ /* Check whether an invalid uart number has been specified */
if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS) if (co->index < 0 || co->index >= BFIN_SPORT_UART_MAX_PORTS)
@ -729,6 +798,22 @@ static int __devinit sport_uart_probe(struct platform_device *pdev)
ret = -ENOENT; ret = -ENOENT;
goto out_error_unmap; goto out_error_unmap;
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (res == NULL)
sport->cts_pin = -1;
else
sport->cts_pin = res->start;
res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (res == NULL)
sport->rts_pin = -1;
else
sport->rts_pin = res->start;
if (sport->rts_pin >= 0)
gpio_request(sport->rts_pin, DRV_NAME);
#endif
} }
#ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE #ifdef CONFIG_SERIAL_BFIN_SPORT_CONSOLE
@ -767,6 +852,10 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
if (sport) { if (sport) {
uart_remove_one_port(&sport_uart_reg, &sport->port); uart_remove_one_port(&sport_uart_reg, &sport->port);
#ifdef CONFIG_SERIAL_BFIN_CTSRTS
if (sport->rts_pin >= 0)
gpio_free(sport->rts_pin);
#endif
iounmap(sport->port.membase); iounmap(sport->port.membase);
peripheral_free_list( peripheral_free_list(
(unsigned short *)pdev->dev.platform_data); (unsigned short *)pdev->dev.platform_data);

View File

@ -72,4 +72,15 @@
#define SPORT_TX_FIFO_SIZE 8 #define SPORT_TX_FIFO_SIZE 8
#define SPORT_UART_GET_CTS(x) gpio_get_value(x->cts_pin)
#define SPORT_UART_DISABLE_RTS(x) gpio_set_value(x->rts_pin, 1)
#define SPORT_UART_ENABLE_RTS(x) gpio_set_value(x->rts_pin, 0)
#if defined(CONFIG_SERIAL_BFIN_SPORT0_UART_CTSRTS) \
|| defined(CONFIG_SERIAL_BFIN_SPORT1_UART_CTSRTS) \
|| defined(CONFIG_SERIAL_BFIN_SPORT2_UART_CTSRTS) \
|| defined(CONFIG_SERIAL_BFIN_SPORT3_UART_CTSRTS)
# define CONFIG_SERIAL_BFIN_SPORT_CTSRTS
#endif
#endif /* _BFIN_SPORT_UART_H */ #endif /* _BFIN_SPORT_UART_H */