]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
soc: qcom: gsbi: Add support for ADM CRCI muxing
authorAndy Gross <agross@codeaurora.org>
Mon, 9 Feb 2015 22:01:06 +0000 (16:01 -0600)
committerKumar Gala <galak@codeaurora.org>
Wed, 11 Mar 2015 20:18:39 +0000 (15:18 -0500)
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>
Documentation/devicetree/bindings/soc/qcom/qcom,gsbi.txt
drivers/soc/qcom/Kconfig
drivers/soc/qcom/qcom_gsbi.c

index 4ce24d425bf18a42daa14d529165f506e4e3f224..2f5ede39bea2d1d3cffacbcbe0ed103a7d2c708a 100644 (file)
@@ -6,7 +6,8 @@ configuration settings.  The mode setting will govern the input/output mode of
 the 4 GSBI IOs.
 
 Required properties:
-- compatible: must contain "qcom,gsbi-v1.0.0" for APQ8064/IPQ8064
+- compatible:  Should contain "qcom,gsbi-v1.0.0"
+- cell-index:  Should contain the GSBI index
 - reg: Address range for GSBI registers
 - clocks: required clock
 - clock-names: must contain "iface" entry
@@ -16,6 +17,8 @@ Required properties:
 Optional properties:
 - qcom,crci : indicates CRCI MUX value for QUP CRCI ports.  Please reference
   dt-bindings/soc/qcom,gsbi.h for valid CRCI mux values.
+- syscon-tcsr: indicates phandle of TCSR syscon node.  Required if child uses
+  dma.
 
 Required properties if child node exists:
 - #address-cells: Must be 1
@@ -39,6 +42,7 @@ Example for APQ8064:
 
        gsbi4@16300000 {
                compatible = "qcom,gsbi-v1.0.0";
+               cell-index = <4>;
                reg = <0x16300000 0x100>;
                clocks = <&gcc GSBI4_H_CLK>;
                clock-names = "iface";
@@ -48,22 +52,24 @@ Example for APQ8064:
                qcom,mode = <GSBI_PROT_I2C_UART>;
                qcom,crci = <GSBI_CRCI_QUP>;
 
+               syscon-tcsr = <&tcsr>;
+
                /* child nodes go under here */
 
                i2c_qup4: i2c@16380000 {
-                       compatible = "qcom,i2c-qup-v1.1.1";
-                       reg = <0x16380000 0x1000>;
-                       interrupts = <0 153 0>;
+                       compatible = "qcom,i2c-qup-v1.1.1";
+                       reg = <0x16380000 0x1000>;
+                       interrupts = <0 153 0>;
 
-                       clocks = <&gcc GSBI4_QUP_CLK>, <&gcc GSBI4_H_CLK>;
-                       clock-names = "core", "iface";
+                       clocks = <&gcc GSBI4_QUP_CLK>, <&gcc GSBI4_H_CLK>;
+                       clock-names = "core", "iface";
 
-                       clock-frequency = <200000>;
+                       clock-frequency = <200000>;
 
-                       #address-cells = <1>;
-                       #size-cells = <0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
 
-                };
+               };
 
                uart4:  serial@16340000 {
                        compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
@@ -76,3 +82,7 @@ Example for APQ8064:
                };
        };
 
+       tcsr: syscon@1a400000 {
+               compatible = "qcom,apq8064-tcsr", "syscon";
+               reg = <0x1a400000 0x100>;
+       };
index 7bd2c94f54a4e923f473db63e512b99bffa3a9ba..460b2dba109c8dac48eb3acdb493dc2b535d62c7 100644 (file)
@@ -4,6 +4,7 @@
 config QCOM_GSBI
         tristate "QCOM General Serial Bus Interface"
         depends on ARCH_QCOM
+        select MFD_SYSCON
         help
           Say y here to enable GSBI support.  The GSBI provides control
           functions for connecting the underlying serial UART, SPI, and I2C
index 729425ddfd3e371d04978cdda0871209e2f24885..09c669e70d636861df12f9670dcdf339cf4021ee 100644 (file)
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <dt-bindings/soc/qcom,gsbi.h>
 
 #define GSBI_CTRL_REG          0x0000
 #define GSBI_PROTOCOL_SHIFT    4
