arm: zynq: Migrate platform to clock controller
authorSoren Brinkmann <soren.brinkmann@xilinx.com>
Mon, 13 May 2013 17:46:38 +0000 (10:46 -0700)
committerMichal Simek <michal.simek@xilinx.com>
Mon, 27 May 2013 07:21:22 +0000 (09:21 +0200)
Migrate the Zynq platform and its drivers to use the new clock
controller driver.

Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.cz>
Cc: linux-serial@vger.kernel.org
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Acked-by: Mike Turquette <mturquette@linaro.org>
arch/arm/boot/dts/zynq-7000.dtsi
arch/arm/boot/dts/zynq-zc702.dts
arch/arm/mach-zynq/slcr.c
drivers/clk/Makefile
drivers/clk/zynq/Makefile [new file with mode: 0644]
drivers/clocksource/cadence_ttc_timer.c
drivers/tty/serial/xilinx_uartps.c
include/linux/clk/zynq.h

index 14fb2e6..0dbee2c 100644 (file)
 
                uart0: uart@e0000000 {
                        compatible = "xlnx,xuartps";
+                       clocks = <&clkc 23>, <&clkc 40>;
+                       clock-names = "ref_clk", "aper_clk";
                        reg = <0xE0000000 0x1000>;
                        interrupts = <0 27 4>;
-                       clocks = <&uart_clk 0>;
                };
 
                uart1: uart@e0001000 {
                        compatible = "xlnx,xuartps";
+                       clocks = <&clkc 24>, <&clkc 41>;
+                       clock-names = "ref_clk", "aper_clk";
                        reg = <0xE0001000 0x1000>;
                        interrupts = <0 50 4>;
-                       clocks = <&uart_clk 1>;
                };
 
                slcr: slcr@f8000000 {
                                #address-cells = <1>;
                                #size-cells = <0>;
 
-                               ps_clk: ps_clk {
-                                       #clock-cells = <0>;
-                                       compatible = "fixed-clock";
-                                       /* clock-frequency set in board-specific file */
-                                       clock-output-names = "ps_clk";
-                               };
-                               armpll: armpll {
-                                       #clock-cells = <0>;
-                                       compatible = "xlnx,zynq-pll";
-                                       clocks = <&ps_clk>;
-                                       reg = <0x100 0x110>;
-                                       clock-output-names = "armpll";
-                               };
-                               ddrpll: ddrpll {
-                                       #clock-cells = <0>;
-                                       compatible = "xlnx,zynq-pll";
-                                       clocks = <&ps_clk>;
-                                       reg = <0x104 0x114>;
-                                       clock-output-names = "ddrpll";
-                               };
-                               iopll: iopll {
-                                       #clock-cells = <0>;
-                                       compatible = "xlnx,zynq-pll";
-                                       clocks = <&ps_clk>;
-                                       reg = <0x108 0x118>;
-                                       clock-output-names = "iopll";
-                               };
-                               uart_clk: uart_clk {
-                                       #clock-cells = <1>;
-                                       compatible = "xlnx,zynq-periph-clock";
-                                       clocks = <&iopll &armpll &ddrpll>;
-                                       reg = <0x154>;
-                                       clock-output-names = "uart0_ref_clk",
-                                                            "uart1_ref_clk";
-                               };
-                               cpu_clk: cpu_clk {
+                               clkc: clkc {
                                        #clock-cells = <1>;
-                                       compatible = "xlnx,zynq-cpu-clock";
-                                       clocks = <&iopll &armpll &ddrpll>;
-                                       reg = <0x120 0x1C4>;
-                                       clock-output-names = "cpu_6x4x",
-                                                            "cpu_3x2x",
-                                                            "cpu_2x",
-                                                            "cpu_1x";
+                                       compatible = "xlnx,ps7-clkc";
+                                       ps-clk-frequency = <33333333>;
+                                       clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
+                                                       "cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
+                                                       "dci", "lqspi", "smc", "pcap", "gem0", "gem1",
+                                                       "fclk0", "fclk1", "fclk2", "fclk3", "can0", "can1",
+                                                       "sdio0", "sdio1", "uart0", "uart1", "spi0", "spi1",
+                                                       "dma", "usb0_aper", "usb1_aper", "gem0_aper",
+                                                       "gem1_aper", "sdio0_aper", "sdio1_aper",
+                                                       "spi0_aper", "spi1_aper", "can0_aper", "can1_aper",
+                                                       "i2c0_aper", "i2c1_aper", "uart0_aper", "uart1_aper",
+                                                       "gpio_aper", "lqspi_aper", "smc_aper", "swdt",
+                                                       "dbg_trc", "dbg_apb";
                                };
                        };
                };
                        interrupt-parent = <&intc>;
                        interrupts = < 0 10 4 0 11 4 0 12 4 >;
                        compatible = "cdns,ttc";
+                       clocks = <&clkc 6>;
                        reg = <0xF8001000 0x1000>;
-                       clocks = <&cpu_clk 3>;
-                       clock-names = "cpu_1x";
                        clock-ranges;
                };
 
                        interrupt-parent = <&intc>;
                        interrupts = < 0 37 4 0 38 4 0 39 4 >;
                        compatible = "cdns,ttc";
