1
0
Fork 0

clk: fsl-sai: new driver

With this driver it is possible to use the BCLK pin of the SAI module as
a generic clock output. This is esp. useful if you want to drive a clock
to an audio codec. Because the output only allows integer divider values
the audio codec needs an integrated PLL.

Signed-off-by: Michael Walle <michael@walle.cc>
Link: https://lkml.kernel.org/r/20200102231101.11834-3-michael@walle.cc
Signed-off-by: Stephen Boyd <sboyd@kernel.org>
alistair/sensors
Michael Walle 2020-01-03 00:11:01 +01:00 committed by Stephen Boyd
parent 8798e8fb08
commit 9cd1020522
3 changed files with 105 additions and 0 deletions

View File

@ -174,6 +174,18 @@ config COMMON_CLK_CS2000_CP
help
If you say yes here you get support for the CS2000 clock multiplier.
config COMMON_CLK_FSL_SAI
bool "Clock driver for BCLK of Freescale SAI cores"
depends on ARCH_LAYERSCAPE || COMPILE_TEST
help
This driver supports the Freescale SAI (Synchronous Audio Interface)
to be used as a generic clock output. Some SoCs have restrictions
regarding the possible pin multiplexer settings. Eg. on some SoCs
two SAI interfaces can only be enabled together. If just one is
needed, the BCLK pin of the second one can be used as general
purpose clock output. Ideally, it can be used to drive an audio
codec (sometimes known as MCLK).
config COMMON_CLK_GEMINI
bool "Clock driver for Cortina Systems Gemini SoC"
depends on ARCH_GEMINI || COMPILE_TEST

View File

@ -29,6 +29,7 @@ obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) += clk-fixed-mmio.o
obj-$(CONFIG_COMMON_CLK_FSL_SAI) += clk-fsl-sai.o
obj-$(CONFIG_COMMON_CLK_GEMINI) += clk-gemini.o
obj-$(CONFIG_COMMON_CLK_ASPEED) += clk-aspeed.o
obj-$(CONFIG_MACH_ASPEED_G6) += clk-ast2600.o

View File

@ -0,0 +1,92 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Freescale SAI BCLK as a generic clock driver
*
* Copyright 2020 Michael Walle <michael@walle.cc>
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/slab.h>
#define I2S_CSR 0x00
#define I2S_CR2 0x08
#define CSR_BCE_BIT 28
#define CR2_BCD BIT(24)
#define CR2_DIV_SHIFT 0
#define CR2_DIV_WIDTH 8
struct fsl_sai_clk {
struct clk_divider div;
struct clk_gate gate;
spinlock_t lock;
};
static int fsl_sai_clk_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct fsl_sai_clk *sai_clk;
struct clk_parent_data pdata = { .index = 0 };
void __iomem *base;
struct clk_hw *hw;
struct resource *res;
sai_clk = devm_kzalloc(dev, sizeof(*sai_clk), GFP_KERNEL);
if (!sai_clk)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
spin_lock_init(&sai_clk->lock);
sai_clk->gate.reg = base + I2S_CSR;
sai_clk->gate.bit_idx = CSR_BCE_BIT;
sai_clk->gate.lock = &sai_clk->lock;
sai_clk->div.reg = base + I2S_CR2;
sai_clk->div.shift = CR2_DIV_SHIFT;
sai_clk->div.width = CR2_DIV_WIDTH;
sai_clk->div.lock = &sai_clk->lock;
/* set clock direction, we are the BCLK master */
writel(CR2_BCD, base + I2S_CR2);
hw = clk_hw_register_composite_pdata(dev, dev->of_node->name,
&pdata, 1, NULL, NULL,
&sai_clk->div.hw,
&clk_divider_ops,
&sai_clk->gate.hw,
&clk_gate_ops,
CLK_SET_RATE_GATE);
if (IS_ERR(hw))
return PTR_ERR(hw);
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
}
static const struct of_device_id of_fsl_sai_clk_ids[] = {
{ .compatible = "fsl,vf610-sai-clock" },
{ }
};
MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids);
static struct platform_driver fsl_sai_clk_driver = {
.probe = fsl_sai_clk_probe,
.driver = {
.name = "fsl-sai-clk",
.of_match_table = of_fsl_sai_clk_ids,
},
};
module_platform_driver(fsl_sai_clk_driver);
MODULE_DESCRIPTION("Freescale SAI bitclock-as-a-clock driver");
MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:fsl-sai-clk");