spi: omap2-mcspi: Fix hardcoded reference clock
authorVaishnav Achath <vaishnav.a@ti.com>
Tue, 26 Sep 2023 11:38:12 +0000 (17:08 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 20 Nov 2023 10:59:08 +0000 (11:59 +0100)
[ Upstream commit 2d9f4877988f64f0f336983de65c365b6a7debfb ]

A hardcoded reference clock of 48 MHz is used to calculate the
clock divisor values, but the reference clock frequency can be
different across devices and can be configured which can cause
a mismatch between the reported frequency and actual SPI clock
frequency observed. Fix this by fetching the clock rate from
the clock provider and falling back to hardcoded reference only
if the clock is not supplied.

Fixes: 2cd7d393f461 ("arm64: dts: ti: k3-am654: Add McSPI DT nodes")

Signed-off-by: Vaishnav Achath <vaishnav.a@ti.com>
Reviewed-by: Dhruva Gole <d-gole@ti.com>
Link: https://lore.kernel.org/r/20230926113812.30692-1-vaishnav.a@ti.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/spi/spi-omap2-mcspi.c

index 79888e6..ddf1c68 100644 (file)
@@ -125,10 +125,12 @@ struct omap2_mcspi {
        struct omap2_mcspi_dma  *dma_channels;
        struct device           *dev;
        struct omap2_mcspi_regs ctx;
+       struct clk              *ref_clk;
        int                     fifo_depth;
        bool                    target_aborted;
        unsigned int            pin_dir:1;
        size_t                  max_xfer_len;
+       u32                     ref_clk_hz;
 };
 
 struct omap2_mcspi_cs {
@@ -880,12 +882,12 @@ out:
        return count - c;
 }
 
-static u32 omap2_mcspi_calc_divisor(u32 speed_hz)
+static u32 omap2_mcspi_calc_divisor(u32 speed_hz, u32 ref_clk_hz)
 {
        u32 div;
 
        for (div = 0; div < 15; div++)
-               if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div))
+               if (speed_hz >= (ref_clk_hz >> div))
                        return div;
 
        return 15;
@@ -897,7 +899,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
 {
        struct omap2_mcspi_cs *cs = spi->controller_state;
        struct omap2_mcspi *mcspi;
-       u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0;
+       u32 ref_clk_hz, l = 0, clkd = 0, div, extclk = 0, clkg = 0;
        u8 word_len = spi->bits_per_word;
        u32 speed_hz = spi->max_speed_hz;
 
@@ -911,14 +913,15 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi,
        if (t && t->speed_hz)
                speed_hz = t->speed_hz;
 
-       speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ);
-       if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) {
-               clkd = omap2_mcspi_calc_divisor(speed_hz);
-               speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd;
+       ref_clk_hz = mcspi->ref_clk_hz;
+       speed_hz = min_t(u32, speed_hz, ref_clk_hz);
+       if (speed_hz < (ref_clk_hz / OMAP2_MCSPI_MAX_DIVIDER)) {
+               clkd = omap2_mcspi_calc_divisor(speed_hz, ref_clk_hz);
+               speed_hz = ref_clk_hz >> clkd;
                clkg = 0;
        } else {
-               div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz;
-               speed_hz = OMAP2_MCSPI_MAX_FREQ / div;
+               div = (ref_clk_hz + speed_hz - 1) / speed_hz;
+               speed_hz = ref_clk_hz / div;
                clkd = (div - 1) & 0xf;
                extclk = (div - 1) >> 4;
                clkg = OMAP2_MCSPI_CHCONF_CLKG;
@@ -1448,8 +1451,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
        ctlr->cleanup = omap2_mcspi_cleanup;
        ctlr->target_abort = omap2_mcspi_target_abort;
        ctlr->dev.of_node = node;
-       ctlr->max_speed_hz = OMAP2_MCSPI_MAX_FREQ;
-       ctlr->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15;
        ctlr->use_gpio_descriptors = true;
 
        platform_set_drvdata(pdev, ctlr);
@@ -1519,6 +1520,14 @@ static int omap2_mcspi_probe(struct platform_device *pdev)
                goto free_ctlr;
        }
 
+       mcspi->ref_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
+       if (mcspi->ref_clk)
+               mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk);
+       else
+               mcspi->ref_clk_hz = OMAP2_MCSPI_MAX_FREQ;
+       ctlr->max_speed_hz = mcspi->ref_clk_hz;
+       ctlr->min_speed_hz = mcspi->ref_clk_hz >> 15;
+
        pm_runtime_use_autosuspend(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
        pm_runtime_enable(&pdev->dev);