summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/Kconfig53
-rw-r--r--drivers/bus/Makefile15
-rw-r--r--drivers/bus/simple-pm-bus.c58
-rw-r--r--drivers/clk/shmobile/Makefile1
-rw-r--r--drivers/clk/shmobile/clk-r8a7778.c143
5 files changed, 243 insertions, 27 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index b99729e36860..7e9c2674af81 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -4,6 +4,21 @@
menu "Bus devices"
+config ARM_CCI
+ bool "ARM CCI driver support"
+ depends on ARM && OF && CPU_V7
+ help
+ Driver supporting the CCI cache coherent interconnect for ARM
+ platforms.
+
+config ARM_CCN
+ bool "ARM CCN driver support"
+ depends on ARM || ARM64
+ depends on PERF_EVENTS
+ help
+ PMU (perf) driver supporting the ARM CCN (Cache Coherent Network)
+ interconnect.
+
config BRCMSTB_GISB_ARB
bool "Broadcom STB GISB bus arbiter"
depends on ARM || MIPS
@@ -27,15 +42,6 @@ config MVEBU_MBUS
Driver needed for the MBus configuration on Marvell EBU SoCs
(Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP).
-config OMAP_OCP2SCP
- tristate "OMAP OCP2SCP DRIVER"
- depends on ARCH_OMAP2PLUS
- help
- Driver to enable ocp2scp module which transforms ocp interface
- protocol to scp protocol. In OMAP4, USB PHY is connected via
- OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via
- OCP2SCP.
-
config OMAP_INTERCONNECT
tristate "OMAP INTERCONNECT DRIVER"
depends on ARCH_OMAP2PLUS
@@ -43,20 +49,27 @@ config OMAP_INTERCONNECT
help
Driver to enable OMAP interconnect error handling driver.
-config ARM_CCI
- bool "ARM CCI driver support"
- depends on ARM && OF && CPU_V7
+config OMAP_OCP2SCP
+ tristate "OMAP OCP2SCP DRIVER"
+ depends on ARCH_OMAP2PLUS
help
- Driver supporting the CCI cache coherent interconnect for ARM
- platforms.
+ Driver to enable ocp2scp module which transforms ocp interface
+ protocol to scp protocol. In OMAP4, USB PHY is connected via
+ OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via
+ OCP2SCP.
-config ARM_CCN
- bool "ARM CCN driver support"
- depends on ARM || ARM64
- depends on PERF_EVENTS
+config SIMPLE_PM_BUS
+ bool "Simple Power-Managed Bus Driver"
+ depends on OF && PM
+ depends on ARCH_SHMOBILE || COMPILE_TEST
help
- PMU (perf) driver supporting the ARM CCN (Cache Coherent Network)
- interconnect.
+ Driver for transparent busses that don't need a real driver, but
+ where the bus controller is part of a PM domain, or under the control
+ of a functional clock, and thus relies on runtime PM for managing
+ this PM domain and/or clock.
+ An example of such a bus controller is the Renesas Bus State
+ Controller (BSC, sometimes called "LBSC within Bus Bridge", or
+ "External Bus Interface") as found on several Renesas ARM SoCs.
config VEXPRESS_CONFIG
bool "Versatile Express configuration bus"
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 2973c18cbcc2..e023a2bec664 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -2,16 +2,17 @@
# Makefile for the bus drivers.
#
+# Interconnect bus drivers for ARM platforms
+obj-$(CONFIG_ARM_CCI) += arm-cci.o
+obj-$(CONFIG_ARM_CCN) += arm-ccn.o
+
obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o
-obj-$(CONFIG_IMX_WEIM) += imx-weim.o
-obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
-obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
+obj-$(CONFIG_IMX_WEIM) += imx-weim.o
+obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
# Interconnect bus driver for OMAP SoCs.
obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
-# Interconnect bus drivers for ARM platforms
-obj-$(CONFIG_ARM_CCI) += arm-cci.o
-obj-$(CONFIG_ARM_CCN) += arm-ccn.o
-
+obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
+obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
diff --git a/drivers/bus/simple-pm-bus.c b/drivers/bus/simple-pm-bus.c
new file mode 100644
index 000000000000..c5eb46cbf388
--- /dev/null
+++ b/drivers/bus/simple-pm-bus.c
@@ -0,0 +1,58 @@
+/*
+ * Simple Power-Managed Bus Driver
+ *
+ * Copyright (C) 2014-2015 Glider bvba
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+
+static int simple_pm_bus_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ pm_runtime_enable(&pdev->dev);
+
+ if (np)
+ of_platform_populate(np, NULL, NULL, &pdev->dev);
+
+ return 0;
+}
+
+static int simple_pm_bus_remove(struct platform_device *pdev)
+{
+ dev_dbg(&pdev->dev, "%s\n", __func__);
+
+ pm_runtime_disable(&pdev->dev);
+ return 0;
+}
+
+static const struct of_device_id simple_pm_bus_of_match[] = {
+ { .compatible = "simple-pm-bus", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, simple_pm_bus_of_match);
+
+static struct platform_driver simple_pm_bus_driver = {
+ .probe = simple_pm_bus_probe,
+ .remove = simple_pm_bus_remove,
+ .driver = {
+ .name = "simple-pm-bus",
+ .of_match_table = simple_pm_bus_of_match,
+ },
+};
+
+module_platform_driver(simple_pm_bus_driver);
+
+MODULE_DESCRIPTION("Simple Power-Managed Bus Driver");
+MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 0689d7fb2666..97c71c885e4f 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
+obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c
new file mode 100644
index 000000000000..cb33b57274bf
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a7778.c
@@ -0,0 +1,143 @@
+/*
+ * r8a7778 Core CPG Clocks
+ *
+ * Copyright (C) 2014 Ulrich Hecht
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/of_address.h>
+
+struct r8a7778_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+/* PLL multipliers per bits 11, 12, and 18 of MODEMR */
+struct {
+ unsigned long plla_mult;
+ unsigned long pllb_mult;
+} r8a7778_rates[] __initdata = {
+ [0] = { 21, 21 },
+ [1] = { 24, 24 },
+ [2] = { 28, 28 },
+ [3] = { 32, 32 },
+ [5] = { 24, 21 },
+ [6] = { 28, 21 },
+ [7] = { 32, 24 },
+};
+
+/* Clock dividers per bits 1 and 2 of MODEMR */
+struct {
+ const char *name;
+ unsigned int div[4];
+} r8a7778_divs[6] __initdata = {
+ { "b", { 12, 12, 16, 18 } },
+ { "out", { 12, 12, 16, 18 } },
+ { "p", { 16, 12, 16, 12 } },
+ { "s", { 4, 3, 4, 3 } },
+ { "s1", { 8, 6, 8, 6 } },
+};
+
+static u32 cpg_mode_rates __initdata;
+static u32 cpg_mode_divs __initdata;
+
+static struct clk * __init
+r8a7778_cpg_register_clock(struct device_node *np, struct r8a7778_cpg *cpg,
+ const char *name)
+{
+ if (!strcmp(name, "plla")) {
+ return clk_register_fixed_factor(NULL, "plla",
+ of_clk_get_parent_name(np, 0), 0,
+ r8a7778_rates[cpg_mode_rates].plla_mult, 1);
+ } else if (!strcmp(name, "pllb")) {
+ return clk_register_fixed_factor(NULL, "pllb",
+ of_clk_get_parent_name(np, 0), 0,
+ r8a7778_rates[cpg_mode_rates].pllb_mult, 1);
+ } else {
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) {
+ if (!strcmp(name, r8a7778_divs[i].name)) {
+ return clk_register_fixed_factor(NULL,
+ r8a7778_divs[i].name,
+ "plla", 0, 1,
+ r8a7778_divs[i].div[cpg_mode_divs]);
+ }
+ }
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+
+static void __init r8a7778_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a7778_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = r8a7778_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+
+CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks",
+ r8a7778_cpg_clocks_init);
+
+void __init r8a7778_clocks_init(u32 mode)
+{
+ BUG_ON(!(mode & BIT(19)));
+
+ cpg_mode_rates = (!!(mode & BIT(18)) << 2) |
+ (!!(mode & BIT(12)) << 1) |
+ (!!(mode & BIT(11)));
+ cpg_mode_divs = (!!(mode & BIT(2)) << 1) |
+ (!!(mode & BIT(1)));
+
+ of_clk_init(NULL);
+}