serial: sh-sci: Use a bitmask to indicate supported sampling rates
authorGeert Uytterhoeven <geert+renesas@glider.be>
Mon, 4 Jan 2016 13:45:21 +0000 (14:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 7 Feb 2016 06:54:55 +0000 (22:54 -0800)
Replace the single sampling rate and special handling for HSCIF's
variable sampling rates by a bitmask and a custom iterator.
This prepares for the advent of SCIFA/SCIFB's sparse variable sampling
rates.

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/sh-sci.c

index 70f005f37de085f404e483b5e6daab8f2279b42b..dbf488b9ae27923a523c2450925f846968359227 100644 (file)
@@ -84,6 +84,18 @@ enum SCI_CLKS {
        SCI_NUM_CLKS
 };
 
+/* Bit x set means sampling rate x + 1 is supported */
+#define SCI_SR(x)              BIT((x) - 1)
+#define SCI_SR_RANGE(x, y)     GENMASK((y) - 1, (x) - 1)
+
+#define min_sr(_port)          ffs((_port)->sampling_rate_mask)
+#define max_sr(_port)          fls((_port)->sampling_rate_mask)
+
+/* Iterate over all supported sampling rates, from high to low */
+#define for_each_sr(_sr, _port)                                                \
+       for ((_sr) = max_sr(_port); (_sr) >= min_sr(_port); (_sr)--)    \
+               if ((_port)->sampling_rate_mask & SCI_SR((_sr)))
+
 struct sci_port {
        struct uart_port        port;
 
@@ -93,7 +105,7 @@ struct sci_port {
        unsigned int            overrun_mask;
        unsigned int            error_mask;
        unsigned int            error_clear;
-       unsigned int            sampling_rate;
+       unsigned int            sampling_rate_mask;
        resource_size_t         reg_size;
 
        /* Break timer */
@@ -1904,21 +1916,13 @@ static int sci_sck_calc(struct sci_port *s, unsigned int bps,
                        unsigned int *srr)
 {
        unsigned long freq = s->clk_rates[SCI_SCK];
-       unsigned int min_sr, max_sr, sr;
        int err, min_err = INT_MAX;
+       unsigned int sr;
 
        if (s->port.type != PORT_HSCIF)
                freq *= 2;
-       if (s->sampling_rate) {
-               /* SCI(F) has a fixed sampling rate */
-               min_sr = max_sr = s->sampling_rate;
-       } else {
-               /* HSCIF has a variable 1/(8..32) sampling rate */
-               min_sr = 8;
-               max_sr = 32;
-       }
 
-       for (sr = max_sr; sr >= min_sr; sr--) {
+       for_each_sr(sr, s) {
                err = DIV_ROUND_CLOSEST(freq, sr) - bps;
                if (abs(err) >= abs(min_err))
                        continue;
@@ -1939,21 +1943,13 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps,
                        unsigned long freq, unsigned int *dlr,
                        unsigned int *srr)
 {
-       unsigned int min_sr, max_sr, sr, dl;
        int err, min_err = INT_MAX;
+       unsigned int sr, dl;
 
        if (s->port.type != PORT_HSCIF)
                freq *= 2;
-       if (s->sampling_rate) {
-               /* SCIF has a fixed sampling rate */
-               min_sr = max_sr = s->sampling_rate;
-       } else {
-               /* HSCIF has a variable 1/(8..32) sampling rate */
-               min_sr = 8;
-               max_sr = 32;
-       }
 
-       for (sr = max_sr; sr >= min_sr; sr--) {
+       for_each_sr(sr, s) {
                dl = DIV_ROUND_CLOSEST(freq, sr * bps);
                dl = clamp(dl, 1U, 65535U);
 
@@ -1979,19 +1975,12 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
                          unsigned int *brr, unsigned int *srr,
                          unsigned int *cks)
 {
-       unsigned int min_sr, max_sr, sr, br, prediv, scrate, c;
        unsigned long freq = s->clk_rates[SCI_FCK];
+       unsigned int sr, br, prediv, scrate, c;
        int err, min_err = INT_MAX;
 
        if (s->port.type != PORT_HSCIF)
                freq *= 2;
-       if (s->sampling_rate) {
-               min_sr = max_sr = s->sampling_rate;
-       } else {
-               /* HSCIF has a variable sample rate */
-               min_sr = 8;
-               max_sr = 32;
-       }
 
        /*
         * Find the combination of sample rate and clock select with the
@@ -2008,7 +1997,7 @@ static int sci_scbrr_calc(struct sci_port *s, unsigned int bps,
         *      (|D - 0.5| / N * (1 + F))|
         *  NOTE: Usually, treat D for 0.5, F is 0 by this calculation.
         */
-       for (sr = max_sr; sr >= min_sr; sr--) {
+       for_each_sr(sr, s) {
                for (c = 0; c <= 3; c++) {
                        /* integerized formulas from HSCIF documentation */
                        prediv = sr * (1 << (2 * c + 1));
@@ -2102,8 +2091,7 @@ static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
        for (i = 0; i < SCI_NUM_CLKS; i++)
                max_freq = max(max_freq, s->clk_rates[i]);
 
-       baud = uart_get_baud_rate(port, termios, old, 0,
-                                 max_freq / max(s->sampling_rate, 8U));
+       baud = uart_get_baud_rate(port, termios, old, 0, max_freq / min_sr(s));
        if (!baud)
                goto done;
 
@@ -2535,37 +2523,37 @@ static int sci_init_single(struct platform_device *dev,
                port->fifosize = 256;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCIFA_ORER;
-               sci_port->sampling_rate = 16;
+               sci_port->sampling_rate_mask = SCI_SR(16);
                break;
        case PORT_HSCIF:
                port->fifosize = 128;
                sci_port->overrun_reg = SCLSR;
                sci_port->overrun_mask = SCLSR_ORER;
-               sci_port->sampling_rate = 0;
+               sci_port->sampling_rate_mask = SCI_SR_RANGE(8, 32);
                break;
        case PORT_SCIFA:
                port->fifosize = 64;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCIFA_ORER;
-               sci_port->sampling_rate = 16;
+               sci_port->sampling_rate_mask = SCI_SR(16);
                break;
        case PORT_SCIF:
                port->fifosize = 16;
                if (p->regtype == SCIx_SH7705_SCIF_REGTYPE) {
                        sci_port->overrun_reg = SCxSR;
                        sci_port->overrun_mask = SCIFA_ORER;
-                       sci_port->sampling_rate = 16;
+                       sci_port->sampling_rate_mask = SCI_SR(16);
                } else {
                        sci_port->overrun_reg = SCLSR;
                        sci_port->overrun_mask = SCLSR_ORER;
-                       sci_port->sampling_rate = 32;
+                       sci_port->sampling_rate_mask = SCI_SR(32);
                }
                break;
        default:
                port->fifosize = 1;
                sci_port->overrun_reg = SCxSR;
                sci_port->overrun_mask = SCI_ORER;
-               sci_port->sampling_rate = 32;
+               sci_port->sampling_rate_mask = SCI_SR(32);
                break;
        }
 
@@ -2574,7 +2562,7 @@ static int sci_init_single(struct platform_device *dev,
         * data override the sampling rate for now.
         */
        if (p->sampling_rate)
-               sci_port->sampling_rate = p->sampling_rate;
+               sci_port->sampling_rate_mask = SCI_SR(p->sampling_rate);
 
        if (!early) {
                ret = sci_init_clocks(sci_port, &dev->dev);