Esempio n. 1
0
static void __init
s3c_serial_get_options(struct uart_port *port, int *baud,
			   int *parity, int *bits)
{
	struct s3c_uart_clksrc clksrc;
	struct clk *clk;
	unsigned int ulcon;
	unsigned int ucon;
	unsigned int ubrdiv;
	unsigned int udivslot;
	unsigned long rate;

	ulcon  = rd_regl(port, S3C_ULCON);
	ucon   = rd_regl(port, S3C_UCON);
	ubrdiv = rd_regl(port, S3C_UBRDIV);
	udivslot = rd_regl(port, S3C_UDIVSLOT);

	dbg("s3c_serial_get_options: port=%p\n"
	    "registers: ulcon=%08x, ucon=%08x, ubdriv=%08x, udivslot=%08x\n",
	    port, ulcon, ucon, ubrdiv, udivslot);

	if ((ucon & 0xf) != 0) {
		/* consider the serial port configured if the tx/rx mode set */

		switch (ulcon & S3C_LCON_CSMASK) {
		case S3C_LCON_CS5:
			*bits = 5;
			break;
		case S3C_LCON_CS6:
			*bits = 6;
			break;
		case S3C_LCON_CS7:
			*bits = 7;
			break;
		default:
		case S3C_LCON_CS8:
			*bits = 8;
			break;
		}

		switch (ulcon & S3C_LCON_PMASK) {
		case S3C_LCON_PEVEN:
			*parity = 'e';
			break;

		case S3C_LCON_PODD:
			*parity = 'o';
			break;

		case S3C_LCON_PNONE:
		default:
			*parity = 'n';
		}

		/* now calculate the baud rate */

		s3c_serial_getsource(port, &clksrc);

		clk = clk_get(port->dev, clksrc.name);
		if (!IS_ERR(clk) && clk != NULL)
			rate = clk_get_rate(clk) / clksrc.divisor;
		else
			rate = 1;


		*baud = rate / (16 * (ubrdiv + 1));
		dbg("calculated baud %d\n", *baud);
	}

}
Esempio n. 2
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;
}
Esempio n. 3
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;
}