示例#1
0
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);

	if (port) {
		clk_enable(ourport->clk);
		s3c_serial_resetport(port, s3c_port_to_cfg(port));
		clk_disable(ourport->clk);

		uart_resume_port(&s3c_uart_drv, port);
	}

	return 0;
}
示例#2
0
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;
}
示例#3
0
static void s3c_serial_set_termios(struct uart_port *port,
				       struct ktermios *termios,
				       struct ktermios *old)
{
	struct s3c_uartcfg *cfg = s3c_port_to_cfg(port);
	struct s3c_uart_port *ourport = to_ourport(port);
	struct s3c_uart_clksrc *clksrc = NULL;
	struct clk *clk = NULL;
	unsigned long flags;
	unsigned int baud, ubrdiv, udivslot;
	unsigned int ulcon;
	unsigned int umcon;

	/*
	 * 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, 4000000);

	if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) {
		ubrdiv = port->custom_divisor;
		udivslot = 0;
	}
	else
		ubrdiv = s3c_serial_getclk(port, &clksrc, &clk, baud, &udivslot);

	/* check to see if we need  to change clock source */

	if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
		s3c_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;
	}

	switch (termios->c_cflag & CSIZE) {
	case CS5:
		dbg("config: 5bits/char\n");
		ulcon = S3C_LCON_CS5;
		break;
	case CS6:
		dbg("config: 6bits/char\n");
		ulcon = S3C_LCON_CS6;
		break;
	case CS7:
		dbg("config: 7bits/char\n");
		ulcon = S3C_LCON_CS7;
		break;
	case CS8:
	default:
		dbg("config: 8bits/char\n");
		ulcon = S3C_LCON_CS8;
		break;
	}

	/* preserve original lcon IR settings */
	ulcon |= (cfg->ulcon & S3C_LCON_IRM);

	if (termios->c_cflag & CSTOPB)
		ulcon |= S3C_LCON_STOPB;

	umcon = (termios->c_cflag & CRTSCTS) ? S3C_UMCOM_AFC : 0;

	if (termios->c_cflag & PARENB) {
		if (termios->c_cflag & PARODD)
			ulcon |= S3C_LCON_PODD;
		else
			ulcon |= S3C_LCON_PEVEN;
	} else {
		ulcon |= S3C_LCON_PNONE;
	}

	spin_lock_irqsave(&port->lock, flags);

	dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);

	wr_regl(port, S3C_ULCON, ulcon);
	wr_regl(port, S3C_UBRDIV, ubrdiv);
	wr_regl(port, S3C_UDIVSLOT, udivslot_table[udivslot]);
	wr_regl(port, S3C_UMCON, umcon);

	/*
	 * 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 = S3C_UERSTAT_OVERRUN;
	if (termios->c_iflag & INPCK)
		port->read_status_mask |= S3C_UERSTAT_FRAME | S3C_UERSTAT_PARITY;

	/*
	 * Which character status flags should we ignore?
	 */
	port->ignore_status_mask = 0;
	if (termios->c_iflag & IGNPAR)
		port->ignore_status_mask |= S3C_UERSTAT_OVERRUN;
	if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
		port->ignore_status_mask |= S3C_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);
}
示例#4
0
static unsigned int s3c_serial_getclk(struct uart_port *port,
					  struct s3c_uart_clksrc **clksrc,
					  struct clk **clk,
					  unsigned int baud,
					  unsigned int *udivslot)
{
	struct s3c_uartcfg *cfg = s3c_port_to_cfg(port);
	struct s3c_uart_clksrc *clkp;
	struct baud_calc res[MAX_CLKS];
	struct baud_calc *resptr, *best, *sptr;
	struct clk *uclk1;
	int i;

	clkp = cfg->clocks;
	best = NULL;

	if (cfg->clocks_size < 2) {
		if (cfg->clocks_size == 0)
			clkp = &tmp_clksrc;

		/* check to see if we're sourcing fclk, and if so we're
		 * going to have to update the clock source
		 */

		if (strcmp(clkp->name, "fclk") == 0) {
			struct s3c_uart_clksrc src;

			s3c_serial_getsource(port, &src);

			/* check that the port already using fclk, and if
			 * not, then re-select fclk
			 */

			if (strcmp(src.name, clkp->name) == 0) {
				s3c_serial_setsource(port, clkp);
				s3c_serial_getsource(port, &src);
			}

			clkp->divisor = src.divisor;
		}

		if (strcmp(clkp->name, "uclk1") == 0) {
			uclk1 = clk_get(NULL, clkp->name);
			clk_set_parent(uclk1, clk_get(NULL, "dout_mpll"));	
			clk_set_rate(uclk1, 133000000);	
			clk_put(uclk1);
		}

		s3c_serial_calcbaud(res, port, clkp, baud);
		best = res;
		resptr = best + 1;
	} else {
		resptr = res;

		for (i = 0; i < cfg->clocks_size; i++, clkp++) {
			if (s3c_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;

	*udivslot = best->udivslot;

	return best->ubrdiv;
}
示例#5
0
static unsigned int s3c_serial_getclk(struct uart_port *port,
					  struct s3c24xx_uart_clksrc **clksrc,
					  struct clk **clk,
					  unsigned int baud, unsigned int *slot)
{
	struct s3c2410_uartcfg *cfg = s3c_port_to_cfg(port);
	struct s3c24xx_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;

		/* check to see if we're sourcing fclk, and if so we're
		 * going to have to update the clock source
		 */

		if (strcmp(clkp->name, "fclk") == 0) {
			struct s3c24xx_uart_clksrc src;

			s3c_serial_getsource(port, &src);

			/* check that the port already using fclk, and if
			 * not, then re-select fclk
			 */

			if (strcmp(src.name, clkp->name) == 0) {
				s3c_serial_setsource(port, clkp);
				s3c_serial_getsource(port, &src);
			}

			clkp->divisor = src.divisor;
		}

		s3c_serial_calcbaud(res, port, clkp, baud);
		best = res;
		resptr = best + 1;
	} else {
		resptr = res;

		for (i = 0; i < cfg->clocks_size; i++, clkp++) {
			if (s3c_serial_calcbaud(resptr, port, clkp, baud))
				resptr++;
		}
	}

	/* ok, we now need to select the best clock we found */

	if (best==NULL) {
		unsigned int deviation = (1<<30)|((1<<30)-1);
		int calc_deviation;
		
		best = sptr = res;

		for (sptr = res; sptr < resptr; sptr++) {
			printk(KERN_DEBUG
			       "found clk %p (%s) quot %d, calc %d\n",
			       sptr->clksrc, sptr->clksrc->name,
			       sptr->quot, sptr->calc);

			calc_deviation = baud - sptr->calc;
			
			if (calc_deviation < 0)
				calc_deviation = -calc_deviation;

			if (calc_deviation < deviation) {
				best = sptr;
				deviation = calc_deviation;
			}
		}

		printk(KERN_DEBUG "The best clksrc among candidate clksrc: %p(%s) (deviation: %d bps)\n", best, best->clksrc->name, deviation);
	}

	printk(KERN_DEBUG "Selected clock is %p (%s) quot %d, calc %d\n",
	       best->clksrc, best->clksrc->name, best->quot, best->calc);

	/* store results to pass back */
	*clksrc = best->clksrc;
	*clk    = best->src;
	*slot = best->slot;
	
	return best->quot;
}