Change the clock rate in spi_master.setup() to accomodate the desired maximum clock rate for the device being set up. Use clk-fixed on a fake clock behaving like the internal MSIOF divider. Setting the rate of the fake clock will make clk-fixed find an optimal rate for the mso clock, with an optimal internal msiof divider. Results (sequential operations during probing): 1. msiof0 (and mso) set to 400 MHz, msiof0-div at 28.6 MHz 2. msiof2 (and mso) set to 8 MHz, msiof2-div at 1 MHz 3. msiof3 kept at 8 MHz, msiof3-div at 20 kHz Observations: - The algorithm used by clk-fixed does find a better clock, closer to the target rate, - However, mso clock rates are really high, - Despite calling clk_set_rate_range() on each msiofX clock, clk_set_rate() on another msiofX clock may reprogram mso to violate the set constraints. Hence at the end the mso clock runs at only 8 MHz, which is suboptimal. - The parent clock frequency cannot be changed while the mso clock is enabled. This is tricky, as the MSIOF modules are part of a Clock Domain, hence their clocks (and its parent clock) are under control of Runtime PM. So the parent clock may still be enabled due to asynchronous runtime-suspend not having disabled it yet, causing clk_set_rate() to fail sometimes with -EBUSY. Not-Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx> --- Not intended for upstream merge. --- drivers/spi/spi-sh-msiof.c | 198 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 656eaa4d03ed497b..c13420888f86371f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -13,6 +13,7 @@ #include <linux/bitmap.h> #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -44,6 +45,7 @@ struct sh_msiof_spi_priv { struct spi_master *master; void __iomem *mapbase; struct clk *clk; + struct clk *div_clk; struct platform_device *pdev; struct sh_msiof_spi_info *info; struct completion done; @@ -579,6 +581,194 @@ static int sh_msiof_clk_notifier_cb(struct notifier_block *nb, } } +static const struct clk_div_table sh_misof_div_clk_table[] = { + { .div = 1 * 1, .val = SCR_BRDV_DIV_1 | SCR_BRPS( 1) }, + { .div = 1 * 2, .val = SCR_BRDV_DIV_1 | SCR_BRPS( 2) }, + + { .div = 2 * 1, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 1) }, + { .div = 2 * 2, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 2) }, + { .div = 2 * 3, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 3) }, + { .div = 2 * 4, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 4) }, + { .div = 2 * 5, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 5) }, + { .div = 2 * 6, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 6) }, + { .div = 2 * 7, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 7) }, + { .div = 2 * 8, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 8) }, + { .div = 2 * 9, .val = SCR_BRDV_DIV_2 | SCR_BRPS( 9) }, + { .div = 2 * 10, .val = SCR_BRDV_DIV_2 | SCR_BRPS(10) }, + { .div = 2 * 11, .val = SCR_BRDV_DIV_2 | SCR_BRPS(11) }, + { .div = 2 * 12, .val = SCR_BRDV_DIV_2 | SCR_BRPS(12) }, + { .div = 2 * 13, .val = SCR_BRDV_DIV_2 | SCR_BRPS(13) }, + { .div = 2 * 14, .val = SCR_BRDV_DIV_2 | SCR_BRPS(14) }, + { .div = 2 * 15, .val = SCR_BRDV_DIV_2 | SCR_BRPS(15) }, + { .div = 2 * 16, .val = SCR_BRDV_DIV_2 | SCR_BRPS(16) }, + { .div = 2 * 17, .val = SCR_BRDV_DIV_2 | SCR_BRPS(17) }, + { .div = 2 * 18, .val = SCR_BRDV_DIV_2 | SCR_BRPS(18) }, + { .div = 2 * 19, .val = SCR_BRDV_DIV_2 | SCR_BRPS(19) }, + { .div = 2 * 20, .val = SCR_BRDV_DIV_2 | SCR_BRPS(20) }, + { .div = 2 * 21, .val = SCR_BRDV_DIV_2 | SCR_BRPS(21) }, + { .div = 2 * 22, .val = SCR_BRDV_DIV_2 | SCR_BRPS(22) }, + { .div = 2 * 23, .val = SCR_BRDV_DIV_2 | SCR_BRPS(23) }, + { .div = 2 * 24, .val = SCR_BRDV_DIV_2 | SCR_BRPS(24) }, + { .div = 2 * 25, .val = SCR_BRDV_DIV_2 | SCR_BRPS(25) }, + { .div = 2 * 26, .val = SCR_BRDV_DIV_2 | SCR_BRPS(26) }, + { .div = 2 * 27, .val = SCR_BRDV_DIV_2 | SCR_BRPS(27) }, + { .div = 2 * 28, .val = SCR_BRDV_DIV_2 | SCR_BRPS(28) }, + { .div = 2 * 29, .val = SCR_BRDV_DIV_2 | SCR_BRPS(29) }, + { .div = 2 * 30, .val = SCR_BRDV_DIV_2 | SCR_BRPS(30) }, + { .div = 2 * 31, .val = SCR_BRDV_DIV_2 | SCR_BRPS(31) }, + { .div = 2 * 32, .val = SCR_BRDV_DIV_2 | SCR_BRPS(32) }, + + { .div = 4 * 1, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 1) }, + { .div = 4 * 2, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 2) }, + { .div = 4 * 3, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 3) }, + { .div = 4 * 4, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 4) }, + { .div = 4 * 5, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 5) }, + { .div = 4 * 6, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 6) }, + { .div = 4 * 7, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 7) }, + { .div = 4 * 8, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 8) }, + { .div = 4 * 9, .val = SCR_BRDV_DIV_4 | SCR_BRPS( 9) }, + { .div = 4 * 10, .val = SCR_BRDV_DIV_4 | SCR_BRPS(10) }, + { .div = 4 * 11, .val = SCR_BRDV_DIV_4 | SCR_BRPS(11) }, + { .div = 4 * 12, .val = SCR_BRDV_DIV_4 | SCR_BRPS(12) }, + { .div = 4 * 13, .val = SCR_BRDV_DIV_4 | SCR_BRPS(13) }, + { .div = 4 * 14, .val = SCR_BRDV_DIV_4 | SCR_BRPS(14) }, + { .div = 4 * 15, .val = SCR_BRDV_DIV_4 | SCR_BRPS(15) }, + { .div = 4 * 16, .val = SCR_BRDV_DIV_4 | SCR_BRPS(16) }, + { .div = 4 * 17, .val = SCR_BRDV_DIV_4 | SCR_BRPS(17) }, + { .div = 4 * 18, .val = SCR_BRDV_DIV_4 | SCR_BRPS(18) }, + { .div = 4 * 19, .val = SCR_BRDV_DIV_4 | SCR_BRPS(19) }, + { .div = 4 * 20, .val = SCR_BRDV_DIV_4 | SCR_BRPS(20) }, + { .div = 4 * 21, .val = SCR_BRDV_DIV_4 | SCR_BRPS(21) }, + { .div = 4 * 22, .val = SCR_BRDV_DIV_4 | SCR_BRPS(22) }, + { .div = 4 * 23, .val = SCR_BRDV_DIV_4 | SCR_BRPS(23) }, + { .div = 4 * 24, .val = SCR_BRDV_DIV_4 | SCR_BRPS(24) }, + { .div = 4 * 25, .val = SCR_BRDV_DIV_4 | SCR_BRPS(25) }, + { .div = 4 * 26, .val = SCR_BRDV_DIV_4 | SCR_BRPS(26) }, + { .div = 4 * 27, .val = SCR_BRDV_DIV_4 | SCR_BRPS(27) }, + { .div = 4 * 28, .val = SCR_BRDV_DIV_4 | SCR_BRPS(28) }, + { .div = 4 * 29, .val = SCR_BRDV_DIV_4 | SCR_BRPS(29) }, + { .div = 4 * 30, .val = SCR_BRDV_DIV_4 | SCR_BRPS(30) }, + { .div = 4 * 31, .val = SCR_BRDV_DIV_4 | SCR_BRPS(31) }, + { .div = 4 * 32, .val = SCR_BRDV_DIV_4 | SCR_BRPS(32) }, + + { .div = 8 * 1, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 1) }, + { .div = 8 * 2, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 2) }, + { .div = 8 * 3, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 3) }, + { .div = 8 * 4, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 4) }, + { .div = 8 * 5, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 5) }, + { .div = 8 * 6, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 6) }, + { .div = 8 * 7, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 7) }, + { .div = 8 * 8, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 8) }, + { .div = 8 * 9, .val = SCR_BRDV_DIV_8 | SCR_BRPS( 9) }, + { .div = 8 * 10, .val = SCR_BRDV_DIV_8 | SCR_BRPS(10) }, + { .div = 8 * 11, .val = SCR_BRDV_DIV_8 | SCR_BRPS(11) }, + { .div = 8 * 12, .val = SCR_BRDV_DIV_8 | SCR_BRPS(12) }, + { .div = 8 * 13, .val = SCR_BRDV_DIV_8 | SCR_BRPS(13) }, + { .div = 8 * 14, .val = SCR_BRDV_DIV_8 | SCR_BRPS(14) }, + { .div = 8 * 15, .val = SCR_BRDV_DIV_8 | SCR_BRPS(15) }, + { .div = 8 * 16, .val = SCR_BRDV_DIV_8 | SCR_BRPS(16) }, + { .div = 8 * 17, .val = SCR_BRDV_DIV_8 | SCR_BRPS(17) }, + { .div = 8 * 18, .val = SCR_BRDV_DIV_8 | SCR_BRPS(18) }, + { .div = 8 * 19, .val = SCR_BRDV_DIV_8 | SCR_BRPS(19) }, + { .div = 8 * 20, .val = SCR_BRDV_DIV_8 | SCR_BRPS(20) }, + { .div = 8 * 21, .val = SCR_BRDV_DIV_8 | SCR_BRPS(21) }, + { .div = 8 * 22, .val = SCR_BRDV_DIV_8 | SCR_BRPS(22) }, + { .div = 8 * 23, .val = SCR_BRDV_DIV_8 | SCR_BRPS(23) }, + { .div = 8 * 24, .val = SCR_BRDV_DIV_8 | SCR_BRPS(24) }, + { .div = 8 * 25, .val = SCR_BRDV_DIV_8 | SCR_BRPS(25) }, + { .div = 8 * 26, .val = SCR_BRDV_DIV_8 | SCR_BRPS(26) }, + { .div = 8 * 27, .val = SCR_BRDV_DIV_8 | SCR_BRPS(27) }, + { .div = 8 * 28, .val = SCR_BRDV_DIV_8 | SCR_BRPS(28) }, + { .div = 8 * 29, .val = SCR_BRDV_DIV_8 | SCR_BRPS(29) }, + { .div = 8 * 30, .val = SCR_BRDV_DIV_8 | SCR_BRPS(30) }, + { .div = 8 * 31, .val = SCR_BRDV_DIV_8 | SCR_BRPS(31) }, + { .div = 8 * 32, .val = SCR_BRDV_DIV_8 | SCR_BRPS(32) }, + + { .div = 16 * 1, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 1) }, + { .div = 16 * 2, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 2) }, + { .div = 16 * 3, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 3) }, + { .div = 16 * 4, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 4) }, + { .div = 16 * 5, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 5) }, + { .div = 16 * 6, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 6) }, + { .div = 16 * 7, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 7) }, + { .div = 16 * 8, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 8) }, + { .div = 16 * 9, .val = SCR_BRDV_DIV_16 | SCR_BRPS( 9) }, + { .div = 16 * 10, .val = SCR_BRDV_DIV_16 | SCR_BRPS(10) }, + { .div = 16 * 11, .val = SCR_BRDV_DIV_16 | SCR_BRPS(11) }, + { .div = 16 * 12, .val = SCR_BRDV_DIV_16 | SCR_BRPS(12) }, + { .div = 16 * 13, .val = SCR_BRDV_DIV_16 | SCR_BRPS(13) }, + { .div = 16 * 14, .val = SCR_BRDV_DIV_16 | SCR_BRPS(14) }, + { .div = 16 * 15, .val = SCR_BRDV_DIV_16 | SCR_BRPS(15) }, + { .div = 16 * 16, .val = SCR_BRDV_DIV_16 | SCR_BRPS(16) }, + { .div = 16 * 17, .val = SCR_BRDV_DIV_16 | SCR_BRPS(17) }, + { .div = 16 * 18, .val = SCR_BRDV_DIV_16 | SCR_BRPS(18) }, + { .div = 16 * 19, .val = SCR_BRDV_DIV_16 | SCR_BRPS(19) }, + { .div = 16 * 20, .val = SCR_BRDV_DIV_16 | SCR_BRPS(20) }, + { .div = 16 * 21, .val = SCR_BRDV_DIV_16 | SCR_BRPS(21) }, + { .div = 16 * 22, .val = SCR_BRDV_DIV_16 | SCR_BRPS(22) }, + { .div = 16 * 23, .val = SCR_BRDV_DIV_16 | SCR_BRPS(23) }, + { .div = 16 * 24, .val = SCR_BRDV_DIV_16 | SCR_BRPS(24) }, + { .div = 16 * 25, .val = SCR_BRDV_DIV_16 | SCR_BRPS(25) }, + { .div = 16 * 26, .val = SCR_BRDV_DIV_16 | SCR_BRPS(26) }, + { .div = 16 * 27, .val = SCR_BRDV_DIV_16 | SCR_BRPS(27) }, + { .div = 16 * 28, .val = SCR_BRDV_DIV_16 | SCR_BRPS(28) }, + { .div = 16 * 29, .val = SCR_BRDV_DIV_16 | SCR_BRPS(29) }, + { .div = 16 * 30, .val = SCR_BRDV_DIV_16 | SCR_BRPS(30) }, + { .div = 16 * 31, .val = SCR_BRDV_DIV_16 | SCR_BRPS(31) }, + { .div = 16 * 32, .val = SCR_BRDV_DIV_16 | SCR_BRPS(32) }, + + { .div = 32 * 1, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 1) }, + { .div = 32 * 2, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 2) }, + { .div = 32 * 3, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 3) }, + { .div = 32 * 4, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 4) }, + { .div = 32 * 5, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 5) }, + { .div = 32 * 6, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 6) }, + { .div = 32 * 7, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 7) }, + { .div = 32 * 8, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 8) }, + { .div = 32 * 9, .val = SCR_BRDV_DIV_32 | SCR_BRPS( 9) }, + { .div = 32 * 10, .val = SCR_BRDV_DIV_32 | SCR_BRPS(10) }, + { .div = 32 * 11, .val = SCR_BRDV_DIV_32 | SCR_BRPS(11) }, + { .div = 32 * 12, .val = SCR_BRDV_DIV_32 | SCR_BRPS(12) }, + { .div = 32 * 13, .val = SCR_BRDV_DIV_32 | SCR_BRPS(13) }, + { .div = 32 * 14, .val = SCR_BRDV_DIV_32 | SCR_BRPS(14) }, + { .div = 32 * 15, .val = SCR_BRDV_DIV_32 | SCR_BRPS(15) }, + { .div = 32 * 16, .val = SCR_BRDV_DIV_32 | SCR_BRPS(16) }, + { .div = 32 * 17, .val = SCR_BRDV_DIV_32 | SCR_BRPS(17) }, + { .div = 32 * 18, .val = SCR_BRDV_DIV_32 | SCR_BRPS(18) }, + { .div = 32 * 19, .val = SCR_BRDV_DIV_32 | SCR_BRPS(19) }, + { .div = 32 * 20, .val = SCR_BRDV_DIV_32 | SCR_BRPS(20) }, + { .div = 32 * 21, .val = SCR_BRDV_DIV_32 | SCR_BRPS(21) }, + { .div = 32 * 22, .val = SCR_BRDV_DIV_32 | SCR_BRPS(22) }, + { .div = 32 * 23, .val = SCR_BRDV_DIV_32 | SCR_BRPS(23) }, + { .div = 32 * 24, .val = SCR_BRDV_DIV_32 | SCR_BRPS(24) }, + { .div = 32 * 25, .val = SCR_BRDV_DIV_32 | SCR_BRPS(25) }, + { .div = 32 * 26, .val = SCR_BRDV_DIV_32 | SCR_BRPS(26) }, + { .div = 32 * 27, .val = SCR_BRDV_DIV_32 | SCR_BRPS(27) }, + { .div = 32 * 28, .val = SCR_BRDV_DIV_32 | SCR_BRPS(28) }, + { .div = 32 * 29, .val = SCR_BRDV_DIV_32 | SCR_BRPS(29) }, + { .div = 32 * 30, .val = SCR_BRDV_DIV_32 | SCR_BRPS(30) }, + { .div = 32 * 31, .val = SCR_BRDV_DIV_32 | SCR_BRPS(31) }, + { .div = 32 * 32, .val = SCR_BRDV_DIV_32 | SCR_BRPS(32) }, + + { .div = 0, .val = 0 }, +}; + +static void sh_msiof_register_div_clk(struct sh_msiof_spi_priv *p) +{ + char parent_name[16], name[16]; + + snprintf(parent_name, sizeof(parent_name), "%pC", p->clk); + snprintf(name, sizeof(name), "%pC-div", p->clk); + + p->div_clk = clk_register_divider_table(NULL, name, parent_name, + CLK_SET_RATE_PARENT, NULL, 0, + 16, 0, sh_misof_div_clk_table, + NULL); + if (IS_ERR(p->div_clk)) + pr_err("clk_register_divider_table %s failed: %ld\n", name, + PTR_ERR(p->div_clk)); +} + static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; @@ -594,6 +784,12 @@ static int sh_msiof_spi_setup(struct spi_device *spi) "%s: master speed min %u max %u, device speed max = %u\n", __func__, min_speed_hz, max_speed_hz, spi->max_speed_hz); + clk_set_rate(p->div_clk, spi->max_speed_hz); + /* Set lower bound to 80% of desired rate */ + clk_set_rate_range(p->div_clk, spi->max_speed_hz * 4 / 5, + spi->max_speed_hz); + pr_info("%pC at %pCr, %pC at %pCr\n", p->clk, p->clk, p->div_clk, p->div_clk); + p->dev_max_speed_hz = spi->max_speed_hz; pm_runtime_get_sync(&p->pdev->dev); @@ -1322,6 +1518,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) if (clk_notifier_register(p->clk, &p->clk_rate_change_nb)) dev_warn(&pdev->dev, "Unable to register clock notifier.\n"); + sh_msiof_register_div_clk(p); + /* Platform data may override FIFO sizes */ p->tx_fifo_size = chipdata->tx_fifo_size; p->rx_fifo_size = chipdata->rx_fifo_size; -- 1.9.1