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>
This commit is contained in:
Родитель
0ee52b157b
Коммит
30e1e28598
|
@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -121,9 +94,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;
|
||||
};
|
||||
|
||||
|
@ -131,9 +103,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 {
|
||||
|
@ -141,7 +112,7 @@
|
|||
interrupts = < 1 13 0x301 >;
|
||||
compatible = "arm,cortex-a9-twd-timer";
|
||||
reg = < 0xf8f00600 0x20 >;
|
||||
clocks = <&cpu_clk 1>;
|
||||
clocks = <&clkc 4>;
|
||||
} ;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -28,7 +28,3 @@
|
|||
};
|
||||
|
||||
};
|
||||
|
||||
&ps_clk {
|
||||
clock-frequency = <33333330>;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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/
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Zynq clock specific Makefile
|
||||
|
||||
obj-$(CONFIG_ARCH_ZYNQ) += clkc.o pll.o
|
|
@ -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();
|
||||
}
|
||||
|
||||
ttc_setup_clocksource(clk, timer_baseaddr);
|
||||
ttc_setup_clockevent(clk, timer_baseaddr + 4, irq);
|
||||
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_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);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
@ -138,6 +139,16 @@
|
|||
#define XUARTPS_SR_TXFULL 0x00000010 /* TX FIFO full */
|
||||
#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
|
||||
|
@ -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, "could not enable clock\n");
|
||||
return -EBUSY;
|
||||
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, "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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче