exynos-usi.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2021 Linaro Ltd.
  4. * Author: Sam Protsenko <[email protected]>
  5. *
  6. * Samsung Exynos USI driver (Universal Serial Interface).
  7. */
  8. #include <linux/clk.h>
  9. #include <linux/mfd/syscon.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <linux/of_platform.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/regmap.h>
  15. #include <dt-bindings/soc/samsung,exynos-usi.h>
  16. /* USIv2: System Register: SW_CONF register bits */
  17. #define USI_V2_SW_CONF_NONE 0x0
  18. #define USI_V2_SW_CONF_UART BIT(0)
  19. #define USI_V2_SW_CONF_SPI BIT(1)
  20. #define USI_V2_SW_CONF_I2C BIT(2)
  21. #define USI_V2_SW_CONF_MASK (USI_V2_SW_CONF_UART | USI_V2_SW_CONF_SPI | \
  22. USI_V2_SW_CONF_I2C)
  23. /* USIv2: USI register offsets */
  24. #define USI_CON 0x04
  25. #define USI_OPTION 0x08
  26. /* USIv2: USI register bits */
  27. #define USI_CON_RESET BIT(0)
  28. #define USI_OPTION_CLKREQ_ON BIT(1)
  29. #define USI_OPTION_CLKSTOP_ON BIT(2)
  30. enum exynos_usi_ver {
  31. USI_VER2 = 2,
  32. };
  33. struct exynos_usi_variant {
  34. enum exynos_usi_ver ver; /* USI IP-core version */
  35. unsigned int sw_conf_mask; /* SW_CONF mask for all protocols */
  36. size_t min_mode; /* first index in exynos_usi_modes[] */
  37. size_t max_mode; /* last index in exynos_usi_modes[] */
  38. size_t num_clks; /* number of clocks to assert */
  39. const char * const *clk_names; /* clock names to assert */
  40. };
  41. struct exynos_usi {
  42. struct device *dev;
  43. void __iomem *regs; /* USI register map */
  44. struct clk_bulk_data *clks; /* USI clocks */
  45. size_t mode; /* current USI SW_CONF mode index */
  46. bool clkreq_on; /* always provide clock to IP */
  47. /* System Register */
  48. struct regmap *sysreg; /* System Register map */
  49. unsigned int sw_conf; /* SW_CONF register offset in sysreg */
  50. const struct exynos_usi_variant *data;
  51. };
  52. struct exynos_usi_mode {
  53. const char *name; /* mode name */
  54. unsigned int val; /* mode register value */
  55. };
  56. static const struct exynos_usi_mode exynos_usi_modes[] = {
  57. [USI_V2_NONE] = { .name = "none", .val = USI_V2_SW_CONF_NONE },
  58. [USI_V2_UART] = { .name = "uart", .val = USI_V2_SW_CONF_UART },
  59. [USI_V2_SPI] = { .name = "spi", .val = USI_V2_SW_CONF_SPI },
  60. [USI_V2_I2C] = { .name = "i2c", .val = USI_V2_SW_CONF_I2C },
  61. };
  62. static const char * const exynos850_usi_clk_names[] = { "pclk", "ipclk" };
  63. static const struct exynos_usi_variant exynos850_usi_data = {
  64. .ver = USI_VER2,
  65. .sw_conf_mask = USI_V2_SW_CONF_MASK,
  66. .min_mode = USI_V2_NONE,
  67. .max_mode = USI_V2_I2C,
  68. .num_clks = ARRAY_SIZE(exynos850_usi_clk_names),
  69. .clk_names = exynos850_usi_clk_names,
  70. };
  71. static const struct of_device_id exynos_usi_dt_match[] = {
  72. {
  73. .compatible = "samsung,exynos850-usi",
  74. .data = &exynos850_usi_data,
  75. },
  76. { } /* sentinel */
  77. };
  78. MODULE_DEVICE_TABLE(of, exynos_usi_dt_match);
  79. /**
  80. * exynos_usi_set_sw_conf - Set USI block configuration mode
  81. * @usi: USI driver object
  82. * @mode: Mode index
  83. *
  84. * Select underlying serial protocol (UART/SPI/I2C) in USI IP-core.
  85. *
  86. * Return: 0 on success, or negative error code on failure.
  87. */
  88. static int exynos_usi_set_sw_conf(struct exynos_usi *usi, size_t mode)
  89. {
  90. unsigned int val;
  91. int ret;
  92. if (mode < usi->data->min_mode || mode > usi->data->max_mode)
  93. return -EINVAL;
  94. val = exynos_usi_modes[mode].val;
  95. ret = regmap_update_bits(usi->sysreg, usi->sw_conf,
  96. usi->data->sw_conf_mask, val);
  97. if (ret)
  98. return ret;
  99. usi->mode = mode;
  100. dev_dbg(usi->dev, "protocol: %s\n", exynos_usi_modes[usi->mode].name);
  101. return 0;
  102. }
  103. /**
  104. * exynos_usi_enable - Initialize USI block
  105. * @usi: USI driver object
  106. *
  107. * USI IP-core start state is "reset" (on startup and after CPU resume). This
  108. * routine enables the USI block by clearing the reset flag. It also configures
  109. * HWACG behavior (needed e.g. for UART Rx). It should be performed before
  110. * underlying protocol becomes functional.
  111. *
  112. * Return: 0 on success, or negative error code on failure.
  113. */
  114. static int exynos_usi_enable(const struct exynos_usi *usi)
  115. {
  116. u32 val;
  117. int ret;
  118. ret = clk_bulk_prepare_enable(usi->data->num_clks, usi->clks);
  119. if (ret)
  120. return ret;
  121. /* Enable USI block */
  122. val = readl(usi->regs + USI_CON);
  123. val &= ~USI_CON_RESET;
  124. writel(val, usi->regs + USI_CON);
  125. udelay(1);
  126. /* Continuously provide the clock to USI IP w/o gating */
  127. if (usi->clkreq_on) {
  128. val = readl(usi->regs + USI_OPTION);
  129. val &= ~USI_OPTION_CLKSTOP_ON;
  130. val |= USI_OPTION_CLKREQ_ON;
  131. writel(val, usi->regs + USI_OPTION);
  132. }
  133. clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks);
  134. return ret;
  135. }
  136. static int exynos_usi_configure(struct exynos_usi *usi)
  137. {
  138. int ret;
  139. ret = exynos_usi_set_sw_conf(usi, usi->mode);
  140. if (ret)
  141. return ret;
  142. if (usi->data->ver == USI_VER2)
  143. return exynos_usi_enable(usi);
  144. return 0;
  145. }
  146. static int exynos_usi_parse_dt(struct device_node *np, struct exynos_usi *usi)
  147. {
  148. int ret;
  149. u32 mode;
  150. ret = of_property_read_u32(np, "samsung,mode", &mode);
  151. if (ret)
  152. return ret;
  153. if (mode < usi->data->min_mode || mode > usi->data->max_mode)
  154. return -EINVAL;
  155. usi->mode = mode;
  156. usi->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
  157. if (IS_ERR(usi->sysreg))
  158. return PTR_ERR(usi->sysreg);
  159. ret = of_property_read_u32_index(np, "samsung,sysreg", 1,
  160. &usi->sw_conf);
  161. if (ret)
  162. return ret;
  163. usi->clkreq_on = of_property_read_bool(np, "samsung,clkreq-on");
  164. return 0;
  165. }
  166. static int exynos_usi_get_clocks(struct exynos_usi *usi)
  167. {
  168. const size_t num = usi->data->num_clks;
  169. struct device *dev = usi->dev;
  170. size_t i;
  171. if (num == 0)
  172. return 0;
  173. usi->clks = devm_kcalloc(dev, num, sizeof(*usi->clks), GFP_KERNEL);
  174. if (!usi->clks)
  175. return -ENOMEM;
  176. for (i = 0; i < num; ++i)
  177. usi->clks[i].id = usi->data->clk_names[i];
  178. return devm_clk_bulk_get(dev, num, usi->clks);
  179. }
  180. static int exynos_usi_probe(struct platform_device *pdev)
  181. {
  182. struct device *dev = &pdev->dev;
  183. struct device_node *np = dev->of_node;
  184. struct exynos_usi *usi;
  185. int ret;
  186. usi = devm_kzalloc(dev, sizeof(*usi), GFP_KERNEL);
  187. if (!usi)
  188. return -ENOMEM;
  189. usi->dev = dev;
  190. platform_set_drvdata(pdev, usi);
  191. usi->data = of_device_get_match_data(dev);
  192. if (!usi->data)
  193. return -EINVAL;
  194. ret = exynos_usi_parse_dt(np, usi);
  195. if (ret)
  196. return ret;
  197. ret = exynos_usi_get_clocks(usi);
  198. if (ret)
  199. return ret;
  200. if (usi->data->ver == USI_VER2) {
  201. usi->regs = devm_platform_ioremap_resource(pdev, 0);
  202. if (IS_ERR(usi->regs))
  203. return PTR_ERR(usi->regs);
  204. }
  205. ret = exynos_usi_configure(usi);
  206. if (ret)
  207. return ret;
  208. /* Make it possible to embed protocol nodes into USI np */
  209. return of_platform_populate(np, NULL, NULL, dev);
  210. }
  211. static int __maybe_unused exynos_usi_resume_noirq(struct device *dev)
  212. {
  213. struct exynos_usi *usi = dev_get_drvdata(dev);
  214. return exynos_usi_configure(usi);
  215. }
  216. static const struct dev_pm_ops exynos_usi_pm = {
  217. SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, exynos_usi_resume_noirq)
  218. };
  219. static struct platform_driver exynos_usi_driver = {
  220. .driver = {
  221. .name = "exynos-usi",
  222. .pm = &exynos_usi_pm,
  223. .of_match_table = exynos_usi_dt_match,
  224. },
  225. .probe = exynos_usi_probe,
  226. };
  227. module_platform_driver(exynos_usi_driver);
  228. MODULE_DESCRIPTION("Samsung USI driver");
  229. MODULE_AUTHOR("Sam Protsenko <[email protected]>");
  230. MODULE_LICENSE("GPL");