aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Gross <agross@codeaurora.org>2015-02-09 17:01:06 -0500
committerKumar Gala <galak@codeaurora.org>2015-03-11 16:18:39 -0400
commite5fdad68d47ed344832b7ca4e18b2e9708d8141e (patch)
tree466a67a78537c815fc63bbc6e12a28d763bb812a
parent767b0235dd476596c0d4154839ae6880bec71b3c (diff)
soc: qcom: gsbi: Add support for ADM CRCI muxing
This patch adds automatic configuration for the ADM CRCI muxing required to support DMA operations for GSBI clients. The GSBI mode and instance determine the correct TCSR ADM CRCI MUX value that must be programmed so that the DMA works properly. Signed-off-by: Andy Gross <agross@codeaurora.org> Signed-off-by: Kumar Gala <galak@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt30
-rw-r--r--drivers/soc/qcom/Kconfig1
-rw-r--r--drivers/soc/qcom/qcom_gsbi.c152
3 files changed, 173 insertions, 10 deletions
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt
index 4ce24d425bf1..2f5ede39bea2 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt
@@ -6,7 +6,8 @@ configuration settings. The mode setting will govern the input/output mode of
6the 4 GSBI IOs. 6the 4 GSBI IOs.
7 7
8Required properties: 8Required properties:
9- compatible: must contain "qcom,gsbi-v1.0.0" for APQ8064/IPQ8064 9- compatible: Should contain "qcom,gsbi-v1.0.0"
10- cell-index: Should contain the GSBI index
10- reg: Address range for GSBI registers 11- reg: Address range for GSBI registers
11- clocks: required clock 12- clocks: required clock
12- clock-names: must contain "iface" entry 13- clock-names: must contain "iface" entry
@@ -16,6 +17,8 @@ Required properties:
16Optional properties: 17Optional properties:
17- qcom,crci : indicates CRCI MUX value for QUP CRCI ports. Please reference 18- qcom,crci : indicates CRCI MUX value for QUP CRCI ports. Please reference
18 dt-bindings/soc/qcom,gsbi.h for valid CRCI mux values. 19 dt-bindings/soc/qcom,gsbi.h for valid CRCI mux values.
20- syscon-tcsr: indicates phandle of TCSR syscon node. Required if child uses
21 dma.
19 22
20Required properties if child node exists: 23Required properties if child node exists:
21- #address-cells: Must be 1 24- #address-cells: Must be 1
@@ -39,6 +42,7 @@ Example for APQ8064:
39 42
40 gsbi4@16300000 { 43 gsbi4@16300000 {
41 compatible = "qcom,gsbi-v1.0.0"; 44 compatible = "qcom,gsbi-v1.0.0";
45 cell-index = <4>;
42 reg = <0x16300000 0x100>; 46 reg = <0x16300000 0x100>;
43 clocks = <&gcc GSBI4_H_CLK>; 47 clocks = <&gcc GSBI4_H_CLK>;
44 clock-names = "iface"; 48 clock-names = "iface";
@@ -48,22 +52,24 @@ Example for APQ8064:
48 qcom,mode = <GSBI_PROT_I2C_UART>; 52 qcom,mode = <GSBI_PROT_I2C_UART>;
49 qcom,crci = <GSBI_CRCI_QUP>; 53 qcom,crci = <GSBI_CRCI_QUP>;
50 54
55 syscon-tcsr = <&tcsr>;
56
51 /* child nodes go under here */ 57 /* child nodes go under here */
52 58
53 i2c_qup4: i2c@16380000 { 59 i2c_qup4: i2c@16380000 {
54 compatible = "qcom,i2c-qup-v1.1.1"; 60 compatible = "qcom,i2c-qup-v1.1.1";
55 reg = <0x16380000 0x1000>; 61 reg = <0x16380000 0x1000>;
56 interrupts = <0 153 0>; 62 interrupts = <0 153 0>;
57 63
58 clocks = <&gcc GSBI4_QUP_CLK>, <&gcc GSBI4_H_CLK>; 64 clocks = <&gcc GSBI4_QUP_CLK>, <&gcc GSBI4_H_CLK>;
59 clock-names = "core", "iface"; 65 clock-names = "core", "iface";
60 66
61 clock-frequency = <200000>; 67 clock-frequency = <200000>;
62 68
63 #address-cells = <1>; 69 #address-cells = <1>;
64 #size-cells = <0>; 70 #size-cells = <0>;
65 71
66 }; 72 };
67 73
68 uart4: serial@16340000 { 74 uart4: serial@16340000 {
69 compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; 75 compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
@@ -76,3 +82,7 @@ Example for APQ8064:
76 }; 82 };
77 }; 83 };
78 84
85 tcsr: syscon@1a400000 {
86 compatible = "qcom,apq8064-tcsr", "syscon";
87 reg = <0x1a400000 0x100>;
88 };
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 7bd2c94f54a4..460b2dba109c 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -4,6 +4,7 @@
4config QCOM_GSBI 4config QCOM_GSBI
5 tristate "QCOM General Serial Bus Interface" 5 tristate "QCOM General Serial Bus Interface"
6 depends on ARCH_QCOM 6 depends on ARCH_QCOM
7 select MFD_SYSCON
7 help 8 help
8 Say y here to enable GSBI support. The GSBI provides control 9 Say y here to enable GSBI support. The GSBI provides control
9 functions for connecting the underlying serial UART, SPI, and I2C 10 functions for connecting the underlying serial UART, SPI, and I2C
diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c
index 729425ddfd3e..09c669e70d63 100644
--- a/drivers/soc/qcom/qcom_gsbi.c
+++ b/drivers/soc/qcom/qcom_gsbi.c
@@ -18,22 +18,129 @@
18#include <linux/of.h> 18#include <linux/of.h>
19#include <linux/of_platform.h> 19#include <linux/of_platform.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/regmap.h>
22#include <linux/mfd/syscon.h>
23#include <dt-bindings/soc/qcom,gsbi.h>
21 24
22#define GSBI_CTRL_REG 0x0000 25#define GSBI_CTRL_REG 0x0000
23#define GSBI_PROTOCOL_SHIFT 4 26#define GSBI_PROTOCOL_SHIFT 4
27#define MAX_GSBI 12
28
29#define TCSR_ADM_CRCI_BASE 0x70
30
31struct crci_config {
32 u32 num_rows;
33 const u32 (*array)[MAX_GSBI];
34};
35
36static const u32 crci_ipq8064[][MAX_GSBI] = {
37 {
38 0x000003, 0x00000c, 0x000030, 0x0000c0,
39 0x000300, 0x000c00, 0x003000, 0x00c000,
40 0x030000, 0x0c0000, 0x300000, 0xc00000
41 },
42 {
43 0x000003, 0x00000c, 0x000030, 0x0000c0,
44 0x000300, 0x000c00, 0x003000, 0x00c000,
45 0x030000, 0x0c0000, 0x300000, 0xc00000
46 },
47};
48
49static const struct crci_config config_ipq8064 = {
50 .num_rows = ARRAY_SIZE(crci_ipq8064),
51 .array = crci_ipq8064,
52};
53
54static const unsigned int crci_apq8064[][MAX_GSBI] = {
55 {
56 0x001800, 0x006000, 0x000030, 0x0000c0,
57 0x000300, 0x000400, 0x000000, 0x000000,
58 0x000000, 0x000000, 0x000000, 0x000000
59 },
60 {
61 0x000000, 0x000000, 0x000000, 0x000000,
62 0x000000, 0x000020, 0x0000c0, 0x000000,
63 0x000000, 0x000000, 0x000000, 0x000000
64 },
65};
66
67static const struct crci_config config_apq8064 = {
68 .num_rows = ARRAY_SIZE(crci_apq8064),
69 .array = crci_apq8064,
70};
71
72static const unsigned int crci_msm8960[][MAX_GSBI] = {
73 {
74 0x000003, 0x00000c, 0x000030, 0x0000c0,
75 0x000300, 0x000400, 0x000000, 0x000000,
76 0x000000, 0x000000, 0x000000, 0x000000
77 },
78 {
79 0x000000, 0x000000, 0x000000, 0x000000,
80 0x000000, 0x000020, 0x0000c0, 0x000300,
81 0x001800, 0x006000, 0x000000, 0x000000
82 },
83};
84
85static const struct crci_config config_msm8960 = {
86 .num_rows = ARRAY_SIZE(crci_msm8960),
87 .array = crci_msm8960,
88};
89
90static const unsigned int crci_msm8660[][MAX_GSBI] = {
91 { /* ADM 0 - B */
92 0x000003, 0x00000c, 0x000030, 0x0000c0,
93 0x000300, 0x000c00, 0x003000, 0x00c000,
94 0x030000, 0x0c0000, 0x300000, 0xc00000
95 },
96 { /* ADM 0 - B */
97 0x000003, 0x00000c, 0x000030, 0x0000c0,
98 0x000300, 0x000c00, 0x003000, 0x00c000,
99 0x030000, 0x0c0000, 0x300000, 0xc00000
100 },
101 { /* ADM 1 - A */
102 0x000003, 0x00000c, 0x000030, 0x0000c0,
103 0x000300, 0x000c00, 0x003000, 0x00c000,
104 0x030000, 0x0c0000, 0x300000, 0xc00000
105 },
106 { /* ADM 1 - B */
107 0x000003, 0x00000c, 0x000030, 0x0000c0,
108 0x000300, 0x000c00, 0x003000, 0x00c000,
109 0x030000, 0x0c0000, 0x300000, 0xc00000
110 },
111};
112
113static const struct crci_config config_msm8660 = {
114 .num_rows = ARRAY_SIZE(crci_msm8660),
115 .array = crci_msm8660,
116};
24 117
25struct gsbi_info { 118struct gsbi_info {
26 struct clk *hclk; 119 struct clk *hclk;
27 u32 mode; 120 u32 mode;
28 u32 crci; 121 u32 crci;
122 struct regmap *tcsr;
123};
124
125static const struct of_device_id tcsr_dt_match[] = {
126 { .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064},
127 { .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064},
128 { .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960},
129 { .compatible = "qcom,tcsr-msm8660", .data = &config_msm8660},
130 { },
29}; 131};
30 132
31static int gsbi_probe(struct platform_device *pdev) 133static int gsbi_probe(struct platform_device *pdev)
32{ 134{
33 struct device_node *node = pdev->dev.of_node; 135 struct device_node *node = pdev->dev.of_node;
136 struct device_node *tcsr_node;
137 const struct of_device_id *match;
34 struct resource *res; 138 struct resource *res;
35 void __iomem *base; 139 void __iomem *base;
36 struct gsbi_info *gsbi; 140 struct gsbi_info *gsbi;
141 int i;
142 u32 mask, gsbi_num;
143 const struct crci_config *config = NULL;
37 144
38 gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL); 145 gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
39 146
@@ -45,6 +152,32 @@ static int gsbi_probe(struct platform_device *pdev)
45 if (IS_ERR(base)) 152 if (IS_ERR(base))
46 return PTR_ERR(base); 153 return PTR_ERR(base);
47 154
155 /* get the tcsr node and setup the config and regmap */
156 gsbi->tcsr = syscon_regmap_lookup_by_phandle(node, "syscon-tcsr");
157
158 if (!IS_ERR(gsbi->tcsr)) {
159 tcsr_node = of_parse_phandle(node, "syscon-tcsr", 0);
160 if (tcsr_node) {
161 match = of_match_node(tcsr_dt_match, tcsr_node);
162 if (match)
163 config = match->data;
164 else
165 dev_warn(&pdev->dev, "no matching TCSR\n");
166
167 of_node_put(tcsr_node);
168 }
169 }
170
171 if (of_property_read_u32(node, "cell-index", &gsbi_num)) {
172 dev_err(&pdev->dev, "missing cell-index\n");
173 return -EINVAL;
174 }
175
176 if (gsbi_num < 1 || gsbi_num > MAX_GSBI) {
177 dev_err(&pdev->dev, "invalid cell-index\n");
178 return -EINVAL;
179 }
180
48 if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) { 181 if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
49 dev_err(&pdev->dev, "missing mode configuration\n"); 182 dev_err(&pdev->dev, "missing mode configuration\n");
50 return -EINVAL; 183 return -EINVAL;
@@ -64,6 +197,25 @@ static int gsbi_probe(struct platform_device *pdev)
64 writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci, 197 writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
65 base + GSBI_CTRL_REG); 198 base + GSBI_CTRL_REG);
66 199
200 /*
201 * modify tcsr to reflect mode and ADM CRCI mux
202 * Each gsbi contains a pair of bits, one for RX and one for TX
203 * SPI mode requires both bits cleared, otherwise they are set
204 */
205 if (config) {
206 for (i = 0; i < config->num_rows; i++) {
207 mask = config->array[i][gsbi_num - 1];
208
209 if (gsbi->mode == GSBI_PROT_SPI)
210 regmap_update_bits(gsbi->tcsr,
211 TCSR_ADM_CRCI_BASE + 4 * i, mask, 0);
212 else
213 regmap_update_bits(gsbi->tcsr,
214 TCSR_ADM_CRCI_BASE + 4 * i, mask, mask);
215
216 }
217 }
218
67 /* make sure the gsbi control write is not reordered */ 219 /* make sure the gsbi control write is not reordered */
68 wmb(); 220 wmb();
69 221