/* OF Platform device Usage :
*
* This driver is only used for PSCs configured in uart mode. The device
- * tree will have a node for each PSC in uart mode w/ device_type = "serial"
- * and "mpc52xx-psc-uart" in the compatible string
+ * tree will have a node for each PSC with "mpc52xx-psc-uart" in the compatible
+ * list.
*
* By default, PSC devices are enumerated in the order they are found. However
* a particular PSC number can be forces by adding 'device_no = <port#>'
static void
mpc52xx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* Not implemented */
+ if (mctrl & TIOCM_RTS)
+ out_8(&PSC(port)->op1, MPC52xx_PSC_OP_RTS);
+ else
+ out_8(&PSC(port)->op0, MPC52xx_PSC_OP_RTS);
}
static unsigned int
mpc52xx_uart_get_mctrl(struct uart_port *port)
{
- /* Not implemented */
- return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+ unsigned int ret = TIOCM_DSR;
+ u8 status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+
+ if (!(status & MPC52xx_PSC_CTS))
+ ret |= TIOCM_CTS;
+ if (!(status & MPC52xx_PSC_DCD))
+ ret |= TIOCM_CAR;
+
+ return ret;
}
static void
static void
mpc52xx_uart_enable_ms(struct uart_port *port)
{
- /* Not implemented */
+ struct mpc52xx_psc __iomem *psc = PSC(port);
+
+ /* clear D_*-bits by reading them */
+ in_8(&psc->mpc52xx_psc_ipcr);
+ /* enable CTS and DCD as IPC interrupts */
+ out_8(&psc->mpc52xx_psc_acr, MPC52xx_PSC_IEC_CTS | MPC52xx_PSC_IEC_DCD);
+
+ port->read_status_mask |= MPC52xx_PSC_IMR_IPC;
+ out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
}
static void
/* Request IRQ */
ret = request_irq(port->irq, mpc52xx_uart_int,
- IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
"mpc52xx_psc_uart", port);
if (ret)
return ret;
MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
MPC52xx_PSC_MODE_ONE_STOP;
+ if (new->c_cflag & CRTSCTS) {
+ mr1 |= MPC52xx_PSC_MODE_RXRTS;
+ mr2 |= MPC52xx_PSC_MODE_TXCTS;
+ }
baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
quot = uart_get_divisor(port, baud);
/* Update the per-port timeout */
uart_update_timeout(port, new->c_cflag, baud);
- /* Do our best to flush TX & RX, so we don't loose anything */
- /* But we don't wait indefinitly ! */
+ /* Do our best to flush TX & RX, so we don't lose anything */
+ /* But we don't wait indefinitely ! */
j = 5000000; /* Maximum wait */
/* FIXME Can't receive chars since set_termios might be called at early
* boot for the console, all stuff is not yet ready to receive at that
out_8(&psc->ctur, ctr >> 8);
out_8(&psc->ctlr, ctr & 0xff);
+ if (UART_ENABLE_MS(port, new->c_cflag))
+ mpc52xx_uart_enable_ms(port);
+
/* Reenable TX & RX */
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
if (status & MPC52xx_PSC_SR_RB) {
flag = TTY_BREAK;
uart_handle_break(port);
- } else if (status & MPC52xx_PSC_SR_PE)
+ port->icount.brk++;
+ } else if (status & MPC52xx_PSC_SR_PE) {
flag = TTY_PARITY;
- else if (status & MPC52xx_PSC_SR_FE)
+ port->icount.parity++;
+ }
+ else if (status & MPC52xx_PSC_SR_FE) {
flag = TTY_FRAME;
+ port->icount.frame++;
+ }
/* Clear error condition */
out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
* affect the current character
*/
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ port->icount.overrun++;
}
}
struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
+ u8 status;
spin_lock(&port->lock);
if (psc_ops->tx_rdy(port))
keepgoing |= mpc52xx_uart_int_tx_chars(port);
+ status = in_8(&PSC(port)->mpc52xx_psc_ipcr);
+ if (status & MPC52xx_PSC_D_DCD)
+ uart_handle_dcd_change(port, !(status & MPC52xx_PSC_DCD));
+
+ if (status & MPC52xx_PSC_D_CTS)
+ uart_handle_cts_change(port, !(status & MPC52xx_PSC_CTS));
+
/* Limit number of iteration */
if (!(--pass))
keepgoing = 0;
return ret;
port->mapbase = res.start;
+ if (!port->mapbase) {
+ dev_dbg(&op->dev, "Could not allocate resources for PSC\n");
+ return -EINVAL;
+ }
+
port->irq = irq_of_parse_and_map(op->node, 0);
+ if (port->irq == NO_IRQ) {
+ dev_dbg(&op->dev, "Could not get irq\n");
+ return -EINVAL;
+ }
dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
(void *)port->mapbase, port->irq, port->uartclk);
- if ((port->irq == NO_IRQ) || !port->mapbase) {
- printk(KERN_ERR "Could not allocate resources for PSC\n");
- return -EINVAL;
- }
-
/* Add the port to the uart sub-system */
ret = uart_add_one_port(&mpc52xx_uart_driver, port);
- if (!ret)
- dev_set_drvdata(&op->dev, (void *)port);
+ if (ret) {
+ irq_dispose_mapping(port->irq);
+ return ret;
+ }
- return ret;
+ dev_set_drvdata(&op->dev, (void *)port);
+ return 0;
}
static int
#endif
static void
-mpc52xx_uart_of_assign(struct device_node *np, int idx)
+mpc52xx_uart_of_assign(struct device_node *np)
{
- int free_idx = -1;
int i;
- /* Find the first free node */
+ /* Find the first free PSC number */
for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
if (mpc52xx_uart_nodes[i] == NULL) {
- free_idx = i;
- break;
+ of_node_get(np);
+ mpc52xx_uart_nodes[i] = np;
+ return;
}
}
-
- if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
- idx = free_idx;
-
- if (idx < 0)
- return; /* No free slot; abort */
-
- of_node_get(np);
- /* If the slot is already occupied, then swap slots */
- if (mpc52xx_uart_nodes[idx] && (free_idx != -1))
- mpc52xx_uart_nodes[free_idx] = mpc52xx_uart_nodes[idx];
- mpc52xx_uart_nodes[idx] = np;
}
static void
{
static int enum_done;
struct device_node *np;
- const unsigned int *devno;
const struct of_device_id *match;
int i;
if (enum_done)
return;
- for_each_node_by_type(np, "serial") {
+ /* Assign index to each PSC in device tree */
+ for_each_matching_node(np, mpc52xx_uart_of_match) {
match = of_match_node(mpc52xx_uart_of_match, np);
- if (!match)
- continue;
-
psc_ops = match->data;
-
- /* Is a particular device number requested? */
- devno = of_get_property(np, "port-number", NULL);
- mpc52xx_uart_of_assign(np, devno ? *devno : -1);
+ mpc52xx_uart_of_assign(np);
}
enum_done = 1;