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); tx_enabled(port) = 0; ourport->tx_claimed = 0; } if (ourport->rx_claimed) { free_irq(RX_IRQ(port), ourport); ourport->rx_claimed = 0; rx_enabled(port) = 0; } }
static int s3c24xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); int ret; dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", port->mapbase, port->membase); rx_enabled(port) = 1; ret = request_irq(RX_IRQ(port), s3c24xx_serial_rx_chars, 0, s3c24xx_serial_portname(port), ourport); if (ret != 0) { printk(KERN_ERR "cannot get irq %d\n", RX_IRQ(port)); return ret; } ourport->rx_claimed = 1; dbg("requesting tx irq...\n"); tx_enabled(port) = 1; ret = request_irq(TX_IRQ(port), s3c24xx_serial_tx_chars, 0, s3c24xx_serial_portname(port), ourport); if (ret) { printk(KERN_ERR "cannot get irq %d\n", TX_IRQ(port)); goto err; } ourport->tx_claimed = 1; dbg("s3c24xx_serial_startup ok\n"); /* the port reset code should have done the correct * register setup for the port controls */ return ret; err: s3c24xx_serial_shutdown(port); return ret; }
static int s3c24xx_serial_startup(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); int ret; dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n", port->mapbase, port->membase); rx_enabled(port) = 1; 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", ourport->rx_irq); return ret; } ourport->rx_claimed = 1; dbg("requesting tx irq...\n"); tx_enabled(port) = 1; 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", ourport->tx_irq); goto err; } ourport->tx_claimed = 1; dbg("s3c24xx_serial_startup ok\n"); return ret; err: s3c24xx_serial_shutdown(port); return ret; }
static void s3c24xx_serial_start_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct circ_buf *xmit = &port->state->xmit; if (!tx_enabled(port)) { if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_disable(port); tx_enabled(port) = 1; if (!ourport->dma || !ourport->dma->tx_chan) s3c24xx_serial_start_tx_pio(ourport); } if (ourport->dma && ourport->dma->tx_chan) { if (!uart_circ_empty(xmit) && !ourport->tx_in_progress) s3c24xx_serial_start_next_tx(ourport); } }
static void s3c24xx_serial_start_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); static int a =1;//temp if (port->line == 3) { // printk("485_start_tx\n"); if(a){ s3c_gpio_cfgpin(S3C64XX_GPK(5), S3C_GPIO_SFN(1)); a=0; } gpio_set_value(S3C64XX_GPK(5), 1); } if (!tx_enabled(port)) { if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_disable(port); enable_irq(ourport->tx_irq); tx_enabled(port) = 1; } }
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 int imapx200_serial_startup(struct uart_port *port) { struct imapx200_uart_port *ourport = to_ourport(port); int ret; unsigned long flags; dbg("imapx200_serial_startup: port=%p (%08lx,%p)\n", port->mapbase, port->membase); // local_irq_save(flags); rx_enabled(port) = 1; // tx_enabled(port) = 1; uart_enable_irq(port, UART_RX_INT); uart_enable_irq(port, UART_ERR_INT); // uart_enable_irq(port, UART_THRE_INT); ret = request_irq(UART_IRQ(port), imapx200_serial_interrupt, IRQF_DISABLED, imapx200_serial_portname(port), ourport); if (ret != 0) { printk(KERN_ERR "cannot get irq %d\n", UART_IRQ(port)); goto err; } ourport->tx_claimed = 1; ourport->rx_claimed = 1; dbg("imapx200_serial_startup ok\n"); /* the port reset code should have done the correct * register setup for the port controls */ // local_irq_restore(flags); return ret; err: imapx200_serial_shutdown(port); return ret; }
static void s3c24xx_serial_shutdown(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); if (ourport->tx_claimed) { disable_irq(ourport->tx_irq); free_irq(ourport->tx_irq, ourport); tx_enabled(port) = 0; ourport->tx_claimed = 0; } if (ourport->rx_claimed) { disable_irq(ourport->rx_irq); free_irq(ourport->rx_irq, ourport); ourport->rx_claimed = 0; rx_enabled(port) = 0; } if (cfg->set_runstate) cfg->set_runstate(0); }
static int s3c24xx_serial_calcbaud(struct baud_calc *calc, struct uart_port *port, struct s3c24xx_uart_clksrc *clksrc, unsigned int baud) { struct s3c24xx_uart_port *ourport = to_ourport(port); unsigned long rate; calc->src = clk_get(port->dev, clksrc->name); if (calc->src == NULL || IS_ERR(calc->src)) return 0; rate = clk_get_rate(calc->src); rate /= clksrc->divisor; calc->clksrc = clksrc; if (ourport->info->has_divslot) { unsigned long div = rate / baud; /* The UDIVSLOT register on the newer UARTs allows us to * get a divisor adjustment of 1/16th on the baud clock. * * We don't keep the UDIVSLOT value (the 16ths we calculated * by not multiplying the baud by 16) as it is easy enough * to recalculate. */ calc->quot = div / 16; calc->calc = rate / div; } else { calc->quot = (rate + (8 * baud)) / (16 * baud); calc->calc = (rate / (calc->quot * 16)); } calc->quot--; return 1; }
static void imapx200_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) { struct imapx200_uart_port *ourport = to_ourport(port); switch (level) { case 3: if (!IS_ERR(ourport->baudclk) && (ourport->baudclk != NULL)) clk_disable(ourport->baudclk); clk_disable(ourport->clk); break; case 0: clk_enable(ourport->clk); if (!IS_ERR(ourport->baudclk) && (ourport->baudclk != NULL)) clk_enable(ourport->baudclk); break; default: printk(KERN_ERR "imapx200_serial: unknown pm %d\n", level); } }
static int s3c_serial_resume(struct platform_device *dev) { struct uart_port *port = s3c_dev_to_port(&dev->dev); struct s3c_uart_port *ourport = to_ourport(port); unsigned int gpadata = 0; if (port) { clk_enable(ourport->clk); s3c_serial_resetport(port, s3c_port_to_cfg(port)); clk_disable(ourport->clk); s3c6410_pm_do_restore(uart_save + port->line * SAVE_UART_PORT, SAVE_UART_PORT); uart_resume_port(&s3c_uart_drv, port); } if (port->line == 0) { gpadata = __raw_readl(S3C64XX_GPADAT); gpadata &= ~(1<<3); __raw_writel(gpadata, S3C64XX_GPADAT); } else if(port->line == 1) { s3c_gpio_cfgpin(S3C64XX_GPA(7), S3C_GPIO_SFN(1)); gpadata = __raw_readl(S3C64XX_GPADAT); gpadata &= ~(1<<7); __raw_writel(gpadata, S3C64XX_GPADAT); s3c_gpio_setpull(S3C64XX_GPA(7), S3C_GPIO_PULL_NONE); s3c_gpio_cfgpin(S3C64XX_GPA(7), S3C_GPIO_SFN(2)); } return 0; }
static void s3c24xx_serial_stop_tx(struct uart_port *port) { struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_dma *dma = ourport->dma; struct circ_buf *xmit = &port->state->xmit; struct dma_tx_state state; int count; if (!tx_enabled(port)) return; if (s3c24xx_serial_has_interrupt_mask(port)) s3c24xx_set_bit(port, S3C64XX_UINTM_TXD, S3C64XX_UINTM); else disable_irq_nosync(ourport->tx_irq); if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) { dmaengine_pause(dma->tx_chan); dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state); dmaengine_terminate_all(dma->tx_chan); dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE); async_tx_ack(dma->tx_desc); count = dma->tx_bytes_requested - state.residue; xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); port->icount.tx += count; } tx_enabled(port) = 0; ourport->tx_in_progress = 0; if (port->flags & UPF_CONS_FLOW) s3c24xx_serial_rx_enable(port); ourport->tx_mode = 0; }
static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port) { return to_ourport(port)->info; }
/* * s3c64xx and later SoC's include the interrupt mask and status registers in * the controller itself, unlike the s3c24xx SoC's which have these registers * in the interrupt controller. Check if the port type is s3c64xx or higher. */ static int s3c24xx_serial_has_interrupt_mask(struct uart_port *port) { return to_ourport(port)->info->type == PORT_S3C6400; }
static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_clksrc *clksrc = NULL; struct clk *clk = NULL; unsigned long flags; unsigned int baud, quot; unsigned int ulcon; unsigned int umcon; unsigned int udivslot = 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) quot = port->custom_divisor; else quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); /* check to see if we need to change clock source */ if (ourport->clksrc != clksrc || ourport->baudclk != clk) { dbg("selecting clock %p\n", clk); s3c24xx_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; ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0; } if (ourport->info->has_divslot) { unsigned int div = ourport->baudclk_rate / baud; udivslot = udivslot_table[div & 15]; dbg("udivslot = %04x (div %d)\n", udivslot, div & 15); } switch (termios->c_cflag & CSIZE) { case CS5: dbg("config: 5bits/char\n"); ulcon = S3C2410_LCON_CS5; break; case CS6: dbg("config: 6bits/char\n"); ulcon = S3C2410_LCON_CS6; break; case CS7: dbg("config: 7bits/char\n"); ulcon = S3C2410_LCON_CS7; break; case CS8: default: dbg("config: 8bits/char\n"); ulcon = S3C2410_LCON_CS8; break; } /* preserve original lcon IR settings */ ulcon |= (cfg->ulcon & S3C2410_LCON_IRM); if (termios->c_cflag & CSTOPB) ulcon |= S3C2410_LCON_STOPB; umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) ulcon |= S3C2410_LCON_PODD; else ulcon |= S3C2410_LCON_PEVEN; } else { ulcon |= S3C2410_LCON_PNONE; } spin_lock_irqsave(&port->lock, flags); dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n", ulcon, quot, udivslot); wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); wr_regl(port, S3C2410_UMCON, umcon); if (ourport->info->has_divslot) wr_regl(port, S3C2443_DIVSLOT, udivslot); dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", rd_regl(port, S3C2410_ULCON), rd_regl(port, S3C2410_UCON), rd_regl(port, S3C2410_UFCON)); /* * 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 = S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & INPCK) port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY; /* * Which character status flags should we ignore? */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C2410_UERSTAT_FRAME; /* * 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); }
static inline struct imapx200_uart_info *imapx200_port_to_info(struct uart_port *port) { return to_ourport(port)->info; }
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); }