···508508struct baud_calc {509509 struct s3c24xx_uart_clksrc *clksrc;510510 unsigned int calc;511511+ unsigned int divslot;511512 unsigned int quot;512513 struct clk *src;513514};···518517 struct s3c24xx_uart_clksrc *clksrc,519518 unsigned int baud)520519{520520+ struct s3c24xx_uart_port *ourport = to_ourport(port);521521 unsigned long rate;522522523523 calc->src = clk_get(port->dev, clksrc->name);···529527 rate /= clksrc->divisor;530528531529 calc->clksrc = clksrc;532532- calc->quot = (rate + (8 * baud)) / (16 * baud);533533- calc->calc = (rate / (calc->quot * 16));530530+531531+ if (ourport->info->has_divslot) {532532+ unsigned long div = rate / baud;533533+534534+ /* The UDIVSLOT register on the newer UARTs allows us to535535+ * get a divisor adjustment of 1/16th on the baud clock.536536+ *537537+ * We don't keep the UDIVSLOT value (the 16ths we calculated538538+ * by not multiplying the baud by 16) as it is easy enough539539+ * to recalculate.540540+ */541541+542542+ calc->quot = div / 16;543543+ calc->calc = rate / div;544544+ } else {545545+ calc->quot = (rate + (8 * baud)) / (16 * baud);546546+ calc->calc = (rate / (calc->quot * 16));547547+ }534548535549 calc->quot--;536550 return 1;···629611 return best->quot;630612}631613614614+/* udivslot_table[]615615+ *616616+ * This table takes the fractional value of the baud divisor and gives617617+ * the recommended setting for the UDIVSLOT register.618618+ */619619+static u16 udivslot_table[16] = {620620+ [0] = 0x0000,621621+ [1] = 0x0080,622622+ [2] = 0x0808,623623+ [3] = 0x0888,624624+ [4] = 0x2222,625625+ [5] = 0x4924,626626+ [6] = 0x4A52,627627+ [7] = 0x54AA,628628+ [8] = 0x5555,629629+ [9] = 0xD555,630630+ [10] = 0xD5D5,631631+ [11] = 0xDDD5,632632+ [12] = 0xDDDD,633633+ [13] = 0xDFDD,634634+ [14] = 0xDFDF,635635+ [15] = 0xFFDF,636636+};637637+632638static void s3c24xx_serial_set_termios(struct uart_port *port,633639 struct ktermios *termios,634640 struct ktermios *old)···665623 unsigned int baud, quot;666624 unsigned int ulcon;667625 unsigned int umcon;626626+ unsigned int udivslot = 0;668627669628 /*670629 * We don't support modem control lines.···687644 /* check to see if we need to change clock source */688645689646 if (ourport->clksrc != clksrc || ourport->baudclk != clk) {647647+ dbg("selecting clock %p\n", clk);690648 s3c24xx_serial_setsource(port, clksrc);691649692650 if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {···700656 ourport->clksrc = clksrc;701657 ourport->baudclk = clk;702658 ourport->baudclk_rate = clk ? clk_get_rate(clk) : 0;659659+ }660660+661661+ if (ourport->info->has_divslot) {662662+ unsigned int div = ourport->baudclk_rate / baud;663663+664664+ udivslot = udivslot_table[div & 15];665665+ dbg("udivslot = %04x (div %d)\n", udivslot, div & 15);703666 }704667705668 switch (termios->c_cflag & CSIZE) {···748697749698 spin_lock_irqsave(&port->lock, flags);750699751751- dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);700700+ dbg("setting ulcon to %08x, brddiv to %d, udivslot %08x\n",701701+ ulcon, quot, udivslot);752702753703 wr_regl(port, S3C2410_ULCON, ulcon);754704 wr_regl(port, S3C2410_UBRDIV, quot);755705 wr_regl(port, S3C2410_UMCON, umcon);706706+707707+ if (ourport->info->has_divslot)708708+ wr_regl(port, S3C2443_DIVSLOT, udivslot);756709757710 dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",758711 rd_regl(port, S3C2410_ULCON),
+4
drivers/serial/samsung.h
···2121 unsigned long tx_fifoshift;2222 unsigned long tx_fifofull;23232424+ /* uart port features */2525+2626+ unsigned int has_divslot:1;2727+2428 /* clock source control */25292630 int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);