Commit 9161c3b7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux

Pull common clk framework changes from Michael Turquette:
 "This includes a small number of core framework improvments, platform
  ports and new DT bindings."

Fix up trivial conflicts in drivers/clk/Makefile

* tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux: (21 commits)
  clk: fix compile for OF && !COMMON_CLK
  clk: fix clk_get on of_clk_get_by_name return check
  clk: mxs: clk_register_clkdev mx28 usb clocks
  clk: add highbank clock support
  dt: add clock binding doc to primecell bindings
  clk: add DT fixed-clock binding support
  clk: add DT clock binding support
  ARM: integrator: convert to common clock
  clk: add versatile ICST307 driver
  ARM: integrator: put symbolic bus names on devices
  ARM: u300: convert to common clock
  clk: cache parent clocks only for muxes
  clk: wm831x: Add initial WM831x clock driver
  clk: Constify struct clk_init_data
  clk: Add CLK_IS_BASIC flag to identify basic clocks
  clk: Add support for rate table based dividers
  clk: Add support for power of two type dividers
  clk: mxs: imx28: decrease the frequency of ref_io1 for SSP2 and SSP3
  clk: mxs: add clkdev lookup for pwm
  clk: mxs: Fix the GPMI clock name
  ...
parents 97027da6 137f8a72
...@@ -13,11 +13,17 @@ Required properties: ...@@ -13,11 +13,17 @@ Required properties:
Optional properties: Optional properties:
- arm,primecell-periphid : Value to override the h/w value with - arm,primecell-periphid : Value to override the h/w value with
- clocks : From common clock binding. First clock is phandle to clock for apb
pclk. Additional clocks are optional and specific to those peripherals.
- clock-names : From common clock binding. Shall be "apb_pclk" for first clock.
Example: Example:
serial@fff36000 { serial@fff36000 {
compatible = "arm,pl011", "arm,primecell"; compatible = "arm,pl011", "arm,primecell";
arm,primecell-periphid = <0x00341011>; arm,primecell-periphid = <0x00341011>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
Device Tree Clock bindings for Calxeda highbank platform
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be one of the following:
"calxeda,hb-pll-clock" - for a PLL clock
"calxeda,hb-a9periph-clock" - The A9 peripheral clock divided from the
A9 clock.
"calxeda,hb-a9bus-clock" - The A9 bus clock divided from the A9 clock.
"calxeda,hb-emmc-clock" - Divided clock for MMC/SD controller.
- reg : shall be the control register offset from SYSREGs base for the clock.
- clocks : shall be the input parent clock phandle for the clock. This is
either an oscillator or a pll output.
- #clock-cells : from common clock binding; shall be set to 0.
This binding is a work-in-progress, and are based on some experimental
work by benh[1].
Sources of clock signal can be represented by any node in the device
tree. Those nodes are designated as clock providers. Clock consumer
nodes use a phandle and clock specifier pair to connect clock provider
outputs to clock inputs. Similar to the gpio specifiers, a clock
specifier is an array of one more more cells identifying the clock
output on a device. The length of a clock specifier is defined by the
value of a #clock-cells property in the clock provider node.
[1] http://patchwork.ozlabs.org/patch/31551/
==Clock providers==
Required properties:
#clock-cells: Number of cells in a clock specifier; Typically 0 for nodes
with a single clock output and 1 for nodes with multiple
clock outputs.
Optional properties:
clock-output-names: Recommended to be a list of strings of clock output signal
names indexed by the first cell in the clock specifier.
However, the meaning of clock-output-names is domain
specific to the clock provider, and is only provided to
encourage using the same meaning for the majority of clock
providers. This format may not work for clock providers
using a complex clock specifier format. In those cases it
is recommended to omit this property and create a binding
specific names property.
Clock consumer nodes must never directly reference
the provider's clock-output-names property.
For example:
oscillator {
#clock-cells = <1>;
clock-output-names = "ckil", "ckih";
};
- this node defines a device with two clock outputs, the first named
"ckil" and the second named "ckih". Consumer nodes always reference
clocks by index. The names should reflect the clock output signal
names for the device.
==Clock consumers==
Required properties:
clocks: List of phandle and clock specifier pairs, one pair
for each clock input to the device. Note: if the
clock provider specifies '0' for #clock-cells, then
only the phandle portion of the pair will appear.
Optional properties:
clock-names: List of clock input name strings sorted in the same
order as the clocks property. Consumers drivers
will use clock-names to match clock input names
with clocks specifiers.
clock-ranges: Empty property indicating that child nodes can inherit named
clocks from this node. Useful for bus nodes to provide a
clock to their children.
For example:
device {
clocks = <&osc 1>, <&ref 0>;
clock-names = "baud", "register";
};
This represents a device with two clock inputs, named "baud" and "register".
The baud clock is connected to output 1 of the &osc device, and the register
clock is connected to output 0 of the &ref.
==Example==
/* external oscillator */
osc: oscillator {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <32678>;
clock-output-names = "osc";
};
/* phase-locked-loop device, generates a higher frequency clock
* from the external oscillator reference */
pll: pll@4c000 {
compatible = "vendor,some-pll-interface"
#clock-cells = <1>;
clocks = <&osc 0>;
clock-names = "ref";
reg = <0x4c000 0x1000>;
clock-output-names = "pll", "pll-switched";
};
/* UART, using the low frequency oscillator for the baud clock,
* and the high frequency switched PLL output for register
* clocking */
uart@a000 {
compatible = "fsl,imx-uart";
reg = <0xa000 0x1000>;
interrupts = <33>;
clocks = <&osc 0>, <&pll 1>;
clock-names = "baud", "register";
};
This DT fragment defines three devices: an external oscillator to provide a
low-frequency reference clock, a PLL device to generate a higher frequency
clock signal, and a UART.
* The oscillator is fixed-frequency, and provides one clock output, named "osc".
* The PLL is both a clock provider and a clock consumer. It uses the clock
signal generated by the external oscillator, and provides two output signals
("pll" and "pll-switched").
* The UART has its baud clock connected the external oscillator and its
register clock connected to the PLL clock (the "pll-switched" signal)
Binding for simple fixed-rate clock sources.
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible : shall be "fixed-clock".
- #clock-cells : from common clock binding; shall be set to 0.
- clock-frequency : frequency of clock in Hz. Should be a single cell.
Optional properties:
- gpios : From common gpio binding; gpio connection to clock enable pin.
- clock-output-names : From common clock binding.
Example:
clock {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
};
...@@ -7605,6 +7605,7 @@ W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices ...@@ -7605,6 +7605,7 @@ W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices
S: Supported S: Supported
F: Documentation/hwmon/wm83?? F: Documentation/hwmon/wm83??
F: arch/arm/mach-s3c64xx/mach-crag6410* F: arch/arm/mach-s3c64xx/mach-crag6410*
F: drivers/clk/clk-wm83*.c
F: drivers/leds/leds-wm83*.c F: drivers/leds/leds-wm83*.c
F: drivers/hwmon/wm83??-hwmon.c F: drivers/hwmon/wm83??-hwmon.c
F: drivers/input/misc/wm831x-on.c F: drivers/input/misc/wm831x-on.c
......
...@@ -273,8 +273,8 @@ config ARCH_INTEGRATOR ...@@ -273,8 +273,8 @@ config ARCH_INTEGRATOR
bool "ARM Ltd. Integrator family" bool "ARM Ltd. Integrator family"
select ARM_AMBA select ARM_AMBA
select ARCH_HAS_CPUFREQ select ARCH_HAS_CPUFREQ
select CLKDEV_LOOKUP select COMMON_CLK
select HAVE_MACH_CLKDEV select CLK_VERSATILE
select HAVE_TCM select HAVE_TCM
select ICST select ICST
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
...@@ -336,6 +336,7 @@ config ARCH_VEXPRESS ...@@ -336,6 +336,7 @@ config ARCH_VEXPRESS
select ICST select ICST
select NO_IOPORT select NO_IOPORT
select PLAT_VERSATILE select PLAT_VERSATILE
select PLAT_VERSATILE_CLOCK
select PLAT_VERSATILE_CLCD select PLAT_VERSATILE_CLCD
select REGULATOR_FIXED_VOLTAGE if REGULATOR select REGULATOR_FIXED_VOLTAGE if REGULATOR
help help
...@@ -372,6 +373,7 @@ config ARCH_HIGHBANK ...@@ -372,6 +373,7 @@ config ARCH_HIGHBANK
select ARM_TIMER_SP804 select ARM_TIMER_SP804
select CACHE_L2X0 select CACHE_L2X0
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select COMMON_CLK
select CPU_V7 select CPU_V7
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select HAVE_ARM_SCU select HAVE_ARM_SCU
...@@ -929,7 +931,7 @@ config ARCH_U300 ...@@ -929,7 +931,7 @@ config ARCH_U300
select ARM_VIC select ARM_VIC
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP select CLKDEV_LOOKUP
select HAVE_MACH_CLKDEV select COMMON_CLK
select GENERIC_GPIO select GENERIC_GPIO
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
help help
......
/* /*
* Copyright 2011 Calxeda, Inc. * Copyright 2011-2012 Calxeda, Inc.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
...@@ -24,6 +24,7 @@ / { ...@@ -24,6 +24,7 @@ / {
compatible = "calxeda,highbank"; compatible = "calxeda,highbank";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
clock-ranges;
cpus { cpus {
#address-cells = <1>; #address-cells = <1>;
...@@ -33,24 +34,32 @@ cpu@0 { ...@@ -33,24 +34,32 @@ cpu@0 {
compatible = "arm,cortex-a9"; compatible = "arm,cortex-a9";
reg = <0>; reg = <0>;
next-level-cache = <&L2>; next-level-cache = <&L2>;
clocks = <&a9pll>;
clock-names = "cpu";
}; };
cpu@1 { cpu@1 {
compatible = "arm,cortex-a9"; compatible = "arm,cortex-a9";
reg = <1>; reg = <1>;
next-level-cache = <&L2>; next-level-cache = <&L2>;
clocks = <&a9pll>;
clock-names = "cpu";
}; };
cpu@2 { cpu@2 {
compatible = "arm,cortex-a9"; compatible = "arm,cortex-a9";
reg = <2>; reg = <2>;
next-level-cache = <&L2>; next-level-cache = <&L2>;
clocks = <&a9pll>;
clock-names = "cpu";
}; };
cpu@3 { cpu@3 {
compatible = "arm,cortex-a9"; compatible = "arm,cortex-a9";
reg = <3>; reg = <3>;
next-level-cache = <&L2>; next-level-cache = <&L2>;
clocks = <&a9pll>;
clock-names = "cpu";
}; };
}; };
...@@ -75,12 +84,14 @@ timer@fff10600 { ...@@ -75,12 +84,14 @@ timer@fff10600 {
compatible = "arm,cortex-a9-twd-timer"; compatible = "arm,cortex-a9-twd-timer";
reg = <0xfff10600 0x20>; reg = <0xfff10600 0x20>;
interrupts = <1 13 0xf01>; interrupts = <1 13 0xf01>;
clocks = <&a9periphclk>;
}; };
watchdog@fff10620 { watchdog@fff10620 {
compatible = "arm,cortex-a9-twd-wdt"; compatible = "arm,cortex-a9-twd-wdt";
reg = <0xfff10620 0x20>; reg = <0xfff10620 0x20>;
interrupts = <1 14 0xf01>; interrupts = <1 14 0xf01>;
clocks = <&a9periphclk>;
}; };
intc: interrupt-controller@fff11000 { intc: interrupt-controller@fff11000 {
...@@ -116,12 +127,15 @@ sdhci@ffe0e000 { ...@@ -116,12 +127,15 @@ sdhci@ffe0e000 {
compatible = "calxeda,hb-sdhci"; compatible = "calxeda,hb-sdhci";
reg = <0xffe0e000 0x1000>; reg = <0xffe0e000 0x1000>;
interrupts = <0 90 4>; interrupts = <0 90 4>;
clocks = <&eclk>;
}; };
ipc@fff20000 { ipc@fff20000 {
compatible = "arm,pl320", "arm,primecell"; compatible = "arm,pl320", "arm,primecell";
reg = <0xfff20000 0x1000>; reg = <0xfff20000 0x1000>;
interrupts = <0 7 4>; interrupts = <0 7 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
gpioe: gpio@fff30000 { gpioe: gpio@fff30000 {
...@@ -130,6 +144,8 @@ gpioe: gpio@fff30000 { ...@@ -130,6 +144,8 @@ gpioe: gpio@fff30000 {
gpio-controller; gpio-controller;
reg = <0xfff30000 0x1000>; reg = <0xfff30000 0x1000>;
interrupts = <0 14 4>; interrupts = <0 14 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
gpiof: gpio@fff31000 { gpiof: gpio@fff31000 {
...@@ -138,6 +154,8 @@ gpiof: gpio@fff31000 { ...@@ -138,6 +154,8 @@ gpiof: gpio@fff31000 {
gpio-controller; gpio-controller;
reg = <0xfff31000 0x1000>; reg = <0xfff31000 0x1000>;
interrupts = <0 15 4>; interrupts = <0 15 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
gpiog: gpio@fff32000 { gpiog: gpio@fff32000 {
...@@ -146,6 +164,8 @@ gpiog: gpio@fff32000 { ...@@ -146,6 +164,8 @@ gpiog: gpio@fff32000 {
gpio-controller; gpio-controller;
reg = <0xfff32000 0x1000>; reg = <0xfff32000 0x1000>;
interrupts = <0 16 4>; interrupts = <0 16 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
gpioh: gpio@fff33000 { gpioh: gpio@fff33000 {
...@@ -154,24 +174,32 @@ gpioh: gpio@fff33000 { ...@@ -154,24 +174,32 @@ gpioh: gpio@fff33000 {
gpio-controller; gpio-controller;
reg = <0xfff33000 0x1000>; reg = <0xfff33000 0x1000>;
interrupts = <0 17 4>; interrupts = <0 17 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
timer { timer {
compatible = "arm,sp804", "arm,primecell"; compatible = "arm,sp804", "arm,primecell";
reg = <0xfff34000 0x1000>; reg = <0xfff34000 0x1000>;
interrupts = <0 18 4>; interrupts = <0 18 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
rtc@fff35000 { rtc@fff35000 {
compatible = "arm,pl031", "arm,primecell"; compatible = "arm,pl031", "arm,primecell";
reg = <0xfff35000 0x1000>; reg = <0xfff35000 0x1000>;
interrupts = <0 19 4>; interrupts = <0 19 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
serial@fff36000 { serial@fff36000 {
compatible = "arm,pl011", "arm,primecell"; compatible = "arm,pl011", "arm,primecell";
reg = <0xfff36000 0x1000>; reg = <0xfff36000 0x1000>;
interrupts = <0 20 4>; interrupts = <0 20 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
smic@fff3a000 { smic@fff3a000 {
...@@ -186,12 +214,73 @@ smic@fff3a000 { ...@@ -186,12 +214,73 @@ smic@fff3a000 {
sregs@fff3c000 { sregs@fff3c000 {
compatible = "calxeda,hb-sregs"; compatible = "calxeda,hb-sregs";
reg = <0xfff3c000 0x1000>; reg = <0xfff3c000 0x1000>;
clocks {
#address-cells = <1>;
#size-cells = <0>;
osc: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <33333000>;
};
ddrpll: ddrpll {
#clock-cells = <0>;
compatible = "calxeda,hb-pll-clock";
clocks = <&osc>;
reg = <0x108>;
};
a9pll: a9pll {
#clock-cells = <0>;
compatible = "calxeda,hb-pll-clock";
clocks = <&osc>;
reg = <0x100>;
};
a9periphclk: a9periphclk {
#clock-cells = <0>;
compatible = "calxeda,hb-a9periph-clock";
clocks = <&a9pll>;
reg = <0x104>;
};
a9bclk: a9bclk {
#clock-cells = <0>;
compatible = "calxeda,hb-a9bus-clock";
clocks = <&a9pll>;
reg = <0x104>;
};
emmcpll: emmcpll {
#clock-cells = <0>;
compatible = "calxeda,hb-pll-clock";
clocks = <&osc>;
reg = <0x10C>;
};
eclk: eclk {
#clock-cells = <0>;
compatible = "calxeda,hb-emmc-clock";
clocks = <&emmcpll>;
reg = <0x114>;
};
pclk: pclk {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <150000000>;
};
};
}; };
dma@fff3d000 { dma@fff3d000 {
compatible = "arm,pl330", "arm,primecell"; compatible = "arm,pl330", "arm,primecell";
reg = <0xfff3d000 0x1000>; reg = <0xfff3d000 0x1000>;
interrupts = <0 92 4>; interrupts = <0 92 4>;
clocks = <&pclk>;
clock-names = "apb_pclk";
}; };
ethernet@fff50000 { ethernet@fff50000 {
......
obj-y := clock.o highbank.o system.o smc.o obj-y := highbank.o system.o smc.o
plus_sec := $(call as-instr,.arch_extension sec,+sec) plus_sec := $(call as-instr,.arch_extension sec,+sec)
AFLAGS_smc.o :=-Wa,-march=armv7-a$(plus_sec) AFLAGS_smc.o :=-Wa,-march=armv7-a$(plus_sec)
......
/*
* Copyright 2011 Calxeda, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
struct clk {
unsigned long rate;
};
int clk_enable(struct clk *clk)
{
return 0;
}
void clk_disable(struct clk *clk)
{}
unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
long clk_round_rate(struct clk *clk, unsigned long rate)
{
return clk->rate;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
return 0;
}
static struct clk eclk = { .rate = 200000000 };
static struct clk pclk = { .rate = 150000000 };
static struct clk_lookup lookups[] = {
{ .clk = &pclk, .con_id = "apb_pclk", },
{ .clk = &pclk, .dev_id = "sp804", },
{ .clk = &eclk, .dev_id = "ffe0e000.sdhci", },
{ .clk = &pclk, .dev_id = "fff36000.serial", },
};
void __init highbank_clocks_init(void)
{
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
}
...@@ -105,6 +105,11 @@ static void __init highbank_init_irq(void) ...@@ -105,6 +105,11 @@ static void __init highbank_init_irq(void)
#endif #endif
} }
static struct clk_lookup lookup = {
.dev_id = "sp804",
.con_id = NULL,
};
static void __init highbank_timer_init(void) static void __init highbank_timer_init(void)
{ {
int irq; int irq;
...@@ -122,6 +127,8 @@ static void __init highbank_timer_init(void) ...@@ -122,6 +127,8 @@ static void __init highbank_timer_init(void)
irq = irq_of_parse_and_map(np, 0); irq = irq_of_parse_and_map(np, 0);
highbank_clocks_init(); highbank_clocks_init();
lookup.clk = of_clk_get(np, 0);
clkdev_add(&lookup);
sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
sp804_clockevents_init(timer_base, irq, "timer0"); sp804_clockevents_init(timer_base, irq, "timer0");
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/serial.h> #include <linux/amba/serial.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clkdev.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/platform.h> #include <mach/platform.h>
...@@ -41,17 +40,17 @@ static struct amba_pl010_data integrator_uart_data; ...@@ -41,17 +40,17 @@ static struct amba_pl010_data integrator_uart_data;
#define KMI0_IRQ { IRQ_KMIINT0 } #define KMI0_IRQ { IRQ_KMIINT0 }
#define KMI1_IRQ { IRQ_KMIINT1 } #define KMI1_IRQ { IRQ_KMIINT1 }
static AMBA_APB_DEVICE(rtc, "mb:15", 0, static AMBA_APB_DEVICE(rtc, "rtc", 0,
INTEGRATOR_RTC_BASE, INTEGRATOR_RTC_IRQ, NULL); INTEGRATOR_RTC_BASE, INTEGRATOR_RTC_IRQ, NULL);
static AMBA_APB_DEVICE(uart0, "mb:16", 0, static AMBA_APB_DEVICE(uart0, "uart0", 0,
INTEGRATOR_UART0_BASE, INTEGRATOR_UART0_IRQ, &integrator_uart_data); INTEGRATOR_UART0_BASE, INTEGRATOR_UART0_IRQ, &integrator_uart_data);
static AMBA_APB_DEVICE(uart1, "mb:17", 0, static AMBA_APB_DEVICE(uart1, "uart1", 0,
INTEGRATOR_UART1_BASE, INTEGRATOR_UART1_IRQ, &integrator_uart_data); INTEGRATOR_UART1_BASE, INTEGRATOR_UART1_IRQ, &integrator_uart_data);
static AMBA_APB_DEVICE(kmi0, "mb:18", 0, KMI0_BASE, KMI0_IRQ, NULL); static AMBA_APB_DEVICE(kmi0, "kmi0", 0, KMI0_BASE, KMI0_IRQ, NULL);
static AMBA_APB_DEVICE(kmi1, "mb:19", 0, KMI1_BASE, KMI1_IRQ, NULL); static AMBA_APB_DEVICE(kmi1, "kmi1", 0, KMI1_BASE, KMI1_IRQ, NULL);
static struct amba_device *amba_devs[] __initdata = { static struct amba_device *amba_devs[] __initdata = {
&rtc_device, &rtc_device,
...@@ -61,50 +60,6 @@ static struct amba_device *amba_devs[] __initdata = { ...@@ -61,50 +60,6 @@ static struct amba_device *amba_devs[] __initdata = {
&kmi1_device, &kmi1_device,
}; };
/*
* These are fixed clocks.
*/
static struct clk clk24mhz = {
.rate = 24000000,
};
static struct clk uartclk = {
.rate = 14745600,
};
static struct clk dummy_apb_pclk;
static struct clk_lookup lookups[] = {
{ /* Bus clock */
.con_id = "apb_pclk",
.clk = &dummy_apb_pclk,
}, {
/* Integrator/AP timer frequency */
.dev_id = "ap_timer",
.clk = &clk24mhz,
}, { /* UART0 */
.dev_id = "mb:16",
.clk = &uartclk,
}, { /* UART1 */
.dev_id = "mb:17",
.clk = &uartclk,
}, { /* KMI0 */
.dev_id = "mb:18",
.clk = &clk24mhz,
}, { /* KMI1 */
.dev_id = "mb:19",
.clk = &clk24mhz,
}, { /* MMCI - IntegratorCP */
.dev_id = "mb:1c",
.clk = &uartclk,
}
};
void __init integrator_init_early(void)
{
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
}
static int __init integrator_init(void) static int __init integrator_init(void)
{ {
int i; int i;
......
#ifndef __ASM_MACH_CLKDEV_H
#define __ASM_MACH_CLKDEV_H
#include <linux/module.h>
#include <plat/clock.h>
struct clk {
unsigned long rate;
const struct clk_ops *ops;
struct module *owner;
const struct icst_params *params;
void __iomem *vcoreg;
void *data;
};
static inline int __clk_get(struct clk *clk)
{
return try_module_get(clk->owner);
}
static inline void __clk_put(struct clk *clk)
{
module_put(clk->owner);
}
#endif
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/platform_data/clk-integrator.h>
#include <video/vga.h> #include <video/vga.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -174,6 +175,7 @@ static void __init ap_init_irq(void) ...@@ -174,6 +175,7 @@ static void __init ap_init_irq(void)
fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START, fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START,
-1, INTEGRATOR_SC_VALID_INT, NULL); -1, INTEGRATOR_SC_VALID_INT, NULL);
integrator_clk_init(false);
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
...@@ -440,6 +442,10 @@ static void integrator_clockevent_init(unsigned long inrate) ...@@ -440,6 +442,10 @@ static void integrator_clockevent_init(unsigned long inrate)
0xffffU); 0xffffU);
} }
void __init ap_init_early(void)
{
}
/* /*
* Set up timer(s). * Set up timer(s).
*/ */
...@@ -471,7 +477,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator") ...@@ -471,7 +477,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator")
.reserve = integrator_reserve, .reserve = integrator_reserve,
.map_io = ap_map_io, .map_io = ap_map_io,
.nr_irqs = NR_IRQS_INTEGRATOR_AP, .nr_irqs = NR_IRQS_INTEGRATOR_AP,
.init_early = integrator_init_early, .init_early = ap_init_early,
.init_irq = ap_init_irq, .init_irq = ap_init_irq,
.handle_irq = fpga_handle_irq, .handle_irq = fpga_handle_irq,
.timer = &ap_timer, .timer = &ap_timer,
......
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
#include <linux/amba/mmci.h> #include <linux/amba/mmci.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/gfp.h> #include <linux/gfp.h>
#include <linux/clkdev.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/platform_data/clk-integrator.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/platform.h> #include <mach/platform.h>
...@@ -171,64 +171,9 @@ static void __init intcp_init_irq(void) ...@@ -171,64 +171,9 @@ static void __init intcp_init_irq(void)
fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START, fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START,
IRQ_CP_CPPLDINT, sic_mask, NULL); IRQ_CP_CPPLDINT, sic_mask, NULL);
integrator_clk_init(true);
} }
/*
* Clock handling
*/
#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c)
static const struct icst_params cp_auxvco_params = {
.ref = 24000000,
.vco_max = ICST525_VCO_MAX_5V,
.vco_min = ICST525_VCO_MIN,
.vd_min = 8,
.vd_max = 263,
.rd_min = 3,
.rd_max = 65,
.s2div = icst525_s2div,
.idx2s = icst525_idx2s,
};
static void cp_auxvco_set(struct clk *clk, struct icst_vco vco)
{
u32 val;
val = readl(clk->vcoreg) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
writel(0xa05f, CM_LOCK);
writel(val, clk->vcoreg);
writel(0, CM_LOCK);
}
static const struct clk_ops cp_auxclk_ops = {
.round = icst_clk_round,
.set = icst_clk_set,
.setvco = cp_auxvco_set,
};
static struct clk cp_auxclk = {
.ops = &cp_auxclk_ops,
.params = &cp_auxvco_params,
.vcoreg = CM_AUXOSC,
};
static struct clk sp804_clk = {
.rate = 1000000,
};
static struct clk_lookup cp_lookups[] = {
{ /* CLCD */
.dev_id = "mb:c0",
.clk = &cp_auxclk,
}, { /* SP804 timers */
.dev_id = "sp804",
.clk = &sp804_clk,
},
};
/* /*
* Flash handling. * Flash handling.
*/ */
...@@ -336,10 +281,10 @@ static struct mmci_platform_data mmc_data = { ...@@ -336,10 +281,10 @@ static struct mmci_platform_data mmc_data = {
#define INTEGRATOR_CP_MMC_IRQS { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 } #define INTEGRATOR_CP_MMC_IRQS { IRQ_CP_MMCIINT0, IRQ_CP_MMCIINT1 }
#define INTEGRATOR_CP_AACI_IRQS { IRQ_CP_AACIINT } #define INTEGRATOR_CP_AACI_IRQS { IRQ_CP_AACIINT }
static AMBA_APB_DEVICE(mmc, "mb:1c", 0, INTEGRATOR_CP_MMC_BASE, static AMBA_APB_DEVICE(mmc, "mmci", 0, INTEGRATOR_CP_MMC_BASE,
INTEGRATOR_CP_MMC_IRQS, &mmc_data); INTEGRATOR_CP_MMC_IRQS, &mmc_data);
static AMBA_APB_DEVICE(aaci, "mb:1d", 0, INTEGRATOR_CP_AACI_BASE, static AMBA_APB_DEVICE(aaci, "aaci", 0, INTEGRATOR_CP_AACI_BASE,
INTEGRATOR_CP_AACI_IRQS, NULL); INTEGRATOR_CP_AACI_IRQS, NULL);
...@@ -393,7 +338,7 @@ static struct clcd_board clcd_data = { ...@@ -393,7 +338,7 @@ static struct clcd_board clcd_data = {
.remove = versatile_clcd_remove_dma, .remove = versatile_clcd_remove_dma,
}; };
static AMBA_AHB_DEVICE(clcd, "mb:c0", 0, INTCP_PA_CLCD_BASE, static AMBA_AHB_DEVICE(clcd, "clcd", 0, INTCP_PA_CLCD_BASE,
{ IRQ_CP_CLCDCINT }, &clcd_data); { IRQ_CP_CLCDCINT }, &clcd_data);
static struct amba_device *amba_devs[] __initdata = { static struct amba_device *amba_devs[] __initdata = {
...@@ -406,10 +351,6 @@ static struct amba_device *amba_devs[] __initdata = { ...@@ -406,10 +351,6 @@ static struct amba_device *amba_devs[] __initdata = {
static void __init intcp_init_early(void) static void __init intcp_init_early(void)
{ {
clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups));
integrator_init_early();
#ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK #ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK
versatile_sched_clock_init(REFCOUNTER, 24000000); versatile_sched_clock_init(REFCOUNTER, 24000000);
#endif #endif
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for the linux kernel, U300 machine. # Makefile for the linux kernel, U300 machine.
# #
obj-y := core.o clock.o timer.o obj-y := core.o timer.o
obj-m := obj-m :=
obj-n := obj-n :=
obj- := obj- :=
......
/*
*
* arch/arm/mach-u300/clock.c
*
*
* Copyright (C) 2007-2009 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Define clocks in the app platform.
* Author: Linus Walleij <linus.walleij@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/io.h>
#include <linux/seq_file.h>
#include <linux/clkdev.h>
#include <mach/hardware.h>
#include <mach/syscon.h>
#include "clock.h"
/*
* TODO:
* - move all handling of the CCR register into this file and create
* a spinlock for the CCR register
* - switch to the clkdevice lookup mechanism that maps clocks to
* device ID:s instead when it becomes available in kernel 2.6.29.
* - implement rate get/set for all clocks that need it.
*/
/*
* Syscon clock I/O registers lock so clock requests don't collide
* NOTE: this is a local lock only used to lock access to clock and
* reset registers in syscon.
*/
static DEFINE_SPINLOCK(syscon_clkreg_lock);
static DEFINE_SPINLOCK(syscon_resetreg_lock);
/*
* The clocking hierarchy currently looks like this.
* NOTE: the idea is NOT to show how the clocks are routed on the chip!
* The ideas is to show dependencies, so a clock higher up in the
* hierarchy has to be on in order for another clock to be on. Now,
* both CPU and DMA can actually be on top of the hierarchy, and that
* is not modeled currently. Instead we have the backbone AMBA bus on
* top. This bus cannot be programmed in any way but conceptually it
* needs to be active for the bridges and devices to transport data.
*
* Please be aware that a few clocks are hw controlled, which mean that
* the hw itself can turn on/off or change the rate of the clock when
* needed!
*
* AMBA bus
* |
* +- CPU
* +- FSMC NANDIF NAND Flash interface
* +- SEMI Shared Memory interface
* +- ISP Image Signal Processor (U335 only)
* +- CDS (U335 only)
* +- DMA Direct Memory Access Controller
* +- AAIF APP/ACC Inteface (Mobile Scalable Link, MSL)
* +- APEX
* +- VIDEO_ENC AVE2/3 Video Encoder
* +- XGAM Graphics Accelerator Controller
* +- AHB
* |
* +- ahb:0 AHB Bridge
* | |
* | +- ahb:1 INTCON Interrupt controller
* | +- ahb:3 MSPRO Memory Stick Pro controller
* | +- ahb:4 EMIF External Memory interface
* |
* +- fast:0 FAST bridge
* | |
* | +- fast:1 MMCSD MMC/SD card reader controller
* | +- fast:2 I2S0 PCM I2S channel 0 controller
* | +- fast:3 I2S1 PCM I2S channel 1 controller
* | +- fast:4 I2C0 I2C channel 0 controller
* | +- fast:5 I2C1 I2C channel 1 controller
* | +- fast:6 SPI SPI controller
* | +- fast:7 UART1 Secondary UART (U335 only)
* |
* +- slow:0 SLOW bridge
* |
* +- slow:1 SYSCON (not possible to control)
* +- slow:2 WDOG Watchdog
* +- slow:3 UART0 primary UART
* +- slow:4 TIMER_APP Application timer - used in Linux
* +- slow:5 KEYPAD controller
* +- slow:6 GPIO controller
* +- slow:7 RTC controller
* +- slow:8 BT Bus Tracer (not used currently)
* +- slow:9 EH Event Handler (not used currently)
* +- slow:a TIMER_ACC Access style timer (not used currently)
* +- slow:b PPM (U335 only, what is that?)
*/
/*
* Reset control functions. We remember if a block has been
* taken out of reset and don't remove the reset assertion again
* and vice versa. Currently we only remove resets so the
* enablement function is defined out.
*/
static void syscon_block_reset_enable(struct clk *clk)
{
u16 val;
unsigned long iflags;
/* Not all blocks support resetting */
if (!clk->res_reg || !clk->res_mask)
return;
spin_lock_irqsave(&syscon_resetreg_lock, iflags);
val = readw(clk->res_reg);
val |= clk->res_mask;
writew(val, clk->res_reg);
spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
clk->reset = true;
}
static void syscon_block_reset_disable(struct clk *clk)
{
u16 val;
unsigned long iflags;
/* Not all blocks support resetting */
if (!clk->res_reg || !clk->res_mask)
return;
spin_lock_irqsave(&syscon_resetreg_lock, iflags);
val = readw(clk->res_reg);
val &= ~clk->res_mask;
writew(val, clk->res_reg);
spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
clk->reset = false;
}
int __clk_get(struct clk *clk)
{
u16 val;
/* The MMC and MSPRO clocks need some special set-up */
if (!strcmp(clk->name, "MCLK")) {
/* Set default MMC clock divisor to 18.9 MHz */
writew(0x0054U, U300_SYSCON_VBASE + U300_SYSCON_MMF0R);
val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMCR);
/* Disable the MMC feedback clock */
val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
/* Disable MSPRO frequency */
val &= ~U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_MMCR);
}
if (!strcmp(clk->name, "MSPRO")) {
val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMCR);
/* Disable the MMC feedback clock */
val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
/* Enable MSPRO frequency */
val |= U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_MMCR);
}
return 1;
}
EXPORT_SYMBOL(__clk_get);
void __clk_put(struct clk *clk)
{
}
EXPORT_SYMBOL(__clk_put);
static void syscon_clk_disable(struct clk *clk)
{
unsigned long iflags;
/* Don't touch the hardware controlled clocks */
if (clk->hw_ctrld)
return;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
writew(clk->clk_val, U300_SYSCON_VBASE + U300_SYSCON_SBCDR);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
static void syscon_clk_enable(struct clk *clk)
{
unsigned long iflags;
/* Don't touch the hardware controlled clocks */
if (clk->hw_ctrld)
return;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
writew(clk->clk_val, U300_SYSCON_VBASE + U300_SYSCON_SBCER);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
static u16 syscon_clk_get_rate(void)
{
u16 val;
unsigned long iflags;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val &= U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
return val;
}
#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
static void enable_i2s0_vcxo(void)
{
u16 val;
unsigned long iflags;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
/* Set I2S0 to use the VCXO 26 MHz clock */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val |= U300_SYSCON_CCR_TURN_VCXO_ON;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
val |= U300_SYSCON_CCR_I2S0_USE_VCXO;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
val |= U300_SYSCON_CEFR_I2S0_CLK_EN;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
static void enable_i2s1_vcxo(void)
{
u16 val;
unsigned long iflags;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
/* Set I2S1 to use the VCXO 26 MHz clock */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val |= U300_SYSCON_CCR_TURN_VCXO_ON;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
val |= U300_SYSCON_CCR_I2S1_USE_VCXO;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
val |= U300_SYSCON_CEFR_I2S1_CLK_EN;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
static void disable_i2s0_vcxo(void)
{
u16 val;
unsigned long iflags;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
/* Disable I2S0 use of the VCXO 26 MHz clock */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val &= ~U300_SYSCON_CCR_I2S0_USE_VCXO;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
/* Deactivate VCXO if no one else is using VCXO */
if (!(val & U300_SYSCON_CCR_I2S1_USE_VCXO))
val &= ~U300_SYSCON_CCR_TURN_VCXO_ON;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
val &= ~U300_SYSCON_CEFR_I2S0_CLK_EN;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
static void disable_i2s1_vcxo(void)
{
u16 val;
unsigned long iflags;
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
/* Disable I2S1 use of the VCXO 26 MHz clock */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val &= ~U300_SYSCON_CCR_I2S1_USE_VCXO;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
/* Deactivate VCXO if no one else is using VCXO */
if (!(val & U300_SYSCON_CCR_I2S0_USE_VCXO))
val &= ~U300_SYSCON_CCR_TURN_VCXO_ON;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CEFR);
val &= ~U300_SYSCON_CEFR_I2S0_CLK_EN;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CEFR);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
#endif /* CONFIG_MACH_U300_USE_I2S_AS_MASTER */
static void syscon_clk_rate_set_mclk(unsigned long rate)
{
u16 val;
u32 reg;
unsigned long iflags;
switch (rate) {
case 18900000:
val = 0x0054;
break;
case 20800000:
val = 0x0044;
break;
case 23100000:
val = 0x0043;
break;
case 26000000:
val = 0x0033;
break;
case 29700000:
val = 0x0032;
break;
case 34700000:
val = 0x0022;
break;
case 41600000:
val = 0x0021;
break;
case 52000000:
val = 0x0011;
break;
case 104000000:
val = 0x0000;
break;
default:
printk(KERN_ERR "Trying to set MCLK to unknown speed! %ld\n",
rate);
return;
}
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
reg = readw(U300_SYSCON_VBASE + U300_SYSCON_MMF0R) &
~U300_SYSCON_MMF0R_MASK;
writew(reg | val, U300_SYSCON_VBASE + U300_SYSCON_MMF0R);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
void syscon_clk_rate_set_cpuclk(unsigned long rate)
{
u16 val;
unsigned long iflags;
switch (rate) {
case 13000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER;
break;
case 52000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE;
break;
case 104000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH;
break;
case 208000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST;
break;
default:
return;
}
spin_lock_irqsave(&syscon_clkreg_lock, iflags);
val |= readw(U300_SYSCON_VBASE + U300_SYSCON_CCR) &
~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
spin_unlock_irqrestore(&syscon_clkreg_lock, iflags);
}
EXPORT_SYMBOL(syscon_clk_rate_set_cpuclk);
void clk_disable(struct clk *clk)
{
unsigned long iflags;
spin_lock_irqsave(&clk->lock, iflags);
if (clk->usecount > 0 && !(--clk->usecount)) {
/* some blocks lack clocking registers and cannot be disabled */
if (clk->disable)
clk->disable(clk);
if (likely((u32)clk->parent))
clk_disable(clk->parent);
}
#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
if (unlikely(!strcmp(clk->name, "I2S0")))
disable_i2s0_vcxo();
if (unlikely(!strcmp(clk->name, "I2S1")))
disable_i2s1_vcxo();
#endif
spin_unlock_irqrestore(&clk->lock, iflags);
}
EXPORT_SYMBOL(clk_disable);
int clk_enable(struct clk *clk)
{
int ret = 0;
unsigned long iflags;
spin_lock_irqsave(&clk->lock, iflags);
if (clk->usecount++ == 0) {
if (likely((u32)clk->parent))
ret = clk_enable(clk->parent);
if (unlikely(ret != 0))
clk->usecount--;
else {
/* remove reset line (we never enable reset again) */
syscon_block_reset_disable(clk);
/* clocks without enable function are always on */
if (clk->enable)
clk->enable(clk);
#ifdef CONFIG_MACH_U300_USE_I2S_AS_MASTER
if (unlikely(!strcmp(clk->name, "I2S0")))
enable_i2s0_vcxo();
if (unlikely(!strcmp(clk->name, "I2S1")))
enable_i2s1_vcxo();
#endif
}
}
spin_unlock_irqrestore(&clk->lock, iflags);
return ret;
}
EXPORT_SYMBOL(clk_enable);
/* Returns the clock rate in Hz */
static unsigned long clk_get_rate_cpuclk(struct clk *clk)
{
u16 val;
val = syscon_clk_get_rate();
switch (val) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 52000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
return 104000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
return 208000000;
default:
break;
}
return clk->rate;
}
static unsigned long clk_get_rate_ahb_clk(struct clk *clk)
{
u16 val;
val = syscon_clk_get_rate();
switch (val) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 6500000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 26000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
return 52000000;
default:
break;
}
return clk->rate;
}
static unsigned long clk_get_rate_emif_clk(struct clk *clk)
{
u16 val;
val = syscon_clk_get_rate();
switch (val) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 52000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
return 104000000;
default:
break;
}
return clk->rate;
}
static unsigned long clk_get_rate_xgamclk(struct clk *clk)
{
u16 val;
val = syscon_clk_get_rate();
switch (val) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 6500000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 26000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
return 52000000;
default:
break;
}
return clk->rate;
}
static unsigned long clk_get_rate_mclk(struct clk *clk)
{
u16 val;
val = syscon_clk_get_rate();
switch (val) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
/*
* Here, the 208 MHz PLL gets shut down and the always
* on 13 MHz PLL used for RTC etc kicks into use
* instead.
*/
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
{
/*
* This clock is under program control. The register is
* divided in two nybbles, bit 7-4 gives cycles-1 to count
* high, bit 3-0 gives cycles-1 to count low. Distribute
* these with no more than 1 cycle difference between
* low and high and add low and high to get the actual
* divisor. The base PLL is 208 MHz. Writing 0x00 will
* divide by 1 and 1 so the highest frequency possible
* is 104 MHz.
*
* e.g. 0x54 =>
* f = 208 / ((5+1) + (4+1)) = 208 / 11 = 18.9 MHz
*/
u16 val = readw(U300_SYSCON_VBASE + U300_SYSCON_MMF0R) &
U300_SYSCON_MMF0R_MASK;
switch (val) {
case 0x0054:
return 18900000;
case 0x0044:
return 20800000;
case 0x0043:
return 23100000;
case 0x0033:
return 26000000;
case 0x0032:
return 29700000;
case 0x0022:
return 34700000;
case 0x0021:
return 41600000;
case 0x0011:
return 52000000;
case 0x0000:
return 104000000;
default:
break;
}
}
default:
break;
}
return clk->rate;
}
static unsigned long clk_get_rate_i2s_i2c_spi(struct clk *clk)
{
u16 val;
val = syscon_clk_get_rate();
switch (val) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
return 26000000;
default:
break;
}
return clk->rate;
}
unsigned long clk_get_rate(struct clk *clk)
{
if (clk->get_rate)
return clk->get_rate(clk);
else
return clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);
static unsigned long clk_round_rate_mclk(struct clk *clk, unsigned long rate)
{
if (rate <= 18900000)
return 18900000;
if (rate <= 20800000)
return 20800000;
if (rate <= 23100000)
return 23100000;
if (rate <= 26000000)
return 26000000;
if (rate <= 29700000)
return 29700000;
if (rate <= 34700000)
return 34700000;
if (rate <= 41600000)
return 41600000;
if (rate <= 52000000)
return 52000000;
return -EINVAL;
}
static unsigned long clk_round_rate_cpuclk(struct clk *clk, unsigned long rate)
{
if (rate <= 13000000)
return 13000000;
if (rate <= 52000000)
return 52000000;
if (rate <= 104000000)
return 104000000;
if (rate <= 208000000)
return 208000000;
return -EINVAL;
}
/*
* This adjusts a requested rate to the closest exact rate
* a certain clock can provide. For a fixed clock it's
* mostly clk->rate.
*/
long clk_round_rate(struct clk *clk, unsigned long rate)
{
/* TODO: get appropriate switches for EMIFCLK, AHBCLK and MCLK */
/* Else default to fixed value */
if (clk->round_rate) {
return (long) clk->round_rate(clk, rate);
} else {
printk(KERN_ERR "clock: Failed to round rate of %s\n",
clk->name);
}
return (long) clk->rate;
}
EXPORT_SYMBOL(clk_round_rate);
static int clk_set_rate_mclk(struct clk *clk, unsigned long rate)
{
syscon_clk_rate_set_mclk(clk_round_rate(clk, rate));
return 0;
}
static int clk_set_rate_cpuclk(struct clk *clk, unsigned long rate)
{
syscon_clk_rate_set_cpuclk(clk_round_rate(clk, rate));
return 0;
}
int clk_set_rate(struct clk *clk, unsigned long rate)
{
/* TODO: set for EMIFCLK and AHBCLK */
/* Else assume the clock is fixed and fail */
if (clk->set_rate) {
return clk->set_rate(clk, rate);
} else {
printk(KERN_ERR "clock: Failed to set %s to %ld hz\n",
clk->name, rate);
return -EINVAL;
}
}
EXPORT_SYMBOL(clk_set_rate);
/*
* Clock definitions. The clock parents are set to respective
* bridge and the clock framework makes sure that the clocks have
* parents activated and are brought out of reset when in use.
*
* Clocks that have hw_ctrld = true are hw controlled, and the hw
* can by itself turn these clocks on and off.
* So in other words, we don't really have to care about them.
*/
static struct clk amba_clk = {
.name = "AMBA",
.rate = 52000000, /* this varies! */
.hw_ctrld = true,
.reset = false,
.lock = __SPIN_LOCK_UNLOCKED(amba_clk.lock),
};
/*
* These blocks are connected directly to the AMBA bus
* with no bridge.
*/
static struct clk cpu_clk = {
.name = "CPU",
.parent = &amba_clk,
.rate = 208000000, /* this varies! */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_CPU_RESET_EN,
.set_rate = clk_set_rate_cpuclk,
.get_rate = clk_get_rate_cpuclk,
.round_rate = clk_round_rate_cpuclk,
.lock = __SPIN_LOCK_UNLOCKED(cpu_clk.lock),
};
static struct clk nandif_clk = {
.name = "FSMC",
.parent = &amba_clk,
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_NANDIF_RESET_EN,
.clk_val = U300_SYSCON_SBCER_NANDIF_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(nandif_clk.lock),
};
static struct clk semi_clk = {
.name = "SEMI",
.parent = &amba_clk,
.rate = 0, /* FIXME */
/* It is not possible to reset SEMI */
.hw_ctrld = false,
.reset = false,
.clk_val = U300_SYSCON_SBCER_SEMI_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(semi_clk.lock),
};
#ifdef CONFIG_MACH_U300_BS335
static struct clk isp_clk = {
.name = "ISP",
.parent = &amba_clk,
.rate = 0, /* FIXME */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_ISP_RESET_EN,
.clk_val = U300_SYSCON_SBCER_ISP_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(isp_clk.lock),
};
static struct clk cds_clk = {
.name = "CDS",
.parent = &amba_clk,
.rate = 0, /* FIXME */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_CDS_RESET_EN,
.clk_val = U300_SYSCON_SBCER_CDS_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(cds_clk.lock),
};
#endif
static struct clk dma_clk = {
.name = "DMA",
.parent = &amba_clk,
.rate = 52000000, /* this varies! */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_DMAC_RESET_EN,
.clk_val = U300_SYSCON_SBCER_DMAC_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(dma_clk.lock),
};
static struct clk aaif_clk = {
.name = "AAIF",
.parent = &amba_clk,
.rate = 52000000, /* this varies! */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_AAIF_RESET_EN,
.clk_val = U300_SYSCON_SBCER_AAIF_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(aaif_clk.lock),
};
static struct clk apex_clk = {
.name = "APEX",
.parent = &amba_clk,
.rate = 0, /* FIXME */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_APEX_RESET_EN,
.clk_val = U300_SYSCON_SBCER_APEX_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(apex_clk.lock),
};
static struct clk video_enc_clk = {
.name = "VIDEO_ENC",
.parent = &amba_clk,
.rate = 208000000, /* this varies! */
.hw_ctrld = false,
.reset = false,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
/* This has XGAM in the name but refers to the video encoder */
.res_mask = U300_SYSCON_RRR_XGAM_VC_SYNC_RESET_EN,
.clk_val = U300_SYSCON_SBCER_VIDEO_ENC_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(video_enc_clk.lock),
};
static struct clk xgam_clk = {
.name = "XGAMCLK",
.parent = &amba_clk,
.rate = 52000000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_XGAM_RESET_EN,
.clk_val = U300_SYSCON_SBCER_XGAM_CLK_EN,
.get_rate = clk_get_rate_xgamclk,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(xgam_clk.lock),
};
/* This clock is used to activate the video encoder */
static struct clk ahb_clk = {
.name = "AHB",
.parent = &amba_clk,
.rate = 52000000, /* this varies! */
.hw_ctrld = false, /* This one is set to false due to HW bug */
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_AHB_RESET_EN,
.clk_val = U300_SYSCON_SBCER_AHB_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_ahb_clk,
.lock = __SPIN_LOCK_UNLOCKED(ahb_clk.lock),
};
/*
* Clocks on the AHB bridge
*/
static struct clk ahb_subsys_clk = {
.name = "AHB_SUBSYS",
.parent = &amba_clk,
.rate = 52000000, /* this varies! */
.hw_ctrld = true,
.reset = false,
.clk_val = U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_ahb_clk,
.lock = __SPIN_LOCK_UNLOCKED(ahb_subsys_clk.lock),
};
static struct clk intcon_clk = {
.name = "INTCON",
.parent = &ahb_subsys_clk,
.rate = 52000000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_INTCON_RESET_EN,
/* INTCON can be reset but not clock-gated */
.lock = __SPIN_LOCK_UNLOCKED(intcon_clk.lock),
};
static struct clk mspro_clk = {
.name = "MSPRO",
.parent = &ahb_subsys_clk,
.rate = 0, /* FIXME */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_MSPRO_RESET_EN,
.clk_val = U300_SYSCON_SBCER_MSPRO_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(mspro_clk.lock),
};
static struct clk emif_clk = {
.name = "EMIF",
.parent = &ahb_subsys_clk,
.rate = 104000000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RRR,
.res_mask = U300_SYSCON_RRR_EMIF_RESET_EN,
.clk_val = U300_SYSCON_SBCER_EMIF_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_emif_clk,
.lock = __SPIN_LOCK_UNLOCKED(emif_clk.lock),
};
/*
* Clocks on the FAST bridge
*/
static struct clk fast_clk = {
.name = "FAST_BRIDGE",
.parent = &amba_clk,
.rate = 13000000, /* this varies! */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(fast_clk.lock),
};
/*
* The MMCI apb_pclk is hardwired to the same terminal as the
* external MCI clock. Thus this will be referenced twice.
*/
static struct clk mmcsd_clk = {
.name = "MCLK",
.parent = &fast_clk,
.rate = 18900000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_MMC_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_MMC_CLK_EN,
.get_rate = clk_get_rate_mclk,
.set_rate = clk_set_rate_mclk,
.round_rate = clk_round_rate_mclk,
.disable = syscon_clk_disable,
.enable = syscon_clk_enable,
.lock = __SPIN_LOCK_UNLOCKED(mmcsd_clk.lock),
};
static struct clk i2s0_clk = {
.name = "i2s0",
.parent = &fast_clk,
.rate = 26000000, /* this varies! */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_PCM_I2S0_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_I2S0_CORE_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_i2s_i2c_spi,
.lock = __SPIN_LOCK_UNLOCKED(i2s0_clk.lock),
};
static struct clk i2s1_clk = {
.name = "i2s1",
.parent = &fast_clk,
.rate = 26000000, /* this varies! */
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_I2S1_CORE_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_i2s_i2c_spi,
.lock = __SPIN_LOCK_UNLOCKED(i2s1_clk.lock),
};
static struct clk i2c0_clk = {
.name = "I2C0",
.parent = &fast_clk,
.rate = 26000000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_I2C0_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_I2C0_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_i2s_i2c_spi,
.lock = __SPIN_LOCK_UNLOCKED(i2c0_clk.lock),
};
static struct clk i2c1_clk = {
.name = "I2C1",
.parent = &fast_clk,
.rate = 26000000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_I2C1_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_I2C1_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_i2s_i2c_spi,
.lock = __SPIN_LOCK_UNLOCKED(i2c1_clk.lock),
};
/*
* The SPI apb_pclk is hardwired to the same terminal as the
* external SPI clock. Thus this will be referenced twice.
*/
static struct clk spi_clk = {
.name = "SPI",
.parent = &fast_clk,
.rate = 26000000, /* this varies! */
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_SPI_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_SPI_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.get_rate = clk_get_rate_i2s_i2c_spi,
.lock = __SPIN_LOCK_UNLOCKED(spi_clk.lock),
};
#ifdef CONFIG_MACH_U300_BS335
static struct clk uart1_pclk = {
.name = "UART1_PCLK",
.parent = &fast_clk,
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RFR,
.res_mask = U300_SYSCON_RFR_UART1_RESET_ENABLE,
.clk_val = U300_SYSCON_SBCER_UART1_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(uart1_pclk.lock),
};
/* This one is hardwired to PLL13 */
static struct clk uart1_clk = {
.name = "UART1_CLK",
.rate = 13000000,
.hw_ctrld = true,
.lock = __SPIN_LOCK_UNLOCKED(uart1_clk.lock),
};
#endif
/*
* Clocks on the SLOW bridge
*/
static struct clk slow_clk = {
.name = "SLOW_BRIDGE",
.parent = &amba_clk,
.rate = 13000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN,
.clk_val = U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(slow_clk.lock),
};
/* TODO: implement SYSCON clock? */
static struct clk wdog_clk = {
.name = "WDOG",
.parent = &slow_clk,
.hw_ctrld = false,
.rate = 32768,
.reset = false,
/* This is always on, cannot be enabled/disabled or reset */
.lock = __SPIN_LOCK_UNLOCKED(wdog_clk.lock),
};
static struct clk uart0_pclk = {
.name = "UART0_PCLK",
.parent = &slow_clk,
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_UART_RESET_EN,
.clk_val = U300_SYSCON_SBCER_UART_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(uart0_pclk.lock),
};
/* This one is hardwired to PLL13 */
static struct clk uart0_clk = {
.name = "UART0_CLK",
.parent = &slow_clk,
.rate = 13000000,
.hw_ctrld = true,
.lock = __SPIN_LOCK_UNLOCKED(uart0_clk.lock),
};
static struct clk keypad_clk = {
.name = "KEYPAD",
.parent = &slow_clk,
.rate = 32768,
.hw_ctrld = false,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_KEYPAD_RESET_EN,
.clk_val = U300_SYSCON_SBCER_KEYPAD_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(keypad_clk.lock),
};
static struct clk gpio_clk = {
.name = "GPIO",
.parent = &slow_clk,
.rate = 13000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_GPIO_RESET_EN,
.clk_val = U300_SYSCON_SBCER_GPIO_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(gpio_clk.lock),
};
static struct clk rtc_clk = {
.name = "RTC",
.parent = &slow_clk,
.rate = 32768,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_RTC_RESET_EN,
/* This clock is always on, cannot be enabled/disabled */
.lock = __SPIN_LOCK_UNLOCKED(rtc_clk.lock),
};
static struct clk bustr_clk = {
.name = "BUSTR",
.parent = &slow_clk,
.rate = 13000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_BTR_RESET_EN,
.clk_val = U300_SYSCON_SBCER_BTR_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(bustr_clk.lock),
};
static struct clk evhist_clk = {
.name = "EVHIST",
.parent = &slow_clk,
.rate = 13000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_EH_RESET_EN,
.clk_val = U300_SYSCON_SBCER_EH_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(evhist_clk.lock),
};
static struct clk timer_clk = {
.name = "TIMER",
.parent = &slow_clk,
.rate = 13000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_ACC_TMR_RESET_EN,
.clk_val = U300_SYSCON_SBCER_ACC_TMR_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(timer_clk.lock),
};
/*
* There is a binary divider in the hardware that divides
* the 13MHz PLL by 13 down to 1 MHz.
*/
static struct clk app_timer_clk = {
.name = "TIMER_APP",
.parent = &slow_clk,
.rate = 1000000,
.hw_ctrld = true,
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_APP_TMR_RESET_EN,
.clk_val = U300_SYSCON_SBCER_APP_TMR_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(app_timer_clk.lock),
};
#ifdef CONFIG_MACH_U300_BS335
static struct clk ppm_clk = {
.name = "PPM",
.parent = &slow_clk,
.rate = 0, /* FIXME */
.hw_ctrld = true, /* TODO: Look up if it is hw ctrld or not */
.reset = true,
.res_reg = U300_SYSCON_VBASE + U300_SYSCON_RSR,
.res_mask = U300_SYSCON_RSR_PPM_RESET_EN,
.clk_val = U300_SYSCON_SBCER_PPM_CLK_EN,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.lock = __SPIN_LOCK_UNLOCKED(ppm_clk.lock),
};
#endif
#define DEF_LOOKUP(devid, clkref) \
{ \
.dev_id = devid, \
.clk = clkref, \
}
#define DEF_LOOKUP_CON(devid, conid, clkref) \
{ \
.dev_id = devid, \
.con_id = conid, \
.clk = clkref, \
}
/*
* Here we only define clocks that are meaningful to
* look up through clockdevice.
*/
static struct clk_lookup lookups[] = {
/* Connected directly to the AMBA bus */
DEF_LOOKUP("amba", &amba_clk),
DEF_LOOKUP("cpu", &cpu_clk),
DEF_LOOKUP("fsmc-nand", &nandif_clk),
DEF_LOOKUP("semi", &semi_clk),
#ifdef CONFIG_MACH_U300_BS335
DEF_LOOKUP("isp", &isp_clk),
DEF_LOOKUP("cds", &cds_clk),
#endif
DEF_LOOKUP("dma", &dma_clk),
DEF_LOOKUP("msl", &aaif_clk),
DEF_LOOKUP("apex", &apex_clk),
DEF_LOOKUP("video_enc", &video_enc_clk),
DEF_LOOKUP("xgam", &xgam_clk),
DEF_LOOKUP("ahb", &ahb_clk),
/* AHB bridge clocks */
DEF_LOOKUP("ahb_subsys", &ahb_subsys_clk),
DEF_LOOKUP("intcon", &intcon_clk),
DEF_LOOKUP_CON("intcon", "apb_pclk", &intcon_clk),
DEF_LOOKUP("mspro", &mspro_clk),
DEF_LOOKUP("pl172", &emif_clk),
DEF_LOOKUP_CON("pl172", "apb_pclk", &emif_clk),
/* FAST bridge clocks */
DEF_LOOKUP("fast", &fast_clk),
DEF_LOOKUP("mmci", &mmcsd_clk),
DEF_LOOKUP_CON("mmci", "apb_pclk", &mmcsd_clk),
/*
* The .0 and .1 identifiers on these comes from the platform device
* .id field and are assigned when the platform devices are registered.
*/
DEF_LOOKUP("i2s.0", &i2s0_clk),
DEF_LOOKUP("i2s.1", &i2s1_clk),
DEF_LOOKUP("stu300.0", &i2c0_clk),
DEF_LOOKUP("stu300.1", &i2c1_clk),
DEF_LOOKUP("pl022", &spi_clk),
DEF_LOOKUP_CON("pl022", "apb_pclk", &spi_clk),
#ifdef CONFIG_MACH_U300_BS335
DEF_LOOKUP("uart1", &uart1_clk),
DEF_LOOKUP_CON("uart1", "apb_pclk", &uart1_pclk),
#endif
/* SLOW bridge clocks */
DEF_LOOKUP("slow", &slow_clk),
DEF_LOOKUP("coh901327_wdog", &wdog_clk),
DEF_LOOKUP("uart0", &uart0_clk),
DEF_LOOKUP_CON("uart0", "apb_pclk", &uart0_pclk),
DEF_LOOKUP("apptimer", &app_timer_clk),
DEF_LOOKUP("coh901461-keypad", &keypad_clk),
DEF_LOOKUP("u300-gpio", &gpio_clk),
DEF_LOOKUP("rtc-coh901331", &rtc_clk),
DEF_LOOKUP("bustr", &bustr_clk),
DEF_LOOKUP("evhist", &evhist_clk),
DEF_LOOKUP("timer", &timer_clk),
#ifdef CONFIG_MACH_U300_BS335
DEF_LOOKUP("ppm", &ppm_clk),
#endif
};
static void __init clk_register(void)
{
/* Register the lookups */
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
}
#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_U300_DEBUG))
/*
* The following makes it possible to view the status (especially
* reference count and reset status) for the clocks in the platform
* by looking into the special file <debugfs>/u300_clocks
*/
/* A list of all clocks in the platform */
static struct clk *clks[] = {
/* Top node clock for the AMBA bus */
&amba_clk,
/* Connected directly to the AMBA bus */
&cpu_clk,
&nandif_clk,
&semi_clk,
#ifdef CONFIG_MACH_U300_BS335
&isp_clk,
&cds_clk,
#endif
&dma_clk,
&aaif_clk,
&apex_clk,
&video_enc_clk,
&xgam_clk,
&ahb_clk,
/* AHB bridge clocks */
&ahb_subsys_clk,
&intcon_clk,
&mspro_clk,
&emif_clk,
/* FAST bridge clocks */
&fast_clk,
&mmcsd_clk,
&i2s0_clk,
&i2s1_clk,
&i2c0_clk,
&i2c1_clk,
&spi_clk,
#ifdef CONFIG_MACH_U300_BS335
&uart1_clk,
&uart1_pclk,
#endif
/* SLOW bridge clocks */
&slow_clk,
&wdog_clk,
&uart0_clk,
&uart0_pclk,
&app_timer_clk,
&keypad_clk,
&gpio_clk,
&rtc_clk,
&bustr_clk,
&evhist_clk,
&timer_clk,
#ifdef CONFIG_MACH_U300_BS335
&ppm_clk,
#endif
};
static int u300_clocks_show(struct seq_file *s, void *data)
{
struct clk *clk;
int i;
seq_printf(s, "CLOCK DEVICE RESET STATE\t" \
"ACTIVE\tUSERS\tHW CTRL FREQ\n");
seq_printf(s, "---------------------------------------------" \
"-----------------------------------------\n");
for (i = 0; i < ARRAY_SIZE(clks); i++) {
clk = clks[i];
if (clk != ERR_PTR(-ENOENT)) {
/* Format clock and device name nicely */
char cdp[33];
int chars;
chars = snprintf(&cdp[0], 17, "%s", clk->name);
while (chars < 16) {
cdp[chars] = ' ';
chars++;
}
chars = snprintf(&cdp[16], 17, "%s", clk->dev ?
dev_name(clk->dev) : "N/A");
while (chars < 16) {
cdp[chars+16] = ' ';
chars++;
}
cdp[32] = '\0';
if (clk->get_rate || clk->rate != 0)
seq_printf(s,
"%s%s\t%s\t%d\t%s\t%lu Hz\n",
&cdp[0],
clk->reset ?
"ASSERTED" : "RELEASED",
clk->usecount ? "ON" : "OFF",
clk->usecount,
clk->hw_ctrld ? "YES" : "NO ",
clk_get_rate(clk));
else
seq_printf(s,
"%s%s\t%s\t%d\t%s\t" \
"(unknown rate)\n",
&cdp[0],
clk->reset ?
"ASSERTED" : "RELEASED",
clk->usecount ? "ON" : "OFF",
clk->usecount,
clk->hw_ctrld ? "YES" : "NO ");
}
}
return 0;
}
static int u300_clocks_open(struct inode *inode, struct file *file)
{
return single_open(file, u300_clocks_show, NULL);
}
static const struct file_operations u300_clocks_operations = {
.open = u300_clocks_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __init init_clk_read_debugfs(void)
{
/* Expose a simple debugfs interface to view all clocks */
(void) debugfs_create_file("u300_clocks", S_IFREG | S_IRUGO,
NULL, NULL,
&u300_clocks_operations);
return 0;
}
/*
* This needs to come in after the core_initcall() for the
* overall clocks, because debugfs is not available until
* the subsystems come up.
*/
module_init(init_clk_read_debugfs);
#endif
int __init u300_clock_init(void)
{
u16 val;
/*
* FIXME: shall all this powermanagement stuff really live here???
*/
/* Set system to run at PLL208, max performance, a known state. */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
/* Wait for the PLL208 to lock if not locked in yet */
while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
U300_SYSCON_CSR_PLL208_LOCK_IND));
/* Power management enable */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_PMCR);
val |= U300_SYSCON_PMCR_PWR_MGNT_ENABLE;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_PMCR);
clk_register();
/*
* Some of these may be on when we boot the system so make sure they
* are turned OFF.
*/
syscon_block_reset_enable(&timer_clk);
timer_clk.disable(&timer_clk);
/*
* These shall be turned on by default when we boot the system
* so make sure they are ON. (Adding CPU here is a bit too much.)
* These clocks will be claimed by drivers later.
*/
syscon_block_reset_disable(&semi_clk);
syscon_block_reset_disable(&emif_clk);
clk_enable(&semi_clk);
clk_enable(&emif_clk);
return 0;
}
/*
* arch/arm/mach-u300/include/mach/clock.h
*
* Copyright (C) 2004 - 2005 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
* Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
* Copyright (C) 2007-2009 ST-Ericsson AB
* Adopted to ST-Ericsson U300 platforms by
* Jonas Aaberg <jonas.aberg@stericsson.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef __MACH_CLOCK_H
#define __MACH_CLOCK_H
#include <linux/clk.h>
struct clk {
struct list_head node;
struct module *owner;
struct device *dev;
const char *name;
struct clk *parent;
spinlock_t lock;
unsigned long rate;
bool reset;
__u16 clk_val;
__s8 usecount;
void __iomem * res_reg;
__u16 res_mask;
bool hw_ctrld;
void (*recalc) (struct clk *);
int (*set_rate) (struct clk *, unsigned long);
unsigned long (*get_rate) (struct clk *);
unsigned long (*round_rate) (struct clk *, unsigned long);
void (*init) (struct clk *);
void (*enable) (struct clk *);
void (*disable) (struct clk *);
};
int u300_clock_init(void);
#endif
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/pinctrl/consumer.h> #include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf-generic.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/platform_data/clk-u300.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -44,7 +45,6 @@ ...@@ -44,7 +45,6 @@
#include <mach/dma_channels.h> #include <mach/dma_channels.h>
#include <mach/gpio-u300.h> #include <mach/gpio-u300.h>
#include "clock.h"
#include "spi.h" #include "spi.h"
#include "i2c.h" #include "i2c.h"
#include "u300-gpio.h" #include "u300-gpio.h"
...@@ -1658,12 +1658,20 @@ void __init u300_init_irq(void) ...@@ -1658,12 +1658,20 @@ void __init u300_init_irq(void)
int i; int i;
/* initialize clocking early, we want to clock the INTCON */ /* initialize clocking early, we want to clock the INTCON */
u300_clock_init(); u300_clk_init(U300_SYSCON_VBASE);
/* Bootstrap EMIF and SEMI clocks */
clk = clk_get_sys("pl172", NULL);
BUG_ON(IS_ERR(clk));
clk_prepare_enable(clk);
clk = clk_get_sys("semi", NULL);
BUG_ON(IS_ERR(clk));
clk_prepare_enable(clk);
/* Clock the interrupt controller */ /* Clock the interrupt controller */
clk = clk_get_sys("intcon", NULL); clk = clk_get_sys("intcon", NULL);
BUG_ON(IS_ERR(clk)); BUG_ON(IS_ERR(clk));
clk_enable(clk); clk_prepare_enable(clk);
for (i = 0; i < U300_VIC_IRQS_END; i++) for (i = 0; i < U300_VIC_IRQS_END; i++)
set_bit(i, (unsigned long *) &mask[0]); set_bit(i, (unsigned long *) &mask[0]);
...@@ -1811,13 +1819,6 @@ void __init u300_init_devices(void) ...@@ -1811,13 +1819,6 @@ void __init u300_init_devices(void)
/* Check what platform we run and print some status information */ /* Check what platform we run and print some status information */
u300_init_check_chip(); u300_init_check_chip();
/* Set system to run at PLL208, max performance, a known state. */
val = readw(U300_SYSCON_VBASE + U300_SYSCON_CCR);
val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
writew(val, U300_SYSCON_VBASE + U300_SYSCON_CCR);
/* Wait for the PLL208 to lock if not locked in yet */
while (!(readw(U300_SYSCON_VBASE + U300_SYSCON_CSR) &
U300_SYSCON_CSR_PLL208_LOCK_IND));
/* Initialize SPI device with some board specifics */ /* Initialize SPI device with some board specifics */
u300_spi_init(&pl022_device); u300_spi_init(&pl022_device);
......
...@@ -354,7 +354,7 @@ static void __init u300_timer_init(void) ...@@ -354,7 +354,7 @@ static void __init u300_timer_init(void)
/* Clock the interrupt controller */ /* Clock the interrupt controller */
clk = clk_get_sys("apptimer", NULL); clk = clk_get_sys("apptimer", NULL);
BUG_ON(IS_ERR(clk)); BUG_ON(IS_ERR(clk));
clk_enable(clk); clk_prepare_enable(clk);
rate = clk_get_rate(clk); rate = clk_get_rate(clk);
setup_sched_clock(u300_read_sched_clock, 32, rate); setup_sched_clock(u300_read_sched_clock, 32, rate);
......
...@@ -34,4 +34,11 @@ config COMMON_CLK_DEBUG ...@@ -34,4 +34,11 @@ config COMMON_CLK_DEBUG
clk_flags, clk_prepare_count, clk_enable_count & clk_flags, clk_prepare_count, clk_enable_count &
clk_notifier_count. clk_notifier_count.
config COMMON_CLK_WM831X
tristate "Clock driver for WM831x/2x PMICs"
depends on MFD_WM831X
---help---
Supports the clocking subsystem of the WM831x/2x series of
PMICs from Wolfson Microlectronics.
endmenu endmenu
# common clock types
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
clk-mux.o clk-divider.o clk-fixed-factor.o clk-mux.o clk-divider.o clk-fixed-factor.o
# SoCs specific # SoCs specific
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_PLAT_SPEAR) += spear/
obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_ARCH_INTEGRATOR) += versatile/
# Chip specific
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
...@@ -30,18 +30,89 @@ ...@@ -30,18 +30,89 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#define div_mask(d) ((1 << (d->width)) - 1) #define div_mask(d) ((1 << (d->width)) - 1)
#define is_power_of_two(i) !(i & ~i)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
unsigned int maxdiv = 0;
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div > maxdiv)
maxdiv = clkt->div;
return maxdiv;
}
static unsigned int _get_maxdiv(struct clk_divider *divider)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
return div_mask(divider);
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << div_mask(divider);
if (divider->table)
return _get_table_maxdiv(divider->table);
return div_mask(divider) + 1;
}
static unsigned int _get_table_div(const struct clk_div_table *table,
unsigned int val)
{
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->val == val)
return clkt->div;
return 0;
}
static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
return val;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
if (divider->table)
return _get_table_div(divider->table, val);
return val + 1;
}
static unsigned int _get_table_val(const struct clk_div_table *table,
unsigned int div)
{
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div == div)
return clkt->val;
return 0;
}
static unsigned int _get_val(struct clk_divider *divider, u8 div)
{
if (divider->flags & CLK_DIVIDER_ONE_BASED)
return div;
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
if (divider->table)
return _get_table_val(divider->table, div);
return div - 1;
}
static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_divider *divider = to_clk_divider(hw); struct clk_divider *divider = to_clk_divider(hw);
unsigned int div; unsigned int div, val;
div = readl(divider->reg) >> divider->shift; val = readl(divider->reg) >> divider->shift;
div &= div_mask(divider); val &= div_mask(divider);
if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) div = _get_div(divider, val);
div++; if (!div) {
WARN(1, "%s: Invalid divisor for clock %s\n", __func__,
__clk_get_name(hw->clk));
return parent_rate;
}
return parent_rate / div; return parent_rate / div;
} }
...@@ -52,6 +123,26 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, ...@@ -52,6 +123,26 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
*/ */
#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1) #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
static bool _is_valid_table_div(const struct clk_div_table *table,
unsigned int div)
{
const struct clk_div_table *clkt;
for (clkt = table; clkt->div; clkt++)
if (clkt->div == div)
return true;
return false;
}
static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
{
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return is_power_of_two(div);
if (divider->table)
return _is_valid_table_div(divider->table, div);
return true;
}
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate) unsigned long *best_parent_rate)
{ {
...@@ -62,10 +153,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -62,10 +153,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!rate) if (!rate)
rate = 1; rate = 1;
maxdiv = (1 << divider->width); maxdiv = _get_maxdiv(divider);
if (divider->flags & CLK_DIVIDER_ONE_BASED)
maxdiv--;
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate; parent_rate = *best_parent_rate;
...@@ -82,6 +170,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -82,6 +170,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
maxdiv = min(ULONG_MAX / rate, maxdiv); maxdiv = min(ULONG_MAX / rate, maxdiv);
for (i = 1; i <= maxdiv; i++) { for (i = 1; i <= maxdiv; i++) {
if (!_is_valid_div(divider, i))
continue;
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i)); MULT_ROUND_UP(rate, i));
now = parent_rate / i; now = parent_rate / i;
...@@ -93,9 +183,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, ...@@ -93,9 +183,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
} }
if (!bestdiv) { if (!bestdiv) {
bestdiv = (1 << divider->width); bestdiv = _get_maxdiv(divider);
if (divider->flags & CLK_DIVIDER_ONE_BASED)
bestdiv--;
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); *best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
} }
...@@ -115,24 +203,22 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -115,24 +203,22 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_divider *divider = to_clk_divider(hw); struct clk_divider *divider = to_clk_divider(hw);
unsigned int div; unsigned int div, value;
unsigned long flags = 0; unsigned long flags = 0;
u32 val; u32 val;
div = parent_rate / rate; div = parent_rate / rate;
value = _get_val(divider, div);
if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) if (value > div_mask(divider))
div--; value = div_mask(divider);
if (div > div_mask(divider))
div = div_mask(divider);
if (divider->lock) if (divider->lock)
spin_lock_irqsave(divider->lock, flags); spin_lock_irqsave(divider->lock, flags);
val = readl(divider->reg); val = readl(divider->reg);
val &= ~(div_mask(divider) << divider->shift); val &= ~(div_mask(divider) << divider->shift);
val |= div << divider->shift; val |= value << divider->shift;
writel(val, divider->reg); writel(val, divider->reg);
if (divider->lock) if (divider->lock)
...@@ -148,22 +234,11 @@ const struct clk_ops clk_divider_ops = { ...@@ -148,22 +234,11 @@ const struct clk_ops clk_divider_ops = {
}; };
EXPORT_SYMBOL_GPL(clk_divider_ops); EXPORT_SYMBOL_GPL(clk_divider_ops);
/** static struct clk *_register_divider(struct device *dev, const char *name,
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock) u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{ {
struct clk_divider *div; struct clk_divider *div;
struct clk *clk; struct clk *clk;
...@@ -178,7 +253,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -178,7 +253,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
init.name = name; init.name = name;
init.ops = &clk_divider_ops; init.ops = &clk_divider_ops;
init.flags = flags; init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name: NULL); init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0); init.num_parents = (parent_name ? 1 : 0);
...@@ -189,6 +264,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -189,6 +264,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
div->flags = clk_divider_flags; div->flags = clk_divider_flags;
div->lock = lock; div->lock = lock;
div->hw.init = &init; div->hw.init = &init;
div->table = table;
/* register the clock */ /* register the clock */
clk = clk_register(dev, &div->hw); clk = clk_register(dev, &div->hw);
...@@ -198,3 +274,48 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -198,3 +274,48 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
return clk; return clk;
} }
/**
* clk_register_divider - register a divider clock with the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
}
/**
* clk_register_divider_table - register a table based divider clock with
* the clock framework
* @dev: device registering this clock
* @name: name of this clock
* @parent_name: name of clock's parent
* @flags: framework-specific flags
* @reg: register address to adjust divider
* @shift: number of bits to shift the bitfield
* @width: width of the bitfield
* @clk_divider_flags: divider-specific flags for this clock
* @table: array of divider/value pairs ending with a div set to 0
* @lock: shared register lock for this clock
*/
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock)
{
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, table, lock);
}
...@@ -82,7 +82,7 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, ...@@ -82,7 +82,7 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
init.name = name; init.name = name;
init.ops = &clk_fixed_factor_ops; init.ops = &clk_fixed_factor_ops;
init.flags = flags; init.flags = flags | CLK_IS_BASIC;
init.parent_names = &parent_name; init.parent_names = &parent_name;
init.num_parents = 1; init.num_parents = 1;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/of.h>
/* /*
* DOC: basic fixed-rate clock that cannot gate * DOC: basic fixed-rate clock that cannot gate
...@@ -63,7 +64,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ...@@ -63,7 +64,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
init.name = name; init.name = name;
init.ops = &clk_fixed_rate_ops; init.ops = &clk_fixed_rate_ops;
init.flags = flags; init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name: NULL); init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0); init.num_parents = (parent_name ? 1 : 0);
...@@ -79,3 +80,25 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ...@@ -79,3 +80,25 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
return clk; return clk;
} }
#ifdef CONFIG_OF
/**
* of_fixed_clk_setup() - Setup function for simple fixed rate clock
*/
void __init of_fixed_clk_setup(struct device_node *node)
{
struct clk *clk;
const char *clk_name = node->name;
u32 rate;
if (of_property_read_u32(node, "clock-frequency", &rate))
return;
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
if (clk)
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
#endif
...@@ -130,7 +130,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name, ...@@ -130,7 +130,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
init.name = name; init.name = name;
init.ops = &clk_gate_ops; init.ops = &clk_gate_ops;
init.flags = flags; init.flags = flags | CLK_IS_BASIC;
init.parent_names = (parent_name ? &parent_name: NULL); init.parent_names = (parent_name ? &parent_name: NULL);
init.num_parents = (parent_name ? 1 : 0); init.num_parents = (parent_name ? 1 : 0);
......
/*
* Copyright 2011-2012 Calxeda, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
extern void __iomem *sregs_base;
#define HB_PLL_LOCK_500 0x20000000
#define HB_PLL_LOCK 0x10000000
#define HB_PLL_DIVF_SHIFT 20
#define HB_PLL_DIVF_MASK 0x0ff00000
#define HB_PLL_DIVQ_SHIFT 16
#define HB_PLL_DIVQ_MASK 0x00070000
#define HB_PLL_DIVR_SHIFT 8
#define HB_PLL_DIVR_MASK 0x00001f00
#define HB_PLL_RANGE_SHIFT 4
#define HB_PLL_RANGE_MASK 0x00000070
#define HB_PLL_BYPASS 0x00000008
#define HB_PLL_RESET 0x00000004
#define HB_PLL_EXT_BYPASS 0x00000002
#define HB_PLL_EXT_ENA 0x00000001
#define HB_PLL_VCO_MIN_FREQ 2133000000
#define HB_PLL_MAX_FREQ HB_PLL_VCO_MIN_FREQ
#define HB_PLL_MIN_FREQ (HB_PLL_VCO_MIN_FREQ / 64)
#define HB_A9_BCLK_DIV_MASK 0x00000006
#define HB_A9_BCLK_DIV_SHIFT 1
#define HB_A9_PCLK_DIV 0x00000001
struct hb_clk {
struct clk_hw hw;
void __iomem *reg;
char *parent_name;
};
#define to_hb_clk(p) container_of(p, struct hb_clk, hw)
static int clk_pll_prepare(struct clk_hw *hwclk)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 reg;
reg = readl(hbclk->reg);
reg &= ~HB_PLL_RESET;
writel(reg, hbclk->reg);
while ((readl(hbclk->reg) & HB_PLL_LOCK) == 0)
;
while ((readl(hbclk->reg) & HB_PLL_LOCK_500) == 0)
;
return 0;
}
static void clk_pll_unprepare(struct clk_hw *hwclk)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 reg;
reg = readl(hbclk->reg);
reg |= HB_PLL_RESET;
writel(reg, hbclk->reg);
}
static int clk_pll_enable(struct clk_hw *hwclk)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 reg;
reg = readl(hbclk->reg);
reg |= HB_PLL_EXT_ENA;
writel(reg, hbclk->reg);
return 0;
}
static void clk_pll_disable(struct clk_hw *hwclk)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 reg;
reg = readl(hbclk->reg);
reg &= ~HB_PLL_EXT_ENA;
writel(reg, hbclk->reg);
}
static unsigned long clk_pll_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
unsigned long divf, divq, vco_freq, reg;
reg = readl(hbclk->reg);
if (reg & HB_PLL_EXT_BYPASS)
return parent_rate;
divf = (reg & HB_PLL_DIVF_MASK) >> HB_PLL_DIVF_SHIFT;
divq = (reg & HB_PLL_DIVQ_MASK) >> HB_PLL_DIVQ_SHIFT;
vco_freq = parent_rate * (divf + 1);
return vco_freq / (1 << divq);
}
static void clk_pll_calc(unsigned long rate, unsigned long ref_freq,
u32 *pdivq, u32 *pdivf)
{
u32 divq, divf;
unsigned long vco_freq;
if (rate < HB_PLL_MIN_FREQ)
rate = HB_PLL_MIN_FREQ;
if (rate > HB_PLL_MAX_FREQ)
rate = HB_PLL_MAX_FREQ;
for (divq = 1; divq <= 6; divq++) {
if ((rate * (1 << divq)) >= HB_PLL_VCO_MIN_FREQ)
break;
}
vco_freq = rate * (1 << divq);
divf = (vco_freq + (ref_freq / 2)) / ref_freq;
divf--;
*pdivq = divq;
*pdivf = divf;
}
static long clk_pll_round_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long *parent_rate)
{
u32 divq, divf;
unsigned long ref_freq = *parent_rate;
clk_pll_calc(rate, ref_freq, &divq, &divf);
return (ref_freq * (divf + 1)) / (1 << divq);
}
static int clk_pll_set_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long parent_rate)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 divq, divf;
u32 reg;
clk_pll_calc(rate, parent_rate, &divq, &divf);
reg = readl(hbclk->reg);
if (divf != ((reg & HB_PLL_DIVF_MASK) >> HB_PLL_DIVF_SHIFT)) {
/* Need to re-lock PLL, so put it into bypass mode */
reg |= HB_PLL_EXT_BYPASS;
writel(reg | HB_PLL_EXT_BYPASS, hbclk->reg);
writel(reg | HB_PLL_RESET, hbclk->reg);
reg &= ~(HB_PLL_DIVF_MASK | HB_PLL_DIVQ_MASK);
reg |= (divf << HB_PLL_DIVF_SHIFT) | (divq << HB_PLL_DIVQ_SHIFT);
writel(reg | HB_PLL_RESET, hbclk->reg);
writel(reg, hbclk->reg);
while ((readl(hbclk->reg) & HB_PLL_LOCK) == 0)
;
while ((readl(hbclk->reg) & HB_PLL_LOCK_500) == 0)
;
reg |= HB_PLL_EXT_ENA;
reg &= ~HB_PLL_EXT_BYPASS;
} else {
reg &= ~HB_PLL_DIVQ_MASK;
reg |= divq << HB_PLL_DIVQ_SHIFT;
}
writel(reg, hbclk->reg);
return 0;
}
static const struct clk_ops clk_pll_ops = {
.prepare = clk_pll_prepare,
.unprepare = clk_pll_unprepare,
.enable = clk_pll_enable,
.disable = clk_pll_disable,
.recalc_rate = clk_pll_recalc_rate,
.round_rate = clk_pll_round_rate,
.set_rate = clk_pll_set_rate,
};
static unsigned long clk_cpu_periphclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 div = (readl(hbclk->reg) & HB_A9_PCLK_DIV) ? 8 : 4;
return parent_rate / div;
}
static const struct clk_ops a9periphclk_ops = {
.recalc_rate = clk_cpu_periphclk_recalc_rate,
};
static unsigned long clk_cpu_a9bclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 div = (readl(hbclk->reg) & HB_A9_BCLK_DIV_MASK) >> HB_A9_BCLK_DIV_SHIFT;
return parent_rate / (div + 2);
}
static const struct clk_ops a9bclk_ops = {
.recalc_rate = clk_cpu_a9bclk_recalc_rate,
};
static unsigned long clk_periclk_recalc_rate(struct clk_hw *hwclk,
unsigned long parent_rate)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 div;
div = readl(hbclk->reg) & 0x1f;
div++;
div *= 2;
return parent_rate / div;
}
static long clk_periclk_round_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long *parent_rate)
{
u32 div;
div = *parent_rate / rate;
div++;
div &= ~0x1;
return *parent_rate / div;
}
static int clk_periclk_set_rate(struct clk_hw *hwclk, unsigned long rate,
unsigned long parent_rate)
{
struct hb_clk *hbclk = to_hb_clk(hwclk);
u32 div;
div = parent_rate / rate;
if (div & 0x1)
return -EINVAL;
writel(div >> 1, hbclk->reg);
return 0;
}
static const struct clk_ops periclk_ops = {
.recalc_rate = clk_periclk_recalc_rate,
.round_rate = clk_periclk_round_rate,
.set_rate = clk_periclk_set_rate,
};
static __init struct clk *hb_clk_init(struct device_node *node, const struct clk_ops *ops)
{
u32 reg;
struct clk *clk;
struct hb_clk *hb_clk;
const char *clk_name = node->name;
const char *parent_name;
struct clk_init_data init;
int rc;
rc = of_property_read_u32(node, "reg", &reg);
if (WARN_ON(rc))
return NULL;
hb_clk = kzalloc(sizeof(*hb_clk), GFP_KERNEL);
if (WARN_ON(!hb_clk))
return NULL;
hb_clk->reg = sregs_base + reg;
of_property_read_string(node, "clock-output-names", &clk_name);
init.name = clk_name;
init.ops = ops;
init.flags = 0;
parent_name = of_clk_get_parent_name(node, 0);
init.parent_names = &parent_name;
init.num_parents = 1;
hb_clk->hw.init = &init;
clk = clk_register(NULL, &hb_clk->hw);
if (WARN_ON(IS_ERR(clk))) {
kfree(hb_clk);
return NULL;
}
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
return clk;
}
static void __init hb_pll_init(struct device_node *node)
{
hb_clk_init(node, &clk_pll_ops);
}
static void __init hb_a9periph_init(struct device_node *node)
{
hb_clk_init(node, &a9periphclk_ops);
}
static void __init hb_a9bus_init(struct device_node *node)
{
struct clk *clk = hb_clk_init(node, &a9bclk_ops);
clk_prepare_enable(clk);
}
static void __init hb_emmc_init(struct device_node *node)
{
hb_clk_init(node, &periclk_ops);
}
static const __initconst struct of_device_id clk_match[] = {
{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
{ .compatible = "calxeda,hb-pll-clock", .data = hb_pll_init, },
{ .compatible = "calxeda,hb-a9periph-clock", .data = hb_a9periph_init, },
{ .compatible = "calxeda,hb-a9bus-clock", .data = hb_a9bus_init, },
{ .compatible = "calxeda,hb-emmc-clock", .data = hb_emmc_init, },
{}
};
void __init highbank_clocks_init(void)
{
of_clk_init(clk_match);
}
...@@ -106,7 +106,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name, ...@@ -106,7 +106,7 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
init.name = name; init.name = name;
init.ops = &clk_mux_ops; init.ops = &clk_mux_ops;
init.flags = flags; init.flags = flags | CLK_IS_BASIC;
init.parent_names = parent_names; init.parent_names = parent_names;
init.num_parents = num_parents; init.num_parents = num_parents;
......
/*
* U300 clock implementation
* Copyright (C) 2007-2012 ST-Ericsson AB
* License terms: GNU General Public License (GPL) version 2
* Author: Linus Walleij <linus.walleij@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk-provider.h>
#include <linux/spinlock.h>
#include <mach/syscon.h>
/*
* The clocking hierarchy currently looks like this.
* NOTE: the idea is NOT to show how the clocks are routed on the chip!
* The ideas is to show dependencies, so a clock higher up in the
* hierarchy has to be on in order for another clock to be on. Now,
* both CPU and DMA can actually be on top of the hierarchy, and that
* is not modeled currently. Instead we have the backbone AMBA bus on
* top. This bus cannot be programmed in any way but conceptually it
* needs to be active for the bridges and devices to transport data.
*
* Please be aware that a few clocks are hw controlled, which mean that
* the hw itself can turn on/off or change the rate of the clock when
* needed!
*
* AMBA bus
* |
* +- CPU
* +- FSMC NANDIF NAND Flash interface
* +- SEMI Shared Memory interface
* +- ISP Image Signal Processor (U335 only)
* +- CDS (U335 only)
* +- DMA Direct Memory Access Controller
* +- AAIF APP/ACC Inteface (Mobile Scalable Link, MSL)
* +- APEX
* +- VIDEO_ENC AVE2/3 Video Encoder
* +- XGAM Graphics Accelerator Controller
* +- AHB
* |
* +- ahb:0 AHB Bridge
* | |
* | +- ahb:1 INTCON Interrupt controller
* | +- ahb:3 MSPRO Memory Stick Pro controller
* | +- ahb:4 EMIF External Memory interface
* |
* +- fast:0 FAST bridge
* | |
* | +- fast:1 MMCSD MMC/SD card reader controller
* | +- fast:2 I2S0 PCM I2S channel 0 controller
* | +- fast:3 I2S1 PCM I2S channel 1 controller
* | +- fast:4 I2C0 I2C channel 0 controller
* | +- fast:5 I2C1 I2C channel 1 controller
* | +- fast:6 SPI SPI controller
* | +- fast:7 UART1 Secondary UART (U335 only)
* |
* +- slow:0 SLOW bridge
* |
* +- slow:1 SYSCON (not possible to control)
* +- slow:2 WDOG Watchdog
* +- slow:3 UART0 primary UART
* +- slow:4 TIMER_APP Application timer - used in Linux
* +- slow:5 KEYPAD controller
* +- slow:6 GPIO controller
* +- slow:7 RTC controller
* +- slow:8 BT Bus Tracer (not used currently)
* +- slow:9 EH Event Handler (not used currently)
* +- slow:a TIMER_ACC Access style timer (not used currently)
* +- slow:b PPM (U335 only, what is that?)
*/
/* Global syscon virtual base */
static void __iomem *syscon_vbase;
/**
* struct clk_syscon - U300 syscon clock
* @hw: corresponding clock hardware entry
* @hw_ctrld: whether this clock is hardware controlled (for refcount etc)
* and does not need any magic pokes to be enabled/disabled
* @reset: state holder, whether this block's reset line is asserted or not
* @res_reg: reset line enable/disable flag register
* @res_bit: bit for resetting or taking this consumer out of reset
* @en_reg: clock line enable/disable flag register
* @en_bit: bit for enabling/disabling this consumer clock line
* @clk_val: magic value to poke in the register to enable/disable
* this one clock
*/
struct clk_syscon {
struct clk_hw hw;
bool hw_ctrld;
bool reset;
void __iomem *res_reg;
u8 res_bit;
void __iomem *en_reg;
u8 en_bit;
u16 clk_val;
};
#define to_syscon(_hw) container_of(_hw, struct clk_syscon, hw)
static DEFINE_SPINLOCK(syscon_resetreg_lock);
/*
* Reset control functions. We remember if a block has been
* taken out of reset and don't remove the reset assertion again
* and vice versa. Currently we only remove resets so the
* enablement function is defined out.
*/
static void syscon_block_reset_enable(struct clk_syscon *sclk)
{
unsigned long iflags;
u16 val;
/* Not all blocks support resetting */
if (!sclk->res_reg)
return;
spin_lock_irqsave(&syscon_resetreg_lock, iflags);
val = readw(sclk->res_reg);
val |= BIT(sclk->res_bit);
writew(val, sclk->res_reg);
spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
sclk->reset = true;
}
static void syscon_block_reset_disable(struct clk_syscon *sclk)
{
unsigned long iflags;
u16 val;
/* Not all blocks support resetting */
if (!sclk->res_reg)
return;
spin_lock_irqsave(&syscon_resetreg_lock, iflags);
val = readw(sclk->res_reg);
val &= ~BIT(sclk->res_bit);
writew(val, sclk->res_reg);
spin_unlock_irqrestore(&syscon_resetreg_lock, iflags);
sclk->reset = false;
}
static int syscon_clk_prepare(struct clk_hw *hw)
{
struct clk_syscon *sclk = to_syscon(hw);
/* If the block is in reset, bring it out */
if (sclk->reset)
syscon_block_reset_disable(sclk);
return 0;
}
static void syscon_clk_unprepare(struct clk_hw *hw)
{
struct clk_syscon *sclk = to_syscon(hw);
/* Please don't force the console into reset */
if (sclk->clk_val == U300_SYSCON_SBCER_UART_CLK_EN)
return;
/* When unpreparing, force block into reset */
if (!sclk->reset)
syscon_block_reset_enable(sclk);
}
static int syscon_clk_enable(struct clk_hw *hw)
{
struct clk_syscon *sclk = to_syscon(hw);
/* Don't touch the hardware controlled clocks */
if (sclk->hw_ctrld)
return 0;
/* These cannot be controlled */
if (sclk->clk_val == 0xFFFFU)
return 0;
writew(sclk->clk_val, syscon_vbase + U300_SYSCON_SBCER);
return 0;
}
static void syscon_clk_disable(struct clk_hw *hw)
{
struct clk_syscon *sclk = to_syscon(hw);
/* Don't touch the hardware controlled clocks */
if (sclk->hw_ctrld)
return;
if (sclk->clk_val == 0xFFFFU)
return;
/* Please don't disable the console port */
if (sclk->clk_val == U300_SYSCON_SBCER_UART_CLK_EN)
return;
writew(sclk->clk_val, syscon_vbase + U300_SYSCON_SBCDR);
}
static int syscon_clk_is_enabled(struct clk_hw *hw)
{
struct clk_syscon *sclk = to_syscon(hw);
u16 val;
/* If no enable register defined, it's always-on */
if (!sclk->en_reg)
return 1;
val = readw(sclk->en_reg);
val &= BIT(sclk->en_bit);
return val ? 1 : 0;
}
static u16 syscon_get_perf(void)
{
u16 val;
val = readw(syscon_vbase + U300_SYSCON_CCR);
val &= U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
return val;
}
static unsigned long
syscon_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_syscon *sclk = to_syscon(hw);
u16 perf = syscon_get_perf();
switch(sclk->clk_val) {
case U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN:
case U300_SYSCON_SBCER_I2C0_CLK_EN:
case U300_SYSCON_SBCER_I2C1_CLK_EN:
case U300_SYSCON_SBCER_MMC_CLK_EN:
case U300_SYSCON_SBCER_SPI_CLK_EN:
/* The FAST clocks have one progression */
switch(perf) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 13000000;
default:
return parent_rate; /* 26 MHz */
}
case U300_SYSCON_SBCER_DMAC_CLK_EN:
case U300_SYSCON_SBCER_NANDIF_CLK_EN:
case U300_SYSCON_SBCER_XGAM_CLK_EN:
/* AMBA interconnect peripherals */
switch(perf) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 6500000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 26000000;
default:
return parent_rate; /* 52 MHz */
}
case U300_SYSCON_SBCER_SEMI_CLK_EN:
case U300_SYSCON_SBCER_EMIF_CLK_EN:
/* EMIF speeds */
switch(perf) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 52000000;
default:
return 104000000;
}
case U300_SYSCON_SBCER_CPU_CLK_EN:
/* And the fast CPU clock */
switch(perf) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
return 52000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
return 104000000;
default:
return parent_rate; /* 208 MHz */
}
default:
/*
* The SLOW clocks and default just inherit the rate of
* their parent (typically PLL13 13 MHz).
*/
return parent_rate;
}
}
static long
syscon_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_syscon *sclk = to_syscon(hw);
if (sclk->clk_val != U300_SYSCON_SBCER_CPU_CLK_EN)
return *prate;
/* We really only support setting the rate of the CPU clock */
if (rate <= 13000000)
return 13000000;
if (rate <= 52000000)
return 52000000;
if (rate <= 104000000)
return 104000000;
return 208000000;
}
static int syscon_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_syscon *sclk = to_syscon(hw);
u16 val;
/* We only support setting the rate of the CPU clock */
if (sclk->clk_val != U300_SYSCON_SBCER_CPU_CLK_EN)
return -EINVAL;
switch (rate) {
case 13000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER;
break;
case 52000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE;
break;
case 104000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH;
break;
case 208000000:
val = U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST;
break;
default:
return -EINVAL;
}
val |= readw(syscon_vbase + U300_SYSCON_CCR) &
~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK ;
writew(val, syscon_vbase + U300_SYSCON_CCR);
return 0;
}
static const struct clk_ops syscon_clk_ops = {
.prepare = syscon_clk_prepare,
.unprepare = syscon_clk_unprepare,
.enable = syscon_clk_enable,
.disable = syscon_clk_disable,
.is_enabled = syscon_clk_is_enabled,
.recalc_rate = syscon_clk_recalc_rate,
.round_rate = syscon_clk_round_rate,
.set_rate = syscon_clk_set_rate,
};
static struct clk * __init
syscon_clk_register(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
bool hw_ctrld,
void __iomem *res_reg, u8 res_bit,
void __iomem *en_reg, u8 en_bit,
u16 clk_val)
{
struct clk *clk;
struct clk_syscon *sclk;
struct clk_init_data init;
sclk = kzalloc(sizeof(struct clk_syscon), GFP_KERNEL);
if (!sclk) {
pr_err("could not allocate syscon clock %s\n",
name);
return ERR_PTR(-ENOMEM);
}
init.name = name;
init.ops = &syscon_clk_ops;
init.flags = flags;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
sclk->hw.init = &init;
sclk->hw_ctrld = hw_ctrld;
/* Assume the block is in reset at registration */
sclk->reset = true;
sclk->res_reg = res_reg;
sclk->res_bit = res_bit;
sclk->en_reg = en_reg;
sclk->en_bit = en_bit;
sclk->clk_val = clk_val;
clk = clk_register(dev, &sclk->hw);
if (IS_ERR(clk))
kfree(sclk);
return clk;
}
/**
* struct clk_mclk - U300 MCLK clock (MMC/SD clock)
* @hw: corresponding clock hardware entry
* @is_mspro: if this is the memory stick clock rather than MMC/SD
*/
struct clk_mclk {
struct clk_hw hw;
bool is_mspro;
};
#define to_mclk(_hw) container_of(_hw, struct clk_mclk, hw)
static int mclk_clk_prepare(struct clk_hw *hw)
{
struct clk_mclk *mclk = to_mclk(hw);
u16 val;
/* The MMC and MSPRO clocks need some special set-up */
if (!mclk->is_mspro) {
/* Set default MMC clock divisor to 18.9 MHz */
writew(0x0054U, syscon_vbase + U300_SYSCON_MMF0R);
val = readw(syscon_vbase + U300_SYSCON_MMCR);
/* Disable the MMC feedback clock */
val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
/* Disable MSPRO frequency */
val &= ~U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
writew(val, syscon_vbase + U300_SYSCON_MMCR);
} else {
val = readw(syscon_vbase + U300_SYSCON_MMCR);
/* Disable the MMC feedback clock */
val &= ~U300_SYSCON_MMCR_MMC_FB_CLK_SEL_ENABLE;
/* Enable MSPRO frequency */
val |= U300_SYSCON_MMCR_MSPRO_FREQSEL_ENABLE;
writew(val, syscon_vbase + U300_SYSCON_MMCR);
}
return 0;
}
static unsigned long
mclk_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
u16 perf = syscon_get_perf();
switch (perf) {
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER:
/*
* Here, the 208 MHz PLL gets shut down and the always
* on 13 MHz PLL used for RTC etc kicks into use
* instead.
*/
return 13000000;
case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_INTERMEDIATE:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_HIGH:
case U300_SYSCON_CCR_CLKING_PERFORMANCE_BEST:
{
/*
* This clock is under program control. The register is
* divided in two nybbles, bit 7-4 gives cycles-1 to count
* high, bit 3-0 gives cycles-1 to count low. Distribute
* these with no more than 1 cycle difference between
* low and high and add low and high to get the actual
* divisor. The base PLL is 208 MHz. Writing 0x00 will
* divide by 1 and 1 so the highest frequency possible
* is 104 MHz.
*
* e.g. 0x54 =>
* f = 208 / ((5+1) + (4+1)) = 208 / 11 = 18.9 MHz
*/
u16 val = readw(syscon_vbase + U300_SYSCON_MMF0R) &
U300_SYSCON_MMF0R_MASK;
switch (val) {
case 0x0054:
return 18900000;
case 0x0044:
return 20800000;
case 0x0043:
return 23100000;
case 0x0033:
return 26000000;
case 0x0032:
return 29700000;
case 0x0022:
return 34700000;
case 0x0021:
return 41600000;
case 0x0011:
return 52000000;
case 0x0000:
return 104000000;
default:
break;
}
}
default:
break;
}
return parent_rate;
}
static long
mclk_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
if (rate <= 18900000)
return 18900000;
if (rate <= 20800000)
return 20800000;
if (rate <= 23100000)
return 23100000;
if (rate <= 26000000)
return 26000000;
if (rate <= 29700000)
return 29700000;
if (rate <= 34700000)
return 34700000;
if (rate <= 41600000)
return 41600000;
/* Highest rate */
return 52000000;
}
static int mclk_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
u16 val;
u16 reg;
switch (rate) {
case 18900000:
val = 0x0054;
break;
case 20800000:
val = 0x0044;
break;
case 23100000:
val = 0x0043;
break;
case 26000000:
val = 0x0033;
break;
case 29700000:
val = 0x0032;
break;
case 34700000:
val = 0x0022;
break;
case 41600000:
val = 0x0021;
break;
case 52000000:
val = 0x0011;
break;
case 104000000:
val = 0x0000;
break;
default:
return -EINVAL;
}
reg = readw(syscon_vbase + U300_SYSCON_MMF0R) &
~U300_SYSCON_MMF0R_MASK;
writew(reg | val, syscon_vbase + U300_SYSCON_MMF0R);
return 0;
}
static const struct clk_ops mclk_ops = {
.prepare = mclk_clk_prepare,
.recalc_rate = mclk_clk_recalc_rate,
.round_rate = mclk_clk_round_rate,
.set_rate = mclk_clk_set_rate,
};
static struct clk * __init
mclk_clk_register(struct device *dev, const char *name,
const char *parent_name, bool is_mspro)
{
struct clk *clk;
struct clk_mclk *mclk;
struct clk_init_data init;
mclk = kzalloc(sizeof(struct clk_mclk), GFP_KERNEL);
if (!mclk) {
pr_err("could not allocate MMC/SD clock %s\n",
name);
return ERR_PTR(-ENOMEM);
}
init.name = "mclk";
init.ops = &mclk_ops;
init.flags = 0;
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
mclk->hw.init = &init;
mclk->is_mspro = is_mspro;
clk = clk_register(dev, &mclk->hw);
if (IS_ERR(clk))
kfree(mclk);
return clk;
}
void __init u300_clk_init(void __iomem *base)
{
u16 val;
struct clk *clk;
syscon_vbase = base;
/* Set system to run at PLL208, max performance, a known state. */
val = readw(syscon_vbase + U300_SYSCON_CCR);
val &= ~U300_SYSCON_CCR_CLKING_PERFORMANCE_MASK;
writew(val, syscon_vbase + U300_SYSCON_CCR);
/* Wait for the PLL208 to lock if not locked in yet */
while (!(readw(syscon_vbase + U300_SYSCON_CSR) &
U300_SYSCON_CSR_PLL208_LOCK_IND));
/* Power management enable */
val = readw(syscon_vbase + U300_SYSCON_PMCR);
val |= U300_SYSCON_PMCR_PWR_MGNT_ENABLE;
writew(val, syscon_vbase + U300_SYSCON_PMCR);
/* These are always available (RTC and PLL13) */
clk = clk_register_fixed_rate(NULL, "app_32_clk", NULL,
CLK_IS_ROOT, 32768);
/* The watchdog sits directly on the 32 kHz clock */
clk_register_clkdev(clk, NULL, "coh901327_wdog");
clk = clk_register_fixed_rate(NULL, "pll13", NULL,
CLK_IS_ROOT, 13000000);
/* These derive from PLL208 */
clk = clk_register_fixed_rate(NULL, "pll208", NULL,
CLK_IS_ROOT, 208000000);
clk = clk_register_fixed_factor(NULL, "app_208_clk", "pll208",
0, 1, 1);
clk = clk_register_fixed_factor(NULL, "app_104_clk", "pll208",
0, 1, 2);
clk = clk_register_fixed_factor(NULL, "app_52_clk", "pll208",
0, 1, 4);
/* The 52 MHz is divided down to 26 MHz */
clk = clk_register_fixed_factor(NULL, "app_26_clk", "app_52_clk",
0, 1, 2);
/* Directly on the AMBA interconnect */
clk = syscon_clk_register(NULL, "cpu_clk", "app_208_clk", 0, true,
syscon_vbase + U300_SYSCON_RRR, 3,
syscon_vbase + U300_SYSCON_CERR, 3,
U300_SYSCON_SBCER_CPU_CLK_EN);
clk = syscon_clk_register(NULL, "dmac_clk", "app_52_clk", 0, true,
syscon_vbase + U300_SYSCON_RRR, 4,
syscon_vbase + U300_SYSCON_CERR, 4,
U300_SYSCON_SBCER_DMAC_CLK_EN);
clk_register_clkdev(clk, NULL, "dma");
clk = syscon_clk_register(NULL, "fsmc_clk", "app_52_clk", 0, false,
syscon_vbase + U300_SYSCON_RRR, 6,
syscon_vbase + U300_SYSCON_CERR, 6,
U300_SYSCON_SBCER_NANDIF_CLK_EN);
clk_register_clkdev(clk, NULL, "fsmc-nand");
clk = syscon_clk_register(NULL, "xgam_clk", "app_52_clk", 0, true,
syscon_vbase + U300_SYSCON_RRR, 8,
syscon_vbase + U300_SYSCON_CERR, 8,
U300_SYSCON_SBCER_XGAM_CLK_EN);
clk_register_clkdev(clk, NULL, "xgam");
clk = syscon_clk_register(NULL, "semi_clk", "app_104_clk", 0, false,
syscon_vbase + U300_SYSCON_RRR, 9,
syscon_vbase + U300_SYSCON_CERR, 9,
U300_SYSCON_SBCER_SEMI_CLK_EN);
clk_register_clkdev(clk, NULL, "semi");
/* AHB bridge clocks */
clk = syscon_clk_register(NULL, "ahb_subsys_clk", "app_52_clk", 0, true,
syscon_vbase + U300_SYSCON_RRR, 10,
syscon_vbase + U300_SYSCON_CERR, 10,
U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN);
clk = syscon_clk_register(NULL, "intcon_clk", "ahb_subsys_clk", 0, false,
syscon_vbase + U300_SYSCON_RRR, 12,
syscon_vbase + U300_SYSCON_CERR, 12,
/* Cannot be enabled, just taken out of reset */
0xFFFFU);
clk_register_clkdev(clk, NULL, "intcon");
clk = syscon_clk_register(NULL, "emif_clk", "ahb_subsys_clk", 0, false,
syscon_vbase + U300_SYSCON_RRR, 5,
syscon_vbase + U300_SYSCON_CERR, 5,
U300_SYSCON_SBCER_EMIF_CLK_EN);
clk_register_clkdev(clk, NULL, "pl172");
/* FAST bridge clocks */
clk = syscon_clk_register(NULL, "fast_clk", "app_26_clk", 0, true,
syscon_vbase + U300_SYSCON_RFR, 0,
syscon_vbase + U300_SYSCON_CEFR, 0,
U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN);
clk = syscon_clk_register(NULL, "i2c0_p_clk", "fast_clk", 0, false,
syscon_vbase + U300_SYSCON_RFR, 1,
syscon_vbase + U300_SYSCON_CEFR, 1,
U300_SYSCON_SBCER_I2C0_CLK_EN);
clk_register_clkdev(clk, NULL, "stu300.0");
clk = syscon_clk_register(NULL, "i2c1_p_clk", "fast_clk", 0, false,
syscon_vbase + U300_SYSCON_RFR, 2,
syscon_vbase + U300_SYSCON_CEFR, 2,
U300_SYSCON_SBCER_I2C1_CLK_EN);
clk_register_clkdev(clk, NULL, "stu300.1");
clk = syscon_clk_register(NULL, "mmc_p_clk", "fast_clk", 0, false,
syscon_vbase + U300_SYSCON_RFR, 5,
syscon_vbase + U300_SYSCON_CEFR, 5,
U300_SYSCON_SBCER_MMC_CLK_EN);
clk_register_clkdev(clk, "apb_pclk", "mmci");
clk = syscon_clk_register(NULL, "spi_p_clk", "fast_clk", 0, false,
syscon_vbase + U300_SYSCON_RFR, 6,
syscon_vbase + U300_SYSCON_CEFR, 6,
U300_SYSCON_SBCER_SPI_CLK_EN);
/* The SPI has no external clock for the outward bus, uses the pclk */
clk_register_clkdev(clk, NULL, "pl022");
clk_register_clkdev(clk, "apb_pclk", "pl022");
/* SLOW bridge clocks */
clk = syscon_clk_register(NULL, "slow_clk", "pll13", 0, true,
syscon_vbase + U300_SYSCON_RSR, 0,
syscon_vbase + U300_SYSCON_CESR, 0,
U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN);
clk = syscon_clk_register(NULL, "uart0_clk", "slow_clk", 0, false,
syscon_vbase + U300_SYSCON_RSR, 1,
syscon_vbase + U300_SYSCON_CESR, 1,
U300_SYSCON_SBCER_UART_CLK_EN);
/* Same clock is used for APB and outward bus */
clk_register_clkdev(clk, NULL, "uart0");
clk_register_clkdev(clk, "apb_pclk", "uart0");
clk = syscon_clk_register(NULL, "gpio_clk", "slow_clk", 0, false,
syscon_vbase + U300_SYSCON_RSR, 4,
syscon_vbase + U300_SYSCON_CESR, 4,
U300_SYSCON_SBCER_GPIO_CLK_EN);
clk_register_clkdev(clk, NULL, "u300-gpio");
clk = syscon_clk_register(NULL, "keypad_clk", "slow_clk", 0, false,
syscon_vbase + U300_SYSCON_RSR, 5,
syscon_vbase + U300_SYSCON_CESR, 6,
U300_SYSCON_SBCER_KEYPAD_CLK_EN);
clk_register_clkdev(clk, NULL, "coh901461-keypad");
clk = syscon_clk_register(NULL, "rtc_clk", "slow_clk", 0, true,
syscon_vbase + U300_SYSCON_RSR, 6,
/* No clock enable register bit */
NULL, 0, 0xFFFFU);
clk_register_clkdev(clk, NULL, "rtc-coh901331");
clk = syscon_clk_register(NULL, "app_tmr_clk", "slow_clk", 0, false,
syscon_vbase + U300_SYSCON_RSR, 7,
syscon_vbase + U300_SYSCON_CESR, 7,
U300_SYSCON_SBCER_APP_TMR_CLK_EN);
clk_register_clkdev(clk, NULL, "apptimer");
clk = syscon_clk_register(NULL, "acc_tmr_clk", "slow_clk", 0, false,
syscon_vbase + U300_SYSCON_RSR, 8,
syscon_vbase + U300_SYSCON_CESR, 8,
U300_SYSCON_SBCER_ACC_TMR_CLK_EN);
clk_register_clkdev(clk, NULL, "timer");
/* Then this special MMC/SD clock */
clk = mclk_clk_register(NULL, "mmc_clk", "mmc_p_clk", false);
clk_register_clkdev(clk, NULL, "mmci");
}
/*
* WM831x clock control
*
* Copyright 2011-2 Wolfson Microelectronics PLC.
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/mfd/wm831x/core.h>
struct wm831x_clk {
struct wm831x *wm831x;
struct clk_hw xtal_hw;
struct clk_hw fll_hw;
struct clk_hw clkout_hw;
struct clk *xtal;
struct clk *fll;
struct clk *clkout;
bool xtal_ena;
};
static int wm831x_xtal_is_enabled(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
xtal_hw);
return clkdata->xtal_ena;
}
static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
xtal_hw);
if (clkdata->xtal_ena)
return 32768;
else
return 0;
}
static const struct clk_ops wm831x_xtal_ops = {
.is_enabled = wm831x_xtal_is_enabled,
.recalc_rate = wm831x_xtal_recalc_rate,
};
static struct clk_init_data wm831x_xtal_init = {
.name = "xtal",
.ops = &wm831x_xtal_ops,
.flags = CLK_IS_ROOT,
};
static const unsigned long wm831x_fll_auto_rates[] = {
2048000,
11289600,
12000000,
12288000,
19200000,
22579600,
24000000,
24576000,
};
static int wm831x_fll_is_enabled(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_1);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read FLL_CONTROL_1: %d\n",
ret);
return true;
}
return (ret & WM831X_FLL_ENA) != 0;
}
static int wm831x_fll_prepare(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2,
WM831X_FLL_ENA, WM831X_FLL_ENA);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret);
usleep_range(2000, 2000);
return ret;
}
static void wm831x_fll_unprepare(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, WM831X_FLL_ENA, 0);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to disaable FLL: %d\n", ret);
}
static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
ret);
return 0;
}
if (ret & WM831X_FLL_AUTO)
return wm831x_fll_auto_rates[ret & WM831X_FLL_AUTO_FREQ_MASK];
dev_err(wm831x->dev, "FLL only supported in AUTO mode\n");
return 0;
}
static long wm831x_fll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *unused)
{
int best = 0;
int i;
for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
if (abs(wm831x_fll_auto_rates[i] - rate) <
abs(wm831x_fll_auto_rates[best] - rate))
best = i;
return wm831x_fll_auto_rates[best];
}
static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
struct wm831x *wm831x = clkdata->wm831x;
int i;
for (i = 0; i < ARRAY_SIZE(wm831x_fll_auto_rates); i++)
if (wm831x_fll_auto_rates[i] == rate)
break;
if (i == ARRAY_SIZE(wm831x_fll_auto_rates))
return -EINVAL;
if (wm831x_fll_is_enabled(hw))
return -EPERM;
return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2,
WM831X_FLL_AUTO_FREQ_MASK, i);
}
static const char *wm831x_fll_parents[] = {
"xtal",
"clkin",
};
static u8 wm831x_fll_get_parent(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
/* AUTO mode is always clocked from the crystal */
ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
ret);
return 0;
}
if (ret & WM831X_FLL_AUTO)
return 0;
ret = wm831x_reg_read(wm831x, WM831X_FLL_CONTROL_5);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read FLL_CONTROL_5: %d\n",
ret);
return 0;
}
switch (ret & WM831X_FLL_CLK_SRC_MASK) {
case 0:
return 0;
case 1:
return 1;
default:
dev_err(wm831x->dev, "Unsupported FLL clock source %d\n",
ret & WM831X_FLL_CLK_SRC_MASK);
return 0;
}
}
static const struct clk_ops wm831x_fll_ops = {
.is_enabled = wm831x_fll_is_enabled,
.prepare = wm831x_fll_prepare,
.unprepare = wm831x_fll_unprepare,
.round_rate = wm831x_fll_round_rate,
.recalc_rate = wm831x_fll_recalc_rate,
.set_rate = wm831x_fll_set_rate,
.get_parent = wm831x_fll_get_parent,
};
static struct clk_init_data wm831x_fll_init = {
.name = "fll",
.ops = &wm831x_fll_ops,
.parent_names = wm831x_fll_parents,
.num_parents = ARRAY_SIZE(wm831x_fll_parents),
.flags = CLK_SET_RATE_GATE,
};
static int wm831x_clkout_is_enabled(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
clkout_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
ret);
return true;
}
return (ret & WM831X_CLKOUT_ENA) != 0;
}
static int wm831x_clkout_prepare(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
clkout_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_reg_unlock(wm831x);
if (ret != 0) {
dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
return ret;
}
ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
WM831X_CLKOUT_ENA, WM831X_CLKOUT_ENA);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to enable CLKOUT: %d\n", ret);
wm831x_reg_lock(wm831x);
return ret;
}
static void wm831x_clkout_unprepare(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
clkout_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_reg_unlock(wm831x);
if (ret != 0) {
dev_crit(wm831x->dev, "Failed to lock registers: %d\n", ret);
return;
}
ret = wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
WM831X_CLKOUT_ENA, 0);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to disable CLKOUT: %d\n", ret);
wm831x_reg_lock(wm831x);
}
static const char *wm831x_clkout_parents[] = {
"xtal",
"fll",
};
static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
clkout_hw);
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_1);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_1: %d\n",
ret);
return 0;
}
if (ret & WM831X_CLKOUT_SRC)
return 0;
else
return 1;
}
static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
clkout_hw);
struct wm831x *wm831x = clkdata->wm831x;
return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_1,
WM831X_CLKOUT_SRC,
parent << WM831X_CLKOUT_SRC_SHIFT);
}
static const struct clk_ops wm831x_clkout_ops = {
.is_enabled = wm831x_clkout_is_enabled,
.prepare = wm831x_clkout_prepare,
.unprepare = wm831x_clkout_unprepare,
.get_parent = wm831x_clkout_get_parent,
.set_parent = wm831x_clkout_set_parent,
};
static struct clk_init_data wm831x_clkout_init = {
.name = "clkout",
.ops = &wm831x_clkout_ops,
.parent_names = wm831x_clkout_parents,
.num_parents = ARRAY_SIZE(wm831x_clkout_parents),
.flags = CLK_SET_RATE_PARENT,
};
static __devinit int wm831x_clk_probe(struct platform_device *pdev)
{
struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
struct wm831x_clk *clkdata;
int ret;
clkdata = devm_kzalloc(&pdev->dev, sizeof(*clkdata), GFP_KERNEL);
if (!clkdata)
return -ENOMEM;
/* XTAL_ENA can only be set via OTP/InstantConfig so just read once */
ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
if (ret < 0) {
dev_err(wm831x->dev, "Unable to read CLOCK_CONTROL_2: %d\n",
ret);
return ret;
}
clkdata->xtal_ena = ret & WM831X_XTAL_ENA;
clkdata->xtal_hw.init = &wm831x_xtal_init;
clkdata->xtal = clk_register(&pdev->dev, &clkdata->xtal_hw);
if (!clkdata->xtal)
return -EINVAL;
clkdata->fll_hw.init = &wm831x_fll_init;
clkdata->fll = clk_register(&pdev->dev, &clkdata->fll_hw);
if (!clkdata->fll) {
ret = -EINVAL;
goto err_xtal;
}
clkdata->clkout_hw.init = &wm831x_clkout_init;
clkdata->clkout = clk_register(&pdev->dev, &clkdata->clkout_hw);
if (!clkdata->clkout) {
ret = -EINVAL;
goto err_fll;
}
dev_set_drvdata(&pdev->dev, clkdata);
return 0;
err_fll:
clk_unregister(clkdata->fll);
err_xtal:
clk_unregister(clkdata->xtal);
return ret;
}
static int __devexit wm831x_clk_remove(struct platform_device *pdev)
{
struct wm831x_clk *clkdata = dev_get_drvdata(&pdev->dev);
clk_unregister(clkdata->clkout);
clk_unregister(clkdata->fll);
clk_unregister(clkdata->xtal);
return 0;
}
static struct platform_driver wm831x_clk_driver = {
.probe = wm831x_clk_probe,
.remove = __devexit_p(wm831x_clk_remove),
.driver = {
.name = "wm831x-clk",
.owner = THIS_MODULE,
},
};
module_platform_driver(wm831x_clk_driver);
/* Module information */
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_DESCRIPTION("WM831x clock driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:wm831x-clk");
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h>
static DEFINE_SPINLOCK(enable_lock); static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock); static DEFINE_MUTEX(prepare_lock);
...@@ -1235,8 +1236,8 @@ int __clk_init(struct device *dev, struct clk *clk) ...@@ -1235,8 +1236,8 @@ int __clk_init(struct device *dev, struct clk *clk)
* If clk->parents is not NULL we skip this entire block. This allows * If clk->parents is not NULL we skip this entire block. This allows
* for clock drivers to statically initialize clk->parents. * for clock drivers to statically initialize clk->parents.
*/ */
if (clk->num_parents && !clk->parents) { if (clk->num_parents > 1 && !clk->parents) {
clk->parents = kmalloc((sizeof(struct clk*) * clk->num_parents), clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL); GFP_KERNEL);
/* /*
* __clk_lookup returns NULL for parents that have not been * __clk_lookup returns NULL for parents that have not been
...@@ -1550,3 +1551,142 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb) ...@@ -1550,3 +1551,142 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(clk_notifier_unregister); EXPORT_SYMBOL_GPL(clk_notifier_unregister);
#ifdef CONFIG_OF
/**
* struct of_clk_provider - Clock provider registration structure
* @link: Entry in global list of clock providers
* @node: Pointer to device tree node of clock provider
* @get: Get clock callback. Returns NULL or a struct clk for the
* given clock specifier
* @data: context pointer to be passed into @get callback
*/
struct of_clk_provider {
struct list_head link;
struct device_node *node;
struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
void *data;
};
static LIST_HEAD(of_clk_providers);
static DEFINE_MUTEX(of_clk_lock);
struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
void *data)
{
return data;
}
EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
/**
* of_clk_add_provider() - Register a clock provider for a node
* @np: Device node pointer associated with clock provider
* @clk_src_get: callback for decoding clock
* @data: context pointer for @clk_src_get callback.
*/
int of_clk_add_provider(struct device_node *np,
struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
void *data),
void *data)
{
struct of_clk_provider *cp;
cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
if (!cp)
return -ENOMEM;
cp->node = of_node_get(np);
cp->data = data;
cp->get = clk_src_get;
mutex_lock(&of_clk_lock);
list_add(&cp->link, &of_clk_providers);
mutex_unlock(&of_clk_lock);
pr_debug("Added clock from %s\n", np->full_name);
return 0;
}
EXPORT_SYMBOL_GPL(of_clk_add_provider);
/**
* of_clk_del_provider() - Remove a previously registered clock provider
* @np: Device node pointer associated with clock provider
*/
void of_clk_del_provider(struct device_node *np)
{
struct of_clk_provider *cp;
mutex_lock(&of_clk_lock);
list_for_each_entry(cp, &of_clk_providers, link) {
if (cp->node == np) {
list_del(&cp->link);
of_node_put(cp->node);
kfree(cp);
break;
}
}
mutex_unlock(&of_clk_lock);
}
EXPORT_SYMBOL_GPL(of_clk_del_provider);
struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
{
struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-ENOENT);
/* Check if we have such a provider in our array */
mutex_lock(&of_clk_lock);
list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == clkspec->np)
clk = provider->get(clkspec, provider->data);
if (!IS_ERR(clk))
break;
}
mutex_unlock(&of_clk_lock);
return clk;
}
const char *of_clk_get_parent_name(struct device_node *np, int index)
{
struct of_phandle_args clkspec;
const char *clk_name;
int rc;
if (index < 0)
return NULL;
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
&clkspec);
if (rc)
return NULL;
if (of_property_read_string_index(clkspec.np, "clock-output-names",
clkspec.args_count ? clkspec.args[0] : 0,
&clk_name) < 0)
clk_name = clkspec.np->name;
of_node_put(clkspec.np);
return clk_name;
}
EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
/**
* of_clk_init() - Scan and init clock providers from the DT
* @matches: array of compatible values and init functions for providers.
*
* This function scans the device tree for matching clock providers and
* calls their initialization functions
*/
void __init of_clk_init(const struct of_device_id *matches)
{
struct device_node *np;
for_each_matching_node(np, matches) {
const struct of_device_id *match = of_match_node(matches, np);
of_clk_init_cb_t clk_init_cb = match->data;
clk_init_cb(np);
}
}
#endif
...@@ -19,10 +19,80 @@ ...@@ -19,10 +19,80 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
#include <linux/of.h>
static LIST_HEAD(clocks); static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex); static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get(struct device_node *np, int index)
{
struct of_phandle_args clkspec;
struct clk *clk;
int rc;
if (index < 0)
return ERR_PTR(-EINVAL);
rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
&clkspec);
if (rc)
return ERR_PTR(rc);
clk = of_clk_get_from_provider(&clkspec);
of_node_put(clkspec.np);
return clk;
}
EXPORT_SYMBOL(of_clk_get);
/**
* of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
* @np: pointer to clock consumer node
* @name: name of consumer's clock input, or NULL for the first clock reference
*
* This function parses the clocks and clock-names properties,
* and uses them to look up the struct clk from the registered list of clock
* providers.
*/
struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
{
struct clk *clk = ERR_PTR(-ENOENT);
/* Walk up the tree of devices looking for a clock that matches */
while (np) {
int index = 0;
/*
* For named clocks, first look up the name in the
* "clock-names" property. If it cannot be found, then
* index will be an error code, and of_clk_get() will fail.
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
clk = of_clk_get(np, index);
if (!IS_ERR(clk))
break;
else if (name && index >= 0) {
pr_err("ERROR: could not get clock %s:%s(%i)\n",
np->full_name, name ? name : "", index);
return clk;
}
/*
* No matching clock found on this node. If the parent node
* has a "clock-ranges" property, then we can try one of its
* clocks.
*/
np = np->parent;
if (np && !of_get_property(np, "clock-ranges", NULL))
break;
}
return clk;
}
EXPORT_SYMBOL(of_clk_get_by_name);
#endif
/* /*
* Find the correct struct clk for the device and connection ID. * Find the correct struct clk for the device and connection ID.
* We do slightly fuzzy matching here: * We do slightly fuzzy matching here:
...@@ -83,6 +153,13 @@ EXPORT_SYMBOL(clk_get_sys); ...@@ -83,6 +153,13 @@ EXPORT_SYMBOL(clk_get_sys);
struct clk *clk_get(struct device *dev, const char *con_id) struct clk *clk_get(struct device *dev, const char *con_id)
{ {
const char *dev_id = dev ? dev_name(dev) : NULL; const char *dev_id = dev ? dev_name(dev) : NULL;
struct clk *clk;
if (dev) {
clk = of_clk_get_by_name(dev->of_node, con_id);
if (!IS_ERR(clk) && __clk_get(clk))
return clk;
}
return clk_get_sys(dev_id, con_id); return clk_get_sys(dev_id, con_id);
} }
......
...@@ -106,7 +106,7 @@ static struct clk_lookup lcdif_lookups[] = { ...@@ -106,7 +106,7 @@ static struct clk_lookup lcdif_lookups[] = {
static struct clk_lookup gpmi_lookups[] = { static struct clk_lookup gpmi_lookups[] = {
{ .dev_id = "imx23-gpmi-nand", }, { .dev_id = "imx23-gpmi-nand", },
{ .dev_id = "8000c000.gpmi", }, { .dev_id = "8000c000.gpmi-nand", },
}; };
static const char *sel_pll[] __initconst = { "pll", "ref_xtal", }; static const char *sel_pll[] __initconst = { "pll", "ref_xtal", };
...@@ -189,6 +189,7 @@ int __init mx23_clocks_init(void) ...@@ -189,6 +189,7 @@ int __init mx23_clocks_init(void)
} }
clk_register_clkdev(clks[clk32k], NULL, "timrot"); clk_register_clkdev(clks[clk32k], NULL, "timrot");
clk_register_clkdev(clks[pwm], NULL, "80064000.pwm");
clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups));
clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups));
clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups));
......
...@@ -112,11 +112,11 @@ static void __init clk_misc_init(void) ...@@ -112,11 +112,11 @@ static void __init clk_misc_init(void)
/* /*
* 480 MHz seems too high to be ssp clock source directly, * 480 MHz seems too high to be ssp clock source directly,
* so set frac0 to get a 288 MHz ref_io0. * so set frac0 to get a 288 MHz ref_io0 and ref_io1.
*/ */
val = readl_relaxed(FRAC0); val = readl_relaxed(FRAC0);
val &= ~(0x3f << BP_FRAC0_IO0FRAC); val &= ~((0x3f << BP_FRAC0_IO0FRAC) | (0x3f << BP_FRAC0_IO1FRAC));
val |= 30 << BP_FRAC0_IO0FRAC; val |= (30 << BP_FRAC0_IO0FRAC) | (30 << BP_FRAC0_IO1FRAC);
writel_relaxed(val, FRAC0); writel_relaxed(val, FRAC0);
} }
...@@ -174,7 +174,7 @@ static struct clk_lookup lcdif_lookups[] = { ...@@ -174,7 +174,7 @@ static struct clk_lookup lcdif_lookups[] = {
static struct clk_lookup gpmi_lookups[] = { static struct clk_lookup gpmi_lookups[] = {
{ .dev_id = "imx28-gpmi-nand", }, { .dev_id = "imx28-gpmi-nand", },
{ .dev_id = "8000c000.gpmi", }, { .dev_id = "8000c000.gpmi-nand", },
}; };
static struct clk_lookup fec_lookups[] = { static struct clk_lookup fec_lookups[] = {
...@@ -314,6 +314,7 @@ int __init mx28_clocks_init(void) ...@@ -314,6 +314,7 @@ int __init mx28_clocks_init(void)
clk_register_clkdev(clks[clk32k], NULL, "timrot"); clk_register_clkdev(clks[clk32k], NULL, "timrot");
clk_register_clkdev(clks[enet_out], NULL, "enet_out"); clk_register_clkdev(clks[enet_out], NULL, "enet_out");
clk_register_clkdev(clks[pwm], NULL, "80064000.pwm");
clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups)); clk_register_clkdevs(clks[hbus], hbus_lookups, ARRAY_SIZE(hbus_lookups));
clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups)); clk_register_clkdevs(clks[xbus], xbus_lookups, ARRAY_SIZE(xbus_lookups));
clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups)); clk_register_clkdevs(clks[uart], uart_lookups, ARRAY_SIZE(uart_lookups));
...@@ -328,6 +329,10 @@ int __init mx28_clocks_init(void) ...@@ -328,6 +329,10 @@ int __init mx28_clocks_init(void)
clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups)); clk_register_clkdevs(clks[fec], fec_lookups, ARRAY_SIZE(fec_lookups));
clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups)); clk_register_clkdevs(clks[can0], can0_lookups, ARRAY_SIZE(can0_lookups));
clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups)); clk_register_clkdevs(clks[can1], can1_lookups, ARRAY_SIZE(can1_lookups));
clk_register_clkdev(clks[usb0_pwr], NULL, "8007c000.usbphy");
clk_register_clkdev(clks[usb1_pwr], NULL, "8007e000.usbphy");
clk_register_clkdev(clks[usb0], NULL, "80080000.usb");
clk_register_clkdev(clks[usb1], NULL, "80090000.usb");
for (i = 0; i < ARRAY_SIZE(clks_init_on); i++) for (i = 0; i < ARRAY_SIZE(clks_init_on); i++)
clk_prepare_enable(clks[clks_init_on[i]]); clk_prepare_enable(clks[clks_init_on[i]]);
......
# Makefile for Versatile-specific clocks
obj-$(CONFIG_ICST) += clk-icst.o
obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o
/*
* Driver for the ICST307 VCO clock found in the ARM Reference designs.
* We wrap the custom interface from <asm/hardware/icst.h> into the generic
* clock framework.
*
* TODO: when all ARM reference designs are migrated to generic clocks, the
* ICST clock code from the ARM tree should probably be merged into this
* file.
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include "clk-icst.h"
/**
* struct clk_icst - ICST VCO clock wrapper
* @hw: corresponding clock hardware entry
* @params: parameters for this ICST instance
* @rate: current rate
* @setvco: function to commit ICST settings to hardware
*/
struct clk_icst {
struct clk_hw hw;
const struct icst_params *params;
unsigned long rate;
struct icst_vco (*getvco)(void);
void (*setvco)(struct icst_vco);
};
#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
static unsigned long icst_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;
vco = icst->getvco();
icst->rate = icst_hz(icst->params, vco);
return icst->rate;
}
static long icst_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;
vco = icst_hz_to_vco(icst->params, rate);
return icst_hz(icst->params, vco);
}
static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_icst *icst = to_icst(hw);
struct icst_vco vco;
vco = icst_hz_to_vco(icst->params, rate);
icst->rate = icst_hz(icst->params, vco);
icst->setvco(vco);
return 0;
}
static const struct clk_ops icst_ops = {
.recalc_rate = icst_recalc_rate,
.round_rate = icst_round_rate,
.set_rate = icst_set_rate,
};
struct clk * __init icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc)
{
struct clk *clk;
struct clk_icst *icst;
struct clk_init_data init;
icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
if (!icst) {
pr_err("could not allocate ICST clock!\n");
return ERR_PTR(-ENOMEM);
}
init.name = "icst";
init.ops = &icst_ops;
init.flags = CLK_IS_ROOT;
init.parent_names = NULL;
init.num_parents = 0;
icst->hw.init = &init;
icst->params = desc->params;
icst->getvco = desc->getvco;
icst->setvco = desc->setvco;
clk = clk_register(dev, &icst->hw);
if (IS_ERR(clk))
kfree(icst);
return clk;
}
#include <asm/hardware/icst.h>
struct clk_icst_desc {
const struct icst_params *params;
struct icst_vco (*getvco)(void);
void (*setvco)(struct icst_vco);
};
struct clk *icst_clk_register(struct device *dev,
const struct clk_icst_desc *desc);
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/clk-provider.h>
#include <mach/hardware.h>
#include <mach/platform.h>
#include "clk-icst.h"
/*
* Implementation of the ARM Integrator/AP and Integrator/CP clock tree.
* Inspired by portions of:
* plat-versatile/clock.c and plat-versatile/include/plat/clock.h
*/
#define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
#define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c)
/**
* cp_auxvco_get() - get ICST VCO settings for the Integrator/CP
* @vco: ICST VCO parameters to update with hardware status
*/
static struct icst_vco cp_auxvco_get(void)
{
u32 val;
struct icst_vco vco;
val = readl(CM_AUXOSC);
vco.v = val & 0x1ff;
vco.r = (val >> 9) & 0x7f;
vco.s = (val >> 16) & 03;
return vco;
}
/**
* cp_auxvco_set() - commit changes to Integrator/CP ICST VCO
* @vco: ICST VCO parameters to commit
*/
static void cp_auxvco_set(struct icst_vco vco)
{
u32 val;
val = readl(CM_AUXOSC) & ~0x7ffff;
val |= vco.v | (vco.r << 9) | (vco.s << 16);
/* This magic unlocks the CM VCO so it can be controlled */
writel(0xa05f, CM_LOCK);
writel(val, CM_AUXOSC);
/* This locks the CM again */
writel(0, CM_LOCK);
}
static const struct icst_params cp_auxvco_params = {
.ref = 24000000,
.vco_max = ICST525_VCO_MAX_5V,
.vco_min = ICST525_VCO_MIN,
.vd_min = 8,
.vd_max = 263,
.rd_min = 3,
.rd_max = 65,
.s2div = icst525_s2div,
.idx2s = icst525_idx2s,
};
static const struct clk_icst_desc __initdata cp_icst_desc = {
.params = &cp_auxvco_params,
.getvco = cp_auxvco_get,
.setvco = cp_auxvco_set,
};
/*
* integrator_clk_init() - set up the integrator clock tree
* @is_cp: pass true if it's the Integrator/CP else AP is assumed
*/
void __init integrator_clk_init(bool is_cp)
{
struct clk *clk;
/* APB clock dummy */
clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0);
clk_register_clkdev(clk, "apb_pclk", NULL);
/* UART reference clock */
clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
14745600);
clk_register_clkdev(clk, NULL, "uart0");
clk_register_clkdev(clk, NULL, "uart1");
if (is_cp)
clk_register_clkdev(clk, NULL, "mmci");
/* 24 MHz clock */
clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT,
24000000);
clk_register_clkdev(clk, NULL, "kmi0");
clk_register_clkdev(clk, NULL, "kmi1");
if (!is_cp)
clk_register_clkdev(clk, NULL, "ap_timer");
if (!is_cp)
return;
/* 1 MHz clock */
clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT,
1000000);
clk_register_clkdev(clk, NULL, "sp804");
/* ICST VCO clock used on the Integrator/CP CLCD */
clk = icst_clk_register(NULL, &cp_icst_desc);
clk_register_clkdev(clk, NULL, "clcd");
}
...@@ -64,7 +64,7 @@ struct clk { ...@@ -64,7 +64,7 @@ struct clk {
.parent_names = _parent_names, \ .parent_names = _parent_names, \
.num_parents = ARRAY_SIZE(_parent_names), \ .num_parents = ARRAY_SIZE(_parent_names), \
.parents = _parents, \ .parents = _parents, \
.flags = _flags, \ .flags = _flags | CLK_IS_BASIC, \
} }
#define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \ #define DEFINE_CLK_FIXED_RATE(_name, _flags, _rate, \
...@@ -103,9 +103,9 @@ struct clk { ...@@ -103,9 +103,9 @@ struct clk {
DEFINE_CLK(_name, clk_gate_ops, _flags, \ DEFINE_CLK(_name, clk_gate_ops, _flags, \
_name##_parent_names, _name##_parents); _name##_parent_names, _name##_parents);
#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \ #define _DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \ _flags, _reg, _shift, _width, \
_divider_flags, _lock) \ _divider_flags, _table, _lock) \
static struct clk _name; \ static struct clk _name; \
static const char *_name##_parent_names[] = { \ static const char *_name##_parent_names[] = { \
_parent_name, \ _parent_name, \
...@@ -121,11 +121,27 @@ struct clk { ...@@ -121,11 +121,27 @@ struct clk {
.shift = _shift, \ .shift = _shift, \
.width = _width, \ .width = _width, \
.flags = _divider_flags, \ .flags = _divider_flags, \
.table = _table, \
.lock = _lock, \ .lock = _lock, \
}; \ }; \
DEFINE_CLK(_name, clk_divider_ops, _flags, \ DEFINE_CLK(_name, clk_divider_ops, _flags, \
_name##_parent_names, _name##_parents); _name##_parent_names, _name##_parents);
#define DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, _lock) \
_DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, NULL, _lock)
#define DEFINE_CLK_DIVIDER_TABLE(_name, _parent_name, \
_parent_ptr, _flags, _reg, \
_shift, _width, _divider_flags, \
_table, _lock) \
_DEFINE_CLK_DIVIDER(_name, _parent_name, _parent_ptr, \
_flags, _reg, _shift, _width, \
_divider_flags, _table, _lock) \
#define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \ #define DEFINE_CLK_MUX(_name, _parent_names, _parents, _flags, \
_reg, _shift, _width, \ _reg, _shift, _width, \
_mux_flags, _lock) \ _mux_flags, _lock) \
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */ #define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */
#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ #define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
#define CLK_IS_ROOT BIT(4) /* root clk, has no parent */ #define CLK_IS_ROOT BIT(4) /* root clk, has no parent */
#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
struct clk_hw; struct clk_hw;
...@@ -143,7 +144,7 @@ struct clk_init_data { ...@@ -143,7 +144,7 @@ struct clk_init_data {
*/ */
struct clk_hw { struct clk_hw {
struct clk *clk; struct clk *clk;
struct clk_init_data *init; const struct clk_init_data *init;
}; };
/* /*
...@@ -171,6 +172,8 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ...@@ -171,6 +172,8 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
unsigned long fixed_rate); unsigned long fixed_rate);
void of_fixed_clk_setup(struct device_node *np);
/** /**
* struct clk_gate - gating clock * struct clk_gate - gating clock
* *
...@@ -203,6 +206,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name, ...@@ -203,6 +206,11 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
void __iomem *reg, u8 bit_idx, void __iomem *reg, u8 bit_idx,
u8 clk_gate_flags, spinlock_t *lock); u8 clk_gate_flags, spinlock_t *lock);
struct clk_div_table {
unsigned int val;
unsigned int div;
};
/** /**
* struct clk_divider - adjustable divider clock * struct clk_divider - adjustable divider clock
* *
...@@ -210,6 +218,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name, ...@@ -210,6 +218,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
* @reg: register containing the divider * @reg: register containing the divider
* @shift: shift to the divider bit field * @shift: shift to the divider bit field
* @width: width of the divider bit field * @width: width of the divider bit field
* @table: array of value/divider pairs, last entry should have div = 0
* @lock: register lock * @lock: register lock
* *
* Clock with an adjustable divider affecting its output frequency. Implements * Clock with an adjustable divider affecting its output frequency. Implements
...@@ -229,6 +238,7 @@ struct clk_divider { ...@@ -229,6 +238,7 @@ struct clk_divider {
u8 shift; u8 shift;
u8 width; u8 width;
u8 flags; u8 flags;
const struct clk_div_table *table;
spinlock_t *lock; spinlock_t *lock;
}; };
...@@ -240,6 +250,11 @@ struct clk *clk_register_divider(struct device *dev, const char *name, ...@@ -240,6 +250,11 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, spinlock_t *lock); u8 clk_divider_flags, spinlock_t *lock);
struct clk *clk_register_divider_table(struct device *dev, const char *name,
const char *parent_name, unsigned long flags,
void __iomem *reg, u8 shift, u8 width,
u8 clk_divider_flags, const struct clk_div_table *table,
spinlock_t *lock);
/** /**
* struct clk_mux - multiplexer clock * struct clk_mux - multiplexer clock
...@@ -334,5 +349,19 @@ void __clk_unprepare(struct clk *clk); ...@@ -334,5 +349,19 @@ void __clk_unprepare(struct clk *clk);
void __clk_reparent(struct clk *clk, struct clk *new_parent); void __clk_reparent(struct clk *clk, struct clk *new_parent);
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate); unsigned long __clk_round_rate(struct clk *clk, unsigned long rate);
struct of_device_id;
typedef void (*of_clk_init_cb_t)(struct device_node *);
int of_clk_add_provider(struct device_node *np,
struct clk *(*clk_src_get)(struct of_phandle_args *args,
void *data),
void *data);
void of_clk_del_provider(struct device_node *np);
struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
void *data);
const char *of_clk_get_parent_name(struct device_node *np, int index);
void of_clk_init(const struct of_device_id *matches);
#endif /* CONFIG_COMMON_CLK */ #endif /* CONFIG_COMMON_CLK */
#endif /* CLK_PROVIDER_H */ #endif /* CLK_PROVIDER_H */
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#ifndef __LINUX_CLK_H #ifndef __LINUX_CLK_H
#define __LINUX_CLK_H #define __LINUX_CLK_H
#include <linux/err.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/notifier.h> #include <linux/notifier.h>
...@@ -310,4 +311,23 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id); ...@@ -310,4 +311,23 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id);
int clk_add_alias(const char *alias, const char *alias_dev_name, char *id, int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
struct device *dev); struct device *dev);
struct device_node;
struct of_phandle_args;
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get(struct device_node *np, int index);
struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec);
#else
static inline struct clk *of_clk_get(struct device_node *np, int index)
{
return ERR_PTR(-ENOENT);
}
static inline struct clk *of_clk_get_by_name(struct device_node *np,
const char *name)
{
return ERR_PTR(-ENOENT);
}
#endif
#endif #endif
void integrator_clk_init(bool is_cp);
void __init u300_clk_init(void __iomem *base);
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