clk-fsl-sai.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Freescale SAI BCLK as a generic clock driver
  4. *
  5. * Copyright 2020 Michael Walle <[email protected]>
  6. */
  7. #include <linux/module.h>
  8. #include <linux/platform_device.h>
  9. #include <linux/clk-provider.h>
  10. #include <linux/err.h>
  11. #include <linux/of.h>
  12. #include <linux/of_address.h>
  13. #include <linux/slab.h>
  14. #define I2S_CSR 0x00
  15. #define I2S_CR2 0x08
  16. #define CSR_BCE_BIT 28
  17. #define CR2_BCD BIT(24)
  18. #define CR2_DIV_SHIFT 0
  19. #define CR2_DIV_WIDTH 8
  20. struct fsl_sai_clk {
  21. struct clk_divider div;
  22. struct clk_gate gate;
  23. spinlock_t lock;
  24. };
  25. static int fsl_sai_clk_probe(struct platform_device *pdev)
  26. {
  27. struct device *dev = &pdev->dev;
  28. struct fsl_sai_clk *sai_clk;
  29. struct clk_parent_data pdata = { .index = 0 };
  30. void __iomem *base;
  31. struct clk_hw *hw;
  32. struct resource *res;
  33. sai_clk = devm_kzalloc(dev, sizeof(*sai_clk), GFP_KERNEL);
  34. if (!sai_clk)
  35. return -ENOMEM;
  36. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  37. base = devm_ioremap_resource(dev, res);
  38. if (IS_ERR(base))
  39. return PTR_ERR(base);
  40. spin_lock_init(&sai_clk->lock);
  41. sai_clk->gate.reg = base + I2S_CSR;
  42. sai_clk->gate.bit_idx = CSR_BCE_BIT;
  43. sai_clk->gate.lock = &sai_clk->lock;
  44. sai_clk->div.reg = base + I2S_CR2;
  45. sai_clk->div.shift = CR2_DIV_SHIFT;
  46. sai_clk->div.width = CR2_DIV_WIDTH;
  47. sai_clk->div.lock = &sai_clk->lock;
  48. /* set clock direction, we are the BCLK master */
  49. writel(CR2_BCD, base + I2S_CR2);
  50. hw = devm_clk_hw_register_composite_pdata(dev, dev->of_node->name,
  51. &pdata, 1, NULL, NULL,
  52. &sai_clk->div.hw,
  53. &clk_divider_ops,
  54. &sai_clk->gate.hw,
  55. &clk_gate_ops,
  56. CLK_SET_RATE_GATE);
  57. if (IS_ERR(hw))
  58. return PTR_ERR(hw);
  59. return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
  60. }
  61. static const struct of_device_id of_fsl_sai_clk_ids[] = {
  62. { .compatible = "fsl,vf610-sai-clock" },
  63. { }
  64. };
  65. MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids);
  66. static struct platform_driver fsl_sai_clk_driver = {
  67. .probe = fsl_sai_clk_probe,
  68. .driver = {
  69. .name = "fsl-sai-clk",
  70. .of_match_table = of_fsl_sai_clk_ids,
  71. },
  72. };
  73. module_platform_driver(fsl_sai_clk_driver);
  74. MODULE_DESCRIPTION("Freescale SAI bitclock-as-a-clock driver");
  75. MODULE_AUTHOR("Michael Walle <[email protected]>");
  76. MODULE_LICENSE("GPL");
  77. MODULE_ALIAS("platform:fsl-sai-clk");