+#define MAX_GSBI               12
+
+#define TCSR_ADM_CRCI_BASE     0x70
+
+struct crci_config {
+       u32 num_rows;
+       const u32 (*array)[MAX_GSBI];
+};
+
+static const u32 crci_ipq8064[][MAX_GSBI] = {
+       {
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000c00, 0x003000, 0x00c000,
+               0x030000, 0x0c0000, 0x300000, 0xc00000
+       },
+       {
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000c00, 0x003000, 0x00c000,
+               0x030000, 0x0c0000, 0x300000, 0xc00000
+       },
+};
+
+static const struct crci_config config_ipq8064 = {
+       .num_rows = ARRAY_SIZE(crci_ipq8064),
+       .array = crci_ipq8064,
+};
+
+static const unsigned int crci_apq8064[][MAX_GSBI] = {
+       {
+               0x001800, 0x006000, 0x000030, 0x0000c0,
+               0x000300, 0x000400, 0x000000, 0x000000,
+               0x000000, 0x000000, 0x000000, 0x000000
+       },
+       {
+               0x000000, 0x000000, 0x000000, 0x000000,
+               0x000000, 0x000020, 0x0000c0, 0x000000,
+               0x000000, 0x000000, 0x000000, 0x000000
+       },
+};
+
+static const struct crci_config config_apq8064 = {
+       .num_rows = ARRAY_SIZE(crci_apq8064),
+       .array = crci_apq8064,
+};
+
+static const unsigned int crci_msm8960[][MAX_GSBI] = {
+       {
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000400, 0x000000, 0x000000,
+               0x000000, 0x000000, 0x000000, 0x000000
+       },
+       {
+               0x000000, 0x000000, 0x000000, 0x000000,
+               0x000000, 0x000020, 0x0000c0, 0x000300,
+               0x001800, 0x006000, 0x000000, 0x000000
+       },
+};
+
+static const struct crci_config config_msm8960 = {
+       .num_rows = ARRAY_SIZE(crci_msm8960),
+       .array = crci_msm8960,
+};
+
+static const unsigned int crci_msm8660[][MAX_GSBI] = {
+       {       /* ADM 0 - B */
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000c00, 0x003000, 0x00c000,
+               0x030000, 0x0c0000, 0x300000, 0xc00000
+       },
+       {       /* ADM 0 - B */
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000c00, 0x003000, 0x00c000,
+               0x030000, 0x0c0000, 0x300000, 0xc00000
+       },
+       {       /* ADM 1 - A */
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000c00, 0x003000, 0x00c000,
+               0x030000, 0x0c0000, 0x300000, 0xc00000
+       },
+       {       /* ADM 1 - B */
+               0x000003, 0x00000c, 0x000030, 0x0000c0,
+               0x000300, 0x000c00, 0x003000, 0x00c000,
+               0x030000, 0x0c0000, 0x300000, 0xc00000
+       },
+};
+
+static const struct crci_config config_msm8660 = {
+       .num_rows = ARRAY_SIZE(crci_msm8660),
+       .array = crci_msm8660,
+};
 
 struct gsbi_info {
        struct clk *hclk;
        u32 mode;
        u32 crci;
+       struct regmap *tcsr;
+};
+
+static const struct of_device_id tcsr_dt_match[] = {
+       { .compatible = "qcom,tcsr-ipq8064", .data = &config_ipq8064},
+       { .compatible = "qcom,tcsr-apq8064", .data = &config_apq8064},
+       { .compatible = "qcom,tcsr-msm8960", .data = &config_msm8960},
+       { .compatible = "qcom,tcsr-msm8660", .data = &config_msm8660},
+       { },
 };
 
 static int gsbi_probe(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
+       struct device_node *tcsr_node;
+       const struct of_device_id *match;
        struct resource *res;
        void __iomem *base;
        struct gsbi_info *gsbi;
+       int i;
+       u32 mask, gsbi_num;
+       const struct crci_config *config = NULL;
 
        gsbi = devm_kzalloc(&pdev->dev, sizeof(*gsbi), GFP_KERNEL);
 
@@ -45,6 +152,32 @@ static int gsbi_probe(struct platform_device *pdev)
        if (IS_ERR(base))
                return PTR_ERR(base);
 
+       /* get the tcsr node and setup the config and regmap */
+       gsbi->tcsr = syscon_regmap_lookup_by_phandle(node, "syscon-tcsr");
+
+       if (!IS_ERR(gsbi->tcsr)) {
+               tcsr_node = of_parse_phandle(node, "syscon-tcsr", 0);
+               if (tcsr_node) {
+                       match = of_match_node(tcsr_dt_match, tcsr_node);
+                       if (match)
+                               config = match->data;
+                       else
+                               dev_warn(&pdev->dev, "no matching TCSR\n");
+
+                       of_node_put(tcsr_node);
+               }
+       }
+
+       if (of_property_read_u32(node, "cell-index", &gsbi_num)) {
+               dev_err(&pdev->dev, "missing cell-index\n");
+               return -EINVAL;
+       }
+
+       if (gsbi_num < 1 || gsbi_num > MAX_GSBI) {
+               dev_err(&pdev->dev, "invalid cell-index\n");
+               return -EINVAL;
+       }
+
        if (of_property_read_u32(node, "qcom,mode", &gsbi->mode)) {
                dev_err(&pdev->dev, "missing mode configuration\n");
                return -EINVAL;
@@ -64,6 +197,25 @@ static int gsbi_probe(struct platform_device *pdev)
        writel_relaxed((gsbi->mode << GSBI_PROTOCOL_SHIFT) | gsbi->crci,
                                base + GSBI_CTRL_REG);
 
+       /*
+        * modify tcsr to reflect mode and ADM CRCI mux
+        * Each gsbi contains a pair of bits, one for RX and one for TX
+        * SPI mode requires both bits cleared, otherwise they are set
+        */
+       if (config) {
+               for (i = 0; i < config->num_rows; i++) {
+                       mask = config->array[i][gsbi_num - 1];
+
+                       if (gsbi->mode == GSBI_PROT_SPI)
+                               regmap_update_bits(gsbi->tcsr,
+                                       TCSR_ADM_CRCI_BASE + 4 * i, mask, 0);
+                       else
+                               regmap_update_bits(gsbi->tcsr,
+                                       TCSR_ADM_CRCI_BASE + 4 * i, mask, mask);
+
+               }
+       }
+
        /* make sure the gsbi control write is not reordered */
        wmb();