Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
[pandora-kernel.git] / arch / sh / boards / mach-sdk7786 / setup.c
index 2ec1ea5..7e0c4e3 100644 (file)
@@ -20,6 +20,8 @@
 #include <asm/machvec.h>
 #include <asm/heartbeat.h>
 #include <asm/sizes.h>
+#include <asm/clock.h>
+#include <asm/clkdev.h>
 #include <asm/reboot.h>
 #include <asm/smp-ops.h>
 
@@ -140,6 +142,45 @@ static int sdk7786_mode_pins(void)
        return fpga_read_reg(MODSWR);
 }
 
+/*
+ * FPGA-driven PCIe clocks
+ *
+ * Historically these include the oscillator, clock B (slots 2/3/4) and
+ * clock A (slot 1 and the CPU clock). Newer revs of the PCB shove
+ * everything under a single PCIe clocks enable bit that happens to map
+ * to the same bit position as the oscillator bit for earlier FPGA
+ * versions.
+ *
+ * Given that the legacy clocks have the side-effect of shutting the CPU
+ * off through the FPGA along with the PCI slots, we simply leave them in
+ * their initial state and don't bother registering them with the clock
+ * framework.
+ */
+static int sdk7786_pcie_clk_enable(struct clk *clk)
+{
+       fpga_write_reg(fpga_read_reg(PCIECR) | PCIECR_CLKEN, PCIECR);
+       return 0;
+}
+
+static void sdk7786_pcie_clk_disable(struct clk *clk)
+{
+       fpga_write_reg(fpga_read_reg(PCIECR) & ~PCIECR_CLKEN, PCIECR);
+}
+
+static struct clk_ops sdk7786_pcie_clk_ops = {
+       .enable         = sdk7786_pcie_clk_enable,
+       .disable        = sdk7786_pcie_clk_disable,
+};
+
+static struct clk sdk7786_pcie_clk = {
+       .ops            = &sdk7786_pcie_clk_ops,
+};
+
+static struct clk_lookup sdk7786_pcie_cl = {
+       .con_id         = "pcie_plat_clk",
+       .clk            = &sdk7786_pcie_clk,
+};
+
 static int sdk7786_clk_init(void)
 {
        struct clk *clk;
@@ -158,7 +199,18 @@ static int sdk7786_clk_init(void)
        ret = clk_set_rate(clk, 33333333);
        clk_put(clk);
 
-       return ret;
+       /*
+        * Setup the FPGA clocks.
+        */
+       ret = clk_register(&sdk7786_pcie_clk);
+       if (unlikely(ret)) {
+               pr_err("FPGA clock registration failed\n");
+               return ret;
+       }
+
+       clkdev_add(&sdk7786_pcie_cl);
+
+       return 0;
 }
 
 static void sdk7786_restart(char *cmd)