tclk_hz = clk_get_rate(orion_spi->clk);
----- /*
----- * the supported rates are: 4,6,8...30
----- * round up as we look for equal or less speed
----- */
----- rate = DIV_ROUND_UP(tclk_hz, speed);
----- rate = roundup(rate, 2);
+++++ if (devdata->typ == ARMADA_SPI) {
+++++ unsigned int clk, spr, sppr, sppr2, err;
+++++ unsigned int best_spr, best_sppr, best_err;
+
---- /* check if requested speed is too small */
---- if (rate > 30)
---- return -EINVAL;
+++++ best_err = speed;
+++++ best_spr = 0;
+++++ best_sppr = 0;
+
---- if (rate < 4)
---- rate = 4;
+++++ /* Iterate over the valid range looking for best fit */
+++++ for (sppr = 0; sppr < 8; sppr++) {
+++++ sppr2 = 0x1 << sppr;
+++++
+++++ spr = tclk_hz / sppr2;
+++++ spr = DIV_ROUND_UP(spr, speed);
+++++ if ((spr == 0) || (spr > 15))
+++++ continue;
++++
- /* check if requested speed is too small */
- if (rate > 30)
- return -EINVAL;
+++++ clk = tclk_hz / (spr * sppr2);
+++++ err = speed - clk;
++++
- if (rate < 4)
- rate = 4;
+++++ if (err < best_err) {
+++++ best_spr = spr;
+++++ best_sppr = sppr;
+++++ best_err = err;
+++++ }
+++++ }
+
---- /* Convert the rate to SPI clock divisor value. */
---- prescale = 0x10 + rate/2;
+++++ if ((best_sppr == 0) && (best_spr == 0))
+++++ return -EINVAL;
+++++
+++++ prescale = ((best_sppr & 0x6) << 5) |
+++++ ((best_sppr & 0x1) << 4) | best_spr;
+++++ } else {
+++++ /*
+++++ * the supported rates are: 4,6,8...30
+++++ * round up as we look for equal or less speed
+++++ */
+++++ rate = DIV_ROUND_UP(tclk_hz, speed);
+++++ rate = roundup(rate, 2);
+++++
+++++ /* check if requested speed is too small */
+++++ if (rate > 30)
+++++ return -EINVAL;
++++
- /* Convert the rate to SPI clock divisor value. */
- prescale = 0x10 + rate/2;
+++++ if (rate < 4)
+++++ rate = 4;
+++++
+++++ /* Convert the rate to SPI clock divisor value. */
+++++ prescale = 0x10 + rate/2;
+++++ }
reg = readl(spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
----- reg = ((reg & ~ORION_SPI_CLK_PRESCALE_MASK) | prescale);
+++++ reg = ((reg & ~devdata->prescale_mask) | prescale);
writel(reg, spi_reg(orion_spi, ORION_SPI_IF_CONFIG_REG));
return 0;