static unsigned int imapx200_serial_getclk(struct uart_port *port, struct imapx200_uart_clksrc **clksrc, struct clk **clk, unsigned int baud) { struct imapx200_uartcfg *cfg = imapx200_port_to_cfg(port); struct imapx200_uart_clksrc *clkp; struct baud_calc res[MAX_CLKS]; struct baud_calc *resptr, *best, *sptr; int i; clkp = cfg->clocks; best = NULL; if (cfg->clocks_size < 2) { if (cfg->clocks_size == 0) clkp = &tmp_clksrc; imapx200_serial_calcbaud(res, port, clkp, baud); best = res; resptr = best + 1; } else { resptr = res; for (i = 0; i < cfg->clocks_size; i++, clkp++) { if (imapx200_serial_calcbaud(resptr, port, clkp, baud)) resptr++; } } /* ok, we now need to select the best clock we found */ if (!best) { unsigned int deviation = (1<<30)|((1<<30)-1); int calc_deviation; for (sptr = res; sptr < resptr; sptr++) { calc_deviation = baud - sptr->calc; if (calc_deviation < 0) calc_deviation = -calc_deviation; if (calc_deviation < deviation) { best = sptr; deviation = calc_deviation; } } } /* store results to pass back */ *clksrc = best->clksrc; *clk = best->src; return best->divisor; }
static int imapx200_serial_resume(struct platform_device *dev) { struct uart_port *port = imapx200_dev_to_port(&dev->dev); struct imapx200_uart_port *ourport = to_ourport(port); if (port) { clk_enable(ourport->clk); imapx200_serial_resetport(port, imapx200_port_to_cfg(port)); clk_disable(ourport->clk); uart_resume_port(&imapx200_uart_drv, port); } return 0; }
static int imapx200_serial_resume(struct platform_device *dev) { struct uart_port *port = imapx200_dev_to_port(&dev->dev); struct imapx200_uart_port *ourport = to_ourport(port); if (port) { clk_enable(ourport->clk); imapx200_serial_resetport(port, imapx200_port_to_cfg(port)); clk_disable(ourport->clk); uart_resume_port(&imapx200_uart_drv, port); } if(port->irq == IRQ_UART3) { printk(KERN_ERR "resume port3: mdelay.\n"); mdelay(20); } return 0; }
static void imapx200_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct imapx200_uartcfg *cfg = imapx200_port_to_cfg(port); struct imapx200_uart_port *ourport = to_ourport(port); struct imapx200_uart_clksrc *clksrc = NULL; struct clk *clk = NULL; unsigned long flags; unsigned int baud, divisor = 0; unsigned int lcr = 0, mcr = 0; /* * We don't support modem control lines. */ termios->c_cflag &= ~(HUPCL | CMSPAR); termios->c_cflag |= CLOCAL; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); if ((baud == 38400) && ((port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)) divisor = port->custom_divisor; else divisor = imapx200_serial_getclk(port, &clksrc, &clk, baud); /* check to see if we need to change clock source */ if (ourport->clksrc != clksrc || ourport->baudclk != clk) { imapx200_serial_setsource(port, clksrc); if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { clk_disable(ourport->baudclk); ourport->baudclk = NULL; } clk_enable(clk); ourport->clksrc = clksrc; ourport->baudclk = clk; } switch (termios->c_cflag & CSIZE) { case CS5: dbg("config: 5bits/char\n"); lcr |= IMAPX200_LCR_DLS_5BIT; break; case CS6: dbg("config: 6bits/char\n"); lcr |= IMAPX200_LCR_DLS_6BIT; break; case CS7: dbg("config: 7bits/char\n"); lcr |= IMAPX200_LCR_DLS_7BIT; break; case CS8: default: dbg("config: 8bits/char\n"); lcr |= IMAPX200_LCR_DLS_8BIT; break; } /* preserve original lcon IR settings */ mcr |= (cfg->mcr & IMAPX200_MCR_SIRE_IRDA_ENABLE); if (termios->c_cflag & CSTOPB) lcr |= IMAPX200_LCR_STOP_1POINT5_2_STOP_BIT; if (termios->c_cflag & CRTSCTS) mcr |= IMAPX200_MCR_AFCE_AFC_ENABLE; else mcr &= ~IMAPX200_MCR_AFCE_AFC_ENABLE; if (termios->c_cflag & PARENB) { lcr |= IMAPX200_LCR_PEN_PARITY_ENABLE; if (termios->c_cflag & PARODD) lcr &= ~IMAPX200_LCR_EPS_EVEN_PARITY; else lcr |= IMAPX200_LCR_EPS_EVEN_PARITY; } else { lcr &= ~IMAPX200_LCR_PEN_PARITY_ENABLE; } spin_lock_irqsave(&port->lock, flags); dbg("setting lcr to %08x, divisor to %d\n", lcr, divisor); wr_regl(port, IMAPX200_LCR, (lcr | IMAPX200_LCR_DLAB_ENABLE)); wr_regl(port, IMAPX200_DLL, (divisor & 0xff)); wr_regl(port, IMAPX200_DLH, ((divisor & 0xff00) >> 8)); wr_regl(port, IMAPX200_LCR, (lcr & ~IMAPX200_LCR_DLAB_ENABLE)); wr_regl(port, IMAPX200_LCR, lcr); wr_regl(port, IMAPX200_MCR, mcr); dbg("uart: lcr = 0x%08x, mcr = 0x%08x\n", rd_regl(port, IMAPX200_LCR), rd_regl(port, IMAPX200_MCR)); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); /* * Which character status flags are we interested in? */ port->read_status_mask = IMAPX200_LSR_OE_MASK; if (termios->c_iflag & INPCK) port->read_status_mask |= IMAPX200_LSR_FE_MASK | IMAPX200_LSR_PE_MASK; /* * Which character status flags should we ignore? */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= IMAPX200_LSR_OE_MASK; if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) port->ignore_status_mask |= IMAPX200_LSR_FE_MASK; /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= RXSTAT_DUMMY_READ; spin_unlock_irqrestore(&port->lock, flags); }