| From 036eae88dd3e2eee9c2227661f0a21060529ecef Mon Sep 17 00:00:00 2001 |
| From: Soren Brinkmann <soren.brinkmann@xilinx.com> |
| Date: Mon, 13 May 2013 10:46:38 -0700 |
| Subject: arm: zynq: Migrate platform to clock controller |
| |
| 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> |
| (cherry picked from commit 30e1e28598c2674c133148d8aec6d431d7acd314) |
| Signed-off-by: Daniel Sangorrin <daniel.sangorrin@toshiba.co.jp> |
| Signed-off-by: Yoshitake Kobayashi <yoshitake.kobayashi@toshiba.co.jp> |
| --- |
| arch/arm/boot/dts/zynq-7000.dtsi | 71 +++++++------------------- |
| arch/arm/boot/dts/zynq-zc702.dts | 4 - |
| arch/arm/mach-zynq/slcr.c | 2 |
| drivers/clk/Makefile | 2 |
| drivers/clk/zynq/Makefile | 3 + |
| drivers/clocksource/cadence_ttc_timer.c | 23 ++++++-- |
| drivers/tty/serial/xilinx_uartps.c | 85 +++++++++++++++++++++++++------- |
| include/linux/clk/zynq.h | 8 ++- |
| 8 files changed, 118 insertions(+), 80 deletions(-) |
| create mode 100644 drivers/clk/zynq/Makefile |
| |
| --- a/arch/arm/boot/dts/zynq-7000.dtsi |
| +++ b/arch/arm/boot/dts/zynq-7000.dtsi |
| @@ -49,16 +49,18 @@ |
| |
| 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 { |
| @@ -69,50 +71,21 @@ |
| #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 { |
| + clkc: clkc { |
| #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 { |
| - #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"; |
| }; |
| }; |
| }; |
| @@ -129,9 +102,8 @@ |
| 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; |
| }; |
| |
| @@ -139,9 +111,8 @@ |
| 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 { |
| @@ -149,7 +120,7 @@ |
| interrupts = < 1 13 0x301 >; |
| compatible = "arm,cortex-a9-twd-timer"; |
| reg = < 0xf8f00600 0x20 >; |
| - clocks = <&cpu_clk 1>; |
| + clocks = <&clkc 4>; |
| } ; |
| }; |
| }; |
| --- a/arch/arm/boot/dts/zynq-zc702.dts |
| +++ b/arch/arm/boot/dts/zynq-zc702.dts |
| @@ -28,7 +28,3 @@ |
| }; |
| |
| }; |
| - |
| -&ps_clk { |
| - clock-frequency = <33333330>; |
| -}; |
| --- a/arch/arm/mach-zynq/slcr.c |
| +++ b/arch/arm/mach-zynq/slcr.c |
| @@ -106,7 +106,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); |
| |
| --- a/drivers/clk/Makefile |
| +++ b/drivers/clk/Makefile |
| @@ -27,7 +27,7 @@ obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x |
| 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/ |
| obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ |
| --- /dev/null |
| +++ b/drivers/clk/zynq/Makefile |
| @@ -0,0 +1,3 @@ |
| +# Zynq clock specific Makefile |
| + |
| +obj-$(CONFIG_ARCH_ZYNQ) += clkc.o pll.o |
| --- a/drivers/clocksource/cadence_ttc_timer.c |
| +++ b/drivers/clocksource/cadence_ttc_timer.c |
| @@ -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 |
| { |
| 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 |
| 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); |
| } |
| --- a/drivers/tty/serial/xilinx_uartps.c |
| +++ b/drivers/tty/serial/xilinx_uartps.c |
| @@ -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> |
| @@ -139,6 +140,16 @@ |
| #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 |
| 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 |
| 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 |
| 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; |
| } |
| |
| --- a/include/linux/clk/zynq.h |
| +++ b/include/linux/clk/zynq.h |
| @@ -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 |
| @@ -19,6 +20,11 @@ |
| #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 |