forked from Minki/linux
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:
parent
b59588aae8
commit
1f7d1c85df
@ -1443,24 +1443,48 @@ config SERIAL_BFIN_SPORT0_UART
|
||||
help
|
||||
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
|
||||
bool "Enable UART over SPORT1"
|
||||
depends on SERIAL_BFIN_SPORT
|
||||
help
|
||||
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
|
||||
bool "Enable UART over SPORT2"
|
||||
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
|
||||
help
|
||||
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
|
||||
bool "Enable UART over SPORT3"
|
||||
depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539)
|
||||
help
|
||||
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
|
||||
tristate "Support for timberdale UART"
|
||||
select SERIAL_CORE
|
||||
|
@ -48,6 +48,10 @@ struct sport_uart_port {
|
||||
unsigned short txmask2;
|
||||
unsigned char stopb;
|
||||
/* 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);
|
||||
@ -198,6 +202,59 @@ static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
|
||||
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 */
|
||||
static int sport_startup(struct uart_port *port)
|
||||
{
|
||||
@ -226,6 +283,21 @@ static int sport_startup(struct uart_port *port)
|
||||
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;
|
||||
fail2:
|
||||
free_irq(up->port.irq+1, up);
|
||||
@ -283,17 +355,6 @@ static unsigned int sport_tx_empty(struct uart_port *port)
|
||||
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)
|
||||
{
|
||||
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+1, 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)
|
||||
@ -536,7 +601,11 @@ sport_uart_console_setup(struct console *co, char *options)
|
||||
int baud = 57600;
|
||||
int bits = 8;
|
||||
int parity = 'n';
|
||||
# ifdef CONFIG_SERIAL_BFIN_SPORT_CTSRTS
|
||||
int flow = 'r';
|
||||
# else
|
||||
int flow = 'n';
|
||||
# endif
|
||||
|
||||
/* Check whether an invalid uart number has been specified */
|
||||
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;
|
||||
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
|
||||
@ -767,6 +852,10 @@ static int __devexit sport_uart_remove(struct platform_device *pdev)
|
||||
|
||||
if (sport) {
|
||||
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);
|
||||
peripheral_free_list(
|
||||
(unsigned short *)pdev->dev.platform_data);
|
||||
|
@ -72,4 +72,15 @@
|
||||
|
||||
#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 */
|
||||
|
Loading…
Reference in New Issue
Block a user