16C950 UART has 3 register, that will be used for baudrate setting: divisor, TCR and CPR. Below you can see our calculation routine (http://svn.visionsystems.de/cgi-bin/viewvc.cgi/trunk/drivers/serial/serial_core.c?view=markup&root=linux-2.6.33-OnRISC&sortby=log&pathrev=10): /** * serial16C950_get_divisors - return TCR, CPR and divisor values for 16C950 UART * @baudbase: baud base * @baud: desired baud rate in decimal * @TCR: times clock register value * @CPR: clock prescaler register value * @Divisor: 16-bit divisor value for DLL and DLM registers * * Search for the valid values of the TCR, CPR and divisor. According to the datasheet * the crystal clock applied to the 16C950 can't be greater than 60MHz. * * The baud rates smaller than 1000bit/s can be calculated immediately. For the greater baud rates * TCR, CPR and divisor values will be tried to find the first combination generating the * baud rate with an error smaller than 3 per mil, but we also accept the baudr rates with an error * smaller than 2%. * * If no suitable combination is found, 0 is returned. Otherwise 1 will be returned. */ int serial16C950_get_divisors(unsigned long baudbase, unsigned long baud, unsigned *TCR, unsigned *CPR, unsigned short *Divisor) { unsigned long crystal8, Error, maxerr, e03p, e20p, div = 0; long long tmp; int iCPR, iTCR, ret; ret = 0; crystal8 = baudbase * 16 * 8; // crystal speed (max = 60MHz * 8) *TCR = 0; *CPR = 8; *Divisor = 96; iTCR = 16; if (baud > baudbase * (16 / 4)) return ret; if(baud < 1000) { iCPR = ((baudbase*8)/65535) + 1; *Divisor = ((baudbase*8) / iCPR)/baud; *CPR = iCPR; *TCR = iTCR; ret = 1; goto DoubleBreak; } e03p = (baud * 3) / 1000; // 3 per mil e20p = (baud * 2) / 100; // 2% maxerr = baud; do { iCPR = 8; do { tmp = iTCR*iCPR*baud; // check if we get division overflow if (tmp < 2* crystal8) { // calculate actual divisor div = (crystal8 + ((unsigned long)tmp/2)) / (unsigned long)(tmp); // divisor must fit into 16 bit if (div < 0x10000) { // calculate possible error Error = abs(baud - (crystal8) / (iTCR*iCPR*div)); if (Error < maxerr) { maxerr = Error; *Divisor = div; *CPR = iCPR; *TCR = iTCR; } } } // if error is smaller than 2% we have a valid result if (maxerr <= e20p) ret = 1; // exact result if (maxerr == 0) goto DoubleBreak; if ((iTCR >= 14) && (maxerr <= e03p)) goto DoubleBreak; if ((iTCR < 14) && (maxerr <= e20p)) goto DoubleBreak; if (div == 0) break; else iCPR++; } while (iCPR <= 255); iTCR--; } while (iTCR >= 4); DoubleBreak: *TCR &= 0x0F; return ret; } It would be great, if such functionality would be available in mainline kernel. What do you think about this? Yegor -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html