Merge branch 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* 'tty-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: serial: bcm63xx_uart: fix irq storm after rx fifo overrun. amba pl011: platform data for reg lockup and glitch v2 amba pl011: workaround for uart registers lockup tty: n_gsm: improper skb_pull() use was leaking framed data tty: n_gsm: Fixed logic to decode break signal from modem status TTY: ntty, add one more sanity check TTY: ldisc, do not close until there are readers 8250: Fix capabilities when changing the port type 8250_pci: Fix missing const from merges ARM: SAMSUNG: serial: Fix on handling of one clock source for UART serial: ioremap warning fix for jsm driver. 8250_pci: add -ENODEV code for Intel EG20T PCH
This commit is contained in:
@@ -35,6 +35,7 @@ void __init exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
|
|||||||
tcfg->clocks = exynos4_serial_clocks;
|
tcfg->clocks = exynos4_serial_clocks;
|
||||||
tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks);
|
tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks);
|
||||||
}
|
}
|
||||||
|
tcfg->flags |= NO_NEED_CHECK_CLKSRC;
|
||||||
}
|
}
|
||||||
|
|
||||||
s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no);
|
s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no);
|
||||||
|
@@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = {
|
|||||||
GPIO168_KP_O0,
|
GPIO168_KP_O0,
|
||||||
|
|
||||||
/* UART */
|
/* UART */
|
||||||
GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
|
/* uart-0 pins gpio configuration should be
|
||||||
GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
|
* kept intact to prevent glitch in tx line
|
||||||
GPIO2_U0_RXD | PIN_INPUT_PULLUP,
|
* when tty dev is opened. Later these pins
|
||||||
GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
|
* are configured to uart mop500_pins_uart0
|
||||||
|
*
|
||||||
|
* It will be replaced with uart configuration
|
||||||
|
* once the issue is solved.
|
||||||
|
*/
|
||||||
|
GPIO0_GPIO | PIN_INPUT_PULLUP,
|
||||||
|
GPIO1_GPIO | PIN_OUTPUT_HIGH,
|
||||||
|
GPIO2_GPIO | PIN_INPUT_PULLUP,
|
||||||
|
GPIO3_GPIO | PIN_OUTPUT_HIGH,
|
||||||
|
|
||||||
GPIO29_U2_RXD | PIN_INPUT_PULLUP,
|
GPIO29_U2_RXD | PIN_INPUT_PULLUP,
|
||||||
GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
|
GPIO30_U2_TXD | PIN_OUTPUT_HIGH,
|
||||||
|
@@ -27,18 +27,21 @@
|
|||||||
#include <linux/leds-lp5521.h>
|
#include <linux/leds-lp5521.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/gpio_keys.h>
|
#include <linux/gpio_keys.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include <asm/mach-types.h>
|
#include <asm/mach-types.h>
|
||||||
#include <asm/mach/arch.h>
|
#include <asm/mach/arch.h>
|
||||||
|
|
||||||
#include <plat/i2c.h>
|
#include <plat/i2c.h>
|
||||||
#include <plat/ste_dma40.h>
|
#include <plat/ste_dma40.h>
|
||||||
|
#include <plat/pincfg.h>
|
||||||
|
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
#include <mach/setup.h>
|
#include <mach/setup.h>
|
||||||
#include <mach/devices.h>
|
#include <mach/devices.h>
|
||||||
#include <mach/irqs.h>
|
#include <mach/irqs.h>
|
||||||
|
|
||||||
|
#include "pins-db8500.h"
|
||||||
#include "ste-dma40-db8500.h"
|
#include "ste-dma40-db8500.h"
|
||||||
#include "devices-db8500.h"
|
#include "devices-db8500.h"
|
||||||
#include "board-mop500.h"
|
#include "board-mop500.h"
|
||||||
@@ -393,12 +396,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static pin_cfg_t mop500_pins_uart0[] = {
|
||||||
|
GPIO0_U0_CTSn | PIN_INPUT_PULLUP,
|
||||||
|
GPIO1_U0_RTSn | PIN_OUTPUT_HIGH,
|
||||||
|
GPIO2_U0_RXD | PIN_INPUT_PULLUP,
|
||||||
|
GPIO3_U0_TXD | PIN_OUTPUT_HIGH,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PRCC_K_SOFTRST_SET 0x18
|
||||||
|
#define PRCC_K_SOFTRST_CLEAR 0x1C
|
||||||
|
static void ux500_uart0_reset(void)
|
||||||
|
{
|
||||||
|
void __iomem *prcc_rst_set, *prcc_rst_clr;
|
||||||
|
|
||||||
|
prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
|
||||||
|
PRCC_K_SOFTRST_SET);
|
||||||
|
prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE +
|
||||||
|
PRCC_K_SOFTRST_CLEAR);
|
||||||
|
|
||||||
|
/* Activate soft reset PRCC_K_SOFTRST_CLEAR */
|
||||||
|
writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr);
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
/* Release soft reset PRCC_K_SOFTRST_SET */
|
||||||
|
writel((readl(prcc_rst_set) | 0x1), prcc_rst_set);
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ux500_uart0_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nmk_config_pins(mop500_pins_uart0,
|
||||||
|
ARRAY_SIZE(mop500_pins_uart0));
|
||||||
|
if (ret < 0)
|
||||||
|
pr_err("pl011: uart pins_enable failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ux500_uart0_exit(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = nmk_config_pins_sleep(mop500_pins_uart0,
|
||||||
|
ARRAY_SIZE(mop500_pins_uart0));
|
||||||
|
if (ret < 0)
|
||||||
|
pr_err("pl011: uart pins_disable failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
static struct amba_pl011_data uart0_plat = {
|
static struct amba_pl011_data uart0_plat = {
|
||||||
#ifdef CONFIG_STE_DMA40
|
#ifdef CONFIG_STE_DMA40
|
||||||
.dma_filter = stedma40_filter,
|
.dma_filter = stedma40_filter,
|
||||||
.dma_rx_param = &uart0_dma_cfg_rx,
|
.dma_rx_param = &uart0_dma_cfg_rx,
|
||||||
.dma_tx_param = &uart0_dma_cfg_tx,
|
.dma_tx_param = &uart0_dma_cfg_tx,
|
||||||
#endif
|
#endif
|
||||||
|
.init = ux500_uart0_init,
|
||||||
|
.exit = ux500_uart0_exit,
|
||||||
|
.reset = ux500_uart0_reset,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct amba_pl011_data uart1_plat = {
|
static struct amba_pl011_data uart1_plat = {
|
||||||
|
@@ -224,6 +224,8 @@
|
|||||||
#define S5PV210_UFSTAT_RXMASK (255<<0)
|
#define S5PV210_UFSTAT_RXMASK (255<<0)
|
||||||
#define S5PV210_UFSTAT_RXSHIFT (0)
|
#define S5PV210_UFSTAT_RXSHIFT (0)
|
||||||
|
|
||||||
|
#define NO_NEED_CHECK_CLKSRC 1
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
/* struct s3c24xx_uart_clksrc
|
/* struct s3c24xx_uart_clksrc
|
||||||
|
@@ -875,7 +875,8 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
|
|||||||
*dp++ = last << 7 | first << 6 | 1; /* EA */
|
*dp++ = last << 7 | first << 6 | 1; /* EA */
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
memcpy(dp, skb_pull(dlci->skb, len), len);
|
memcpy(dp, dlci->skb->data, len);
|
||||||
|
skb_pull(dlci->skb, len);
|
||||||
__gsm_data_queue(dlci, msg);
|
__gsm_data_queue(dlci, msg);
|
||||||
if (last)
|
if (last)
|
||||||
dlci->skb = NULL;
|
dlci->skb = NULL;
|
||||||
@@ -984,10 +985,22 @@ static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
|
||||||
u32 modem)
|
u32 modem, int clen)
|
||||||
{
|
{
|
||||||
int mlines = 0;
|
int mlines = 0;
|
||||||
u8 brk = modem >> 6;
|
u8 brk = 0;
|
||||||
|
|
||||||
|
/* The modem status command can either contain one octet (v.24 signals)
|
||||||
|
or two octets (v.24 signals + break signals). The length field will
|
||||||
|
either be 2 or 3 respectively. This is specified in section
|
||||||
|
5.4.6.3.7 of the 27.010 mux spec. */
|
||||||
|
|
||||||
|
if (clen == 2)
|
||||||
|
modem = modem & 0x7f;
|
||||||
|
else {
|
||||||
|
brk = modem & 0x7f;
|
||||||
|
modem = (modem >> 7) & 0x7f;
|
||||||
|
};
|
||||||
|
|
||||||
/* Flow control/ready to communicate */
|
/* Flow control/ready to communicate */
|
||||||
if (modem & MDM_FC) {
|
if (modem & MDM_FC) {
|
||||||
@@ -1061,7 +1074,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tty = tty_port_tty_get(&dlci->port);
|
tty = tty_port_tty_get(&dlci->port);
|
||||||
gsm_process_modem(tty, dlci, modem);
|
gsm_process_modem(tty, dlci, modem, clen);
|
||||||
if (tty) {
|
if (tty) {
|
||||||
tty_wakeup(tty);
|
tty_wakeup(tty);
|
||||||
tty_kref_put(tty);
|
tty_kref_put(tty);
|
||||||
@@ -1482,12 +1495,13 @@ static void gsm_dlci_begin_close(struct gsm_dlci *dlci)
|
|||||||
* open we shovel the bits down it, if not we drop them.
|
* open we shovel the bits down it, if not we drop them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
|
static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen)
|
||||||
{
|
{
|
||||||
/* krefs .. */
|
/* krefs .. */
|
||||||
struct tty_port *port = &dlci->port;
|
struct tty_port *port = &dlci->port;
|
||||||
struct tty_struct *tty = tty_port_tty_get(port);
|
struct tty_struct *tty = tty_port_tty_get(port);
|
||||||
unsigned int modem = 0;
|
unsigned int modem = 0;
|
||||||
|
int len = clen;
|
||||||
|
|
||||||
if (debug & 16)
|
if (debug & 16)
|
||||||
pr_debug("%d bytes for tty %p\n", len, tty);
|
pr_debug("%d bytes for tty %p\n", len, tty);
|
||||||
@@ -1507,7 +1521,7 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
gsm_process_modem(tty, dlci, modem);
|
gsm_process_modem(tty, dlci, modem, clen);
|
||||||
/* Line state will go via DLCI 0 controls only */
|
/* Line state will go via DLCI 0 controls only */
|
||||||
case 1:
|
case 1:
|
||||||
default:
|
default:
|
||||||
|
@@ -1815,6 +1815,7 @@ do_it_again:
|
|||||||
/* FIXME: does n_tty_set_room need locking ? */
|
/* FIXME: does n_tty_set_room need locking ? */
|
||||||
n_tty_set_room(tty);
|
n_tty_set_room(tty);
|
||||||
timeout = schedule_timeout(timeout);
|
timeout = schedule_timeout(timeout);
|
||||||
|
BUG_ON(!tty->read_buf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
__set_current_state(TASK_RUNNING);
|
__set_current_state(TASK_RUNNING);
|
||||||
|
@@ -3318,6 +3318,7 @@ void serial8250_unregister_port(int line)
|
|||||||
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
|
uart->port.flags &= ~UPF_BOOT_AUTOCONF;
|
||||||
uart->port.type = PORT_UNKNOWN;
|
uart->port.type = PORT_UNKNOWN;
|
||||||
uart->port.dev = &serial8250_isa_devs->dev;
|
uart->port.dev = &serial8250_isa_devs->dev;
|
||||||
|
uart->capabilities = uart_config[uart->port.type].flags;
|
||||||
uart_add_one_port(&serial8250_reg, &uart->port);
|
uart_add_one_port(&serial8250_reg, &uart->port);
|
||||||
} else {
|
} else {
|
||||||
uart->port.dev = NULL;
|
uart->port.dev = NULL;
|
||||||
|
@@ -994,6 +994,15 @@ static int skip_tx_en_setup(struct serial_private *priv,
|
|||||||
return pci_default_setup(priv, board, port, idx);
|
return pci_default_setup(priv, board, port, idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pci_eg20t_init(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
#if defined(CONFIG_SERIAL_PCH_UART) || defined(CONFIG_SERIAL_PCH_UART_MODULE)
|
||||||
|
return -ENODEV;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* This should be in linux/pci_ids.h */
|
/* This should be in linux/pci_ids.h */
|
||||||
#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
|
#define PCI_VENDOR_ID_SBSMODULARIO 0x124B
|
||||||
#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
|
#define PCI_SUBVENDOR_ID_SBSMODULARIO 0x124B
|
||||||
@@ -1446,6 +1455,56 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
|
|||||||
.init = pci_oxsemi_tornado_init,
|
.init = pci_oxsemi_tornado_init,
|
||||||
.setup = pci_default_setup,
|
.setup = pci_default_setup,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.vendor = PCI_VENDOR_ID_INTEL,
|
||||||
|
.device = 0x8811,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = PCI_VENDOR_ID_INTEL,
|
||||||
|
.device = 0x8812,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = PCI_VENDOR_ID_INTEL,
|
||||||
|
.device = 0x8813,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = PCI_VENDOR_ID_INTEL,
|
||||||
|
.device = 0x8814,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = 0x10DB,
|
||||||
|
.device = 0x8027,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = 0x10DB,
|
||||||
|
.device = 0x8028,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = 0x10DB,
|
||||||
|
.device = 0x8029,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = 0x10DB,
|
||||||
|
.device = 0x800C,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = 0x10DB,
|
||||||
|
.device = 0x800D,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.vendor = 0x10DB,
|
||||||
|
.device = 0x800D,
|
||||||
|
.init = pci_eg20t_init,
|
||||||
|
},
|
||||||
/*
|
/*
|
||||||
* Cronyx Omega PCI (PLX-chip based)
|
* Cronyx Omega PCI (PLX-chip based)
|
||||||
*/
|
*/
|
||||||
|
@@ -50,6 +50,7 @@
|
|||||||
#include <linux/dmaengine.h>
|
#include <linux/dmaengine.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/sizes.h>
|
#include <asm/sizes.h>
|
||||||
@@ -65,6 +66,30 @@
|
|||||||
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
|
#define UART_DR_ERROR (UART011_DR_OE|UART011_DR_BE|UART011_DR_PE|UART011_DR_FE)
|
||||||
#define UART_DUMMY_DR_RX (1 << 16)
|
#define UART_DUMMY_DR_RX (1 << 16)
|
||||||
|
|
||||||
|
|
||||||
|
#define UART_WA_SAVE_NR 14
|
||||||
|
|
||||||
|
static void pl011_lockup_wa(unsigned long data);
|
||||||
|
static const u32 uart_wa_reg[UART_WA_SAVE_NR] = {
|
||||||
|
ST_UART011_DMAWM,
|
||||||
|
ST_UART011_TIMEOUT,
|
||||||
|
ST_UART011_LCRH_RX,
|
||||||
|
UART011_IBRD,
|
||||||
|
UART011_FBRD,
|
||||||
|
ST_UART011_LCRH_TX,
|
||||||
|
UART011_IFLS,
|
||||||
|
ST_UART011_XFCR,
|
||||||
|
ST_UART011_XON1,
|
||||||
|
ST_UART011_XON2,
|
||||||
|
ST_UART011_XOFF1,
|
||||||
|
ST_UART011_XOFF2,
|
||||||
|
UART011_CR,
|
||||||
|
UART011_IMSC
|
||||||
|
};
|
||||||
|
|
||||||
|
static u32 uart_wa_regdata[UART_WA_SAVE_NR];
|
||||||
|
static DECLARE_TASKLET(pl011_lockup_tlet, pl011_lockup_wa, 0);
|
||||||
|
|
||||||
/* There is by now at least one vendor with differing details, so handle it */
|
/* There is by now at least one vendor with differing details, so handle it */
|
||||||
struct vendor_data {
|
struct vendor_data {
|
||||||
unsigned int ifls;
|
unsigned int ifls;
|
||||||
@@ -72,6 +97,7 @@ struct vendor_data {
|
|||||||
unsigned int lcrh_tx;
|
unsigned int lcrh_tx;
|
||||||
unsigned int lcrh_rx;
|
unsigned int lcrh_rx;
|
||||||
bool oversampling;
|
bool oversampling;
|
||||||
|
bool interrupt_may_hang; /* vendor-specific */
|
||||||
bool dma_threshold;
|
bool dma_threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -90,9 +116,12 @@ static struct vendor_data vendor_st = {
|
|||||||
.lcrh_tx = ST_UART011_LCRH_TX,
|
.lcrh_tx = ST_UART011_LCRH_TX,
|
||||||
.lcrh_rx = ST_UART011_LCRH_RX,
|
.lcrh_rx = ST_UART011_LCRH_RX,
|
||||||
.oversampling = true,
|
.oversampling = true,
|
||||||
|
.interrupt_may_hang = true,
|
||||||
.dma_threshold = true,
|
.dma_threshold = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct uart_amba_port *amba_ports[UART_NR];
|
||||||
|
|
||||||
/* Deals with DMA transactions */
|
/* Deals with DMA transactions */
|
||||||
|
|
||||||
struct pl011_sgbuf {
|
struct pl011_sgbuf {
|
||||||
@@ -132,6 +161,7 @@ struct uart_amba_port {
|
|||||||
unsigned int lcrh_rx; /* vendor-specific */
|
unsigned int lcrh_rx; /* vendor-specific */
|
||||||
bool autorts;
|
bool autorts;
|
||||||
char type[12];
|
char type[12];
|
||||||
|
bool interrupt_may_hang; /* vendor-specific */
|
||||||
#ifdef CONFIG_DMA_ENGINE
|
#ifdef CONFIG_DMA_ENGINE
|
||||||
/* DMA stuff */
|
/* DMA stuff */
|
||||||
bool using_tx_dma;
|
bool using_tx_dma;
|
||||||
@@ -1008,6 +1038,68 @@ static inline bool pl011_dma_rx_running(struct uart_amba_port *uap)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pl011_lockup_wa
|
||||||
|
* This workaround aims to break the deadlock situation
|
||||||
|
* when after long transfer over uart in hardware flow
|
||||||
|
* control, uart interrupt registers cannot be cleared.
|
||||||
|
* Hence uart transfer gets blocked.
|
||||||
|
*
|
||||||
|
* It is seen that during such deadlock condition ICR
|
||||||
|
* don't get cleared even on multiple write. This leads
|
||||||
|
* pass_counter to decrease and finally reach zero. This
|
||||||
|
* can be taken as trigger point to run this UART_BT_WA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void pl011_lockup_wa(unsigned long data)
|
||||||
|
{
|
||||||
|
struct uart_amba_port *uap = amba_ports[0];
|
||||||
|
void __iomem *base = uap->port.membase;
|
||||||
|
struct circ_buf *xmit = &uap->port.state->xmit;
|
||||||
|
struct tty_struct *tty = uap->port.state->port.tty;
|
||||||
|
int buf_empty_retries = 200;
|
||||||
|
int loop;
|
||||||
|
|
||||||
|
/* Stop HCI layer from submitting data for tx */
|
||||||
|
tty->hw_stopped = 1;
|
||||||
|
while (!uart_circ_empty(xmit)) {
|
||||||
|
if (buf_empty_retries-- == 0)
|
||||||
|
break;
|
||||||
|
udelay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Backup registers */
|
||||||
|
for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
|
||||||
|
uart_wa_regdata[loop] = readl(base + uart_wa_reg[loop]);
|
||||||
|
|
||||||
|
/* Disable UART so that FIFO data is flushed out */
|
||||||
|
writew(0x00, uap->port.membase + UART011_CR);
|
||||||
|
|
||||||
|
/* Soft reset UART module */
|
||||||
|
if (uap->port.dev->platform_data) {
|
||||||
|
struct amba_pl011_data *plat;
|
||||||
|
|
||||||
|
plat = uap->port.dev->platform_data;
|
||||||
|
if (plat->reset)
|
||||||
|
plat->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore registers */
|
||||||
|
for (loop = 0; loop < UART_WA_SAVE_NR; loop++)
|
||||||
|
writew(uart_wa_regdata[loop] ,
|
||||||
|
uap->port.membase + uart_wa_reg[loop]);
|
||||||
|
|
||||||
|
/* Initialise the old status of the modem signals */
|
||||||
|
uap->old_status = readw(uap->port.membase + UART01x_FR) &
|
||||||
|
UART01x_FR_MODEM_ANY;
|
||||||
|
|
||||||
|
if (readl(base + UART011_MIS) & 0x2)
|
||||||
|
printk(KERN_EMERG "UART_BT_WA: ***FAILED***\n");
|
||||||
|
|
||||||
|
/* Start Tx/Rx */
|
||||||
|
tty->hw_stopped = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void pl011_stop_tx(struct uart_port *port)
|
static void pl011_stop_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
struct uart_amba_port *uap = (struct uart_amba_port *)port;
|
||||||
@@ -1158,8 +1250,11 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
|
|||||||
if (status & UART011_TXIS)
|
if (status & UART011_TXIS)
|
||||||
pl011_tx_chars(uap);
|
pl011_tx_chars(uap);
|
||||||
|
|
||||||
if (pass_counter-- == 0)
|
if (pass_counter-- == 0) {
|
||||||
|
if (uap->interrupt_may_hang)
|
||||||
|
tasklet_schedule(&pl011_lockup_tlet);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
status = readw(uap->port.membase + UART011_MIS);
|
status = readw(uap->port.membase + UART011_MIS);
|
||||||
} while (status != 0);
|
} while (status != 0);
|
||||||
@@ -1339,6 +1434,14 @@ static int pl011_startup(struct uart_port *port)
|
|||||||
writew(uap->im, uap->port.membase + UART011_IMSC);
|
writew(uap->im, uap->port.membase + UART011_IMSC);
|
||||||
spin_unlock_irq(&uap->port.lock);
|
spin_unlock_irq(&uap->port.lock);
|
||||||
|
|
||||||
|
if (uap->port.dev->platform_data) {
|
||||||
|
struct amba_pl011_data *plat;
|
||||||
|
|
||||||
|
plat = uap->port.dev->platform_data;
|
||||||
|
if (plat->init)
|
||||||
|
plat->init();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clk_dis:
|
clk_dis:
|
||||||
@@ -1394,6 +1497,15 @@ static void pl011_shutdown(struct uart_port *port)
|
|||||||
* Shut down the clock producer
|
* Shut down the clock producer
|
||||||
*/
|
*/
|
||||||
clk_disable(uap->clk);
|
clk_disable(uap->clk);
|
||||||
|
|
||||||
|
if (uap->port.dev->platform_data) {
|
||||||
|
struct amba_pl011_data *plat;
|
||||||
|
|
||||||
|
plat = uap->port.dev->platform_data;
|
||||||
|
if (plat->exit)
|
||||||
|
plat->exit();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1700,6 +1812,14 @@ static int __init pl011_console_setup(struct console *co, char *options)
|
|||||||
if (!uap)
|
if (!uap)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (uap->port.dev->platform_data) {
|
||||||
|
struct amba_pl011_data *plat;
|
||||||
|
|
||||||
|
plat = uap->port.dev->platform_data;
|
||||||
|
if (plat->init)
|
||||||
|
plat->init();
|
||||||
|
}
|
||||||
|
|
||||||
uap->port.uartclk = clk_get_rate(uap->clk);
|
uap->port.uartclk = clk_get_rate(uap->clk);
|
||||||
|
|
||||||
if (options)
|
if (options)
|
||||||
@@ -1774,6 +1894,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
|
|||||||
uap->lcrh_rx = vendor->lcrh_rx;
|
uap->lcrh_rx = vendor->lcrh_rx;
|
||||||
uap->lcrh_tx = vendor->lcrh_tx;
|
uap->lcrh_tx = vendor->lcrh_tx;
|
||||||
uap->fifosize = vendor->fifosize;
|
uap->fifosize = vendor->fifosize;
|
||||||
|
uap->interrupt_may_hang = vendor->interrupt_may_hang;
|
||||||
uap->port.dev = &dev->dev;
|
uap->port.dev = &dev->dev;
|
||||||
uap->port.mapbase = dev->res.start;
|
uap->port.mapbase = dev->res.start;
|
||||||
uap->port.membase = base;
|
uap->port.membase = base;
|
||||||
|
@@ -250,6 +250,20 @@ static void bcm_uart_do_rx(struct uart_port *port)
|
|||||||
/* get overrun/fifo empty information from ier
|
/* get overrun/fifo empty information from ier
|
||||||
* register */
|
* register */
|
||||||
iestat = bcm_uart_readl(port, UART_IR_REG);
|
iestat = bcm_uart_readl(port, UART_IR_REG);
|
||||||
|
|
||||||
|
if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
/* fifo reset is required to clear
|
||||||
|
* interrupt */
|
||||||
|
val = bcm_uart_readl(port, UART_CTL_REG);
|
||||||
|
val |= UART_CTL_RSTRXFIFO_MASK;
|
||||||
|
bcm_uart_writel(port, val, UART_CTL_REG);
|
||||||
|
|
||||||
|
port->icount.overrun++;
|
||||||
|
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
||||||
|
}
|
||||||
|
|
||||||
if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
|
if (!(iestat & UART_IR_STAT(UART_IR_RXNOTEMPTY)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -284,10 +298,6 @@ static void bcm_uart_do_rx(struct uart_port *port)
|
|||||||
if (uart_handle_sysrq_char(port, c))
|
if (uart_handle_sysrq_char(port, c))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (unlikely(iestat & UART_IR_STAT(UART_IR_RXOVER))) {
|
|
||||||
port->icount.overrun++;
|
|
||||||
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((cstat & port->ignore_status_mask) == 0)
|
if ((cstat & port->ignore_status_mask) == 0)
|
||||||
tty_insert_flip_char(tty, c, flag);
|
tty_insert_flip_char(tty, c, flag);
|
||||||
|
@@ -125,7 +125,7 @@ static int __devinit jsm_probe_one(struct pci_dev *pdev, const struct pci_device
|
|||||||
brd->bd_uart_offset = 0x200;
|
brd->bd_uart_offset = 0x200;
|
||||||
brd->bd_dividend = 921600;
|
brd->bd_dividend = 921600;
|
||||||
|
|
||||||
brd->re_map_membase = ioremap(brd->membase, 0x1000);
|
brd->re_map_membase = ioremap(brd->membase, pci_resource_len(pdev, 0));
|
||||||
if (!brd->re_map_membase) {
|
if (!brd->re_map_membase) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"card has no PCI Memory resources, "
|
"card has no PCI Memory resources, "
|
||||||
|
@@ -30,7 +30,7 @@ static int s5pv210_serial_setsource(struct uart_port *port,
|
|||||||
struct s3c2410_uartcfg *cfg = port->dev->platform_data;
|
struct s3c2410_uartcfg *cfg = port->dev->platform_data;
|
||||||
unsigned long ucon = rd_regl(port, S3C2410_UCON);
|
unsigned long ucon = rd_regl(port, S3C2410_UCON);
|
||||||
|
|
||||||
if ((cfg->clocks_size) == 1)
|
if (cfg->flags & NO_NEED_CHECK_CLKSRC)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (strcmp(clk->name, "pclk") == 0)
|
if (strcmp(clk->name, "pclk") == 0)
|
||||||
@@ -55,7 +55,7 @@ static int s5pv210_serial_getsource(struct uart_port *port,
|
|||||||
|
|
||||||
clk->divisor = 1;
|
clk->divisor = 1;
|
||||||
|
|
||||||
if ((cfg->clocks_size) == 1)
|
if (cfg->flags & NO_NEED_CHECK_CLKSRC)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (ucon & S5PV210_UCON_CLKMASK) {
|
switch (ucon & S5PV210_UCON_CLKMASK) {
|
||||||
|
@@ -555,7 +555,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty)
|
|||||||
static int tty_ldisc_wait_idle(struct tty_struct *tty)
|
static int tty_ldisc_wait_idle(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
ret = wait_event_interruptible_timeout(tty_ldisc_idle,
|
ret = wait_event_timeout(tty_ldisc_idle,
|
||||||
atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
|
atomic_read(&tty->ldisc->users) == 1, 5 * HZ);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
@@ -763,6 +763,8 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc)
|
|||||||
if (IS_ERR(ld))
|
if (IS_ERR(ld))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
WARN_ON_ONCE(tty_ldisc_wait_idle(tty));
|
||||||
|
|
||||||
tty_ldisc_close(tty, tty->ldisc);
|
tty_ldisc_close(tty, tty->ldisc);
|
||||||
tty_ldisc_put(tty->ldisc);
|
tty_ldisc_put(tty->ldisc);
|
||||||
tty->ldisc = NULL;
|
tty->ldisc = NULL;
|
||||||
|
@@ -201,6 +201,9 @@ struct amba_pl011_data {
|
|||||||
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
|
bool (*dma_filter)(struct dma_chan *chan, void *filter_param);
|
||||||
void *dma_rx_param;
|
void *dma_rx_param;
|
||||||
void *dma_tx_param;
|
void *dma_tx_param;
|
||||||
|
void (*init) (void);
|
||||||
|
void (*exit) (void);
|
||||||
|
void (*reset) (void);
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user