clk-fsl-sai.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Freescale SAI BCLK as a generic clock driver
  4. *
  5. * Copyright 2020 Michael Walle <michael@walle.cc>
  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 = 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. platform_set_drvdata(pdev, hw);
  60. return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
  61. }
  62. static int fsl_sai_clk_remove(struct platform_device *pdev)
  63. {
  64. struct clk_hw *hw = platform_get_drvdata(pdev);
  65. clk_hw_unregister_composite(hw);
  66. return 0;
  67. }
  68. static const struct of_device_id of_fsl_sai_clk_ids[] = {
  69. { .compatible = "fsl,vf610-sai-clock" },
  70. { }
  71. };
  72. MODULE_DEVICE_TABLE(of, of_fsl_sai_clk_ids);
  73. static struct platform_driver fsl_sai_clk_driver = {
  74. .probe = fsl_sai_clk_probe,
  75. .remove = fsl_sai_clk_remove,
  76. .driver = {
  77. .name = "fsl-sai-clk",
  78. .of_match_table = of_fsl_sai_clk_ids,
  79. },
  80. };
  81. module_platform_driver(fsl_sai_clk_driver);
  82. MODULE_DESCRIPTION("Freescale SAI bitclock-as-a-clock driver");
  83. MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
  84. MODULE_LICENSE("GPL");
  85. MODULE_ALIAS("platform:fsl-sai-clk");