#include <linux/dma-mapping.h>
#include <linux/fs_uart_pd.h>
#include <linux/of_platform.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
#include <asm/io.h>
#include <asm/irq.h>
static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- /* Whee. Do nothing. */
+ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+ if (pinfo->gpios[GPIO_RTS] >= 0)
+ gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS));
+
+ if (pinfo->gpios[GPIO_DTR] >= 0)
+ gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR));
}
static unsigned int cpm_uart_get_mctrl(struct uart_port *port)
{
- /* Whee. Do nothing. */
- return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+ unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
+
+ if (pinfo->gpios[GPIO_CTS] >= 0) {
+ if (gpio_get_value(pinfo->gpios[GPIO_CTS]))
+ mctrl &= ~TIOCM_CTS;
+ }
+
+ if (pinfo->gpios[GPIO_DSR] >= 0) {
+ if (gpio_get_value(pinfo->gpios[GPIO_DSR]))
+ mctrl &= ~TIOCM_DSR;
+ }
+
+ if (pinfo->gpios[GPIO_DCD] >= 0) {
+ if (gpio_get_value(pinfo->gpios[GPIO_DCD]))
+ mctrl &= ~TIOCM_CAR;
+ }
+
+ if (pinfo->gpios[GPIO_RI] >= 0) {
+ if (!gpio_get_value(pinfo->gpios[GPIO_RI]))
+ mctrl |= TIOCM_RNG;
+ }
+
+ return mctrl;
}
/*
cpm_uart_tx_pump(port);
}
+#ifdef CONFIG_CONSOLE_POLL
+static int serial_polled;
+#endif
+
/*
* Receive characters
*/
*/
bdp = pinfo->rx_cur;
for (;;) {
+#ifdef CONFIG_CONSOLE_POLL
+ if (unlikely(serial_polled)) {
+ serial_polled = 0;
+ return;
+ }
+#endif
/* get status */
status = in_be16(&bdp->cbd_sc);
/* If this one is empty, return happy */
goto handle_error;
if (uart_handle_sysrq_char(port, ch))
continue;
-
+#ifdef CONFIG_CONSOLE_POLL
+ if (unlikely(serial_polled)) {
+ serial_polled = 0;
+ return;
+ }
+#endif
error_return:
tty_insert_flip_char(tty, ch, flg);
}
/* Shut them really down and reinit buffer descriptors */
- if (IS_SMC(pinfo))
+ if (IS_SMC(pinfo)) {
+ out_be16(&pinfo->smcup->smc_brkcr, 0);
cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
- else
+ } else {
+ out_be16(&pinfo->sccup->scc_brkcr, 0);
cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
+ }
cpm_uart_initbd(pinfo);
}
* enables, because we want to put them back if they were
* present.
*/
- prev_mode = in_be16(&smcp->smc_smcmr);
- out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval | SMCMR_SM_UART);
- setbits16(&smcp->smc_smcmr, (prev_mode & (SMCMR_REN | SMCMR_TEN)));
+ prev_mode = in_be16(&smcp->smc_smcmr) & (SMCMR_REN | SMCMR_TEN);
+ /* Output in *one* operation, so we don't interrupt RX/TX if they
+ * were already enabled. */
+ out_be16(&smcp->smc_smcmr, smcr_mk_clen(bits) | cval |
+ SMCMR_SM_UART | prev_mode);
} else {
out_be16(&sccp->scc_psmr, (sbits << 12) | scval);
}
- cpm_set_brg(pinfo->brg - 1, baud);
+ if (pinfo->clk)
+ clk_set_rate(pinfo->clk, baud);
+ else
+ cpm_set_brg(pinfo->brg - 1, baud);
spin_unlock_irqrestore(&port->lock, flags);
}
cpm_uart_request_port(port);
}
}
+
+#ifdef CONFIG_CONSOLE_POLL
+/* Serial polling routines for writing and reading from the uart while
+ * in an interrupt or debug context.
+ */
+
+#define GDB_BUF_SIZE 512 /* power of 2, please */
+
+static char poll_buf[GDB_BUF_SIZE];
+static char *pollp;
+static int poll_chars;
+
+static int poll_wait_key(char *obuf, struct uart_cpm_port *pinfo)
+{
+ u_char c, *cp;
+ volatile cbd_t *bdp;
+ int i;
+
+ /* Get the address of the host memory buffer.
+ */
+ bdp = pinfo->rx_cur;
+ while (bdp->cbd_sc & BD_SC_EMPTY)
+ ;
+
+ /* If the buffer address is in the CPM DPRAM, don't
+ * convert it.
+ */
+ cp = cpm2cpu_addr(bdp->cbd_bufaddr, pinfo);
+
+ if (obuf) {
+ i = c = bdp->cbd_datlen;
+ while (i-- > 0)
+ *obuf++ = *cp++;
+ } else
+ c = *cp;
+ bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID);
+ bdp->cbd_sc |= BD_SC_EMPTY;
+
+ if (bdp->cbd_sc & BD_SC_WRAP)
+ bdp = pinfo->rx_bd_base;
+ else
+ bdp++;
+ pinfo->rx_cur = (cbd_t *)bdp;
+
+ return (int)c;
+}
+
+static int cpm_get_poll_char(struct uart_port *port)
+{
+ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+
+ if (!serial_polled) {
+ serial_polled = 1;
+ poll_chars = 0;
+ }
+ if (poll_chars <= 0) {
+ poll_chars = poll_wait_key(poll_buf, pinfo);
+ pollp = poll_buf;
+ }
+ poll_chars--;
+ return *pollp++;
+}
+
+static void cpm_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port;
+ static char ch[2];
+
+ ch[0] = (char)c;
+ cpm_uart_early_write(pinfo->port.line, ch, 1);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
static struct uart_ops cpm_uart_pops = {
.tx_empty = cpm_uart_tx_empty,
.set_mctrl = cpm_uart_set_mctrl,
.request_port = cpm_uart_request_port,
.config_port = cpm_uart_config_port,
.verify_port = cpm_uart_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = cpm_get_poll_char,
+ .poll_put_char = cpm_put_poll_char,
+#endif
};
struct uart_cpm_port cpm_uart_ports[UART_NR];
void __iomem *mem, *pram;
int len;
int ret;
+ int i;
- data = of_get_property(np, "fsl,cpm-brg", &len);
- if (!data || len != 4) {
- printk(KERN_ERR "CPM UART %s has no/invalid "
- "fsl,cpm-brg property.\n", np->name);
- return -EINVAL;
+ data = of_get_property(np, "clock", NULL);
+ if (data) {
+ struct clk *clk = clk_get(NULL, (const char*)data);
+ if (!IS_ERR(clk))
+ pinfo->clk = clk;
+ }
+ if (!pinfo->clk) {
+ data = of_get_property(np, "fsl,cpm-brg", &len);
+ if (!data || len != 4) {
+ printk(KERN_ERR "CPM UART %s has no/invalid "
+ "fsl,cpm-brg property.\n", np->name);
+ return -EINVAL;
+ }
+ pinfo->brg = *data;
}
- pinfo->brg = *data;
data = of_get_property(np, "fsl,cpm-command", &len);
if (!data || len != 4) {
goto out_pram;
}
+ for (i = 0; i < NUM_GPIOS; i++)
+ pinfo->gpios[i] = of_get_gpio(np, i);
+
return cpm_uart_request_port(&pinfo->port);
out_pram:
udbg_putc = NULL;
#endif
- cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
-
if (IS_SMC(pinfo)) {
+ out_be16(&pinfo->smcup->smc_brkcr, 0);
+ cpm_line_cr_cmd(pinfo, CPM_CR_STOP_TX);
clrbits8(&pinfo->smcp->smc_smcm, SMCM_RX | SMCM_TX);
clrbits16(&pinfo->smcp->smc_smcmr, SMCMR_REN | SMCMR_TEN);
} else {
+ out_be16(&pinfo->sccup->scc_brkcr, 0);
+ cpm_line_cr_cmd(pinfo, CPM_CR_GRA_STOP_TX);
clrbits16(&pinfo->sccp->scc_sccm, UART_SCCM_TX | UART_SCCM_RX);
clrbits32(&pinfo->sccp->scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
}