aboutsummaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/8250.c225
-rw-r--r--drivers/serial/8250_pci.c134
-rw-r--r--drivers/serial/Kconfig25
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/amba-pl010.c2
-rw-r--r--drivers/serial/amba-pl011.c2
-rw-r--r--drivers/serial/bfin_5xx.c239
-rw-r--r--drivers/serial/bfin_sport_uart.c60
-rw-r--r--drivers/serial/imx.c8
-rw-r--r--drivers/serial/jsm/jsm_tty.c2
-rw-r--r--drivers/serial/pxa.c3
-rw-r--r--drivers/serial/s3c24a0.c118
-rw-r--r--drivers/serial/s3c6400.c151
-rw-r--r--drivers/serial/samsung.c184
-rw-r--r--drivers/serial/samsung.h9
-rw-r--r--drivers/serial/serial_core.c155
-rw-r--r--drivers/serial/serial_lh7a40x.c3
17 files changed, 928 insertions, 394 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 303272af386e..daa00567bc44 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -279,6 +279,13 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO,
},
+ [PORT_OCTEON] = {
+ .name = "OCTEON",
+ .fifo_size = 64,
+ .tx_loadsz = 64,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+ .flags = UART_CAP_FIFO,
+ },
};
#if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -303,16 +310,16 @@ static const u8 au_io_out_map[] = {
};
/* sane hardware needs no mapping */
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_AU)
+ if (p->iotype != UPIO_AU)
return offset;
return au_io_in_map[offset];
}
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_AU)
+ if (p->iotype != UPIO_AU)
return offset;
return au_io_out_map[offset];
}
@@ -341,16 +348,16 @@ static const u8
[UART_SCR] = 0x2c
};
-static inline int map_8250_in_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_in_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_RM9000)
+ if (p->iotype != UPIO_RM9000)
return offset;
return regmap_in[offset];
}
-static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
+static inline int map_8250_out_reg(struct uart_port *p, int offset)
{
- if (up->port.iotype != UPIO_RM9000)
+ if (p->iotype != UPIO_RM9000)
return offset;
return regmap_out[offset];
}
@@ -363,108 +370,170 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
#endif
-static unsigned int serial_in(struct uart_8250_port *up, int offset)
+static unsigned int hub6_serial_in(struct uart_port *p, int offset)
{
- unsigned int tmp;
- offset = map_8250_in_reg(up, offset) << up->port.regshift;
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ outb(p->hub6 - 1 + offset, p->iobase);
+ return inb(p->iobase + 1);
+}
- switch (up->port.iotype) {
- case UPIO_HUB6:
- outb(up->port.hub6 - 1 + offset, up->port.iobase);
- return inb(up->port.iobase + 1);
+static void hub6_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ outb(p->hub6 - 1 + offset, p->iobase);
+ outb(value, p->iobase + 1);
+}
- case UPIO_MEM:
- case UPIO_DWAPB:
- return readb(up->port.membase + offset);
+static unsigned int mem_serial_in(struct uart_port *p, int offset)
+{
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ return readb(p->membase + offset);
+}
- case UPIO_RM9000:
- case UPIO_MEM32:
- return readl(up->port.membase + offset);
+static void mem_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ writeb(value, p->membase + offset);
+}
+
+static void mem32_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ writel(value, p->membase + offset);
+}
+
+static unsigned int mem32_serial_in(struct uart_port *p, int offset)
+{
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ return readl(p->membase + offset);
+}
#ifdef CONFIG_SERIAL_8250_AU1X00
- case UPIO_AU:
- return __raw_readl(up->port.membase + offset);
+static unsigned int au_serial_in(struct uart_port *p, int offset)
+{
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ return __raw_readl(p->membase + offset);
+}
+
+static void au_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ __raw_writel(value, p->membase + offset);
+}
#endif
- case UPIO_TSI:
- if (offset == UART_IIR) {
- tmp = readl(up->port.membase + (UART_IIR & ~3));
- return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
- } else
- return readb(up->port.membase + offset);
+static unsigned int tsi_serial_in(struct uart_port *p, int offset)
+{
+ unsigned int tmp;
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ if (offset == UART_IIR) {
+ tmp = readl(p->membase + (UART_IIR & ~3));
+ return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
+ } else
+ return readb(p->membase + offset);
+}
- default:
- return inb(up->port.iobase + offset);
- }
+static void tsi_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+ writeb(value, p->membase + offset);
}
-static void
-serial_out(struct uart_8250_port *up, int offset, int value)
+static void dwapb_serial_out(struct uart_port *p, int offset, int value)
{
- /* Save the offset before it's remapped */
int save_offset = offset;
- offset = map_8250_out_reg(up, offset) << up->port.regshift;
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ /* Save the LCR value so it can be re-written when a
+ * Busy Detect interrupt occurs. */
+ if (save_offset == UART_LCR) {
+ struct uart_8250_port *up = (struct uart_8250_port *)p;
+ up->lcr = value;
+ }
+ writeb(value, p->membase + offset);
+ /* Read the IER to ensure any interrupt is cleared before
+ * returning from ISR. */
+ if (save_offset == UART_TX || save_offset == UART_IER)
+ value = p->serial_in(p, UART_IER);
+}
- switch (up->port.iotype) {
+static unsigned int io_serial_in(struct uart_port *p, int offset)
+{
+ offset = map_8250_in_reg(p, offset) << p->regshift;
+ return inb(p->iobase + offset);
+}
+
+static void io_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = map_8250_out_reg(p, offset) << p->regshift;
+ outb(value, p->iobase + offset);
+}
+
+static void set_io_from_upio(struct uart_port *p)
+{
+ switch (p->iotype) {
case UPIO_HUB6:
- outb(up->port.hub6 - 1 + offset, up->port.iobase);
- outb(value, up->port.iobase + 1);
+ p->serial_in = hub6_serial_in;
+ p->serial_out = hub6_serial_out;
break;
case UPIO_MEM:
- writeb(value, up->port.membase + offset);
+ p->serial_in = mem_serial_in;
+ p->serial_out = mem_serial_out;
break;
case UPIO_RM9000:
case UPIO_MEM32:
- writel(value, up->port.membase + offset);
+ p->serial_in = mem32_serial_in;
+ p->serial_out = mem32_serial_out;
break;
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
- __raw_writel(value, up->port.membase + offset);
+ p->serial_in = au_serial_in;
+ p->serial_out = au_serial_out;
break;
#endif
case UPIO_TSI:
- if (!((offset == UART_IER) && (value & UART_IER_UUE)))
- writeb(value, up->port.membase + offset);
+ p->serial_in = tsi_serial_in;
+ p->serial_out = tsi_serial_out;
break;
case UPIO_DWAPB:
- /* Save the LCR value so it can be re-written when a
- * Busy Detect interrupt occurs. */
- if (save_offset == UART_LCR)
- up->lcr = value;
- writeb(value, up->port.membase + offset);
- /* Read the IER to ensure any interrupt is cleared before
- * returning from ISR. */
- if (save_offset == UART_TX || save_offset == UART_IER)
- value = serial_in(up, UART_IER);
+ p->serial_in = mem_serial_in;
+ p->serial_out = dwapb_serial_out;
break;
default:
- outb(value, up->port.iobase + offset);
+ p->serial_in = io_serial_in;
+ p->serial_out = io_serial_out;
+ break;
}
}
static void
serial_out_sync(struct uart_8250_port *up, int offset, int value)
{
- switch (up->port.iotype) {
+ struct uart_port *p = &up->port;
+ switch (p->iotype) {
case UPIO_MEM:
case UPIO_MEM32:
#ifdef CONFIG_SERIAL_8250_AU1X00
case UPIO_AU:
#endif
case UPIO_DWAPB:
- serial_out(up, offset, value);
- serial_in(up, UART_LCR); /* safe, no side-effects */
+ p->serial_out(p, offset, value);
+ p->serial_in(p, UART_LCR); /* safe, no side-effects */
break;
default:
- serial_out(up, offset, value);
+ p->serial_out(p, offset, value);
}
}
+#define serial_in(up, offset) \
+ (up->port.serial_in(&(up)->port, (offset)))
+#define serial_out(up, offset, value) \
+ (up->port.serial_out(&(up)->port, (offset), (value)))
/*
* We used to support using pause I/O for certain machines. We
* haven't supported this for a while, but just in case it's badly
@@ -2576,6 +2645,7 @@ static void __init serial8250_isa_init_ports(void)
up->port.membase = old_serial_port[i].iomem_base;
up->port.iotype = old_serial_port[i].io_type;
up->port.regshift = old_serial_port[i].iomem_reg_shift;
+ set_io_from_upio(&up->port);
if (share_irqs)
up->port.flags |= UPF_SHARE_IRQ;
}
@@ -2752,12 +2822,30 @@ static struct uart_driver serial8250_reg = {
*/
int __init early_serial_setup(struct uart_port *port)
{
+ struct uart_port *p;
+
if (port->line >= ARRAY_SIZE(serial8250_ports))
return -ENODEV;
serial8250_isa_init_ports();
- serial8250_ports[port->line].port = *port;
- serial8250_ports[port->line].port.ops = &serial8250_pops;
+ p = &serial8250_ports[port->line].port;
+ p->iobase = port->iobase;
+ p->membase = port->membase;
+ p->irq = port->irq;
+ p->uartclk = port->uartclk;
+ p->fifosize = port->fifosize;
+ p->regshift = port->regshift;
+ p->iotype = port->iotype;
+ p->flags = port->flags;
+ p->mapbase = port->mapbase;
+ p->private_data = port->private_data;
+
+ set_io_from_upio(p);
+ if (port->serial_in)
+ p->serial_in = port->serial_in;
+ if (port->serial_out)
+ p->serial_out = port->serial_out;
+
return 0;
}
@@ -2822,6 +2910,9 @@ static int __devinit serial8250_probe(struct platform_device *dev)
port.mapbase = p->mapbase;
port.hub6 = p->hub6;
port.private_data = p->private_data;
+ port.type = p->type;
+ port.serial_in = p->serial_in;
+ port.serial_out = p->serial_out;
port.dev = &dev->dev;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
@@ -2976,6 +3067,20 @@ int serial8250_register_port(struct uart_port *port)
if (port->dev)
uart->port.dev = port->dev;
+ if (port->flags & UPF_FIXED_TYPE) {
+ uart->port.type = port->type;
+ uart->port.fifosize = uart_config[port->type].fifo_size;
+ uart->capabilities = uart_config[port->type].flags;
+ uart->tx_loadsz = uart_config[port->type].tx_loadsz;
+ }
+
+ set_io_from_upio(&uart->port);
+ /* Possibly override default I/O functions. */
+ if (port->serial_in)
+ uart->port.serial_in = port->serial_in;
+ if (port->serial_out)
+ uart->port.serial_out = port->serial_out;
+
ret = uart_add_one_port(&serial8250_reg, &uart->port);
if (ret == 0)
ret = uart->port.line;
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 5450a0e5ecdb..c088146b7513 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -42,7 +42,8 @@ struct pci_serial_quirk {
u32 subvendor;
u32 subdevice;
int (*init)(struct pci_dev *dev);
- int (*setup)(struct serial_private *, struct pciserial_board *,
+ int (*setup)(struct serial_private *,
+ const struct pciserial_board *,
struct uart_port *, int);
void (*exit)(struct pci_dev *dev);
};
@@ -107,7 +108,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
* ADDI-DATA GmbH communication cards <info@addi-data.com>
*/
static int addidata_apci7800_setup(struct serial_private *priv,
- struct pciserial_board *board,
+ const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@@ -134,7 +135,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
* Not that ugly ;) -- HW
*/
static int
-afavlab_setup(struct serial_private *priv, struct pciserial_board *board,
+afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -188,8 +189,9 @@ static int pci_hp_diva_init(struct pci_dev *dev)
* some serial ports are supposed to be hidden on certain models.
*/
static int
-pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board,
- struct uart_port *port, int idx)
+pci_hp_diva_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
+ struct uart_port *port, int idx)
{
unsigned int offset = board->first_offset;
unsigned int bar = FL_GET_BASE(board->flags);
@@ -306,7 +308,7 @@ static void __devexit pci_plx9050_exit(struct pci_dev *dev)
/* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
static int
-sbs_setup(struct serial_private *priv, struct pciserial_board *board,
+sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -463,7 +465,7 @@ static int pci_siig_init(struct pci_dev *dev)
}
static int pci_siig_setup(struct serial_private *priv,
- struct pciserial_board *board,
+ const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
@@ -534,7 +536,8 @@ static int pci_timedia_init(struct pci_dev *dev)
* Ugh, this is ugly as all hell --- TYT
*/
static int
-pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
+pci_timedia_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar = 0, offset = board->first_offset;
@@ -568,7 +571,7 @@ pci_timedia_setup(struct serial_private *priv, struct pciserial_board *board,
*/
static int
titan_400l_800l_setup(struct serial_private *priv,
- struct pciserial_board *board,
+ const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset;
@@ -737,8 +740,41 @@ static void __devexit pci_ite887x_exit(struct pci_dev *dev)
release_region(ioport, ITE_887x_IOSIZE);
}
+/*
+ * Oxford Semiconductor Inc.
+ * Check that device is part of the Tornado range of devices, then determine
+ * the number of ports available on the device.
+ */
+static int pci_oxsemi_tornado_init(struct pci_dev *dev)
+{
+ u8 __iomem *p;
+ unsigned long deviceID;
+ unsigned int number_uarts = 0;
+
+ /* OxSemi Tornado devices are all 0xCxxx */
+ if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
+ (dev->device & 0xF000) != 0xC000)
+ return 0;
+
+ p = pci_iomap(dev, 0, 5);
+ if (p == NULL)
+ return -ENOMEM;
+
+ deviceID = ioread32(p);
+ /* Tornado device */
+ if (deviceID == 0x07000200) {
+ number_uarts = ioread8(p + 4);
+ printk(KERN_DEBUG
+ "%d ports detected on Oxford PCI Express device\n",
+ number_uarts);
+ }
+ pci_iounmap(dev, p);
+ return number_uarts;
+}
+
static int
-pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
+pci_default_setup(struct serial_private *priv,
+ const struct pciserial_board *board,
struct uart_port *port, int idx)
{
unsigned int bar, offset = board->first_offset, maxnr;
@@ -1018,6 +1054,25 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
.setup = pci_default_setup,
},
/*
+ * For Oxford Semiconductor and Mainpine
+ */
+ {
+ .vendor = PCI_VENDOR_ID_OXSEMI,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_MAINPINE,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .init = pci_oxsemi_tornado_init,
+ .setup = pci_default_setup,
+ },
+ /*
* Default "match everything" terminator entry
*/
{
@@ -1048,7 +1103,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev)
}
static inline int get_pci_irq(struct pci_dev *dev,
- struct pciserial_board *board)
+ const struct pciserial_board *board)
{
if (board->flags & FL_NOIRQ)
return 0;
@@ -1843,8 +1898,8 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
}
static inline int
-serial_pci_matches(struct pciserial_board *board,
- struct pciserial_board *guessed)
+serial_pci_matches(const struct pciserial_board *board,
+ const struct pciserial_board *guessed)
{
return
board->num_ports == guessed->num_ports &&
@@ -1854,54 +1909,14 @@ serial_pci_matches(struct pciserial_board *board,
board->first_offset == guessed->first_offset;
}
-/*
- * Oxford Semiconductor Inc.
- * Check that device is part of the Tornado range of devices, then determine
- * the number of ports available on the device.
- */
-static int pci_oxsemi_tornado_init(struct pci_dev *dev, struct pciserial_board *board)
-{
- u8 __iomem *p;
- unsigned long deviceID;
- unsigned int number_uarts;
-
- /* OxSemi Tornado devices are all 0xCxxx */
- if (dev->vendor == PCI_VENDOR_ID_OXSEMI &&
- (dev->device & 0xF000) != 0xC000)
- return 0;
-
- p = pci_iomap(dev, 0, 5);
- if (p == NULL)
- return -ENOMEM;
-
- deviceID = ioread32(p);
- /* Tornado device */
- if (deviceID == 0x07000200) {
- number_uarts = ioread8(p + 4);
- board->num_ports = number_uarts;
- printk(KERN_DEBUG
- "%d ports detected on Oxford PCI Express device\n",
- number_uarts);
- }
- pci_iounmap(dev, p);
- return 0;
-}
-
struct serial_private *
-pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board)
+pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
{
struct uart_port serial_port;
struct serial_private *priv;
struct pci_serial_quirk *quirk;
int rc, nr_ports, i;
- /*
- * Find number of ports on board
- */
- if (dev->vendor == PCI_VENDOR_ID_OXSEMI ||
- dev->vendor == PCI_VENDOR_ID_MAINPINE)
- pci_oxsemi_tornado_init(dev, board);
-
nr_ports = board->num_ports;
/*
@@ -2028,7 +2043,8 @@ static int __devinit
pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
{
struct serial_private *priv;
- struct pciserial_board *board, tmp;
+ const struct pciserial_board *board;
+ struct pciserial_board tmp;
int rc;
if (ent->driver_data >= ARRAY_SIZE(pci_boards)) {
@@ -2055,7 +2071,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent)
* We matched one of our class entries. Try to
* determine the parameters of this board.
*/
- rc = serial_pci_guess_board(dev, board);
+ rc = serial_pci_guess_board(dev, &tmp);
if (rc)
goto disable;
} else {
@@ -2271,6 +2287,9 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_115200 },
+ { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_7803,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b2_8_460800 },
{ PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b2_8_115200 },
@@ -2372,6 +2391,9 @@ static struct pci_device_id serial_pci_tbl[] = {
* For now just used the hex ID 0x950a.
*/
{ PCI_VENDOR_ID_OXSEMI, 0x950a,
+ PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_DUAL_SERIAL, 0, 0,
+ pbn_b0_2_115200 },
+ { PCI_VENDOR_ID_OXSEMI, 0x950a,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_2_1130000 },
{ PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 579d63a81aa2..b695ab3142d8 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -447,7 +447,7 @@ config SERIAL_CLPS711X_CONSOLE
config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
- depends on ARM && PLAT_S3C24XX
+ depends on ARM && PLAT_S3C
select SERIAL_CORE
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
@@ -455,6 +455,16 @@ config SERIAL_SAMSUNG
provide all of these ports, depending on how the serial port
pins are configured.
+config SERIAL_SAMSUNG_UARTS
+ int
+ depends on SERIAL_SAMSUNG
+ default 2 if ARCH_S3C2400
+ default 4 if ARCH_S3C64XX || CPU_S3C2443
+ default 3
+ help
+ Select the number of available UART ports for the Samsung S3C
+ serial driver
+
config SERIAL_SAMSUNG_DEBUG
bool "Samsung SoC serial debug"
depends on SERIAL_SAMSUNG && DEBUG_LL
@@ -508,7 +518,20 @@ config SERIAL_S3C2440
help
Serial port support for the Samsung S3C2440 and S3C2442 SoC
+config SERIAL_S3C24A0
+ tristate "Samsung S3C24A0 Serial port support"
+ depends on SERIAL_SAMSUNG && CPU_S3C24A0
+ default y if CPU_S3C24A0
+ help
+ Serial port support for the Samsung S3C24A0 SoC
+config SERIAL_S3C6400
+ tristate "Samsung S3C6400/S3C6410 Serial port support"
+ depends on SERIAL_SAMSUNG && (CPU_S3C600 || CPU_S3C6410)
+ default y
+ help
+ Serial port support for the Samsung S3C6400 and S3C6410
+ SoCs
config SERIAL_DZ
bool "DECstation DZ serial driver"
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 0c17c8ddb19d..dfe775ac45b2 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -41,6 +41,8 @@ obj-$(CONFIG_SERIAL_S3C2400) += s3c2400.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_S3C2412) += s3c2412.o
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
+obj-$(CONFIG_SERIAL_S3C24A0) += s3c24a0.o
+obj-$(CONFIG_SERIAL_S3C6400) += s3c6400.o
obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 71562689116f..e3a5ad5ef1d6 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -692,7 +692,7 @@ static int pl010_probe(struct amba_device *dev, void *id)
goto free;
}
- uap->clk = clk_get(&dev->dev, "UARTCLK");
+ uap->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
goto unmap;
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index b7180046f8db..8b2b9700f3e4 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -756,7 +756,7 @@ static int pl011_probe(struct amba_device *dev, void *id)
goto free;
}
- uap->clk = clk_get(&dev->dev, "UARTCLK");
+ uap->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
goto unmap;
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 569f0e2476c6..318d69dce8e1 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -22,7 +22,8 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
-#ifdef CONFIG_KGDB_UART
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
#include <linux/kgdb.h>
#include <asm/irq_regs.h>
#endif
@@ -45,6 +46,16 @@
static struct bfin_serial_port bfin_serial_ports[BFIN_UART_NR_PORTS];
static int nr_active_ports = ARRAY_SIZE(bfin_serial_resource);
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+
+# ifndef CONFIG_SERIAL_BFIN_PIO
+# error KGDB only support UART in PIO mode.
+# endif
+
+static int kgdboc_port_line;
+static int kgdboc_break_enabled;
+#endif
/*
* Setup for console. Argument comes from the menuconfig
*/
@@ -62,13 +73,17 @@ static void bfin_serial_tx_chars(struct bfin_serial_port *uart);
static void bfin_serial_mctrl_check(struct bfin_serial_port *uart);
+static void bfin_serial_reset_irda(struct uart_port *port);
+
/*
* interrupts are disabled on entry
*/
static void bfin_serial_stop_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+#ifdef CONFIG_SERIAL_BFIN_DMA
struct circ_buf *xmit = &uart->port.info->xmit;
+#endif
while (!(UART_GET_LSR(uart) & TEMT))
cpu_relax();
@@ -94,6 +109,14 @@ static void bfin_serial_stop_tx(struct uart_port *port)
static void bfin_serial_start_tx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ struct tty_struct *tty = uart->port.info->port.tty;
+
+ /*
+ * To avoid losting RX interrupt, we reset IR function
+ * before sending data.
+ */
+ if (tty->termios->c_line == N_IRDA)
+ bfin_serial_reset_irda(port);
#ifdef CONFIG_SERIAL_BFIN_DMA
if (uart->tx_done)
@@ -110,9 +133,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
static void bfin_serial_stop_rx(struct uart_port *port)
{
struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
-#ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
+
UART_CLEAR_IER(uart, ERBFI);
}
@@ -123,49 +144,6 @@ static void bfin_serial_enable_ms(struct uart_port *port)
{
}
-#ifdef CONFIG_KGDB_UART
-static int kgdb_entry_state;
-
-void kgdb_put_debug_char(int chr)
-{
- struct bfin_serial_port *uart;
-
- if (CONFIG_KGDB_UART_PORT < 0
- || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
- uart = &bfin_serial_ports[0];
- else
- uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
- while (!(UART_GET_LSR(uart) & THRE)) {
- SSYNC();
- }
-
- UART_CLEAR_DLAB(uart);
- UART_PUT_CHAR(uart, (unsigned char)chr);
- SSYNC();
-}
-
-int kgdb_get_debug_char(void)
-{
- struct bfin_serial_port *uart;
- unsigned char chr;
-
- if (CONFIG_KGDB_UART_PORT < 0
- || CONFIG_KGDB_UART_PORT >= BFIN_UART_NR_PORTS)
- uart = &bfin_serial_ports[0];
- else
- uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
-
- while(!(UART_GET_LSR(uart) & DR)) {
- SSYNC();
- }
- UART_CLEAR_DLAB(uart);
- chr = UART_GET_CHAR(uart);
- SSYNC();
-
- return chr;
-}
-#endif
#if ANOMALY_05000363 && defined(CONFIG_SERIAL_BFIN_PIO)
# define UART_GET_ANOMALY_THRESHOLD(uart) ((uart)->anomaly_threshold)
@@ -178,7 +156,7 @@ int kgdb_get_debug_char(void)
#ifdef CONFIG_SERIAL_BFIN_PIO
static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
{
- struct tty_struct *tty = uart->port.info->port.tty;
+ struct tty_struct *tty = NULL;
unsigned int status, ch, flg;
static struct timeval anomaly_start = { .tv_sec = 0 };
@@ -188,27 +166,18 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
ch = UART_GET_CHAR(uart);
uart->port.icount.rx++;
-#ifdef CONFIG_KGDB_UART
- if (uart->port.line == CONFIG_KGDB_UART_PORT) {
- struct pt_regs *regs = get_irq_regs();
- if (uart->port.cons->index == CONFIG_KGDB_UART_PORT && ch == 0x1) { /* Ctrl + A */
- kgdb_breakkey_pressed(regs);
- return;
- } else if (kgdb_entry_state == 0 && ch == '$') {/* connection from KGDB */
- kgdb_entry_state = 1;
- } else if (kgdb_entry_state == 1 && ch == 'q') {
- kgdb_entry_state = 0;
- kgdb_breakkey_pressed(regs);
- return;
- } else if (ch == 0x3) {/* Ctrl + C */
- kgdb_entry_state = 0;
- kgdb_breakkey_pressed(regs);
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+ if (kgdb_connected && kgdboc_port_line == uart->port.line)
+ if (ch == 0x3) {/* Ctrl + C */
+ kgdb_breakpoint();
return;
- } else {
- kgdb_entry_state = 0;
}
- }
+
+ if (!uart->port.info || !uart->port.info->tty)
+ return;
#endif
+ tty = uart->port.info->tty;
if (ANOMALY_05000363) {
/* The BF533 (and BF561) family of processors have a nice anomaly
@@ -250,6 +219,7 @@ static void bfin_serial_rx_chars(struct bfin_serial_port *uart)
return;
known_good_char:
+ status &= ~BI;
anomaly_start.tv_sec = 0;
}
}
@@ -445,7 +415,9 @@ static void bfin_serial_dma_rx_chars(struct bfin_serial_port *uart)
void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
{
- int x_pos, pos;
+ int x_pos, pos, flags;
+
+ spin_lock_irqsave(&uart->port.lock, flags);
uart->rx_dma_nrows = get_dma_curr_ycount(uart->rx_dma_channel);
x_pos = get_dma_curr_xcount(uart->rx_dma_channel);
@@ -463,6 +435,8 @@ void bfin_serial_rx_dma_timeout(struct bfin_serial_port *uart)
uart->rx_dma_buf.tail = uart->rx_dma_buf.head;
}
+ spin_unlock_irqrestore(&uart->port.lock, flags);
+
mod_timer(&(uart->rx_dma_timer), jiffies + DMA_RX_FLUSH_JIFFIES);
}
@@ -497,10 +471,9 @@ static irqreturn_t bfin_serial_dma_rx_int(int irq, void *dev_id)
spin_lock(&uart->port.lock);
irqstat = get_dma_curr_irqstat(uart->rx_dma_channel);
clear_dma_irqstat(uart->rx_dma_channel);
+ bfin_serial_dma_rx_chars(uart);
spin_unlock(&uart->port.lock);
- mod_timer(&(uart->rx_dma_timer), jiffies);
-
return IRQ_HANDLED;
}
#endif
@@ -630,16 +603,16 @@ static int bfin_serial_startup(struct uart_port *port)
uart->rx_dma_timer.expires = jiffies + DMA_RX_FLUSH_JIFFIES;
add_timer(&(uart->rx_dma_timer));
#else
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+ if (kgdboc_port_line == uart->port.line && kgdboc_break_enabled)
+ kgdboc_break_enabled = 0;
+ else {
+# endif
if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
"BFIN_UART_RX", uart)) {
-# ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT) {
-# endif
printk(KERN_NOTICE "Unable to attach BlackFin UART RX interrupt\n");
return -EBUSY;
-# ifdef CONFIG_KGDB_UART
- }
-# endif
}
if (request_irq
@@ -685,6 +658,10 @@ static int bfin_serial_startup(struct uart_port *port)
}
}
# endif
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+ }
+# endif
#endif
UART_SET_IER(uart, ERBFI);
return 0;
@@ -716,9 +693,6 @@ static void bfin_serial_shutdown(struct uart_port *port)
break;
};
#endif
-#ifdef CONFIG_KGDB_UART
- if (uart->port.line != CONFIG_KGDB_UART_PORT)
-#endif
free_irq(uart->port.irq, uart);
free_irq(uart->port.irq+1, uart);
#endif
@@ -887,6 +861,65 @@ static void bfin_serial_set_ldisc(struct uart_port *port)
}
}
+#ifdef CONFIG_CONSOLE_POLL
+static void bfin_serial_poll_put_char(struct uart_port *port, unsigned char chr)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+
+ while (!(UART_GET_LSR(uart) & THRE))
+ cpu_relax();
+
+ UART_CLEAR_DLAB(uart);
+ UART_PUT_CHAR(uart, (unsigned char)chr);
+}
+
+static int bfin_serial_poll_get_char(struct uart_port *port)
+{
+ struct bfin_serial_port *uart = (struct bfin_serial_port *)port;
+ unsigned char chr;
+
+ while (!(UART_GET_LSR(uart) & DR))
+ cpu_relax();
+
+ UART_CLEAR_DLAB(uart);
+ chr = UART_GET_CHAR(uart);
+
+ return chr;
+}
+#endif
+
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+static void bfin_kgdboc_port_shutdown(struct uart_port *port)
+{
+ if (kgdboc_break_enabled) {
+ kgdboc_break_enabled = 0;
+ bfin_serial_shutdown(port);
+ }
+}
+
+static int bfin_kgdboc_port_startup(struct uart_port *port)
+{
+ kgdboc_port_line = port->line;
+ kgdboc_break_enabled = !bfin_serial_startup(port);
+ return 0;
+}
+#endif
+
+static void bfin_serial_reset_irda(struct uart_port *port)
+{
+ int line = port->line;
+ unsigned short val;
+
+ val = UART_GET_GCTL(&bfin_serial_ports[line]);
+ val &= ~(IREN | RPOLC);
+ UART_PUT_GCTL(&bfin_serial_ports[line], val);
+ SSYNC();
+ val |= (IREN | RPOLC);
+ UART_PUT_GCTL(&bfin_serial_ports[line], val);
+ SSYNC();
+}
+
static struct uart_ops bfin_serial_pops = {
.tx_empty = bfin_serial_tx_empty,
.set_mctrl = bfin_serial_set_mctrl,
@@ -905,6 +938,15 @@ static struct uart_ops bfin_serial_pops = {
.request_port = bfin_serial_request_port,
.config_port = bfin_serial_config_port,
.verify_port = bfin_serial_verify_port,
+#if defined(CONFIG_KGDB_SERIAL_CONSOLE) || \
+ defined(CONFIG_KGDB_SERIAL_CONSOLE_MODULE)
+ .kgdboc_port_startup = bfin_kgdboc_port_startup,
+ .kgdboc_port_shutdown = bfin_kgdboc_port_shutdown,
+#endif
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_put_char = bfin_serial_poll_put_char,
+ .poll_get_char = bfin_serial_poll_get_char,
+#endif
};
static void __init bfin_serial_init_ports(void)
@@ -950,7 +992,7 @@ static void __init bfin_serial_init_ports(void)
}
-#ifdef CONFIG_SERIAL_BFIN_CONSOLE
+#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
/*
* If the port was already initialised (eg, by a boot loader),
* try to determine the current setup.
@@ -994,24 +1036,20 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud,
}
pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
-#endif
-#if defined(CONFIG_SERIAL_BFIN_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
static struct uart_driver bfin_serial_reg;
static int __init
bfin_serial_console_setup(struct console *co, char *options)
{
struct bfin_serial_port *uart;
-# ifdef CONFIG_SERIAL_BFIN_CONSOLE
int baud = 57600;
int bits = 8;
int parity = 'n';
-# ifdef CONFIG_SERIAL_BFIN_CTSRTS
+# ifdef CONFIG_SERIAL_BFIN_CTSRTS
int flow = 'r';
-# else
+# else
int flow = 'n';
-# endif
# endif
/*
@@ -1023,16 +1061,12 @@ bfin_serial_console_setup(struct console *co, char *options)
co->index = 0;
uart = &bfin_serial_ports[co->index];
-# ifdef CONFIG_SERIAL_BFIN_CONSOLE
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
bfin_serial_console_get_options(uart, &baud, &parity, &bits);
return uart_set_options(&uart->port, co, baud, parity, bits, flow);
-# else
- return 0;
-# endif
}
#endif /* defined (CONFIG_SERIAL_BFIN_CONSOLE) ||
defined (CONFIG_EARLY_PRINTK) */
@@ -1076,10 +1110,7 @@ static int __init bfin_serial_rs_console_init(void)
{
bfin_serial_init_ports();
register_console(&bfin_serial_console);
-#ifdef CONFIG_KGDB_UART
- kgdb_entry_state = 0;
- init_kgdb_uart();
-#endif
+
return 0;
}
console_initcall(bfin_serial_rs_console_init);
@@ -1144,7 +1175,7 @@ struct console __init *bfin_earlyserial_init(unsigned int port,
return &bfin_early_serial_console;
}
-#endif /* CONFIG_SERIAL_BFIN_CONSOLE */
+#endif /* CONFIG_EARLY_PRINTK */
static struct uart_driver bfin_serial_reg = {
.owner = THIS_MODULE,
@@ -1235,10 +1266,6 @@ static struct platform_driver bfin_serial_driver = {
static int __init bfin_serial_init(void)
{
int ret;
-#ifdef CONFIG_KGDB_UART
- struct bfin_serial_port *uart = &bfin_serial_ports[CONFIG_KGDB_UART_PORT];
- struct ktermios t;
-#endif
pr_info("Serial: Blackfin serial driver\n");
@@ -1252,21 +1279,6 @@ static int __init bfin_serial_init(void)
uart_unregister_driver(&bfin_serial_reg);
}
}
-#ifdef CONFIG_KGDB_UART
- if (uart->port.cons->index != CONFIG_KGDB_UART_PORT) {
- request_irq(uart->port.irq, bfin_serial_rx_int,
- IRQF_DISABLED, "BFIN_UART_RX", uart);
- pr_info("Request irq for kgdb uart port\n");
- UART_SET_IER(uart, ERBFI);
- SSYNC();
- t.c_cflag = CS8|B57600;
- t.c_iflag = 0;
- t.c_oflag = 0;
- t.c_lflag = ICANON;
- t.c_line = CONFIG_KGDB_UART_PORT;
- bfin_serial_set_termios(&uart->port, &t, &t);
- }
-#endif
return ret;
}
@@ -1276,6 +1288,7 @@ static void __exit bfin_serial_exit(void)
uart_unregister_driver(&bfin_serial_reg);
}
+
module_init(bfin_serial_init);
module_exit(bfin_serial_exit);
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
index dd8564d25051..529c0ff7952c 100644
--- a/drivers/serial/bfin_sport_uart.c
+++ b/drivers/serial/bfin_sport_uart.c
@@ -99,7 +99,7 @@ static void sport_stop_tx(struct uart_port *port);
static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
{
- pr_debug("%s value:%x\n", __FUNCTION__, value);
+ pr_debug("%s value:%x\n", __func__, value);
/* Place a Start and Stop bit */
__asm__ volatile (
"R2 = b#01111111100;\n\t"
@@ -110,7 +110,7 @@ static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
:"=r"(value)
:"0"(value)
:"R2", "R3");
- pr_debug("%s value:%x\n", __FUNCTION__, value);
+ pr_debug("%s value:%x\n", __func__, value);
SPORT_PUT_TX(up, value);
}
@@ -120,7 +120,7 @@ static inline unsigned int rx_one_byte(struct sport_uart_port *up)
unsigned int value, extract;
value = SPORT_GET_RX32(up);
- pr_debug("%s value:%x\n", __FUNCTION__, value);
+ pr_debug("%s value:%x\n", __func__, value);
/* Extract 8 bits data */
__asm__ volatile (
@@ -151,12 +151,12 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
/* Set TCR1 and TCR2 */
SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
SPORT_PUT_TCR2(up, 10);
- pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+ pr_debug("%s TCR1:%x, TCR2:%x\n", __func__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
/* Set RCR1 and RCR2 */
SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
SPORT_PUT_RCR2(up, 28);
- pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+ pr_debug("%s RCR1:%x, RCR2:%x\n", __func__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
tclkdiv = sclk/(2 * baud_rate) - 1;
tfsdiv = 12;
@@ -166,7 +166,7 @@ static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
SPORT_PUT_RCLKDIV(up, rclkdiv);
SSYNC();
pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
- __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
+ __func__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
return 0;
}
@@ -231,7 +231,7 @@ static int sport_startup(struct uart_port *port)
char buffer[20];
int retval;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
memset(buffer, 20, '\0');
snprintf(buffer, 20, "%s rx", up->name);
retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
@@ -320,7 +320,7 @@ static unsigned int sport_tx_empty(struct uart_port *port)
unsigned int stat;
stat = SPORT_GET_STAT(up);
- pr_debug("%s stat:%04x\n", __FUNCTION__, stat);
+ pr_debug("%s stat:%04x\n", __func__, stat);
if (stat & TXHRE) {
return TIOCSER_TEMT;
} else
@@ -329,13 +329,13 @@ static unsigned int sport_tx_empty(struct uart_port *port)
static unsigned int sport_get_mctrl(struct uart_port *port)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ 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", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
}
static void sport_stop_tx(struct uart_port *port)
@@ -343,7 +343,7 @@ static void sport_stop_tx(struct uart_port *port)
struct sport_uart_port *up = (struct sport_uart_port *)port;
unsigned int stat;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
stat = SPORT_GET_STAT(up);
while(!(stat & TXHRE)) {
@@ -366,21 +366,21 @@ static void sport_start_tx(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
/* Write data into SPORT FIFO before enable SPROT to transmit */
sport_uart_tx_chars(up);
/* Enable transmit, then an interrupt will generated */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
SSYNC();
- pr_debug("%s exit\n", __FUNCTION__);
+ pr_debug("%s exit\n", __func__);
}
static void sport_stop_rx(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
/* Disable sport to stop rx */
SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
SSYNC();
@@ -388,19 +388,19 @@ static void sport_stop_rx(struct uart_port *port)
static void sport_enable_ms(struct uart_port *port)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
}
static void sport_break_ctl(struct uart_port *port, int break_state)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
}
static void sport_shutdown(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
/* Disable sport */
SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
@@ -421,7 +421,7 @@ static void sport_shutdown(struct uart_port *port)
static void sport_set_termios(struct uart_port *port,
struct termios *termios, struct termios *old)
{
- pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag);
+ pr_debug("%s enter, c_cflag:%08x\n", __func__, termios->c_cflag);
uart_update_timeout(port, CS8 ,port->uartclk);
}
@@ -429,18 +429,18 @@ static const char *sport_type(struct uart_port *port)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
return up->name;
}
static void sport_release_port(struct uart_port *port)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
}
static int sport_request_port(struct uart_port *port)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
return 0;
}
@@ -448,13 +448,13 @@ static void sport_config_port(struct uart_port *port, int flags)
{
struct sport_uart_port *up = (struct sport_uart_port *)port;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
up->port.type = PORT_BFIN_SPORT;
}
static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
return 0;
}
@@ -527,7 +527,7 @@ static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
{
struct sport_uart_port *sport = platform_get_drvdata(dev);
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
if (sport)
uart_suspend_port(&sport_uart_reg, &sport->port);
@@ -538,7 +538,7 @@ static int sport_uart_resume(struct platform_device *dev)
{
struct sport_uart_port *sport = platform_get_drvdata(dev);
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
if (sport)
uart_resume_port(&sport_uart_reg, &sport->port);
@@ -547,7 +547,7 @@ static int sport_uart_resume(struct platform_device *dev)
static int sport_uart_probe(struct platform_device *dev)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
sport_uart_ports[dev->id].port.dev = &dev->dev;
uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
@@ -559,7 +559,7 @@ static int sport_uart_remove(struct platform_device *dev)
{
struct sport_uart_port *sport = platform_get_drvdata(dev);
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
platform_set_drvdata(dev, NULL);
if (sport)
@@ -582,7 +582,7 @@ static int __init sport_uart_init(void)
{
int ret;
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
ret = uart_register_driver(&sport_uart_reg);
if (ret != 0) {
printk(KERN_ERR "Failed to register %s:%d\n",
@@ -597,13 +597,13 @@ static int __init sport_uart_init(void)
}
- pr_debug("%s exit\n", __FUNCTION__);
+ pr_debug("%s exit\n", __func__);
return ret;
}
static void __exit sport_uart_exit(void)
{
- pr_debug("%s enter\n", __FUNCTION__);
+ pr_debug("%s enter\n", __func__);
platform_driver_unregister(&sport_uart_driver);
uart_unregister_driver(&sport_uart_reg);
}
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 3f90f1bbbbcd..a50954612b60 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -66,7 +66,7 @@
#define ONEMS 0xb0 /* One Millisecond register */
#define UTS 0xb4 /* UART Test Register */
#endif
-#ifdef CONFIG_ARCH_IMX
+#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
#define BIPR1 0xb0 /* Incremental Preset Register 1 */
#define BIPR2 0xb4 /* Incremental Preset Register 2 */
#define BIPR3 0xb8 /* Incremental Preset Register 3 */
@@ -96,7 +96,7 @@
#define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */
#define UCR1_SNDBRK (1<<4) /* Send break */
#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */
-#ifdef CONFIG_ARCH_IMX
+#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
#define UCR1_UARTCLKEN (1<<2) /* UART clock enabled */
#endif
#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
@@ -187,11 +187,11 @@
#define MAX_INTERNAL_IRQ IMX_IRQS
#endif
-#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+#ifdef CONFIG_ARCH_MXC
#define SERIAL_IMX_MAJOR 207
#define MINOR_START 16
#define DEV_NAME "ttymxc"
-#define MAX_INTERNAL_IRQ MXC_MAX_INT_LINES
+#define MAX_INTERNAL_IRQ MXC_INTERNAL_IRQS
#endif
/*
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index a697914ae3d0..3547558d2caf 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -272,7 +272,7 @@ static void jsm_tty_close(struct uart_port *port)
jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
bd = channel->ch_bd;
- ts = channel->uart_port.info->port.tty->termios;
+ ts = port->info->port.tty->termios;
channel->ch_flags &= ~(CH_STOPI);
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index abc00be55433..f6e3b86bb0be 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -48,6 +48,7 @@
#include <mach/hardware.h>
#include <asm/irq.h>
#include <mach/pxa-regs.h>
+#include <mach/regs-uart.h>
struct uart_pxa_port {
@@ -766,7 +767,7 @@ static int serial_pxa_probe(struct platform_device *dev)
if (!sport)
return -ENOMEM;
- sport->clk = clk_get(&dev->dev, "UARTCLK");
+ sport->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(sport->clk)) {
ret = PTR_ERR(sport->clk);
goto err_free;
diff --git a/drivers/serial/s3c24a0.c b/drivers/serial/s3c24a0.c
new file mode 100644
index 000000000000..ebf2fd3c8f7d
--- /dev/null
+++ b/drivers/serial/s3c24a0.c
@@ -0,0 +1,118 @@
+/* linux/drivers/serial/s3c24a0.c
+ *
+ * Driver for Samsung S3C24A0 SoC onboard UARTs.
+ *
+ * Based on drivers/serial/s3c2410.c
+ *
+ * Author: Sandeep Patil <sandeep.patil@azingo.com>
+ *
+ * Ben Dooks, Copyright (c) 2003-2005,2008 Simtec Electronics
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+#include <mach/regs-gpio.h>
+
+#include "samsung.h"
+
+static int s3c24a0_serial_setsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ if (strcmp(clk->name, "uclk") == 0)
+ ucon |= S3C2410_UCON_UCLK;
+ else
+ ucon &= ~S3C2410_UCON_UCLK;
+
+ wr_regl(port, S3C2410_UCON, ucon);
+ return 0;
+}
+
+static int s3c24a0_serial_getsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ clk->divisor = 1;
+ clk->name = (ucon & S3C2410_UCON_UCLK) ? "uclk" : "pclk";
+
+ return 0;
+}
+
+static int s3c24a0_serial_resetport(struct uart_port *port,
+ struct s3c2410_uartcfg *cfg)
+{
+ dbg("s3c24a0_serial_resetport: port=%p (%08lx), cfg=%p\n",
+ port, port->mapbase, cfg);
+
+ wr_regl(port, S3C2410_UCON, cfg->ucon);
+ wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+ /* reset both fifos */
+
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+ return 0;
+}
+
+static struct s3c24xx_uart_info s3c24a0_uart_inf = {
+ .name = "Samsung S3C24A0 UART",
+ .type = PORT_S3C2410,
+ .fifosize = 16,
+ .rx_fifomask = S3C24A0_UFSTAT_RXMASK,
+ .rx_fifoshift = S3C24A0_UFSTAT_RXSHIFT,
+ .rx_fifofull = S3C24A0_UFSTAT_RXFULL,
+ .tx_fifofull = S3C24A0_UFSTAT_TXFULL,
+ .tx_fifomask = S3C24A0_UFSTAT_TXMASK,
+ .tx_fifoshift = S3C24A0_UFSTAT_TXSHIFT,
+ .get_clksrc = s3c24a0_serial_getsource,
+ .set_clksrc = s3c24a0_serial_setsource,
+ .reset_port = s3c24a0_serial_resetport,
+};
+
+static int s3c24a0_serial_probe(struct platform_device *dev)
+{
+ return s3c24xx_serial_probe(dev, &s3c24a0_uart_inf);
+}
+
+static struct platform_driver s3c24a0_serial_drv = {
+ .probe = s3c24a0_serial_probe,
+ .remove = s3c24xx_serial_remove,
+ .driver = {
+ .name = "s3c24a0-uart",
+ .owner = THIS_MODULE,
+ },
+};
+
+s3c24xx_console_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf);
+
+static int __init s3c24a0_serial_init(void)
+{
+ return s3c24xx_serial_init(&s3c24a0_serial_drv, &s3c24a0_uart_inf);
+}
+
+static void __exit s3c24a0_serial_exit(void)
+{
+ platform_driver_unregister(&s3c24a0_serial_drv);
+}
+
+module_init(s3c24a0_serial_init);
+module_exit(s3c24a0_serial_exit);
+
diff --git a/drivers/serial/s3c6400.c b/drivers/serial/s3c6400.c
new file mode 100644
index 000000000000..06936d13393f
--- /dev/null
+++ b/drivers/serial/s3c6400.c
@@ -0,0 +1,151 @@
+/* linux/drivers/serial/s3c6400.c
+ *
+ * Driver for Samsung S3C6400 and S3C6410 SoC onboard UARTs.
+ *
+ * Copyright 2008 Openmoko, Inc.
+ * Copyright 2008 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+
+#include <plat/regs-serial.h>
+
+#include "samsung.h"
+
+static int s3c6400_serial_setsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ if (strcmp(clk->name, "uclk0") == 0) {
+ ucon &= ~S3C6400_UCON_CLKMASK;
+ ucon |= S3C6400_UCON_UCLK0;
+ } else if (strcmp(clk->name, "uclk1") == 0)
+ ucon |= S3C6400_UCON_UCLK1;
+ else if (strcmp(clk->name, "pclk") == 0) {
+ /* See notes about transitioning from UCLK to PCLK */
+ ucon &= ~S3C6400_UCON_UCLK0;
+ } else {
+ printk(KERN_ERR "unknown clock source %s\n", clk->name);
+ return -EINVAL;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+ return 0;
+}
+
+
+static int s3c6400_serial_getsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ u32 ucon = rd_regl(port, S3C2410_UCON);
+
+ clk->divisor = 1;
+
+ switch (ucon & S3C6400_UCON_CLKMASK) {
+ case S3C6400_UCON_UCLK0:
+ clk->name = "uclk0";
+ break;
+
+ case S3C6400_UCON_UCLK1:
+ clk->name = "uclk1";
+ break;
+
+ case S3C6400_UCON_PCLK:
+ case S3C6400_UCON_PCLK2:
+ clk->name = "pclk";
+ break;
+ }
+
+ return 0;
+}
+
+static int s3c6400_serial_resetport(struct uart_port *port,
+ struct s3c2410_uartcfg *cfg)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ dbg("s3c6400_serial_resetport: port=%p (%08lx), cfg=%p\n",
+ port, port->mapbase, cfg);
+
+ /* ensure we don't change the clock settings... */
+
+ ucon &= S3C6400_UCON_CLKMASK;
+
+ wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
+ wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+ /* reset both fifos */
+
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+ return 0;
+}
+
+static struct s3c24xx_uart_info s3c6400_uart_inf = {
+ .name = "Samsung S3C6400 UART",
+ .type = PORT_S3C6400,
+ .fifosize = 64,
+ .rx_fifomask = S3C2440_UFSTAT_RXMASK,
+ .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
+ .rx_fifofull = S3C2440_UFSTAT_RXFULL,
+ .tx_fifofull = S3C2440_UFSTAT_TXFULL,
+ .tx_fifomask = S3C2440_UFSTAT_TXMASK,
+ .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
+ .get_clksrc = s3c6400_serial_getsource,
+ .set_clksrc = s3c6400_serial_setsource,
+ .reset_port = s3c6400_serial_resetport,
+};
+
+/* device management */
+
+static int s3c6400_serial_probe(struct platform_device *dev)
+{
+ dbg("s3c6400_serial_probe: dev=%p\n", dev);
+ return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
+}
+
+static struct platform_driver s3c6400_serial_drv = {
+ .probe = s3c6400_serial_probe,
+ .remove = s3c24xx_serial_remove,
+ .driver = {
+ .name = "s3c6400-uart",
+ .owner = THIS_MODULE,
+ },
+};
+
+s3c24xx_console_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
+
+static int __init s3c6400_serial_init(void)
+{
+ return s3c24xx_serial_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
+}
+
+static void __exit s3c6400_serial_exit(void)
+{
+ platform_driver_unregister(&s3c6400_serial_drv);
+}
+
+module_init(s3c6400_serial_init);
+module_exit(s3c6400_serial_exit);
+
+MODULE_DESCRIPTION("Samsung S3C6400,S3C6410 SoC Serial port driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:s3c6400-uart");
diff --git a/drivers/serial/samsung.c b/drivers/serial/samsung.c
index 1e219d3d0352..41ac94872b8d 100644
--- a/drivers/serial/samsung.c
+++ b/drivers/serial/samsung.c
@@ -42,13 +42,14 @@
#include <linux/serial.h>
#include <linux/delay.h>
#include <linux/clk.h>
+#include <linux/cpufreq.h>
#include <asm/irq.h>
#include <mach/hardware.h>
+#include <mach/map.h>
#include <plat/regs-serial.h>
-#include <mach/regs-gpio.h>
#include "samsung.h"
@@ -58,19 +59,6 @@
#define S3C24XX_SERIAL_MAJOR 204
#define S3C24XX_SERIAL_MINOR 64
-/* we can support 3 uarts, but not always use them */
-
-#ifdef CONFIG_CPU_S3C2400
-#define NR_PORTS (2)
-#else
-#define NR_PORTS (3)
-#endif
-
-/* port irq numbers */
-
-#define TX_IRQ(port) ((port)->irq + 1)
-#define RX_IRQ(port) ((port)->irq)
-
/* macros to change one thing to another */
#define tx_enabled(port) ((port)->unused[0])
@@ -136,8 +124,10 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
if (tx_enabled(port)) {
- disable_irq(TX_IRQ(port));
+ disable_irq(ourport->tx_irq);
tx_enabled(port) = 0;
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_enable(port);
@@ -146,11 +136,13 @@ static void s3c24xx_serial_stop_tx(struct uart_port *port)
static void s3c24xx_serial_start_tx(struct uart_port *port)
{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
if (!tx_enabled(port)) {
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
- enable_irq(TX_IRQ(port));
+ enable_irq(ourport->tx_irq);
tx_enabled(port) = 1;
}
}
@@ -158,9 +150,11 @@ static void s3c24xx_serial_start_tx(struct uart_port *port)
static void s3c24xx_serial_stop_rx(struct uart_port *port)
{
+ struct s3c24xx_uart_port *ourport = to_ourport(port);
+
if (rx_enabled(port)) {
dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
- disable_irq(RX_IRQ(port));
+ disable_irq(ourport->rx_irq);
rx_enabled(port) = 0;
}
}
@@ -384,13 +378,13 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
struct s3c24xx_uart_port *ourport = to_ourport(port);
if (ourport->tx_claimed) {
- free_irq(TX_IRQ(port), ourport);
+ free_irq(ourport->tx_irq, ourport);
tx_enabled(port) = 0;
ourport->tx_claimed = 0;
}
if (ourport->rx_claimed) {
- free_irq(RX_IRQ(port), ourport);
+ free_irq(ourport->rx_irq, ourport);
ourport->rx_claimed = 0;
rx_enabled(port) = 0;
}
@@ -407,12 +401,11 @@ static int s3c24xx_serial_startup(struct uart_port *port)
rx_enabled(port) = 1;
- ret = request_irq(RX_IRQ(port),
- s3c24xx_serial_rx_chars, 0,
+ ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
s3c24xx_serial_portname(port), ourport);
if (ret != 0) {
- printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port));
+ printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
return ret;
}
@@ -422,12 +415,11 @@ static int s3c24xx_serial_startup(struct uart_port *port)
tx_enabled(port) = 1;
- ret = request_irq(TX_IRQ(port),
- s3c24xx_serial_tx_chars, 0,
+ ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
s3c24xx_serial_portname(port), ourport);
if (ret) {
- printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port));
+ printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
goto err;
}
@@ -452,6 +444,8 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+ ourport->pm_level = level;
+
switch (level) {
case 3:
if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
@@ -661,6 +655,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
ourport->clksrc = clksrc;
ourport->baudclk = clk;
+ ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;
}
switch (termios->c_cflag & CSIZE) {
@@ -752,6 +747,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
return "S3C2440";
case PORT_S3C2412:
return "S3C2412";
+ case PORT_S3C6400:
+ return "S3C6400/10";
default:
return NULL;
}
@@ -827,14 +824,14 @@ static struct uart_ops s3c24xx_serial_ops = {
static struct uart_driver s3c24xx_uart_drv = {
.owner = THIS_MODULE,
.dev_name = "s3c2410_serial",
- .nr = 3,
+ .nr = CONFIG_SERIAL_SAMSUNG_UARTS,
.cons = S3C24XX_SERIAL_CONSOLE,
.driver_name = S3C24XX_SERIAL_NAME,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
-static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
+static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
@@ -859,7 +856,7 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
.line = 1,
}
},
-#if NR_PORTS > 2
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 2
[2] = {
.port = {
@@ -872,6 +869,20 @@ static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS] = {
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
}
+ },
+#endif
+#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
+ [3] = {
+ .port = {
+ .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
+ .iotype = UPIO_MEM,
+ .irq = IRQ_S3CUART_RX3,
+ .uartclk = 0,
+ .fifosize = 16,
+ .ops = &s3c24xx_serial_ops,
+ .flags = UPF_BOOT_AUTOCONF,
+ .line = 3,
+ }
}
#endif
};
@@ -890,6 +901,89 @@ static inline int s3c24xx_serial_resetport(struct uart_port *port,
return (info->reset_port)(port, cfg);
}
+
+#ifdef CONFIG_CPU_FREQ
+
+static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ struct s3c24xx_uart_port *port;
+ struct uart_port *uport;
+
+ port = container_of(nb, struct s3c24xx_uart_port, freq_transition);
+ uport = &port->port;
+
+ /* check to see if port is enabled */
+
+ if (port->pm_level != 0)
+ return 0;
+
+ /* try and work out if the baudrate is changing, we can detect
+ * a change in rate, but we do not have support for detecting
+ * a disturbance in the clock-rate over the change.
+ */
+
+ if (IS_ERR(port->clk))
+ goto exit;
+
+ if (port->baudclk_rate == clk_get_rate(port->clk))
+ goto exit;
+
+ if (val == CPUFREQ_PRECHANGE) {
+ /* we should really shut the port down whilst the
+ * frequency change is in progress. */
+
+ } else if (val == CPUFREQ_POSTCHANGE) {
+ struct ktermios *termios;
+ struct tty_struct *tty;
+
+ if (uport->info == NULL)
+ goto exit;
+
+ tty = uport->info->port.tty;
+
+ if (tty == NULL)
+ goto exit;
+
+ termios = tty->termios;
+
+ if (termios == NULL) {
+ printk(KERN_WARNING "%s: no termios?\n", __func__);
+ goto exit;
+ }
+
+ s3c24xx_serial_set_termios(uport, termios, NULL);
+ }
+
+ exit:
+ return 0;
+}
+
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+ port->freq_transition.notifier_call = s3c24xx_serial_cpufreq_transition;
+
+ return cpufreq_register_notifier(&port->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+ cpufreq_unregister_notifier(&port->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+}
+
+#else
+static inline int s3c24xx_serial_cpufreq_register(struct s3c24xx_uart_port *port)
+{
+ return 0;
+}
+
+static inline void s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port)
+{
+}
+#endif
+
/* s3c24xx_serial_init_port
*
* initialise a single serial port from the platform device given
@@ -914,8 +1008,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
if (port->mapbase != 0)
return 0;
- if (cfg->hwport > 3)
- return -EINVAL;
+ if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
+ printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
+ cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
+ return -ERANGE;
+ }
/* setup info for port */
port->dev = &platdev->dev;
@@ -943,18 +1040,26 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);
- port->mapbase = res->start;
- port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
+ port->mapbase = res->start;
+ port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000);
ret = platform_get_irq(platdev, 0);
if (ret < 0)
port->irq = 0;
- else
+ else {
port->irq = ret;
+ ourport->rx_irq = ret;
+ ourport->tx_irq = ret + 1;
+ }
+
+ ret = platform_get_irq(platdev, 1);
+ if (ret > 0)
+ ourport->tx_irq = ret;
ourport->clk = clk_get(&platdev->dev, "uart");
- dbg("port: map=%08x, mem=%08x, irq=%d, clock=%ld\n",
- port->mapbase, port->membase, port->irq, port->uartclk);
+ dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
+ port->mapbase, port->membase, port->irq,
+ ourport->rx_irq, ourport->tx_irq, port->uartclk);
/* reset the fifos (and setup the uart) */
s3c24xx_serial_resetport(port, cfg);
@@ -1002,6 +1107,10 @@ int s3c24xx_serial_probe(struct platform_device *dev,
if (ret < 0)
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
+ ret = s3c24xx_serial_cpufreq_register(ourport);
+ if (ret < 0)
+ dev_err(&dev->dev, "failed to add cpufreq notifier\n");
+
return 0;
probe_err:
@@ -1015,6 +1124,7 @@ int s3c24xx_serial_remove(struct platform_device *dev)
struct uart_port *port = s3c24xx_dev_to_port(&dev->dev);
if (port) {
+ s3c24xx_serial_cpufreq_deregister(to_ourport(port));
device_remove_file(&dev->dev, &dev_attr_clock_source);
uart_remove_one_port(&s3c24xx_uart_drv, port);
}
@@ -1219,7 +1329,7 @@ static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
platdev_ptr = s3c24xx_uart_devs;
- for (i = 0; i < NR_PORTS; i++, ptr++, platdev_ptr++) {
+ for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
}
@@ -1240,7 +1350,7 @@ s3c24xx_serial_console_setup(struct console *co, char *options)
/* is this a valid port */
- if (co->index == -1 || co->index >= NR_PORTS)
+ if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
co->index = 0;
port = &s3c24xx_serial_ports[co->index].port;
diff --git a/drivers/serial/samsung.h b/drivers/serial/samsung.h
index 5c92ebbe7d9e..571d6b90d206 100644
--- a/drivers/serial/samsung.h
+++ b/drivers/serial/samsung.h
@@ -33,12 +33,21 @@ struct s3c24xx_uart_info {
struct s3c24xx_uart_port {
unsigned char rx_claimed;
unsigned char tx_claimed;
+ unsigned int pm_level;
+ unsigned long baudclk_rate;
+
+ unsigned int rx_irq;
+ unsigned int tx_irq;
struct s3c24xx_uart_info *info;
struct s3c24xx_uart_clksrc *clksrc;
struct clk *clk;
struct clk *baudclk;
struct uart_port port;
+
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block freq_transition;
+#endif
};
/* conversion functions */
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 874786a11fe9..dc68b7e0c930 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -50,7 +50,7 @@ static struct lock_class_key port_lock_key;
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
-#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->port.blocked_open : 0))
+#define uart_users(state) ((state)->count + (state)->info.port.blocked_open)
#ifdef CONFIG_SERIAL_CORE_CONSOLE
#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
@@ -94,7 +94,7 @@ static void __uart_start(struct tty_struct *tty)
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
- if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf &&
+ if (!uart_circ_empty(&state->info.xmit) && state->info.xmit.buf &&
!tty->stopped && !tty->hw_stopped)
port->ops->start_tx(port);
}
@@ -113,7 +113,7 @@ static void uart_start(struct tty_struct *tty)
static void uart_tasklet_action(unsigned long data)
{
struct uart_state *state = (struct uart_state *)data;
- tty_wakeup(state->info->port.tty);
+ tty_wakeup(state->info.port.tty);
}
static inline void
@@ -139,7 +139,7 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
*/
static int uart_startup(struct uart_state *state, int init_hw)
{
- struct uart_info *info = state->info;
+ struct uart_info *info = &state->info;
struct uart_port *port = state->port;
unsigned long page;
int retval = 0;
@@ -212,14 +212,15 @@ static int uart_startup(struct uart_state *state, int init_hw)
*/
static void uart_shutdown(struct uart_state *state)
{
- struct uart_info *info = state->info;
+ struct uart_info *info = &state->info;
struct uart_port *port = state->port;
+ struct tty_struct *tty = info->port.tty;
/*
* Set the TTY IO error marker
*/
- if (info->port.tty)
- set_bit(TTY_IO_ERROR, &info->port.tty->flags);
+ if (tty)
+ set_bit(TTY_IO_ERROR, &tty->flags);
if (info->flags & UIF_INITIALIZED) {
info->flags &= ~UIF_INITIALIZED;
@@ -227,7 +228,7 @@ static void uart_shutdown(struct uart_state *state)
/*
* Turn off DTR and RTS early.
*/
- if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL))
+ if (!tty || (tty->termios->c_cflag & HUPCL))
uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
/*
@@ -427,7 +428,7 @@ EXPORT_SYMBOL(uart_get_divisor);
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
- struct tty_struct *tty = state->info->port.tty;
+ struct tty_struct *tty = state->info.port.tty;
struct uart_port *port = state->port;
struct ktermios *termios;
@@ -444,14 +445,14 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
* Set flags based on termios cflag
*/
if (termios->c_cflag & CRTSCTS)
- state->info->flags |= UIF_CTS_FLOW;
+ state->info.flags |= UIF_CTS_FLOW;
else
- state->info->flags &= ~UIF_CTS_FLOW;
+ state->info.flags &= ~UIF_CTS_FLOW;
if (termios->c_cflag & CLOCAL)
- state->info->flags &= ~UIF_CHECK_CD;
+ state->info.flags &= ~UIF_CHECK_CD;
else
- state->info->flags |= UIF_CHECK_CD;
+ state->info.flags |= UIF_CHECK_CD;
port->ops->set_termios(port, termios, old_termios);
}
@@ -479,7 +480,7 @@ static int uart_put_char(struct tty_struct *tty, unsigned char ch)
{
struct uart_state *state = tty->driver_data;
- return __uart_put_char(state->port, &state->info->xmit, ch);
+ return __uart_put_char(state->port, &state->info.xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
@@ -500,13 +501,13 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
- if (!state || !state->info) {
+ if (!state) {
WARN_ON(1);
return -EL3HLT;
}
port = state->port;
- circ = &state->info->xmit;
+ circ = &state->info.xmit;
if (!circ->buf)
return 0;
@@ -537,7 +538,7 @@ static int uart_write_room(struct tty_struct *tty)
int ret;
spin_lock_irqsave(&state->port->lock, flags);
- ret = uart_circ_chars_free(&state->info->xmit);
+ ret = uart_circ_chars_free(&state->info.xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
}
@@ -549,7 +550,7 @@ static int uart_chars_in_buffer(struct tty_struct *tty)
int ret;
spin_lock_irqsave(&state->port->lock, flags);
- ret = uart_circ_chars_pending(&state->info->xmit);
+ ret = uart_circ_chars_pending(&state->info.xmit);
spin_unlock_irqrestore(&state->port->lock, flags);
return ret;
}
@@ -564,7 +565,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
* This means you called this function _after_ the port was
* closed. No cookie for you.
*/
- if (!state || !state->info) {
+ if (!state) {
WARN_ON(1);
return;
}
@@ -573,7 +574,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
- uart_circ_clear(&state->info->xmit);
+ uart_circ_clear(&state->info.xmit);
if (port->ops->flush_buffer)
port->ops->flush_buffer(port);
spin_unlock_irqrestore(&port->lock, flags);
@@ -837,15 +838,15 @@ static int uart_set_info(struct uart_state *state,
state->closing_wait = closing_wait;
if (new_serial.xmit_fifo_size)
port->fifosize = new_serial.xmit_fifo_size;
- if (state->info->port.tty)
- state->info->port.tty->low_latency =
+ if (state->info.port.tty)
+ state->info.port.tty->low_latency =
(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
check_and_exit:
retval = 0;
if (port->type == PORT_UNKNOWN)
goto exit;
- if (state->info->flags & UIF_INITIALIZED) {
+ if (state->info.flags & UIF_INITIALIZED) {
if (((old_flags ^ port->flags) & UPF_SPD_MASK) ||
old_custom_divisor != port->custom_divisor) {
/*
@@ -858,7 +859,7 @@ static int uart_set_info(struct uart_state *state,
printk(KERN_NOTICE
"%s sets custom speed on %s. This "
"is deprecated.\n", current->comm,
- tty_name(state->info->port.tty, buf));
+ tty_name(state->info.port.tty, buf));
}
uart_change_speed(state, NULL);
}
@@ -889,8 +890,8 @@ static int uart_get_lsr_info(struct uart_state *state,
* interrupt happens).
*/
if (port->x_char ||
- ((uart_circ_chars_pending(&state->info->xmit) > 0) &&
- !state->info->port.tty->stopped && !state->info->port.tty->hw_stopped))
+ ((uart_circ_chars_pending(&state->info.xmit) > 0) &&
+ !state->info.port.tty->stopped && !state->info.port.tty->hw_stopped))
result &= ~TIOCSER_TEMT;
return put_user(result, value);
@@ -1017,7 +1018,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
port->ops->enable_ms(port);
spin_unlock_irq(&port->lock);
- add_wait_queue(&state->info->delta_msr_wait, &wait);
+ add_wait_queue(&state->info.delta_msr_wait, &wait);
for (;;) {
spin_lock_irq(&port->lock);
memcpy(&cnow, &port->icount, sizeof(struct uart_icount));
@@ -1045,7 +1046,7 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg)
}
current->state = TASK_RUNNING;
- remove_wait_queue(&state->info->delta_msr_wait, &wait);
+ remove_wait_queue(&state->info.delta_msr_wait, &wait);
return ret;
}
@@ -1241,7 +1242,7 @@ static void uart_set_termios(struct tty_struct *tty,
*/
if (!(old_termios->c_cflag & CLOCAL) &&
(tty->termios->c_cflag & CLOCAL))
- wake_up_interruptible(&state->info->port.open_wait);
+ wake_up_interruptible(&info->port.open_wait);
#endif
}
@@ -1303,7 +1304,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
* At this point, we stop accepting input. To do this, we
* disable the receive line status interrupts.
*/
- if (state->info->flags & UIF_INITIALIZED) {
+ if (state->info.flags & UIF_INITIALIZED) {
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
port->ops->stop_rx(port);
@@ -1322,9 +1323,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
tty_ldisc_flush(tty);
tty->closing = 0;
- state->info->port.tty = NULL;
+ state->info.port.tty = NULL;
- if (state->info->port.blocked_open) {
+ if (state->info.port.blocked_open) {
if (state->close_delay)
msleep_interruptible(state->close_delay);
} else if (!uart_console(port)) {
@@ -1334,8 +1335,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
/*
* Wake up anyone trying to open this port.
*/
- state->info->flags &= ~UIF_NORMAL_ACTIVE;
- wake_up_interruptible(&state->info->port.open_wait);
+ state->info.flags &= ~UIF_NORMAL_ACTIVE;
+ wake_up_interruptible(&state->info.port.open_wait);
done:
mutex_unlock(&state->mutex);
@@ -1409,19 +1410,20 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout)
static void uart_hangup(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ struct uart_info *info = &state->info;
BUG_ON(!kernel_locked());
pr_debug("uart_hangup(%d)\n", state->port->line);
mutex_lock(&state->mutex);
- if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) {
+ if (info->flags & UIF_NORMAL_ACTIVE) {
uart_flush_buffer(tty);
uart_shutdown(state);
state->count = 0;
- state->info->flags &= ~UIF_NORMAL_ACTIVE;
- state->info->port.tty = NULL;
- wake_up_interruptible(&state->info->port.open_wait);
- wake_up_interruptible(&state->info->delta_msr_wait);
+ info->flags &= ~UIF_NORMAL_ACTIVE;
+ info->port.tty = NULL;
+ wake_up_interruptible(&info->port.open_wait);
+ wake_up_interruptible(&info->delta_msr_wait);
}
mutex_unlock(&state->mutex);
}
@@ -1434,7 +1436,7 @@ static void uart_hangup(struct tty_struct *tty)
*/
static void uart_update_termios(struct uart_state *state)
{
- struct tty_struct *tty = state->info->port.tty;
+ struct tty_struct *tty = state->info.port.tty;
struct uart_port *port = state->port;
if (uart_console(port) && port->cons->cflag) {
@@ -1469,7 +1471,7 @@ static int
uart_block_til_ready(struct file *filp, struct uart_state *state)
{
DECLARE_WAITQUEUE(wait, current);
- struct uart_info *info = state->info;
+ struct uart_info *info = &state->info;
struct uart_port *port = state->port;
unsigned int mctrl;
@@ -1563,28 +1565,6 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line)
ret = -ENXIO;
goto err_unlock;
}
-
- /* BKL: RACE HERE - LEAK */
- /* We should move this into the uart_state structure and kill off
- this whole complexity */
- if (!state->info) {
- state->info = kzalloc(sizeof(struct uart_info), GFP_KERNEL);
- if (state->info) {
- init_waitqueue_head(&state->info->port.open_wait);
- init_waitqueue_head(&state->info->delta_msr_wait);
-
- /*
- * Link the info into the other structures.
- */
- state->port->info = state->info;
-
- tasklet_init(&state->info->tlet, uart_tasklet_action,
- (unsigned long)state);
- } else {
- ret = -ENOMEM;
- goto err_unlock;
- }
- }
return state;
err_unlock:
@@ -1641,9 +1621,10 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
* Any failures from here onwards should not touch the count.
*/
tty->driver_data = state;
+ state->port->info = &state->info;
tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
- state->info->port.tty = tty;
+ state->info.port.tty = tty;
/*
* If the port is in the middle of closing, bail out now.
@@ -1676,8 +1657,8 @@ static int uart_open(struct tty_struct *tty, struct file *filp)
/*
* If this is the first open to succeed, adjust things to suit.
*/
- if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) {
- state->info->flags |= UIF_NORMAL_ACTIVE;
+ if (retval == 0 && !(state->info.flags & UIF_NORMAL_ACTIVE)) {
+ state->info.flags |= UIF_NORMAL_ACTIVE;
uart_update_termios(state);
}
@@ -2028,11 +2009,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
}
port->suspended = 1;
- if (state->info && state->info->flags & UIF_INITIALIZED) {
+ if (state->info.flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
int tries;
- state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
+ state->info.flags = (state->info.flags & ~UIF_INITIALIZED)
| UIF_SUSPENDED;
spin_lock_irq(&port->lock);
@@ -2107,15 +2088,15 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
/*
* If that's unset, use the tty termios setting.
*/
- if (state->info && state->info->port.tty && termios.c_cflag == 0)
- termios = *state->info->port.tty->termios;
+ if (state->info.port.tty && termios.c_cflag == 0)
+ termios = *state->info.port.tty->termios;
uart_change_pm(state, 0);
port->ops->set_termios(port, &termios, NULL);
console_start(port->cons);
}
- if (state->info && state->info->flags & UIF_SUSPENDED) {
+ if (state->info.flags & UIF_SUSPENDED) {
const struct uart_ops *ops = port->ops;
int ret;
@@ -2130,7 +2111,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
ops->set_mctrl(port, port->mctrl);
ops->start_tx(port);
spin_unlock_irq(&port->lock);
- state->info->flags |= UIF_INITIALIZED;
+ state->info.flags |= UIF_INITIALIZED;
} else {
/*
* Failed to resume - maybe hardware went away?
@@ -2140,7 +2121,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
uart_shutdown(state);
}
- state->info->flags &= ~UIF_SUSPENDED;
+ state->info.flags &= ~UIF_SUSPENDED;
}
mutex_unlock(&state->mutex);
@@ -2198,11 +2179,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* Now do the auto configuration stuff. Note that config_port
* is expected to claim the resources and map the port for us.
*/
- flags = UART_CONFIG_TYPE;
+ flags = 0;
if (port->flags & UPF_AUTO_IRQ)
flags |= UART_CONFIG_IRQ;
if (port->flags & UPF_BOOT_AUTOCONF) {
- port->type = PORT_UNKNOWN;
+ if (!(port->flags & UPF_FIXED_TYPE)) {
+ port->type = PORT_UNKNOWN;
+ flags |= UART_CONFIG_TYPE;
+ }
port->ops->config_port(port, flags);
}
@@ -2383,8 +2367,12 @@ int uart_register_driver(struct uart_driver *drv)
state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
-
mutex_init(&state->mutex);
+
+ tty_port_init(&state->info.port);
+ init_waitqueue_head(&state->info.delta_msr_wait);
+ tasklet_init(&state->info.tlet, uart_tasklet_action,
+ (unsigned long)state);
}
retval = tty_register_driver(normal);
@@ -2455,7 +2443,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
state->pm_state = -1;
port->cons = drv->cons;
- port->info = state->info;
+ port->info = &state->info;
/*
* If this port is a console, then the spinlock is already
@@ -2527,18 +2515,11 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
*/
tty_unregister_device(drv->tty_driver, port->line);
- info = state->info;
+ info = &state->info;
if (info && info->port.tty)
tty_vhangup(info->port.tty);
/*
- * All users of this port should now be disconnected from
- * this driver, and the port shut down. We should be the
- * only thread fiddling with this port from now on.
- */
- state->info = NULL;
-
- /*
* Free the port IO and memory resources, if any.
*/
if (port->type != PORT_UNKNOWN)
@@ -2552,10 +2533,8 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
/*
* Kill the tasklet, and free resources.
*/
- if (info) {
+ if (info)
tasklet_kill(&info->tlet);
- kfree(info);
- }
state->port = NULL;
mutex_unlock(&port_mutex);
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index 61dc8b3daa26..a7bf024a8286 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -41,9 +41,10 @@
#include <linux/tty_flip.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/irq.h>
+#include <mach/hardware.h>
#define DEV_MAJOR 204
#define DEV_MINOR 16