aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-u300
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2009-06-14 11:01:44 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-06-14 11:01:44 +0100
commitb7c11ec9f1c9f4272f032215ddb0b65d64b22ecc (patch)
treec65b81ef9ae5076d2137034accfa2610f45a13de /arch/arm/mach-u300
parent06099961002a813324d057a91695af7c72939da6 (diff)
parent7666c17e2b0986a079da46122d8658544416c2cf (diff)
Merge branch 'u300' into devel
Conflicts: arch/arm/Makefile Updates: arch/arm/mach-u300/core.c arch/arm/mach-u300/timer.c
Diffstat (limited to 'arch/arm/mach-u300')
-rw-r--r--arch/arm/mach-u300/Kconfig105
-rw-r--r--arch/arm/mach-u300/Makefile11
-rw-r--r--arch/arm/mach-u300/Makefile.boot15
-rw-r--r--arch/arm/mach-u300/clock.c1487
-rw-r--r--arch/arm/mach-u300/clock.h53
-rw-r--r--arch/arm/mach-u300/core.c649
-rw-r--r--arch/arm/mach-u300/gpio.c703
-rw-r--r--arch/arm/mach-u300/include/mach/clkdev.h7
-rw-r--r--arch/arm/mach-u300/include/mach/debug-macro.S22
-rw-r--r--arch/arm/mach-u300/include/mach/entry-macro.S40
-rw-r--r--arch/arm/mach-u300/include/mach/gpio.h290
-rw-r--r--arch/arm/mach-u300/include/mach/hardware.h5
-rw-r--r--arch/arm/mach-u300/include/mach/io.h20
-rw-r--r--arch/arm/mach-u300/include/mach/irqs.h114
-rw-r--r--arch/arm/mach-u300/include/mach/memory.h42
-rw-r--r--arch/arm/mach-u300/include/mach/platform.h19
-rw-r--r--arch/arm/mach-u300/include/mach/syscon.h644
-rw-r--r--arch/arm/mach-u300/include/mach/system.h42
-rw-r--r--arch/arm/mach-u300/include/mach/timex.h17
-rw-r--r--arch/arm/mach-u300/include/mach/u300-regs.h187
-rw-r--r--arch/arm/mach-u300/include/mach/uncompress.h46
-rw-r--r--arch/arm/mach-u300/include/mach/vmalloc.h12
-rw-r--r--arch/arm/mach-u300/mmc.c216
-rw-r--r--arch/arm/mach-u300/mmc.h18
-rw-r--r--arch/arm/mach-u300/padmux.c58
-rw-r--r--arch/arm/mach-u300/padmux.h19
-rw-r--r--arch/arm/mach-u300/timer.c422
-rw-r--r--arch/arm/mach-u300/u300.c55
28 files changed, 5318 insertions, 0 deletions
diff --git a/arch/arm/mach-u300/Kconfig b/arch/arm/mach-u300/Kconfig
new file mode 100644
index 00000000000..337b9aabce4
--- /dev/null
+++ b/arch/arm/mach-u300/Kconfig
@@ -0,0 +1,105 @@
+if ARCH_U300
+
+menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
+
+comment "ST-Ericsson Mobile Platform Products"
+
+config MACH_U300
+ bool "U300"
+
+comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
+
+choice
+ prompt "U300/U330/U335/U365 system type"
+ default MACH_U300_BS2X
+ ---help---
+ You need to select the target system, i.e. the
+ U300/U330/U335/U365 board that you want to compile your kernel
+ for.
+
+config MACH_U300_BS2X
+ bool "S26/S26/B25/B26 Test Products"
+ depends on MACH_U300
+ help
+ Select this if you're developing on the
+ S26/S25 test products. (Also works on
+ B26/B25 big boards.)
+
+config MACH_U300_BS330
+ bool "S330/B330 Test Products"
+ depends on MACH_U300
+ help
+ Select this if you're developing on the
+ S330/B330 test products.
+
+config MACH_U300_BS335
+ bool "S335/B335 Test Products"
+ depends on MACH_U300
+ help
+ Select this if you're developing on the
+ S335/B335 test products.
+
+config MACH_U300_BS365
+ bool "S365/B365 Test Products"
+ depends on MACH_U300
+ help
+ Select this if you're developing on the
+ S365/B365 test products.
+
+endchoice
+
+choice
+ prompt "Memory configuration"
+ default MACH_U300_SINGLE_RAM
+ ---help---
+ You have to config the kernel according to the physical memory
+ configuration.
+
+config MACH_U300_SINGLE_RAM
+ bool "Single RAM"
+ help
+ Select this if you want support for Single RAM phones.
+
+config MACH_U300_DUAL_RAM
+ bool "Dual RAM"
+ help
+ Select this if you want support for Dual RAM phones.
+ This is two RAM memorys on different EMIFs.
+endchoice
+
+config U300_DEBUG
+ bool "Debug support for U300"
+ depends on PM
+ help
+ Debug support for U300 in sysfs, procfs etc.
+
+config MACH_U300_SEMI_IS_SHARED
+ bool "The SEMI is used by both the access and application side"
+ depends on MACH_U300
+ help
+ This makes it possible to use the SEMI (Shared External
+ Memory Interface) from both from access and application
+ side.
+
+comment "All the settings below must match the bootloader's settings"
+
+config MACH_U300_ACCESS_MEM_SIZE
+ int "Access CPU memory allocation"
+ range 7 25
+ depends on MACH_U300_SINGLE_RAM
+ default 13
+ help
+ How much memory in MiB that the Access side CPU has allocated
+
+config MACH_U300_2MB_ALIGNMENT_FIX
+ bool "2MiB alignment fix"
+ depends on MACH_U300_SINGLE_RAM
+ default y
+ help
+ If yes and the Access side CPU has allocated an odd size in
+ MiB, this fix gives you one MiB extra that would otherwise be
+ lost due to Linux 2 MiB alignment policy.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-u300/Makefile b/arch/arm/mach-u300/Makefile
new file mode 100644
index 00000000000..24950e0df4b
--- /dev/null
+++ b/arch/arm/mach-u300/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux kernel, U300 machine.
+#
+
+obj-y := core.o clock.o timer.o gpio.o padmux.o
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_ARCH_U300) += u300.o
+obj-$(CONFIG_MMC) += mmc.o
diff --git a/arch/arm/mach-u300/Makefile.boot b/arch/arm/mach-u300/Makefile.boot
new file mode 100644
index 00000000000..6fbfc6ea2d3
--- /dev/null
+++ b/arch/arm/mach-u300/Makefile.boot
@@ -0,0 +1,15 @@
+# Note: the following conditions must always be true:
+# ZRELADDR == virt_to_phys(TEXTADDR)
+# PARAMS_PHYS must be within 4MB of ZRELADDR
+# INITRD_PHYS must be in RAM
+
+ifdef CONFIG_MACH_U300_SINGLE_RAM
+ zreladdr-y := 0x28E08000
+ params_phys-y := 0x28E00100
+else
+ zreladdr-y := 0x48008000
+ params_phys-y := 0x48000100
+endif
+
+# This isn't used.
+#initrd_phys-y := 0x29800000
diff --git a/arch/arm/mach-u300/clock.c b/arch/arm/mach-u300/clock.c
new file mode 100644
index 00000000000..5cd04d6751b
--- /dev/null
+++ b/arch/arm/mach-u300/clock.c
@@ -0,0 +1,1487 @@
+/*
+ *
+ * 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 <asm/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
+ * +- 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 noone 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 noone 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 apropriate 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,
+};
+
+/*
+ * 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,
+};
+
+static struct clk nandif_clk = {
+ .name = "NANDIF",
+ .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,
+};
+
+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,
+};
+
+#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,
+};
+
+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,
+};
+#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_SY