+                       clocks = <&clkc 6>;
                        reg = <0xF8002000 0x1000>;
-                       clocks = <&cpu_clk 3>;
-                       clock-names = "cpu_1x";
                        clock-ranges;
                };
                scutimer: scutimer@f8f00600 {
                        interrupts = < 1 13 0x301 >;
                        compatible = "arm,cortex-a9-twd-timer";
                        reg = < 0xf8f00600 0x20 >;
-                       clocks = <&cpu_clk 1>;
+                       clocks = <&clkc 4>;
                } ;
        };
 };
index 86f44d5..e25a307 100644 (file)
@@ -28,7 +28,3 @@
        };
 
 };
-
-&ps_clk {
-       clock-frequency = <33333330>;
-};
index c70969b..50d008d 100644 (file)
@@ -117,7 +117,7 @@ int __init zynq_slcr_init(void)
 
        pr_info("%s mapped to %p\n", np->name, zynq_slcr_base);
 
-       xilinx_zynq_clocks_init(zynq_slcr_base);
+       zynq_clock_init(zynq_slcr_base);
 
        of_node_put(np);
 
index 137d3e7..fa435bc 100644 (file)
@@ -27,7 +27,7 @@ obj-$(CONFIG_MACH_LOONGSON1)  += clk-ls1x.o
 obj-$(CONFIG_ARCH_SUNXI)       += sunxi/
 obj-$(CONFIG_ARCH_U8500)       += ux500/
 obj-$(CONFIG_ARCH_VT8500)      += clk-vt8500.o
-obj-$(CONFIG_ARCH_ZYNQ)                += clk-zynq.o
+obj-$(CONFIG_ARCH_ZYNQ)                += zynq/
 obj-$(CONFIG_ARCH_TEGRA)       += tegra/
 obj-$(CONFIG_PLAT_SAMSUNG)     += samsung/
 
diff --git a/drivers/clk/zynq/Makefile b/drivers/clk/zynq/Makefile
new file mode 100644 (file)
index 0000000..156d923
--- /dev/null
@@ -0,0 +1,3 @@
+# Zynq clock specific Makefile
+
+obj-$(CONFIG_ARCH_ZYNQ)        += clkc.o pll.o
index 685bc60..4cbe28c 100644 (file)
@@ -51,6 +51,8 @@
 
 #define TTC_CNT_CNTRL_DISABLE_MASK     0x1
 
