#define I2S_CSR 0x00
#define I2S_CR2 0x08
+#define I2S_MCR 0x100
#define CSR_BCE_BIT 28
+#define CSR_TE_BIT 31
#define CR2_BCD BIT(24)
#define CR2_DIV_SHIFT 0
#define CR2_DIV_WIDTH 8
+#define MCR_MOE BIT(30)
struct fsl_sai_data {
unsigned int offset; /* Register offset */
+ bool have_mclk; /* Have MCLK control */
};
struct fsl_sai_clk {
+ const struct fsl_sai_data *data;
struct clk_divider bclk_div;
+ struct clk_divider mclk_div;
struct clk_gate bclk_gate;
+ struct clk_gate mclk_gate;
struct clk_hw *bclk_hw;
+ struct clk_hw *mclk_hw;
spinlock_t lock;
};
{
struct fsl_sai_clk *sai_clk = data;
- return sai_clk->bclk_hw;
+ if (clkspec->args_count == 0)
+ return sai_clk->bclk_hw;
+
+ if (clkspec->args_count == 1) {
+ if (clkspec->args[0] == 0)
+ return sai_clk->bclk_hw;
+ if (sai_clk->data->have_mclk && clkspec->args[0] == 1)
+ return sai_clk->mclk_hw;
+ }
+
+ return ERR_PTR(-EINVAL);
}
static int fsl_sai_clk_register(struct device *dev, void __iomem *base,
if (IS_ERR(clk_bus))
return PTR_ERR(clk_bus);
+ sai_clk->data = data;
spin_lock_init(&sai_clk->lock);
ret = fsl_sai_clk_register(dev, base, &sai_clk->lock,
if (ret)
return ret;
+ if (data->have_mclk) {
+ ret = fsl_sai_clk_register(dev, base, &sai_clk->lock,
+ &sai_clk->mclk_div,
+ &sai_clk->mclk_gate,
+ &sai_clk->mclk_hw,
+ CSR_TE_BIT, MCR_MOE, I2S_MCR,
+ "MCLK");
+ if (ret)
+ return ret;
+ }
+
return devm_of_clk_add_hw_provider(dev, fsl_sai_of_clk_get, sai_clk);
}
static const struct fsl_sai_data fsl_sai_vf610_data = {
.offset = 0,
+ .have_mclk = false,
};
static const struct fsl_sai_data fsl_sai_imx8mq_data = {
.offset = 8,
+ .have_mclk = true,
};
static const struct of_device_id of_fsl_sai_clk_ids[] = {