summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-tegra11.c59
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;
}