* Re: [PATCH RESEND 2/8] serial: 8250: Add ioctl to enable auto rs485 mode with some Exar UARTs
From: Alan Cox @ 2011-12-09 19:00 UTC (permalink / raw)
To: Wolfram Sang
Cc: linux-serial, linux-kernel, Greg KH, Alan Cox, Claudio Scordino,
Matthias Fuchs
In-Reply-To: <1323450440-414-3-git-send-email-w.sang@pengutronix.de>
On Fri, 9 Dec 2011 18:07:14 +0100
Wolfram Sang <w.sang@pengutronix.de> wrote:
> From: Matthias Fuchs <mfuchs@ma-fu.de>
>
> Some Exar UARTs support an auto rs485 mode. In this mode
> the UART's RTS# pin is activated during transmitting and
> can be used to enable a rs485 line driver. This has nothing
> to do with attempts to do this by manually asserting/
> deasserting handshake lines in software.
Please split this out so that the ioctl handler calls a pair of port->
methods or errors if NULL. That'll future proof it and keep chip specific
stuff out of the direct paths.
Other than that I'm fine with it. Functionality, locking etc.
Alan
^ permalink raw reply
* Re: [PATCH RESEND 1/8] serial: 8250: replace hardcoded 0xbf with #define
From: Alan Cox @ 2011-12-09 18:58 UTC (permalink / raw)
To: Wolfram Sang
Cc: linux-serial, linux-kernel, Greg KH, Alan Cox, Claudio Scordino
In-Reply-To: <1323450440-414-2-git-send-email-w.sang@pengutronix.de>
On Fri, 9 Dec 2011 18:07:13 +0100
Wolfram Sang <w.sang@pengutronix.de> wrote:
> Makes it easier to find all occurences requesting CONF_MODE_B.
>
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Acked-by: Alan Cox <alan@linux.intel.com>
That should go in anyway
^ permalink raw reply
* Re: [uclinux-dist-devel] [PATCH 2/2] serial: bfin-uart: Remove ASYNC_CTS_FLOW flag for hardware automatic CTS.
From: Mike Frysinger @ 2011-12-09 17:17 UTC (permalink / raw)
To: uclinux-dist-devel
Cc: Alan Cox, Sonic Zhang, Greg Kroah-Hartman, LKML, linux-serial
In-Reply-To: <20111209111205.04780196@pyramind.ukuu.org.uk>
[-- Attachment #1: Type: Text/Plain, Size: 406 bytes --]
On Friday 09 December 2011 06:12:05 Alan Cox wrote:
> > +#ifdef CONFIG_SERIAL_BFIN_CTSRTS
> >
> > uart->port.flags |= ASYNC_CTS_FLOW;
> >
> > +#endif
>
> As an aside could the cts/hard cts etc be passed as properties to the
> platform device rather than ifdeffed ?
most platforms don't bother with flow control, so we made support in the driver
optional to keep things smaller.
-mike
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH RESEND 0/8] serial: 8250: support hw-based RS485 direction control
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang
Some 8250-variants control the direction pin for RS485 in hardware. Linux has
RS485 support these days, so update the 8250-driver to adhere to that.
Code is based on 3.2-rc4, tested on a OMAP-based custom board with a 16V2750.
A git tree can be found here:
git://git.pengutronix.de/git/wsa/linux-2.6.git 8250_rs485
There is no code change since the initial post of this series. I updated some
of the patch descriptions, though. A kind-of-ack from Claudio can be found here
[1]. Please consider for inclusion.
Thanks and regards,
Wolfram
[1] http://lkml.org/lkml/2011/11/24/201
Matthias Fuchs (1):
serial: 8250: Add ioctl to enable auto rs485 mode with some Exar UARTs
Wolfram Sang (7):
serial: 8250: replace hardcoded 0xbf with #define
serial: 8250: save rs485_flags per instance
serial: 8250: add RX_DURING_TX capability to RS485 mode
serial: 8250: reject delaying RTS with RS485
serial: 8250: update rs485 flags with polarity settings
serial: 8250: add Exar 16V2750 support
serial: 8250: fix comment about accessing EMSR
drivers/tty/serial/8250.c | 143 +++++++++++++++++++++++++++++++++++++++---
include/linux/serial_core.h | 3 +-
include/linux/serial_reg.h | 4 +-
3 files changed, 137 insertions(+), 13 deletions(-)
--
1.7.7.3
^ permalink raw reply
* [PATCH RESEND 3/8] serial: 8250: save rs485_flags per instance
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
When set, save RS485 related flags in the private struct. This avoids
mangling with chip registers when reading back the RS485 config. Also,
features can check their configuration at runtime which will be needed
for a later patch.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 16 +++++-----------
1 files changed, 5 insertions(+), 11 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 920b4df..b5d3248 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -154,6 +154,7 @@ struct uart_8250_port {
unsigned char lsr_saved_flags;
#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
unsigned char msr_saved_flags;
+ __u32 rs485_flags; /* copied from IOCTL */
};
struct irq_info {
@@ -2729,28 +2730,21 @@ static int serial8250_ioctl_port(struct uart_port *port,
serial_outp(up, UART_FCTR, fctr);
serial_outp(up, UART_LCR, lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
+
+ up->rs485_flags = rs485ctrl.flags;
+
return 0;
}
case TIOCGRS485:
{
struct serial_rs485 rs485ctrl;
- unsigned char lcr;
if (port->type != PORT_16850)
return -ENOTTY;
memset(&rs485ctrl, 0, sizeof(rs485ctrl));
-
- spin_lock_irqsave(&up->port.lock, flags);
- lcr = serial_inp(up, UART_LCR);
- serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
- if (serial_inp(up, UART_FCTR) & UART_FCTR_RS485)
- rs485ctrl.flags = SER_RS485_ENABLED;
- else
- rs485ctrl.flags = 0;
- serial_outp(up, UART_LCR, lcr);
- spin_unlock_irqrestore(&up->port.lock, flags);
+ rs485ctrl.flags = up->rs485_flags;
if (copy_to_user((struct serial_rs485 *)arg, &rs485ctrl,
sizeof(rs485ctrl)))
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 4/8] serial: 8250: add RX_DURING_TX capability to RS485 mode
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang,
Juergen Beisert
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
To prevent echo in some configurations, make sure we do not read back
when we are sending if RS485 is configured this way. We need to shuffle
stop_rx() around, implement start_rx() and call it in apropriate places.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 34 +++++++++++++++++++++++++---------
1 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index b5d3248..6a2f47f 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1304,6 +1304,26 @@ static void autoconfig_irq(struct uart_8250_port *up)
up->port.irq = (irq > 0) ? irq : 0;
}
+static void serial8250_stop_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+
+ up->ier &= ~UART_IER_RLSI;
+ up->port.read_status_mask &= ~UART_LSR_DR;
+ serial_out(up, UART_IER, up->ier);
+}
+
+static void serial8250_start_rx(struct uart_port *port)
+{
+ struct uart_8250_port *up =
+ container_of(port, struct uart_8250_port, port);
+
+ up->ier |= UART_IER_RLSI;
+ up->port.read_status_mask |= UART_LSR_DR;
+ serial_out(up, UART_IER, up->ier);
+}
+
static inline void __stop_tx(struct uart_8250_port *p)
{
if (p->ier & UART_IER_THRI) {
@@ -1326,6 +1346,9 @@ static void serial8250_stop_tx(struct uart_port *port)
up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
+
+ if (!(up->rs485_flags & SER_RS485_RX_DURING_TX))
+ serial8250_start_rx(port);
}
static void transmit_chars(struct uart_8250_port *up);
@@ -1357,16 +1380,9 @@ static void serial8250_start_tx(struct uart_port *port)
up->acr &= ~UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
-}
-static void serial8250_stop_rx(struct uart_port *port)
-{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
-
- up->ier &= ~UART_IER_RLSI;
- up->port.read_status_mask &= ~UART_LSR_DR;
- serial_out(up, UART_IER, up->ier);
+ if (!(up->rs485_flags & SER_RS485_RX_DURING_TX))
+ serial8250_stop_rx(port);
}
static void serial8250_enable_ms(struct uart_port *port)
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 8/8] serial: 8250: fix comment about accessing EMSR
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
All docs I checked do say LCR should NOT be 0xBF (16c850, 16c854,
16v2750). Fix it according to that, since the only usage of the register
currently implements the revised access method. If somebody later finds
a derivate which actually does need 0xBF to enable that register, we can
update the comment again with precise references.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
include/linux/serial_reg.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 0267bab6..0a1beca 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -211,7 +211,7 @@
#define UART_FCTR_TX 0x80 /* Programmable trigger mode select */
/*
- * LCR=0xBF, FCTR[6]=1
+ * LCR!=0xBF (some docs say =0), FCTR[6]=1, XR16C85x
*/
#define UART_EMSR 7 /* Extended Mode Select Register */
#define UART_EMSR_FIFO_COUNT 0x01 /* Rx/Tx select */
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 7/8] serial: 8250: add Exar 16V2750 support
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang,
Juergen Beisert
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
This variant can select the polarity of RTS# when TX is active with
RS485. Add code to support that, too.
Signed-off-by: Juergen Beisert <jbe@pengutronix.de>
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 51 +++++++++++++++++++++++++++++++++++++------
include/linux/serial_core.h | 3 +-
include/linux/serial_reg.h | 1 +
3 files changed, 47 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 8cf6d76..5039e60 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -247,6 +247,13 @@ static const struct serial8250_config uart_config[] = {
UART_FCR_T_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
},
+ [PORT_16V2750] = {
+ .name = "XR16V2750",
+ .fifo_size = 64,
+ .tx_loadsz = 32,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .flags = UART_CAP_FIFO | UART_CAP_EFR | UART_CAP_SLEEP,
+ },
[PORT_16850] = {
.name = "XR16850",
.fifo_size = 128,
@@ -838,6 +845,7 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
* We check for a XR16C850 by setting DLL and DLM to 0, and then
* reading back DLL and DLM. The chip type depends on the DLM
* value read back:
+ * 0x0a - XR16V2750
* 0x10 - XR16C850 and the DLL contains the chip revision.
* 0x12 - XR16C2850.
* 0x14 - XR16C854.
@@ -850,6 +858,10 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
up->port.type = PORT_16850;
return;
}
+ if (id2 == 0x0a) {
+ up->port.type = PORT_16V2750;
+ return;
+ }
/*
* It wasn't an XR16C850.
@@ -2060,7 +2072,7 @@ static int serial8250_startup(struct uart_port *port)
/*
* For a XR16C850, we need to set the trigger levels
*/
- if (up->port.type == PORT_16850) {
+ if (up->port.type == PORT_16850 || up->port.type == PORT_16V2750) {
unsigned char fctr;
serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
@@ -2726,9 +2738,9 @@ static int serial8250_ioctl_port(struct uart_port *port,
case TIOCSRS485:
{
struct serial_rs485 rs485ctrl;
- unsigned char fctr, lcr;
+ unsigned char fctr, lcr, emsr;
- if (port->type != PORT_16850)
+ if (port->type != PORT_16850 && port->type != PORT_16V2750)
return -ENOTTY;
if (copy_from_user(&rs485ctrl, (struct serial_rs485 *)arg,
@@ -2739,6 +2751,34 @@ static int serial8250_ioctl_port(struct uart_port *port,
return -EOPNOTSUPP;
spin_lock_irqsave(&up->port.lock, flags);
+ if (up->port.type == PORT_16V2750) {
+ /* make EMSR visible */
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ fctr = serial_inp(up, UART_FCTR);
+ serial_outp(up, UART_FCTR, fctr | UART_FCTR_SCR_SWAP);
+ serial_outp(up, UART_LCR, 0);
+
+ /* set RTS polarity */
+ emsr = serial_inp(up, UART_EMSR) & ~UART_EMSR_RS485_INV;
+ if (rs485ctrl.flags & SER_RS485_RTS_ON_SEND) {
+ emsr |= UART_EMSR_RS485_INV;
+ rs485ctrl.flags &= ~SER_RS485_RTS_AFTER_SEND;
+ } else {
+ rs485ctrl.flags |= SER_RS485_RTS_AFTER_SEND;
+ }
+ serial_outp(up, UART_EMSR, emsr);
+
+ /* make the EMSR invisible */
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ fctr = serial_inp(up, UART_FCTR) & ~UART_FCTR_SCR_SWAP;
+ serial_outp(up, UART_FCTR, fctr);
+ serial_outp(up, UART_LCR, 0);
+ } else {
+ /* only mode supported by the 16C850 */
+ rs485ctrl.flags &= ~SER_RS485_RTS_ON_SEND;
+ rs485ctrl.flags |= SER_RS485_RTS_AFTER_SEND;
+ }
+
lcr = serial_inp(up, UART_LCR);
serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
fctr = serial_inp(up, UART_FCTR);
@@ -2750,9 +2790,6 @@ static int serial8250_ioctl_port(struct uart_port *port,
serial_outp(up, UART_LCR, lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
- /* only mode supported by the 16C850 */
- rs485ctrl.flags &= ~SER_RS485_RTS_ON_SEND;
- rs485ctrl.flags |= SER_RS485_RTS_AFTER_SEND;
up->rs485_flags = rs485ctrl.flags;
return 0;
@@ -2762,7 +2799,7 @@ static int serial8250_ioctl_port(struct uart_port *port,
{
struct serial_rs485 rs485ctrl;
- if (port->type != PORT_16850)
+ if (port->type != PORT_16850 && port->type != PORT_16V2750)
return -ENOTTY;
memset(&rs485ctrl, 0, sizeof(rs485ctrl));
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index eadf33d..72118c5 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -47,7 +47,8 @@
#define PORT_U6_16550A 19 /* ST-Ericsson U6xxx internal UART */
#define PORT_TEGRA 20 /* NVIDIA Tegra internal UART */
#define PORT_XR17D15X 21 /* Exar XR17D15x UART */
-#define PORT_MAX_8250 21 /* max port ID */
+#define PORT_16V2750 22 /* Exar XR16V2750 */
+#define PORT_MAX_8250 22 /* max port ID */
/*
* ARM specific type numbers. These are not currently guaranteed
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index fb37c4f..0267bab6 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -216,6 +216,7 @@
#define UART_EMSR 7 /* Extended Mode Select Register */
#define UART_EMSR_FIFO_COUNT 0x01 /* Rx/Tx select */
#define UART_EMSR_ALT_COUNT 0x02 /* Alternating count select */
+#define UART_EMSR_RS485_INV 0x08 /* RS485 RTS output inversion */
/*
* The Intel XScale on-chip UARTs define these bits
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 6/8] serial: 8250: update rs485 flags with polarity settings
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
Report the only mode we can support with the 16C850.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 28b3608..8cf6d76 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -2750,6 +2750,9 @@ static int serial8250_ioctl_port(struct uart_port *port,
serial_outp(up, UART_LCR, lcr);
spin_unlock_irqrestore(&up->port.lock, flags);
+ /* only mode supported by the 16C850 */
+ rs485ctrl.flags &= ~SER_RS485_RTS_ON_SEND;
+ rs485ctrl.flags |= SER_RS485_RTS_AFTER_SEND;
up->rs485_flags = rs485ctrl.flags;
return 0;
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 5/8] serial: 8250: reject delaying RTS with RS485
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
There might be chips capable of doing this, but for now nothing is implemented,
so reject usage of this feature.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index 6a2f47f..28b3608 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -2735,6 +2735,9 @@ static int serial8250_ioctl_port(struct uart_port *port,
sizeof(rs485ctrl)))
return -EFAULT;
+ if (rs485ctrl.delay_rts_before_send || rs485ctrl.delay_rts_after_send)
+ return -EOPNOTSUPP;
+
spin_lock_irqsave(&up->port.lock, flags);
lcr = serial_inp(up, UART_LCR);
serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 2/8] serial: 8250: Add ioctl to enable auto rs485 mode with some Exar UARTs
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Matthias Fuchs,
Wolfram Sang
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
From: Matthias Fuchs <mfuchs@ma-fu.de>
Some Exar UARTs support an auto rs485 mode. In this mode
the UART's RTS# pin is activated during transmitting and
can be used to enable a rs485 line driver. This has nothing
to do with attempts to do this by manually asserting/
deasserting handshake lines in software.
Signed-off-by: Matthias Fuchs <mfuchs@ma-fu.de>
[wsa] Replaced 0xbf with define, saved some line-breaks.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 68 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/serial_reg.h | 1 +
2 files changed, 69 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index f8f2320..920b4df 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -38,6 +38,7 @@
#include <linux/nmi.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -2698,6 +2699,72 @@ serial8250_type(struct uart_port *port)
return uart_config[type].name;
}
+static int serial8250_ioctl_port(struct uart_port *port,
+ unsigned int cmd, unsigned long arg)
+{
+ struct uart_8250_port *up = (struct uart_8250_port *)port;
+ unsigned long flags;
+
+ switch (cmd) {
+ case TIOCSRS485:
+ {
+ struct serial_rs485 rs485ctrl;
+ unsigned char fctr, lcr;
+
+ if (port->type != PORT_16850)
+ return -ENOTTY;
+
+ if (copy_from_user(&rs485ctrl, (struct serial_rs485 *)arg,
+ sizeof(rs485ctrl)))
+ return -EFAULT;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ lcr = serial_inp(up, UART_LCR);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ fctr = serial_inp(up, UART_FCTR);
+ if (rs485ctrl.flags & SER_RS485_ENABLED)
+ fctr |= UART_FCTR_RS485;
+ else
+ fctr &= ~UART_FCTR_RS485;
+ serial_outp(up, UART_FCTR, fctr);
+ serial_outp(up, UART_LCR, lcr);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ return 0;
+ }
+
+ case TIOCGRS485:
+ {
+ struct serial_rs485 rs485ctrl;
+ unsigned char lcr;
+
+ if (port->type != PORT_16850)
+ return -ENOTTY;
+
+ memset(&rs485ctrl, 0, sizeof(rs485ctrl));
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ lcr = serial_inp(up, UART_LCR);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ if (serial_inp(up, UART_FCTR) & UART_FCTR_RS485)
+ rs485ctrl.flags = SER_RS485_ENABLED;
+ else
+ rs485ctrl.flags = 0;
+ serial_outp(up, UART_LCR, lcr);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ if (copy_to_user((struct serial_rs485 *)arg, &rs485ctrl,
+ sizeof(rs485ctrl)))
+ return -EFAULT;
+ return 0;
+ }
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
static struct uart_ops serial8250_pops = {
.tx_empty = serial8250_tx_empty,
.set_mctrl = serial8250_set_mctrl,
@@ -2717,6 +2784,7 @@ static struct uart_ops serial8250_pops = {
.request_port = serial8250_request_port,
.config_port = serial8250_config_port,
.verify_port = serial8250_verify_port,
+ .ioctl = serial8250_ioctl_port,
#ifdef CONFIG_CONSOLE_POLL
.poll_get_char = serial8250_get_poll_char,
.poll_put_char = serial8250_put_poll_char,
diff --git a/include/linux/serial_reg.h b/include/linux/serial_reg.h
index 8ce70d7..fb37c4f 100644
--- a/include/linux/serial_reg.h
+++ b/include/linux/serial_reg.h
@@ -201,6 +201,7 @@
#define UART_FCTR_RTS_8DELAY 0x03
#define UART_FCTR_IRDA 0x04 /* IrDa data encode select */
#define UART_FCTR_TX_INT 0x08 /* Tx interrupt type select */
+#define UART_FCTR_RS485 0x08 /* Auto RS485 mode */
#define UART_FCTR_TRGA 0x00 /* Tx/Rx 550 trigger table select */
#define UART_FCTR_TRGB 0x10 /* Tx/Rx 650 trigger table select */
#define UART_FCTR_TRGC 0x20 /* Tx/Rx 654 trigger table select */
--
1.7.7.3
^ permalink raw reply related
* [PATCH RESEND 1/8] serial: 8250: replace hardcoded 0xbf with #define
From: Wolfram Sang @ 2011-12-09 17:07 UTC (permalink / raw)
To: linux-serial
Cc: linux-kernel, Greg KH, Alan Cox, Claudio Scordino, Wolfram Sang
In-Reply-To: <1323450440-414-1-git-send-email-w.sang@pengutronix.de>
Makes it easier to find all occurences requesting CONF_MODE_B.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
---
drivers/tty/serial/8250.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index eeadf1b..f8f2320 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -2000,7 +2000,7 @@ static int serial8250_startup(struct uart_port *port)
serial_outp(up, UART_IER, 0);
serial_outp(up, UART_LCR, 0);
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */
- serial_outp(up, UART_LCR, 0xBF);
+ serial_outp(up, UART_LCR, UART_LCR_CONF_MODE_B);
serial_outp(up, UART_EFR, UART_EFR_ECB);
serial_outp(up, UART_LCR, 0);
}
--
1.7.7.3
^ permalink raw reply related
* Re: [PATCH 2/2] serial: bfin-uart: Remove ASYNC_CTS_FLOW flag for hardware automatic CTS.
From: Alan Cox @ 2011-12-09 11:12 UTC (permalink / raw)
To: Sonic Zhang
Cc: Greg Kroah-Hartman, linux-serial, LKML, uclinux-dist-devel,
Sonic Zhang
In-Reply-To: <1323410421-10465-2-git-send-email-sonic.adi@gmail.com>
> +#ifdef CONFIG_SERIAL_BFIN_CTSRTS
> uart->port.flags |= ASYNC_CTS_FLOW;
> +#endif
As an aside could the cts/hard cts etc be passed as properties to the
platform device rather than ifdeffed ?
Alan
^ permalink raw reply
* [PATCH 2/2] serial: bfin-uart: Remove ASYNC_CTS_FLOW flag for hardware automatic CTS.
From: Sonic Zhang @ 2011-12-09 6:00 UTC (permalink / raw)
To: Greg Kroah-Hartman, linux-serial; +Cc: LKML, uclinux-dist-devel, Sonic Zhang
In-Reply-To: <1323410421-10465-1-git-send-email-sonic.adi@gmail.com>
From: Sonic Zhang <sonic.zhang@analog.com>
Blackfin uart supports automatic CTS trigger when hardware flow control is enabled.
No need to start and top tx in CTS interrupt. So, remote ASYNC_CTS_FLOW flag.
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
---
drivers/tty/serial/bfin_uart.c | 17 ++++++++++++++---
1 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 57747c4..929dd11 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -116,11 +116,20 @@ static void bfin_serial_set_mctrl(struct uart_port *port, unsigned int mctrl)
static irqreturn_t bfin_serial_mctrl_cts_int(int irq, void *dev_id)
{
struct bfin_serial_port *uart = dev_id;
- unsigned int status;
-
- status = bfin_serial_get_mctrl(&uart->port);
+ unsigned int status = bfin_serial_get_mctrl(&uart->port);
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
+ struct tty_struct *tty = uart->port.state->port.tty;
+
UART_CLEAR_SCTS(uart);
+ if (tty->hw_stopped) {
+ if (status) {
+ tty->hw_stopped = 0;
+ uart_write_wakeup(&uart->port);
+ }
+ } else {
+ if (!status)
+ tty->hw_stopped = 1;
+ }
#endif
uart_handle_cts_change(&uart->port, status & TIOCM_CTS);
@@ -1358,7 +1367,9 @@ static int bfin_serial_probe(struct platform_device *pdev)
uart->cts_pin = -1;
else {
uart->cts_pin = res->start;
+#ifdef CONFIG_SERIAL_BFIN_CTSRTS
uart->port.flags |= ASYNC_CTS_FLOW;
+#endif
}
res = platform_get_resource(pdev, IORESOURCE_IO, 1);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 1/2] serial: bfin-uart: Enable hardware automatic CTS only when CTS pin is available.
From: Sonic Zhang @ 2011-12-09 6:00 UTC (permalink / raw)
To: Greg Kroah-Hartman, linux-serial; +Cc: LKML, uclinux-dist-devel, Sonic Zhang
From: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
---
drivers/tty/serial/bfin_uart.c | 19 ++++++++++---------
1 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/tty/serial/bfin_uart.c b/drivers/tty/serial/bfin_uart.c
index 21bfa9a..57747c4 100644
--- a/drivers/tty/serial/bfin_uart.c
+++ b/drivers/tty/serial/bfin_uart.c
@@ -726,16 +726,17 @@ static int bfin_serial_startup(struct uart_port *port)
}
#endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
- if (uart->cts_pin >= 0 && request_irq(uart->status_irq,
- bfin_serial_mctrl_cts_int,
- IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
- uart->cts_pin = -1;
- pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
- }
+ if (uart->cts_pin >= 0) {
+ if (request_irq(uart->status_irq, bfin_serial_mctrl_cts_int,
+ IRQF_DISABLED, "BFIN_UART_MODEM_STATUS", uart)) {
+ uart->cts_pin = -1;
+ pr_info("Unable to attach BlackFin UART Modem Status interrupt.\n");
+ }
- /* CTS RTS PINs are negative assertive. */
- UART_PUT_MCR(uart, ACTS);
- UART_SET_IER(uart, EDSSI);
+ /* CTS RTS PINs are negative assertive. */
+ UART_PUT_MCR(uart, ACTS);
+ UART_SET_IER(uart, EDSSI);
+ }
#endif
UART_SET_IER(uart, ERBFI);
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Benjamin Herrenschmidt @ 2011-12-08 19:44 UTC (permalink / raw)
To: Finn Thain; +Cc: Geert Uytterhoeven, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <alpine.LNX.2.00.1112082128330.2357@nippy.intranet>
On Thu, 2011-12-08 at 22:26 +1100, Finn Thain wrote:
>
> Maybe the modem wants a transition on DTR or similar, but it hasn't had
> time to initialise when that happens during SCC resumption.
>
> If so, calling pmz_shutdown() then pmz_startup() from the tail of
> pmz_resume() without delay should probably fail to revive it...
Well, we power the modem down and back up... but it's possible that we
fail to re-enable something, I'll check. That used to work (at least
with macserial, maybe I never tried this specific torture with pmz...).
I'll figure it out eventually.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Geert Uytterhoeven @ 2011-12-08 11:54 UTC (permalink / raw)
To: Finn Thain; +Cc: Benjamin Herrenschmidt, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <alpine.LNX.2.00.1112082128330.2357@nippy.intranet>
Hi Finn,
On Thu, Dec 8, 2011 at 12:26, Finn Thain <fthain@telegraphics.com.au> wrote:
> On Thu, 8 Dec 2011, Benjamin Herrenschmidt wrote:
>> On Thu, 2011-12-08 at 15:20 +1100, Benjamin Herrenschmidt wrote:
>> > So basic operations seem to work, I've applied the patch to
>> > powerpc-next.
>
> Then I guess Geert should not push this for 3.3 -- or does it make no
> difference?
I do not plan to push it myself, that's why it's not in my for-next branch.
The for-3.3 is just indicative.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Finn Thain @ 2011-12-08 11:26 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: Geert Uytterhoeven, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <1323318638.12793.23.camel@pasglop>
On Thu, 8 Dec 2011, Benjamin Herrenschmidt wrote:
> On Thu, 2011-12-08 at 15:20 +1100, Benjamin Herrenschmidt wrote:
>
> > So basic operations seem to work, I've applied the patch to
> > powerpc-next.
Then I guess Geert should not push this for 3.3 -- or does it make no
difference?
> > However, the internal modem on my Pismo powerbook doesn't appear to
> > survive suspend/resume. I'll dig into that and merge a fixup patch
> > asap.
>
> BTW. I applied anyway because suspend/resume was already broken (you
> spotted that we don't clear the suspended flag for example).
>
> Fixing the flag alone helps a bit. We can't use the modem if we
> suspend/resume with the open port,
If the SCC IRQ counters change across suspend/resume, perhaps the modem
itself is not powering up...
> but closing and re-opening works.
Maybe the modem wants a transition on DTR or similar, but it hasn't had
time to initialise when that happens during SCC resumption.
If so, calling pmz_shutdown() then pmz_startup() from the tail of
pmz_resume() without delay should probably fail to revive it...
>
> Lockdep also picked-up a A->B B->A between the port mutex and the pmz
> irq mutex on suspend.
>
> I'll try to fix all these, and will let you know (I may not have time
> today).
Thanks.
Finn
>
> Cheers,
> Ben.
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Benjamin Herrenschmidt @ 2011-12-08 4:30 UTC (permalink / raw)
To: Finn Thain; +Cc: Geert Uytterhoeven, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <1323318004.12793.21.camel@pasglop>
On Thu, 2011-12-08 at 15:20 +1100, Benjamin Herrenschmidt wrote:
> So basic operations seem to work, I've applied the patch to
> powerpc-next.
>
> However, the internal modem on my Pismo powerbook doesn't appear to
> survive suspend/resume. I'll dig into that and merge a fixup patch asap.
BTW. I applied anyway because suspend/resume was already broken (you
spotted that we don't clear the suspended flag for example).
Fixing the flag alone helps a bit. We can't use the modem if we
suspend/resume with the open port, but closing and re-opening works.
Lockdep also picked-up a A->B B->A between the port mutex and the pmz
irq mutex on suspend.
I'll try to fix all these, and will let you know (I may not have time
today).
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Benjamin Herrenschmidt @ 2011-12-08 4:20 UTC (permalink / raw)
To: Finn Thain; +Cc: Geert Uytterhoeven, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <alpine.LNX.2.00.1112071427280.28552@nippy.intranet>
On Wed, 2011-12-07 at 14:49 +1100, Finn Thain wrote:
> On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be
> masked. This can be a problem when pmac_zilog starts up.
>
> For example, the serial debugging code in arch/m68k/kernel/head.S may be
> used beforehand. It disables the SCC interrupts at the chip but doesn't
> ack them. Then when a pmac_zilog port is used, the machine locks up with
> "unexpected interrupt".
>
> This can happen in pmz_shutdown() since the irq is freed before the
> channel interrupts are disabled.
>
> Fix this by clearing interrupt enable bits before the handler is
> uninstalled. Also move the interrupt control bit flipping into a separate
> pmz_interrupt_control() routine. Replace all instances of these operations
> with calls to this routine. Omit the zssync() calls that seem to serve no
> purpose.
>
> Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
> Acked-by: Alan Cox <alan@linux.intel.com>
>
> ---
So basic operations seem to work, I've applied the patch to
powerpc-next.
However, the internal modem on my Pismo powerbook doesn't appear to
survive suspend/resume. I'll dig into that and merge a fixup patch asap.
Cheers,
Ben.
^ permalink raw reply
* [PATCH 2/2] msm_serial_hs: Fix spinlock recursion in handling CTS
From: Mayank Rana @ 2011-12-08 3:36 UTC (permalink / raw)
To: gregkh; +Cc: linux-arm-msm, linux-serial, imirkin, npelly, Mayank Rana
In-Reply-To: <1323315369-19260-1-git-send-email-mrana@codeaurora.org>
msm_hs_handle_delta_cts tries to acquire port->lock already acquired
by the callee function msm_hs_isr. Change function name to follow
"_locked" convention.
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
---
drivers/tty/serial/msm_serial_hs.c | 7 ++-----
1 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index f1d5695..ec16037 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -1085,12 +1085,10 @@ static void msm_hs_config_port(struct uart_port *uport, int cfg_flags)
}
/* Handle CTS changes (Called from interrupt handler) */
-static void msm_hs_handle_delta_cts(struct uart_port *uport)
+static void msm_hs_handle_delta_cts_locked(struct uart_port *uport)
{
- unsigned long flags;
struct msm_hs_port *msm_uport = UARTDM_TO_MSM(uport);
- spin_lock_irqsave(&uport->lock, flags);
clk_enable(msm_uport->clk);
/* clear interrupt */
@@ -1098,7 +1096,6 @@ static void msm_hs_handle_delta_cts(struct uart_port *uport)
uport->icount.cts++;
clk_disable(msm_uport->clk);
- spin_unlock_irqrestore(&uport->lock, flags);
/* clear the IOCTL TIOCMIWAIT if called */
wake_up_interruptible(&uport->state->port.delta_msr_wait);
@@ -1246,7 +1243,7 @@ static irqreturn_t msm_hs_isr(int irq, void *dev)
/* Change in CTS interrupt */
if (isr_status & UARTDM_ISR_DELTA_CTS_BMSK)
- msm_hs_handle_delta_cts(uport);
+ msm_hs_handle_delta_cts_locked(uport);
spin_unlock_irqrestore(&uport->lock, flags);
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related
* [PATCH 1/2] msm_serial_hs: Fix type inconsistency for tx and rx command_ptr_ptr
From: Mayank Rana @ 2011-12-08 3:36 UTC (permalink / raw)
To: gregkh; +Cc: linux-arm-msm, linux-serial, imirkin, npelly, Mayank Rana
Both tx and rx command_ptr_ptr are of type u32*. While allocating
memory for it, sizeof(u32 *) is used as part of kmalloc API instead
of sizeof(u32). ADM Hardare requires size of command_ptr_ptr as 1 Word.
Both sizeof(u32 *) and sizeof(u32) are same on 32-bit architecture
whereas sizeof(u32 *) would be different in size compare to sizeof(u32)
on anyother architecture.
Hence correct usage of sizeof(command_ptr_ptr) for Tx and Rx with
kmalloc and dma_(map/unmap)_single APIs.
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Reported-by: Ilia Mirkin <imirkin@alum.mit.edu>
---
drivers/tty/serial/msm_serial_hs.c | 16 ++++++++--------
1 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/msm_serial_hs.c b/drivers/tty/serial/msm_serial_hs.c
index 624701f..f1d5695 100644
--- a/drivers/tty/serial/msm_serial_hs.c
+++ b/drivers/tty/serial/msm_serial_hs.c
@@ -420,9 +420,9 @@ static int __devexit msm_hs_remove(struct platform_device *pdev)
msm_uport->rx.rbuffer);
dma_pool_destroy(msm_uport->rx.pool);
- dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32 *),
+ dma_unmap_single(dev, msm_uport->rx.cmdptr_dmaaddr, sizeof(u32),
DMA_TO_DEVICE);
- dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32 *),
+ dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr_ptr, sizeof(u32),
DMA_TO_DEVICE);
dma_unmap_single(dev, msm_uport->tx.mapped_cmd_ptr, sizeof(dmov_box),
DMA_TO_DEVICE);
@@ -810,7 +810,7 @@ static void msm_hs_submit_tx_locked(struct uart_port *uport)
*tx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(tx->mapped_cmd_ptr);
dma_sync_single_for_device(uport->dev, tx->mapped_cmd_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
/* Save tx_count to use in Callback */
tx->tx_count = tx_count;
@@ -1535,7 +1535,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
if (!tx->command_ptr)
return -ENOMEM;
- tx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+ tx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!tx->command_ptr_ptr) {
ret = -ENOMEM;
goto err_tx_command_ptr_ptr;
@@ -1545,7 +1545,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
sizeof(dmov_box), DMA_TO_DEVICE);
tx->mapped_cmd_ptr_ptr = dma_map_single(uport->dev,
tx->command_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
tx->xfer.cmdptr = DMOV_CMD_ADDR(tx->mapped_cmd_ptr_ptr);
init_waitqueue_head(&rx->wait);
@@ -1573,7 +1573,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
goto err_rx_command_ptr;
}
- rx->command_ptr_ptr = kmalloc(sizeof(u32 *), GFP_KERNEL | __GFP_DMA);
+ rx->command_ptr_ptr = kmalloc(sizeof(u32), GFP_KERNEL | __GFP_DMA);
if (!rx->command_ptr_ptr) {
pr_err("%s(): cannot allocate rx->command_ptr_ptr", __func__);
ret = -ENOMEM;
@@ -1591,7 +1591,7 @@ static int __devinit uartdm_init_port(struct uart_port *uport)
*rx->command_ptr_ptr = CMD_PTR_LP | DMOV_CMD_ADDR(rx->mapped_cmd_ptr);
rx->cmdptr_dmaaddr = dma_map_single(uport->dev, rx->command_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
rx->xfer.cmdptr = DMOV_CMD_ADDR(rx->cmdptr_dmaaddr);
INIT_WORK(&rx->tty_work, msm_hs_tty_flip_buffer_work);
@@ -1607,7 +1607,7 @@ err_dma_pool_alloc:
dma_pool_destroy(msm_uport->rx.pool);
err_dma_pool_create:
dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr_ptr,
- sizeof(u32 *), DMA_TO_DEVICE);
+ sizeof(u32), DMA_TO_DEVICE);
dma_unmap_single(uport->dev, msm_uport->tx.mapped_cmd_ptr,
sizeof(dmov_box), DMA_TO_DEVICE);
kfree(msm_uport->tx.command_ptr_ptr);
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related
* Re: [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Benjamin Herrenschmidt @ 2011-12-08 3:17 UTC (permalink / raw)
To: Finn Thain; +Cc: Geert Uytterhoeven, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <alpine.LNX.2.00.1112071427280.28552@nippy.intranet>
On Wed, 2011-12-07 at 14:49 +1100, Finn Thain wrote:
> On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be
> masked. This can be a problem when pmac_zilog starts up.
Thanks. I'll test it on a powermac or two and will merge it via the
powerpc -next tree if it works out allright.
Cheers,
Ben.
> For example, the serial debugging code in arch/m68k/kernel/head.S may be
> used beforehand. It disables the SCC interrupts at the chip but doesn't
> ack them. Then when a pmac_zilog port is used, the machine locks up with
> "unexpected interrupt".
>
> This can happen in pmz_shutdown() since the irq is freed before the
> channel interrupts are disabled.
>
> Fix this by clearing interrupt enable bits before the handler is
> uninstalled. Also move the interrupt control bit flipping into a separate
> pmz_interrupt_control() routine. Replace all instances of these operations
> with calls to this routine. Omit the zssync() calls that seem to serve no
> purpose.
>
> Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
> Acked-by: Alan Cox <alan@linux.intel.com>
>
> ---
>
> Re-implemented as v2 using a simpler approach that avoids messing with the
> Master Interrupt Enable bit. As well as the ifdef problem, it turns out
> that v1 was not sufficient to entirely fix the problem.
>
> v3 avoids needless changes to the logic and locking in the suspend and
> shutdown code and tries to keep register writes closer to their original
> sequence.
>
> This patch has been tested on a PowerBook 520 but no PowerMacs yet.
>
>
> Index: linux-git/drivers/tty/serial/pmac_zilog.c
> ===================================================================
> --- linux-git.orig/drivers/tty/serial/pmac_zilog.c 2011-12-07 12:36:32.000000000 +1100
> +++ linux-git/drivers/tty/serial/pmac_zilog.c 2011-12-07 14:29:21.000000000 +1100
> @@ -216,6 +216,18 @@ static void pmz_maybe_update_regs(struct
> }
> }
>
> +static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
> +{
> + if (enable) {
> + uap->curregs[1] |= INT_ALL_Rx | TxINT_ENAB;
> + if (!ZS_IS_EXTCLK(uap))
> + uap->curregs[1] |= EXT_INT_ENAB;
> + } else {
> + uap->curregs[1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
> + }
> + write_zsreg(uap, R1, uap->curregs[1]);
> +}
> +
> static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
> {
> struct tty_struct *tty = NULL;
> @@ -339,9 +351,7 @@ static struct tty_struct *pmz_receive_ch
>
> return tty;
> flood:
> - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
> - write_zsreg(uap, R1, uap->curregs[R1]);
> - zssync(uap);
> + pmz_interrupt_control(uap, 0);
> pmz_error("pmz: rx irq flood !\n");
> return tty;
> }
> @@ -990,12 +1000,9 @@ static int pmz_startup(struct uart_port
> if (ZS_IS_IRDA(uap))
> pmz_irda_reset(uap);
>
> - /* Enable interrupts emission from the chip */
> + /* Enable interrupt requests for the channel */
> spin_lock_irqsave(&port->lock, flags);
> - uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
> - if (!ZS_IS_EXTCLK(uap))
> - uap->curregs[R1] |= EXT_INT_ENAB;
> - write_zsreg(uap, R1, uap->curregs[R1]);
> + pmz_interrupt_control(uap, 1);
> spin_unlock_irqrestore(&port->lock, flags);
>
> pmz_debug("pmz: startup() done.\n");
> @@ -1015,6 +1022,25 @@ static void pmz_shutdown(struct uart_por
>
> mutex_lock(&pmz_irq_mutex);
>
> + spin_lock_irqsave(&port->lock, flags);
> +
> + if (!ZS_IS_ASLEEP(uap)) {
> + /* Disable interrupt requests for the channel */
> + pmz_interrupt_control(uap, 0);
> +
> + if (!ZS_IS_CONS(uap)) {
> + /* Disable receiver and transmitter */
> + uap->curregs[R3] &= ~RxENABLE;
> + uap->curregs[R5] &= ~TxENABLE;
> +
> + /* Disable break assertion */
> + uap->curregs[R5] &= ~SND_BRK;
> + pmz_maybe_update_regs(uap);
> + }
> + }
> +
> + spin_unlock_irqrestore(&port->lock, flags);
> +
> /* Release interrupt handler */
> free_irq(uap->port.irq, uap);
>
> @@ -1025,29 +1051,8 @@ static void pmz_shutdown(struct uart_por
> if (!ZS_IS_OPEN(uap->mate))
> pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
>
> - /* Disable interrupts */
> - if (!ZS_IS_ASLEEP(uap)) {
> - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
> - write_zsreg(uap, R1, uap->curregs[R1]);
> - zssync(uap);
> - }
> -
> - if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
> - spin_unlock_irqrestore(&port->lock, flags);
> - mutex_unlock(&pmz_irq_mutex);
> - return;
> - }
> -
> - /* Disable receiver and transmitter. */
> - uap->curregs[R3] &= ~RxENABLE;
> - uap->curregs[R5] &= ~TxENABLE;
> -
> - /* Disable all interrupts and BRK assertion. */
> - uap->curregs[R5] &= ~SND_BRK;
> - pmz_maybe_update_regs(uap);
> -
> - /* Shut the chip down */
> - pmz_set_scc_power(uap, 0);
> + if (!ZS_IS_ASLEEP(uap) && !ZS_IS_CONS(uap))
> + pmz_set_scc_power(uap, 0); /* Shut the chip down */
>
> spin_unlock_irqrestore(&port->lock, flags);
>
> @@ -1352,19 +1357,15 @@ static void pmz_set_termios(struct uart_
> spin_lock_irqsave(&port->lock, flags);
>
> /* Disable IRQs on the port */
> - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
> - write_zsreg(uap, R1, uap->curregs[R1]);
> + pmz_interrupt_control(uap, 0);
>
> /* Setup new port configuration */
> __pmz_set_termios(port, termios, old);
>
> /* Re-enable IRQs on the port */
> - if (ZS_IS_OPEN(uap)) {
> - uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
> - if (!ZS_IS_EXTCLK(uap))
> - uap->curregs[R1] |= EXT_INT_ENAB;
> - write_zsreg(uap, R1, uap->curregs[R1]);
> - }
> + if (ZS_IS_OPEN(uap))
> + pmz_interrupt_control(uap, 1);
> +
> spin_unlock_irqrestore(&port->lock, flags);
> }
>
> @@ -1671,14 +1672,17 @@ static int pmz_suspend(struct macio_dev
> spin_lock_irqsave(&uap->port.lock, flags);
>
> if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
> - /* Disable receiver and transmitter. */
> + /* Disable interrupt requests for the channel */
> + pmz_interrupt_control(uap, 0);
> +
> + /* Disable receiver and transmitter */
> uap->curregs[R3] &= ~RxENABLE;
> uap->curregs[R5] &= ~TxENABLE;
>
> - /* Disable all interrupts and BRK assertion. */
> - uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
> + /* Disable break assertion */
> uap->curregs[R5] &= ~SND_BRK;
> pmz_load_zsregs(uap, uap->curregs);
> +
> uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
> mb();
> }
> @@ -1738,14 +1742,6 @@ static int pmz_resume(struct macio_dev *
> /* Take care of config that may have changed while asleep */
> __pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
>
> - if (ZS_IS_OPEN(uap)) {
> - /* Enable interrupts */
> - uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
> - if (!ZS_IS_EXTCLK(uap))
> - uap->curregs[R1] |= EXT_INT_ENAB;
> - write_zsreg(uap, R1, uap->curregs[R1]);
> - }
> -
> spin_unlock_irqrestore(&uap->port.lock, flags);
>
> if (ZS_IS_CONS(uap))
> @@ -1757,6 +1753,12 @@ static int pmz_resume(struct macio_dev *
> enable_irq(uap->port.irq);
> }
>
> + if (ZS_IS_OPEN(uap)) {
> + spin_lock_irqsave(&uap->port.lock, flags);
> + pmz_interrupt_control(uap, 1);
> + spin_unlock_irqrestore(&uap->port.lock, flags);
> + }
> +
> bail:
> mutex_unlock(&state->port.mutex);
> mutex_unlock(&pmz_irq_mutex);
^ permalink raw reply
* Re: RS-485 automatic RTS toggle in Linux (on Winbond W83627UHG)
From: Tomas Lastovicka @ 2011-12-07 11:58 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linux-serial
In-Reply-To: <CAFnDbmBN=TWzVfNhf41A441L3Fcq4u=MnkWKU7PD8LiK2UXcRg@mail.gmail.com>
Hi,
to conclude this thread: the Winbond W83627UHG, used in my brand new
device, really does not support the automatic RTS toggle for the
RS-485 line. Thus the most appropriate solution appears to be the RTS
toggling from within a driver.
Cheers,
Tomas
On Tue, Nov 29, 2011 at 6:15 PM, Tomas Lastovicka
<tomas.lastovicka@gmail.com> wrote:
> Thanks for both links Wolfram! I will find out what revision i actually have.
>
> Best,
> Tomas
>
>
> On Tue, Nov 29, 2011 at 5:36 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>> On Tue, Nov 29, 2011 at 05:25:32PM -0500, Tomas Lastovicka wrote:
>>
>>> Then i definitely have a different datasheet (v1.41). No 485 matches were found.
>>
>> I got v1.7:
>>
>> http://www.nuvoton.com/NuvotonMOSS/Community/ProductInfo.aspx?tp_GUID=8310ab06-af65-4ec9-92a6-17cf791aa9f2
>>
>> Ah, it says RS485 is only available on Revision E. Hopefully, you have that.
>>
>>> Indeed, if it has support then there is no need for software toggle
>>> (although i still think it is done this way in the Etrax driver coming
>>> with the kernel).
>>
>> I think that was the first RS485 one, so probably just lucky ;)
>>
>> If you are interested, another series adding support for 8250-variants that
>> have HW support can be found here:
>>
>> http://lkml.org/lkml/2011/11/16/270
>>
>> Regards,
>>
>> Wolfram
>>
>> --
>> Pengutronix e.K. | Wolfram Sang |
>> Industrial Linux Solutions | http://www.pengutronix.de/ |
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 01/16 v3] pmac_zilog: fix unexpected irq
From: Finn Thain @ 2011-12-07 3:49 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Benjamin Herrenschmidt, linux-m68k, linuxppc-dev, linux-serial
In-Reply-To: <alpine.LNX.2.00.1112070203310.14968@nippy.intranet>
On most 68k Macs the SCC IRQ is an autovector interrupt and cannot be
masked. This can be a problem when pmac_zilog starts up.
For example, the serial debugging code in arch/m68k/kernel/head.S may be
used beforehand. It disables the SCC interrupts at the chip but doesn't
ack them. Then when a pmac_zilog port is used, the machine locks up with
"unexpected interrupt".
This can happen in pmz_shutdown() since the irq is freed before the
channel interrupts are disabled.
Fix this by clearing interrupt enable bits before the handler is
uninstalled. Also move the interrupt control bit flipping into a separate
pmz_interrupt_control() routine. Replace all instances of these operations
with calls to this routine. Omit the zssync() calls that seem to serve no
purpose.
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Acked-by: Alan Cox <alan@linux.intel.com>
---
Re-implemented as v2 using a simpler approach that avoids messing with the
Master Interrupt Enable bit. As well as the ifdef problem, it turns out
that v1 was not sufficient to entirely fix the problem.
v3 avoids needless changes to the logic and locking in the suspend and
shutdown code and tries to keep register writes closer to their original
sequence.
This patch has been tested on a PowerBook 520 but no PowerMacs yet.
Index: linux-git/drivers/tty/serial/pmac_zilog.c
===================================================================
--- linux-git.orig/drivers/tty/serial/pmac_zilog.c 2011-12-07 12:36:32.000000000 +1100
+++ linux-git/drivers/tty/serial/pmac_zilog.c 2011-12-07 14:29:21.000000000 +1100
@@ -216,6 +216,18 @@ static void pmz_maybe_update_regs(struct
}
}
+static void pmz_interrupt_control(struct uart_pmac_port *uap, int enable)
+{
+ if (enable) {
+ uap->curregs[1] |= INT_ALL_Rx | TxINT_ENAB;
+ if (!ZS_IS_EXTCLK(uap))
+ uap->curregs[1] |= EXT_INT_ENAB;
+ } else {
+ uap->curregs[1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+ }
+ write_zsreg(uap, R1, uap->curregs[1]);
+}
+
static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_struct *tty = NULL;
@@ -339,9 +351,7 @@ static struct tty_struct *pmz_receive_ch
return tty;
flood:
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
- write_zsreg(uap, R1, uap->curregs[R1]);
- zssync(uap);
+ pmz_interrupt_control(uap, 0);
pmz_error("pmz: rx irq flood !\n");
return tty;
}
@@ -990,12 +1000,9 @@ static int pmz_startup(struct uart_port
if (ZS_IS_IRDA(uap))
pmz_irda_reset(uap);
- /* Enable interrupts emission from the chip */
+ /* Enable interrupt requests for the channel */
spin_lock_irqsave(&port->lock, flags);
- uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
- if (!ZS_IS_EXTCLK(uap))
- uap->curregs[R1] |= EXT_INT_ENAB;
- write_zsreg(uap, R1, uap->curregs[R1]);
+ pmz_interrupt_control(uap, 1);
spin_unlock_irqrestore(&port->lock, flags);
pmz_debug("pmz: startup() done.\n");
@@ -1015,6 +1022,25 @@ static void pmz_shutdown(struct uart_por
mutex_lock(&pmz_irq_mutex);
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (!ZS_IS_ASLEEP(uap)) {
+ /* Disable interrupt requests for the channel */
+ pmz_interrupt_control(uap, 0);
+
+ if (!ZS_IS_CONS(uap)) {
+ /* Disable receiver and transmitter */
+ uap->curregs[R3] &= ~RxENABLE;
+ uap->curregs[R5] &= ~TxENABLE;
+
+ /* Disable break assertion */
+ uap->curregs[R5] &= ~SND_BRK;
+ pmz_maybe_update_regs(uap);
+ }
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
/* Release interrupt handler */
free_irq(uap->port.irq, uap);
@@ -1025,29 +1051,8 @@ static void pmz_shutdown(struct uart_por
if (!ZS_IS_OPEN(uap->mate))
pmz_get_port_A(uap)->flags &= ~PMACZILOG_FLAG_IS_IRQ_ON;
- /* Disable interrupts */
- if (!ZS_IS_ASLEEP(uap)) {
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
- write_zsreg(uap, R1, uap->curregs[R1]);
- zssync(uap);
- }
-
- if (ZS_IS_CONS(uap) || ZS_IS_ASLEEP(uap)) {
- spin_unlock_irqrestore(&port->lock, flags);
- mutex_unlock(&pmz_irq_mutex);
- return;
- }
-
- /* Disable receiver and transmitter. */
- uap->curregs[R3] &= ~RxENABLE;
- uap->curregs[R5] &= ~TxENABLE;
-
- /* Disable all interrupts and BRK assertion. */
- uap->curregs[R5] &= ~SND_BRK;
- pmz_maybe_update_regs(uap);
-
- /* Shut the chip down */
- pmz_set_scc_power(uap, 0);
+ if (!ZS_IS_ASLEEP(uap) && !ZS_IS_CONS(uap))
+ pmz_set_scc_power(uap, 0); /* Shut the chip down */
spin_unlock_irqrestore(&port->lock, flags);
@@ -1352,19 +1357,15 @@ static void pmz_set_termios(struct uart_
spin_lock_irqsave(&port->lock, flags);
/* Disable IRQs on the port */
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
- write_zsreg(uap, R1, uap->curregs[R1]);
+ pmz_interrupt_control(uap, 0);
/* Setup new port configuration */
__pmz_set_termios(port, termios, old);
/* Re-enable IRQs on the port */
- if (ZS_IS_OPEN(uap)) {
- uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
- if (!ZS_IS_EXTCLK(uap))
- uap->curregs[R1] |= EXT_INT_ENAB;
- write_zsreg(uap, R1, uap->curregs[R1]);
- }
+ if (ZS_IS_OPEN(uap))
+ pmz_interrupt_control(uap, 1);
+
spin_unlock_irqrestore(&port->lock, flags);
}
@@ -1671,14 +1672,17 @@ static int pmz_suspend(struct macio_dev
spin_lock_irqsave(&uap->port.lock, flags);
if (ZS_IS_OPEN(uap) || ZS_IS_CONS(uap)) {
- /* Disable receiver and transmitter. */
+ /* Disable interrupt requests for the channel */
+ pmz_interrupt_control(uap, 0);
+
+ /* Disable receiver and transmitter */
uap->curregs[R3] &= ~RxENABLE;
uap->curregs[R5] &= ~TxENABLE;
- /* Disable all interrupts and BRK assertion. */
- uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
+ /* Disable break assertion */
uap->curregs[R5] &= ~SND_BRK;
pmz_load_zsregs(uap, uap->curregs);
+
uap->flags |= PMACZILOG_FLAG_IS_ASLEEP;
mb();
}
@@ -1738,14 +1742,6 @@ static int pmz_resume(struct macio_dev *
/* Take care of config that may have changed while asleep */
__pmz_set_termios(&uap->port, &uap->termios_cache, NULL);
- if (ZS_IS_OPEN(uap)) {
- /* Enable interrupts */
- uap->curregs[R1] |= INT_ALL_Rx | TxINT_ENAB;
- if (!ZS_IS_EXTCLK(uap))
- uap->curregs[R1] |= EXT_INT_ENAB;
- write_zsreg(uap, R1, uap->curregs[R1]);
- }
-
spin_unlock_irqrestore(&uap->port.lock, flags);
if (ZS_IS_CONS(uap))
@@ -1757,6 +1753,12 @@ static int pmz_resume(struct macio_dev *
enable_irq(uap->port.irq);
}
+ if (ZS_IS_OPEN(uap)) {
+ spin_lock_irqsave(&uap->port.lock, flags);
+ pmz_interrupt_control(uap, 1);
+ spin_unlock_irqrestore(&uap->port.lock, flags);
+ }
+
bail:
mutex_unlock(&state->port.mutex);
mutex_unlock(&pmz_irq_mutex);
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox