diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 16:40:57 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-24 16:40:57 -0700 |
commit | 9161c3b796a2841a9a7be3d9c9dd121269ce90e8 (patch) | |
tree | 4920a191c4a2eecae1a4e055af7e967f1e769714 /arch/arm | |
parent | 97027da6adf2e24a4e8d3d9c0668da3006b29971 (diff) | |
parent | 137f8a7213d80c1388ca48280c1ef0856b6fec30 (diff) |
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
...
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/Kconfig | 8 | ||||
-rw-r--r-- | arch/arm/boot/dts/highbank.dts | 91 | ||||
-rw-r--r-- | arch/arm/mach-highbank/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-highbank/clock.c | 62 | ||||
-rw-r--r-- | arch/arm/mach-highbank/highbank.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-integrator/core.c | 55 | ||||
-rw-r--r-- | arch/arm/mach-integrator/include/mach/clkdev.h | 26 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-integrator/integrator_cp.c | 69 | ||||
-rw-r--r-- | arch/arm/mach-u300/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/mach-u300/clock.c | 1504 | ||||
-rw-r--r-- | arch/arm/mach-u300/clock.h | 50 | ||||
-rw-r--r-- | arch/arm/mach-u300/core.c | 21 | ||||
-rw-r--r-- | arch/arm/mach-u300/timer.c | 2 |
14 files changed, 133 insertions, 1774 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c7e6d208fa8..b25c9d3c379 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -273,8 +273,8 @@ config ARCH_INTEGRATOR bool "ARM Ltd. Integrator family" select ARM_AMBA select ARCH_HAS_CPUFREQ - select CLKDEV_LOOKUP - select HAVE_MACH_CLKDEV + select COMMON_CLK + select CLK_VERSATILE select HAVE_TCM select ICST select GENERIC_CLOCKEVENTS @@ -336,6 +336,7 @@ config ARCH_VEXPRESS select ICST select NO_IOPORT select PLAT_VERSATILE + select PLAT_VERSATILE_CLOCK select PLAT_VERSATILE_CLCD select REGULATOR_FIXED_VOLTAGE if REGULATOR help @@ -372,6 +373,7 @@ config ARCH_HIGHBANK select ARM_TIMER_SP804 select CACHE_L2X0 select CLKDEV_LOOKUP + select COMMON_CLK select CPU_V7 select GENERIC_CLOCKEVENTS select HAVE_ARM_SCU @@ -929,7 +931,7 @@ config ARCH_U300 select ARM_VIC select GENERIC_CLOCKEVENTS select CLKDEV_LOOKUP - select HAVE_MACH_CLKDEV + select COMMON_CLK select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB help diff --git a/arch/arm/boot/dts/highbank.dts b/arch/arm/boot/dts/highbank.dts index 83e72294aef..2e1cfa00c25 100644 --- a/arch/arm/boot/dts/highbank.dts +++ b/arch/arm/boot/dts/highbank.dts @@ -1,5 +1,5 @@ /* - * Copyright 2011 Calxeda, Inc. + * 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, @@ -24,6 +24,7 @@ compatible = "calxeda,highbank"; #address-cells = <1>; #size-cells = <1>; + clock-ranges; cpus { #address-cells = <1>; @@ -33,24 +34,32 @@ compatible = "arm,cortex-a9"; reg = <0>; next-level-cache = <&L2>; + clocks = <&a9pll>; + clock-names = "cpu"; }; cpu@1 { compatible = "arm,cortex-a9"; reg = <1>; next-level-cache = <&L2>; + clocks = <&a9pll>; + clock-names = "cpu"; }; cpu@2 { compatible = "arm,cortex-a9"; reg = <2>; next-level-cache = <&L2>; + clocks = <&a9pll>; + clock-names = "cpu"; }; cpu@3 { compatible = "arm,cortex-a9"; reg = <3>; next-level-cache = <&L2>; + clocks = <&a9pll>; + clock-names = "cpu"; }; }; @@ -75,12 +84,14 @@ compatible = "arm,cortex-a9-twd-timer"; reg = <0xfff10600 0x20>; interrupts = <1 13 0xf01>; + clocks = <&a9periphclk>; }; watchdog@fff10620 { compatible = "arm,cortex-a9-twd-wdt"; reg = <0xfff10620 0x20>; interrupts = <1 14 0xf01>; + clocks = <&a9periphclk>; }; intc: interrupt-controller@fff11000 { @@ -116,12 +127,15 @@ compatible = "calxeda,hb-sdhci"; reg = <0xffe0e000 0x1000>; interrupts = <0 90 4>; + clocks = <&eclk>; }; ipc@fff20000 { compatible = "arm,pl320", "arm,primecell"; reg = <0xfff20000 0x1000>; interrupts = <0 7 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; gpioe: gpio@fff30000 { @@ -130,6 +144,8 @@ gpio-controller; reg = <0xfff30000 0x1000>; interrupts = <0 14 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; gpiof: gpio@fff31000 { @@ -138,6 +154,8 @@ gpio-controller; reg = <0xfff31000 0x1000>; interrupts = <0 15 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; gpiog: gpio@fff32000 { @@ -146,6 +164,8 @@ gpio-controller; reg = <0xfff32000 0x1000>; interrupts = <0 16 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; gpioh: gpio@fff33000 { @@ -154,24 +174,32 @@ gpio-controller; reg = <0xfff33000 0x1000>; interrupts = <0 17 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; timer { compatible = "arm,sp804", "arm,primecell"; reg = <0xfff34000 0x1000>; interrupts = <0 18 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; rtc@fff35000 { compatible = "arm,pl031", "arm,primecell"; reg = <0xfff35000 0x1000>; interrupts = <0 19 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; serial@fff36000 { compatible = "arm,pl011", "arm,primecell"; reg = <0xfff36000 0x1000>; interrupts = <0 20 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; smic@fff3a000 { @@ -186,12 +214,73 @@ sregs@fff3c000 { compatible = "calxeda,hb-sregs"; 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 { compatible = "arm,pl330", "arm,primecell"; reg = <0xfff3d000 0x1000>; interrupts = <0 92 4>; + clocks = <&pclk>; + clock-names = "apb_pclk"; }; ethernet@fff50000 { diff --git a/arch/arm/mach-highbank/Makefile b/arch/arm/mach-highbank/Makefile index ded4652ada8..3ec8bdd25d0 100644 --- a/arch/arm/mach-highbank/Makefile +++ b/arch/arm/mach-highbank/Makefile @@ -1,4 +1,4 @@ -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) AFLAGS_smc.o :=-Wa,-march=armv7-a$(plus_sec) diff --git a/arch/arm/mach-highbank/clock.c b/arch/arm/mach-highbank/clock.c deleted file mode 100644 index c25a2ae4fde..00000000000 --- a/arch/arm/mach-highbank/clock.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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)); -} diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c index 8777612b1a4..d75b0a78d88 100644 --- a/arch/arm/mach-highbank/highbank.c +++ b/arch/arm/mach-highbank/highbank.c @@ -105,6 +105,11 @@ static void __init highbank_init_irq(void) #endif } +static struct clk_lookup lookup = { + .dev_id = "sp804", + .con_id = NULL, +}; + static void __init highbank_timer_init(void) { int irq; @@ -122,6 +127,8 @@ static void __init highbank_timer_init(void) irq = irq_of_parse_and_map(np, 0); highbank_clocks_init(); + lookup.clk = of_clk_get(np, 0); + clkdev_add(&lookup); sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1"); sp804_clockevents_init(timer_base, irq, "timer0"); diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c index eaf6c6366ff..ebf680bebdf 100644 --- a/arch/arm/mach-integrator/core.c +++ b/arch/arm/mach-integrator/core.c @@ -21,7 +21,6 @@ #include <linux/amba/bus.h> #include <linux/amba/serial.h> #include <linux/io.h> -#include <linux/clkdev.h> #include <mach/hardware.h> #include <mach/platform.h> @@ -41,17 +40,17 @@ static struct amba_pl010_data integrator_uart_data; #define KMI0_IRQ { IRQ_KMIINT0 } #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); -static AMBA_APB_DEVICE(uart0, "mb:16", 0, +static AMBA_APB_DEVICE(uart0, "uart0", 0, 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); -static AMBA_APB_DEVICE(kmi0, "mb:18", 0, KMI0_BASE, KMI0_IRQ, NULL); -static AMBA_APB_DEVICE(kmi1, "mb:19", 0, KMI1_BASE, KMI1_IRQ, NULL); +static AMBA_APB_DEVICE(kmi0, "kmi0", 0, KMI0_BASE, KMI0_IRQ, NULL); +static AMBA_APB_DEVICE(kmi1, "kmi1", 0, KMI1_BASE, KMI1_IRQ, NULL); static struct amba_device *amba_devs[] __initdata = { &rtc_device, @@ -61,50 +60,6 @@ static struct amba_device *amba_devs[] __initdata = { &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) { int i; diff --git a/arch/arm/mach-integrator/include/mach/clkdev.h b/arch/arm/mach-integrator/include/mach/clkdev.h deleted file mode 100644 index bfe07679fae..00000000000 --- a/arch/arm/mach-integrator/include/mach/clkdev.h +++ /dev/null @@ -1,26 +0,0 @@ -#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 diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index c857501c578..7b1055c8e0b 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -33,6 +33,7 @@ #include <linux/io.h> #include <linux/mtd/physmap.h> #include <linux/clk.h> +#include <linux/platform_data/clk-integrator.h> #include <video/vga.h> #include <mach/hardware.h> @@ -174,6 +175,7 @@ static void __init ap_init_irq(void) fpga_irq_init(VA_IC_BASE, "SC", IRQ_PIC_START, -1, INTEGRATOR_SC_VALID_INT, NULL); + integrator_clk_init(false); } #ifdef CONFIG_PM @@ -440,6 +442,10 @@ static void integrator_clockevent_init(unsigned long inrate) 0xffffU); } +void __init ap_init_early(void) +{ +} + /* * Set up timer(s). */ @@ -471,7 +477,7 @@ MACHINE_START(INTEGRATOR, "ARM-Integrator") .reserve = integrator_reserve, .map_io = ap_map_io, .nr_irqs = NR_IRQS_INTEGRATOR_AP, - .init_early = integrator_init_early, + .init_early = ap_init_early, .init_irq = ap_init_irq, .handle_irq = fpga_handle_irq, .timer = &ap_timer, diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index a56c5360893..82d5c837cc7 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -21,8 +21,8 @@ #include <linux/amba/mmci.h> #include <linux/io.h> #include <linux/gfp.h> -#include <linux/clkdev.h> #include <linux/mtd/physmap.h> +#include <linux/platform_data/clk-integrator.h> #include <mach/hardware.h> #include <mach/platform.h> @@ -171,65 +171,10 @@ static void __init intcp_init_irq(void) fpga_irq_init(INTCP_VA_SIC_BASE, "SIC", IRQ_SIC_START, 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. */ static int intcp_flash_init(struct platform_device *dev) @@ -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_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); -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); @@ -393,7 +338,7 @@ static struct clcd_board clcd_data = { .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); 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) { - clkdev_add_table(cp_lookups, ARRAY_SIZE(cp_lookups)); - - integrator_init_early(); - #ifdef CONFIG_PLAT_VERSATILE_SCHED_CLOCK versatile_sched_clock_init(REFCOUNTER, 24000000); #endif diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile index fd3a5c382f4..7e47d37aeb0 100644 --- a/arch/arm/mach-u300/Makefile +++ b/arch/arm/mach-u300/Makefile @@ -2,7 +2,7 @@ # Makefile for the linux kernel, U300 machine. # -obj-y := core.o clock.o timer.o +obj-y := core.o timer.o obj-m := obj-n := obj- := diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c deleted file mode 100644 index 5535dd0a78c..00000000000 --- a/arch/arm/mach-u300/clock.c +++ /dev/null @@ -1,1504 +0,0 @@ -/* - * - * 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_CC |