Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

clk: fsl-sai: Add MCLK generation support

The driver currently supports generating BCLK. There are systems which
require generation of MCLK instead. Register new MCLK clock and handle
clock-cells = <1> to differentiate between BCLK and MCLK. In case of a
legacy system with clock-cells = <0>, the driver behaves as before, i.e.
always returns BCLK.

Note that it is not possible re-use the current SAI audio driver to
generate MCLK and correctly enable and disable the MCLK.

If SAI (audio driver) is used to control the MCLK enablement, then MCLK
clock is not always enabled, and it is not necessarily enabled when the
codec may need the clock to be enabled. There is also no way for the
codec node to specify phandle to clock provider in DT, because the SAI
(audio driver) is not clock provider.

If SAI (clock driver) is used to control the MCLK enablement, then MCLK
clock is enabled when the codec needs the clock enabled, because the
codec is the clock consumer and the SAI (clock driver) is the clock
provider, and the codec driver can request the clock to be enabled when
needed. There is also the usual phandle to clock provider in DT, because
the SAI (clock driver) is clock provider.

Acked-by: Michael Walle <mwalle@kernel.org>
Signed-off-by: Marek Vasut <marex@nabladev.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Marek Vasut and committed by
Stephen Boyd
6358c883 32b0c7aa

+33 -1
+33 -1
drivers/clk/clk-fsl-sai.c
··· 16 16 17 17 #define I2S_CSR 0x00 18 18 #define I2S_CR2 0x08 19 + #define I2S_MCR 0x100 19 20 #define CSR_BCE_BIT 28 21 + #define CSR_TE_BIT 31 20 22 #define CR2_BCD BIT(24) 21 23 #define CR2_DIV_SHIFT 0 22 24 #define CR2_DIV_WIDTH 8 25 + #define MCR_MOE BIT(30) 23 26 24 27 struct fsl_sai_data { 25 28 unsigned int offset; /* Register offset */ 29 + bool have_mclk; /* Have MCLK control */ 26 30 }; 27 31 28 32 struct fsl_sai_clk { 33 + const struct fsl_sai_data *data; 29 34 struct clk_divider bclk_div; 35 + struct clk_divider mclk_div; 30 36 struct clk_gate bclk_gate; 37 + struct clk_gate mclk_gate; 31 38 struct clk_hw *bclk_hw; 39 + struct clk_hw *mclk_hw; 32 40 spinlock_t lock; 33 41 }; 34 42 ··· 45 37 { 46 38 struct fsl_sai_clk *sai_clk = data; 47 39 48 - return sai_clk->bclk_hw; 40 + if (clkspec->args_count == 0) 41 + return sai_clk->bclk_hw; 42 + 43 + if (clkspec->args_count == 1) { 44 + if (clkspec->args[0] == 0) 45 + return sai_clk->bclk_hw; 46 + if (sai_clk->data->have_mclk && clkspec->args[0] == 1) 47 + return sai_clk->mclk_hw; 48 + } 49 + 50 + return ERR_PTR(-EINVAL); 49 51 } 50 52 51 53 static int fsl_sai_clk_register(struct device *dev, void __iomem *base, ··· 122 104 if (IS_ERR(clk_bus)) 123 105 return PTR_ERR(clk_bus); 124 106 107 + sai_clk->data = data; 125 108 spin_lock_init(&sai_clk->lock); 126 109 127 110 ret = fsl_sai_clk_register(dev, base, &sai_clk->lock, ··· 132 113 if (ret) 133 114 return ret; 134 115 116 + if (data->have_mclk) { 117 + ret = fsl_sai_clk_register(dev, base, &sai_clk->lock, 118 + &sai_clk->mclk_div, 119 + &sai_clk->mclk_gate, 120 + &sai_clk->mclk_hw, 121 + CSR_TE_BIT, MCR_MOE, I2S_MCR, 122 + "MCLK"); 123 + if (ret) 124 + return ret; 125 + } 126 + 135 127 return devm_of_clk_add_hw_provider(dev, fsl_sai_of_clk_get, sai_clk); 136 128 } 137 129 138 130 static const struct fsl_sai_data fsl_sai_vf610_data = { 139 131 .offset = 0, 132 + .have_mclk = false, 140 133 }; 141 134 142 135 static const struct fsl_sai_data fsl_sai_imx8mq_data = { 143 136 .offset = 8, 137 + .have_mclk = true, 144 138 }; 145 139 146 140 static const struct of_device_id of_fsl_sai_clk_ids[] = {