Commit 30e1e285 authored by Soren Brinkmann's avatar Soren Brinkmann Committed by Michal Simek

arm: zynq: Migrate platform to clock controller

Migrate the Zynq platform and its drivers to use the new clock
controller driver.
Signed-off-by: default avatarSoren 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: default avatarMichal Simek <michal.simek@xilinx.com>
Acked-by: default avatarMike Turquette <mturquette@linaro.org>
parent 0ee52b15
......@@ -49,16 +49,18 @@ L2: cache-controller {
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 @@ clocks {
#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";
};
};
};
......@@ -121,9 +94,8 @@ ttc0: ttc0@f8001000 {
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 @@ ttc1: ttc1@f8002000 {
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 @@ scutimer: scutimer@f8f00600 {
interrupts = < 1 13 0x301 >;
compatible = "arm,cortex-a9-twd-timer";
reg = < 0xf8f00600 0x20 >;
clocks = <&cpu_clk 1>;
clocks = <&clkc 4>;
} ;
};
};
......@@ -28,7 +28,3 @@ chosen {
};
};
&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/
......
# 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();
}
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);
}
......
......@@ -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, "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;
}
......
/*
* 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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment