19cd10205SMichael Walle // SPDX-License-Identifier: GPL-2.0 29cd10205SMichael Walle /* 39cd10205SMichael Walle * Freescale SAI BCLK as a generic clock driver 49cd10205SMichael Walle * 59cd10205SMichael Walle * Copyright 2020 Michael Walle <michael@walle.cc> 69cd10205SMichael Walle */ 79cd10205SMichael Walle 89cd10205SMichael Walle #include <linux/module.h> 99cd10205SMichael Walle #include <linux/platform_device.h> 109cd10205SMichael Walle #include <linux/clk-provider.h> 119cd10205SMichael Walle #include <linux/err.h> 129cd10205SMichael Walle #include <linux/of.h> 139cd10205SMichael Walle #include <linux/of_address.h> 149cd10205SMichael Walle #include <linux/slab.h> 159cd10205SMichael Walle 169cd10205SMichael Walle #define I2S_CSR 0x00 179cd10205SMichael Walle #define I2S_CR2 0x08 189cd10205SMichael Walle #define CSR_BCE_BIT 28 199cd10205SMichael Walle #define CR2_BCD BIT(24) 209cd10205SMichael Walle #define CR2_DIV_SHIFT 0 219cd10205SMichael Walle #define CR2_DIV_WIDTH 8 229cd10205SMichael Walle 239cd10205SMichael Walle struct fsl_sai_clk { 249cd10205SMichael Walle struct clk_divider div; 259cd10205SMichael Walle struct clk_gate gate; 269cd10205SMichael Walle spinlock_t lock; 279cd10205SMichael Walle }; 289cd10205SMichael Walle 299cd10205SMichael Walle static int fsl_sai_clk_probe(struct platform_device *pdev) 309cd10205SMichael Walle { 319cd10205SMichael Walle struct device *dev = &pdev->dev; 329cd10205SMichael Walle struct fsl_sai_clk *sai_clk; 339cd10205SMichael Walle struct clk_parent_data pdata = { .index = 0 }; 349cd10205SMichael Walle void __iomem *base; 359cd10205SMichael Walle struct clk_hw *hw; 369cd10205SMichael Walle struct resource *res; 379cd10205SMichael Walle 389cd10205SMichael Walle sai_clk = devm_kzalloc(dev, sizeof(*sai_clk), GFP_KERNEL); 399cd10205SMichael Walle if (!sai_clk) 409cd10205SMichael Walle return -ENOMEM; 419cd10205SMichael Walle 429cd10205SMichael Walle res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 439cd10205SMichael Walle base = devm_ioremap_resource(dev, res); 449cd10205SMichael Walle if (IS_ERR(base)) 459cd10205SMichael Walle return PTR_ERR(base); 469cd10205SMichael Walle 479cd10205SMichael Walle spin_lock_init(&sai_clk->lock); 489cd10205SMichael Walle 499cd10205SMichael Walle sai_clk->gate.reg = base + I2S_CSR; 509cd10205SMichael Walle sai_clk->gate.bit_idx = CSR_BCE_BIT; 519cd10205SMichael Walle sai_clk->gate.lock = &sai_clk->lock; 529cd10205SMichael Walle 539cd10205SMichael Walle sai_clk->div.reg = base + I2S_CR2; 549cd10205SMichael Walle sai_clk->div.shift = CR2_DIV_SHIFT; 559cd10205SMichael Walle sai_clk->div.width = CR2_DIV_WIDTH; 569cd10205SMichael Walle sai_clk->div.lock = &sai_clk->lock; 579cd10205SMichael Walle 589cd10205SMichael Walle /* set clock direction, we are the BCLK master */ 599cd10205SMichael Walle writel(CR2_BCD, base + I2S_CR2); 609cd10205SMichael Walle 61*fb871515SMichael Walle hw = devm_clk_hw_register_composite_pdata(dev, dev->of_node->name, 629cd10205SMichael Walle &pdata, 1, NULL, NULL, 639cd10205SMichael Walle &sai_clk->div.hw, 649cd10205SMichael Walle &clk_divider_ops, 659cd10205SMichael Walle &sai_clk->gate.hw, 669cd10205SMichael Walle &clk_gate_ops, 679cd10205SMichael Walle CLK_SET_RATE_GATE); 689cd10205SMichael Walle if (IS_ERR(hw)) 699cd10205SMichael Walle return PTR_ERR(hw); 709cd10205SMichael Walle 719cd10205SMichael Walle return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw); 729cd10205SMichael Walle } 739cd10205SMichael Walle 749cd10205SMichael Walle static const struct of_device_id of_fsl_sai_clk_ids[] = { 759cd10205SMichael Walle { .compatible = "fsl,vf610-sai-clock" }, 769cd10205SMichael Walle { } 779cd10205SMichael Walle }; 789cd10205SMichael Walle MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids); 799cd10205SMichael Walle 809cd10205SMichael Walle static struct platform_driver fsl_sai_clk_driver = { 819cd10205SMichael Walle .probe = fsl_sai_clk_probe, 829cd10205SMichael Walle .driver = { 839cd10205SMichael Walle .name = "fsl-sai-clk", 849cd10205SMichael Walle .of_match_table = of_fsl_sai_clk_ids, 859cd10205SMichael Walle }, 869cd10205SMichael Walle }; 879cd10205SMichael Walle module_platform_driver(fsl_sai_clk_driver); 889cd10205SMichael Walle 899cd10205SMichael Walle MODULE_DESCRIPTION("Freescale SAI bitclock-as-a-clock driver"); 909cd10205SMichael Walle MODULE_AUTHOR("Michael Walle <michael@walle.cc>"); 919cd10205SMichael Walle MODULE_LICENSE("GPL"); 929cd10205SMichael Walle MODULE_ALIAS("platform:fsl-sai-clk"); 93