soc-ep93xx.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * SoC driver for Cirrus EP93xx chips.
  4. * Copyright (C) 2022 Nikita Shubin <nikita.shubin@maquefel.me>
  5. *
  6. * Based on a rewrite of arch/arm/mach-ep93xx/core.c
  7. * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
  8. * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org>
  9. *
  10. * Thanks go to Michael Burian and Ray Lehtiniemi for their key
  11. * role in the ep93xx Linux community.
  12. */
  13. #include <linux/bits.h>
  14. #include <linux/cleanup.h>
  15. #include <linux/init.h>
  16. #include <linux/mfd/syscon.h>
  17. #include <linux/of.h>
  18. #include <linux/of_fdt.h>
  19. #include <linux/platform_device.h>
  20. #include <linux/regmap.h>
  21. #include <linux/slab.h>
  22. #include <linux/spinlock.h>
  23. #include <linux/sys_soc.h>
  24. #include <linux/soc/cirrus/ep93xx.h>
  25. #define EP93XX_SYSCON_DEVCFG 0x80
  26. #define EP93XX_SWLOCK_MAGICK 0xaa
  27. #define EP93XX_SYSCON_SWLOCK 0xc0
  28. #define EP93XX_SYSCON_SYSCFG 0x9c
  29. #define EP93XX_SYSCON_SYSCFG_REV_MASK GENMASK(31, 28)
  30. #define EP93XX_SYSCON_SYSCFG_REV_SHIFT 28
  31. struct ep93xx_map_info {
  32. spinlock_t lock;
  33. void __iomem *base;
  34. struct regmap *map;
  35. };
  36. /*
  37. * EP93xx System Controller software locked register write
  38. *
  39. * Logic safeguards are included to condition the control signals for
  40. * power connection to the matrix to prevent part damage. In addition, a
  41. * software lock register is included that must be written with 0xAA
  42. * before each register write to change the values of the four switch
  43. * matrix control registers.
  44. */
  45. static void ep93xx_regmap_write(struct regmap *map, spinlock_t *lock,
  46. unsigned int reg, unsigned int val)
  47. {
  48. guard(spinlock_irqsave)(lock);
  49. regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
  50. regmap_write(map, reg, val);
  51. }
  52. static void ep93xx_regmap_update_bits(struct regmap *map, spinlock_t *lock,
  53. unsigned int reg, unsigned int mask,
  54. unsigned int val)
  55. {
  56. guard(spinlock_irqsave)(lock);
  57. regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
  58. /* force write is required to clear swlock if no changes are made */
  59. regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
  60. }
  61. static void ep93xx_unregister_adev(void *_adev)
  62. {
  63. struct auxiliary_device *adev = _adev;
  64. auxiliary_device_delete(adev);
  65. auxiliary_device_uninit(adev);
  66. }
  67. static void ep93xx_adev_release(struct device *dev)
  68. {
  69. struct auxiliary_device *adev = to_auxiliary_dev(dev);
  70. struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);
  71. kfree(rdev);
  72. }
  73. static struct auxiliary_device __init *ep93xx_adev_alloc(struct device *parent,
  74. const char *name,
  75. struct ep93xx_map_info *info)
  76. {
  77. struct ep93xx_regmap_adev *rdev __free(kfree) = NULL;
  78. struct auxiliary_device *adev;
  79. int ret;
  80. rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
  81. if (!rdev)
  82. return ERR_PTR(-ENOMEM);
  83. rdev->map = info->map;
  84. rdev->base = info->base;
  85. rdev->lock = &info->lock;
  86. rdev->write = ep93xx_regmap_write;
  87. rdev->update_bits = ep93xx_regmap_update_bits;
  88. adev = &rdev->adev;
  89. adev->name = name;
  90. adev->dev.parent = parent;
  91. adev->dev.release = ep93xx_adev_release;
  92. ret = auxiliary_device_init(adev);
  93. if (ret)
  94. return ERR_PTR(ret);
  95. return &no_free_ptr(rdev)->adev;
  96. }
  97. static int __init ep93xx_controller_register(struct device *parent, const char *name,
  98. struct ep93xx_map_info *info)
  99. {
  100. struct auxiliary_device *adev;
  101. int ret;
  102. adev = ep93xx_adev_alloc(parent, name, info);
  103. if (IS_ERR(adev))
  104. return PTR_ERR(adev);
  105. ret = auxiliary_device_add(adev);
  106. if (ret) {
  107. auxiliary_device_uninit(adev);
  108. return ret;
  109. }
  110. return devm_add_action_or_reset(parent, ep93xx_unregister_adev, adev);
  111. }
  112. static unsigned int __init ep93xx_soc_revision(struct regmap *map)
  113. {
  114. unsigned int val;
  115. regmap_read(map, EP93XX_SYSCON_SYSCFG, &val);
  116. val &= EP93XX_SYSCON_SYSCFG_REV_MASK;
  117. val >>= EP93XX_SYSCON_SYSCFG_REV_SHIFT;
  118. return val;
  119. }
  120. static const char __init *ep93xx_get_soc_rev(unsigned int rev)
  121. {
  122. switch (rev) {
  123. case EP93XX_CHIP_REV_D0:
  124. return "D0";
  125. case EP93XX_CHIP_REV_D1:
  126. return "D1";
  127. case EP93XX_CHIP_REV_E0:
  128. return "E0";
  129. case EP93XX_CHIP_REV_E1:
  130. return "E1";
  131. case EP93XX_CHIP_REV_E2:
  132. return "E2";
  133. default:
  134. return "unknown";
  135. }
  136. }
  137. static const char *pinctrl_names[] __initconst = {
  138. "pinctrl-ep9301", /* EP93XX_9301_SOC */
  139. "pinctrl-ep9307", /* EP93XX_9307_SOC */
  140. "pinctrl-ep9312", /* EP93XX_9312_SOC */
  141. };
  142. static int __init ep93xx_syscon_probe(struct platform_device *pdev)
  143. {
  144. enum ep93xx_soc_model model;
  145. struct ep93xx_map_info *map_info;
  146. struct soc_device_attribute *attrs;
  147. struct soc_device *soc_dev;
  148. struct device *dev = &pdev->dev;
  149. struct regmap *map;
  150. void __iomem *base;
  151. unsigned int rev;
  152. int ret;
  153. model = (enum ep93xx_soc_model)(uintptr_t)device_get_match_data(dev);
  154. map = device_node_to_regmap(dev->of_node);
  155. if (IS_ERR(map))
  156. return PTR_ERR(map);
  157. base = devm_platform_ioremap_resource(pdev, 0);
  158. if (IS_ERR(base))
  159. return PTR_ERR(base);
  160. attrs = devm_kzalloc(dev, sizeof(*attrs), GFP_KERNEL);
  161. if (!attrs)
  162. return -ENOMEM;
  163. rev = ep93xx_soc_revision(map);
  164. attrs->machine = of_flat_dt_get_machine_name();
  165. attrs->family = "Cirrus Logic EP93xx";
  166. attrs->revision = ep93xx_get_soc_rev(rev);
  167. soc_dev = soc_device_register(attrs);
  168. if (IS_ERR(soc_dev))
  169. return PTR_ERR(soc_dev);
  170. map_info = devm_kzalloc(dev, sizeof(*map_info), GFP_KERNEL);
  171. if (!map_info)
  172. return -ENOMEM;
  173. spin_lock_init(&map_info->lock);
  174. map_info->map = map;
  175. map_info->base = base;
  176. ret = ep93xx_controller_register(dev, pinctrl_names[model], map_info);
  177. if (ret)
  178. dev_err(dev, "registering pinctrl controller failed\n");
  179. /*
  180. * EP93xx SSP clock rate was doubled in version E2. For more information
  181. * see section 6 "2x SSP (Synchronous Serial Port) Clock – Revision E2 only":
  182. * http://www.cirrus.com/en/pubs/appNote/AN273REV4.pdf
  183. */
  184. if (rev == EP93XX_CHIP_REV_E2)
  185. ret = ep93xx_controller_register(dev, "clk-ep93xx.e2", map_info);
  186. else
  187. ret = ep93xx_controller_register(dev, "clk-ep93xx", map_info);
  188. if (ret)
  189. dev_err(dev, "registering clock controller failed\n");
  190. ret = ep93xx_controller_register(dev, "reset-ep93xx", map_info);
  191. if (ret)
  192. dev_err(dev, "registering reset controller failed\n");
  193. return 0;
  194. }
  195. static const struct of_device_id ep9301_syscon_of_device_ids[] = {
  196. { .compatible = "cirrus,ep9301-syscon", .data = (void *)EP93XX_9301_SOC },
  197. { .compatible = "cirrus,ep9302-syscon", .data = (void *)EP93XX_9301_SOC },
  198. { .compatible = "cirrus,ep9307-syscon", .data = (void *)EP93XX_9307_SOC },
  199. { .compatible = "cirrus,ep9312-syscon", .data = (void *)EP93XX_9312_SOC },
  200. { .compatible = "cirrus,ep9315-syscon", .data = (void *)EP93XX_9312_SOC },
  201. { /* sentinel */ }
  202. };
  203. static struct platform_driver ep9301_syscon_driver = {
  204. .driver = {
  205. .name = "ep9301-syscon",
  206. .of_match_table = ep9301_syscon_of_device_ids,
  207. },
  208. };
  209. builtin_platform_driver_probe(ep9301_syscon_driver, ep93xx_syscon_probe);