diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2017-06-19 17:05:01 -0700 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2017-06-19 17:06:46 -0700 |
commit | 4d4f9a6a192d4e580d27208e7c49dfda12cabb59 (patch) | |
tree | c4800ee68ae2298e7fad95b82ab6576e7f79bbbc /drivers/clk/mvebu | |
parent | b7f8101d6e75fefd22c39624a30c9ed3d7a72463 (diff) | |
parent | a45af6d3a98b4d8a2746de13a8db52fb4123bb56 (diff) |
Merge branch 'clk-cp110' of git://git.infradead.org/linux-mvebu into clk-next
Pull improved Marvel Armada 7K/8K cp110 clk support from Gregory CLEMENT:
We got more information about the clock controllers and the clock tree
of the CP110 part that we find in the Marvell Armada 7K/8K SoCs. The
clk driver is modified accordingly from this new information.
* 'clk-cp110' of git://git.infradead.org/linux-mvebu:
clk: mvebu: cp110: add sdio clock to cp-110 system controller
clk: mvebu: cp110: introduce a new binding
clk: mvebu: cp110: do not depend anymore of the *-clock-output-names
clk: mvebu: cp110: make failure labels more meaningful
Diffstat (limited to 'drivers/clk/mvebu')
-rw-r--r-- | drivers/clk/mvebu/cp110-system-controller.c | 200 |
1 files changed, 138 insertions, 62 deletions
diff --git a/drivers/clk/mvebu/cp110-system-controller.c b/drivers/clk/mvebu/cp110-system-controller.c index 6b11d7b3e0e0..b034b79345ec 100644 --- a/drivers/clk/mvebu/cp110-system-controller.c +++ b/drivers/clk/mvebu/cp110-system-controller.c @@ -11,15 +11,16 @@ */ /* - * CP110 has 5 core clocks: + * CP110 has 6 core clocks: * * - APLL (1 Ghz) * - PPv2 core (1/3 APLL) * - EIP (1/2 APLL) - * - Core (1/2 EIP) + * - Core (1/2 EIP) + * - SDIO (2/5 APLL) * * - NAND clock, which is either: - * - Equal to the core clock + * - Equal to SDIO clock * - 2/5 APLL * * CP110 has 32 gatable clocks, for the various peripherals in the @@ -46,7 +47,7 @@ enum { CP110_CLK_TYPE_GATABLE, }; -#define CP110_MAX_CORE_CLOCKS 5 +#define CP110_MAX_CORE_CLOCKS 6 #define CP110_MAX_GATABLE_CLOCKS 32 #define CP110_CLK_NUM \ @@ -57,6 +58,7 @@ enum { #define CP110_CORE_EIP 2 #define CP110_CORE_CORE 3 #define CP110_CORE_NAND 4 +#define CP110_CORE_SDIO 5 /* A number of gatable clocks need special handling */ #define CP110_GATE_AUDIO 0 @@ -84,6 +86,33 @@ enum { #define CP110_GATE_EIP150 25 #define CP110_GATE_EIP197 26 +const char *gate_base_names[] = { + [CP110_GATE_AUDIO] = "audio", + [CP110_GATE_COMM_UNIT] = "communit", + [CP110_GATE_NAND] = "nand", + [CP110_GATE_PPV2] = "ppv2", + [CP110_GATE_SDIO] = "sdio", + [CP110_GATE_MG] = "mg-domain", + [CP110_GATE_MG_CORE] = "mg-core", + [CP110_GATE_XOR1] = "xor1", + [CP110_GATE_XOR0] = "xor0", + [CP110_GATE_GOP_DP] = "gop-dp", + [CP110_GATE_PCIE_X1_0] = "pcie_x10", + [CP110_GATE_PCIE_X1_1] = "pcie_x11", + [CP110_GATE_PCIE_X4] = "pcie_x4", + [CP110_GATE_PCIE_XOR] = "pcie-xor", + [CP110_GATE_SATA] = "sata", + [CP110_GATE_SATA_USB] = "sata-usb", + [CP110_GATE_MAIN] = "main", + [CP110_GATE_SDMMC_GOP] = "sd-mmc-gop", + [CP110_GATE_SLOW_IO] = "slow-io", + [CP110_GATE_USB3H0] = "usb3h0", + [CP110_GATE_USB3H1] = "usb3h1", + [CP110_GATE_USB3DEV] = "usb3dev", + [CP110_GATE_EIP150] = "eip150", + [CP110_GATE_EIP197] = "eip197" +}; + struct cp110_gate_clk { struct clk_hw hw; struct regmap *regmap; @@ -186,17 +215,37 @@ static struct clk_hw *cp110_of_clk_get(struct of_phandle_args *clkspec, return ERR_PTR(-EINVAL); } -static int cp110_syscon_clk_probe(struct platform_device *pdev) +static char *cp110_unique_name(struct device *dev, struct device_node *np, + const char *name) +{ + const __be32 *reg; + u64 addr; + + /* Do not create a name if there is no clock */ + if (!name) + return NULL; + + reg = of_get_property(np, "reg", NULL); + addr = of_translate_address(np, reg); + return devm_kasprintf(dev, GFP_KERNEL, "%llx-%s", + (unsigned long long)addr, name); +} + +static int cp110_syscon_common_probe(struct platform_device *pdev, + struct device_node *syscon_node) { struct regmap *regmap; - struct device_node *np = pdev->dev.of_node; - const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + const char *ppv2_name, *apll_name, *core_name, *eip_name, *nand_name, + *sdio_name; struct clk_hw_onecell_data *cp110_clk_data; struct clk_hw *hw, **cp110_clks; u32 nand_clk_ctrl; int i, ret; + char *gate_name[ARRAY_SIZE(gate_base_names)]; - regmap = syscon_node_to_regmap(np); + regmap = syscon_node_to_regmap(syscon_node); if (IS_ERR(regmap)) return PTR_ERR(regmap); @@ -205,7 +254,7 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) if (ret) return ret; - cp110_clk_data = devm_kzalloc(&pdev->dev, sizeof(*cp110_clk_data) + + cp110_clk_data = devm_kzalloc(dev, sizeof(*cp110_clk_data) + sizeof(struct clk_hw *) * CP110_CLK_NUM, GFP_KERNEL); if (!cp110_clk_data) @@ -215,53 +264,47 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) cp110_clk_data->num = CP110_CLK_NUM; /* Register the APLL which is the root of the hw tree */ - of_property_read_string_index(np, "core-clock-output-names", - CP110_CORE_APLL, &apll_name); + apll_name = cp110_unique_name(dev, syscon_node, "apll"); hw = clk_hw_register_fixed_rate(NULL, apll_name, NULL, 0, 1000 * 1000 * 1000); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail0; + goto fail_apll; } cp110_clks[CP110_CORE_APLL] = hw; /* PPv2 is APLL/3 */ - of_property_read_string_index(np, "core-clock-output-names", - CP110_CORE_PPV2, &ppv2_name); + ppv2_name = cp110_unique_name(dev, syscon_node, "ppv2-core"); hw = clk_hw_register_fixed_factor(NULL, ppv2_name, apll_name, 0, 1, 3); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail1; + goto fail_ppv2; } cp110_clks[CP110_CORE_PPV2] = hw; /* EIP clock is APLL/2 */ - of_property_read_string_index(np, "core-clock-output-names", - CP110_CORE_EIP, &eip_name); + eip_name = cp110_unique_name(dev, syscon_node, "eip"); hw = clk_hw_register_fixed_factor(NULL, eip_name, apll_name, 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail2; + goto fail_eip; } cp110_clks[CP110_CORE_EIP] = hw; /* Core clock is EIP/2 */ - of_property_read_string_index(np, "core-clock-output-names", - CP110_CORE_CORE, &core_name); + core_name = cp110_unique_name(dev, syscon_node, "core"); hw = clk_hw_register_fixed_factor(NULL, core_name, eip_name, 0, 1, 2); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail3; + goto fail_core; } cp110_clks[CP110_CORE_CORE] = hw; - /* NAND can be either APLL/2.5 or core clock */ - of_property_read_string_index(np, "core-clock-output-names", - CP110_CORE_NAND, &nand_name); + nand_name = cp110_unique_name(dev, syscon_node, "nand-core"); if (nand_clk_ctrl & NF_CLOCK_SEL_400_MASK) hw = clk_hw_register_fixed_factor(NULL, nand_name, apll_name, 0, 2, 5); @@ -270,23 +313,31 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) core_name, 0, 1, 1); if (IS_ERR(hw)) { ret = PTR_ERR(hw); - goto fail4; + goto fail_nand; } cp110_clks[CP110_CORE_NAND] = hw; - for (i = 0; i < CP110_MAX_GATABLE_CLOCKS; i++) { - const char *parent, *name; - int ret; - - ret = of_property_read_string_index(np, - "gate-clock-output-names", - i, &name); - /* Reached the end of the list? */ - if (ret < 0) - break; + /* SDIO clock is APLL/2.5 */ + sdio_name = cp110_unique_name(dev, syscon_node, "sdio-core"); + hw = clk_hw_register_fixed_factor(NULL, sdio_name, + apll_name, 0, 2, 5); + if (IS_ERR(hw)) { + ret = PTR_ERR(hw); + goto fail_sdio; + } - if (!strcmp(name, "none")) + cp110_clks[CP110_CORE_SDIO] = hw; + + /* create the unique name for all the gate clocks */ + for (i = 0; i < ARRAY_SIZE(gate_base_names); i++) + gate_name[i] = cp110_unique_name(dev, syscon_node, + gate_base_names[i]); + + for (i = 0; i < ARRAY_SIZE(gate_base_names); i++) { + const char *parent; + + if (gate_name[i] == NULL) continue; switch (i) { @@ -295,14 +346,10 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) case CP110_GATE_EIP150: case CP110_GATE_EIP197: case CP110_GATE_SLOW_IO: - of_property_read_string_index(np, - "gate-clock-output-names", - CP110_GATE_MAIN, &parent); + parent = gate_name[CP110_GATE_MAIN]; break; case CP110_GATE_MG: - of_property_read_string_index(np, - "gate-clock-output-names", - CP110_GATE_MG_CORE, &parent); + parent = gate_name[CP110_GATE_MG_CORE]; break; case CP110_GATE_NAND: parent = nand_name; @@ -311,34 +358,30 @@ static int cp110_syscon_clk_probe(struct platform_device *pdev) parent = ppv2_name; break; case CP110_GATE_SDIO: + parent = sdio_name; + break; case CP110_GATE_GOP_DP: - of_property_read_string_index(np, - "gate-clock-output-names", - CP110_GATE_SDMMC_GOP, &parent); + parent = gate_name[CP110_GATE_SDMMC_GOP]; break; case CP110_GATE_XOR1: case CP110_GATE_XOR0: case CP110_GATE_PCIE_X1_0: case CP110_GATE_PCIE_X1_1: case CP110_GATE_PCIE_X4: - of_property_read_string_index(np, - "gate-clock-output-names", - CP110_GATE_PCIE_XOR, &parent); + parent = gate_name[CP110_GATE_PCIE_XOR]; break; case CP110_GATE_SATA: case CP110_GATE_USB3H0: case CP110_GATE_USB3H1: case CP110_GATE_USB3DEV: - of_property_read_string_index(np, - "gate-clock-output-names", - CP110_GATE_SATA_USB, &parent); + parent = gate_name[CP110_GATE_SATA_USB]; break; default: parent = core_name; break; } + hw = cp110_register_gate(gate_name[i], parent, regmap, i); - hw = cp110_register_gate(name, parent, regmap, i); if (IS_ERR(hw)) { ret = PTR_ERR(hw); goto fail_gate; @@ -364,30 +407,63 @@ fail_gate: cp110_unregister_gate(hw); } + clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_SDIO]); +fail_sdio: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_NAND]); -fail4: +fail_nand: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_CORE]); -fail3: +fail_core: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_EIP]); -fail2: +fail_eip: clk_hw_unregister_fixed_factor(cp110_clks[CP110_CORE_PPV2]); -fail1: +fail_ppv2: clk_hw_unregister_fixed_rate(cp110_clks[CP110_CORE_APLL]); -fail0: +fail_apll: return ret; } -static const struct of_device_id cp110_syscon_of_match[] = { +static int cp110_syscon_legacy_clk_probe(struct platform_device *pdev) +{ + dev_warn(&pdev->dev, FW_WARN "Using legacy device tree binding\n"); + dev_warn(&pdev->dev, FW_WARN "Update your device tree:\n"); + dev_warn(&pdev->dev, FW_WARN + "This binding won't be supported in future kernels\n"); + + return cp110_syscon_common_probe(pdev, pdev->dev.of_node); +} + +static int cp110_clk_probe(struct platform_device *pdev) +{ + return cp110_syscon_common_probe(pdev, pdev->dev.of_node->parent); +} + + +static const struct of_device_id cp110_syscon_legacy_of_match[] = { { .compatible = "marvell,cp110-system-controller0", }, { } }; -static struct platform_driver cp110_syscon_driver = { - .probe = cp110_syscon_clk_probe, +static struct platform_driver cp110_syscon_legacy_driver = { + .probe = *cp110_syscon_legacy_clk_probe, .driver = { .name = "marvell-cp110-system-controller0", - .of_match_table = cp110_syscon_of_match, + .of_match_table = cp110_syscon_legacy_of_match, + .suppress_bind_attrs = true, + }, +}; +builtin_platform_driver(cp110_syscon_legacy_driver); + +static const struct of_device_id cp110_clock_of_match[] = { + { .compatible = "marvell,cp110-clock", }, + { } +}; + +static struct platform_driver cp110_clock_driver = { + .probe = cp110_clk_probe, + .driver = { + .name = "marvell-cp110-clock", + .of_match_table = cp110_clock_of_match, .suppress_bind_attrs = true, }, }; -builtin_platform_driver(cp110_syscon_driver); +builtin_platform_driver(cp110_clock_driver); |