102-soc-qcom-gsbi-Add-support-for-ADM-CRCI-muxing.patch 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. --- a/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt
  2. +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt
  3. @@ -6,7 +6,8 @@ configuration settings. The mode settin
  4. the 4 GSBI IOs.
  5. Required properties:
  6. -- compatible: must contain "qcom,gsbi-v1.0.0" for APQ8064/IPQ8064
  7. +- compatible: Should contain "qcom,gsbi-v1.0.0"
  8. +- cell-index: Should contain the GSBI index
  9. - reg: Address range for GSBI registers
  10. - clocks: required clock
  11. - clock-names: must contain "iface" entry
  12. @@ -16,6 +17,8 @@ Required properties:
  13. Optional properties:
  14. - qcom,crci : indicates CRCI MUX value for QUP CRCI ports. Please reference
  15. dt-bindings/soc/qcom,gsbi.h for valid CRCI mux values.
  16. +- syscon-tcsr: indicates phandle of TCSR syscon node. Required if child uses
  17. + dma.
  18. Required properties if child node exists:
  19. - #address-cells: Must be 1
  20. @@ -39,6 +42,7 @@ Example for APQ8064:
  21. gsbi4@16300000 {
  22. compatible = "qcom,gsbi-v1.0.0";
  23. + cell-index = <4>;
  24. reg = <0x16300000 0x100>;
  25. clocks = <&gcc GSBI4_H_CLK>;
  26. clock-names = "iface";
  27. @@ -48,6 +52,8 @@ Example for APQ8064:
  28. qcom,mode = <GSBI_PROT_I2C_UART>;
  29. qcom,crci = <GSBI_CRCI_QUP>;
  30. + syscon-tcsr = <&tcsr>;
  31. +
  32. /* child nodes go under here */
  33. i2c_qup4: i2c@16380000 {
  34. @@ -76,3 +82,9 @@ Example for APQ8064:
  35. };
  36. };
  37. + tcsr: syscon@1a400000 {
  38. + compatible = "qcom,apq8064-tcsr", "syscon";
  39. + reg = <0x1a400000 0x100>;
  40. + };
  41. +
  42. +
  43. --- a/drivers/soc/qcom/Kconfig
  44. +++ b/drivers/soc/qcom/Kconfig
  45. @@ -4,6 +4,7 @@
  46. config QCOM_GSBI
  47. tristate "QCOM General Serial Bus Interface"
  48. depends on ARCH_QCOM
  49. + select MFD_SYSCON
  50. help
  51. Say y here to enable GSBI support. The GSBI provides control
  52. functions for connecting the underlying serial UART, SPI, and I2C
  53. --- a/drivers/soc/qcom/qcom_gsbi.c
  54. +++ b/drivers/soc/qcom/qcom_gsbi.c
  55. @@ -18,22 +18,129 @@
  56. #include <linux/of.h>
  57. #include <linux/of_platform.h>
  58. #include <linux/platform_device.h>
  59. +#include <linux/regmap.h>
  60. +#include <linux/mfd/syscon.h>
  61. +#include <dt-bindings/soc/qcom,gsbi.h>
  62. #define GSBI_CTRL_REG 0x0000
  63. #define GSBI_PROTOCOL_SHIFT 4
  64. +#define MAX_GSBI 12
  65. +
  66. +#define TCSR_ADM_CRCI_BASE 0x70
  67. +
  68. +struct crci_config {
  69. + u32 num_rows;
  70. + const u32 (*array)[MAX_GSBI];
  71. +};
  72. +
  73. +static const u32 crci_ipq8064[][MAX_GSBI] = {
  74. + {
  75. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  76. + 0x000300, 0x000c00, 0x003000, 0x00c000,
  77. + 0x030000, 0x0c0000, 0x300000, 0xc00000
  78. + },
  79. + {
  80. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  81. + 0x000300, 0x000c00, 0x003000, 0x00c000,
  82. + 0x030000, 0x0c0000, 0x300000, 0xc00000
  83. + },
  84. +};
  85. +
  86. +static const struct crci_config config_ipq8064 = {
  87. + .num_rows = ARRAY_SIZE(crci_ipq8064),
  88. + .array = crci_ipq8064,
  89. +};
  90. +
  91. +static const unsigned int crci_apq8064[][MAX_GSBI] = {
  92. + {
  93. + 0x001800, 0x006000, 0x000030, 0x0000c0,
  94. + 0x000300, 0x000400, 0x000000, 0x000000,
  95. + 0x000000, 0x000000, 0x000000, 0x000000
  96. + },
  97. + {
  98. + 0x000000, 0x000000, 0x000000, 0x000000,
  99. + 0x000000, 0x000020, 0x0000c0, 0x000000,
  100. + 0x000000, 0x000000, 0x000000, 0x000000
  101. + },
  102. +};
  103. +
  104. +static const struct crci_config config_apq8064 = {
  105. + .num_rows = ARRAY_SIZE(crci_apq8064),
  106. + .array = crci_apq8064,
  107. +};
  108. +
  109. +static const unsigned int crci_msm8960[][MAX_GSBI] = {
  110. + {
  111. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  112. + 0x000300, 0x000400, 0x000000, 0x000000,
  113. + 0x000000, 0x000000, 0x000000, 0x000000
  114. + },
  115. + {
  116. + 0x000000, 0x000000, 0x000000, 0x000000,
  117. + 0x000000, 0x000020, 0x0000c0, 0x000300,
  118. + 0x001800, 0x006000, 0x000000, 0x000000
  119. + },
  120. +};
  121. +
  122. +static const struct crci_config config_msm8960 = {
  123. + .num_rows = ARRAY_SIZE(crci_msm8960),
  124. + .array = crci_msm8960,
  125. +};
  126. +
  127. +static const unsigned int crci_msm8660[][MAX_GSBI] = {
  128. + { /* ADM 0 - B */
  129. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  130. + 0x000300, 0x000c00, 0x003000, 0x00c000,
  131. + 0x030000, 0x0c0000, 0x300000, 0xc00000
  132. + },
  133. + { /* ADM 0 - B */
  134. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  135. + 0x000300, 0x000c00, 0x003000, 0x00c000,
  136. + 0x030000, 0x0c0000, 0x300000, 0xc00000
  137. + },
  138. + { /* ADM 1 - A */
  139. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  140. + 0x000300, 0x000c00, 0x003000, 0x00c000,
  141. + 0x030000, 0x0c0000, 0x300000, 0xc00000
  142. + },
  143. + { /* ADM 1 - B */
  144. + 0x000003, 0x00000c, 0x000030, 0x0000c0,
  145. + 0x000300, 0x000c00, 0x003000, 0x00c000,
  146. + 0x030000, 0x0c0000, 0x300000, 0xc00000
  147. + },
  148. +};
  149. +
  150. +static const struct crci_config config_msm8660 = {
  151. + .num_rows = ARRAY_SIZE(crci_msm8660),
  152. + .array = crci_msm8660,
  153. +};
  154. struct gsbi_info {
  155. struct clk *hclk;
  156. u32 mode;
  157. u32 crci;
  158. + struct regmap *tcsr;
  159. +};
  160. +
  161. +static const struct of_device_id tcsr_dt_match[] = {
  162. + { .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064},
  163. + { .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064},
  164. + { .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960},
  165. + { .compatible = "qcom,tcsr-msm8660", .data = &config_msm8660},
  166. + { },
  167. };
  168. static int gsbi_probe(struct platform_device *pdev)
  169. {
  170. struct device_node *node = pdev->dev.of_node;
  171. + struct device_node *tcsr_node;
  172. + const struct of_device_id *match;
  173. struct resource *res;
  174. void __iomem *base;
  175. struct gsbi_info *gsbi;
  176. + int i;
  177. + u32 mask, gsbi_num;
  178. + const struct crci_config *config = NULL;
  179. gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
  180. @@ -45,6 +152,32 @@ static int gsbi_probe(struct platform_de
  181. if (IS_ERR(base))
  182. return PTR_ERR(base);
  183. + /* get the tcsr node and setup the config and regmap */
  184. + gsbi->tcsr = syscon_regmap_lookup_by_phandle(node, "syscon-tcsr");
  185. +
  186. + if (!IS_ERR(gsbi->tcsr)) {
  187. + tcsr_node = of_parse_phandle(node, "syscon-tcsr", 0);
  188. + if (tcsr_node) {
  189. + match = of_match_node(tcsr_dt_match, tcsr_node);
  190. + if (match)
  191. + config = match->data;
  192. + else
  193. + dev_warn(&pdev->dev, "no matching TCSR\n");
  194. +
  195. + of_node_put(tcsr_node);
  196. + }
  197. + }
  198. +
  199. + if (of_property_read_u32(node, "cell-index", &gsbi_num)) {
  200. + dev_err(&pdev->dev, "missing cell-index\n");
  201. + return -EINVAL;
  202. + }
  203. +
  204. + if (gsbi_num < 1 || gsbi_num > MAX_GSBI) {
  205. + dev_err(&pdev->dev, "invalid cell-index\n");
  206. + return -EINVAL;
  207. + }
  208. +
  209. if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
  210. dev_err(&pdev->dev, "missing mode configuration\n");
  211. return -EINVAL;
  212. @@ -64,6 +197,25 @@ static int gsbi_probe(struct platform_de
  213. writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
  214. base + GSBI_CTRL_REG);
  215. + /*
  216. + * modify tcsr to reflect mode and ADM CRCI mux
  217. + * Each gsbi contains a pair of bits, one for RX and one for TX
  218. + * SPI mode requires both bits cleared, otherwise they are set
  219. + */
  220. + if (config) {
  221. + for (i = 0; i < config->num_rows; i++) {
  222. + mask = config->array[i][gsbi_num - 1];
  223. +
  224. + if (gsbi->mode == GSBI_PROT_SPI)
  225. + regmap_update_bits(gsbi->tcsr,
  226. + TCSR_ADM_CRCI_BASE + 4 * i, mask, 0);
  227. + else
  228. + regmap_update_bits(gsbi->tcsr,
  229. + TCSR_ADM_CRCI_BASE + 4 * i, mask, mask);
  230. +
  231. + }
  232. + }
  233. +
  234. /* make sure the gsbi control write is not reordered */
  235. wmb();