The current approximation relies on scale comparison which is wrong in
two ways: a) the required scale doesn't take into consideration
remainder of the division, and b) minimal scale doesn't guarantee the
best approximation.

This patch change the approach to use comparison between remainders
instead of direct scale testing.

Signed-off-by: Andy Shevchenko <andy.shevche...@gmail.com>
---
 drivers/spi/spi-fsl-dspi.c | 32 +++++++++++---------------------
 1 file changed, 11 insertions(+), 21 deletions(-)

diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 96cac87..31cdee5 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -144,34 +144,24 @@ static void hz_to_spi_baud(char *pbr, char *br, int 
speed_hz,
 {
        /* Valid baud rate pre-scaler values */
        int pbr_tbl[4] = {2, 3, 5, 7};
-       int brs[16] = { 2,      4,      6,      8,
+       int brs[16] = {
+               2,      4,      6,      8,
                16,     32,     64,     128,
                256,    512,    1024,   2048,
-               4096,   8192,   16384,  32768 };
-       int scale_needed, scale, minscale = INT_MAX;
+               4096,   8192,   16384,  32768,
+       };
+       unsigned long r = INT_MAX, tmp;
        int i, j;
 
-       scale_needed = clkrate / speed_hz;
-
        for (i = 0; i < ARRAY_SIZE(brs); i++)
                for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
-                       scale = brs[i] * pbr_tbl[j];
-                       if (scale >= scale_needed) {
-                               if (scale < minscale) {
-                                       minscale = scale;
-                                       *br = i;
-                                       *pbr = j;
-                               }
-                               break;
-                       }
+                       tmp = abs(clkrate / pbr_tbl[j] / brs[i] - speed_hz);
+                       if (tmp >= r)
+                               continue;
+                       r = tmp;
+                       *br = i;
+                       *pbr = j;
                }
-
-       if (minscale == INT_MAX) {
-               pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is 
%ld, we use the max prescaler value.\n",
-                       speed_hz, clkrate);
-               *pbr = ARRAY_SIZE(pbr_tbl) - 1;
-               *br =  ARRAY_SIZE(brs) - 1;
-       }
 }
 
 static int dspi_transfer_write(struct fsl_dspi *dspi)
-- 
1.9.3

--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to