diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-tegra11.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/spi/spi-tegra11.c b/drivers/spi/spi-tegra11.c index 1b37821ec3c9..8c86c6249253 100644 --- a/drivers/spi/spi-tegra11.c +++ b/drivers/spi/spi-tegra11.c @@ -644,6 +644,64 @@ static int spi_tegra_start_cpu_based_transfer( return 0; } +static void set_best_clk_source(struct spi_tegra_data *tspi, + unsigned long speed) +{ + long new_rate; + unsigned long err_rate; + int rate = speed; + unsigned int fin_err = speed; + int final_index = -1; + int count; + int ret; + struct clk *pclk; + unsigned long prate, crate, nrate; + unsigned long cdiv; + + if (!tspi->parent_clk_count || !tspi->parent_clk_list) + return; + + /* make sure divisor is more than min_div */ + pclk = clk_get_parent(tspi->clk); + prate = clk_get_rate(pclk); + crate = clk_get_rate(tspi->clk); + cdiv = DIV_ROUND_UP(prate, crate); + if (cdiv < tspi->min_div) { + nrate = DIV_ROUND_UP(prate, tspi->min_div); + clk_set_rate(tspi->clk, nrate); + } + + for (count = 0; count < tspi->parent_clk_count; ++count) { + if (!tspi->parent_clk_list[count].parent_clk) + continue; + ret = clk_set_parent(tspi->clk, + tspi->parent_clk_list[count].parent_clk); + if (ret < 0) { + dev_warn(&tspi->pdev->dev, + "Error in setting parent clk src %s\n", + tspi->parent_clk_list[count].name); + continue; + } + + new_rate = clk_round_rate(tspi->clk, rate); + if (new_rate < 0) + continue; + + err_rate = abs(new_rate - rate); + if (err_rate < fin_err) { + final_index = count; + fin_err = err_rate; + } + } + + if (final_index >= 0) { + dev_info(&tspi->pdev->dev, "Setting clk_src %s\n", + tspi->parent_clk_list[final_index].name); + clk_set_parent(tspi->clk, + tspi->parent_clk_list[final_index].parent_clk); + } +} + static void spi_tegra_start_transfer(struct spi_device *spi, struct spi_transfer *t, bool is_first_of_msg, bool is_single_xfer) @@ -665,6 +723,7 @@ static void spi_tegra_start_transfer(struct spi_device *spi, if (!speed) speed = SPI_DEFAULT_SPEED; if (speed != tspi->cur_speed) { + set_best_clk_source(tspi, speed); clk_set_rate(tspi->clk, speed); tspi->cur_speed = speed; } |