Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e5fdad68 authored by Andy Gross's avatar Andy Gross Committed by Kumar Gala
Browse files

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: default avatarAndy Gross <agross@codeaurora.org>
Signed-off-by: default avatarKumar Gala <galak@codeaurora.org>
parent 767b0235
Loading
Loading
Loading
Loading
+20 −10
Original line number Diff line number Diff line
@@ -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,6 +52,8 @@ 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 {
@@ -76,3 +82,7 @@ Example for APQ8064:
		};
	};

	tcsr: syscon@1a400000 {
		compatible = "qcom,apq8064-tcsr", "syscon";
		reg = <0x1a400000 0x100>;
	};
+1 −0
Original line number Diff line number Diff line
@@ -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
+152 −0
Original line number Diff line number Diff line
@@ -18,22 +18,129 @@
#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();