+#define TTC_CLK_CNTRL_CSRC_MASK                (1 << 5)        /* clock source */
+
 /*
  * Setup the timers to use pre-scaling, using a fixed value for now that will
  * work across most input frequency, but it may need to be more dynamic
@@ -396,8 +398,9 @@ static void __init ttc_timer_init(struct device_node *timer)
 {
        unsigned int irq;
        void __iomem *timer_baseaddr;
-       struct clk *clk;
+       struct clk *clk_cs, *clk_ce;
        static int initialized;
+       int clksel;
 
        if (initialized)
                return;
@@ -421,14 +424,24 @@ static void __init ttc_timer_init(struct device_node *timer)
                BUG();
        }
 
-       clk = of_clk_get_by_name(timer, "cpu_1x");
-       if (IS_ERR(clk)) {
+       clksel = __raw_readl(timer_baseaddr + TTC_CLK_CNTRL_OFFSET);
+       clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK);
+       clk_cs = of_clk_get(timer, clksel);
+       if (IS_ERR(clk_cs)) {
+               pr_err("ERROR: timer input clock not found\n");
+               BUG();
+       }
+
+       clksel = __raw_readl(timer_baseaddr + 4 + TTC_CLK_CNTRL_OFFSET);
+       clksel = !!(clksel & TTC_CLK_CNTRL_CSRC_MASK);
+       clk_ce = of_clk_get(timer, clksel);
+       if (IS_ERR(clk_ce)) {
                pr_err("ERROR: timer input clock not found\n");
                BUG();
        }
 
-       ttc_setup_clocksource(clk, timer_baseaddr);
-       ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
+       ttc_setup_clocksource(clk_cs, timer_baseaddr);
+       ttc_setup_clockevent(clk_ce, timer_baseaddr + 4, irq);
 
        pr_info("%s #0 at %p, irq=%d\n", timer->name, timer_baseaddr, irq);
 }
index 4e5c778..a4a3028 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/slab.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/console.h>
 #define XUARTPS_SR_RXTRIG      0x00000001 /* Rx Trigger */
 
 /**
+ * struct xuartps - device data
+ * @refclk     Reference clock
+ * @aperclk    APB clock
+ */
+struct xuartps {
+       struct clk              *refclk;
+       struct clk              *aperclk;
+};
+
+/**
  * xuartps_isr - Interrupt handler
  * @irq: Irq number
  * @dev_id: Id of the port
@@ -936,34 +947,55 @@ static int xuartps_probe(struct platform_device *pdev)
        int rc;
        struct uart_port *port;
        struct resource *res, *res2;
-       struct clk *clk;
+       struct xuartps *xuartps_data;
 
-       clk = of_clk_get(pdev->dev.of_node, 0);
-       if (IS_ERR(clk)) {
-               dev_err(&pdev->dev, "no clock specified\n");
-               return PTR_ERR(clk);
+       xuartps_data = kzalloc(sizeof(*xuartps_data), GFP_KERNEL);
+       if (!xuartps_data)
+               return -ENOMEM;
+
+       xuartps_data->aperclk = clk_get(&pdev->dev, "aper_clk");
+       if (IS_ERR(xuartps_data->aperclk)) {
+               dev_err(&pdev->dev, "aper_clk clock not found.\n");
+               rc = PTR_ERR(xuartps_data->aperclk);
+               goto err_out_free;
+       }
+       xuartps_data->refclk = clk_get(&pdev->dev, "ref_clk");
+       if (IS_ERR(xuartps_data->refclk)) {
+               dev_err(&pdev->dev, "ref_clk clock not found.\n");
+               rc = PTR_ERR(xuartps_data->refclk);
+               goto err_out_clk_put_aper;
        }
 
-       rc = clk_prepare_enable(clk);
+       rc = clk_prepare_enable(xuartps_data->aperclk);
+       if (rc) {
+               dev_err(&pdev->dev, "Unable to enable APER clock.\n");
+               goto err_out_clk_put;
+       }
+       rc = clk_prepare_enable(xuartps_data->refclk);
        if (rc) {
-               dev_err(&pdev->dev, "could not enable clock\n");
-               return -EBUSY;
+               dev_err(&pdev->dev, "Unable to enable device clock.\n");
+               goto err_out_clk_dis_aper;
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
+       if (!res) {
+               rc = -ENODEV;
+               goto err_out_clk_disable;
+       }
 
        res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res2)
-               return -ENODEV;
+       if (!res2) {
+               rc = -ENODEV;
+               goto err_out_clk_disable;
+       }
 
        /* Initialize the port structure */
        port = xuartps_get_port();
 
        if (!port) {
                dev_err(&pdev->dev, "Cannot get uart_port structure\n");
-               return -ENODEV;
+               rc = -ENODEV;
+               goto err_out_clk_disable;
        } else {
                /* Register the port.
                 * This function also registers this device with the tty layer
@@ -972,18 +1004,31 @@ static int xuartps_probe(struct platform_device *pdev)
                port->mapbase = res->start;
                port->irq = res2->start;
                port->dev = &pdev->dev;
-               port->uartclk = clk_get_rate(clk);
-               port->private_data = clk;
+               port->uartclk = clk_get_rate(xuartps_data->refclk);
+               port->private_data = xuartps_data;
                dev_set_drvdata(&pdev->dev, port);
                rc = uart_add_one_port(&xuartps_uart_driver, port);
                if (rc) {
                        dev_err(&pdev->dev,
                                "uart_add_one_port() failed; err=%i\n", rc);
                        dev_set_drvdata(&pdev->dev, NULL);
-                       return rc;
+                       goto err_out_clk_disable;
                }
                return 0;
        }
+
+err_out_clk_disable:
+       clk_disable_unprepare(xuartps_data->refclk);
+err_out_clk_dis_aper:
+       clk_disable_unprepare(xuartps_data->aperclk);
+err_out_clk_put:
+       clk_put(xuartps_data->refclk);
+err_out_clk_put_aper:
+       clk_put(xuartps_data->aperclk);
+err_out_free:
+       kfree(xuartps_data);
+
+       return rc;
 }
 
 /**
@@ -995,14 +1040,18 @@ static int xuartps_probe(struct platform_device *pdev)
 static int xuartps_remove(struct platform_device *pdev)
 {
        struct uart_port *port = dev_get_drvdata(&pdev->dev);
-       struct clk *clk = port->private_data;
+       struct xuartps *xuartps_data = port->private_data;
        int rc;
 
        /* Remove the xuartps port from the serial core */
        rc = uart_remove_one_port(&xuartps_uart_driver, port);
        dev_set_drvdata(&pdev->dev, NULL);
        port->mapbase = 0;
-       clk_disable_unprepare(clk);
+       clk_disable_unprepare(xuartps_data->refclk);
+       clk_disable_unprepare(xuartps_data->aperclk);
+       clk_put(xuartps_data->refclk);
+       clk_put(xuartps_data->aperclk);
+       kfree(xuartps_data);
        return rc;
 }
 
index 56be7cd..e062d31 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2013 Xilinx Inc.
  * Copyright (C) 2012 National Instruments
  *
  * This program is free software; you can redistribute it and/or modify
 #ifndef __LINUX_CLK_ZYNQ_H_
 #define __LINUX_CLK_ZYNQ_H_
 
-void __init xilinx_zynq_clocks_init(void __iomem *slcr);
+#include <linux/spinlock.h>
 
+void zynq_clock_init(void __iomem *slcr);
+
+struct clk *clk_register_zynq_pll(const char *name, const char *parent,
+               void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index,
+               spinlock_t *lock);
 #endif