diff options
Diffstat (limited to 'arch/arm/mach-mx5')
57 files changed, 26289 insertions, 0 deletions
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig new file mode 100755 index 00000000..acac8d32 --- /dev/null +++ b/arch/arm/mach-mx5/Kconfig @@ -0,0 +1,263 @@ +if ARCH_MX503 || ARCH_MX51 +# ARCH_MX5/50/53 are left to mark places where prevent multi-soc in single +# image. So for most time, SOC_IMX50/51/53 should be used. + +config ARCH_MX5 + bool + +config ARCH_MX50 + bool + +config ARCH_MX53 + bool + +config SOC_IMX50 + bool + select CPU_V7 + select ARM_L1_CACHE_SHIFT_6 + select MXC_TZIC + select ARCH_MXC_IOMUX_V3 + select ARCH_MXC_AUDMUX_V2 + select ARCH_HAS_CPUFREQ + select ARCH_MX5 + select ARCH_MX50 + select ARCH_HAS_RNGC + +config SOC_IMX51 + bool + select CPU_V7 + select ARM_L1_CACHE_SHIFT_6 + select MXC_TZIC + select ARCH_MXC_IOMUX_V3 + select ARCH_MXC_AUDMUX_V2 + select ARCH_HAS_CPUFREQ + select ARCH_MX5 + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_MXC_PWM + select IMX_HAVE_PLATFORM_IMX_IPUV3 + select IMX_HAVE_PLATFORM_IMX_TVE + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_IIM + select IMX_HAVE_PLATFORM_IMX_SPDIF + +config SOC_IMX53 + bool + select CPU_V7 + select ARM_L1_CACHE_SHIFT_6 + select MXC_TZIC + select ARCH_MXC_IOMUX_V3 + select ARCH_MX5 + select ARCH_MX53 + select ARCH_HAS_CPUFREQ + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_MXC_PWM + select IMX_HAVE_PLATFORM_IMX_IPUV3 + select IMX_HAVE_PLATFORM_IMX_TVE + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_IIM + select IMX_HAVE_PLATFORM_LDB + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_IMX_ESAI + +if ARCH_MX50_SUPPORTED +#comment "i.MX50 machines:" + +config MACH_MX50_RDP + bool "Support MX50 reference design platform" + select SOC_IMX50 + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_GPMI_NFC + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX_DCP + select IMX_HAVE_PLATFORM_RANDOM_RNGC + select IMX_HAVE_PLATFORM_PERFMON + select IMX_HAVE_PLATFORM_IMX_PXP + select IMX_HAVE_PLATFORM_IMX_EPDC + help + Include support for MX50 reference design platform (RDP) board. This + includes specific configurations for the board and its peripherals. + +endif # ARCH_MX50_SUPPORTED + +if ARCH_MX51 +comment "i.MX51 machines:" + +config MACH_MX51_BABBAGE + bool "Support MX51 BABBAGE platforms" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for MX51 Babbage platform, also known as MX51EVK in + u-boot. This includes specific configurations for the board and its + peripherals. + +config MACH_MX51_3DS + bool "Support MX51PDK (3DS)" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_DEBUG_BOARD + help + Include support for MX51PDK (3DS) platform. This includes specific + configurations for the board and its peripherals. + +config MACH_EUKREA_CPUIMX51 + bool "Support Eukrea CPUIMX51 module" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for Eukrea CPUIMX51 platform. This includes + specific configurations for the module and its peripherals. + +choice + prompt "Baseboard" + depends on MACH_EUKREA_CPUIMX51 + default MACH_EUKREA_MBIMX51_BASEBOARD + +config MACH_EUKREA_MBIMX51_BASEBOARD + prompt "Eukrea MBIMX51 development board" + bool + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + help + This adds board specific devices that can be found on Eukrea's + MBIMX51 evaluation board. + +endchoice + +config MACH_EUKREA_CPUIMX51SD + bool "Support Eukrea CPUIMX51SD module" + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_NAND + help + Include support for Eukrea CPUIMX51SD platform. This includes + specific configurations for the module and its peripherals. + +choice + prompt "Baseboard" + depends on MACH_EUKREA_CPUIMX51SD + default MACH_EUKREA_MBIMXSD51_BASEBOARD + +config MACH_EUKREA_MBIMXSD51_BASEBOARD + prompt "Eukrea MBIMXSD development board" + bool + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + help + This adds board specific devices that can be found on Eukrea's + MBIMXSD evaluation board. + +endchoice + +config MX51_EFIKA_COMMON + bool + select SOC_IMX51 + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + +config MACH_MX51_EFIKAMX + bool "Support MX51 Genesi Efika MX nettop" + select MX51_EFIKA_COMMON + help + Include support for Genesi Efika MX nettop. This includes specific + configurations for the board and its peripherals. + +config MACH_MX51_EFIKASB + bool "Support MX51 Genesi Efika Smartbook" + select MX51_EFIKA_COMMON + help + Include support for Genesi Efika Smartbook. This includes specific + configurations for the board and its peripherals. + +endif # ARCH_MX51 + +if ARCH_MX53_SUPPORTED +comment "i.MX53 machines:" + +config MACH_MX53_EVK + bool "Support MX53 EVK platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_MXC_GPU + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_AHCI + help + Include support for MX53 EVK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_SMD + bool "Support MX53 SMD platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_MXC_GPU + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_IMX_SRTC + select IMX_HAVE_PLATFORM_AHCI + help + Include support for MX53 SMD platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_LOCO + bool "Support MX53 LOCO platforms" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX_SRTC + select IMX_HAVE_PLATFORM_MXC_GPU + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_AHCI + help + Include support for MX53 LOCO platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX53_ARD + bool "Support MX53 ARD platform" + select SOC_IMX53 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_GPU + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_AHCI + help + Include support for MX53 ARD platform. This includes specific + configurations for the board and its peripherals. +endif # ARCH_MX53_SUPPORTED + +config MACH_IMX_BLUETOOTH_RFKILL + tristate "i.MX Bluetooth rfkill interface support" + depends on RFKILL + ---help--- + Say Y to get the standard rfkill interface of Bluetooth +endif diff --git a/arch/arm/mach-mx5/Makefile b/arch/arm/mach-mx5/Makefile new file mode 100755 index 00000000..8dbcf863 --- /dev/null +++ b/arch/arm/mach-mx5/Makefile @@ -0,0 +1,28 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. +obj-y := cpu.o mm.o devices.o ehci.o bus_freq.o sdram_autogating.o \ +pm.o system.o suspend.o usb_dr.o usb_h1.o usb_h2.o cpu_regulator-mx5.o + +obj-$(CONFIG_SOC_IMX50) += clock_mx50.o mm-mx50.o mx50_wfi.o mx50_suspend.o mx50_freq.o mx50_ddr_freq.o +obj-$(CONFIG_SOC_IMX51) += clock.o +obj-$(CONFIG_SOC_IMX53) += clock.o + +obj-$(CONFIG_CPU_FREQ_IMX) += cpu_op-mx51.o cpu_op-mx53.o cpu_op-mx50.o +obj-$(CONFIG_MACH_MX51_BABBAGE) += board-mx51_babbage.o mx51_babbage_pmic_mc13892.o +obj-$(CONFIG_MACH_MX51_3DS) += board-mx51_3ds.o +obj-$(CONFIG_MACH_MX53_EVK) += board-mx53_evk.o +obj-$(CONFIG_MACH_MX53_SMD) += board-mx53_smd.o mx53_smd_pmic_da9053.o +obj-$(CONFIG_MACH_IMX_BLUETOOTH_RFKILL) += imx_bt_rfkill.o +obj-$(CONFIG_MACH_MX53_LOCO) += board-mx53_loco.o mx53_loco_pmic_da9053.o mx53_loco_pmic_mc34708.o +obj-$(CONFIG_MACH_MX53_ARD) += board-mx53_ard.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX51) += board-cpuimx51.o +obj-$(CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD) += eukrea_mbimx51-baseboard.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX51SD) += board-cpuimx51sd.o +obj-$(CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD) += eukrea_mbimxsd-baseboard.o +obj-$(CONFIG_MX51_EFIKA_COMMON) += mx51_efika.o +obj-$(CONFIG_MACH_MX51_EFIKAMX) += board-mx51_efikamx.o +obj-$(CONFIG_MACH_MX51_EFIKASB) += board-mx51_efikasb.o +obj-$(CONFIG_MACH_MX50_RDP) += board-mx50_rdp.o mx50_rdp_pmic_mc13892.o diff --git a/arch/arm/mach-mx5/Makefile.boot b/arch/arm/mach-mx5/Makefile.boot new file mode 100644 index 00000000..e928be1b --- /dev/null +++ b/arch/arm/mach-mx5/Makefile.boot @@ -0,0 +1,9 @@ + zreladdr-$(CONFIG_ARCH_MX50) := 0x70008000 +params_phys-$(CONFIG_ARCH_MX50) := 0x70000100 +initrd_phys-$(CONFIG_ARCH_MX50) := 0x70800000 + zreladdr-$(CONFIG_ARCH_MX51) := 0x90008000 +params_phys-$(CONFIG_ARCH_MX51) := 0x90000100 +initrd_phys-$(CONFIG_ARCH_MX51) := 0x90800000 + zreladdr-$(CONFIG_ARCH_MX53) := 0x70008000 +params_phys-$(CONFIG_ARCH_MX53) := 0x70000100 +initrd_phys-$(CONFIG_ARCH_MX53) := 0x70800000 diff --git a/arch/arm/mach-mx5/board-cpuimx51.c b/arch/arm/mach-mx5/board-cpuimx51.c new file mode 100644 index 00000000..4efa02ee --- /dev/null +++ b/arch/arm/mach-mx5/board-cpuimx51.c @@ -0,0 +1,304 @@ +/* + * + * Copyright (C) 2010 Eric Bénard <eric@eukrea.com> + * + * based on board-mx51_babbage.c which is + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> + +#include <mach/eukrea-baseboards.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx51.h" +#include "devices.h" + +#define CPUIMX51_USBH1_STP IMX_GPIO_NR(1, 27) +#define CPUIMX51_QUARTA_GPIO IMX_GPIO_NR(3, 28) +#define CPUIMX51_QUARTB_GPIO IMX_GPIO_NR(3, 25) +#define CPUIMX51_QUARTC_GPIO IMX_GPIO_NR(3, 26) +#define CPUIMX51_QUARTD_GPIO IMX_GPIO_NR(3, 27) +#define CPUIMX51_QUARTA_IRQ (MXC_INTERNAL_IRQS + CPUIMX51_QUARTA_GPIO) +#define CPUIMX51_QUARTB_IRQ (MXC_INTERNAL_IRQS + CPUIMX51_QUARTB_GPIO) +#define CPUIMX51_QUARTC_IRQ (MXC_INTERNAL_IRQS + CPUIMX51_QUARTC_GPIO) +#define CPUIMX51_QUARTD_IRQ (MXC_INTERNAL_IRQS + CPUIMX51_QUARTD_GPIO) +#define CPUIMX51_QUART_XTAL 14745600 +#define CPUIMX51_QUART_REGSHIFT 17 + +/* USB_CTRL_1 */ +#define MX51_USB_CTRL_1_OFFSET 0x10 +#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) + +#define MX51_USB_PLLDIV_12_MHZ 0x00 +#define MX51_USB_PLL_DIV_19_2_MHZ 0x01 +#define MX51_USB_PLL_DIV_24_MHZ 0x02 + +static struct plat_serial8250_port serial_platform_data[] = { + { + .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x400000), + .irq = CPUIMX51_QUARTA_IRQ, + .irqflags = IRQF_TRIGGER_HIGH, + .uartclk = CPUIMX51_QUART_XTAL, + .regshift = CPUIMX51_QUART_REGSHIFT, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x800000), + .irq = CPUIMX51_QUARTB_IRQ, + .irqflags = IRQF_TRIGGER_HIGH, + .uartclk = CPUIMX51_QUART_XTAL, + .regshift = CPUIMX51_QUART_REGSHIFT, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x1000000), + .irq = CPUIMX51_QUARTC_IRQ, + .irqflags = IRQF_TRIGGER_HIGH, + .uartclk = CPUIMX51_QUART_XTAL, + .regshift = CPUIMX51_QUART_REGSHIFT, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + .mapbase = (unsigned long)(MX51_CS1_BASE_ADDR + 0x2000000), + .irq = CPUIMX51_QUARTD_IRQ, + .irqflags = IRQF_TRIGGER_HIGH, + .uartclk = CPUIMX51_QUART_XTAL, + .regshift = CPUIMX51_QUART_REGSHIFT, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + } +}; + +static struct platform_device serial_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = serial_platform_data, + }, +}; + +static struct platform_device *devices[] __initdata = { + &serial_device, +}; + +static iomux_v3_cfg_t eukrea_cpuimx51_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + + /* I2C2 */ + MX51_PAD_GPIO1_2__I2C2_SCL, + MX51_PAD_GPIO1_3__I2C2_SDA, + MX51_PAD_NANDF_D10__GPIO3_30, + + /* QUART IRQ */ + MX51_PAD_NANDF_D15__GPIO3_25, + MX51_PAD_NANDF_D14__GPIO3_26, + MX51_PAD_NANDF_D13__GPIO3_27, + MX51_PAD_NANDF_D12__GPIO3_28, + + /* USB HOST1 */ + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + MX51_PAD_USBH1_STP__USBH1_STP, +}; + +static const struct mxc_nand_platform_data + eukrea_cpuimx51_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const +struct imxi2c_platform_data eukrea_cpuimx51_i2c_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info eukrea_cpuimx51_i2c_devices[] = { + { + I2C_BOARD_INFO("pcf8563", 0x51), + }, +}; + +/* This function is board specific as the bit mask for the plldiv will also +be different for other Freescale SoCs, thus a common bitmask is not +possible and cannot get place in /plat-mxc/ehci.c.*/ +static int initialize_otg_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* Set the PHY clock to 19.2MHz */ + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK; + v |= MX51_USB_PLL_DIV_19_2_MHZ; + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY); +} + +static int initialize_usbh1_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* The clock for the USBH1 ULPI port will come externally from the PHY. */ + v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET); + __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_ITC_NO_THRESHOLD); +} + +static struct mxc_usbh_platform_data dr_utmi_config = { + .init = initialize_otg_port, + .portsc = MXC_EHCI_UTMI_16BIT, +}; + +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, +}; + +static struct mxc_usbh_platform_data usbh1_config = { + .init = initialize_usbh1_port, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static int otg_mode_host; + +static int __init eukrea_cpuimx51_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", eukrea_cpuimx51_otg_mode); + +/* + * Board specific initialization. + */ +static void __init eukrea_cpuimx51_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads, + ARRAY_SIZE(eukrea_cpuimx51_pads)); + + imx51_add_imx_uart(0, &uart_pdata); + imx51_add_mxc_nand(&eukrea_cpuimx51_nand_board_info); + + gpio_request(CPUIMX51_QUARTA_GPIO, "quarta_irq"); + gpio_direction_input(CPUIMX51_QUARTA_GPIO); + gpio_free(CPUIMX51_QUARTA_GPIO); + gpio_request(CPUIMX51_QUARTB_GPIO, "quartb_irq"); + gpio_direction_input(CPUIMX51_QUARTB_GPIO); + gpio_free(CPUIMX51_QUARTB_GPIO); + gpio_request(CPUIMX51_QUARTC_GPIO, "quartc_irq"); + gpio_direction_input(CPUIMX51_QUARTC_GPIO); + gpio_free(CPUIMX51_QUARTC_GPIO); + gpio_request(CPUIMX51_QUARTD_GPIO, "quartd_irq"); + gpio_direction_input(CPUIMX51_QUARTD_GPIO); + gpio_free(CPUIMX51_QUARTD_GPIO); + + imx51_add_fec(NULL); + platform_add_devices(devices, ARRAY_SIZE(devices)); + + imx51_add_imx_i2c(1, &eukrea_cpuimx51_i2c_data); + i2c_register_board_info(1, eukrea_cpuimx51_i2c_devices, + ARRAY_SIZE(eukrea_cpuimx51_i2c_devices)); + + if (otg_mode_host) + mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + else { + initialize_otg_port(NULL); + mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + } + mxc_register_device(&mxc_usbh1_device, &usbh1_config); + +#ifdef CONFIG_MACH_EUKREA_MBIMX51_BASEBOARD + eukrea_mbimx51_baseboard_init(); +#endif +} + +static void __init eukrea_cpuimx51_timer_init(void) +{ + mx51_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mxc_timer = { + .init = eukrea_cpuimx51_timer_init, +}; + +MACHINE_START(EUKREA_CPUIMX51, "Eukrea CPUIMX51 Module") + /* Maintainer: Eric Bénard <eric@eukrea.com> */ + .boot_params = MX51_PHYS_OFFSET + 0x100, + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .timer = &mxc_timer, + .init_machine = eukrea_cpuimx51_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-cpuimx51sd.c b/arch/arm/mach-mx5/board-cpuimx51sd.c new file mode 100644 index 00000000..5ef25a59 --- /dev/null +++ b/arch/arm/mach-mx5/board-cpuimx51sd.c @@ -0,0 +1,338 @@ +/* + * + * Copyright (C) 2010 Eric Bénard <eric@eukrea.com> + * + * based on board-mx51_babbage.c which is + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/i2c/tsc2007.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/i2c-gpio.h> +#include <linux/spi/spi.h> +#include <linux/can/platform/mcp251x.h> + +#include <mach/eukrea-baseboards.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx51.h" +#include "devices.h" +#include "cpu_op-mx51.h" + +#define USBH1_RST IMX_GPIO_NR(2, 28) +#define ETH_RST IMX_GPIO_NR(2, 31) +#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 12) +#define CAN_IRQGPIO IMX_GPIO_NR(1, 1) +#define CAN_RST IMX_GPIO_NR(4, 15) +#define CAN_NCS IMX_GPIO_NR(4, 24) +#define CAN_RXOBF IMX_GPIO_NR(1, 4) +#define CAN_RX1BF IMX_GPIO_NR(1, 6) +#define CAN_TXORTS IMX_GPIO_NR(1, 7) +#define CAN_TX1RTS IMX_GPIO_NR(1, 8) +#define CAN_TX2RTS IMX_GPIO_NR(1, 9) +#define I2C_SCL IMX_GPIO_NR(4, 16) +#define I2C_SDA IMX_GPIO_NR(4, 17) + +/* USB_CTRL_1 */ +#define MX51_USB_CTRL_1_OFFSET 0x10 +#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) + +#define MX51_USB_PLLDIV_12_MHZ 0x00 +#define MX51_USB_PLL_DIV_19_2_MHZ 0x01 +#define MX51_USB_PLL_DIV_24_MHZ 0x02 + +static iomux_v3_cfg_t eukrea_cpuimx51sd_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + + /* USB HOST1 */ + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + MX51_PAD_USBH1_STP__USBH1_STP, + MX51_PAD_EIM_CS3__GPIO2_28, /* PHY nRESET */ + + /* FEC */ + MX51_PAD_EIM_DTACK__GPIO2_31, /* PHY nRESET */ + + /* HSI2C */ + MX51_PAD_I2C1_CLK__GPIO4_16, + MX51_PAD_I2C1_DAT__GPIO4_17, + + /* CAN */ + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI, + MX51_PAD_CSPI1_MISO__ECSPI1_MISO, + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK, + MX51_PAD_CSPI1_SS0__GPIO4_24, /* nCS */ + MX51_PAD_CSI2_PIXCLK__GPIO4_15, /* nReset */ + MX51_PAD_GPIO1_1__GPIO1_1, /* IRQ */ + MX51_PAD_GPIO1_4__GPIO1_4, /* Control signals */ + MX51_PAD_GPIO1_6__GPIO1_6, + MX51_PAD_GPIO1_7__GPIO1_7, + MX51_PAD_GPIO1_8__GPIO1_8, + MX51_PAD_GPIO1_9__GPIO1_9, + + /* Touchscreen */ + /* IRQ */ + _MX51_PAD_GPIO_NAND__GPIO_NAND | MUX_PAD_CTRL(PAD_CTL_PUS_22K_UP | + PAD_CTL_PKE | PAD_CTL_SRE_FAST | + PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS), +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct tsc2007_platform_data tsc2007_info = { + .model = 2007, + .x_plate_ohms = 180, +}; + +static struct i2c_board_info eukrea_cpuimx51sd_i2c_devices[] = { + { + I2C_BOARD_INFO("pcf8563", 0x51), + }, { + I2C_BOARD_INFO("tsc2007", 0x49), + .type = "tsc2007", + .platform_data = &tsc2007_info, + .irq = gpio_to_irq(TSC2007_IRQGPIO), + }, +}; + +static const struct mxc_nand_platform_data + eukrea_cpuimx51sd_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +/* This function is board specific as the bit mask for the plldiv will also +be different for other Freescale SoCs, thus a common bitmask is not +possible and cannot get place in /plat-mxc/ehci.c.*/ +static int initialize_otg_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* Set the PHY clock to 19.2MHz */ + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK; + v |= MX51_USB_PLL_DIV_19_2_MHZ; + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY); +} + +static int initialize_usbh1_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* The clock for the USBH1 ULPI port will come from the PHY. */ + v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET); + __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, + usbother_base + MX51_USB_CTRL_1_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_ITC_NO_THRESHOLD); +} + +static struct mxc_usbh_platform_data dr_utmi_config = { + .init = initialize_otg_port, + .portsc = MXC_EHCI_UTMI_16BIT, +}; + +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, +}; + +static struct mxc_usbh_platform_data usbh1_config = { + .init = initialize_usbh1_port, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static int otg_mode_host; + +static int __init eukrea_cpuimx51sd_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", eukrea_cpuimx51sd_otg_mode); + +static struct i2c_gpio_platform_data pdata = { + .sda_pin = I2C_SDA, + .sda_is_open_drain = 0, + .scl_pin = I2C_SCL, + .scl_is_open_drain = 0, + .udelay = 2, +}; + +static struct platform_device hsi2c_gpio_device = { + .name = "i2c-gpio", + .id = 0, + .dev.platform_data = &pdata, +}; + +static struct mcp251x_platform_data mcp251x_info = { + .oscillator_frequency = 24E6, +}; + +static struct spi_board_info cpuimx51sd_spi_device[] = { + { + .modalias = "mcp2515", + .max_speed_hz = 10000000, + .bus_num = 0, + .mode = SPI_MODE_0, + .chip_select = 0, + .platform_data = &mcp251x_info, + .irq = gpio_to_irq(CAN_IRQGPIO) + }, +}; + +static int cpuimx51sd_spi1_cs[] = { + CAN_NCS, +}; + +static const struct spi_imx_master cpuimx51sd_ecspi1_pdata __initconst = { + .chipselect = cpuimx51sd_spi1_cs, + .num_chipselect = ARRAY_SIZE(cpuimx51sd_spi1_cs), +}; + +static struct platform_device *platform_devices[] __initdata = { + &hsi2c_gpio_device, +}; + +static void __init eukrea_cpuimx51sd_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51sd_pads, + ARRAY_SIZE(eukrea_cpuimx51sd_pads)); + +#if defined(CONFIG_CPU_FREQ_IMX) + get_cpu_op = mx51_get_cpu_op; +#endif + + imx51_add_imx_uart(0, &uart_pdata); + imx51_add_mxc_nand(&eukrea_cpuimx51sd_nand_board_info); + + gpio_request(ETH_RST, "eth_rst"); + gpio_set_value(ETH_RST, 1); + imx51_add_fec(NULL); + + gpio_request(CAN_IRQGPIO, "can_irq"); + gpio_direction_input(CAN_IRQGPIO); + gpio_free(CAN_IRQGPIO); + gpio_request(CAN_NCS, "can_ncs"); + gpio_direction_output(CAN_NCS, 1); + gpio_free(CAN_NCS); + gpio_request(CAN_RST, "can_rst"); + gpio_direction_output(CAN_RST, 0); + msleep(20); + gpio_set_value(CAN_RST, 1); + imx51_add_ecspi(0, &cpuimx51sd_ecspi1_pdata); + spi_register_board_info(cpuimx51sd_spi_device, + ARRAY_SIZE(cpuimx51sd_spi_device)); + + gpio_request(TSC2007_IRQGPIO, "tsc2007_irq"); + gpio_direction_input(TSC2007_IRQGPIO); + gpio_free(TSC2007_IRQGPIO); + + i2c_register_board_info(0, eukrea_cpuimx51sd_i2c_devices, + ARRAY_SIZE(eukrea_cpuimx51sd_i2c_devices)); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + + if (otg_mode_host) + mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + else { + initialize_otg_port(NULL); + mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + } + + gpio_request(USBH1_RST, "usb_rst"); + gpio_direction_output(USBH1_RST, 0); + msleep(20); + gpio_set_value(USBH1_RST, 1); + mxc_register_device(&mxc_usbh1_device, &usbh1_config); + +#ifdef CONFIG_MACH_EUKREA_MBIMXSD51_BASEBOARD + eukrea_mbimxsd51_baseboard_init(); +#endif +} + +static void __init eukrea_cpuimx51sd_timer_init(void) +{ + mx51_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mxc_timer = { + .init = eukrea_cpuimx51sd_timer_init, +}; + +MACHINE_START(EUKREA_CPUIMX51SD, "Eukrea CPUIMX51SD") + /* Maintainer: Eric Bénard <eric@eukrea.com> */ + .boot_params = MX51_PHYS_OFFSET + 0x100, + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .timer = &mxc_timer, + .init_machine = eukrea_cpuimx51sd_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx50_rdp.c b/arch/arm/mach-mx5/board-mx50_rdp.c new file mode 100755 index 00000000..f191d1c4 --- /dev/null +++ b/arch/arm/mach-mx5/board-mx50_rdp.c @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx50.h> +#include <mach/epdc.h> +#include <mach/mxc_dvfs.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx50.h" +#include "cpu_op-mx50.h" +#include "devices.h" +#include "usb.h" +#include "crm_regs.h" + +#define FEC_EN IMX_GPIO_NR(6, 23) +#define FEC_RESET_B IMX_GPIO_NR(4, 12) +#define MX50_RDP_CSPI_CS0 IMX_GPIO_NR(4, 13) +#define MX50_RDP_CSPI_CS1 IMX_GPIO_NR(4, 11) +#define MX50_RDP_EPDC_D0 IMX_GPIO_NR(3, 0) +#define MX50_RDP_EPDC_D1 IMX_GPIO_NR(3, 1) +#define MX50_RDP_EPDC_D2 IMX_GPIO_NR(3, 2) +#define MX50_RDP_EPDC_D3 IMX_GPIO_NR(3, 3) +#define MX50_RDP_EPDC_D4 IMX_GPIO_NR(3, 4) +#define MX50_RDP_EPDC_D5 IMX_GPIO_NR(3, 5) +#define MX50_RDP_EPDC_D6 IMX_GPIO_NR(3, 6) +#define MX50_RDP_EPDC_D7 IMX_GPIO_NR(3, 7) +#define MX50_RDP_EPDC_GDCLK IMX_GPIO_NR(3, 16) +#define MX50_RDP_EPDC_GDSP IMX_GPIO_NR(3, 17) +#define MX50_RDP_EPDC_GDOE IMX_GPIO_NR(3, 18) +#define MX50_RDP_EPDC_GDRL IMX_GPIO_NR(3, 19) +#define MX50_RDP_EPDC_SDCLK IMX_GPIO_NR(3, 20) +#define MX50_RDP_EPDC_SDOEZ IMX_GPIO_NR(3, 21) +#define MX50_RDP_EPDC_SDOED IMX_GPIO_NR(3, 22) +#define MX50_RDP_EPDC_SDOE IMX_GPIO_NR(3, 23) +#define MX50_RDP_EPDC_SDLE IMX_GPIO_NR(3, 24) +#define MX50_RDP_EPDC_SDCLKN IMX_GPIO_NR(3, 25) +#define MX50_RDP_EPDC_SDSHR IMX_GPIO_NR(3, 26) +#define MX50_RDP_EPDC_PWRCOM IMX_GPIO_NR(3, 27) +#define MX50_RDP_EPDC_PWRSTAT IMX_GPIO_NR(3, 28) +#define MX50_RDP_EPDC_PWRCTRL0 IMX_GPIO_NR(3, 29) +#define MX50_RDP_EPDC_PWRCTRL1 IMX_GPIO_NR(3, 30) +#define MX50_RDP_EPDC_PWRCTRL2 IMX_GPIO_NR(3, 31) +#define MX50_RDP_EPDC_PWRCTRL3 IMX_GPIO_NR(4, 20) +#define MX50_RDP_EPDC_BDR0 IMX_GPIO_NR(4, 23) +#define MX50_RDP_EPDC_BDR1 IMX_GPIO_NR(4, 24) +#define MX50_RDP_EPDC_SDCE0 IMX_GPIO_NR(4, 25) +#define MX50_RDP_EPDC_SDCE1 IMX_GPIO_NR(4, 26) +#define MX50_RDP_EPDC_SDCE2 IMX_GPIO_NR(4, 27) +#define MX50_RDP_EPDC_SDCE3 IMX_GPIO_NR(4, 28) +#define MX50_RDP_EPDC_SDCE4 IMX_GPIO_NR(4, 29) +#define MX50_RDP_EPDC_SDCE5 IMX_GPIO_NR(4, 30) +#define MX50_RDP_EPDC_PMIC_WAKE IMX_GPIO_NR(6, 16) +#define MX50_RDP_EPDC_PMIC_INT IMX_GPIO_NR(6, 17) +#define MX50_RDP_EPDC_VCOM IMX_GPIO_NR(4, 21) +#define MX50_RDP_SD1_WP IMX_GPIO_NR(4, 19) /*GPIO_4_19 */ +#define MX50_RDP_SD1_CD IMX_GPIO_NR(1, 27) /*GPIO_1_27 */ +#define MX50_RDP_SD2_WP IMX_GPIO_NR(5, 16) /*GPIO_5_16 */ +#define MX50_RDP_SD2_CD IMX_GPIO_NR(5, 17) /*GPIO_5_17 */ +#define MX50_RDP_SD3_WP IMX_GPIO_NR(5, 28) /*GPIO_5_28 */ +#define MX50_RDP_USB_OTG_PWR IMX_GPIO_NR(6, 25) /*GPIO_6_25*/ + +extern int mx50_rdp_init_mc13892(void); +extern void mx5_cpu_regulator_init(void); +extern char *lp_reg_id; +extern char *gp_reg_id; +static int max17135_regulator_init(struct max17135 *max17135); + +static iomux_v3_cfg_t mx50_rdp_pads[] __initdata = { + /* SD1 */ + MX50_PAD_ECSPI2_SS0__GPIO_4_19, + MX50_PAD_EIM_CRE__GPIO_1_27, + MX50_PAD_SD1_CMD__SD1_CMD, + + MX50_PAD_SD1_CLK__SD1_CLK, + MX50_PAD_SD1_D0__SD1_D0, + MX50_PAD_SD1_D1__SD1_D1, + MX50_PAD_SD1_D2__SD1_D2, + MX50_PAD_SD1_D3__SD1_D3, + + /* SD2 */ + MX50_PAD_SD2_CD__GPIO_5_17, + MX50_PAD_SD2_WP__GPIO_5_16, + MX50_PAD_SD2_CMD__SD2_CMD, + MX50_PAD_SD2_CLK__SD2_CLK, + MX50_PAD_SD2_D0__SD2_D0, + MX50_PAD_SD2_D1__SD2_D1, + MX50_PAD_SD2_D2__SD2_D2, + MX50_PAD_SD2_D3__SD2_D3, + MX50_PAD_SD2_D4__SD2_D4, + MX50_PAD_SD2_D5__SD2_D5, + MX50_PAD_SD2_D6__SD2_D6, + MX50_PAD_SD2_D7__SD2_D7, + + /* SD3 */ + MX50_PAD_SD3_CMD__SD3_CMD, + MX50_PAD_SD3_CLK__SD3_CLK, + MX50_PAD_SD3_D0__SD3_D0, + MX50_PAD_SD3_D1__SD3_D1, + MX50_PAD_SD3_D2__SD3_D2, + MX50_PAD_SD3_D3__SD3_D3, + MX50_PAD_SD3_D4__SD3_D4, + MX50_PAD_SD3_D5__SD3_D5, + MX50_PAD_SD3_D6__SD3_D6, + MX50_PAD_SD3_D7__SD3_D7, + + /* PWR_INT */ + MX50_PAD_ECSPI2_MISO__GPIO_4_18, + + /* UART pad setting */ + MX50_PAD_UART1_TXD__UART1_TXD, + MX50_PAD_UART1_RXD__UART1_RXD, + MX50_PAD_UART1_RTS__UART1_RTS, + MX50_PAD_UART2_TXD__UART2_TXD, + MX50_PAD_UART2_RXD__UART2_RXD, + MX50_PAD_UART2_CTS__UART2_CTS, + MX50_PAD_UART2_RTS__UART2_RTS, + + MX50_PAD_I2C1_SCL__I2C1_SCL, + MX50_PAD_I2C1_SDA__I2C1_SDA, + MX50_PAD_I2C2_SCL__I2C2_SCL, + MX50_PAD_I2C2_SDA__I2C2_SDA, + + /* EPDC pins */ + MX50_PAD_EPDC_PWRSTAT__GPIO_3_28, + MX50_PAD_EPDC_VCOM0__GPIO_4_21, + MX50_PAD_EPDC_PWRCTRL0__GPIO_3_29, + + MX50_PAD_DISP_D8__DISP_D8, + MX50_PAD_DISP_D9__DISP_D9, + MX50_PAD_DISP_D10__DISP_D10, + MX50_PAD_DISP_D11__DISP_D11, + MX50_PAD_DISP_D12__DISP_D12, + MX50_PAD_DISP_D13__DISP_D13, + MX50_PAD_DISP_D14__DISP_D14, + MX50_PAD_DISP_D15__DISP_D15, + MX50_PAD_DISP_RS__ELCDIF_VSYNC, + + /* EPD PMIC WAKEUP */ + MX50_PAD_UART4_TXD__GPIO_6_16, + + /* EPD PMIC intr */ + MX50_PAD_UART4_RXD__GPIO_6_17, + + MX50_PAD_EPITO__USBH1_PWR, + /* Need to comment below line if + * one needs to debug owire. + */ + MX50_PAD_OWIRE__USBH1_OC, + /* using gpio to control otg pwr */ + MX50_PAD_PWM2__GPIO_6_25, + MX50_PAD_I2C3_SCL__USBOTG_OC, + + MX50_PAD_SSI_RXC__FEC_MDIO, + MX50_PAD_SSI_RXFS__FEC_MDC, + MX50_PAD_DISP_D0__FEC_TXCLK, + MX50_PAD_DISP_D1__FEC_RX_ER, + MX50_PAD_DISP_D2__FEC_RX_DV, + MX50_PAD_DISP_D3__FEC_RXD1, + MX50_PAD_DISP_D4__FEC_RXD0, + MX50_PAD_DISP_D5__FEC_TX_EN, + MX50_PAD_DISP_D6__FEC_TXD1, + MX50_PAD_DISP_D7__FEC_TXD0, + MX50_PAD_I2C3_SDA__GPIO_6_23, + MX50_PAD_ECSPI1_SCLK__GPIO_4_12, + + MX50_PAD_CSPI_SS0__CSPI_SS0, + MX50_PAD_ECSPI1_MOSI__CSPI_SS1, + MX50_PAD_CSPI_MOSI__CSPI_MOSI, + MX50_PAD_CSPI_MISO__CSPI_MISO, + + /* SGTL500_OSC_EN */ + MX50_PAD_UART1_CTS__GPIO_6_8, + + /* SGTL_AMP_SHDN */ + MX50_PAD_UART3_RXD__GPIO_6_15, + + /* Keypad */ + MX50_PAD_KEY_COL0__KEY_COL0, + MX50_PAD_KEY_ROW0__KEY_ROW0, + MX50_PAD_KEY_COL1__KEY_COL1, + MX50_PAD_KEY_ROW1__KEY_ROW1, + MX50_PAD_KEY_COL2__KEY_COL2, + MX50_PAD_KEY_ROW2__KEY_ROW2, + MX50_PAD_KEY_COL3__KEY_COL3, + MX50_PAD_KEY_ROW3__KEY_ROW3, + MX50_PAD_EIM_DA0__KEY_COL4, + MX50_PAD_EIM_DA1__KEY_ROW4, + MX50_PAD_EIM_DA2__KEY_COL5, + MX50_PAD_EIM_DA3__KEY_ROW5, + MX50_PAD_EIM_DA4__KEY_COL6, + MX50_PAD_EIM_DA5__KEY_ROW6, + MX50_PAD_EIM_DA6__KEY_COL7, + MX50_PAD_EIM_DA7__KEY_ROW7, + /*EIM pads */ + MX50_PAD_EIM_DA8__GPIO_1_8, + MX50_PAD_EIM_DA9__GPIO_1_9, + MX50_PAD_EIM_DA10__GPIO_1_10, + MX50_PAD_EIM_DA11__GPIO_1_11, + MX50_PAD_EIM_DA12__GPIO_1_12, + MX50_PAD_EIM_DA13__GPIO_1_13, + MX50_PAD_EIM_DA14__GPIO_1_14, + MX50_PAD_EIM_DA15__GPIO_1_15, + MX50_PAD_EIM_CS2__GPIO_1_16, + MX50_PAD_EIM_CS1__GPIO_1_17, + MX50_PAD_EIM_CS0__GPIO_1_18, + MX50_PAD_EIM_EB0__GPIO_1_19, + MX50_PAD_EIM_EB1__GPIO_1_20, + MX50_PAD_EIM_WAIT__GPIO_1_21, + MX50_PAD_EIM_BCLK__GPIO_1_22, + MX50_PAD_EIM_RDY__GPIO_1_23, + MX50_PAD_EIM_OE__GPIO_1_24, +}; + +/* Serial ports */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct fec_platform_data fec_data __initconst = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +static struct regulator_consumer_supply display_consumers[] = { + { + /* MAX17135 */ + .supply = "DISPLAY", + }, +}; + +static struct regulator_consumer_supply vcom_consumers[] = { + { + /* MAX17135 */ + .supply = "VCOM", + }, +}; + +static struct regulator_consumer_supply v3p3_consumers[] = { + { + /* MAX17135 */ + .supply = "V3P3", + }, +}; + +static struct regulator_init_data max17135_init_data[] = { + { + .constraints = { + .name = "DISPLAY", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(display_consumers), + .consumer_supplies = display_consumers, + }, { + .constraints = { + .name = "GVDD", + .min_uV = V_to_uV(20), + .max_uV = V_to_uV(20), + }, + }, { + .constraints = { + .name = "GVEE", + .min_uV = V_to_uV(-22), + .max_uV = V_to_uV(-22), + }, + }, { + .constraints = { + .name = "HVINN", + .min_uV = V_to_uV(-22), + .max_uV = V_to_uV(-22), + }, + }, { + .constraints = { + .name = "HVINP", + .min_uV = V_to_uV(20), + .max_uV = V_to_uV(20), + }, + }, { + .constraints = { + .name = "VCOM", + .min_uV = mV_to_uV(-4325), + .max_uV = mV_to_uV(-500), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vcom_consumers), + .consumer_supplies = vcom_consumers, + }, { + .constraints = { + .name = "VNEG", + .min_uV = V_to_uV(-15), + .max_uV = V_to_uV(-15), + }, + }, { + .constraints = { + .name = "VPOS", + .min_uV = V_to_uV(15), + .max_uV = V_to_uV(15), + }, + }, { + .constraints = { + .name = "V3P3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(v3p3_consumers), + .consumer_supplies = v3p3_consumers, + }, +}; + +static struct platform_device max17135_sensor_device = { + .name = "max17135_sensor", + .id = 0, +}; + +static struct max17135_platform_data max17135_pdata __initdata = { + .vneg_pwrup = 1, + .gvee_pwrup = 1, + .vpos_pwrup = 2, + .gvdd_pwrup = 1, + .gvdd_pwrdn = 1, + .vpos_pwrdn = 2, + .gvee_pwrdn = 1, + .vneg_pwrdn = 1, + .gpio_pmic_pwrgood = MX50_RDP_EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = MX50_RDP_EPDC_VCOM, + .gpio_pmic_wakeup = MX50_RDP_EPDC_PMIC_WAKE, + .gpio_pmic_v3p3 = MX50_RDP_EPDC_PWRCTRL0, + .gpio_pmic_intr = MX50_RDP_EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int max17135_regulator_init(struct max17135 *max17135) +{ + struct max17135_platform_data *pdata = &max17135_pdata; + int i, ret; + + max17135->gvee_pwrup = pdata->gvee_pwrup; + max17135->vneg_pwrup = pdata->vneg_pwrup; + max17135->vpos_pwrup = pdata->vpos_pwrup; + max17135->gvdd_pwrup = pdata->gvdd_pwrup; + max17135->gvdd_pwrdn = pdata->gvdd_pwrdn; + max17135->vpos_pwrdn = pdata->vpos_pwrdn; + max17135->vneg_pwrdn = pdata->vneg_pwrdn; + max17135->gvee_pwrdn = pdata->gvee_pwrdn; + + max17135->max_wait = pdata->vpos_pwrup + pdata->vneg_pwrup + + pdata->gvdd_pwrup + pdata->gvee_pwrup; + + max17135->gpio_pmic_pwrgood = pdata->gpio_pmic_pwrgood; + max17135->gpio_pmic_vcom_ctrl = pdata->gpio_pmic_vcom_ctrl; + max17135->gpio_pmic_wakeup = pdata->gpio_pmic_wakeup; + max17135->gpio_pmic_v3p3 = pdata->gpio_pmic_v3p3; + max17135->gpio_pmic_intr = pdata->gpio_pmic_intr; + + gpio_request(max17135->gpio_pmic_wakeup, "epdc-pmic-wake"); + gpio_direction_output(max17135->gpio_pmic_wakeup, 0); + + gpio_request(max17135->gpio_pmic_vcom_ctrl, "epdc-vcom"); + gpio_direction_output(max17135->gpio_pmic_vcom_ctrl, 0); + + gpio_request(max17135->gpio_pmic_v3p3, "epdc-v3p3"); + gpio_direction_output(max17135->gpio_pmic_v3p3, 0); + + gpio_request(max17135->gpio_pmic_intr, "epdc-pmic-int"); + gpio_direction_input(max17135->gpio_pmic_intr); + + gpio_request(max17135->gpio_pmic_pwrgood, "epdc-pwrstat"); + gpio_direction_input(max17135->gpio_pmic_pwrgood); + + max17135->vcom_setup = false; + max17135->init_done = false; + + for (i = 0; i < MAX17135_NUM_REGULATORS; i++) { + ret = max17135_register_regulator(max17135, i, + &pdata->regulator_init[i]); + if (ret != 0) { + printk(KERN_ERR"max17135 regulator init failed: %d\n", + ret); + return ret; + } + } + + regulator_has_full_constraints(); + + return 0; +} + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0x48), + .platform_data = &max17135_pdata, + }, + { + .type = "mma8450", + .addr = 0x1c, + }, + { + .type = "eeprom", + .addr = 0x50, + }, +}; + +static int epdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for EPDC pins - used during power up/down */ + ret |= gpio_request(MX50_RDP_EPDC_D0, "epdc_d0"); + ret |= gpio_request(MX50_RDP_EPDC_D1, "epdc_d1"); + ret |= gpio_request(MX50_RDP_EPDC_D2, "epdc_d2"); + ret |= gpio_request(MX50_RDP_EPDC_D3, "epdc_d3"); + ret |= gpio_request(MX50_RDP_EPDC_D4, "epdc_d4"); + ret |= gpio_request(MX50_RDP_EPDC_D5, "epdc_d5"); + ret |= gpio_request(MX50_RDP_EPDC_D6, "epdc_d6"); + ret |= gpio_request(MX50_RDP_EPDC_D7, "epdc_d7"); + ret |= gpio_request(MX50_RDP_EPDC_GDCLK, "epdc_gdclk"); + ret |= gpio_request(MX50_RDP_EPDC_GDSP, "epdc_gdsp"); + ret |= gpio_request(MX50_RDP_EPDC_GDOE, "epdc_gdoe"); + ret |= gpio_request(MX50_RDP_EPDC_GDRL, "epdc_gdrl"); + ret |= gpio_request(MX50_RDP_EPDC_SDCLK, "epdc_sdclk"); + ret |= gpio_request(MX50_RDP_EPDC_SDOE, "epdc_sdoe"); + ret |= gpio_request(MX50_RDP_EPDC_SDLE, "epdc_sdle"); + ret |= gpio_request(MX50_RDP_EPDC_SDSHR, "epdc_sdshr"); + ret |= gpio_request(MX50_RDP_EPDC_BDR0, "epdc_bdr0"); + ret |= gpio_request(MX50_RDP_EPDC_SDCE0, "epdc_sdce0"); + ret |= gpio_request(MX50_RDP_EPDC_SDCE1, "epdc_sdce1"); + ret |= gpio_request(MX50_RDP_EPDC_SDCE2, "epdc_sdce2"); + + return ret; +} + +static void epdc_put_pins(void) +{ + gpio_free(MX50_RDP_EPDC_D0); + gpio_free(MX50_RDP_EPDC_D1); + gpio_free(MX50_RDP_EPDC_D2); + gpio_free(MX50_RDP_EPDC_D3); + gpio_free(MX50_RDP_EPDC_D4); + gpio_free(MX50_RDP_EPDC_D5); + gpio_free(MX50_RDP_EPDC_D6); + gpio_free(MX50_RDP_EPDC_D7); + gpio_free(MX50_RDP_EPDC_GDCLK); + gpio_free(MX50_RDP_EPDC_GDSP); + gpio_free(MX50_RDP_EPDC_GDOE); + gpio_free(MX50_RDP_EPDC_GDRL); + gpio_free(MX50_RDP_EPDC_SDCLK); + gpio_free(MX50_RDP_EPDC_SDOE); + gpio_free(MX50_RDP_EPDC_SDLE); + gpio_free(MX50_RDP_EPDC_SDSHR); + gpio_free(MX50_RDP_EPDC_BDR0); + gpio_free(MX50_RDP_EPDC_SDCE0); + gpio_free(MX50_RDP_EPDC_SDCE1); + gpio_free(MX50_RDP_EPDC_SDCE2); +} + +static iomux_v3_cfg_t mx50_epdc_pads_enabled[] = { + MX50_PAD_EPDC_D0__EPDC_D0, + MX50_PAD_EPDC_D1__EPDC_D1, + MX50_PAD_EPDC_D2__EPDC_D2, + MX50_PAD_EPDC_D3__EPDC_D3, + MX50_PAD_EPDC_D4__EPDC_D4, + MX50_PAD_EPDC_D5__EPDC_D5, + MX50_PAD_EPDC_D6__EPDC_D6, + MX50_PAD_EPDC_D7__EPDC_D7, + MX50_PAD_EPDC_GDCLK__EPDC_GDCLK, + MX50_PAD_EPDC_GDSP__EPDC_GDSP, + MX50_PAD_EPDC_GDOE__EPDC_GDOE, + MX50_PAD_EPDC_GDRL__EPDC_GDRL, + MX50_PAD_EPDC_SDCLK__EPDC_SDCLK, + MX50_PAD_EPDC_SDOE__EPDC_SDOE, + MX50_PAD_EPDC_SDLE__EPDC_SDLE, + MX50_PAD_EPDC_SDSHR__EPDC_SDSHR, + MX50_PAD_EPDC_BDR0__EPDC_BDR0, + MX50_PAD_EPDC_SDCE0__EPDC_SDCE0, + MX50_PAD_EPDC_SDCE1__EPDC_SDCE1, + MX50_PAD_EPDC_SDCE2__EPDC_SDCE2, +}; + +static iomux_v3_cfg_t mx50_epdc_pads_disabled[] = { + MX50_PAD_EPDC_D0__GPIO_3_0, + MX50_PAD_EPDC_D1__GPIO_3_1, + MX50_PAD_EPDC_D2__GPIO_3_2, + MX50_PAD_EPDC_D3__GPIO_3_3, + MX50_PAD_EPDC_D4__GPIO_3_4, + MX50_PAD_EPDC_D5__GPIO_3_5, + MX50_PAD_EPDC_D6__GPIO_3_6, + MX50_PAD_EPDC_D7__GPIO_3_7, + MX50_PAD_EPDC_GDCLK__GPIO_3_16, + MX50_PAD_EPDC_GDSP__GPIO_3_17, + MX50_PAD_EPDC_GDOE__GPIO_3_18, + MX50_PAD_EPDC_GDRL__GPIO_3_19, + MX50_PAD_EPDC_SDCLK__GPIO_3_20, + MX50_PAD_EPDC_SDOE__GPIO_3_23, + MX50_PAD_EPDC_SDLE__GPIO_3_24, + MX50_PAD_EPDC_SDSHR__GPIO_3_26, + MX50_PAD_EPDC_BDR0__GPIO_4_23, + MX50_PAD_EPDC_SDCE0__GPIO_4_25, + MX50_PAD_EPDC_SDCE1__GPIO_4_26, + MX50_PAD_EPDC_SDCE2__GPIO_4_27, +}; + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx50_epdc_pads_enabled, \ + ARRAY_SIZE(mx50_epdc_pads_enabled)); + + gpio_direction_input(MX50_RDP_EPDC_D0); + gpio_direction_input(MX50_RDP_EPDC_D1); + gpio_direction_input(MX50_RDP_EPDC_D2); + gpio_direction_input(MX50_RDP_EPDC_D3); + gpio_direction_input(MX50_RDP_EPDC_D4); + gpio_direction_input(MX50_RDP_EPDC_D5); + gpio_direction_input(MX50_RDP_EPDC_D6); + gpio_direction_input(MX50_RDP_EPDC_D7); + gpio_direction_input(MX50_RDP_EPDC_GDCLK); + gpio_direction_input(MX50_RDP_EPDC_GDSP); + gpio_direction_input(MX50_RDP_EPDC_GDOE); + gpio_direction_input(MX50_RDP_EPDC_GDRL); + gpio_direction_input(MX50_RDP_EPDC_SDCLK); + gpio_direction_input(MX50_RDP_EPDC_SDOE); + gpio_direction_input(MX50_RDP_EPDC_SDLE); + gpio_direction_input(MX50_RDP_EPDC_SDSHR); + gpio_direction_input(MX50_RDP_EPDC_BDR0); + gpio_direction_input(MX50_RDP_EPDC_SDCE0); + gpio_direction_input(MX50_RDP_EPDC_SDCE1); + gpio_direction_input(MX50_RDP_EPDC_SDCE2); +} + +static void epdc_disable_pins(void) +{ + /* Configure MUX settings for EPDC pins to + * GPIO and drive to 0. */ + mxc_iomux_v3_setup_multiple_pads(mx50_epdc_pads_disabled, \ + ARRAY_SIZE(mx50_epdc_pads_disabled)); + + gpio_direction_output(MX50_RDP_EPDC_D0, 0); + gpio_direction_output(MX50_RDP_EPDC_D1, 0); + gpio_direction_output(MX50_RDP_EPDC_D2, 0); + gpio_direction_output(MX50_RDP_EPDC_D3, 0); + gpio_direction_output(MX50_RDP_EPDC_D4, 0); + gpio_direction_output(MX50_RDP_EPDC_D5, 0); + gpio_direction_output(MX50_RDP_EPDC_D6, 0); + gpio_direction_output(MX50_RDP_EPDC_D7, 0); + gpio_direction_output(MX50_RDP_EPDC_GDCLK, 0); + gpio_direction_output(MX50_RDP_EPDC_GDSP, 0); + gpio_direction_output(MX50_RDP_EPDC_GDOE, 0); + gpio_direction_output(MX50_RDP_EPDC_GDRL, 0); + gpio_direction_output(MX50_RDP_EPDC_SDCLK, 0); + gpio_direction_output(MX50_RDP_EPDC_SDOE, 0); + gpio_direction_output(MX50_RDP_EPDC_SDLE, 0); + gpio_direction_output(MX50_RDP_EPDC_SDSHR, 0); + gpio_direction_output(MX50_RDP_EPDC_BDR0, 0); + gpio_direction_output(MX50_RDP_EPDC_SDCE0, 0); + gpio_direction_output(MX50_RDP_EPDC_SDCE1, 0); + gpio_direction_output(MX50_RDP_EPDC_SDCE2, 0); +} + +static struct fb_videomode e60_v110_mode = { + .name = "E60_V110", + .refresh = 50, + .xres = 800, + .yres = 600, + .pixclock = 18604700, + .left_margin = 8, + .right_margin = 178, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct fb_videomode e60_v220_mode = { + .name = "E60_V220", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 30000000, + .left_margin = 8, + .right_margin = 164, + .upper_margin = 4, + .lower_margin = 8, + .hsync_len = 4, + .vsync_len = 1, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct fb_videomode e97_v110_mode = { + .name = "E97_V110", + .refresh = 50, + .xres = 1200, + .yres = 825, + .pixclock = 32000000, + .left_margin = 12, + .right_margin = 128, + .upper_margin = 4, + .lower_margin = 10, + .hsync_len = 20, + .vsync_len = 4, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct imx_epdc_fb_mode panel_modes[] = { + { + &e60_v110_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 428, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 1, /* num_ce */ + }, + { + &e60_v220_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 465, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 9, /* gdclk_offs */ + 1, /* num_ce */ + }, + { + &e97_v110_mode, + 8, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 632, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 1, /* gdclk_offs */ + 3, /* num_ce */ + } +}; + +static struct imx_epdc_fb_platform_data epdc_data = { + .epdc_mode = panel_modes, + .num_modes = ARRAY_SIZE(panel_modes), + .get_pins = epdc_get_pins, + .put_pins = epdc_put_pins, + .enable_pins = epdc_enable_pins, + .disable_pins = epdc_disable_pins, +}; + +static inline void mx50_rdp_fec_reset(void) +{ + gpio_request(FEC_EN, "fec-en"); + gpio_direction_output(FEC_EN, 0); + gpio_request(FEC_RESET_B, "fec-reset_b"); + gpio_direction_output(FEC_RESET_B, 0); + msleep(1); + gpio_set_value(FEC_RESET_B, 1); +} + +static const struct imxi2c_platform_data i2c_data __initconst = { + .bitrate = 100000, +}; + +static struct mxc_gpu_platform_data gpu_data __initdata = { + .z160_revision = 1, +}; + +static int mx50_rdp_spi_cs[] = { + MX50_RDP_CSPI_CS0, + MX50_RDP_CSPI_CS1, +}; + +static const struct spi_imx_master mx50_rdp_spi_pdata __initconst = { + .chipselect = mx50_rdp_spi_cs, + .num_chipselect = ARRAY_SIZE(mx50_rdp_spi_cs), +}; + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx50_gpmi_nand[] __initdata = { + MX50_PIN_EIM_DA8__NANDF_CLE, + MX50_PIN_EIM_DA9__NANDF_ALE, + MX50_PIN_EIM_DA10__NANDF_CE0, + MX50_PIN_EIM_DA11__NANDF_CE1, + MX50_PIN_EIM_DA12__NANDF_CE2, + MX50_PIN_EIM_DA13__NANDF_CE3, + MX50_PAD_EIM_DA14__NANDF_READY, + MX50_PIN_EIM_DA15__NANDF_DQS, + MX50_PIN_SD3_D4__NANDF_D0, + MX50_PIN_SD3_D5__NANDF_D1, + MX50_PIN_SD3_D6__NANDF_D2, + MX50_PIN_SD3_D7__NANDF_D3, + MX50_PIN_SD3_D0__NANDF_D4, + MX50_PIN_SD3_D1__NANDF_D5, + MX50_PIN_SD3_D2__NANDF_D6, + MX50_PIN_SD3_D3__NANDF_D7, + MX50_PIN_SD3_CLK__NANDF_RDN, + MX50_PIN_SD3_CMD__NANDF_WRN, + MX50_PIN_SD3_WP__NANDF_RESETN, +}; + +static int gpmi_nfc_platform_init(void) +{ + return mxc_iomux_v3_setup_multiple_pads(mx50_gpmi_nand, + ARRAY_SIZE(mx50_gpmi_nand)); +} + +static struct gpmi_nfc_platform_data mx50_gpmi_nfc_platform_data __initdata = { + .platform_init = gpmi_nfc_platform_init, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 1, +}; + + +static struct mxc_dvfs_platform_data rdp_dvfscore_data = { + .reg_id = "cpu_vddgp", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 80, +}; + +static struct mxc_regulator_platform_data rdp_regulator_data = { + .cpu_reg_id = "cpu_vddgp", + .vcc_reg_id = "lp_vcc", +}; + +static const struct esdhc_platform_data mx50_rdp_sd1_data __initconst = { + .cd_gpio = MX50_RDP_SD1_CD, + .wp_gpio = MX50_RDP_SD1_WP, +}; + +static const struct esdhc_platform_data mx50_rdp_sd2_data __initconst = { + .cd_gpio = MX50_RDP_SD2_CD, + .wp_gpio = MX50_RDP_SD2_WP, +}; + +static const struct esdhc_platform_data mx50_rdp_sd3_data __initconst = { + .wp_gpio = MX50_RDP_SD3_WP, + .always_present = 1, +}; + +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static void mx50_rdp_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(MX50_RDP_USB_OTG_PWR, 1); + else + gpio_set_value(MX50_RDP_USB_OTG_PWR, 0); +} + +static void __init mx50_rdp_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX50_IO_ADDRESS(MX50_OTG_BASE_ADDR); + ret = gpio_request(MX50_RDP_USB_OTG_PWR, "usb-pwr"); + if (ret) { + printk(KERN_ERR"failed to get GPIO OTG_VBUS: %d\n", ret); + return; + } + gpio_direction_output(MX50_RDP_USB_OTG_PWR, 0); + + mx5_set_otghost_vbus_func(mx50_rdp_usbotg_vbus); + mx5_usb_dr_init(); + mx5_usbh1_init(); +} +/* + * Board specific initialization. + */ +static void __init mx50_rdp_board_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx50_rdp_pads, + ARRAY_SIZE(mx50_rdp_pads)); + + pr_info("CPU is iMX50 Revision %u\n", + mx50_revision()); + + gp_reg_id = rdp_regulator_data.cpu_reg_id; + lp_reg_id = rdp_regulator_data.vcc_reg_id; + + imx50_add_cspi(3, &mx50_rdp_spi_pdata); + + imx50_add_dma(); + imx50_add_imx_uart(0, NULL); + imx50_add_imx_uart(1, NULL); + imx50_add_srtc(); + imx50_add_imx_pxp(); + imx50_add_imx_pxp_client(); + mx50_rdp_fec_reset(); + imx50_add_fec(&fec_data); + imx50_add_gpmi(&mx50_gpmi_nfc_platform_data); + imx50_add_imx_i2c(0, &i2c_data); + imx50_add_imx_i2c(1, &i2c_data); + imx50_add_imx_i2c(2, &i2c_data); + i2c_register_board_info(0, mxc_i2c0_board_info, + ARRAY_SIZE(mxc_i2c0_board_info)); + mxc_register_device(&max17135_sensor_device, NULL); + imx50_add_imx_epdc(&epdc_data); + imx50_add_mxc_gpu(&gpu_data); + imx50_add_sdhci_esdhc_imx(0, &mx50_rdp_sd1_data); + imx50_add_sdhci_esdhc_imx(1, &mx50_rdp_sd2_data); + imx50_add_sdhci_esdhc_imx(2, &mx50_rdp_sd3_data); + imx50_add_otp(); + imx50_add_viim(); + imx50_add_dcp(); + imx50_add_rngb(); + imx50_add_perfmon(); + mx50_rdp_init_mc13892(); + + imx50_add_dvfs_core(&rdp_dvfscore_data); + + imx50_add_busfreq(); + + mx50_rdp_init_usb(); + + mx5_cpu_regulator_init(); +} + +static void __init mx50_rdp_timer_init(void) +{ + mx50_clocks_init(32768, 24000000, 22579200); +} + +static struct sys_timer mx50_rdp_timer = { + .init = mx50_rdp_timer_init, +}; + +MACHINE_START(MX50_RDP, "Freescale MX50 Reference Design Platform") + .fixup = fixup_mxc_board, + .map_io = mx50_map_io, + .init_early = imx50_init_early, + .init_irq = mx50_init_irq, + .timer = &mx50_rdp_timer, + .init_machine = mx50_rdp_board_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx51_3ds.c b/arch/arm/mach-mx5/board-mx51_3ds.c new file mode 100644 index 00000000..b51f08ea --- /dev/null +++ b/arch/arm/mach-mx5/board-mx51_3ds.c @@ -0,0 +1,196 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2010 Jason Wang <jason77.wang@gmail.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx51.h> +#include <mach/3ds_debugboard.h> + +#include "devices-imx51.h" +#include "devices.h" + +#define EXPIO_PARENT_INT (MXC_INTERNAL_IRQS + GPIO_PORTA + 6) +#define MX51_3DS_ECSPI2_CS (GPIO_PORTC + 28) + +static iomux_v3_cfg_t mx51_3ds_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + + /* UART2 */ + MX51_PAD_UART2_RXD__UART2_RXD, + MX51_PAD_UART2_TXD__UART2_TXD, + MX51_PAD_EIM_D25__UART2_CTS, + MX51_PAD_EIM_D26__UART2_RTS, + + /* UART3 */ + MX51_PAD_UART3_RXD__UART3_RXD, + MX51_PAD_UART3_TXD__UART3_TXD, + MX51_PAD_EIM_D24__UART3_CTS, + MX51_PAD_EIM_D27__UART3_RTS, + + /* CPLD PARENT IRQ PIN */ + MX51_PAD_GPIO1_6__GPIO1_6, + + /* KPP */ + MX51_PAD_KEY_ROW0__KEY_ROW0, + MX51_PAD_KEY_ROW1__KEY_ROW1, + MX51_PAD_KEY_ROW2__KEY_ROW2, + MX51_PAD_KEY_ROW3__KEY_ROW3, + MX51_PAD_KEY_COL0__KEY_COL0, + MX51_PAD_KEY_COL1__KEY_COL1, + MX51_PAD_KEY_COL2__KEY_COL2, + MX51_PAD_KEY_COL3__KEY_COL3, + MX51_PAD_KEY_COL4__KEY_COL4, + MX51_PAD_KEY_COL5__KEY_COL5, + + /* eCSPI2 */ + MX51_PAD_NANDF_RB2__ECSPI2_SCLK, + MX51_PAD_NANDF_RB3__ECSPI2_MISO, + MX51_PAD_NANDF_D15__ECSPI2_MOSI, + MX51_PAD_NANDF_D12__GPIO3_28, + + MX51_PAD_GPIO1_7__SPDIF_OUT, +}; + +/* Serial ports */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static int mx51_3ds_board_keymap[] = { + KEY(0, 0, KEY_1), + KEY(0, 1, KEY_2), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_F1), + KEY(0, 4, KEY_UP), + KEY(0, 5, KEY_F2), + + KEY(1, 0, KEY_4), + KEY(1, 1, KEY_5), + KEY(1, 2, KEY_6), + KEY(1, 3, KEY_LEFT), + KEY(1, 4, KEY_SELECT), + KEY(1, 5, KEY_RIGHT), + + KEY(2, 0, KEY_7), + KEY(2, 1, KEY_8), + KEY(2, 2, KEY_9), + KEY(2, 3, KEY_F3), + KEY(2, 4, KEY_DOWN), + KEY(2, 5, KEY_F4), + + KEY(3, 0, KEY_0), + KEY(3, 1, KEY_OK), + KEY(3, 2, KEY_ESC), + KEY(3, 3, KEY_ENTER), + KEY(3, 4, KEY_MENU), + KEY(3, 5, KEY_BACK) +}; + +static const struct matrix_keymap_data mx51_3ds_map_data __initconst = { + .keymap = mx51_3ds_board_keymap, + .keymap_size = ARRAY_SIZE(mx51_3ds_board_keymap), +}; + +static int mx51_3ds_spi2_cs[] = { + MXC_SPI_CS(0), + MX51_3DS_ECSPI2_CS, +}; + +static const struct spi_imx_master mx51_3ds_ecspi2_pdata __initconst = { + .chipselect = mx51_3ds_spi2_cs, + .num_chipselect = ARRAY_SIZE(mx51_3ds_spi2_cs), +}; + +static struct spi_board_info mx51_3ds_spi_nor_device[] = { + { + .modalias = "m25p80", + .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 1, + .chip_select = 1, + .mode = SPI_MODE_0, + .platform_data = NULL,}, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* tx clk from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* tx clk from CKIH2 for 48k and 32k */ + .spdif_div_44100 = 8, + .spdif_div_48000 = 8, + .spdif_div_32000 = 12, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +/* + * Board specific initialization. + */ +static void __init mx51_3ds_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51_3ds_pads, + ARRAY_SIZE(mx51_3ds_pads)); + + imx51_add_imx_uart(0, &uart_pdata); + imx51_add_imx_uart(1, &uart_pdata); + imx51_add_imx_uart(2, &uart_pdata); + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + imx51_add_ecspi(1, &mx51_3ds_ecspi2_pdata); + spi_register_board_info(mx51_3ds_spi_nor_device, + ARRAY_SIZE(mx51_3ds_spi_nor_device)); + + if (mxc_expio_init(MX51_CS5_BASE_ADDR, EXPIO_PARENT_INT)) + printk(KERN_WARNING "Init of the debugboard failed, all " + "devices on the board are unusable.\n"); + + imx51_add_sdhci_esdhc_imx(0, NULL); + imx51_add_imx_keypad(&mx51_3ds_map_data); + imx51_add_imx2_wdt(0, NULL); + + imx51_add_spdif(&mxc_spdif_data); + imx51_add_spdif_dai(); + imx51_add_spdif_audio_device(); +} + +static void __init mx51_3ds_timer_init(void) +{ + mx51_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mx51_3ds_timer = { + .init = mx51_3ds_timer_init, +}; + +MACHINE_START(MX51_3DS, "Freescale MX51 3-Stack Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX51_PHYS_OFFSET + 0x100, + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .timer = &mx51_3ds_timer, + .init_machine = mx51_3ds_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c new file mode 100755 index 00000000..f8661ff5 --- /dev/null +++ b/arch/arm/mach-mx5/board-mx51_babbage.c @@ -0,0 +1,832 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/fsl_devices.h> +#include <linux/fec.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> +#include <mach/mxc_ehci.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_dvfs.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx51.h" +#include "devices.h" +#include "crm_regs.h" +#include "cpu_op-mx51.h" + +#define BABBAGE_USB_HUB_RESET IMX_GPIO_NR(1, 7) +#define BABBAGE_USBH1_STP IMX_GPIO_NR(1, 27) +#define BABBAGE_PHY_RESET IMX_GPIO_NR(2, 5) +#define BABBAGE_VGA_RESET IMX_GPIO_NR(2, 13) +#define BABBAGE_FEC_PHY_RESET IMX_GPIO_NR(2, 14) +#define BABBAGE_POWER_KEY IMX_GPIO_NR(2, 21) +#define BABBAGE_ECSPI1_CS0 IMX_GPIO_NR(4, 24) +#define BABBAGE_ECSPI1_CS1 IMX_GPIO_NR(4, 25) +#define MX51_BBG_SD1_CD IMX_GPIO_NR(1, 0) +#define MX51_BBG_SD1_WP IMX_GPIO_NR(1, 1) +#define MX51_BBG_SD2_CD IMX_GPIO_NR(1, 6) +#define MX51_BBG_SD2_WP IMX_GPIO_NR(1, 5) +#define BABBAGE_AUDAMP_STBY IMX_GPIO_NR(2, 17) +#define BABBAGE_HEADPHONE_DET IMX_GPIO_NR(3, 26) +#define BABBAGE_AUDIO_CLK_EN IMX_GPIO_NR(4, 26) +#define BABBAGE_OSC_EN_B IMX_GPIO_NR(2, 2) + +#define BABBAGE_26M_OSC_EN IMX_GPIO_NR(3, 1) +#define BABBAGE_LVDS_POWER_DOWN IMX_GPIO_NR(3, 3) /* GPIO_3_3 */ +#define BABBAGE_DISP_BRIGHTNESS_CTL IMX_GPIO_NR(3, 4) /* GPIO_3_4 */ +#define BABBAGE_DVI_RESET IMX_GPIO_NR(3, 5) /* GPIO_3_5 */ +#define BABBAGE_DVI_POWER IMX_GPIO_NR(3, 6) /* GPIO_3_6 */ +#define BABBAGE_HEADPHONE_DET IMX_GPIO_NR(3, 26) /* GPIO_3_26 */ +#define BABBAGE_DVI_DET IMX_GPIO_NR(3, 28) /* GPIO_3_28 */ + +#define BABBAGE_LCD_3V3_ON IMX_GPIO_NR(4, 9) /* GPIO_4_9 */ +#define BABBAGE_LCD_5V_ON IMX_GPIO_NR(4, 10) /* GPIO_4_10 */ +#define BABBAGE_DVI_I2C_EN IMX_GPIO_NR(4, 14) /* GPIO_4_14 */ + +/* USB_CTRL_1 */ +#define MX51_USB_CTRL_1_OFFSET 0x10 +#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) + +#define MX51_USB_PLLDIV_12_MHZ 0x00 +#define MX51_USB_PLL_DIV_19_2_MHZ 0x01 +#define MX51_USB_PLL_DIV_24_MHZ 0x02 + +extern char *lp_reg_id; +extern char *gp_reg_id; +extern void mx5_cpu_regulator_init(void); + +static struct gpio_keys_button babbage_buttons[] = { + { + .gpio = BABBAGE_POWER_KEY, + .code = BTN_0, + .desc = "PWR", + .active_low = 1, + .wakeup = 1, + }, +}; + +static const struct gpio_keys_platform_data imx_button_data __initconst = { + .buttons = babbage_buttons, + .nbuttons = ARRAY_SIZE(babbage_buttons), +}; + +static iomux_v3_cfg_t mx51babbage_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + + /* UART2 */ + MX51_PAD_UART2_RXD__UART2_RXD, + MX51_PAD_UART2_TXD__UART2_TXD, + + /* UART3 */ + MX51_PAD_EIM_D25__UART3_RXD, + MX51_PAD_EIM_D26__UART3_TXD, + MX51_PAD_EIM_D27__UART3_RTS, + MX51_PAD_EIM_D24__UART3_CTS, + + /* I2C1 */ + MX51_PAD_EIM_D16__I2C1_SDA, + MX51_PAD_EIM_D19__I2C1_SCL, + + /* I2C2 */ + MX51_PAD_KEY_COL4__I2C2_SCL, + MX51_PAD_KEY_COL5__I2C2_SDA, + + /* HSI2C */ + MX51_PAD_I2C1_CLK__I2C1_CLK, + MX51_PAD_I2C1_DAT__I2C1_DAT, + + /* USB HOST1 */ + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + + /* USB HUB reset line*/ + MX51_PAD_GPIO1_7__GPIO1_7, + + /* FEC */ + MX51_PAD_EIM_EB2__FEC_MDIO, + MX51_PAD_EIM_EB3__FEC_RDATA1, + MX51_PAD_EIM_CS2__FEC_RDATA2, + MX51_PAD_EIM_CS3__FEC_RDATA3, + MX51_PAD_EIM_CS4__FEC_RX_ER, + MX51_PAD_EIM_CS5__FEC_CRS, + MX51_PAD_NANDF_RB2__FEC_COL, + MX51_PAD_NANDF_RB3__FEC_RX_CLK, + MX51_PAD_NANDF_D9__FEC_RDATA0, + MX51_PAD_NANDF_D8__FEC_TDATA0, + MX51_PAD_NANDF_CS2__FEC_TX_ER, + MX51_PAD_NANDF_CS3__FEC_MDC, + MX51_PAD_NANDF_CS4__FEC_TDATA1, + MX51_PAD_NANDF_CS5__FEC_TDATA2, + MX51_PAD_NANDF_CS6__FEC_TDATA3, + MX51_PAD_NANDF_CS7__FEC_TX_EN, + MX51_PAD_NANDF_RDY_INT__FEC_TX_CLK, + + /* FEC PHY reset line */ + MX51_PAD_EIM_A20__GPIO2_14, + + MX51_PAD_GPIO1_0__GPIO1_0, + MX51_PAD_GPIO1_1__GPIO1_1, + MX51_PAD_GPIO1_5__GPIO1_5, + MX51_PAD_GPIO1_6__GPIO1_6, + /* SD 1 */ + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + + /* SD 2 */ + MX51_PAD_SD2_CMD__SD2_CMD, + MX51_PAD_SD2_CLK__SD2_CLK, + MX51_PAD_SD2_DATA0__SD2_DATA0, + MX51_PAD_SD2_DATA1__SD2_DATA1, + MX51_PAD_SD2_DATA2__SD2_DATA2, + MX51_PAD_SD2_DATA3__SD2_DATA3, + + /* eCSPI1 */ + MX51_PAD_CSPI1_MISO__ECSPI1_MISO, + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI, + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK, + MX51_PAD_CSPI1_SS0__ECSPI1_SS0, + MX51_PAD_CSPI1_SS0__GPIO4_24, + MX51_PAD_CSPI1_SS1__GPIO4_25, + MX51_PAD_CSPI1_RDY__GPIO4_26, + MX51_PAD_CSPI1_SS1__ECSPI1_SS1, + + /* Display */ + MX51_PAD_EIM_A19__GPIO2_13, + MX51_PAD_DI1_D0_CS__GPIO3_3, + MX51_PAD_DISPB2_SER_DIN__GPIO3_5, + MX51_PAD_DISPB2_SER_DIO__GPIO3_6, + MX51_PAD_NANDF_D14__GPIO3_26, + MX51_PAD_NANDF_D12__GPIO3_28, + MX51_PAD_CSI2_D12__GPIO4_9, + MX51_PAD_CSI2_D13__GPIO4_10, + MX51_PAD_CSI2_HSYNC__GPIO4_14, + + MX51_PAD_DI_GP4__DI2_PIN15, + MX51_PAD_GPIO1_2__PWM1_PWMO, + +#ifdef CONFIG_FB_MXC_CLAA_WVGA_SYNC_PANEL + MX51_PAD_DISP1_DAT22__DISP2_DAT16, + MX51_PAD_DISP1_DAT23__DISP2_DAT17, + + MX51_PAD_DI1_D1_CS__GPIO3_4, +#endif + MX51_PAD_EIM_LBA__GPIO3_1, + MX51_PAD_AUD3_BB_TXD__AUD3_TXD, + MX51_PAD_AUD3_BB_RXD__AUD3_RXD, + MX51_PAD_AUD3_BB_CK__AUD3_TXC, + MX51_PAD_AUD3_BB_FS__AUD3_TXFS, + + MX51_PAD_OWIRE_LINE__SPDIF_OUT, +}; + +static struct mxc_dvfs_platform_data bbg_dvfscore_data = { + .reg_id = "cpu_vcc", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static struct mxc_regulator_platform_data bbg_regulator_data = { + .cpu_reg_id = "cpu_vcc", +}; + +/* Serial ports */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxi2c_platform_data babbage_i2c_data __initconst = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data babbage_hsi2c_data = { + .bitrate = 400000, +}; + +static const struct esdhc_platform_data mx51_bbg_sd1_data __initconst = { + .wp_gpio = MX51_BBG_SD1_WP, + .cd_gpio = MX51_BBG_SD1_CD, +}; + +static const struct esdhc_platform_data mx51_bbg_sd2_data __initconst = { + .wp_gpio = MX51_BBG_SD2_WP, + .cd_gpio = MX51_BBG_SD2_CD, +}; + +static void babbage_suspend_enter(void) +{ +} + +static void babbage_suspend_exit(void) +{ + /*clear the EMPGC0/1 bits */ + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); +} + +static struct mxc_pm_platform_data babbage_pm_data = { + .suspend_enter = babbage_suspend_enter, + .suspend_exit = babbage_suspend_exit, +}; + +static int gpio_usbh1_active(void) +{ + iomux_v3_cfg_t usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO1_27; + iomux_v3_cfg_t phyreset_gpio = MX51_PAD_EIM_D21__GPIO2_5; + int ret; + + /* Set USBH1_STP to GPIO and toggle it */ + mxc_iomux_v3_setup_pad(usbh1stp_gpio); + ret = gpio_request(BABBAGE_USBH1_STP, "usbh1_stp"); + + if (ret) { + pr_debug("failed to get MX51_PAD_USBH1_STP__GPIO_1_27: %d\n", ret); + return ret; + } + gpio_direction_output(BABBAGE_USBH1_STP, 0); + gpio_set_value(BABBAGE_USBH1_STP, 1); + msleep(100); + gpio_free(BABBAGE_USBH1_STP); + + /* De-assert USB PHY RESETB */ + mxc_iomux_v3_setup_pad(phyreset_gpio); + ret = gpio_request(BABBAGE_PHY_RESET, "phy_reset"); + + if (ret) { + pr_debug("failed to get MX51_PAD_EIM_D21__GPIO_2_5: %d\n", ret); + return ret; + } + gpio_direction_output(BABBAGE_PHY_RESET, 1); + return 0; +} + +static inline void babbage_usbhub_reset(void) +{ + int ret; + + /* Bring USB hub out of reset */ + ret = gpio_request(BABBAGE_USB_HUB_RESET, "GPIO1_7"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_USB_HUB_RESET: %d\n", ret); + return; + } + gpio_direction_output(BABBAGE_USB_HUB_RESET, 0); + + /* USB HUB RESET - De-assert USB HUB RESET_N */ + msleep(1); + gpio_set_value(BABBAGE_USB_HUB_RESET, 0); + msleep(1); + gpio_set_value(BABBAGE_USB_HUB_RESET, 1); +} + +static inline void babbage_fec_reset(void) +{ + int ret; + + /* reset FEC PHY */ + ret = gpio_request_one(BABBAGE_FEC_PHY_RESET, + GPIOF_OUT_INIT_LOW, "fec-phy-reset"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret); + return; + } + msleep(1); + gpio_set_value(BABBAGE_FEC_PHY_RESET, 1); +} + +/* This function is board specific as the bit mask for the plldiv will also +be different for other Freescale SoCs, thus a common bitmask is not +possible and cannot get place in /plat-mxc/ehci.c.*/ +static int initialize_otg_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* Set the PHY clock to 19.2MHz */ + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK; + v |= MX51_USB_PLL_DIV_19_2_MHZ; + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(0, MXC_EHCI_INTERNAL_PHY); +} + +static int initialize_usbh1_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + /* The clock for the USBH1 ULPI port will come externally from the PHY. */ + v = __raw_readl(usbother_base + MX51_USB_CTRL_1_OFFSET); + __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, usbother_base + MX51_USB_CTRL_1_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(1, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_ITC_NO_THRESHOLD); +} + +static struct mxc_usbh_platform_data dr_utmi_config = { + .init = initialize_otg_port, + .portsc = MXC_EHCI_UTMI_16BIT, +}; + +static struct fsl_usb2_platform_data usb_pdata = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, +}; + +static struct mxc_usbh_platform_data usbh1_config = { + .init = initialize_usbh1_port, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static int otg_mode_host; + +static int __init babbage_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", babbage_otg_mode); + +static struct spi_board_info mx51_babbage_spi_board_info[] __initdata = { + { + .modalias = "mtd_dataflash", + .max_speed_hz = 25000000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + .platform_data = NULL, + }, +}; + +static int mx51_babbage_spi_cs[] = { + BABBAGE_ECSPI1_CS0, + BABBAGE_ECSPI1_CS1, +}; + +static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = { + .chipselect = mx51_babbage_spi_cs, + .num_chipselect = ARRAY_SIZE(mx51_babbage_spi_cs), +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct ipuv3_fb_platform_data bbg_fb_data[] = { + { + .disp_dev = "dvi", + .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .mode_str = "1024x768M-16@60", + .default_bpp = 16, + .int_clk = false, + }, { + .disp_dev = "lcd", + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static struct imx_ipuv3_platform_data ipu_data = { + .rev = 2, +}; + +static struct platform_pwm_backlight_data bbg_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 78770, +}; + +static struct fsl_mxc_tve_platform_data tve_data = { + .dac_reg = "VVIDEO", +}; + +static void vga_reset(void) +{ + + gpio_set_value(BABBAGE_VGA_RESET, 0); + msleep(50); + /* do reset */ + gpio_set_value(BABBAGE_VGA_RESET, 1); + msleep(10); /* tRES >= 50us */ + gpio_set_value(BABBAGE_VGA_RESET, 0); +} + +static struct fsl_mxc_lcd_platform_data vga_data = { + .core_reg = "VCAM", + .io_reg = "VGEN3", + .analog_reg = "VAUDIO", + .reset = vga_reset, +}; + +static void ddc_dvi_init(void) +{ + /* enable DVI I2C */ + gpio_set_value(BABBAGE_DVI_I2C_EN, 1); +} + +static int ddc_dvi_update(void) +{ + /* DVI cable state */ + if (gpio_get_value(BABBAGE_DVI_DET) == 1) + return 1; + else + return 0; +} + +static struct fsl_mxc_dvi_platform_data bbg_ddc_dvi_data = { + .ipu_id = 0, + .disp_id = 0, + .init = ddc_dvi_init, + .update = ddc_dvi_update, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000", + .addr = 0x0a, + }, + { + .type = "mxc_dvi", + .addr = 0x50, + .irq = gpio_to_irq(BABBAGE_DVI_DET), + .platform_data = &bbg_ddc_dvi_data, + }, +}; + +static struct i2c_board_info mxc_i2c_hs_board_info[] __initdata = { + { + .type = "ch7026", + .addr = 0x75, + .platform_data = &vga_data, + }, +}; + +static struct mxc_gpu_platform_data gpu_data __initdata; + +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_512M; + int left_mem = 0; + int gpu_mem = SZ_64M; + int fb_mem = 0; + char *str; + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /*reserve memory for gpu*/ + gpu_data.reserved_mem_base = + mem_tag->u.mem.start + left_mem; + gpu_data.reserved_mem_size = gpu_mem; + + /* reserver memory for fb */ + bbg_fb_data[0].res_base[0] = gpu_data.reserved_mem_base + + gpu_data.reserved_mem_size; + bbg_fb_data[0].res_size[0] = fb_mem; + } +} + +static struct imx_ssi_platform_data bbg_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +extern int mx51_babbage_init_mc13892(void); +static int bbg_sgtl5000_init(void) +{ + gpio_request(BABBAGE_AUDAMP_STBY, "audio_amp"); + gpio_direction_input(BABBAGE_AUDAMP_STBY); + + /* Enable OSC_CKIH1_EN for audio */ + gpio_request(BABBAGE_AUDIO_CLK_EN, "audio_clk"); + gpio_direction_output(BABBAGE_AUDIO_CLK_EN, 0); + gpio_set_value(BABBAGE_AUDIO_CLK_EN, 0); + + return 0; +} + +static struct mxc_audio_platform_data bbg_audio_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .init = bbg_sgtl5000_init, + .sysclk = 26000000, + .hp_gpio = BABBAGE_HEADPHONE_DET, + .hp_active_low = 1, +}; + +static struct platform_device bbg_audio_device = { + .name = "imx-sgtl5000", +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* tx clk from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* tx clk from CKIH2 for 48k and 32k */ + .spdif_div_44100 = 8, + .spdif_div_48000 = 8, + .spdif_div_32000 = 12, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +/* + * Board specific initialization. + */ +static void __init mx51_babbage_init(void) +{ + int i; + + iomux_v3_cfg_t usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP; + iomux_v3_cfg_t power_key = _MX51_PAD_EIM_A27__GPIO2_21 | + MUX_PAD_CTRL(PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP); + + mxc_iomux_v3_setup_multiple_pads(mx51babbage_pads, + ARRAY_SIZE(mx51babbage_pads)); + + gp_reg_id = bbg_regulator_data.cpu_reg_id; + lp_reg_id = bbg_regulator_data.vcc_reg_id; + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + imx51_add_imx_uart(0, &uart_pdata); + imx51_add_imx_uart(1, &uart_pdata); + imx51_add_imx_uart(2, &uart_pdata); + + imx51_add_srtc(); + + babbage_fec_reset(); + imx51_add_fec(NULL); + + imx51_add_ipuv3(0, &ipu_data); + for (i = 0; i < ARRAY_SIZE(bbg_fb_data); i++) + imx51_add_ipuv3fb(i, &bbg_fb_data[i]); + imx51_add_lcdif(&lcdif_data); + imx51_add_vpu(); + imx51_add_tve(&tve_data); + imx51_add_v4l2_output(0); + + imx51_add_mxc_pwm(0); + imx51_add_mxc_pwm_backlight(0, &bbg_pwm_backlight_data); + + /* Set the PAD settings for the pwr key. */ + mxc_iomux_v3_setup_pad(power_key); + imx51_add_gpio_keys(&imx_button_data); + + imx51_add_imx_i2c(0, &babbage_i2c_data); + imx51_add_imx_i2c(1, &babbage_i2c_data); + + imx51_add_spdif(&mxc_spdif_data); + imx51_add_spdif_dai(); + imx51_add_spdif_audio_device(); + + mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data); + mxc_register_device(&mxc_pm_device, &babbage_pm_data); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + + vga_data.core_reg = NULL; + vga_data.io_reg = NULL; + vga_data.analog_reg = NULL; + + i2c_register_board_info(3, mxc_i2c_hs_board_info, + ARRAY_SIZE(mxc_i2c_hs_board_info)); + + /*if (otg_mode_host) + mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + else { + initialize_otg_port(NULL); + mxc_register_device(&mxc_usbdr_udc_device, &usb_pdata); + } + + gpio_usbh1_active(); + mxc_register_device(&mxc_usbh1_device, &usbh1_config);*/ + /* setback USBH1_STP to be function */ + mxc_iomux_v3_setup_pad(usbh1stp); + babbage_usbhub_reset(); + + imx51_add_sdhci_esdhc_imx(0, &mx51_bbg_sd1_data); + imx51_add_sdhci_esdhc_imx(1, &mx51_bbg_sd2_data); + + spi_register_board_info(mx51_babbage_spi_board_info, + ARRAY_SIZE(mx51_babbage_spi_board_info)); + + imx51_add_ecspi(0, &mx51_babbage_spi_pdata); + imx51_add_imx2_wdt(0, NULL); + imx51_add_mxc_gpu(&gpu_data); + + /* this call required to release IRAM partition held by ROM during boot, + * even if SCC2 driver is not part of the image + */ + imx51_add_mxc_scc2(); + + if (mx51_revision() >= IMX_CHIP_REVISION_3_0) { + /* DVI_I2C_ENB = 0 tristates the DVI I2C level shifter */ + gpio_request(BABBAGE_DVI_I2C_EN, "dvi-i2c-en"); + gpio_direction_output(BABBAGE_DVI_I2C_EN, 0); + } + + /* Deassert VGA reset to free i2c bus */ + gpio_request(BABBAGE_VGA_RESET, "vga-reset"); + gpio_direction_output(BABBAGE_VGA_RESET, 1); + + /* LCD related gpio */ + gpio_request(BABBAGE_DISP_BRIGHTNESS_CTL, "disp-brightness-ctl"); + gpio_request(BABBAGE_LVDS_POWER_DOWN, "lvds-power-down"); + gpio_request(BABBAGE_LCD_3V3_ON, "lcd-3v3-on"); + gpio_request(BABBAGE_LCD_5V_ON, "lcd-5v-on"); + gpio_direction_output(BABBAGE_DISP_BRIGHTNESS_CTL, 0); + gpio_direction_output(BABBAGE_LVDS_POWER_DOWN, 0); + gpio_direction_output(BABBAGE_LCD_3V3_ON, 0); + gpio_direction_output(BABBAGE_LCD_5V_ON, 0); + + /* DI0-LVDS */ + gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 0); + msleep(1); + gpio_set_value(BABBAGE_LVDS_POWER_DOWN, 1); + gpio_set_value(BABBAGE_LCD_3V3_ON, 1); + gpio_set_value(BABBAGE_LCD_5V_ON, 1); + + /* DVI Detect */ + gpio_request(BABBAGE_DVI_DET, "dvi-detect"); + gpio_direction_input(BABBAGE_DVI_DET); + /* DVI Reset - Assert for i2c disabled mode */ + gpio_request(BABBAGE_DVI_RESET, "dvi-reset"); + gpio_direction_output(BABBAGE_DVI_RESET, 0); + /* DVI Power-down */ + gpio_request(BABBAGE_DVI_POWER, "dvi-power"); + gpio_direction_output(BABBAGE_DVI_POWER, 1); + + gpio_request(BABBAGE_26M_OSC_EN, "26M-OSC-CLK"); + gpio_direction_output(BABBAGE_26M_OSC_EN, 1); + + /* OSC_EN */ + gpio_request(BABBAGE_OSC_EN_B, "osc-en"); + gpio_direction_output(BABBAGE_OSC_EN_B, 1); + + /* WVGA Reset */ + gpio_set_value(BABBAGE_DISP_BRIGHTNESS_CTL, 1); + + mx51_babbage_init_mc13892(); + mxc_register_device(&bbg_audio_device, &bbg_audio_data); + imx51_add_imx_ssi(1, &bbg_ssi_pdata); + + imx51_add_dvfs_core(&bbg_dvfscore_data); + imx51_add_busfreq(); + mx5_cpu_regulator_init(); +} + +static void __init mx51_babbage_timer_init(void) +{ + mx51_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mx51_babbage_timer = { + .init = mx51_babbage_timer_init, +}; + +MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board") + /* Maintainer: Amit Kucheria <amit.kucheria@canonical.com> */ + .fixup = fixup_mxc_board, + .boot_params = MX51_PHYS_OFFSET + 0x100, + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .timer = &mx51_babbage_timer, + .init_machine = mx51_babbage_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx51_efikamx.c b/arch/arm/mach-mx5/board-mx51_efikamx.c new file mode 100644 index 00000000..6e362315 --- /dev/null +++ b/arch/arm/mach-mx5/board-mx51_efikamx.c @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2010 Linaro Limited + * + * based on code from the following + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved. + * Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/mfd/mc13892.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/consumer.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx51.h" +#include "devices.h" +#include "efika.h" + +#define EFIKAMX_PCBID0 IMX_GPIO_NR(3, 16) +#define EFIKAMX_PCBID1 IMX_GPIO_NR(3, 17) +#define EFIKAMX_PCBID2 IMX_GPIO_NR(3, 11) + +#define EFIKAMX_BLUE_LED IMX_GPIO_NR(3, 13) +#define EFIKAMX_GREEN_LED IMX_GPIO_NR(3, 14) +#define EFIKAMX_RED_LED IMX_GPIO_NR(3, 15) + +#define EFIKAMX_POWER_KEY IMX_GPIO_NR(2, 31) + +/* board 1.1 doesn't have same reset gpio */ +#define EFIKAMX_RESET1_1 IMX_GPIO_NR(3, 2) +#define EFIKAMX_RESET IMX_GPIO_NR(1, 4) + +#define EFIKAMX_POWEROFF IMX_GPIO_NR(4, 13) + +#define EFIKAMX_PMIC IMX_GPIO_NR(1, 6) + +/* the pci ids pin have pull up. they're driven low according to board id */ +#define MX51_PAD_PCBID0 IOMUX_PAD(0x518, 0x130, 3, 0x0, 0, PAD_CTL_PUS_100K_UP) +#define MX51_PAD_PCBID1 IOMUX_PAD(0x51C, 0x134, 3, 0x0, 0, PAD_CTL_PUS_100K_UP) +#define MX51_PAD_PCBID2 IOMUX_PAD(0x504, 0x128, 3, 0x0, 0, PAD_CTL_PUS_100K_UP) +#define MX51_PAD_PWRKEY IOMUX_PAD(0x48c, 0x0f8, 1, 0x0, 0, PAD_CTL_PUS_100K_UP | PAD_CTL_PKE) + +static iomux_v3_cfg_t mx51efikamx_pads[] = { + /* board id */ + MX51_PAD_PCBID0, + MX51_PAD_PCBID1, + MX51_PAD_PCBID2, + + /* leds */ + MX51_PAD_CSI1_D9__GPIO3_13, + MX51_PAD_CSI1_VSYNC__GPIO3_14, + MX51_PAD_CSI1_HSYNC__GPIO3_15, + + /* power key */ + MX51_PAD_PWRKEY, + + /* reset */ + MX51_PAD_DI1_PIN13__GPIO3_2, + MX51_PAD_GPIO1_4__GPIO1_4, + + /* power off */ + MX51_PAD_CSI2_VSYNC__GPIO4_13, +}; + +/* PCBID2 PCBID1 PCBID0 STATE + 1 1 1 ER1:rev1.1 + 1 1 0 ER2:rev1.2 + 1 0 1 ER3:rev1.3 + 1 0 0 ER4:rev1.4 +*/ +static void __init mx51_efikamx_board_id(void) +{ + int id; + + /* things are taking time to settle */ + msleep(150); + + gpio_request(EFIKAMX_PCBID0, "pcbid0"); + gpio_direction_input(EFIKAMX_PCBID0); + gpio_request(EFIKAMX_PCBID1, "pcbid1"); + gpio_direction_input(EFIKAMX_PCBID1); + gpio_request(EFIKAMX_PCBID2, "pcbid2"); + gpio_direction_input(EFIKAMX_PCBID2); + + id = gpio_get_value(EFIKAMX_PCBID0); + id |= gpio_get_value(EFIKAMX_PCBID1) << 1; + id |= gpio_get_value(EFIKAMX_PCBID2) << 2; + + switch (id) { + case 7: + system_rev = 0x11; + break; + case 6: + system_rev = 0x12; + break; + case 5: + system_rev = 0x13; + break; + case 4: + system_rev = 0x14; + break; + default: + system_rev = 0x10; + break; + } + + if ((system_rev == 0x10) + || (system_rev == 0x12) + || (system_rev == 0x14)) { + printk(KERN_WARNING + "EfikaMX: Unsupported board revision 1.%u!\n", + system_rev & 0xf); + } +} + +static struct gpio_led mx51_efikamx_leds[] = { + { + .name = "efikamx:green", + .default_trigger = "default-on", + .gpio = EFIKAMX_GREEN_LED, + }, + { + .name = "efikamx:red", + .default_trigger = "ide-disk", + .gpio = EFIKAMX_RED_LED, + }, + { + .name = "efikamx:blue", + .default_trigger = "mmc0", + .gpio = EFIKAMX_BLUE_LED, + }, +}; + +static struct gpio_led_platform_data mx51_efikamx_leds_data = { + .leds = mx51_efikamx_leds, + .num_leds = ARRAY_SIZE(mx51_efikamx_leds), +}; + +static struct platform_device mx51_efikamx_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mx51_efikamx_leds_data, + }, +}; + +static struct gpio_keys_button mx51_efikamx_powerkey[] = { + { + .code = KEY_POWER, + .gpio = EFIKAMX_POWER_KEY, + .type = EV_PWR, + .desc = "Power Button (CM)", + .wakeup = 1, + .debounce_interval = 10, /* ms */ + }, +}; + +static const struct gpio_keys_platform_data mx51_efikamx_powerkey_data __initconst = { + .buttons = mx51_efikamx_powerkey, + .nbuttons = ARRAY_SIZE(mx51_efikamx_powerkey), +}; + +void mx51_efikamx_reset(void) +{ + if (system_rev == 0x11) + gpio_direction_output(EFIKAMX_RESET1_1, 0); + else + gpio_direction_output(EFIKAMX_RESET, 0); +} + +static struct regulator *pwgt1, *pwgt2, *coincell; + +static void mx51_efikamx_power_off(void) +{ + if (!IS_ERR(coincell)) + regulator_disable(coincell); + + if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { + regulator_disable(pwgt2); + regulator_disable(pwgt1); + } + gpio_direction_output(EFIKAMX_POWEROFF, 1); +} + +static int __init mx51_efikamx_power_init(void) +{ + if (machine_is_mx51_efikamx()) { + pwgt1 = regulator_get(NULL, "pwgt1"); + pwgt2 = regulator_get(NULL, "pwgt2"); + if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { + regulator_enable(pwgt1); + regulator_enable(pwgt2); + } + gpio_request(EFIKAMX_POWEROFF, "poweroff"); + pm_power_off = mx51_efikamx_power_off; + + /* enable coincell charger. maybe need a small power driver ? */ + coincell = regulator_get(NULL, "coincell"); + if (!IS_ERR(coincell)) { + regulator_set_voltage(coincell, 3000000, 3000000); + regulator_enable(coincell); + } + + regulator_has_full_constraints(); + } + + return 0; +} +late_initcall(mx51_efikamx_power_init); + +static void __init mx51_efikamx_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51efikamx_pads, + ARRAY_SIZE(mx51efikamx_pads)); + efika_board_common_init(); + + mx51_efikamx_board_id(); + + /* on < 1.2 boards both SD controllers are used */ + if (system_rev < 0x12) { + imx51_add_sdhci_esdhc_imx(1, NULL); + mx51_efikamx_leds[2].default_trigger = "mmc1"; + } + + platform_device_register(&mx51_efikamx_leds_device); + imx_add_gpio_keys(&mx51_efikamx_powerkey_data); + + if (system_rev == 0x11) { + gpio_request(EFIKAMX_RESET1_1, "reset"); + gpio_direction_output(EFIKAMX_RESET1_1, 1); + } else { + gpio_request(EFIKAMX_RESET, "reset"); + gpio_direction_output(EFIKAMX_RESET, 1); + } + + /* + * enable wifi by default only on mx + * sb and mx have same wlan pin but the value to enable it are + * different :/ + */ + gpio_request(EFIKA_WLAN_EN, "wlan_en"); + gpio_direction_output(EFIKA_WLAN_EN, 0); + msleep(10); + + gpio_request(EFIKA_WLAN_RESET, "wlan_rst"); + gpio_direction_output(EFIKA_WLAN_RESET, 0); + msleep(10); + gpio_set_value(EFIKA_WLAN_RESET, 1); +} + +static void __init mx51_efikamx_timer_init(void) +{ + mx51_clocks_init(32768, 24000000, 22579200, 24576000); +} + +static struct sys_timer mx51_efikamx_timer = { + .init = mx51_efikamx_timer_init, +}; + +MACHINE_START(MX51_EFIKAMX, "Genesi EfikaMX nettop") + /* Maintainer: Amit Kucheria <amit.kucheria@linaro.org> */ + .boot_params = MX51_PHYS_OFFSET + 0x100, + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .timer = &mx51_efikamx_timer, + .init_machine = mx51_efikamx_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx51_efikasb.c b/arch/arm/mach-mx5/board-mx51_efikasb.c new file mode 100644 index 00000000..474fc6e4 --- /dev/null +++ b/arch/arm/mach-mx5/board-mx51_efikasb.c @@ -0,0 +1,280 @@ +/* + * Copyright (C) Arnaud Patard <arnaud.patard@rtp-net.org> + * + * based on code from the following + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved. + * Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/mfd/mc13892.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/consumer.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <mach/ulpi.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx51.h" +#include "devices.h" +#include "efika.h" + +#define EFIKASB_USBH2_STP IMX_GPIO_NR(2, 20) +#define EFIKASB_GREEN_LED IMX_GPIO_NR(1, 3) +#define EFIKASB_WHITE_LED IMX_GPIO_NR(2, 25) +#define EFIKASB_PCBID0 IMX_GPIO_NR(2, 28) +#define EFIKASB_PCBID1 IMX_GPIO_NR(2, 29) +#define EFIKASB_PWRKEY IMX_GPIO_NR(2, 31) +#define EFIKASB_LID IMX_GPIO_NR(3, 14) +#define EFIKASB_POWEROFF IMX_GPIO_NR(4, 13) +#define EFIKASB_RFKILL IMX_GPIO_NR(3, 1) + +#define MX51_PAD_PWRKEY IOMUX_PAD(0x48c, 0x0f8, 1, 0x0, 0, PAD_CTL_PUS_100K_UP | PAD_CTL_PKE) + +static iomux_v3_cfg_t mx51efikasb_pads[] = { + /* USB HOST2 */ + MX51_PAD_EIM_D16__USBH2_DATA0, + MX51_PAD_EIM_D17__USBH2_DATA1, + MX51_PAD_EIM_D18__USBH2_DATA2, + MX51_PAD_EIM_D19__USBH2_DATA3, + MX51_PAD_EIM_D20__USBH2_DATA4, + MX51_PAD_EIM_D21__USBH2_DATA5, + MX51_PAD_EIM_D22__USBH2_DATA6, + MX51_PAD_EIM_D23__USBH2_DATA7, + MX51_PAD_EIM_A24__USBH2_CLK, + MX51_PAD_EIM_A25__USBH2_DIR, + MX51_PAD_EIM_A26__USBH2_STP, + MX51_PAD_EIM_A27__USBH2_NXT, + + /* leds */ + MX51_PAD_EIM_CS0__GPIO2_25, + MX51_PAD_GPIO1_3__GPIO1_3, + + /* pcb id */ + MX51_PAD_EIM_CS3__GPIO2_28, + MX51_PAD_EIM_CS4__GPIO2_29, + + /* lid */ + MX51_PAD_CSI1_VSYNC__GPIO3_14, + + /* power key*/ + MX51_PAD_PWRKEY, + + /* wifi/bt button */ + MX51_PAD_DI1_PIN12__GPIO3_1, + + /* power off */ + MX51_PAD_CSI2_VSYNC__GPIO4_13, + + /* wdog reset */ + MX51_PAD_GPIO1_4__WDOG1_WDOG_B, + + /* BT */ + MX51_PAD_EIM_A17__GPIO2_11, +}; + +static int initialize_usbh2_port(struct platform_device *pdev) +{ + iomux_v3_cfg_t usbh2stp = MX51_PAD_EIM_A26__USBH2_STP; + iomux_v3_cfg_t usbh2gpio = MX51_PAD_EIM_A26__GPIO2_20; + + mxc_iomux_v3_setup_pad(usbh2gpio); + gpio_request(EFIKASB_USBH2_STP, "usbh2_stp"); + gpio_direction_output(EFIKASB_USBH2_STP, 0); + msleep(1); + gpio_set_value(EFIKASB_USBH2_STP, 1); + msleep(1); + + gpio_free(EFIKASB_USBH2_STP); + mxc_iomux_v3_setup_pad(usbh2stp); + + mdelay(10); + + return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_ITC_NO_THRESHOLD); +} + +static struct mxc_usbh_platform_data usbh2_config = { + .init = initialize_usbh2_port, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static void __init mx51_efikasb_usb(void) +{ + usbh2_config.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT | ULPI_OTG_EXTVBUSIND); + if (usbh2_config.otg) + mxc_register_device(&mxc_usbh2_device, &usbh2_config); +} + +static struct gpio_led mx51_efikasb_leds[] = { + { + .name = "efikasb:green", + .default_trigger = "default-on", + .gpio = EFIKASB_GREEN_LED, + .active_low = 1, + }, + { + .name = "efikasb:white", + .default_trigger = "caps", + .gpio = EFIKASB_WHITE_LED, + }, +}; + +static struct gpio_led_platform_data mx51_efikasb_leds_data = { + .leds = mx51_efikasb_leds, + .num_leds = ARRAY_SIZE(mx51_efikasb_leds), +}; + +static struct platform_device mx51_efikasb_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mx51_efikasb_leds_data, + }, +}; + +static struct gpio_keys_button mx51_efikasb_keys[] = { + { + .code = KEY_POWER, + .gpio = EFIKASB_PWRKEY, + .type = EV_PWR, + .desc = "Power Button", + .wakeup = 1, + .debounce_interval = 10, /* ms */ + }, + { + .code = SW_LID, + .gpio = EFIKASB_LID, + .type = EV_SW, + .desc = "Lid Switch", + }, + { + /* SW_RFKILLALL vs KEY_RFKILL ? */ + .code = SW_RFKILL_ALL, + .gpio = EFIKASB_RFKILL, + .type = EV_SW, + .desc = "rfkill", + }, +}; + +static const struct gpio_keys_platform_data mx51_efikasb_keys_data __initconst = { + .buttons = mx51_efikasb_keys, + .nbuttons = ARRAY_SIZE(mx51_efikasb_keys), +}; + +static struct regulator *pwgt1, *pwgt2; + +static void mx51_efikasb_power_off(void) +{ + gpio_set_value(EFIKA_USB_PHY_RESET, 0); + + if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { + regulator_disable(pwgt2); + regulator_disable(pwgt1); + } + gpio_direction_output(EFIKASB_POWEROFF, 1); +} + +static int __init mx51_efikasb_power_init(void) +{ + if (machine_is_mx51_efikasb()) { + pwgt1 = regulator_get(NULL, "pwgt1"); + pwgt2 = regulator_get(NULL, "pwgt2"); + if (!IS_ERR(pwgt1) && !IS_ERR(pwgt2)) { + regulator_enable(pwgt1); + regulator_enable(pwgt2); + } + gpio_request(EFIKASB_POWEROFF, "poweroff"); + pm_power_off = mx51_efikasb_power_off; + + regulator_has_full_constraints(); + } + + return 0; +} +late_initcall(mx51_efikasb_power_init); + +/* 01 R1.3 board + 10 R2.0 board */ +static void __init mx51_efikasb_board_id(void) +{ + int id; + + gpio_request(EFIKASB_PCBID0, "pcb id0"); + gpio_direction_input(EFIKASB_PCBID0); + gpio_request(EFIKASB_PCBID1, "pcb id1"); + gpio_direction_input(EFIKASB_PCBID1); + + id = gpio_get_value(EFIKASB_PCBID0); + id |= gpio_get_value(EFIKASB_PCBID1) << 1; + + switch (id) { + default: + break; + case 1: + system_rev = 0x13; + break; + case 2: + system_rev = 0x20; + break; + } +} + +static void __init efikasb_board_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51efikasb_pads, + ARRAY_SIZE(mx51efikasb_pads)); + efika_board_common_init(); + + mx51_efikasb_board_id(); + mx51_efikasb_usb(); + imx51_add_sdhci_esdhc_imx(1, NULL); + + platform_device_register(&mx51_efikasb_leds_device); + imx_add_gpio_keys(&mx51_efikasb_keys_data); + +} + +static void __init mx51_efikasb_timer_init(void) +{ + mx51_clocks_init(32768, 24000000, 22579200, 24576000); +} + +static struct sys_timer mx51_efikasb_timer = { + .init = mx51_efikasb_timer_init, +}; + +MACHINE_START(MX51_EFIKASB, "Genesi Efika Smartbook") + .boot_params = MX51_PHYS_OFFSET + 0x100, + .map_io = mx51_map_io, + .init_early = imx51_init_early, + .init_irq = mx51_init_irq, + .init_machine = efikasb_board_init, + .timer = &mx51_efikasb_timer, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx53_ard.c b/arch/arm/mach-mx5/board-mx53_ard.c new file mode 100755 index 00000000..7774b73f --- /dev/null +++ b/arch/arm/mach-mx5/board-mx53_ard.c @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/mxcfb.h> +#include <linux/ipu.h> +#include <linux/pwm_backlight.h> +#include <linux/smsc911x.h> +#include <linux/i2c/pca953x.h> +#include <linux/regulator/consumer.h> +#include <sound/pcm.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/imx-uart.h> +#include <mach/iomux-mx53.h> +#include <mach/ipu-v3.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "crm_regs.h" +#include "devices-imx53.h" + +#define ARD_SD1_CD IMX_GPIO_NR(1, 1) +#define ARD_SD1_WP IMX_GPIO_NR(1, 9) +#define ARD_SD2_CD IMX_GPIO_NR(1, 4) +#define ARD_SD2_WP IMX_GPIO_NR(1, 2) +#define ARD_ESAI_INT IMX_GPIO_NR(2, 4) +#define ARD_TS_INT IMX_GPIO_NR(7, 12) +#define ARD_ETHERNET_INT_B IMX_GPIO_NR(2, 31) + +/* Start directly after the CPU's GPIO*/ +#define MAX7310_BASE_ADDR 224 /* 7x32 */ +#define ARD_BACKLIGHT_ON MAX7310_BASE_ADDR +#define ARD_SPARE (MAX7310_BASE_ADDR + 1) +#define ARD_CPU_PER_RST_B (MAX7310_BASE_ADDR + 2) +#define ARD_MAIN_PER_RST_B (MAX7310_BASE_ADDR + 3) +#define ARD_IPOD_RST_B (MAX7310_BASE_ADDR + 4) +#define ARD_MLB_RST_B (MAX7310_BASE_ADDR + 5) +#define ARD_SSI_STEERING (MAX7310_BASE_ADDR + 6) +#define ARD_GPS_RST_B (MAX7310_BASE_ADDR + 7) + +extern char *gp_reg_id; +extern char *lp_reg_id; +extern void mx5_cpu_regulator_init(void); + +static iomux_v3_cfg_t mx53_ard_pads[] = { + /* UART */ + MX53_PAD_PATA_DIOW__UART1_TXD_MUX, + MX53_PAD_PATA_DMACK__UART1_RXD_MUX, + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX, + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX, + MX53_PAD_PATA_DIOR__UART2_RTS, + MX53_PAD_PATA_INTRQ__UART2_CTS, + MX53_PAD_PATA_CS_0__UART3_TXD_MUX, + MX53_PAD_PATA_CS_1__UART3_RXD_MUX, + MX53_PAD_PATA_DA_1__UART3_CTS, + MX53_PAD_PATA_DA_2__UART3_RTS, + + /* SDHC1 */ + MX53_PAD_SD1_CMD__ESDHC1_CMD, + MX53_PAD_SD1_CLK__ESDHC1_CLK, + MX53_PAD_SD1_DATA0__ESDHC1_DAT0, + MX53_PAD_SD1_DATA1__ESDHC1_DAT1, + MX53_PAD_SD1_DATA2__ESDHC1_DAT2, + MX53_PAD_SD1_DATA3__ESDHC1_DAT3, + MX53_PAD_PATA_DATA8__ESDHC1_DAT4, + MX53_PAD_PATA_DATA9__ESDHC1_DAT5, + MX53_PAD_PATA_DATA10__ESDHC1_DAT6, + MX53_PAD_PATA_DATA11__ESDHC1_DAT7, + MX53_PAD_GPIO_1__GPIO1_1, + MX53_PAD_GPIO_9__GPIO1_9, + + /* SDHC2 */ + MX53_PAD_SD2_CLK__ESDHC2_CLK, + MX53_PAD_SD2_CMD__ESDHC2_CMD, + MX53_PAD_SD2_DATA0__ESDHC2_DAT0, + MX53_PAD_SD2_DATA1__ESDHC2_DAT1, + MX53_PAD_SD2_DATA2__ESDHC2_DAT2, + MX53_PAD_SD2_DATA3__ESDHC2_DAT3, + MX53_PAD_PATA_DATA12__ESDHC2_DAT4, + MX53_PAD_PATA_DATA13__ESDHC2_DAT5, + MX53_PAD_PATA_DATA14__ESDHC2_DAT6, + MX53_PAD_PATA_DATA15__ESDHC2_DAT7, + MX53_PAD_GPIO_4__GPIO1_4, + MX53_PAD_GPIO_2__GPIO1_2, + + /* WEIM for CS1 */ + /* ETHERNET_INT_B */ + MX53_PAD_EIM_EB3__GPIO2_31, + MX53_PAD_EIM_D16__EMI_WEIM_D_16, + MX53_PAD_EIM_D17__EMI_WEIM_D_17, + MX53_PAD_EIM_D18__EMI_WEIM_D_18, + MX53_PAD_EIM_D19__EMI_WEIM_D_19, + MX53_PAD_EIM_D20__EMI_WEIM_D_20, + MX53_PAD_EIM_D21__EMI_WEIM_D_21, + MX53_PAD_EIM_D22__EMI_WEIM_D_22, + MX53_PAD_EIM_D23__EMI_WEIM_D_23, + MX53_PAD_EIM_D24__EMI_WEIM_D_24, + MX53_PAD_EIM_D25__EMI_WEIM_D_25, + MX53_PAD_EIM_D26__EMI_WEIM_D_26, + MX53_PAD_EIM_D27__EMI_WEIM_D_27, + MX53_PAD_EIM_D28__EMI_WEIM_D_28, + MX53_PAD_EIM_D29__EMI_WEIM_D_29, + MX53_PAD_EIM_D30__EMI_WEIM_D_30, + MX53_PAD_EIM_D31__EMI_WEIM_D_31, + MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0, + MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1, + MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2, + MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3, + MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4, + MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5, + MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6, + MX53_PAD_EIM_OE__EMI_WEIM_OE, + MX53_PAD_EIM_RW__EMI_WEIM_RW, + MX53_PAD_EIM_CS1__EMI_WEIM_CS_1, + /* I2C2 */ + MX53_PAD_EIM_EB2__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, + + /* I2C3 */ + MX53_PAD_GPIO_3__I2C3_SCL, + MX53_PAD_GPIO_16__I2C3_SDA, + + /* TOUCH_INT_B */ + MX53_PAD_GPIO_17__GPIO7_12, + + /* MAINBRD_SPDIF_IN */ + MX53_PAD_KEY_COL3__SPDIF_IN1, + /* LVDS */ + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0, + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3, + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2, + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK, + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0, + /* PWM */ + MX53_PAD_DISP0_DAT8__PWM1_PWMO, + MX53_PAD_DISP0_DAT9__PWM2_PWMO +}; + +/* Config CS1 settings for ethernet controller */ +static void weim_cs_config(void) +{ + u32 reg; + void __iomem *weim_base, *iomuxc_base; + weim_base = ioremap(MX53_WEIM_BASE_ADDR, SZ_4K); + iomuxc_base = ioremap(MX53_IOMUXC_BASE_ADDR, SZ_4K); + + /* CS1 timings for LAN9220 */ + writel(0x20001, (weim_base + 0x18)); + writel(0x0, (weim_base + 0x1C)); + writel(0x16000202, (weim_base + 0x20)); + writel(0x00000002, (weim_base + 0x24)); + writel(0x16002082, (weim_base + 0x28)); + writel(0x00000000, (weim_base + 0x2C)); + writel(0x00000000, (weim_base + 0x90)); + + /* specify 64 MB on CS1 and CS0 on GPR1 */ + reg = readl(iomuxc_base + 0x4); + reg &= ~0x3F; + reg |= 0x1B; + writel(reg, (iomuxc_base + 0x4)); + iounmap(iomuxc_base); + iounmap(weim_base); +} + +static struct resource ard_smsc911x_resources[] = { + { + .start = MX53_CS1_BASE_ADDR, + .end = MX53_CS1_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = gpio_to_irq(ARD_ETHERNET_INT_B), + .end = gpio_to_irq(ARD_ETHERNET_INT_B), + .flags = IORESOURCE_IRQ, + }, +}; + + +struct smsc911x_platform_config ard_smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT, +}; + +static struct platform_device ard_smsc_lan9220_device = { + .name = "smsc911x", + .id = 0, + .num_resources = ARRAY_SIZE(ard_smsc911x_resources), + .resource = ard_smsc911x_resources, +}; + +static iomux_v3_cfg_t mx53_ard_esai_pads[] = { + MX53_PAD_FEC_MDIO__ESAI1_SCKR, + MX53_PAD_FEC_REF_CLK__ESAI1_FSR, + MX53_PAD_FEC_CRS_DV__ESAI1_SCKT, + MX53_PAD_FEC_RXD1__ESAI1_FST, + MX53_PAD_FEC_TX_EN__ESAI1_TX3_RX2, + MX53_PAD_GPIO_5__ESAI1_TX2_RX3, + MX53_PAD_FEC_TXD0__ESAI1_TX4_RX1, + MX53_PAD_GPIO_8__ESAI1_TX5_RX0, + MX53_PAD_NANDF_CS2__ESAI1_TX0, + MX53_PAD_NANDF_CS3__ESAI1_TX1, + MX53_PAD_PATA_DATA4__GPIO2_4, +}; + +void ard_gpio_activate_esai_ports(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53_ard_esai_pads, + ARRAY_SIZE(mx53_ard_esai_pads)); + /* ESAI_INT */ + gpio_request(ARD_ESAI_INT, "esai-int"); + gpio_direction_input(ARD_ESAI_INT); + +} + +static struct imx_esai_platform_data esai_data = { + .flags = IMX_ESAI_NET, +}; + +static struct platform_device mxc_alsa_surround_device = { + .name = "imx-cs42888", +}; + +static struct mxc_audio_platform_data mxc_surround_audio_data = { + .ext_ram = 1, + .sysclk = 24576000, +}; + +static struct mxc_audio_codec_platform_data cs42888_data = { + .rates = (SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000), +}; + +static int imx53_init_audio(void) +{ + ard_gpio_activate_esai_ports(); + + mxc_register_device(&mxc_alsa_surround_device, + &mxc_surround_audio_data); + imx53_add_imx_esai(0, &esai_data); + + return 0; +} + +static int mx53_ard_max7310_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + static int max7310_gpio_value[] = { + 1, 1, 1, 1, 0, 0, 0, 0, + }; + int n; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 GPIO Expander"); + if (max7310_gpio_value[n] < 0) + gpio_direction_input(gpio_base + n); + else + gpio_direction_output(gpio_base + n, + max7310_gpio_value[n]); + /* Export, direction locked down */ + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data mx53_i2c_max7310_platdata = { + .gpio_base = MAX7310_BASE_ADDR, + .invert = 0, /* Do not invert */ + .setup = mx53_ard_max7310_setup, +}; + +static const struct imxuart_platform_data mx53_ard_uart_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct esdhc_platform_data mx53_ard_sd1_data __initconst = { + .cd_gpio = ARD_SD1_CD, + .wp_gpio = ARD_SD1_WP, +}; + +static const struct esdhc_platform_data mx53_ard_sd2_data __initconst = { + .cd_gpio = ARD_SD2_CD, + .wp_gpio = ARD_SD2_WP, +}; + +static struct imxi2c_platform_data mx53_ard_i2c1_data = { + .bitrate = 50000, +}; + +static struct imxi2c_platform_data mx53_ard_i2c2_data = { + .bitrate = 400000, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "cs42888", + .addr = 0x48, + .platform_data = (void *)&cs42888_data, + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("max11801", 0x49), + .irq = gpio_to_irq(ARD_TS_INT), + }, + { + .type = "max7310", + .addr = 0x18, + .platform_data = &mx53_i2c_max7310_platdata, + }, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 0, + .spdif_rx = 1, + .spdif_clk_44100 = 0, /* tx clk from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* tx clk from CKIH2 for 48k and 32k */ + .spdif_div_44100 = 8, + .spdif_div_48000 = 8, + .spdif_div_32000 = 12, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct mxc_regulator_platform_data ard_regulator_data = { + .cpu_reg_id = "SW1", +}; + +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static inline void mx53_ard_init_uart(void) +{ + imx53_add_imx_uart(0, NULL); + imx53_add_imx_uart(1, &mx53_ard_uart_data); + imx53_add_imx_uart(2, &mx53_ard_uart_data); +} + +static struct ipuv3_fb_platform_data ard_fb_data[] = { + { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 16, + .int_clk = false, + }, + { + .disp_dev = "vga", + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "VGA-XGA", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static struct imx_ipuv3_platform_data ipu_data = { + .rev = 3, +}; + +static struct platform_pwm_backlight_data ard_pwm1_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct platform_pwm_backlight_data ard_pwm2_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct fsl_mxc_tve_platform_data tve_data = { + .dac_reg = "LDO4", +}; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 0, + .disp_id = 0, + .ext_ref = 1, + .mode = LDB_SIN0, +}; + +static void __init mx53_ard_io_init(void) +{ + /* MX53 ARD board */ + pr_info("MX53 ARD board \n"); + gpio_request(ARD_ETHERNET_INT_B, "eth-int-b"); + gpio_direction_input(ARD_ETHERNET_INT_B); +} + +static int __initdata enable_ard_vga = { 0 }; +static int __init ard_vga_setup(char *__unused) +{ + enable_ard_vga = 1; + printk(KERN_INFO "Enable MX53 ARD VGA\n"); + return cpu_is_mx53(); +} +__setup("ard-vga", ard_vga_setup); + +static void __init mx53_ard_board_init(void) +{ + int i; + mxc_iomux_v3_setup_multiple_pads(mx53_ard_pads, + ARRAY_SIZE(mx53_ard_pads)); + + /* setup VGA PINs */ + if (enable_ard_vga) { + iomux_v3_cfg_t vga; + vga = MX53_PAD_EIM_OE__IPU_DI1_PIN7; + mxc_iomux_v3_setup_pad(vga); + vga = MX53_PAD_EIM_RW__IPU_DI1_PIN8; + mxc_iomux_v3_setup_pad(vga); + } + + gp_reg_id = ard_regulator_data.cpu_reg_id; + lp_reg_id = ard_regulator_data.vcc_reg_id; + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + mx53_ard_init_uart(); + + imx53_add_ipuv3(0, &ipu_data); + for (i = 0; i < ARRAY_SIZE(ard_fb_data); i++) + imx53_add_ipuv3fb(i, &ard_fb_data[i]); + + imx53_add_vpu(); + imx53_add_ldb(&ldb_data); + imx53_add_tve(&tve_data); + imx53_add_v4l2_output(0); + + imx53_add_mxc_pwm(0); + imx53_add_mxc_pwm_backlight(0, &ard_pwm1_backlight_data); + imx53_add_mxc_pwm(1); + imx53_add_mxc_pwm_backlight(1, &ard_pwm2_backlight_data); + + imx53_add_srtc(); + imx53_add_imx2_wdt(0, NULL); + imx53_add_sdhci_esdhc_imx(0, &mx53_ard_sd1_data); + imx53_add_sdhci_esdhc_imx(1, &mx53_ard_sd2_data); + mxc_register_device(&imx_ahci_device_hwmon, NULL); + + weim_cs_config(); + mx53_ard_io_init(); + mxc_register_device(&ard_smsc_lan9220_device, &ard_smsc911x_config); + imx53_add_imx_i2c(1, &mx53_ard_i2c1_data); + imx53_add_imx_i2c(2, &mx53_ard_i2c2_data); + + imx53_add_spdif(&mxc_spdif_data); + imx53_add_spdif_dai(); + imx53_add_spdif_audio_device(); + + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + imx53_init_audio(); + + mx5_cpu_regulator_init(); + + /* this call required to release SCC RAM partition held by ROM + * during boot, even if SCC2 driver is not part of the image + */ + imx53_add_mxc_scc2(); +} + +static void __init mx53_ard_timer_init(void) +{ + mx53_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mx53_ard_timer = { + .init = mx53_ard_timer_init, +}; + +MACHINE_START(MX53_ARD, "Freescale MX53 ARD Board") + .fixup = fixup_mxc_board, + .map_io = mx53_map_io, + .init_early = imx53_init_early, + .init_irq = mx53_init_irq, + .timer = &mx53_ard_timer, + .init_machine = mx53_ard_board_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx53_evk.c b/arch/arm/mach-mx5/board-mx53_evk.c new file mode 100755 index 00000000..be703204 --- /dev/null +++ b/arch/arm/mach-mx5/board-mx53_evk.c @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2010 Yong Shen. <Yong.Shen@linaro.org> + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/fec.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/mxcfb.h> +#include <linux/ipu.h> +#include <linux/pwm_backlight.h> +#include <linux/regulator/consumer.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/imx-uart.h> +#include <mach/iomux-mx53.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_dvfs.h> + +#include "crm_regs.h" +#include "devices-imx53.h" +#include "devices.h" + +#define MX53_EVK_FEC_PHY_RST IMX_GPIO_NR(7, 6) +#define EVK_ECSPI1_CS0 IMX_GPIO_NR(2, 30) +#define EVK_ECSPI1_CS1 IMX_GPIO_NR(3, 19) +#define EVK_HP_DETECT IMX_GPIO_NR(2, 5) /* GPIO_2_5 */ +#define EVK_ECSPI1_CS0 IMX_GPIO_NR(2, 30) +#define EVK_SD3_CD IMX_GPIO_NR(3, 11) /* GPIO_3_11 */ +#define EVK_SD3_WP IMX_GPIO_NR(3, 12) /* GPIO_3_12 */ +#define EVK_SD1_CD IMX_GPIO_NR(3, 13) /* GPIO_3_13 */ +#define EVK_SD1_WP IMX_GPIO_NR(3, 14) /* GPIO_3_14 */ +#define EVK_ECSPI1_CS1 IMX_GPIO_NR(3, 19) +#define EVK_DISP0_PD IMX_GPIO_NR(3, 24) /* GPIO_3_24 */ +#define EVK_TS_INT IMX_GPIO_NR(3, 26) /* GPIO_3_26 */ +#define EVK_DISP0_I2C_EN IMX_GPIO_NR(3, 28) /* GPIO_3_28 */ +#define EVK_DISP0_DET_INT IMX_GPIO_NR(3, 31) /* GPIO_3_31 */ +#define EVK_CAM_RESET IMX_GPIO_NR(4, 0) /* GPIO_4_0 */ +#define EVK_ESAI_RESET IMX_GPIO_NR(4, 2) /* GPIO_4_2 */ +#define EVK_CAN2_EN2 IMX_GPIO_NR(4, 4) /* GPIO_4_4 */ +#define EVK_12V_EN IMX_GPIO_NR(4, 5) /* GPIO_4_5 */ +#define EVK_DISP0_RESET IMX_GPIO_NR(5, 0) /* GPIO_5_0 */ +#define EVK_USB_HUB_RESET IMX_GPIO_NR(5, 20) /* GPIO_5_20 */ +#define EVK_TVIN_PWR IMX_GPIO_NR(5, 23) /* GPIO_5_23 */ +#define EVK_CAN2_EN1 IMX_GPIO_NR(5, 24) /* GPIO_5_24 */ +#define EVK_TVIN_RESET IMX_GPIO_NR(5, 25) /* GPIO_5_25 */ +#define EVK_OTG_VBUS IMX_GPIO_NR(6, 6) /* GPIO_6_6 */ +#define EVK_FEC_PHY_RST IMX_GPIO_NR(7, 6) +#define EVK_USBH1_VBUS IMX_GPIO_NR(7, 8) /* GPIO_7_8 */ +#define EVK_PMIC_INT IMX_GPIO_NR(7, 11) /* GPIO_7_11 */ +#define EVK_CAN1_EN1 IMX_GPIO_NR(7, 12) /* GPIO_7_12 */ +#define EVK_CAN1_EN2 IMX_GPIO_NR(7, 13) /* GPIO_7_13 */ + +#define ARM2_SD1_CD IMX_GPIO_NR(1, 1) /* GPIO_1_1 */ +#define ARM2_OTG_VBUS IMX_GPIO_NR(3, 22) /* GPIO_3_22 */ +#define ARM2_LCD_CONTRAST IMX_GPIO_NR(4, 20) /* GPIO_4_20 */ + +extern char *lp_reg_id; +extern char *gp_reg_id; +extern void mx5_cpu_regulator_init(void); + +static iomux_v3_cfg_t mx53common_pads[] = { + MX53_PAD_EIM_WAIT__GPIO5_0, + + MX53_PAD_EIM_OE__IPU_DI1_PIN7, + MX53_PAD_EIM_RW__IPU_DI1_PIN8, + + MX53_PAD_EIM_A25__IPU_DI0_D1_CS, + + MX53_PAD_EIM_D16__ECSPI1_SCLK, + MX53_PAD_EIM_D17__ECSPI1_MISO, + MX53_PAD_EIM_D18__ECSPI1_MOSI, + + MX53_PAD_EIM_D20__IPU_SER_DISP0_CS, + + MX53_PAD_EIM_D23__IPU_DI0_D0_CS, + + MX53_PAD_EIM_D24__GPIO3_24, + MX53_PAD_EIM_D26__GPIO3_26, + + MX53_PAD_EIM_D29__IPU_DISPB0_SER_RS, + + MX53_PAD_EIM_D30__IPU_DI0_PIN11, + MX53_PAD_EIM_D31__IPU_DI0_PIN12, + + MX53_PAD_PATA_DA_1__GPIO7_7, + MX53_PAD_PATA_DATA4__GPIO2_4, + MX53_PAD_PATA_DATA5__GPIO2_5, + MX53_PAD_PATA_DATA6__GPIO2_6, + + MX53_PAD_SD2_CLK__ESDHC2_CLK, + MX53_PAD_SD2_CMD__ESDHC2_CMD, + MX53_PAD_SD2_DATA0__ESDHC2_DAT0, + MX53_PAD_SD2_DATA1__ESDHC2_DAT1, + MX53_PAD_SD2_DATA2__ESDHC2_DAT2, + MX53_PAD_SD2_DATA3__ESDHC2_DAT3, + MX53_PAD_PATA_DATA12__ESDHC2_DAT4, + MX53_PAD_PATA_DATA13__ESDHC2_DAT5, + MX53_PAD_PATA_DATA14__ESDHC2_DAT6, + MX53_PAD_PATA_DATA15__ESDHC2_DAT7, + + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX, + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX, + + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX, + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX, + MX53_PAD_PATA_DIOR__UART2_RTS, + MX53_PAD_PATA_INTRQ__UART2_CTS, + + MX53_PAD_PATA_CS_0__UART3_TXD_MUX, + MX53_PAD_PATA_CS_1__UART3_RXD_MUX, + + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC, + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD, + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD, + + MX53_PAD_CSI0_DAT7__GPIO5_25, + + MX53_PAD_GPIO_2__MLB_MLBDAT, + MX53_PAD_GPIO_3__MLB_MLBCLK, + + MX53_PAD_GPIO_6__MLB_MLBSIG, + + MX53_PAD_GPIO_4__GPIO1_4, + MX53_PAD_GPIO_7__GPIO1_7, + MX53_PAD_GPIO_8__GPIO1_8, + + MX53_PAD_GPIO_10__GPIO4_0, + + MX53_PAD_KEY_COL2__CAN1_TXCAN, + MX53_PAD_KEY_ROW2__CAN1_RXCAN, + + /* CAN1 -- EN */ + MX53_PAD_GPIO_18__GPIO7_13, + /* CAN1 -- STBY */ + MX53_PAD_GPIO_17__GPIO7_12, + /* CAN1 -- NERR */ + MX53_PAD_GPIO_5__GPIO1_5, + + MX53_PAD_KEY_COL4__CAN2_TXCAN, + MX53_PAD_KEY_ROW4__CAN2_RXCAN, + + /* CAN2 -- EN */ + MX53_PAD_CSI0_DAT6__GPIO5_24, + /* CAN2 -- STBY */ + MX53_PAD_GPIO_14__GPIO4_4, + /* CAN2 -- NERR */ + MX53_PAD_CSI0_DAT4__GPIO5_22, + + MX53_PAD_GPIO_11__GPIO4_1, + MX53_PAD_GPIO_12__GPIO4_2, + MX53_PAD_GPIO_13__GPIO4_3, + MX53_PAD_GPIO_16__GPIO7_11, + MX53_PAD_GPIO_19__GPIO4_5, + + /* DI0 display clock */ + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK, + + /* DI0 data enable */ + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15, + /* DI0 HSYNC */ + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2, + /* DI0 VSYNC */ + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3, + + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0, + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1, + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2, + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3, + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4, + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5, + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6, + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7, + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8, + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9, + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10, + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11, + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12, + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13, + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14, + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15, + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16, + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17, + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18, + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19, + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20, + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21, + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22, + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23, + + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0, + + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3, + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK, + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2, + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0, + + /* audio and CSI clock out */ + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK, + + MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12, + MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13, + MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14, + MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15, + MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16, + MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17, + MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18, + MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19, + + MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK, + /* Camera low power */ + MX53_PAD_CSI0_DAT5__GPIO5_23, + + /* esdhc1 */ + MX53_PAD_SD1_CMD__ESDHC1_CMD, + MX53_PAD_SD1_CLK__ESDHC1_CLK, + MX53_PAD_SD1_DATA0__ESDHC1_DAT0, + MX53_PAD_SD1_DATA1__ESDHC1_DAT1, + MX53_PAD_SD1_DATA2__ESDHC1_DAT2, + MX53_PAD_SD1_DATA3__ESDHC1_DAT3, + + /* esdhc3 */ + MX53_PAD_PATA_DATA8__ESDHC3_DAT0, + MX53_PAD_PATA_DATA9__ESDHC3_DAT1, + MX53_PAD_PATA_DATA10__ESDHC3_DAT2, + MX53_PAD_PATA_DATA11__ESDHC3_DAT3, + MX53_PAD_PATA_DATA0__ESDHC3_DAT4, + MX53_PAD_PATA_DATA1__ESDHC3_DAT5, + MX53_PAD_PATA_DATA2__ESDHC3_DAT6, + MX53_PAD_PATA_DATA3__ESDHC3_DAT7, + MX53_PAD_PATA_RESET_B__ESDHC3_CMD, + MX53_PAD_PATA_IORDY__ESDHC3_CLK, + + /* FEC pins */ + MX53_PAD_FEC_MDIO__FEC_MDIO, + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK, + MX53_PAD_FEC_RX_ER__FEC_RX_ER, + MX53_PAD_FEC_CRS_DV__FEC_RX_DV, + MX53_PAD_FEC_RXD1__FEC_RDATA_1, + MX53_PAD_FEC_RXD0__FEC_RDATA_0, + MX53_PAD_FEC_TX_EN__FEC_TX_EN, + MX53_PAD_FEC_TXD1__FEC_TDATA_1, + MX53_PAD_FEC_TXD0__FEC_TDATA_0, + MX53_PAD_FEC_MDC__FEC_MDC, + + MX53_PAD_CSI0_DAT8__I2C1_SDA, + MX53_PAD_CSI0_DAT9__I2C1_SCL, + + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, +}; + +static iomux_v3_cfg_t mx53evk_pads[] = { + /* USB OTG USB_OC */ + MX53_PAD_EIM_A24__GPIO5_4, + + /* USB OTG USB_PWR */ + MX53_PAD_EIM_A23__GPIO6_6, + + /* DISPB0_SER_CLK */ + MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK, + + /* DI0_PIN1 */ + MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN, + + /* DISP0 I2C ENABLE */ + MX53_PAD_EIM_D28__GPIO3_28, + + /* DISP0 DET */ + MX53_PAD_EIM_D31__GPIO3_31, + + /* SDHC1 SD_CD */ + MX53_PAD_EIM_DA13__GPIO3_13, + + /* SDHC1 SD_WP */ + MX53_PAD_EIM_DA14__GPIO3_14, + + /* SDHC3 SD_CD */ + MX53_PAD_EIM_DA11__GPIO3_11, + + /* SDHC3 SD_WP */ + MX53_PAD_EIM_DA12__GPIO3_12, + + /* PWM backlight */ + MX53_PAD_GPIO_1__PWM2_PWMO, + + /* USB HOST USB_PWR */ + MX53_PAD_PATA_DA_2__GPIO7_8, + + /* USB HOST USB_RST */ + MX53_PAD_CSI0_DATA_EN__GPIO5_20, + + /* USB HOST CARD_ON */ + MX53_PAD_EIM_DA15__GPIO3_15, + + /* USB HOST CARD_RST */ + MX53_PAD_PATA_DATA7__GPIO2_7, + + /* USB HOST WAN_WAKE */ + MX53_PAD_EIM_D25__GPIO3_25, + + /* FEC_RST */ + MX53_PAD_PATA_DA_0__GPIO7_6, +}; + +static iomux_v3_cfg_t mx53arm2_pads[] = { + /* USB OTG USB_OC */ + MX53_PAD_EIM_D21__GPIO3_21, + + /* USB OTG USB_PWR */ + MX53_PAD_EIM_D22__GPIO3_22, + + /* SDHC1 SD_CD */ + MX53_PAD_GPIO_1__GPIO1_1, + + /* gpio backlight */ + MX53_PAD_DI0_PIN4__GPIO4_20, +}; + +static iomux_v3_cfg_t mx53_nand_pads[] = { + MX53_PAD_NANDF_CLE__EMI_NANDF_CLE, + MX53_PAD_NANDF_ALE__EMI_NANDF_ALE, + MX53_PAD_NANDF_WP_B__EMI_NANDF_WP_B, + MX53_PAD_NANDF_WE_B__EMI_NANDF_WE_B, + MX53_PAD_NANDF_RE_B__EMI_NANDF_RE_B, + MX53_PAD_NANDF_RB0__EMI_NANDF_RB_0, + MX53_PAD_NANDF_CS0__EMI_NANDF_CS_0, + MX53_PAD_NANDF_CS1__EMI_NANDF_CS_1 , + MX53_PAD_NANDF_CS2__EMI_NANDF_CS_2, + MX53_PAD_NANDF_CS3__EMI_NANDF_CS_3 , + MX53_PAD_EIM_DA0__EMI_NAND_WEIM_DA_0, + MX53_PAD_EIM_DA1__EMI_NAND_WEIM_DA_1, + MX53_PAD_EIM_DA2__EMI_NAND_WEIM_DA_2, + MX53_PAD_EIM_DA3__EMI_NAND_WEIM_DA_3, + MX53_PAD_EIM_DA4__EMI_NAND_WEIM_DA_4, + MX53_PAD_EIM_DA5__EMI_NAND_WEIM_DA_5, + MX53_PAD_EIM_DA6__EMI_NAND_WEIM_DA_6, + MX53_PAD_EIM_DA7__EMI_NAND_WEIM_DA_7, +}; + +static const struct imxuart_platform_data mx53_evk_uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct ipuv3_fb_platform_data evk_fb_data[] = { + { + .disp_dev = "lcd", + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .default_bpp = 16, + .int_clk = false, + }, { + .disp_dev = "vga", + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "VGA-XGA", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static struct imx_ipuv3_platform_data ipu_data = { + .rev = 3, +}; + +static struct platform_pwm_backlight_data evk_pwm_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct fsl_mxc_tve_platform_data tve_data = { + .dac_reg = "VVIDEO", +}; + +static inline void mx53_evk_init_uart(void) +{ + imx53_add_imx_uart(0, NULL); + imx53_add_imx_uart(1, &mx53_evk_uart_pdata); + imx53_add_imx_uart(2, NULL); +} + +static const struct imxi2c_platform_data mx53_evk_i2c_data __initconst = { + .bitrate = 100000, +}; + +static inline void mx53_evk_fec_reset(void) +{ + int ret; + + /* reset FEC PHY */ + ret = gpio_request_one(MX53_EVK_FEC_PHY_RST, GPIOF_OUT_INIT_LOW, + "fec-phy-reset"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret); + return; + } + msleep(1); + gpio_set_value(MX53_EVK_FEC_PHY_RST, 1); +} + +static struct fec_platform_data mx53_evk_fec_pdata = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static struct spi_board_info mx53_evk_spi_board_info[] __initdata = { + { + .modalias = "mtd_dataflash", + .max_speed_hz = 25000000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + .platform_data = NULL, + }, +}; + +static int mx53_evk_spi_cs[] = { + EVK_ECSPI1_CS0, + EVK_ECSPI1_CS1, +}; + +static const struct spi_imx_master mx53_evk_spi_data __initconst = { + .chipselect = mx53_evk_spi_cs, + .num_chipselect = ARRAY_SIZE(mx53_evk_spi_cs), +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { +}; + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(EVK_DISP0_RESET, 0); + msleep(10); + gpio_set_value(EVK_DISP0_RESET, 1); + msleep(10); +} + +static struct fsl_mxc_lcd_platform_data sii902x_hdmi_data = { + .reset = sii902x_hdmi_reset, +}; + +static void ddc_dvi_init(void) +{ + /* enable DVI I2C */ + gpio_set_value(EVK_DISP0_I2C_EN, 1); +} + +static int ddc_dvi_update(void) +{ + /* DVI cable state */ + if (gpio_get_value(EVK_DISP0_DET_INT) == 1) + return 1; + else + return 0; +} + +static struct fsl_mxc_dvi_platform_data evk_ddc_dvi_data = { + .ipu_id = 0, + .disp_id = 0, + .init = ddc_dvi_init, + .update = ddc_dvi_update, + .analog_regulator = "VSD", +}; + +/* TO DO add platform data */ +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000-i2c", + .addr = 0x0a, + }, + { + .type = "tsc2007", + .addr = 0x48, + .irq = gpio_to_irq(EVK_TS_INT), + }, + { + .type = "backlight-i2c", + .addr = 0x2c, + }, + { + .type = "mxc_dvi", + .addr = 0x50, + .irq = gpio_to_irq(EVK_DISP0_DET_INT), + .platform_data = &evk_ddc_dvi_data, + }, + { + .type = "sii902x", + .addr = 0x39, + .irq = gpio_to_irq(EVK_DISP0_DET_INT), + .platform_data = &sii902x_hdmi_data, + }, +}; + +static struct mxc_dvfs_platform_data evk_dvfs_core_data = { + .reg_id = "SW1", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static const struct esdhc_platform_data mx53_evk_sd1_data __initconst = { + .cd_gpio = EVK_SD1_CD, + .wp_gpio = EVK_SD1_WP, +}; + +static const struct esdhc_platform_data mx53_evk_sd3_data __initconst = { + .cd_gpio = EVK_SD3_CD, + .wp_gpio = EVK_SD3_WP, +}; + +static int __initdata enable_spdif = { 0 }; +static int __init spdif_setup(char *__unused) +{ + enable_spdif = 1; + return 1; +} +__setup("spdif", spdif_setup); + +static void __init mx53_evk_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx53common_pads, + ARRAY_SIZE(mx53common_pads)); + + if (board_is_mx53_arm2()) { + /* MX53 ARM2 CPU board */ + pr_info("MX53 ARM2 board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53arm2_pads, + ARRAY_SIZE(mx53arm2_pads)); + + /* Config GPIO for OTG VBus */ + gpio_request(ARM2_OTG_VBUS, "otg-vbus"); + gpio_direction_output(ARM2_OTG_VBUS, 1); + + gpio_request(ARM2_SD1_CD, "sdhc1-cd"); + gpio_direction_input(ARM2_SD1_CD); /* SD1 CD */ + + gpio_request(ARM2_LCD_CONTRAST, "lcd-contrast"); + gpio_direction_output(ARM2_LCD_CONTRAST, 1); + } else { + /* MX53 EVK board */ + pr_info("MX53 EVK board \n"); + mxc_iomux_v3_setup_multiple_pads(mx53evk_pads, + ARRAY_SIZE(mx53evk_pads)); + + /* Host1 Vbus with GPIO high */ + gpio_request(EVK_USBH1_VBUS, "usbh1-vbus"); + gpio_direction_output(EVK_USBH1_VBUS, 1); + /* shutdown the Host1 Vbus when system bring up, + * Vbus will be opened in Host1 driver's probe function */ + gpio_set_value(EVK_USBH1_VBUS, 0); + + /* USB HUB RESET - De-assert USB HUB RESET_N */ + gpio_request(EVK_USB_HUB_RESET, "usb-hub-reset"); + gpio_direction_output(EVK_USB_HUB_RESET, 0); + msleep(1); + gpio_set_value(EVK_USB_HUB_RESET, 1); + + /* Config GPIO for OTG VBus */ + gpio_request(EVK_OTG_VBUS, "otg-vbus"); + gpio_direction_output(EVK_OTG_VBUS, 0); + if (board_is_mx53_evk_a()) /*rev A,"1" disable, "0" enable vbus*/ + gpio_set_value(EVK_OTG_VBUS, 1); + else if (board_is_mx53_evk_b()) /* rev B,"0" disable,"1" enable Vbus*/ + gpio_set_value(EVK_OTG_VBUS, 0); + + gpio_request(EVK_SD1_CD, "sdhc1-cd"); + gpio_direction_input(EVK_SD1_CD); /* SD1 CD */ + gpio_request(EVK_SD1_WP, "sdhc1-wp"); + gpio_direction_input(EVK_SD1_WP); /* SD1 WP */ + + /* SD3 CD */ + gpio_request(EVK_SD3_CD, "sdhc3-cd"); + gpio_direction_input(EVK_SD3_CD); + + /* SD3 WP */ + gpio_request(EVK_SD3_WP, "sdhc3-wp"); + gpio_direction_input(EVK_SD3_WP); + + /* reset FEC PHY */ + gpio_request(EVK_FEC_PHY_RST, "fec-phy-reset"); + gpio_direction_output(EVK_FEC_PHY_RST, 0); + msleep(1); + gpio_set_value(EVK_FEC_PHY_RST, 1); + + gpio_request(EVK_ESAI_RESET, "fesai-reset"); + gpio_direction_output(EVK_ESAI_RESET, 0); + } + + /* DISP0 Detect */ + gpio_request(EVK_DISP0_DET_INT, "disp0-detect"); + gpio_direction_input(EVK_DISP0_DET_INT); + /* DISP0 Reset - Assert for i2c disabled mode */ + gpio_request(EVK_DISP0_RESET, "disp0-reset"); + gpio_direction_output(EVK_DISP0_RESET, 0); + + /* DISP0 Power-down */ + gpio_request(EVK_DISP0_PD, "disp0-pd"); + gpio_direction_output(EVK_DISP0_PD, 1); + + /* DISP0 I2C enable */ + gpio_request(EVK_DISP0_I2C_EN, "disp0-i2c"); + gpio_direction_output(EVK_DISP0_I2C_EN, 0); + + mxc_iomux_v3_setup_multiple_pads(mx53_nand_pads, + ARRAY_SIZE(mx53_nand_pads)); + + gpio_request(EVK_PMIC_INT, "pmic-int"); + gpio_direction_input(EVK_PMIC_INT); /*PMIC_INT*/ + + /* headphone_det_b */ + gpio_request(EVK_HP_DETECT, "hp-detect"); + gpio_direction_input(EVK_HP_DETECT); + + /* power key */ + + /* LCD related gpio */ + + /* Camera reset */ + gpio_request(EVK_CAM_RESET, "cam-reset"); + gpio_direction_output(EVK_CAM_RESET, 1); + + /* TVIN reset */ + gpio_request(EVK_TVIN_RESET, "tvin-reset"); + gpio_direction_output(EVK_TVIN_RESET, 0); + msleep(5); + gpio_set_value(EVK_TVIN_RESET, 1); + + /* TVin power down */ + gpio_request(EVK_TVIN_PWR, "tvin-pwr"); + gpio_direction_output(EVK_TVIN_PWR, 0); + + /* CAN1 enable GPIO*/ + gpio_request(EVK_CAN1_EN1, "can1-en1"); + gpio_direction_output(EVK_CAN1_EN1, 0); + + gpio_request(EVK_CAN1_EN2, "can1-en2"); + gpio_direction_output(EVK_CAN1_EN2, 0); + + /* CAN2 enable GPIO*/ + gpio_request(EVK_CAN2_EN1, "can2-en1"); + gpio_direction_output(EVK_CAN2_EN1, 0); + + gpio_request(EVK_CAN2_EN2, "can2-en2"); + gpio_direction_output(EVK_CAN2_EN2, 0); + + if (enable_spdif) { + iomux_v3_cfg_t spdif_pin = MX53_PAD_GPIO_19__SPDIF_OUT1; + mxc_iomux_v3_setup_pad(spdif_pin); + } else { + /* GPIO for 12V */ + gpio_request(EVK_12V_EN, "12v-en"); + gpio_direction_output(EVK_12V_EN, 0); + } +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* tx clk from CKIH1 for 44.1K */ + .spdif_clk_48000 = 7, /* tx clk from CKIH2 for 48k and 32k */ + .spdif_div_44100 = 8, + .spdif_div_48000 = 8, + .spdif_div_32000 = 12, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct mxc_regulator_platform_data evk_regulator_data = { + .cpu_reg_id = "SW1", + .vcc_reg_id = "SW2", +}; + +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static void __init mx53_evk_board_init(void) +{ + int i; + + mx53_evk_io_init(); + + gp_reg_id = evk_regulator_data.cpu_reg_id; + lp_reg_id = evk_regulator_data.vcc_reg_id; + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mx53_evk_init_uart(); + imx53_add_srtc(); + mx53_evk_fec_reset(); + imx53_add_fec(&mx53_evk_fec_pdata); + + imx53_add_ipuv3(0, &ipu_data); + for (i = 0; i < ARRAY_SIZE(evk_fb_data); i++) + imx53_add_ipuv3fb(i, &evk_fb_data[i]); + imx53_add_vpu(); + imx53_add_tve(&tve_data); + imx53_add_v4l2_output(0); + + if (!board_is_mx53_arm2()) { + imx53_add_mxc_pwm(1); + imx53_add_mxc_pwm_backlight(0, &evk_pwm_backlight_data); + } + + imx53_add_dvfs_core(&evk_dvfs_core_data); + imx53_add_busfreq(); + imx53_add_imx_i2c(0, &mx53_evk_i2c_data); + imx53_add_imx_i2c(1, &mx53_evk_i2c_data); + i2c_register_board_info(0, mxc_i2c0_board_info, + ARRAY_SIZE(mxc_i2c0_board_info)); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + + imx53_add_sdhci_esdhc_imx(0, &mx53_evk_sd1_data); + imx53_add_sdhci_esdhc_imx(2, &mx53_evk_sd3_data); + mxc_register_device(&imx_ahci_device_hwmon, NULL); + + spi_register_board_info(mx53_evk_spi_board_info, + ARRAY_SIZE(mx53_evk_spi_board_info)); + imx53_add_ecspi(0, &mx53_evk_spi_data); + imx53_add_imx2_wdt(0, NULL); + + imx53_add_spdif(&mxc_spdif_data); + imx53_add_spdif_dai(); + imx53_add_spdif_audio_device(); + + mx5_cpu_regulator_init(); + + /* this call required to release SCC RAM partition held by ROM + * during boot, even if SCC2 driver is not part of the image + */ + imx53_add_mxc_scc2(); +} + +static void __init mx53_evk_timer_init(void) +{ + mx53_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mx53_evk_timer = { + .init = mx53_evk_timer_init, +}; + +MACHINE_START(MX53_EVK, "Freescale MX53 EVK Board") + .fixup = fixup_mxc_board, + .map_io = mx53_map_io, + .init_early = imx53_init_early, + .init_irq = mx53_init_irq, + .timer = &mx53_evk_timer, + .init_machine = mx53_evk_board_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c new file mode 100755 index 00000000..257933af --- /dev/null +++ b/arch/arm/mach-mx5/board-mx53_loco.c @@ -0,0 +1,787 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/fec.h> +#include <linux/delay.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio.h> +#include <linux/mxcfb.h> +#include <linux/ipu.h> +#include <linux/pwm_backlight.h> +#include <linux/ahci_platform.h> +#include <linux/gpio_keys.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/imx-uart.h> +#include <mach/iomux-mx53.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_dvfs.h> +#include <mach/ahci_sata.h> +#include <mach/mxc.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/setup.h> + +#include "crm_regs.h" +#include "devices-imx53.h" +#include "devices.h" +#include "usb.h" + +#define MX53_LOCO_POWER IMX_GPIO_NR(1, 8) +#define LOCO_HEADPHONE_DET IMX_GPIO_NR(2, 5) +#define MX53_LOCO_UI1 IMX_GPIO_NR(2, 14) +#define MX53_LOCO_UI2 IMX_GPIO_NR(2, 15) +#define MX53_LOCO_SD3_CD IMX_GPIO_NR(3, 11) +#define MX53_LOCO_SD3_WP IMX_GPIO_NR(3, 12) +#define MX53_LOCO_SD1_CD IMX_GPIO_NR(3, 13) +#define LOCO_DISP0_PWR IMX_GPIO_NR(3, 24) +#define LOCO_DISP0_DET_INT IMX_GPIO_NR(3, 31) +#define LOCO_DISP0_RESET IMX_GPIO_NR(5, 0) +#define LOCO_FEC_PHY_RST IMX_GPIO_NR(7, 6) +#define LOCO_USBH1_VBUS IMX_GPIO_NR(7, 8) + +#define MX53_LOCO_MC34708_IRQ_REVA IMX_GPIO_NR(5, 30) +#define MX53_LOCO_MC34708_IRQ_REVB IMX_GPIO_NR(5, 23) + +static struct clk *sata_clk, *sata_ref_clk; +static u32 mx53_loco_mc34708_irq; + +extern void __iomem *arm_plat_base; +extern void __iomem *gpc_base; +extern void __iomem *ccm_base; +extern void __iomem *imx_otg_base; +extern char *lp_reg_id; +extern char *gp_reg_id; +extern void mx5_cpu_regulator_init(void); +extern int __init mx53_loco_init_da9052(void); +extern int __init mx53_loco_init_mc34708(u32 int_gpio); + +static iomux_v3_cfg_t mx53_loco_pads[] = { + /* FEC */ + MX53_PAD_FEC_MDC__FEC_MDC, + MX53_PAD_FEC_MDIO__FEC_MDIO, + MX53_PAD_FEC_REF_CLK__FEC_TX_CLK, + MX53_PAD_FEC_RX_ER__FEC_RX_ER, + MX53_PAD_FEC_CRS_DV__FEC_RX_DV, + MX53_PAD_FEC_RXD1__FEC_RDATA_1, + MX53_PAD_FEC_RXD0__FEC_RDATA_0, + MX53_PAD_FEC_TX_EN__FEC_TX_EN, + MX53_PAD_FEC_TXD1__FEC_TDATA_1, + MX53_PAD_FEC_TXD0__FEC_TDATA_0, + /* FEC_nRST */ + MX53_PAD_PATA_DA_0__GPIO7_6, + /* FEC_nINT */ + MX53_PAD_PATA_DATA4__GPIO2_4, + /* AUDMUX5 */ + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC, + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD, + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD, + /* I2C2 */ + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, + /* SD1 */ + MX53_PAD_SD1_CMD__ESDHC1_CMD, + MX53_PAD_SD1_CLK__ESDHC1_CLK, + MX53_PAD_SD1_DATA0__ESDHC1_DAT0, + MX53_PAD_SD1_DATA1__ESDHC1_DAT1, + MX53_PAD_SD1_DATA2__ESDHC1_DAT2, + MX53_PAD_SD1_DATA3__ESDHC1_DAT3, + /* SD1_CD */ + MX53_PAD_EIM_DA13__GPIO3_13, + /* SD3 */ + MX53_PAD_PATA_DATA8__ESDHC3_DAT0, + MX53_PAD_PATA_DATA9__ESDHC3_DAT1, + MX53_PAD_PATA_DATA10__ESDHC3_DAT2, + MX53_PAD_PATA_DATA11__ESDHC3_DAT3, + MX53_PAD_PATA_DATA0__ESDHC3_DAT4, + MX53_PAD_PATA_DATA1__ESDHC3_DAT5, + MX53_PAD_PATA_DATA2__ESDHC3_DAT6, + MX53_PAD_PATA_DATA3__ESDHC3_DAT7, + MX53_PAD_PATA_IORDY__ESDHC3_CLK, + MX53_PAD_PATA_RESET_B__ESDHC3_CMD, + /* SD3_CD */ + MX53_PAD_EIM_DA11__GPIO3_11, + /* SD3_WP */ + MX53_PAD_EIM_DA12__GPIO3_12, + /* VGA */ + MX53_PAD_EIM_OE__IPU_DI1_PIN7, + MX53_PAD_EIM_RW__IPU_DI1_PIN8, + /* DISPLB */ + MX53_PAD_EIM_D20__IPU_SER_DISP0_CS, + MX53_PAD_EIM_D21__IPU_DISPB0_SER_CLK, + MX53_PAD_EIM_D22__IPU_DISPB0_SER_DIN, + MX53_PAD_EIM_D23__IPU_DI0_D0_CS, + /* DISP0_POWER_EN */ + MX53_PAD_EIM_D24__GPIO3_24, + /* DISP0 DET INT */ + MX53_PAD_EIM_D31__GPIO3_31, + /* LVDS */ + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0, + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3, + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2, + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK, + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0, + /* I2C1 */ + MX53_PAD_CSI0_DAT8__I2C1_SDA, + MX53_PAD_CSI0_DAT9__I2C1_SCL, + /* UART1 */ + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX, + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX, + /* CSI0 */ + MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12, + MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13, + MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14, + MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15, + MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16, + MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17, + MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18, + MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19, + MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK, + /* DISPLAY */ + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK, + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15, + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2, + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3, + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0, + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1, + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2, + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3, + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4, + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5, + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6, + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7, + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8, + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9, + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10, + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11, + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12, + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13, + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14, + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15, + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16, + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17, + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18, + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19, + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20, + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21, + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22, + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23, + /* Audio CLK*/ + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK, + /* PWM */ + MX53_PAD_GPIO_1__PWM2_PWMO, + /* SPDIF */ + MX53_PAD_GPIO_7__SPDIF_PLOCK, + MX53_PAD_GPIO_17__SPDIF_OUT1, + /* GPIO */ + MX53_PAD_PATA_DA_1__GPIO7_7, + MX53_PAD_PATA_DA_2__GPIO7_8, + MX53_PAD_PATA_DATA5__GPIO2_5, + MX53_PAD_PATA_DATA6__GPIO2_6, + MX53_PAD_PATA_DATA14__GPIO2_14, + MX53_PAD_PATA_DATA15__GPIO2_15, + MX53_PAD_PATA_INTRQ__GPIO7_2, + MX53_PAD_EIM_WAIT__GPIO5_0, + MX53_PAD_NANDF_WP_B__GPIO6_9, + MX53_PAD_NANDF_RB0__GPIO6_10, + MX53_PAD_NANDF_CS1__GPIO6_14, + MX53_PAD_NANDF_CS2__GPIO6_15, + MX53_PAD_NANDF_CS3__GPIO6_16, + MX53_PAD_GPIO_5__GPIO1_5, + MX53_PAD_GPIO_16__GPIO7_11, + MX53_PAD_GPIO_8__GPIO1_8, +}; + +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ +} + +static const struct gpio_keys_button loco_buttons[] __initconst = { + GPIO_BUTTON(MX53_LOCO_POWER, KEY_POWER, 1, "power", 1), + GPIO_BUTTON(MX53_LOCO_UI1, KEY_VOLUMEUP, 1, "volume-up", 0), + GPIO_BUTTON(MX53_LOCO_UI2, KEY_VOLUMEDOWN, 1, "volume-down", 0), +}; + +static const struct gpio_keys_platform_data loco_button_data __initconst = { + .buttons = (struct gpio_keys_button *)loco_buttons, + .nbuttons = ARRAY_SIZE(loco_buttons), +}; + +static inline void mx53_loco_fec_reset(void) +{ + int ret; + + /* reset FEC PHY */ + ret = gpio_request(LOCO_FEC_PHY_RST, "fec-phy-reset"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret); + return; + } + gpio_direction_output(LOCO_FEC_PHY_RST, 0); + msleep(1); + gpio_set_value(LOCO_FEC_PHY_RST, 1); +} + +static struct fec_platform_data mx53_loco_fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static const struct imxi2c_platform_data mx53_loco_i2c_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "mma8450", + .addr = 0x1C, + }, +}; + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(LOCO_DISP0_RESET, 0); + msleep(10); + gpio_set_value(LOCO_DISP0_RESET, 1); + msleep(10); +} + +static struct fsl_mxc_lcd_platform_data sii902x_hdmi_data = { + .ipu_id = 0, + .disp_id = 0, + .reset = sii902x_hdmi_reset, +}; + +static void loco_suspend_enter(void) +{ + /* da9053 suspend preparation */ +} + +static void loco_suspend_exit(void) +{ + /*clear the EMPGC0/1 bits */ + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); + /* da9053 resmue resore */ +} + +static struct mxc_pm_platform_data loco_pm_data = { + .suspend_enter = loco_suspend_enter, + .suspend_exit = loco_suspend_exit, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000", + .addr = 0x0a, + }, + { + .type = "sii902x", + .addr = 0x39, + .irq = gpio_to_irq(LOCO_DISP0_DET_INT), + .platform_data = &sii902x_hdmi_data, + }, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct ipuv3_fb_platform_data loco_fb_data[] = { + { /*fb0*/ + .disp_dev = "vga", + .interface_pix_fmt = IPU_PIX_FMT_GBR24, + .mode_str = "VGA-XGA", + .default_bpp = 16, + .int_clk = false, + }, { + .disp_dev = "lcd", + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static struct imx_ipuv3_platform_data ipu_data = { + .rev = 3, +}; + +static struct platform_pwm_backlight_data loco_pwm_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct fsl_mxc_tve_platform_data tve_data = { + .dac_reg = "DA9052_LDO7", +}; + +static struct mxc_dvfs_platform_data loco_dvfs_core_data = { + .reg_id = "cpu_vddgp", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_OFFSET, + .gpc_vcr_offset = MXC_GPC_VCR_OFFSET, + .ccm_cdcr_offset = MXC_CCM_CDCR_OFFSET, + .ccm_cacrr_offset = MXC_CCM_CACRR_OFFSET, + .ccm_cdhipr_offset = MXC_CCM_CDHIPR_OFFSET, + .prediv_mask = 0x1F800, + .prediv_offset = 11, + .prediv_val = 3, + .div3ck_mask = 0xE0000000, + .div3ck_offset = 29, + .div3ck_val = 2, + .emac_val = 0x08, + .upthr_val = 25, + .dnthr_val = 9, + .pncthr_val = 33, + .upcnt_val = 10, + .dncnt_val = 10, + .delay_time = 30, +}; + +static const struct esdhc_platform_data mx53_loco_sd1_data __initconst = { + .cd_gpio = MX53_LOCO_SD1_CD, +}; + +static const struct esdhc_platform_data mx53_loco_sd3_data __initconst = { + .cd_gpio = MX53_LOCO_SD3_CD, + .wp_gpio = MX53_LOCO_SD3_WP, +}; + +static void mx53_loco_usbh1_vbus(bool on) +{ + if (on) + gpio_set_value(LOCO_USBH1_VBUS, 1); + else + gpio_set_value(LOCO_USBH1_VBUS, 0); +} + +static void __init mx53_loco_io_init(void) +{ + int ret; + + arm_plat_base = MX53_IO_ADDRESS(MX53_ARM_BASE_ADDR); + gpc_base = MX53_IO_ADDRESS(MX53_GPC_BASE_ADDR); + ccm_base = MX53_IO_ADDRESS(MX53_CCM_BASE_ADDR); + imx_otg_base = MX53_IO_ADDRESS(MX53_OTG_BASE_ADDR); + + mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads, + ARRAY_SIZE(mx53_loco_pads)); + + /* Sii902x HDMI controller */ + ret = gpio_request(LOCO_DISP0_RESET, "disp0-reset"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_LOCO_DISP0_RESET: %d\n", ret); + return; + } + gpio_direction_output(LOCO_DISP0_RESET, 0); + + ret = gpio_request(LOCO_DISP0_DET_INT, "disp0-detect"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_LOCO_DISP0_DET_INT: %d\n", ret); + return; + } + gpio_direction_input(LOCO_DISP0_DET_INT); + + /* enable disp0 power */ + ret = gpio_request(LOCO_DISP0_PWR, "disp0-power-en"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_LOCO_DISP0_PWR: %d\n", ret); + return; + } + gpio_direction_output(LOCO_DISP0_PWR, 1); + + /* usb host1 vbus */ + ret = gpio_request(LOCO_USBH1_VBUS, "usbh1-vbus"); + if (ret) { + printk(KERN_ERR"failed to get GPIO LOCO_USBH1_VBUS: %d\n", ret); + return; + } + gpio_direction_output(LOCO_USBH1_VBUS, 0); +} + +/* HW Initialization, if return 0, initialization is successful. */ +static int mx53_loco_sata_init(struct device *dev, void __iomem *addr) +{ + u32 tmpdata; + int ret = 0; + struct clk *clk; + + sata_clk = clk_get(dev, "imx_sata_clk"); + if (IS_ERR(sata_clk)) { + dev_err(dev, "no sata clock.\n"); + return PTR_ERR(sata_clk); + } + ret = clk_enable(sata_clk); + if (ret) { + dev_err(dev, "can't enable sata clock.\n"); + goto put_sata_clk; + } + + sata_ref_clk = clk_get(NULL, "usb_phy1_clk"); + if (IS_ERR(sata_ref_clk)) { + dev_err(dev, "no sata ref clock.\n"); + ret = PTR_ERR(sata_ref_clk); + goto release_sata_clk; + } + ret = clk_enable(sata_ref_clk); + if (ret) { + dev_err(dev, "can't enable sata ref clock.\n"); + goto put_sata_ref_clk; + } + + /* Get the AHB clock rate, and configure the TIMER1MS reg later */ + clk = clk_get(NULL, "ahb_clk"); + if (IS_ERR(clk)) { + dev_err(dev, "no ahb clock.\n"); + ret = PTR_ERR(clk); + goto release_sata_ref_clk; + } + tmpdata = clk_get_rate(clk) / 1000; + clk_put(clk); + + ret = sata_init(addr, tmpdata); + if (ret == 0) + return ret; + +release_sata_ref_clk: + clk_disable(sata_ref_clk); +put_sata_ref_clk: + clk_put(sata_ref_clk); +release_sata_clk: + clk_disable(sata_clk); +put_sata_clk: + clk_put(sata_clk); + + return ret; +} + +static void mx53_loco_sata_exit(struct device *dev) +{ + clk_disable(sata_ref_clk); + clk_put(sata_ref_clk); + + clk_disable(sata_clk); + clk_put(sata_clk); +} + +static struct ahci_platform_data mx53_loco_sata_data = { + .init = mx53_loco_sata_init, + .exit = mx53_loco_sata_exit, +}; + +static struct mxc_audio_platform_data loco_audio_data; + +static int loco_sgtl5000_init(void) +{ + struct clk *ssi_ext1; + int rate; + + ssi_ext1 = clk_get(NULL, "ssi_ext1_clk"); + if (IS_ERR(ssi_ext1)) { + return -1; + } + rate = clk_round_rate(ssi_ext1, 24000000); + if (rate < 8000000 || rate > 27000000) { + printk(KERN_ERR "Error: SGTL5000 mclk freq %d out of range!\n", + rate); + clk_put(ssi_ext1); + return -1; + } + + loco_audio_data.sysclk = rate; + clk_set_rate(ssi_ext1, rate); + clk_enable(ssi_ext1); + + return 0; +} + +static struct imx_ssi_platform_data loco_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct mxc_audio_platform_data loco_audio_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, + .init = loco_sgtl5000_init, + .hp_gpio = LOCO_HEADPHONE_DET, + .hp_active_low = 1, +}; + +static struct platform_device loco_audio_device = { + .name = "imx-sgtl5000", +}; + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + +static struct mxc_iim_platform_data iim_data = { + .bank_start = MXC_IIM_MX53_BANK_START_ADDR, + .bank_end = MXC_IIM_MX53_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + +static struct mxc_gpu_platform_data gpu_data __initdata; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 0, + .disp_id = 0, + .ext_ref = 1, + .mode = LDB_SIN0, +}; + +static struct mxc_regulator_platform_data loco_regulator_data = { + .cpu_reg_id = "cpu_vddgp", +}; + +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + struct tag *t; + struct tag *mem_tag = 0; + int total_mem = SZ_1G; + int left_mem = 0; + int gpu_mem = SZ_128M; + int fb_mem = SZ_32M; + char *str; + + for_each_tag(mem_tag, tags) { + if (mem_tag->hdr.tag == ATAG_MEM) { + total_mem = mem_tag->u.mem.size; + left_mem = total_mem - gpu_mem - fb_mem; + break; + } + } + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "mem="); + if (str != NULL) { + str += 4; + left_mem = memparse(str, &str); + if (left_mem == 0 || left_mem > total_mem) + left_mem = total_mem - gpu_mem - fb_mem; + } + + str = t->u.cmdline.cmdline; + str = strstr(str, "gpu_memory="); + if (str != NULL) { + str += 11; + gpu_mem = memparse(str, &str); + } + + break; + } + } + + if (mem_tag) { + fb_mem = total_mem - left_mem - gpu_mem; + if (fb_mem < 0) { + gpu_mem = total_mem - left_mem; + fb_mem = 0; + } + mem_tag->u.mem.size = left_mem; + + /* reserve memory for gpu */ + gpu_data.reserved_mem_base = + mem_tag->u.mem.start + left_mem; + gpu_data.reserved_mem_size = gpu_mem; + + /* reserver memory for fb */ + loco_fb_data[0].res_base[0] = gpu_data.reserved_mem_base + + gpu_data.reserved_mem_size; + loco_fb_data[0].res_size[0] = fb_mem; + } +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = -1, /* No source for 44.1K */ + /* Source from CCM spdif_clk (24M) for 48k and 32k + * It's not accurate: for 48Khz it is actually 46875Hz (2.3% off) + */ + .spdif_clk_48000 = 1, + .spdif_div_44100 = 8, + .spdif_div_48000 = 8, + .spdif_div_32000 = 12, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static void __init mx53_loco_board_init(void) +{ + int i, ret; + iomux_v3_cfg_t mc34708_int = MX53_PAD_CSI0_DAT12__GPIO5_30; + + mx53_loco_io_init(); + gp_reg_id = loco_regulator_data.cpu_reg_id; + lp_reg_id = loco_regulator_data.vcc_reg_id; + + imx53_add_imx_uart(0, NULL); + mx53_loco_fec_reset(); + imx53_add_fec(&mx53_loco_fec_data); + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mxc_register_device(&mxc_pm_device, &loco_pm_data); + + imx53_add_ipuv3(0, &ipu_data); + + for (i = 0; i < ARRAY_SIZE(loco_fb_data); i++) + imx53_add_ipuv3fb(i, &loco_fb_data[i]); + + imx53_add_vpu(); + imx53_add_lcdif(&lcdif_data); + imx53_add_ldb(&ldb_data); + imx53_add_tve(&tve_data); + imx53_add_v4l2_output(0); + + imx53_add_mxc_pwm(1); + imx53_add_mxc_pwm_backlight(0, &loco_pwm_backlight_data); + + imx53_add_imx2_wdt(0, NULL); + imx53_add_srtc(); + imx53_add_imx_i2c(0, &mx53_loco_i2c_data); + imx53_add_imx_i2c(1, &mx53_loco_i2c_data); + if (board_is_mx53_loco_mc34708()) { + if (board_is_rev(IMX_BOARD_REV_2)) {/*Board RevA*/ + mc34708_int = MX53_PAD_CSI0_DAT12__GPIO5_30; + mx53_loco_mc34708_irq = MX53_LOCO_MC34708_IRQ_REVA; + } else if (board_is_rev(IMX_BOARD_REV_4)) {/*Board RevB*/ + mc34708_int = MX53_PAD_CSI0_DAT5__GPIO5_23; + mx53_loco_mc34708_irq = MX53_LOCO_MC34708_IRQ_REVB; + } + mxc_iomux_v3_setup_pad(mc34708_int); + ret = gpio_request(mx53_loco_mc34708_irq, "mc34708-int"); + if (ret) { + printk(KERN_ERR"request mc34708-int error!!\n"); + return; + } else { + gpio_direction_input(mx53_loco_mc34708_irq); + mx53_loco_init_mc34708(mx53_loco_mc34708_irq); + } + + } else { + mx53_loco_init_da9052(); + } + i2c_register_board_info(0, mxc_i2c0_board_info, + ARRAY_SIZE(mxc_i2c0_board_info)); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + + imx53_add_sdhci_esdhc_imx(0, &mx53_loco_sd1_data); + imx53_add_sdhci_esdhc_imx(2, &mx53_loco_sd3_data); + imx53_add_ahci(0, &mx53_loco_sata_data); + mxc_register_device(&imx_ahci_device_hwmon, NULL); + imx53_add_iim(&iim_data); + + /* USB */ + mx5_usb_dr_init(); + mx5_set_host1_vbus_func(mx53_loco_usbh1_vbus); + mx5_usbh1_init(); + + mxc_register_device(&loco_audio_device, &loco_audio_data); + imx53_add_imx_ssi(1, &loco_ssi_pdata); + + imx53_add_spdif(&mxc_spdif_data); + imx53_add_spdif_dai(); + imx53_add_spdif_audio_device(); + + /*GPU*/ + if (mx53_revision() >= IMX_CHIP_REVISION_2_0) + gpu_data.z160_revision = 1; + else + gpu_data.z160_revision = 0; + imx53_add_mxc_gpu(&gpu_data); + imx_add_gpio_keys(&loco_button_data); + + /* this call required to release SCC RAM partition held by ROM + * during boot, even if SCC2 driver is not part of the image + */ + imx53_add_mxc_scc2(); + imx53_add_dvfs_core(&loco_dvfs_core_data); + imx53_add_busfreq(); + mx5_cpu_regulator_init(); +} + +static void __init mx53_loco_timer_init(void) +{ + mx53_clocks_init(32768, 24000000, 0, 0); +} + +static struct sys_timer mx53_loco_timer = { + .init = mx53_loco_timer_init, +}; + +MACHINE_START(MX53_LOCO, "Freescale MX53 LOCO Board") + .fixup = fixup_mxc_board, + .map_io = mx53_map_io, + .init_early = imx53_init_early, + .init_irq = mx53_init_irq, + .timer = &mx53_loco_timer, + .init_machine = mx53_loco_board_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/board-mx53_smd.c b/arch/arm/mach-mx5/board-mx53_smd.c new file mode 100755 index 00000000..50fec073 --- /dev/null +++ b/arch/arm/mach-mx5/board-mx53_smd.c @@ -0,0 +1,855 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/fec.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/i2c/mpr.h> +#include <linux/fsl_devices.h> +#include <linux/ahci_platform.h> +#include <linux/regulator/consumer.h> + +#include <linux/pwm_backlight.h> +#include <linux/mxcfb.h> +#include <linux/ipu.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/ipu-v3.h> +#include <mach/imx-uart.h> +#include <mach/iomux-mx53.h> +#include <mach/ahci_sata.h> +#include <mach/imx_rfkill.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "crm_regs.h" +#include "devices-imx53.h" +#include "devices.h" +#include "usb.h" + + +#define SMD_FEC_PHY_RST IMX_GPIO_NR(7, 6) +#define MX53_SMD_SD1_CD IMX_GPIO_NR(3, 13) +#define MX53_SMD_SD1_WP IMX_GPIO_NR(4, 11) +#define MX53_SMD_HDMI_RESET_B IMX_GPIO_NR(5, 0) +#define MX53_SMD_MODEM_RESET_B IMX_GPIO_NR(5, 2) +#define MX53_SMD_KEY_INT IMX_GPIO_NR(5, 4) +#define MX53_SMD_HDMI_INT IMX_GPIO_NR(6, 12) +#define MX53_SMD_CAP_TCH_INT1 IMX_GPIO_NR(3, 20) +#define MX53_SMD_SATA_PWR_EN IMX_GPIO_NR(3, 3) +#define MX53_SMD_OTG_VBUS IMX_GPIO_NR(7, 8) +#define MX53_SMD_NONKEY IMX_GPIO_NR(1, 8) +#define MX53_SMD_UI1 IMX_GPIO_NR(2, 14) +#define MX53_SMD_UI2 IMX_GPIO_NR(2, 15) +#define MX53_SMD_HEADPHONE_DEC IMX_GPIO_NR(2, 5) +#define MX53_SMD_OSC_CKIH1_EN IMX_GPIO_NR(6, 11) +#define MX53_SMD_DCDC1V8_EN IMX_GPIO_NR(3, 1) +#define MX53_SMD_DCDC5V_BB_EN IMX_GPIO_NR(4, 14) +#define MX53_SMD_ALS_INT IMX_GPIO_NR(3, 22) +#define MX53_SMD_BT_RESET IMX_GPIO_NR(3, 28) +#define MX53_SMD_CSI0_RST IMX_GPIO_NR(6, 9) +#define MX53_SMD_CSI0_PWN IMX_GPIO_NR(6, 10) +#define MX53_SMD_ECSPI1_CS0 IMX_GPIO_NR(2, 30) +#define MX53_SMD_ECSPI1_CS1 IMX_GPIO_NR(3, 19) + +static struct clk *sata_clk, *sata_ref_clk; + +extern char *lp_reg_id; +extern char *gp_reg_id; +extern void mx5_cpu_regulator_init(void); +extern int mx53_smd_init_da9052(void); +extern void mx5_cpu_regulator_init(void); + +static iomux_v3_cfg_t mx53_smd_pads[] = { + MX53_PAD_CSI0_DAT10__UART1_TXD_MUX, + MX53_PAD_CSI0_DAT11__UART1_RXD_MUX, + + MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX, + MX53_PAD_PATA_DMARQ__UART2_TXD_MUX, + + MX53_PAD_PATA_CS_0__UART3_TXD_MUX, + MX53_PAD_PATA_CS_1__UART3_RXD_MUX, + MX53_PAD_PATA_DA_1__UART3_CTS, + MX53_PAD_PATA_DA_2__UART3_RTS, + /* I2C1 */ + MX53_PAD_CSI0_DAT8__I2C1_SDA, + MX53_PAD_CSI0_DAT9__I2C1_SCL, + /* I2C2 */ + MX53_PAD_KEY_COL3__I2C2_SCL, + MX53_PAD_KEY_ROW3__I2C2_SDA, + /* I2C3 */ + MX53_PAD_GPIO_3__I2C3_SCL, + MX53_PAD_GPIO_6__I2C3_SDA, + + /* CSPI1 */ + MX53_PAD_EIM_EB2__ECSPI1_SS0, + MX53_PAD_EIM_D16__ECSPI1_SCLK, + MX53_PAD_EIM_D17__ECSPI1_MISO, + MX53_PAD_EIM_D18__ECSPI1_MOSI, + MX53_PAD_EIM_D19__ECSPI1_SS1, + MX53_PAD_EIM_EB2__GPIO2_30, + MX53_PAD_EIM_D19__GPIO3_19, + + /* SD1 */ + MX53_PAD_SD1_CMD__ESDHC1_CMD, + MX53_PAD_SD1_CLK__ESDHC1_CLK, + MX53_PAD_SD1_DATA0__ESDHC1_DAT0, + MX53_PAD_SD1_DATA1__ESDHC1_DAT1, + MX53_PAD_SD1_DATA2__ESDHC1_DAT2, + MX53_PAD_SD1_DATA3__ESDHC1_DAT3, + /* SD1_CD */ + MX53_PAD_EIM_DA13__GPIO3_13, + /* SD1_WP */ + MX53_PAD_KEY_ROW2__GPIO4_11, + + /* SD2 */ + MX53_PAD_SD2_CMD__ESDHC2_CMD, + MX53_PAD_SD2_CLK__ESDHC2_CLK, + MX53_PAD_SD2_DATA0__ESDHC2_DAT0, + MX53_PAD_SD2_DATA1__ESDHC2_DAT1, + MX53_PAD_SD2_DATA2__ESDHC2_DAT2, + MX53_PAD_SD2_DATA3__ESDHC2_DAT3, + + /* SD3 */ + MX53_PAD_PATA_DATA8__ESDHC3_DAT0, + MX53_PAD_PATA_DATA9__ESDHC3_DAT1, + MX53_PAD_PATA_DATA10__ESDHC3_DAT2, + MX53_PAD_PATA_DATA11__ESDHC3_DAT3, + MX53_PAD_PATA_DATA0__ESDHC3_DAT4, + MX53_PAD_PATA_DATA1__ESDHC3_DAT5, + MX53_PAD_PATA_DATA2__ESDHC3_DAT6, + MX53_PAD_PATA_DATA3__ESDHC3_DAT7, + MX53_PAD_PATA_IORDY__ESDHC3_CLK, + MX53_PAD_PATA_RESET_B__ESDHC3_CMD, + + /* SATA_PWR_EN */ + MX53_PAD_EIM_DA3__GPIO3_3, + + /* USB_OTG_OC */ + MX53_PAD_EIM_DA12__GPIO3_12, + /* USB_HUB_RESET_B */ + MX53_PAD_EIM_DA14__GPIO3_14, + /* USB_OTG_PWR_EN */ + MX53_PAD_PATA_DA_2__GPIO7_8, + + /* OSC_CKIH1_EN, for audio codec clk */ + MX53_PAD_NANDF_CS0__GPIO6_11, + + /* AUDMUX3 */ + MX53_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC, + MX53_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD, + MX53_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS, + MX53_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD, + + /* AUDMUX5 */ + MX53_PAD_KEY_COL0__AUDMUX_AUD5_TXC, + MX53_PAD_KEY_ROW0__AUDMUX_AUD5_TXD, + MX53_PAD_KEY_COL1__AUDMUX_AUD5_TXFS, + MX53_PAD_KEY_ROW1__AUDMUX_AUD5_RXD, + + /* AUD_AMP_STBY_B */ + MX53_PAD_EIM_DA2__GPIO3_2, + + /* DCDC1V8_EN */ + MX53_PAD_EIM_DA1__GPIO3_1, + /* DCDC5V_BB_EN */ + MX53_PAD_KEY_COL4__GPIO4_14, + /*SSI_EXT1_CLK*/ + MX53_PAD_GPIO_0__CCM_SSI_EXT1_CLK, + /* PWM */ + MX53_PAD_GPIO_1__PWM2_PWMO, + /* CSI0 */ + MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12, + MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13, + MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14, + MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15, + MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16, + MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17, + MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18, + MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19, + MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC, + MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC, + MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK, + /* DISPLAY */ + MX53_PAD_DI0_DISP_CLK__IPU_DI0_DISP_CLK, + MX53_PAD_DI0_PIN15__IPU_DI0_PIN15, + MX53_PAD_DI0_PIN2__IPU_DI0_PIN2, + MX53_PAD_DI0_PIN3__IPU_DI0_PIN3, + MX53_PAD_DISP0_DAT0__IPU_DISP0_DAT_0, + MX53_PAD_DISP0_DAT1__IPU_DISP0_DAT_1, + MX53_PAD_DISP0_DAT2__IPU_DISP0_DAT_2, + MX53_PAD_DISP0_DAT3__IPU_DISP0_DAT_3, + MX53_PAD_DISP0_DAT4__IPU_DISP0_DAT_4, + MX53_PAD_DISP0_DAT5__IPU_DISP0_DAT_5, + MX53_PAD_DISP0_DAT6__IPU_DISP0_DAT_6, + MX53_PAD_DISP0_DAT7__IPU_DISP0_DAT_7, + MX53_PAD_DISP0_DAT8__IPU_DISP0_DAT_8, + MX53_PAD_DISP0_DAT9__IPU_DISP0_DAT_9, + MX53_PAD_DISP0_DAT10__IPU_DISP0_DAT_10, + MX53_PAD_DISP0_DAT11__IPU_DISP0_DAT_11, + MX53_PAD_DISP0_DAT12__IPU_DISP0_DAT_12, + MX53_PAD_DISP0_DAT13__IPU_DISP0_DAT_13, + MX53_PAD_DISP0_DAT14__IPU_DISP0_DAT_14, + MX53_PAD_DISP0_DAT15__IPU_DISP0_DAT_15, + MX53_PAD_DISP0_DAT16__IPU_DISP0_DAT_16, + MX53_PAD_DISP0_DAT17__IPU_DISP0_DAT_17, + MX53_PAD_DISP0_DAT18__IPU_DISP0_DAT_18, + MX53_PAD_DISP0_DAT19__IPU_DISP0_DAT_19, + MX53_PAD_DISP0_DAT20__IPU_DISP0_DAT_20, + MX53_PAD_DISP0_DAT21__IPU_DISP0_DAT_21, + MX53_PAD_DISP0_DAT22__IPU_DISP0_DAT_22, + MX53_PAD_DISP0_DAT23__IPU_DISP0_DAT_23, + /* LDVS */ + MX53_PAD_LVDS0_TX3_P__LDB_LVDS0_TX3, + MX53_PAD_LVDS0_CLK_P__LDB_LVDS0_CLK, + MX53_PAD_LVDS0_TX2_P__LDB_LVDS0_TX2, + MX53_PAD_LVDS0_TX1_P__LDB_LVDS0_TX1, + MX53_PAD_LVDS0_TX0_P__LDB_LVDS0_TX0, + MX53_PAD_LVDS1_TX3_P__LDB_LVDS1_TX3, + MX53_PAD_LVDS1_TX2_P__LDB_LVDS1_TX2, + MX53_PAD_LVDS1_CLK_P__LDB_LVDS1_CLK, + MX53_PAD_LVDS1_TX1_P__LDB_LVDS1_TX1, + MX53_PAD_LVDS1_TX0_P__LDB_LVDS1_TX0, + + MX53_PAD_GPIO_17__SPDIF_OUT1, +}; + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ +} + +static struct gpio_keys_button smd_buttons[] = { + GPIO_BUTTON(MX53_SMD_NONKEY, KEY_POWER, 1, "power", 0), + GPIO_BUTTON(MX53_SMD_UI1, KEY_VOLUMEUP, 1, "volume-up", 0), + GPIO_BUTTON(MX53_SMD_UI2, KEY_VOLUMEDOWN, 1, "volume-down", 0), +}; + +static struct gpio_keys_platform_data smd_button_data = { + .buttons = smd_buttons, + .nbuttons = ARRAY_SIZE(smd_buttons), +}; + +static struct platform_device smd_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &smd_button_data, + } +}; + +static void __init smd_add_device_buttons(void) +{ + platform_device_register(&smd_button_device); +} +#else +static void __init smd_add_device_buttons(void) {} +#endif + +static const struct imxuart_platform_data mx53_smd_uart_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static inline void mx53_smd_init_uart(void) +{ + imx53_add_imx_uart(0, NULL); + imx53_add_imx_uart(1, NULL); + imx53_add_imx_uart(2, &mx53_smd_uart_data); +} + +static inline void mx53_smd_fec_reset(void) +{ + int ret; + + /* reset FEC PHY */ + ret = gpio_request(SMD_FEC_PHY_RST, "fec-phy-reset"); + if (ret) { + printk(KERN_ERR"failed to get GPIO_FEC_PHY_RESET: %d\n", ret); + return; + } + gpio_direction_output(SMD_FEC_PHY_RST, 0); + msleep(1); + gpio_set_value(SMD_FEC_PHY_RST, 1); +} + +static struct fec_platform_data mx53_smd_fec_data = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static const struct imxi2c_platform_data mx53_smd_i2c_data __initconst = { + .bitrate = 100000, +}; + +static void smd_suspend_enter(void) +{ + /* da9053 suspend preparation */ +} + +static void smd_suspend_exit(void) +{ + /*clear the EMPGC0/1 bits */ + __raw_writel(0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(0, MXC_SRPG_EMPGC1_SRPGCR); + /* da9053 resmue resore */ +} + +static struct mxc_pm_platform_data smd_pm_data = { + .suspend_enter = smd_suspend_enter, + .suspend_exit = smd_suspend_exit, +}; + + +static const struct esdhc_platform_data mx53_smd_sd1_data __initconst = { + .cd_gpio = MX53_SMD_SD1_CD, + .wp_gpio = MX53_SMD_SD1_WP, +}; + +static const struct esdhc_platform_data mx53_smd_sd2_data __initconst = { + .always_present = 1, +}; + +static const struct esdhc_platform_data mx53_smd_sd3_data __initconst = { + .always_present = 1, +}; + +static struct fsl_mxc_camera_platform_data camera_data = { + .analog_regulator = "DA9052_LDO7", + .core_regulator = "DA9052_LDO9", + .mclk = 24000000, + .csi = 0, +}; + +static struct fsl_mxc_lightsensor_platform_data ls_data = { + .rext = 700, /* calibration: 499K->700K */ +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + .type = "mma8451", + .addr = 0x1C, + }, + { + .type = "ov3640", + .addr = 0x3C, + .platform_data = (void *)&camera_data, + }, + +}; + +static u16 smd_touchkey_martix[4] = { + KEY_BACK, KEY_HOME, KEY_MENU, KEY_SEARCH, +}; + +static struct mpr121_platform_data mpr121_keyboard_platdata = { + .keycount = ARRAY_SIZE(smd_touchkey_martix), + .vdd_uv = 3300000, + .matrix = smd_touchkey_martix, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + .type = "sgtl5000", + .addr = 0x0a, + }, + { + .type = "mpr121_touchkey", + .addr = 0x5a, + .irq = gpio_to_irq(MX53_SMD_KEY_INT), + .platform_data = &mpr121_keyboard_platdata, + }, +}; + +static int mx53_smd_spi_cs[] = { + MX53_SMD_ECSPI1_CS0, + MX53_SMD_ECSPI1_CS1, +}; + +static struct spi_imx_master mx53_smd_spi_data = { + .chipselect = mx53_smd_spi_cs, + .num_chipselect = ARRAY_SIZE(mx53_smd_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition m25p32_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00040000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data m25p32_spi_flash_data = { + .name = "m25p32", + .parts = m25p32_partitions, + .nr_parts = ARRAY_SIZE(m25p32_partitions), + .type = "m25p32", +}; +#endif + +static struct spi_board_info m25p32_spi0_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + { + /* The modalias must be the same as spi device driver name */ + .modalias = "m25p80", + .max_speed_hz = 20000000, + .bus_num = 0, + .chip_select = 1, + .platform_data = &m25p32_spi_flash_data, + } +#endif +}; + +static void spi_device_init(void) +{ + spi_register_board_info(m25p32_spi0_board_info, + ARRAY_SIZE(m25p32_spi0_board_info)); +} + +static void mxc_iim_enable_fuse(void) +{ + u32 reg; + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg |= 0x10; + writel(reg, ccm_base + 0x64); +} + +static void mxc_iim_disable_fuse(void) +{ + u32 reg; + if (!ccm_base) + return; + /* enable fuse blown */ + reg = readl(ccm_base + 0x64); + reg &= ~0x10; + writel(reg, ccm_base + 0x64); +} + + +static struct mxc_iim_platform_data iim_data = { + .bank_start = MXC_IIM_MX53_BANK_START_ADDR, + .bank_end = MXC_IIM_MX53_BANK_END_ADDR, + .enable_fuse = mxc_iim_enable_fuse, + .disable_fuse = mxc_iim_disable_fuse, +}; + + +static void sii9022_hdmi_reset(void) +{ + gpio_set_value(MX53_SMD_HDMI_RESET_B, 0); + msleep(10); + gpio_set_value(MX53_SMD_HDMI_RESET_B, 1); + msleep(10); +} + +static struct fsl_mxc_lcd_platform_data sii902x_hdmi_data = { + .reset = sii9022_hdmi_reset, + .analog_reg = "DA9052_LDO2", +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + .type = "sii902x", + .addr = 0x39, + .irq = gpio_to_irq(MX53_SMD_HDMI_INT), + .platform_data = &sii902x_hdmi_data, + }, + { + I2C_BOARD_INFO("p1003_ts", 0x41), + .irq = gpio_to_irq(MX53_SMD_CAP_TCH_INT1), + }, + { + .type = "isl29023", + .addr = 0x44, + .irq = gpio_to_irq(MX53_SMD_ALS_INT), + .platform_data = &ls_data, + }, + +}; + +/* HW Initialization, if return 0, initialization is successful. */ +static int mx53_smd_sata_init(struct device *dev, void __iomem *addr) +{ + u32 tmpdata; + int ret = 0; + struct clk *clk; + + /* Enable SATA PWR */ + ret = gpio_request(MX53_SMD_SATA_PWR_EN, "ahci-sata-pwr"); + if (ret) { + printk(KERN_ERR "failed to get SATA_PWR_EN: %d\n", ret); + return ret; + } + gpio_direction_output(MX53_SMD_SATA_PWR_EN, 1); + + sata_clk = clk_get(dev, "imx_sata_clk"); + if (IS_ERR(sata_clk)) { + dev_err(dev, "no sata clock.\n"); + return PTR_ERR(sata_clk); + } + ret = clk_enable(sata_clk); + if (ret) { + dev_err(dev, "can't enable sata clock.\n"); + goto put_sata_clk; + } + + sata_ref_clk = clk_get(NULL, "usb_phy1_clk"); + if (IS_ERR(sata_ref_clk)) { + dev_err(dev, "no sata ref clock.\n"); + ret = PTR_ERR(sata_ref_clk); + goto release_sata_clk; + } + ret = clk_enable(sata_ref_clk); + if (ret) { + dev_err(dev, "can't enable sata ref clock.\n"); + goto put_sata_ref_clk; + } + + /* Get the AHB clock rate, and configure the TIMER1MS reg later */ + clk = clk_get(NULL, "ahb_clk"); + if (IS_ERR(clk)) { + dev_err(dev, "no ahb clock.\n"); + ret = PTR_ERR(clk); + goto release_sata_ref_clk; + } + tmpdata = clk_get_rate(clk) / 1000; + clk_put(clk); + + ret = sata_init(addr, tmpdata); + if (ret == 0) + return ret; + +release_sata_ref_clk: + clk_disable(sata_ref_clk); +put_sata_ref_clk: + clk_put(sata_ref_clk); +release_sata_clk: + clk_disable(sata_clk); +put_sata_clk: + clk_put(sata_clk); + + return ret; +} + +static void mx53_smd_sata_exit(struct device *dev) +{ + clk_disable(sata_ref_clk); + clk_put(sata_ref_clk); + + clk_disable(sata_clk); + clk_put(sata_clk); +} + +static struct ahci_platform_data mx53_smd_sata_data = { + .init = mx53_smd_sata_init, + .exit = mx53_smd_sata_exit, +}; + +static void mx53_smd_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(MX53_SMD_OTG_VBUS, 1); + else + gpio_set_value(MX53_SMD_OTG_VBUS, 0); +} + +static void __init mx53_smd_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX53_IO_ADDRESS(MX53_OTG_BASE_ADDR); + ret = gpio_request(MX53_SMD_OTG_VBUS, "usb-pwr"); + if (ret) { + printk(KERN_ERR"failed to get GPIO SMD_OTG_VBUS: %d\n", ret); + return; + } + gpio_direction_output(MX53_SMD_OTG_VBUS, 0); + + mx5_set_otghost_vbus_func(mx53_smd_usbotg_vbus); + mx5_usb_dr_init(); + mx5_usbh1_init(); +} + +static void mx53_smd_bt_reset(void) +{ + gpio_request(MX53_SMD_BT_RESET, "bt-reset"); + gpio_direction_output(MX53_SMD_BT_RESET, 0); + /* pull down reset pin at least >5ms */ + mdelay(6); + /* pull up after power supply BT */ + gpio_set_value(MX53_SMD_BT_RESET, 1); + gpio_free(MX53_SMD_BT_RESET); + msleep(100); + /* Bluetooth need some time to reset */ +} + +static int mx53_smd_bt_power_change(int status) +{ + struct regulator *wifi_bt_pwren; + + wifi_bt_pwren = regulator_get(NULL, "wifi_bt"); + if (IS_ERR(wifi_bt_pwren)) { + printk(KERN_ERR "%s: regulator_get error\n", __func__); + return -1; + } + + if (status) { + regulator_enable(wifi_bt_pwren); + mx53_smd_bt_reset(); + } else + regulator_disable(wifi_bt_pwren); + + return 0; +} + +static struct platform_device imx_bt_rfkill = { + .name = "imx_bt_rfkill", +}; + +static struct imx_bt_rfkill_platform_data imx_bt_rfkill_data = { + .power_change = mx53_smd_bt_power_change, +}; + +static struct mxc_audio_platform_data smd_audio_data; + +static int smd_sgtl5000_init(void) +{ + smd_audio_data.sysclk = 22579200; + + /* Enable OSC_CKIH1_EN for audio */ + gpio_request(MX53_SMD_OSC_CKIH1_EN, "osc-en"); + gpio_direction_output(MX53_SMD_OSC_CKIH1_EN, 1); + return 0; +} + +static struct mxc_audio_platform_data smd_audio_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, + .init = smd_sgtl5000_init, + .hp_gpio = MX53_SMD_HEADPHONE_DEC, + .hp_active_low = 1, +}; + +static struct platform_device smd_audio_device = { + .name = "imx-sgtl5000", +}; + +static struct imx_ssi_platform_data smd_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct ipuv3_fb_platform_data smd_fb_data[] = { + { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 16, + .int_clk = false, + }, { + .disp_dev = "hdmi", + .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .mode_str = "1024x768M-16@60", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static struct imx_ipuv3_platform_data ipu_data = { + .rev = 3, + .csi_clk[0] = "ssi_ext1_clk", +}; + +static struct platform_pwm_backlight_data mxc_pwm_backlight_data = { + .pwm_id = 1, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 0, + .disp_id = 1, + .ext_ref = 1, + .mode = LDB_SIN1, +}; + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 0, /* Souce from CKIH1 for 44.1K */ + /* Source from CCM spdif_clk (24M) for 48k and 32k + * It's not accurate + */ + .spdif_clk_48000 = 1, + .spdif_div_44100 = 8, + .spdif_div_48000 = 8, + .spdif_div_32000 = 12, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct mxc_regulator_platform_data smd_regulator_data = { + .cpu_reg_id = "DA9052_BUCK_CORE", +}; + +static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static void __init mx53_smd_board_init(void) +{ + int i; + + mxc_iomux_v3_setup_multiple_pads(mx53_smd_pads, + ARRAY_SIZE(mx53_smd_pads)); + + gp_reg_id = smd_regulator_data.cpu_reg_id; + lp_reg_id = smd_regulator_data.vcc_reg_id; + + mxc_spdif_data.spdif_core_clk = clk_get(NULL, "spdif_xtal_clk"); + clk_put(mxc_spdif_data.spdif_core_clk); + + mx53_smd_init_uart(); + mx53_smd_fec_reset(); + mxc_register_device(&mxc_pm_device, &smd_pm_data); + imx53_add_fec(&mx53_smd_fec_data); + imx53_add_imx2_wdt(0, NULL); + imx53_add_srtc(); + imx53_add_imx_i2c(0, &mx53_smd_i2c_data); + imx53_add_imx_i2c(1, &mx53_smd_i2c_data); + imx53_add_imx_i2c(2, &mx53_smd_i2c_data); + imx53_add_ecspi(0, &mx53_smd_spi_data); + + imx53_add_ipuv3(0, &ipu_data); + for (i = 0; i < ARRAY_SIZE(smd_fb_data); i++) + imx53_add_ipuv3fb(i, &smd_fb_data[i]); + imx53_add_lcdif(&lcdif_data); + imx53_add_vpu(); + imx53_add_ldb(&ldb_data); + imx53_add_v4l2_output(0); + imx53_add_v4l2_capture(0); + imx53_add_mxc_pwm(1); + imx53_add_mxc_pwm_backlight(0, &mxc_pwm_backlight_data); + imx53_add_sdhci_esdhc_imx(0, &mx53_smd_sd1_data); + imx53_add_sdhci_esdhc_imx(1, &mx53_smd_sd2_data); + imx53_add_sdhci_esdhc_imx(2, &mx53_smd_sd3_data); + imx53_add_ahci(0, &mx53_smd_sata_data); + mxc_register_device(&imx_ahci_device_hwmon, NULL); + + mx53_smd_init_usb(); + imx53_add_iim(&iim_data); + smd_add_device_buttons(); + + mx53_smd_init_da9052(); + + /* Camera reset */ + gpio_request(MX53_SMD_CSI0_RST, "cam-reset"); + gpio_set_value(MX53_SMD_CSI0_RST, 1); + + /* Camera power down */ + gpio_request(MX53_SMD_CSI0_PWN, "cam-pwdn"); + gpio_direction_output(MX53_SMD_CSI0_PWN, 1); + msleep(1); + gpio_set_value(MX53_SMD_CSI0_PWN, 0); + + spi_device_init(); + + i2c_register_board_info(0, mxc_i2c0_board_info, + ARRAY_SIZE(mxc_i2c0_board_info)); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + + gpio_request(MX53_SMD_DCDC1V8_EN, "dcdc1v8-en"); + gpio_direction_output(MX53_SMD_DCDC1V8_EN, 1); + + /* ambient light sensor */ + gpio_request(MX53_SMD_ALS_INT, "als int"); + gpio_direction_input(MX53_SMD_ALS_INT); + + mxc_register_device(&smd_audio_device, &smd_audio_data); + mxc_register_device(&imx_bt_rfkill, &imx_bt_rfkill_data); + imx53_add_imx_ssi(1, &smd_ssi_pdata); + + imx53_add_spdif(&mxc_spdif_data); + imx53_add_spdif_dai(); + imx53_add_spdif_audio_device(); + + /* this call required to release SCC RAM partition held by ROM + * during boot, even if SCC2 driver is not part of the image + */ + imx53_add_mxc_scc2(); + + mx5_cpu_regulator_init(); +} + +static void __init mx53_smd_timer_init(void) +{ + mx53_clocks_init(32768, 24000000, 22579200, 0); +} + +static struct sys_timer mx53_smd_timer = { + .init = mx53_smd_timer_init, +}; + +MACHINE_START(MX53_SMD, "Freescale MX53 SMD Board") + .fixup = fixup_mxc_board, + .map_io = mx53_map_io, + .init_early = imx53_init_early, + .init_irq = mx53_init_irq, + .timer = &mx53_smd_timer, + .init_machine = mx53_smd_board_init, +MACHINE_END diff --git a/arch/arm/mach-mx5/bus_freq.c b/arch/arm/mach-mx5/bus_freq.c new file mode 100755 index 00000000..8e1ccce8 --- /dev/null +++ b/arch/arm/mach-mx5/bus_freq.c @@ -0,0 +1,1064 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file bus_freq.c + * + * @brief A common API for the Freescale Semiconductor i.MXC CPUfreq module + * and DVFS CORE module. + * + * The APIs are for setting bus frequency to low or high. + * + * @ingroup PM + */ +#include <asm/io.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/mutex.h> +#include <mach/iram.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdram_autogating.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/cacheflush.h> +#include <asm/tlb.h> +#include "crm_regs.h" + +#define LP_LOW_VOLTAGE 1050000 +#define LP_NORMAL_VOLTAGE 1250000 +#define LP_APM_CLK 24000000 +#define NAND_LP_APM_CLK 12000000 +#define AXI_A_NORMAL_CLK 166250000 +#define AXI_A_CLK_NORMAL_DIV 4 +#define AXI_B_CLK_NORMAL_DIV 5 +#define AHB_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV +#define EMI_SLOW_CLK_NORMAL_DIV AXI_B_CLK_NORMAL_DIV +#define NFC_CLK_NORMAL_DIV 4 +#define SPIN_DELAY 1000000 /* in nanoseconds */ +#define DDR_TYPE_DDR3 0x0 +#define DDR_TYPE_DDR2 0x1 + +static DEFINE_SPINLOCK(ddr_freq_lock); +static DEFINE_SPINLOCK(freq_lock); + +unsigned long lp_normal_rate; +unsigned long lp_med_rate; +unsigned long ddr_normal_rate; +unsigned long ddr_med_rate; +unsigned long ddr_low_rate; +static int cur_ddr_rate; +static unsigned char mx53_ddr_type; + +static struct clk *ddr_clk; +static struct clk *pll1_sw_clk; +static struct clk *pll1; +static struct clk *pll2; +static struct clk *pll3; +static struct clk *pll4; +static struct clk *main_bus_clk; +static struct clk *axi_a_clk; +static struct clk *axi_b_clk; +static struct clk *cpu_clk; +static struct clk *ddr_hf_clk; +static struct clk *ahb_clk; +static struct clk *ddr_clk; +static struct clk *periph_apm_clk; +static struct clk *lp_apm; +static struct clk *gpc_dvfs_clk; +static struct clk *emi_garb_clk; +static void __iomem *pll1_base; +static void __iomem *pll4_base; + +struct regulator *pll_regulator; + +struct regulator *lp_regulator; +int low_bus_freq_mode; +int high_bus_freq_mode; +int med_bus_freq_mode; + +int bus_freq_scaling_initialized; + +static struct cpu_op *cpu_op_tbl; +static struct device *busfreq_dev; +static int busfreq_suspended; +static int cpu_podf; +/* True if bus_frequency is scaled not using DVFS-PER */ +int bus_freq_scaling_is_active; + +static int cpu_op_nr; +int lp_high_freq; +int lp_med_freq; +char *lp_reg_id; + +static int lp_voltage; +struct workqueue_struct *voltage_wq; +static struct work_struct voltage_change_handler; +struct completion voltage_change_cmpl; + +void enter_lpapm_mode_mx50(void); +void enter_lpapm_mode_mx51(void); +void enter_lpapm_mode_mx53(void); +void exit_lpapm_mode_mx50(int high_bus_freq); +void exit_lpapm_mode_mx51(void); +void exit_lpapm_mode_mx53(void); +int low_freq_bus_used(void); +void set_ddr_freq(int ddr_freq); + +extern struct cpu_op *(*get_cpu_op)(int *op); +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; +extern int update_ddr_freq(int ddr_rate); +extern unsigned int mx50_ddr_type; + +static DEFINE_SPINLOCK(voltage_lock); +struct mutex bus_freq_mutex; + +struct timeval start_time; +struct timeval end_time; + +static void voltage_work_handler(struct work_struct *work) +{ + if (lp_regulator != NULL) { + u32 ret = 0; + ret = regulator_set_voltage(lp_regulator, + lp_voltage, lp_voltage); + udelay(400); + if (ret < 0) { + printk(KERN_ERR "COULD NOT SET LP VOLTAGE!!!!!!\n"); + return; + } + } + complete_all(&voltage_change_cmpl); +} + +int set_low_bus_freq(void) +{ + if (busfreq_suspended) + return 0; + if (bus_freq_scaling_initialized) { + /* can not enter low bus freq, when cpu is in higher freq + * or only have one working point */ + if ((clk_get_rate(cpu_clk) > + cpu_op_tbl[cpu_op_nr - 1].cpu_rate) + || (cpu_op_nr == 1)) { + return 0; + } + + mutex_lock(&bus_freq_mutex); + + stop_dvfs_per(); + + stop_sdram_autogating(); + + if (cpu_is_mx50()) + enter_lpapm_mode_mx50(); + else if (cpu_is_mx51()) + enter_lpapm_mode_mx51(); + else + enter_lpapm_mode_mx53(); + mutex_unlock(&bus_freq_mutex); + } + return 0; +} + +void enter_lpapm_mode_mx50() +{ + u32 reg; + unsigned long flags; + spin_lock_irqsave(&freq_lock, flags); + + set_ddr_freq(LP_APM_CLK); + + /* Set the parent of main_bus_clk to be PLL3 */ + clk_set_parent(main_bus_clk, pll3); + /* Set the AHB dividers to be 2. + * Set the dividers so that clock rates + * are not greater than current clock rate. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F) + udelay(10); + + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + med_bus_freq_mode = 0; + + /* Set the source of main_bus_clk to be lp-apm. */ + clk_set_parent(main_bus_clk, lp_apm); + + /* Set the AHB dividers to be 1. */ + /* Set the dividers to be 1, so the clock rates + * are at 24Mhz + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x0F) + udelay(10); + + spin_unlock_irqrestore(&freq_lock, flags); + + spin_lock_irqsave(&voltage_lock, flags); + lp_voltage = LP_LOW_VOLTAGE; + INIT_COMPLETION(voltage_change_cmpl); + queue_work(voltage_wq, &voltage_change_handler); + spin_unlock_irqrestore(&voltage_lock, flags); + + if (clk_get_usecount(pll1_sw_clk) == 1) { + /* Relock PLL1 to 160MHz. */ + clk_set_parent(pll1_sw_clk, pll2); + /* Set the divider to ARM_PODF to 3. */ + __raw_writel(0x02, MXC_CCM_CACRR); + + clk_set_rate(pll1, cpu_op_tbl[cpu_op_nr - 1].cpu_rate); + clk_set_parent(pll1_sw_clk, pll1); + /* Set the divider to ARM_PODF to 1. */ + __raw_writel(0x0, MXC_CCM_CACRR); + } + + udelay(100); +} + +void enter_lpapm_mode_mx51() +{ + u32 reg; + /* Set PLL3 to 133Mhz if no-one is using it. */ + if (clk_get_usecount(pll3) == 0) { + u32 pll3_rate = clk_get_rate(pll3); + + clk_enable(pll3); + clk_set_rate(pll3, clk_round_rate(pll3, 133000000)); + + /*Change the DDR freq to 133Mhz. */ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_low_rate)); + + /* Set the parent of Periph_apm_clk to be PLL3 */ + clk_set_parent(periph_apm_clk, pll3); + clk_set_parent(main_bus_clk, periph_apm_clk); + + /* Set the dividers to be 1, so the clock rates + * are at 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 0 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + clk_disable(emi_garb_clk); + + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + med_bus_freq_mode = 0; + + /* Set the source of Periph_APM_Clock to be lp-apm. */ + clk_set_parent(periph_apm_clk, lp_apm); + + /* Set PLL3 back to original rate. */ + clk_set_rate(pll3, clk_round_rate(pll3, pll3_rate)); + clk_disable(pll3); + } +} + +void enter_lpapm_mode_mx53() +{ + u32 reg; + struct timespec nstimeofday; + struct timespec curtime; + + /* TBD: Reduce DDR frequency for DDR2 */ + /* if (mx53_ddr_type == DDR_TYPE_DDR2) { + } */ + + /* move cpu clk to pll2, 400 / 1 = 400MHZ for cpu */ + /* Change the source of pll1_sw_clk to be the step_clk */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + + cpu_podf = __raw_readl(MXC_CCM_CACRR); + reg = __raw_readl(MXC_CCM_CDHIPR); + while (1) { + if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0) { + __raw_writel(0x0, MXC_CCM_CACRR); + break; + } else { + reg = __raw_readl(MXC_CCM_CDHIPR); + printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n"); + } + } + clk_set_parent(pll1_sw_clk, pll2); + + /* ahb = pll2/8, axi_b = pll2/8, axi_a = pll2/1*/ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 7 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 7 << MXC_CCM_CBCDR_AHB_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY | + MXC_CCM_CDHIPR_AXI_B_PODF_BUSY | + MXC_CCM_CDHIPR_AHB_PODF_BUSY)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec + > SPIN_DELAY) + panic("low bus freq set rate error\n"); + } + + /* keep this infront of propagating */ + low_bus_freq_mode = 1; + high_bus_freq_mode = 0; + med_bus_freq_mode = 0; + + if (clk_get_usecount(pll1) == 0) { + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + } + if (clk_get_usecount(pll4) == 0) { + reg = __raw_readl(pll4_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll4_base + MXC_PLL_DP_CTL); + } +} + +int set_high_bus_freq(int high_bus_freq) +{ + u32 reg; + if (bus_freq_scaling_initialized) { + mutex_lock(&bus_freq_mutex); + /* + * If the CPU freq is 800MHz, set the bus to the high + * setpoint (133MHz) and DDR to 200MHz. + */ + if ((clk_get_rate(cpu_clk) > + cpu_op_tbl[cpu_op_nr - 1].cpu_rate) + || lp_high_freq) + high_bus_freq = 1; + + stop_sdram_autogating(); + + if (low_bus_freq_mode) { + /* Relock PLL3 to 133MHz */ + if (cpu_is_mx50()) + exit_lpapm_mode_mx50(high_bus_freq); + else if (cpu_is_mx51()) + exit_lpapm_mode_mx51(); + else + exit_lpapm_mode_mx53(); + start_dvfs_per(); + } + if (bus_freq_scaling_is_active) { + if (!high_bus_freq_mode && high_bus_freq) { + if (cpu_is_mx50()) { + if (med_bus_freq_mode) { + /* Increase SYS_CLK */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK; + reg |= 4 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + } + } else { + clk_set_rate(ahb_clk, + clk_round_rate(ahb_clk, + lp_normal_rate)); + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, + ddr_normal_rate)); + } + /* Set to the high setpoint. */ + high_bus_freq_mode = 1; + low_bus_freq_mode = 0; + med_bus_freq_mode = 0; + } else if (!med_bus_freq_mode && !high_bus_freq) { + if (cpu_is_mx50()) { + /* Set the dividers to the medium setpoint dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |3 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |5 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + /* Reduce SYS_CLK */ + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~MXC_CCM_CLK_SYS_DIV_PLL_MASK; + reg |= 8 << MXC_CCM_CLK_SYS_DIV_PLL_OFFSET; + __raw_writel(reg, MXC_CCM_CLK_SYS); + } else { + if (cpu_is_mx51()) + clk_set_rate(ddr_hf_clk, + clk_round_rate( + ddr_hf_clk, + ddr_low_rate)); + clk_set_rate(ahb_clk, + clk_round_rate( + ahb_clk, lp_med_rate)); + } + /* Set to the medium setpoint. */ + high_bus_freq_mode = 0; + low_bus_freq_mode = 0; + med_bus_freq_mode = 1; + } + if (cpu_is_mx50()) { + if (med_bus_freq_mode && + (cur_ddr_rate != ddr_med_rate)) + set_ddr_freq(ddr_med_rate); + if (high_bus_freq_mode && + (cur_ddr_rate != ddr_normal_rate)) + set_ddr_freq(ddr_normal_rate); + } + } + start_sdram_autogating(); + mutex_unlock(&bus_freq_mutex); + } + return 0; +} + +void exit_lpapm_mode_mx50(int high_bus_freq) +{ + u32 reg; + unsigned long flags; + + if (clk_get_usecount(pll1_sw_clk) == 1) { + /* Relock PLL1 to 800MHz. */ + clk_set_parent(pll1_sw_clk, pll2); + /* Set the divider to ARM_PODF to 3, cpu is at 160MHz. */ + __raw_writel(0x02, MXC_CCM_CACRR); + + clk_set_rate(pll1, cpu_op_tbl[0].pll_rate); + + /* Set the divider to ARM_PODF to 5 before + * switching the parent. + */ + __raw_writel(0x4, MXC_CCM_CACRR); + clk_set_parent(pll1_sw_clk, pll1); + } + + if (!completion_done(&voltage_change_cmpl)) + wait_for_completion_interruptible(&voltage_change_cmpl); + spin_lock_irqsave(&voltage_lock, flags); + if (lp_voltage != LP_NORMAL_VOLTAGE) { + INIT_COMPLETION(voltage_change_cmpl); + lp_voltage = LP_NORMAL_VOLTAGE; + if (!queue_work(voltage_wq, &voltage_change_handler)) + printk(KERN_ERR "WORK_NOT_ADDED\n"); + spin_unlock_irqrestore(&voltage_lock, flags); + wait_for_completion_interruptible(&voltage_change_cmpl); + } else { + spin_unlock_irqrestore(&voltage_lock, flags); + if (!completion_done(&voltage_change_cmpl)) + wait_for_completion_interruptible(&voltage_change_cmpl); + } + + spin_lock_irqsave(&freq_lock, flags); + if (!low_bus_freq_mode) { + spin_unlock_irqrestore(&freq_lock, flags); + return; + } + + /* Temporarily set the dividers when the source is PLL3. + * No clock rate is above 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + clk_set_parent(main_bus_clk, pll3); + + if (bus_freq_scaling_is_active && !high_bus_freq) { + /* Set the dividers to the medium setpoint dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |3 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |5 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /* Set to the medium setpoint. */ + high_bus_freq_mode = 0; + low_bus_freq_mode = 0; + med_bus_freq_mode = 1; + set_ddr_freq(ddr_med_rate); + } else { + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MX50_CCM_CBCDR_WEIM_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + |1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + |2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + |0 << MX50_CCM_CBCDR_WEIM_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & 0xF) + udelay(10); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /* Set to the high setpoint. */ + high_bus_freq_mode = 1; + low_bus_freq_mode = 0; + med_bus_freq_mode = 0; + set_ddr_freq(ddr_normal_rate); + } + spin_unlock_irqrestore(&freq_lock, flags); + + udelay(100); +} + +void exit_lpapm_mode_mx51() +{ + u32 reg; + + /* Temporarily Set the dividers is PLL3. + * No clock rate is above 133MHz. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (1 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + clk_disable(emi_garb_clk); + + clk_set_parent(periph_apm_clk, pll3); + + /* Set the dividers to the default dividers */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK + | MXC_CCM_CBCDR_EMI_PODF_MASK + | MXC_CCM_CBCDR_NFC_PODF_OFFSET); + reg |= (3 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_AHB_PODF_OFFSET + | 4 << MXC_CCM_CBCDR_EMI_PODF_OFFSET + | 3 << MXC_CCM_CBCDR_NFC_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + clk_enable(emi_garb_clk); + while (__raw_readl(MXC_CCM_CDHIPR) & 0x1F) + udelay(10); + + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + clk_disable(emi_garb_clk); + + /*Set the main_bus_clk parent to be PLL2. */ + clk_set_parent(main_bus_clk, pll2); + + /*Change the DDR freq to 200MHz*/ + clk_set_rate(ddr_hf_clk, + clk_round_rate(ddr_hf_clk, ddr_normal_rate)); +} + +void exit_lpapm_mode_mx53() +{ + u32 reg; + struct timespec nstimeofday; + struct timespec curtime; + + + /* move cpu clk to pll1 */ + reg = __raw_readl(MXC_CCM_CDHIPR); + while (1) { + if ((reg & MXC_CCM_CDHIPR_ARM_PODF_BUSY) == 0) { + __raw_writel(cpu_podf & 0x7, MXC_CCM_CACRR); + break; + } else { + reg = __raw_readl(MXC_CCM_CDHIPR); + printk(KERN_DEBUG "ARM_PODF still in busy!!!!\n"); + } + } + clk_set_parent(pll1_sw_clk, pll1); + + + /* ahb = 400/3, axi_b = 400/2, axi_a = 400*/ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~(MXC_CCM_CBCDR_AXI_A_PODF_MASK + | MXC_CCM_CBCDR_AXI_B_PODF_MASK + | MXC_CCM_CBCDR_AHB_PODF_MASK); + reg |= (0 << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET + | 1 << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET + | 2 << MXC_CCM_CBCDR_AHB_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + (MXC_CCM_CDHIPR_AXI_A_PODF_BUSY | + MXC_CCM_CDHIPR_AXI_B_PODF_BUSY | + MXC_CCM_CDHIPR_AHB_PODF_BUSY)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec + - nstimeofday.tv_nsec + > SPIN_DELAY) + panic("bus freq error\n"); + } + + /* keep this infront of propagating */ + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + + /* TBD: Restore DDR frequency for DDR2 */ + /* if (mx53_ddr_type == DDR_TYPE_DDR2) { + } */ +} + +void set_ddr_freq(int ddr_rate) +{ + unsigned long flags; + unsigned int ret = 0; + + spin_lock_irqsave(&ddr_freq_lock, flags); + + if (cpu_is_mx50()) + ret = update_ddr_freq(ddr_rate); + + spin_unlock_irqrestore(&ddr_freq_lock, flags); + if (!ret) + cur_ddr_rate = ddr_rate; + udelay(100); +} + +int low_freq_bus_used(void) +{ + if ((lp_high_freq == 0) + && (lp_med_freq == 0)) + return 1; + else + return 0; +} + +void setup_pll(void) +{ +} + +static ssize_t bus_freq_scaling_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (bus_freq_scaling_is_active) + return sprintf(buf, "Bus frequency scaling is enabled\n"); + else + return sprintf(buf, "Bus frequency scaling is disabled\n"); +} + +static ssize_t bus_freq_scaling_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + u32 reg; + + if (strncmp(buf, "1", 1) == 0) { + if (dvfs_per_active()) { + printk(KERN_INFO "bus frequency scaling cannot be\ + enabled when DVFS-PER is active\n"); + return size; + } + if (!cpu_is_mx50()) { + /* Initialize DVFS-PODF to 0. */ + reg = __raw_readl(MXC_CCM_CDCR); + reg &= ~MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK; + __raw_writel(reg, MXC_CCM_CDCR); + clk_set_parent(main_bus_clk, pll2); + } + bus_freq_scaling_is_active = 1; + set_high_bus_freq(0); + } else if (strncmp(buf, "0", 1) == 0) { + if (bus_freq_scaling_is_active) + set_high_bus_freq(1); + bus_freq_scaling_is_active = 0; + } + + return size; +} + +static int busfreq_suspend(struct platform_device *pdev, pm_message_t message) +{ + if (low_bus_freq_mode) + set_high_bus_freq(1); + busfreq_suspended = 1; + return 0; +} + +static int busfreq_resume(struct platform_device *pdev) +{ + busfreq_suspended = 0; + return 0; +} + +static DEVICE_ATTR(enable, 0644, bus_freq_scaling_enable_show, + bus_freq_scaling_enable_store); + +/*! + * This is the probe routine for the bus frequency driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ +static int __devinit busfreq_probe(struct platform_device *pdev) +{ + int err = 0; + unsigned long pll2_rate, pll1_rate; + + if (cpu_is_mx51()) { + pll1_base = MX51_IO_ADDRESS(MX51_PLL1_BASE_ADDR); + } else if (cpu_is_mx53()) { + pll1_base = MX53_IO_ADDRESS(MX53_PLL1_BASE_ADDR); + pll4_base = MX53_IO_ADDRESS(MX53_PLL4_BASE_ADDR); + } else if (cpu_is_mx50()) { + pll1_base = MX50_IO_ADDRESS(MX50_PLL1_BASE_ADDR); + } + + busfreq_dev = &pdev->dev; + + main_bus_clk = clk_get(NULL, "main_bus_clk"); + if (IS_ERR(main_bus_clk)) { + printk(KERN_DEBUG "%s: failed to get main_bus_clk\n", + __func__); + return PTR_ERR(main_bus_clk); + } + + pll1_sw_clk = clk_get(NULL, "pll1_sw_clk"); + if (IS_ERR(pll1_sw_clk)) { + printk(KERN_DEBUG "%s: failed to get pll1_sw_clk\n", __func__); + return PTR_ERR(pll1_sw_clk); + } + + pll1 = clk_get(NULL, "pll1_main_clk"); + if (IS_ERR(pll1)) { + printk(KERN_DEBUG "%s: failed to get pll1\n", __func__); + return PTR_ERR(pll1); + } + + pll2 = clk_get(NULL, "pll2"); + if (IS_ERR(pll2)) { + printk(KERN_DEBUG "%s: failed to get pll2\n", __func__); + return PTR_ERR(pll2); + } + + pll3 = clk_get(NULL, "pll3"); + if (IS_ERR(pll3)) { + printk(KERN_DEBUG "%s: failed to get pll3\n", __func__); + return PTR_ERR(pll3); + } + + if (cpu_is_mx53()) { + pll4 = clk_get(NULL, "pll4"); + if (IS_ERR(pll4)) { + printk(KERN_DEBUG "%s: failed to get pll4\n", __func__); + return PTR_ERR(pll4); + } + } + + axi_a_clk = clk_get(NULL, "axi_a_clk"); + if (IS_ERR(axi_a_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_a_clk\n", + __func__); + return PTR_ERR(axi_a_clk); + } + + axi_b_clk = clk_get(NULL, "axi_b_clk"); + if (IS_ERR(axi_b_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_b_clk\n", + __func__); + return PTR_ERR(axi_b_clk); + } + + ddr_clk = clk_get(NULL, "ddr_clk"); + if (IS_ERR(ddr_clk)) { + printk(KERN_DEBUG "%s: failed to get ddr_clk\n", + __func__); + return PTR_ERR(ddr_clk); + } + + ddr_hf_clk = clk_get_parent(ddr_clk); + + if (IS_ERR(ddr_hf_clk)) { + printk(KERN_DEBUG "%s: failed to get ddr_hf_clk\n", + __func__); + return PTR_ERR(ddr_hf_clk); + } + + ahb_clk = clk_get(NULL, "ahb_clk"); + if (IS_ERR(ahb_clk)) { + printk(KERN_DEBUG "%s: failed to get ahb_clk\n", + __func__); + return PTR_ERR(ahb_clk); + } + + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_DEBUG "%s: failed to get cpu_clk\n", + __func__); + return PTR_ERR(cpu_clk); + } + + if (cpu_is_mx51()) + emi_garb_clk = clk_get(NULL, "emi_intr_clk.1"); + else if (cpu_is_mx53()) + emi_garb_clk = clk_get(NULL, "emi_intr_clk.1"); + else + emi_garb_clk = clk_get(NULL, "ocram_clk"); + if (IS_ERR(emi_garb_clk)) { + printk(KERN_DEBUG "%s: failed to get emi_garb_clk\n", + __func__); + return PTR_ERR(emi_garb_clk); + } + + if (cpu_is_mx51() || cpu_is_mx53()) { + periph_apm_clk = clk_get(NULL, "periph_apm_clk"); + if (IS_ERR(periph_apm_clk)) { + printk(KERN_DEBUG "%s: failed to get periph_apm_clk\n", + __func__); + return PTR_ERR(periph_apm_clk); + } + } + + lp_apm = clk_get(NULL, "lp_apm"); + if (IS_ERR(lp_apm)) { + printk(KERN_DEBUG "%s: failed to get lp_apm\n", + __func__); + return PTR_ERR(lp_apm); + } + + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); + if (IS_ERR(gpc_dvfs_clk)) { + printk(KERN_DEBUG "%s: failed to get gpc_dvfs_clk\n", __func__); + return PTR_ERR(gpc_dvfs_clk); + } + + err = sysfs_create_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + if (err) { + printk(KERN_ERR + "Unable to register sysdev entry for BUSFREQ"); + return err; + } + + pll1_rate = clk_get_rate(pll1_sw_clk); + pll2_rate = clk_get_rate(pll2); + + if (pll2_rate == 665000000) { + /* for mx51 */ + lp_normal_rate = pll2_rate / 5; + lp_med_rate = pll2_rate / 8; + ddr_normal_rate = pll1_rate / 4; /* 200M */ + ddr_low_rate = pll1_rate / 6; /* 133M */ + } else if (pll2_rate == 600000000) { + /* for mx53 evk rev.A */ + lp_normal_rate = pll2_rate / 5; + lp_med_rate = pll2_rate / 8; + ddr_normal_rate = pll2_rate / 2; + ddr_low_rate = pll2_rate / 2; + } else if (pll2_rate == 400000000) { + if (cpu_is_mx50()) { + lp_normal_rate = pll2_rate / 3; + ddr_normal_rate = clk_get_rate(ddr_clk); + lp_med_rate = pll2_rate / 6; + ddr_low_rate = LP_APM_CLK; + if (mx50_ddr_type == MX50_LPDDR2) + ddr_med_rate = pll2_rate / 3; + else + /* mDDR @ 133Mhz currently does not work */ + ddr_med_rate = ddr_normal_rate; + } + } + + /* for mx53 */ + if (cpu_is_mx53()) { + /* set DDR type */ + if (machine_is_mx53_evk() || machine_is_mx53_ard()) + mx53_ddr_type = DDR_TYPE_DDR2; + else + mx53_ddr_type = DDR_TYPE_DDR3; + if (mx53_ddr_type == DDR_TYPE_DDR2) { + /* DDR2 */ + lp_normal_rate = pll2_rate / 3; + lp_med_rate = pll2_rate / 5; + ddr_normal_rate = pll2_rate / 1; + ddr_low_rate = pll2_rate / 3; + } else { + /* DDR3: DDR3 frequency can not be lower than 300MHZ */ + lp_normal_rate = pll2_rate / 3; + lp_med_rate = pll2_rate / 5; + ddr_normal_rate = pll2_rate / 1; + ddr_low_rate = pll2_rate / 1; + } + } + + if (cpu_is_mx50()) { + cur_ddr_rate = ddr_normal_rate; + + if (lp_reg_id != NULL) { + lp_regulator = regulator_get(NULL, lp_reg_id); + if (IS_ERR(lp_regulator)) { + printk(KERN_DEBUG + "%s: failed to get lp regulator\n", __func__); + return PTR_ERR(lp_regulator); + } + + voltage_wq = create_workqueue("voltage_change"); + INIT_WORK(&voltage_change_handler, + voltage_work_handler); + + init_completion(&voltage_change_cmpl); + } + } + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + low_bus_freq_mode = 0; + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + bus_freq_scaling_is_active = 0; + bus_freq_scaling_initialized = 1; + + mutex_init(&bus_freq_mutex); + return 0; +} + +static struct platform_driver busfreq_driver = { + .driver = { + .name = "imx_busfreq", + }, + .probe = busfreq_probe, + .suspend = busfreq_suspend, + .resume = busfreq_resume, +}; + +/*! + * Initialise the busfreq_driver. + * + * @return The function always returns 0. + */ + +static int __init busfreq_init(void) +{ + if (platform_driver_register(&busfreq_driver) != 0) { + printk(KERN_ERR "busfreq_driver register failed\n"); + return -ENODEV; + } + + printk(KERN_INFO "Bus freq driver module loaded\n"); + return 0; +} + +static void __exit busfreq_cleanup(void) +{ + sysfs_remove_file(&busfreq_dev->kobj, &dev_attr_enable.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&busfreq_driver); + bus_freq_scaling_initialized = 0; +} + +module_init(busfreq_init); +module_exit(busfreq_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("BusFreq driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c new file mode 100755 index 00000000..a6a409b7 --- /dev/null +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c @@ -0,0 +1,1588 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009-2010 Amit Kucheria <amit.kucheria@canonical.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/mm.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> + +#include <asm/div64.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> + +#include "crm_regs.h" + +/* External clock values passed-in by the board code */ +static unsigned long external_high_reference, external_low_reference; +static unsigned long oscillator_reference, ckih2_reference; + +static struct clk osc_clk; +static struct clk pll1_main_clk; +static struct clk pll1_sw_clk; +static struct clk pll2_sw_clk; +static struct clk pll3_sw_clk; +static struct clk mx53_pll4_sw_clk; +static struct clk lp_apm_clk; +static struct clk periph_apm_clk; +static struct clk ahb_clk; +static struct clk ipg_clk; +static struct clk usboh3_clk; +static struct clk emi_fast_clk; +static struct clk ipu_clk; +static struct clk mipi_hsc1_clk; +static struct clk esdhc1_clk; +static struct clk esdhc2_clk; +static struct clk esdhc3_mx53_clk; + +#define MAX_DPLL_WAIT_TRIES 1000 /* 1000 * udelay(1) = 1ms */ + +/* calculate best pre and post dividers to get the required divider */ +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post, + u32 max_pre, u32 max_post) +{ + if (div >= max_pre * max_post) { + *pre = max_pre; + *post = max_post; + } else if (div >= max_pre) { + u32 min_pre, temp_pre, old_err, err; + min_pre = DIV_ROUND_UP(div, max_post); + old_err = max_pre; + for (temp_pre = max_pre; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = DIV_ROUND_UP(div, *pre); + } else { + *pre = div; + *post = 1; + } +} + +static void _clk_ccgr_setclk(struct clk *clk, unsigned mode) +{ + u32 reg = __raw_readl(clk->enable_reg); + + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= mode << clk->enable_shift; + + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_ccgr_enable(struct clk *clk) +{ + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_ON); + return 0; +} + +static void _clk_ccgr_disable(struct clk *clk) +{ + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_OFF); +} + +static int _clk_ccgr_enable_inrun(struct clk *clk) +{ + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); + return 0; +} + +static void _clk_ccgr_disable_inwait(struct clk *clk) +{ + _clk_ccgr_setclk(clk, MXC_CCM_CCGRx_MOD_IDLE); +} + +/* + * For the 4-to-1 muxed input clock + */ +static inline u32 _get_mux(struct clk *parent, struct clk *m0, + struct clk *m1, struct clk *m2, struct clk *m3) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else + BUG(); + + return -EINVAL; +} + +static inline void __iomem *_mx51_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) + return MX51_DPLL1_BASE; + else if (pll == &pll2_sw_clk) + return MX51_DPLL2_BASE; + else if (pll == &pll3_sw_clk) + return MX51_DPLL3_BASE; + else + BUG(); + + return NULL; +} + +static inline void __iomem *_mx53_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) + return MX53_DPLL1_BASE; + else if (pll == &pll2_sw_clk) + return MX53_DPLL2_BASE; + else if (pll == &pll3_sw_clk) + return MX53_DPLL3_BASE; + else if (pll == &mx53_pll4_sw_clk) + return MX53_DPLL4_BASE; + else + BUG(); + + return NULL; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (cpu_is_mx51()) + return _mx51_get_pll_base(pll); + else + return _mx53_get_pll_base(pll); +} + +static unsigned long clk_pll_get_rate(struct clk *clk) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; + void __iomem *pllbase; + s64 temp; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + pllbase = _get_pll_base(clk); + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + if (pll_hfsm == 0) { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); + } else { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); + } + pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; + mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; + mfi = (mfi <= 5) ? 5 : mfi; + mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; + mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; + /* Sign extend to 32-bits */ + if (mfn >= 0x04000000) { + mfn |= 0xFC000000; + mfn_abs = -mfn; + } + + ref_clk = 2 * parent_rate; + if (dbl != 0) + ref_clk *= 2; + + ref_clk /= (pdf + 1); + temp = (u64) ref_clk * mfn_abs; + do_div(temp, mfd + 1); + if (mfn < 0) + temp = -temp; + temp = (ref_clk * mfi) + temp; + + return temp; +} + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + void __iomem *pllbase; + + long mfi, pdf, mfn, mfd = 999999; + s64 temp64; + unsigned long quad_parent_rate; + unsigned long pll_hfsm, dp_ctl; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + pllbase = _get_pll_base(clk); + + quad_parent_rate = 4 * parent_rate; + pdf = mfi = -1; + while (++pdf < 16 && mfi < 5) + mfi = rate * (pdf+1) / quad_parent_rate; + if (mfi > 15) + return -EINVAL; + pdf--; + + temp64 = rate * (pdf+1) - quad_parent_rate * mfi; + do_div(temp64, quad_parent_rate/1000000); + mfn = (long)temp64; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + if (pll_hfsm == 0) { + reg = mfi << 4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); + } else { + reg = mfi << 4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); + } + + return 0; +} + +static int _clk_pll_enable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + int i = 0; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) | MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + do { + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_LRF) + break; + + udelay(1); + } while (++i < MAX_DPLL_WAIT_TRIES); + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("MX5: pll locking failed\n"); + return -EINVAL; + } + + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); +} + +static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, step; + + reg = __raw_readl(MXC_CCM_CCSR); + + /* When switching from pll_main_clk to a bypass clock, first select a + * multiplexed clock in 'step_sel', then shift the glitchless mux + * 'pll1_sw_clk_sel'. + * + * When switching back, do it in reverse order + */ + if (parent == &pll1_main_clk) { + /* Switch to pll1_main_clk */ + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + /* step_clk mux switched to lp_apm, to save power. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; + reg |= (MXC_CCM_CCSR_STEP_SEL_LP_APM << + MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + if (parent == &lp_apm_clk) { + step = MXC_CCM_CCSR_STEP_SEL_LP_APM; + } else if (parent == &pll2_sw_clk) { + step = MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED; + } else if (parent == &pll3_sw_clk) { + step = MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED; + } else + return -EINVAL; + + reg &= ~MXC_CCM_CCSR_STEP_SEL_MASK; + reg |= (step << MXC_CCM_CCSR_STEP_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CCSR); + /* Switch to step_clk */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +static unsigned long clk_pll1_sw_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CCSR); + + if (clk->parent == &pll2_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> + MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; + } else if (clk->parent == &pll3_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> + MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; + } else + div = 1; + return parent_rate / div; +} + +static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll2_sw_clk) + reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + else + reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (parent == &osc_clk) + reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; + else + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static unsigned long clk_cpu_get_rate(struct clk *clk) +{ + u32 cacrr, div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + cacrr = __raw_readl(MXC_CCM_CACRR); + div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; + + return parent_rate / div; +} + +static int clk_cpu_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, cpu_podf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + cpu_podf = parent_rate / rate - 1; + /* use post divider to change freq */ + reg = __raw_readl(MXC_CCM_CACRR); + reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; + reg |= cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CACRR); + + return 0; +} + +static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + int i = 0; + + mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); + + reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + /* Wait for lock */ + do { + reg = __raw_readl(MXC_CCM_CDHIPR); + if (!(reg & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY)) + break; + + udelay(1); + } while (++i < MAX_DPLL_WAIT_TRIES); + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("MX5: Set parent for periph_apm clock failed\n"); + return -EINVAL; + } + + return 0; +} + +static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CBCDR); + + if (parent == &pll2_sw_clk) + reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + else if (parent == &periph_apm_clk) + reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; + else + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CBCDR); + + return 0; +} + +static struct clk main_bus_clk = { + .parent = &pll2_sw_clk, + .set_parent = _clk_main_bus_set_parent, +}; + +static unsigned long clk_ahb_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> + MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; + return parent_rate / div; +} + + +static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + unsigned long parent_rate; + int i = 0; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div > 8 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + /* Wait for lock */ + do { + reg = __raw_readl(MXC_CCM_CDHIPR); + if (!(reg & MXC_CCM_CDHIPR_AHB_PODF_BUSY)) + break; + + udelay(1); + } while (++i < MAX_DPLL_WAIT_TRIES); + + if (i == MAX_DPLL_WAIT_TRIES) { + pr_err("MX5: clk_ahb_set_rate failed\n"); + return -EINVAL; + } + + return 0; +} + +static unsigned long _clk_ahb_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; +} + + +static int _clk_max_enable(struct clk *clk) +{ + u32 reg; + + _clk_ccgr_enable(clk); + + /* Handshake with MAX when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg &= ~MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS; + else if (cpu_is_mx53()) + reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_max_disable(struct clk *clk) +{ + u32 reg; + + _clk_ccgr_disable_inwait(clk); + + /* No Handshake with MAX when LPM is entered as its disabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg |= MX51_CCM_CLPCR_BYPASS_MAX_LPM_HS; + else if (cpu_is_mx53()) + reg &= ~MX53_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static unsigned long clk_ipg_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> + MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; + + return parent_rate / div; +} + +static unsigned long clk_ipg_per_get_rate(struct clk *clk) +{ + u32 reg, prediv1, prediv2, podf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { + /* the main_bus_clk is the one before the DVFS engine */ + reg = __raw_readl(MXC_CCM_CBCDR); + prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; + prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; + podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> + MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; + return parent_rate / (prediv1 * prediv2 * podf); + } else if (clk->parent == &ipg_clk) + return parent_rate; + else + BUG(); +} + +static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CBCMR); + + reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + + if (parent == &ipg_clk) + reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + else if (parent == &lp_apm_clk) + reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + else if (parent != &main_bus_clk) + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +#define clk_nfc_set_parent NULL + +static unsigned long clk_nfc_get_rate(struct clk *clk) +{ + unsigned long rate; + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >> + MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1; + rate = clk_get_rate(clk->parent) / div; + WARN_ON(rate == 0); + return rate; +} + +static unsigned long clk_nfc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + unsigned long parent_rate = clk_get_rate(clk->parent); + + if (!rate) + return -EINVAL; + + div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + if (div > 8) + return -EINVAL; + + return parent_rate / div; + +} + +static int clk_nfc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + + div = clk_get_rate(clk->parent) / rate; + if (div == 0) + div++; + if (((clk_get_rate(clk->parent) / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){ + } + + return 0; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) +{ + return ckih2_reference; +} + +static unsigned long clk_emi_slow_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >> + MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_ddr_hf_get_rate(struct clk *clk) +{ + unsigned long rate; + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_DDR_PODF_MASK) >> + MXC_CCM_CBCDR_DDR_PODF_OFFSET) + 1; + rate = clk_get_rate(clk->parent) / div; + + return rate; +} + +/* External high frequency clock */ +static struct clk ckih_clk = { + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk ckih2_clk = { + .get_rate = get_ckih2_reference_clock_rate, +}; + +static struct clk osc_clk = { + .get_rate = get_oscillator_reference_clock_rate, +}; + +/* External low frequency (32kHz) clock */ +static struct clk ckil_clk = { + .get_rate = get_low_reference_clock_rate, +}; + +static struct clk pll1_main_clk = { + .parent = &osc_clk, + .get_rate = clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +/* Clock tree block diagram (WIP): + * CCM: Clock Controller Module + * + * PLL output -> | + * | CCM Switcher -> CCM_CLK_ROOT_GEN -> + * PLL bypass -> | + * + */ + +/* PLL1 SW supplies to ARM core */ +static struct clk pll1_sw_clk = { + .parent = &pll1_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = clk_pll1_sw_get_rate, +}; + +/* PLL2 SW supplies to AXI/AHB/IP buses */ +static struct clk pll2_sw_clk = { + .parent = &osc_clk, + .get_rate = clk_pll_get_rate, + .set_rate = _clk_pll_set_rate, + .set_parent = _clk_pll2_sw_set_parent, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +/* PLL3 SW supplies to serial clocks like USB, SSI, etc. */ +static struct clk pll3_sw_clk = { + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +/* PLL4 SW supplies to LVDS Display Bridge(LDB) */ +static struct clk mx53_pll4_sw_clk = { + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +/* Low-power Audio Playback Mode clock */ +static struct clk lp_apm_clk = { + .parent = &osc_clk, + .set_parent = _clk_lp_apm_set_parent, +}; + +static struct clk periph_apm_clk = { + .parent = &pll1_sw_clk, + .set_parent = _clk_periph_apm_set_parent, +}; + +static struct clk cpu_clk = { + .parent = &pll1_sw_clk, + .get_rate = clk_cpu_get_rate, + .set_rate = clk_cpu_set_rate, +}; + +static struct clk ahb_clk = { + .parent = &main_bus_clk, + .get_rate = clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, +}; + +static struct clk iim_clk = { + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, +}; + +/* Main IP interface clock for access to registers */ +static struct clk ipg_clk = { + .parent = &ahb_clk, + .get_rate = clk_ipg_get_rate, +}; + +static struct clk ipg_perclk = { + .parent = &lp_apm_clk, + .get_rate = clk_ipg_per_get_rate, + .set_parent = _clk_ipg_per_set_parent, +}; + +static struct clk ahb_max_clk = { + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, +}; + +static struct clk aips_tz1_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable_inwait, +}; + +static struct clk aips_tz2_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable_inwait, +}; + +static struct clk gpc_dvfs_clk = { + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable, +}; + +static struct clk gpt_32k_clk = { + .id = 0, + .parent = &ckil_clk, +}; + +static struct clk dummy_clk = { + .id = 0, +}; + +static struct clk emi_slow_clk = { + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable_inwait, + .get_rate = clk_emi_slow_get_rate, +}; + +static int clk_ipu_enable(struct clk *clk) +{ + u32 reg; + + _clk_ccgr_enable(clk); + + /* Enable handshake with IPU when certain clock rates are changed */ + reg = __raw_readl(MXC_CCM_CCDR); + reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + /* Enable handshake with IPU when LPM is entered */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void clk_ipu_disable(struct clk *clk) +{ + u32 reg; + + _clk_ccgr_disable(clk); + + /* Disable handshake with IPU whe dividers are changed */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_IPU_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + /* Disable handshake with IPU when LPM is entered */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static struct clk ahbmux1_clk = { + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable_inwait, +}; + +static struct clk ipu_sec_clk = { + .parent = &emi_fast_clk, + .secondary = &ahbmux1_clk, +}; + +static struct clk ddr_hf_clk = { + .parent = &pll1_sw_clk, + .get_rate = _clk_ddr_hf_get_rate, +}; + +static struct clk ddr_clk = { + .parent = &ddr_hf_clk, +}; + +/* clock definitions for MIPI HSC unit which has been removed + * from documentation, but not from hardware + */ +static int _clk_hsc_enable(struct clk *clk) +{ + u32 reg; + + _clk_ccgr_enable(clk); + /* Handshake with IPU when certain clock rates are changed. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg &= ~MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_hsc_disable(struct clk *clk) +{ + u32 reg; + + _clk_ccgr_disable(clk); + /* No handshake with HSC as its not enabled. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static struct clk mipi_hsp_clk = { + .parent = &ipu_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_hsc_enable, + .disable = _clk_hsc_disable, + .secondary = &mipi_hsc1_clk, +}; + +#define DEFINE_CLOCK_CCGR(name, i, er, es, pfx, p, s) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = pfx##_get_rate, \ + .set_rate = pfx##_set_rate, \ + .round_rate = pfx##_round_rate, \ + .set_parent = pfx##_set_parent, \ + .enable = _clk_ccgr_enable, \ + .disable = _clk_ccgr_disable, \ + .parent = p, \ + .secondary = s, \ + } + +#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = pfx##_get_rate, \ + .set_rate = pfx##_set_rate, \ + .set_parent = pfx##_set_parent, \ + .enable = _clk_max_enable, \ + .disable = _clk_max_disable, \ + .parent = p, \ + .secondary = s, \ + } + +#define CLK_GET_RATE(name, nr, bitsname) \ +static unsigned long clk_##name##_get_rate(struct clk *clk) \ +{ \ + u32 reg, pred, podf; \ + \ + reg = __raw_readl(MXC_CCM_CSCDR##nr); \ + pred = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK) \ + >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ + podf = (reg & MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK) \ + >> MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ + \ + return DIV_ROUND_CLOSEST(clk_get_rate(clk->parent), \ + (pred + 1) * (podf + 1)); \ +} + +#define CLK_SET_PARENT(name, nr, bitsname) \ +static int clk_##name##_set_parent(struct clk *clk, struct clk *parent) \ +{ \ + u32 reg, mux; \ + \ + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, \ + &pll3_sw_clk, &lp_apm_clk); \ + reg = __raw_readl(MXC_CCM_CSCMR##nr) & \ + ~MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_MASK; \ + reg |= mux << MXC_CCM_CSCMR##nr##_##bitsname##_CLK_SEL_OFFSET; \ + __raw_writel(reg, MXC_CCM_CSCMR##nr); \ + \ + return 0; \ +} + +#define CLK_SET_RATE(name, nr, bitsname) \ +static int clk_##name##_set_rate(struct clk *clk, unsigned long rate) \ +{ \ + u32 reg, div, parent_rate; \ + u32 pre = 0, post = 0; \ + \ + parent_rate = clk_get_rate(clk->parent); \ + div = parent_rate / rate; \ + \ + if ((parent_rate / div) != rate) \ + return -EINVAL; \ + \ + __calc_pre_post_dividers(div, &pre, &post, \ + (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK >> \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET) + 1, \ + (MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK >> \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET) + 1);\ + \ + /* Set sdhc1 clock divider */ \ + reg = __raw_readl(MXC_CCM_CSCDR##nr) & \ + ~(MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_MASK \ + | MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_MASK); \ + reg |= (post - 1) << \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PODF_OFFSET; \ + reg |= (pre - 1) << \ + MXC_CCM_CSCDR##nr##_##bitsname##_CLK_PRED_OFFSET; \ + __raw_writel(reg, MXC_CCM_CSCDR##nr); \ + \ + return 0; \ +} + +/* UART */ +CLK_GET_RATE(uart, 1, UART) +CLK_SET_PARENT(uart, 1, UART) + +static struct clk uart_root_clk = { + .parent = &pll2_sw_clk, + .get_rate = clk_uart_get_rate, + .set_parent = clk_uart_set_parent, +}; + +/* USBOH3 */ +CLK_GET_RATE(usboh3, 1, USBOH3) +CLK_SET_PARENT(usboh3, 1, USBOH3) + +static struct clk usboh3_clk = { + .parent = &pll2_sw_clk, + .get_rate = clk_usboh3_get_rate, + .set_parent = clk_usboh3_set_parent, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, +}; + +static struct clk usb_ahb_clk = { + .parent = &ipg_clk, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, +}; + +static int clk_usb_phy1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + + if (parent == &pll3_sw_clk) + reg |= 1 << MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk usb_phy1_clk = { + .parent = &pll3_sw_clk, + .set_parent = clk_usb_phy1_set_parent, + .enable = _clk_ccgr_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_ccgr_disable, +}; + +/* eCSPI */ +CLK_GET_RATE(ecspi, 2, CSPI) +CLK_SET_PARENT(ecspi, 1, CSPI) + +static struct clk ecspi_main_clk = { + .parent = &pll3_sw_clk, + .get_rate = clk_ecspi_get_rate, + .set_parent = clk_ecspi_set_parent, +}; + +/* eSDHC */ +CLK_GET_RATE(esdhc1, 1, ESDHC1_MSHC1) +CLK_SET_PARENT(esdhc1, 1, ESDHC1_MSHC1) +CLK_SET_RATE(esdhc1, 1, ESDHC1_MSHC1) + +/* mx51 specific */ +CLK_GET_RATE(esdhc2, 1, ESDHC2_MSHC2) +CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2) +CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2) + +static int clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk) + reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; + else if (parent == &esdhc2_clk) + reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL; + else + return -EINVAL; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static int clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk) + reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc2_clk) + reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + return -EINVAL; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +/* mx53 specific */ +static int clk_esdhc2_mx53_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk) + reg &= ~MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL; + else if (parent == &esdhc3_mx53_clk) + reg |= MXC_CCM_CSCMR1_ESDHC2_MSHC2_MX53_CLK_SEL; + else + return -EINVAL; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +CLK_GET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) +CLK_SET_PARENT(esdhc3_mx53, 1, ESDHC3_MX53) +CLK_SET_RATE(esdhc3_mx53, 1, ESDHC3_MX53) + +static int clk_esdhc4_mx53_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk) + reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc3_mx53_clk) + reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + return -EINVAL; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = gr, \ + .set_rate = sr, \ + .enable = e, \ + .disable = d, \ + .parent = p, \ + .secondary = s, \ + } + +#define DEFINE_CLOCK(name, i, er, es, gr, sr, p, s) \ + DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, _clk_ccgr_enable, _clk_ccgr_disable, p, s) + +/* Shared peripheral bus arbiter */ +DEFINE_CLOCK(spba_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG0_OFFSET, + NULL, NULL, &ipg_clk, NULL); + +/* UART */ +DEFINE_CLOCK(uart1_ipg_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG3_OFFSET, + NULL, NULL, &ipg_clk, &aips_tz1_clk); +DEFINE_CLOCK(uart2_ipg_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG5_OFFSET, + NULL, NULL, &ipg_clk, &aips_tz1_clk); +DEFINE_CLOCK(uart3_ipg_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG7_OFFSET, + NULL, NULL, &ipg_clk, &spba_clk); +DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG4_OFFSET, + NULL, NULL, &uart_root_clk, &uart1_ipg_clk); +DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG6_OFFSET, + NULL, NULL, &uart_root_clk, &uart2_ipg_clk); +DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG8_OFFSET, + NULL, NULL, &uart_root_clk, &uart3_ipg_clk); + +/* GPT */ +DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET, + NULL, NULL, &ipg_clk, &gpt_ipg_clk); + +DEFINE_CLOCK(pwm1_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG6_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(pwm2_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG8_OFFSET, + NULL, NULL, &ipg_clk, NULL); + +/* I2C */ +DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG10_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(i2c3_clk, 2, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET, + NULL, NULL, &ipg_clk, NULL); + +/* FEC */ +DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET, + NULL, NULL, &ipg_clk, NULL); + +/* NFC */ +DEFINE_CLOCK_CCGR(nfc_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG10_OFFSET, + clk_nfc, &emi_slow_clk, NULL); + +/* SSI */ +DEFINE_CLOCK(ssi1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG8_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG9_OFFSET, + NULL, NULL, &pll3_sw_clk, &ssi1_ipg_clk); +DEFINE_CLOCK(ssi2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG10_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG11_OFFSET, + NULL, NULL, &pll3_sw_clk, &ssi2_ipg_clk); +DEFINE_CLOCK(ssi3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG12_OFFSET, + NULL, NULL, &ipg_clk, NULL); +DEFINE_CLOCK(ssi3_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG13_OFFSET, + NULL, NULL, &pll3_sw_clk, &ssi3_ipg_clk); + +/* eCSPI */ +DEFINE_CLOCK_FULL(ecspi1_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET, + NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable, + &ipg_clk, &spba_clk); +DEFINE_CLOCK(ecspi1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG10_OFFSET, + NULL, NULL, &ecspi_main_clk, &ecspi1_ipg_clk); +DEFINE_CLOCK_FULL(ecspi2_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG11_OFFSET, + NULL, NULL, _clk_ccgr_enable_inrun, _clk_ccgr_disable, + &ipg_clk, &aips_tz2_clk); +DEFINE_CLOCK(ecspi2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG12_OFFSET, + NULL, NULL, &ecspi_main_clk, &ecspi2_ipg_clk); + +/* CSPI */ +DEFINE_CLOCK(cspi_ipg_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG9_OFFSET, + NULL, NULL, &ipg_clk, &aips_tz2_clk); +DEFINE_CLOCK(cspi_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG13_OFFSET, + NULL, NULL, &ipg_clk, &cspi_ipg_clk); + +/* SDMA */ +DEFINE_CLOCK(sdma_clk, 1, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG15_OFFSET, + NULL, NULL, &ahb_clk, NULL); + +/* eSDHC */ +DEFINE_CLOCK_FULL(esdhc1_ipg_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG0_OFFSET, + NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); +DEFINE_CLOCK_MAX(esdhc1_clk, 0, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG1_OFFSET, + clk_esdhc1, &pll2_sw_clk, &esdhc1_ipg_clk); +DEFINE_CLOCK_FULL(esdhc2_ipg_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG2_OFFSET, + NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); +DEFINE_CLOCK_FULL(esdhc3_ipg_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG4_OFFSET, + NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); +DEFINE_CLOCK_FULL(esdhc4_ipg_clk, 3, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG6_OFFSET, + NULL, NULL, _clk_max_enable, _clk_max_disable, &ipg_clk, NULL); + +/* mx51 specific */ +DEFINE_CLOCK_MAX(esdhc2_clk, 1, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG3_OFFSET, + clk_esdhc2, &pll2_sw_clk, &esdhc2_ipg_clk); + +static struct clk esdhc3_clk = { + .id = 2, + .parent = &esdhc1_clk, + .set_parent = clk_esdhc3_set_parent, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, + .secondary = &esdhc3_ipg_clk, +}; +static struct clk esdhc4_clk = { + .id = 3, + .parent = &esdhc1_clk, + .set_parent = clk_esdhc4_set_parent, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, + .secondary = &esdhc4_ipg_clk, +}; + +/* mx53 specific */ +static struct clk esdhc2_mx53_clk = { + .id = 2, + .parent = &esdhc1_clk, + .set_parent = clk_esdhc2_mx53_set_parent, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, + .secondary = &esdhc3_ipg_clk, +}; + +DEFINE_CLOCK_MAX(esdhc3_mx53_clk, 2, MXC_CCM_CCGR3, MXC_CCM_CCGRx_CG5_OFFSET, + clk_esdhc3_mx53, &pll2_sw_clk, &esdhc2_ipg_clk); + +static struct clk esdhc4_mx53_clk = { + .id = 3, + .parent = &esdhc1_clk, + .set_parent = clk_esdhc4_mx53_set_parent, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, + .secondary = &esdhc4_ipg_clk, +}; + +DEFINE_CLOCK(mipi_esc_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG5_OFFSET, NULL, NULL, NULL, &pll2_sw_clk); +DEFINE_CLOCK(mipi_hsc2_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG4_OFFSET, NULL, NULL, &mipi_esc_clk, &pll2_sw_clk); +DEFINE_CLOCK(mipi_hsc1_clk, 0, MXC_CCM_CCGR4, MXC_CCM_CCGRx_CG3_OFFSET, NULL, NULL, &mipi_hsc2_clk, &pll2_sw_clk); + +/* IPU */ +DEFINE_CLOCK_FULL(ipu_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG5_OFFSET, + NULL, NULL, clk_ipu_enable, clk_ipu_disable, &ahb_clk, &ipu_sec_clk); + +DEFINE_CLOCK_FULL(emi_fast_clk, 0, MXC_CCM_CCGR5, MXC_CCM_CCGRx_CG7_OFFSET, + NULL, NULL, _clk_ccgr_enable, _clk_ccgr_disable_inwait, + &ddr_clk, NULL); + +DEFINE_CLOCK(ipu_di0_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG5_OFFSET, + NULL, NULL, &pll3_sw_clk, NULL); +DEFINE_CLOCK(ipu_di1_clk, 0, MXC_CCM_CCGR6, MXC_CCM_CCGRx_CG6_OFFSET, + NULL, NULL, &pll3_sw_clk, NULL); + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, + +static struct clk_lookup mx51_lookups[] = { + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) + _REGISTER_CLOCK(NULL, "gpt", gpt_clk) + _REGISTER_CLOCK("fec.0", NULL, fec_clk) + _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk) + _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) + _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_ahb_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb_phy1", usb_phy1_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_ahb_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb", usboh3_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) + _REGISTER_CLOCK("imx-keypad", NULL, dummy_clk) + _REGISTER_CLOCK("mxc_nand", NULL, nfc_clk) + _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) + _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) + _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk) + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk) + _REGISTER_CLOCK(NULL, "ckih", ckih_clk) + _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk) + _REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk) + _REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk) + _REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk) + _REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk) + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk) + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) + _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) + _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) + _REGISTER_CLOCK(NULL, "mipi_hsp", mipi_hsp_clk) + _REGISTER_CLOCK("imx-ipuv3", "ipu", ipu_clk) + _REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk) + _REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk) + _REGISTER_CLOCK(NULL, "gpc_dvfs", gpc_dvfs_clk) +}; + +static struct clk_lookup mx53_lookups[] = { + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) + _REGISTER_CLOCK(NULL, "gpt", gpt_clk) + _REGISTER_CLOCK("fec.0", NULL, fec_clk) + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_mx53_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_mx53_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_mx53_clk) + _REGISTER_CLOCK("imx53-ecspi.0", NULL, ecspi1_clk) + _REGISTER_CLOCK("imx53-ecspi.1", NULL, ecspi2_clk) + _REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk) + _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk) + _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk) + _REGISTER_CLOCK("imx-ipuv3", "ipu", ipu_clk) + _REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk) + _REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk) + _REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk) + _REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk) +}; + +static void clk_tree_init(void) +{ + u32 reg; + + ipg_perclk.set_parent(&ipg_perclk, &lp_apm_clk); + + /* + * Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at + * 8MHz, its derived from lp_apm. + * + * FIXME: Verify if true for all boards + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); +} + +int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, + unsigned long ckih1, unsigned long ckih2) +{ + int i; + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++) + clkdev_add(&mx51_lookups[i]); + + clk_tree_init(); + + clk_enable(&cpu_clk); + clk_enable(&main_bus_clk); + + clk_enable(&iim_clk); + mx51_revision(); + clk_disable(&iim_clk); + mx51_display_revision(); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy1_clk, &osc_clk); + + /* set the usboh3_clk parent to pll2_sw_clk */ + clk_set_parent(&usboh3_clk, &pll2_sw_clk); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(&esdhc1_clk, &pll2_sw_clk); + clk_set_parent(&esdhc2_clk, &pll2_sw_clk); + + /* set SDHC root clock as 166.25MHZ*/ + clk_set_rate(&esdhc1_clk, 166250000); + clk_set_rate(&esdhc2_clk, 166250000); + + /* System timer */ + mxc_timer_init(&gpt_clk, MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), + MX51_MXC_INT_GPT); + return 0; +} + +int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, + unsigned long ckih1, unsigned long ckih2) +{ + int i; + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + for (i = 0; i < ARRAY_SIZE(mx53_lookups); i++) + clkdev_add(&mx53_lookups[i]); + + clk_tree_init(); + + clk_set_parent(&uart_root_clk, &pll3_sw_clk); + clk_enable(&cpu_clk); + clk_enable(&main_bus_clk); + + clk_enable(&iim_clk); + mx53_revision(); + clk_disable(&iim_clk); + mx53_display_revision(); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(&esdhc1_clk, &pll2_sw_clk); + clk_set_parent(&esdhc3_mx53_clk, &pll2_sw_clk); + + /* set SDHC root clock as 200MHZ*/ + clk_set_rate(&esdhc1_clk, 200000000); + clk_set_rate(&esdhc3_mx53_clk, 200000000); + + /* System timer */ + mxc_timer_init(&gpt_clk, MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), + MX53_INT_GPT); + return 0; +} diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c new file mode 100755 index 00000000..bf60ffa6 --- /dev/null +++ b/arch/arm/mach-mx5/clock.c @@ -0,0 +1,5237 @@ +/* + * Copyright (C) 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/time.h> +#include <linux/hrtimer.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdram_autogating.h> + +#include "crm_regs.h" +#include "cpu_op-mx51.h" +#include "cpu_op-mx53.h" + +/* External clock values passed-in by the board code */ +static unsigned long external_high_reference, external_low_reference; +static unsigned long oscillator_reference, ckih2_reference; + +static struct clk pll1_main_clk; +static struct clk pll1_sw_clk; +static struct clk pll2_sw_clk; +static struct clk pll3_sw_clk; +static struct clk pll4_sw_clk; +static struct clk lp_apm_clk; +static struct clk tve_clk; +static struct clk emi_fast_clk; +static struct clk emi_slow_clk; +static struct clk emi_intr_clk[]; +static struct clk ddr_clk; +static struct clk ipu_clk[]; +static struct clk ldb_di_clk[]; +static struct clk axi_a_clk; +static struct clk axi_b_clk; +static struct clk ddr_hf_clk; +static struct clk mipi_hsp_clk; +static struct clk gpu3d_clk; +static struct clk gpu2d_clk; +static struct clk vpu_clk[]; +static int cpu_curr_op; +static struct cpu_op *cpu_op_tbl; + +static void __iomem *pll1_base; +static void __iomem *pll2_base; +static void __iomem *pll3_base; +static void __iomem *pll4_base; + +static int cpu_op_nr; +extern int lp_high_freq; +extern int lp_med_freq; +static int max_axi_a_clk; +static int max_axi_b_clk; +static int max_ahb_clk; +static int max_emi_slow_clk; +extern int dvfs_core_is_active; + +#define SPIN_DELAY 1000000 /* in nanoseconds */ +#define MAX_AXI_A_CLK_MX51 166250000 +#define MAX_AXI_A_CLK_MX53 400000000 +#define MAX_AXI_B_CLK_MX51 133000000 +#define MAX_AXI_B_CLK_MX53 200000000 +#define MAX_AHB_CLK_MX51 133000000 +#define MAX_EMI_SLOW_CLK_MX51 133000000 +#define MAX_AHB_CLK_MX53 133333333 +#define MAX_EMI_SLOW_CLK_MX53 133333333 +#define MAX_DDR_HF_RATE 200000000 +/* To keep compatible with some NAND flash, limit + * max NAND clk to 34MHZ. The user can modify it for + * dedicate NAND flash */ +#define MAX_NFC_CLK 34000000 + +#define UART1_DMA_ENABLE 0 +#define UART2_DMA_ENABLE 0 +#define UART3_DMA_ENABLE 0 +#define UART4_DMA_ENABLE 0 +#define UART5_DMA_ENABLE 0 + +#ifdef CONFIG_CLK_DEBUG +#define __INIT_CLK_DEBUG(n) .name = #n, +#else +#define __INIT_CLK_DEBUG(n) +#endif + +extern int mxc_jtag_enabled; +extern int uart_at_24; +extern int cpufreq_trig_needed; +extern int low_bus_freq_mode; + +static int cpu_clk_set_op(int op); +extern struct cpu_op *(*get_cpu_op)(int *op); +extern void (*set_num_cpu_op)(int num); + +static struct clk esdhc3_clk[]; + +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + if (div >= 512) { + *pre = 8; + *post = 64; + } else if (div >= 8) { + min_pre = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = (div + *pre - 1) / *pre; + } else if (div < 8) { + *pre = div; + *post = 1; + } +} + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg |= MXC_CCM_CCGRx_CG_MASK << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static int _clk_enable_inrun(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static void _clk_disable_inwait(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); +} + +/* + * For the 4-to-1 muxed input clock + */ +static inline u32 _get_mux(struct clk *parent, struct clk *m0, + struct clk *m1, struct clk *m2, struct clk *m3) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else + BUG(); + + return 0; +} + +/* + * For the ddr muxed input clock + */ +static inline u32 _get_mux_ddr(struct clk *parent, struct clk *m0, + struct clk *m1, struct clk *m2, struct clk *m3, struct clk *m4) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else if (parent == m4) + return 4; + else + BUG(); + + return 0; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) + return pll1_base; + else if (pll == &pll2_sw_clk) + return pll2_base; + else if (pll == &pll3_sw_clk) + return pll3_base; + else if (pll == &pll4_sw_clk) + return pll4_base; + else + BUG(); + + return NULL; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) +{ + return ckih2_reference; +} + +/* External high frequency clock */ +static struct clk ckih_clk = { + __INIT_CLK_DEBUG(ckih_clk) + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk ckih2_clk = { + __INIT_CLK_DEBUG(ckih2_clk) + .get_rate = get_ckih2_reference_clock_rate, +}; + +static struct clk osc_clk = { + __INIT_CLK_DEBUG(osc_clk) + .get_rate = get_oscillator_reference_clock_rate, +}; + +/* External low frequency (32kHz) clock */ +static struct clk ckil_clk = { + __INIT_CLK_DEBUG(ckil_clk) + .get_rate = get_low_reference_clock_rate, +}; + +static unsigned long _fpm_get_rate(struct clk *clk) +{ + u32 rate = ckil_clk.get_rate(&ckil_clk) * 512; + if ((__raw_readl(MXC_CCM_CCR) & MXC_CCM_CCR_FPM_MULT_MASK) != 0) + rate *= 2; + return rate; +} + +static int _fpm_enable(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCR); + reg |= MXC_CCM_CCR_FPM_EN; + __raw_writel(reg, MXC_CCM_CCR); + return 0; +} + +static void _fpm_disable(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCR); + reg &= ~MXC_CCM_CCR_FPM_EN; + __raw_writel(reg, MXC_CCM_CCR); +} + +static struct clk fpm_clk = { + __INIT_CLK_DEBUG(fpm_clk) + .parent = &ckil_clk, + .get_rate = _fpm_get_rate, + .enable = _fpm_enable, + .disable = _fpm_disable, +}; + +static unsigned long _fpm_div2_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk fpm_div2_clk = { + __INIT_CLK_DEBUG(fpm_div2_clk) + .parent = &fpm_clk, + .get_rate = _fpm_div2_get_rate, +}; + +static unsigned long _clk_pll_get_rate(struct clk *clk) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; + void __iomem *pllbase; + s64 temp; + + pllbase = _get_pll_base(clk); + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + if (pll_hfsm == 0) { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); + } else { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); + } + pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; + mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; + mfi = (mfi <= 5) ? 5 : mfi; + mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; + mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; + /* Sign extend to 32-bits */ + if (mfn >= 0x04000000) { + mfn |= 0xFC000000; + mfn_abs = -mfn; + } + + ref_clk = 2 * clk_get_rate(clk->parent); + if (dbl != 0) + ref_clk *= 2; + + ref_clk /= (pdf + 1); + temp = (u64) ref_clk * mfn_abs; + do_div(temp, mfd + 1); + if (mfn < 0) + temp = -temp; + temp = (ref_clk * mfi) + temp; + + return temp; +} + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, reg1; + void __iomem *pllbase; + struct timespec nstimeofday; + struct timespec curtime; + + long mfi, pdf, mfn, mfd = 999999; + s64 temp64; + unsigned long quad_parent_rate; + unsigned long pll_hfsm, dp_ctl; + + pllbase = _get_pll_base(clk); + + quad_parent_rate = 4 * clk_get_rate(clk->parent); + pdf = mfi = -1; + while (++pdf < 16 && mfi < 5) + mfi = rate * (pdf+1) / quad_parent_rate; + if (mfi > 15) + return -1; + pdf--; + + temp64 = rate*(pdf+1) - quad_parent_rate*mfi; + do_div(temp64, quad_parent_rate/1000000); + mfn = (long)temp64; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + if (pll_hfsm == 0) { + reg = mfi<<4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); + } else { + reg = mfi<<4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); + } + /* If auto restart is disabled, restart the PLL and + * wait for it to lock. + */ + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_UPEN) { + reg = __raw_readl(pllbase + MXC_PLL_DP_CONFIG); + if (!(reg & MXC_PLL_DP_CONFIG_AREN)) { + reg1 = __raw_readl(pllbase + MXC_PLL_DP_CTL); + reg1 |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg1, pllbase + MXC_PLL_DP_CTL); + } + /* Wait for lock */ + getnstimeofday(&nstimeofday); + while (!(__raw_readl(pllbase + MXC_PLL_DP_CTL) + & MXC_PLL_DP_CTL_LRF)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll_set_rate: pll relock failed\n"); + } + } + return 0; +} + +static int _clk_pll_enable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + struct timespec nstimeofday; + struct timespec curtime; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + + if (reg & MXC_PLL_DP_CTL_UPEN) + return 0; + + reg |= MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + getnstimeofday(&nstimeofday); + while (!(__raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF)) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll relock failed\n"); + } + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); +} + +static struct clk pll1_main_clk = { + __INIT_CLK_DEBUG(pll1_main_clk) + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll1_main_clk) { + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set the step_clk parent to be lp_apm, to save power. */ + mux = _get_mux(&lp_apm_clk, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + if (parent == &lp_apm_clk) { + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + reg = __raw_readl(MXC_CCM_CCSR); + mux = _get_mux(parent, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + mux = _get_mux(parent, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CCSR); + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + + } + } + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static unsigned long _clk_pll1_sw_get_rate(struct clk *clk) +{ + u32 reg, div; + div = 1; + reg = __raw_readl(MXC_CCM_CCSR); + + if (clk->parent == &pll2_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> + MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; + } else if (clk->parent == &pll3_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> + MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; + } + return clk_get_rate(clk->parent) / div; +} + +/* pll1 switch clock */ +static struct clk pll1_sw_clk = { + __INIT_CLK_DEBUG(pll1_sw_clk) + .parent = &pll1_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = _clk_pll1_sw_get_rate, +}; + +static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll2_sw_clk) { + reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } else { + reg = (reg & ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL); + reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +/* same as pll2_main_clk. These two clocks should always be the same */ +static struct clk pll2_sw_clk = { + __INIT_CLK_DEBUG(pll2_sw_clk) + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll_set_rate, + .set_parent = _clk_pll2_sw_set_parent, +}; + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_sw_clk = { + __INIT_CLK_DEBUG(pll3_sw_clk) + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +/* same as pll4_main_clk. These two clocks should always be the same */ +static struct clk pll4_sw_clk = { + __INIT_CLK_DEBUG(pll4_sw_clk) + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (parent == &osc_clk) + reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; + else if (parent == &fpm_clk) + reg = __raw_readl(MXC_CCM_CCSR) | MXC_CCM_CCSR_LP_APM_SEL; + else + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static struct clk lp_apm_clk = { + __INIT_CLK_DEBUG(lp_apm_clk) + .parent = &osc_clk, + .set_parent = _clk_lp_apm_set_parent, +}; + +static unsigned long _clk_arm_get_rate(struct clk *clk) +{ + u32 cacrr, div; + + cacrr = __raw_readl(MXC_CCM_CACRR); + div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_cpu_set_rate(struct clk *clk, unsigned long rate) +{ + u32 i; + + for (i = 0; i < cpu_op_nr; i++) { + if (rate == cpu_op_tbl[i].cpu_rate) + break; + } + if (i >= cpu_op_nr) + return -EINVAL; + cpu_clk_set_op(i); + + return 0; +} + +static unsigned long _clk_cpu_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 i; + u32 op; + + for (i = 0; i < cpu_op_nr; i++) { + if (rate == cpu_op_tbl[i].cpu_rate) + break; + } + + if (i > cpu_op_nr) + op = 0; + + return cpu_op_tbl[op].cpu_rate; +} + + +static struct clk cpu_clk = { + __INIT_CLK_DEBUG(cpu_clk) + .parent = &pll1_sw_clk, + .get_rate = _clk_arm_get_rate, + .set_rate = _clk_cpu_set_rate, + .round_rate = _clk_cpu_round_rate, +}; + +static int _clk_periph_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + struct timespec nstimeofday; + struct timespec curtime; + + mux = _get_mux(parent, &pll1_sw_clk, &pll3_sw_clk, &lp_apm_clk, NULL); + + reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll _clk_periph_apm_set_parent failed\n"); + } + return 0; +} + +static struct clk periph_apm_clk = { + __INIT_CLK_DEBUG(periph_apm_clk) + .parent = &pll1_sw_clk, + .set_parent = _clk_periph_apm_set_parent, +}; + +/* TODO: Need to sync with GPC to determine if DVFS is in place so that + * the DVFS_PODF divider can be applied in CDCR register. + */ +static unsigned long _clk_main_bus_get_rate(struct clk *clk) +{ + u32 div = 0; + + if (dvfs_per_divider_active() || low_bus_freq_mode) + div = (__raw_readl(MXC_CCM_CDCR) & 0x3); + return clk_get_rate(clk->parent) / (div + 1); +} + +static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + if (parent == &pll2_sw_clk) { + reg = __raw_readl(MXC_CCM_CBCDR) & + ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + } else if (parent == &periph_apm_clk) { + reg = __raw_readl(MXC_CCM_CBCDR) | MXC_CCM_CBCDR_PERIPH_CLK_SEL; + } else { + return -EINVAL; + } + __raw_writel(reg, MXC_CCM_CBCDR); + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static struct clk main_bus_clk = { + __INIT_CLK_DEBUG(main_bus_clk) + .parent = &pll2_sw_clk, + .set_parent = _clk_main_bus_set_parent, + .get_rate = _clk_main_bus_get_rate, +}; + +static unsigned long _clk_axi_a_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_A_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_A_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_a_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_A_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AXI_A_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("pll _clk_axi_a_set_rate failed\n"); + } + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static unsigned long _clk_axi_a_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_axi_a_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk axi_a_clk = { + __INIT_CLK_DEBUG(axi_a_clk) + .parent = &main_bus_clk, + .get_rate = _clk_axi_a_get_rate, + .set_rate = _clk_axi_a_set_rate, + .round_rate = _clk_axi_a_round_rate, +}; + +static unsigned long _clk_ddr_hf_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_DDR_PODF_MASK) >> + MXC_CCM_CBCDR_DDR_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_ddr_hf_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > MAX_DDR_HF_RATE) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_ddr_hf_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_DDR_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_DDR_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_DDR_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("clk_ddr_hf_set_rate failed\n"); + } + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static struct clk ddr_hf_clk = { + __INIT_CLK_DEBUG(ddr_hf_clk) + .parent = &pll1_sw_clk, + .get_rate = _clk_ddr_hf_get_rate, + .round_rate = _clk_ddr_hf_round_rate, + .set_rate = _clk_ddr_hf_set_rate, +}; + +static unsigned long _clk_axi_b_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_B_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_B_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_b_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_B_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AXI_B_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("_clk_axi_b_set_rate failed\n"); + } + + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static unsigned long _clk_axi_b_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_axi_b_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk axi_b_clk = { + __INIT_CLK_DEBUG(axi_b_clk) + .parent = &main_bus_clk, + .get_rate = _clk_axi_b_get_rate, + .set_rate = _clk_axi_b_set_rate, + .round_rate = _clk_axi_b_round_rate, +}; + +static unsigned long _clk_ahb_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> + MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + + +static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AHB_PODF_BUSY) { + getnstimeofday(&curtime); + if (curtime.tv_nsec - nstimeofday.tv_nsec > SPIN_DELAY) + panic("_clk_ahb_set_rate failed\n"); + } + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static unsigned long _clk_ahb_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_ahb_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk ahb_clk = { + __INIT_CLK_DEBUG(ahb_clk) + .parent = &main_bus_clk, + .get_rate = _clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, +}; + +static int _clk_max_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with MAX when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51; + else + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + + +static void _clk_max_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable_inwait(clk); + + /* No Handshake with MAX when LPM is entered as its disabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51; + else + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk ahb_max_clk = { + __INIT_CLK_DEBUG(ahb_max_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, +}; + +static int _clk_emi_slow_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + reg = __raw_readl(MXC_CCM_CBCDR); + if (parent == &ahb_clk) { + reg |= MXC_CCM_CBCDR_EMI_CLK_SEL; + } else if (parent == &main_bus_clk) { + reg &= ~MXC_CCM_CBCDR_EMI_CLK_SEL; + } else { + BUG(); + } + __raw_writel(reg, MXC_CCM_CBCDR); + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static unsigned long _clk_emi_slow_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_EMI_PODF_MASK) >> + MXC_CCM_CBCDR_EMI_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_emi_slow_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_EMI_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_EMI_PODF_BUSY) { + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("_clk_emi_slow_set_rate failed\n"); + } + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + + return 0; +} + +static unsigned long _clk_emi_slow_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > max_emi_slow_clk) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk emi_slow_clk = { + __INIT_CLK_DEBUG(emi_slow_clk) + .parent = &main_bus_clk, + .set_parent = _clk_emi_slow_set_parent, + .get_rate = _clk_emi_slow_get_rate, + .set_rate = _clk_emi_slow_set_rate, + .round_rate = _clk_emi_slow_round_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk ahbmux1_clk = { + __INIT_CLK_DEBUG(ahbmux1_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk ahbmux2_clk = { + __INIT_CLK_DEBUG(ahbmux2_clk) + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .disable = _clk_disable_inwait, +}; + + +static struct clk emi_fast_clk = { + __INIT_CLK_DEBUG(emi_fast_clk) + .parent = &ddr_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable_inwait, +}; + +static struct clk emi_intr_clk[] = { + { + __INIT_CLK_DEBUG(emi_intr_clk_0) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahbmux2_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + }, + { + /* On MX51 - this clock is name emi_garb_clk, and controls the + * access of ARM to GARB. + */ + __INIT_CLK_DEBUG(emi_intr_clk_1) + .id = 1, + .parent = &ahb_clk, + .secondary = &ahbmux2_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + } +}; + +static unsigned long _clk_ipg_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> + MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static struct clk ipg_clk = { + __INIT_CLK_DEBUG(ipg_clk) + .parent = &ahb_clk, + .get_rate = _clk_ipg_get_rate, +}; + +static unsigned long _clk_ipg_per_get_rate(struct clk *clk) +{ + u32 reg, prediv1, prediv2, podf; + + if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { + /* the main_bus_clk is the one before the DVFS engine */ + reg = __raw_readl(MXC_CCM_CBCDR); + prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; + prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; + podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> + MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / (prediv1 * prediv2 * podf); + } else if (clk->parent == &ipg_clk) { + return clk_get_rate(&ipg_clk); + } + BUG(); + return 0; +} + +static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &main_bus_clk, &lp_apm_clk, &ipg_clk, NULL); + if (mux == 2) { + reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + } else { + reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + if (mux == 0) + reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + else + reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk ipg_perclk = { + __INIT_CLK_DEBUG(ipg_perclk) + .parent = &lp_apm_clk, + .get_rate = _clk_ipg_per_get_rate, + .set_parent = _clk_ipg_per_set_parent, +}; + +static int _clk_ipmux_enable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_ipmux_disable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(0x1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static struct clk ipumux1_clk = { + __INIT_CLK_DEBUG(ipumux1_clk) + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG6_1_OFFSET, + .enable = _clk_ipmux_enable, + .disable = _clk_ipmux_disable, +}; + +static struct clk ipumux2_clk = { + __INIT_CLK_DEBUG(ipumux2_clk) + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGR5_CG6_2_OFFSET, + .enable = _clk_ipmux_enable, + .disable = _clk_ipmux_disable, +}; + +static int _clk_ocram_enable(struct clk *clk) +{ + return 0; +} + +static void _clk_ocram_disable(struct clk *clk) +{ +} + +static struct clk ocram_clk = { + __INIT_CLK_DEBUG(ocram_clk) + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_ocram_enable, + .disable = _clk_ocram_disable, +}; + + +static struct clk aips_tz1_clk = { + __INIT_CLK_DEBUG(aips_tz1_clk) + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz2_clk = { + __INIT_CLK_DEBUG(aips_tz2_clk) + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk gpc_dvfs_clk = { + __INIT_CLK_DEBUG(gpc_dvfs_clk) + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_sdma_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with SDMA when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; + else + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_sdma_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable(clk); + /* No handshake with SDMA as its not enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + if (cpu_is_mx51()) + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; + else + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk sdma_clk[] = { + { + __INIT_CLK_DEBUG(sdma_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_sdma_enable, + .disable = _clk_sdma_disable, + }, + { + .parent = &ipg_clk, +#ifdef CONFIG_SDMA_IRAM + .secondary = &emi_intr_clk[0], +#endif + }, +}; + +static int _clk_ipu_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + /* Handshake with IPU when certain clock rates are changed. */ + reg = __raw_readl(MXC_CCM_CCDR); + if (cpu_is_mx51()) + reg &= ~MXC_CCM_CCDR_IPU_HS_MASK; + else + reg &= ~MXC_CCM_CCDR_IPU_HS_MX53_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + /* Handshake with IPU when LPM is entered as its enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + start_sdram_autogating(); + + return 0; +} + +static void _clk_ipu_disable(struct clk *clk) +{ + u32 reg; + + if (sdram_autogating_active()) + stop_sdram_autogating(); + + _clk_disable(clk); + + /* No handshake with IPU whe dividers are changed + * as its not enabled. */ + reg = __raw_readl(MXC_CCM_CCDR); + if (cpu_is_mx51()) + reg |= MXC_CCM_CCDR_IPU_HS_MASK; + else + reg |= MXC_CCM_CCDR_IPU_HS_MX53_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + /* No handshake with IPU when LPM is entered as its not enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static int _clk_ipu_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &ahb_clk, + &emi_slow_clk); + reg = (reg & ~MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + + +static struct clk ipu_clk[] = { + { + __INIT_CLK_DEBUG(ipu_clk) + .parent = &ahb_clk, + .secondary = &ipu_clk[1], + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_ipu_enable, + .disable = _clk_ipu_disable, + .set_parent = _clk_ipu_set_parent, + .flags = CPU_FREQ_TRIG_UPDATE | AHB_MED_SET_POINT, + }, + { + __INIT_CLK_DEBUG(ipu_clk_1) + .parent = &emi_fast_clk, + .secondary = &ahbmux1_clk, + } +}; + +static int _clk_ipu_di_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + reg &= ~MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(clk->id); + if (parent == &pll3_sw_clk) + ; + else if (parent == &osc_clk) + reg |= 1 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if (parent == &ckih_clk) + reg |= 2 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if ((parent == &pll4_sw_clk) && (clk->id == 0)) { + if (cpu_is_mx51()) + return -EINVAL; + reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + } else if ((parent == &tve_clk) && (clk->id == 1)) + reg |= 3 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else if ((parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) + reg |= 5 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + else /* Assume any other clock is external clock pin */ + reg |= 4 << MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static int priv_div; +static unsigned long _clk_ipu_di_get_rate(struct clk *clk) +{ + u32 reg, mux; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR2); + mux = (reg & MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(clk->id)) >> + MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(clk->id); + if (mux == 0) { + reg = __raw_readl(MXC_CCM_CDCDR) & + MXC_CCM_CDCDR_DI1_CLK_PRED_MASK; + div = (reg >> MXC_CCM_CDCDR_DI1_CLK_PRED_OFFSET) + 1; + } else if ((mux == 3) && (clk->id == 1)) { + if (priv_div) + div = priv_div; + } else if ((mux == 3) && (clk->id == 0)) { + reg = __raw_readl(MXC_CCM_CDCDR) & + MXC_CCM_CDCDR_DI_PLL4_PODF_MASK; + div = (reg >> MXC_CCM_CDCDR_DI_PLL4_PODF_OFFSET) + 1; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu_di_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + if ((clk->parent == &pll4_sw_clk) && (clk->id == 0)) { + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_DI_PLL4_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CDCDR_DI_PLL4_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + } else if (clk->parent == &pll3_sw_clk) { + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_DI1_CLK_PRED_MASK; + reg |= (div - 1) << MXC_CCM_CDCDR_DI1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + } else if (((clk->parent == &tve_clk) && (clk->id == 1)) || + ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53())) { + priv_div = div; + return 0; + } else + return -EINVAL; + + return 0; +} + +static unsigned long _clk_ipu_di_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + if ((clk->parent == &ldb_di_clk[clk->id]) && cpu_is_mx53()) + return parent_rate; + else { + div = (parent_rate + rate/2) / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; + } +} + +static struct clk ipu_di_clk[] = { + { + __INIT_CLK_DEBUG(ipu_di_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .get_rate = _clk_ipu_di_get_rate, + .set_parent = _clk_ipu_di_set_parent, + .round_rate = _clk_ipu_di_round_rate, + .set_rate = _clk_ipu_di_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ipu_di_clk_1) + .id = 1, + .parent = &pll3_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .get_rate = _clk_ipu_di_get_rate, + .set_parent = _clk_ipu_di_set_parent, + .round_rate = _clk_ipu_di_round_rate, + .set_rate = _clk_ipu_di_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static int _clk_ldb_di_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + + if ((parent == &pll3_sw_clk)) { + if (clk->id == 0) + reg &= ~(MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL); + else + reg &= ~(MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL); + } else if ((parent == &pll4_sw_clk)) { + if (clk->id == 0) + reg |= MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL; + else + reg |= MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL; + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR2); + return 0; +} + +static unsigned long _clk_ldb_di_get_rate(struct clk *clk) +{ + u32 div; + + if (clk->id == 0) + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV; + else + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV; + + if (div) + return clk_get_rate(clk->parent) / 7; + + return (2 * clk_get_rate(clk->parent)) / 7; +} + +static unsigned long _clk_ldb_di_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 parent_rate = clk_get_rate(clk->parent); + + if (rate * 7 <= parent_rate + parent_rate/20) + return parent_rate / 7; + else + return 2 * parent_rate / 7; +} + +static int _clk_ldb_di_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div = 0; + u32 parent_rate = clk_get_rate(clk->parent); + + if (rate * 7 <= parent_rate + parent_rate/20) { + div = 7; + rate = parent_rate / 7; + } else + rate = 2 * parent_rate / 7; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (div == 7) + reg |= (clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV : + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + else + reg &= ~(clk->id ? MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV : + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static int _clk_ldb_di_enable(struct clk *clk) +{ + _clk_enable(clk); + ipu_di_clk[clk->id].set_parent(&ipu_di_clk[clk->id], clk); + ipu_di_clk[clk->id].parent = clk; + ipu_di_clk[clk->id].enable(&ipu_di_clk[clk->id]); + ipu_di_clk[clk->id].usecount++; + return 0; +} + +static void _clk_ldb_di_disable(struct clk *clk) +{ + _clk_disable(clk); + ipu_di_clk[clk->id].disable(&ipu_di_clk[clk->id]); + ipu_di_clk[clk->id].usecount--; +} + +static struct clk ldb_di_clk[] = { + { + __INIT_CLK_DEBUG(ldb_di_clk_0) + .id = 0, + .parent = &pll4_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .get_rate = _clk_ldb_di_get_rate, + .set_parent = _clk_ldb_di_set_parent, + .round_rate = _clk_ldb_di_round_rate, + .set_rate = _clk_ldb_di_set_rate, + .enable = _clk_ldb_di_enable, + .disable = _clk_ldb_di_disable, + .flags = AHB_MED_SET_POINT, + }, + { + __INIT_CLK_DEBUG(ldb_di_clk_1) + .id = 1, + .parent = &pll4_sw_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .get_rate = _clk_ldb_di_get_rate, + .set_parent = _clk_ldb_di_set_parent, + .round_rate = _clk_ldb_di_round_rate, + .set_rate = _clk_ldb_di_set_rate, + .enable = _clk_ldb_di_enable, + .disable = _clk_ldb_di_disable, + .flags = AHB_MED_SET_POINT, + }, +}; + +static int _clk_csi0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_csi0_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CSCDR4); + pred = ((reg & MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent)/(pred * podf); +} + +static unsigned long _clk_csi0_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_csi0_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set CSI clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR4) & + ~(MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK | + MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR4); + + return 0; +} + +static struct clk csi0_clk = { + .parent = &pll3_sw_clk, + .set_parent = _clk_csi0_set_parent, + .get_rate = _clk_csi0_get_rate, + .round_rate = _clk_csi0_round_rate, + .set_rate = _clk_csi0_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_csi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_csi1_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CSCDR4); + pred = ((reg & MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent)/(pred * podf) ; +} + +static unsigned long _clk_csi1_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_csi1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set CSI clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR4) & + ~(MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK | + MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR4); + + return 0; +} + +static struct clk csi1_clk = { + __INIT_CLK_DEBUG(csi1_clk) + .parent = &pll3_sw_clk, + .set_parent = _clk_csi1_set_parent, + .get_rate = _clk_csi1_get_rate, + .round_rate = _clk_csi1_round_rate, + .set_rate = _clk_csi1_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, +}; + + +static int _clk_hsc_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + /* Handshake with IPU when certain clock rates are changed. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg &= ~MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_hsc_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable(clk); + /* No handshake with HSC as its not enabled. */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + +static struct clk mipi_esc_clk = { + __INIT_CLK_DEBUG(mipi_esc_clk) + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, +}; + +static struct clk mipi_hsc2_clk = { + __INIT_CLK_DEBUG(mipi_hsc2_clk) + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .secondary = &mipi_esc_clk, +}; + +static struct clk mipi_hsc1_clk = { + __INIT_CLK_DEBUG(mipi_hsc1_clk) + .parent = &pll2_sw_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .secondary = &mipi_hsc2_clk, +}; + +static struct clk mipi_hsp_clk = { + __INIT_CLK_DEBUG(mipi_hsp_clk) + .parent = &ipu_clk[0], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_hsc_enable, + .disable = _clk_hsc_disable, + .secondary = &mipi_hsc1_clk, +}; + +static int _clk_tve_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + + if ((parent == &pll3_sw_clk) && cpu_is_mx51()) { + reg &= ~(MXC_CCM_CSCMR1_TVE_CLK_SEL); + } else if ((parent == &pll4_sw_clk) && cpu_is_mx53()) { + reg &= ~(MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL); + } else if ((parent == &osc_clk) && cpu_is_mx51()) { + reg |= MXC_CCM_CSCMR1_TVE_CLK_SEL; + reg &= ~MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL; + } else if (parent == &ckih_clk) { + reg |= MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL; + reg |= MXC_CCM_CSCMR1_TVE_CLK_SEL; /* Reserved on MX53 */ + } else { + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static unsigned long _clk_tve_get_rate(struct clk *clk) +{ + u32 reg, div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & (MXC_CCM_CSCMR1_TVE_CLK_SEL | MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL)) == 0) { + reg = __raw_readl(MXC_CCM_CDCDR) & + MXC_CCM_CDCDR_TVE_CLK_PRED_MASK; + div = (reg >> MXC_CCM_CDCDR_TVE_CLK_PRED_OFFSET) + 1; + } + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_tve_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (cpu_is_mx51() && (reg & MXC_CCM_CSCMR1_TVE_CLK_SEL)) + return -EINVAL; + if (cpu_is_mx53() && (reg & MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL)) + return -EINVAL; + + div = (parent_rate + rate/2) / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; +} + +static int _clk_tve_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (cpu_is_mx51() && (reg & MXC_CCM_CSCMR1_TVE_CLK_SEL)) + return -EINVAL; + if (cpu_is_mx53() && (reg & MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL)) + return -EINVAL; + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + div--; + reg = __raw_readl(MXC_CCM_CDCDR) & ~MXC_CCM_CDCDR_TVE_CLK_PRED_MASK; + reg |= div << MXC_CCM_CDCDR_TVE_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + return 0; +} + +static struct clk tve_clk = { + __INIT_CLK_DEBUG(tve_clk) + .parent = &pll3_sw_clk, + .set_parent = _clk_tve_set_parent, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .get_rate = _clk_tve_get_rate, + .round_rate = _clk_tve_round_rate, + .set_rate = _clk_tve_set_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk spba_clk = { + __INIT_CLK_DEBUG(spba_clk) + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_uart_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent)/(prediv * podf) ; +} + +static int _clk_uart_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_UART_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk uart_main_clk = { + __INIT_CLK_DEBUG(uart_main_clk) + .parent = &pll2_sw_clk, + .get_rate = _clk_uart_get_rate, + .set_parent = _clk_uart_set_parent, +}; + +static struct clk uart1_clk[] = { + { + __INIT_CLK_DEBUG(uart1_clk_0) + .id = 0, + .parent = &uart_main_clk, + .secondary = &uart1_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART1_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart1_clk_1) + .id = 0, + .parent = &ipg_clk, +#if UART1_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart2_clk[] = { + { + __INIT_CLK_DEBUG(uart2_clk_0) + .id = 1, + .parent = &uart_main_clk, + .secondary = &uart2_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART2_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart2_clk_1) + .id = 1, + .parent = &ipg_clk, +#if UART2_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart3_clk[] = { + { + __INIT_CLK_DEBUG(uart3_clk_0) + .id = 2, + .parent = &uart_main_clk, + .secondary = &uart3_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART3_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart3_clk_1) + .id = 2, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart4_clk[] = { + { + __INIT_CLK_DEBUG(uart4_clk_0) + .id = 3, + .parent = &uart_main_clk, + .secondary = &uart4_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART4_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart4_clk_1) + .id = 3, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart5_clk[] = { + { + __INIT_CLK_DEBUG(uart5_clk_0) + .id = 4, + .parent = &uart_main_clk, + .secondary = &uart5_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART5_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart5_clk_1) + .id = 4, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk gpt_clk[] = { + { + __INIT_CLK_DEBUG(gpt_clki_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &gpt_clk[1], + }, + { + __INIT_CLK_DEBUG(gpt_clki_1) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(gpt_clki_2) + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm1_clk[] = { + { + __INIT_CLK_DEBUG(pwm1_clk_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm1_clk[1], + }, + { + __INIT_CLK_DEBUG(pwm1_clk_1) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm1_clk_2) + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm2_clk[] = { + { + __INIT_CLK_DEBUG(pwm2_clk_0) + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm2_clk[1], + }, + { + __INIT_CLK_DEBUG(pwm2_clk_1) + .id = 1, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm2_clk_2) + .id = 1, + .parent = &ckil_clk, + }, +}; + +static struct clk i2c_clk[] = { + { + __INIT_CLK_DEBUG(i2c_clk_0) + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_1) + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_2) + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_hsi2c_serial_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR3); + prediv = ((reg & MXC_CCM_CSCDR3_HSI2C_CLK_PRED_MASK) >> + MXC_CCM_CSCDR3_HSI2C_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR3_HSI2C_CLK_PODF_MASK) >> + MXC_CCM_CSCDR3_HSI2C_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static struct clk hsi2c_serial_clk = { + __INIT_CLK_DEBUG(hsi2c_serial_clk) + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .get_rate = _clk_hsi2c_serial_get_rate, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk hsi2c_clk = { + __INIT_CLK_DEBUG(hsi2c_clk) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_cspi_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_cspi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk cspi_main_clk = { + __INIT_CLK_DEBUG(cspi_main_clk) + .parent = &pll3_sw_clk, + .get_rate = _clk_cspi_get_rate, + .set_parent = _clk_cspi_set_parent, +}; + +static struct clk cspi1_clk[] = { + { + __INIT_CLK_DEBUG(cspi1_clk_0) + .id = 0, + .parent = &cspi_main_clk, + .secondary = &cspi1_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(cspi1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi2_clk[] = { + { + __INIT_CLK_DEBUG(cspi2_clk_0) + .id = 1, + .parent = &cspi_main_clk, + .secondary = &cspi2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(cspi2_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi3_clk = { + __INIT_CLK_DEBUG(cspi3_clk) + .id = 2, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &aips_tz2_clk, +}; + +static unsigned long _clk_ieee_rtc_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_IEEE_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_IEEE_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_IEEE_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_IEEE_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_ieee_rtc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 512) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~(MXC_CCM_CSCDR2_IEEE_CLK_PRED_MASK | + MXC_CCM_CSCDR2_IEEE_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR2_IEEE_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR2_IEEE_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static unsigned long _clk_ieee_rtc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_ieee_rtc_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll3_sw_clk, &pll4_sw_clk, + NULL, NULL); + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_IEEE_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_IEEE_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static struct clk ieee_rtc_clk = { + __INIT_CLK_DEBUG(ieee_rtc_clk) + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ieee_rtc_set_parent, + .set_rate = _clk_ieee_rtc_set_rate, + .round_rate = _clk_ieee_rtc_round_rate, + .get_rate = _clk_ieee_rtc_get_rate, +}; + +static int _clk_ssi_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &ckih_clk, &lp_apm_clk, &ckih2_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_lp_apm_clk = { + __INIT_CLK_DEBUG(ssi_lp_apm_clk) + .parent = &ckih_clk, + .set_parent = _clk_ssi_lp_apm_set_parent, +}; + +static unsigned long _clk_ssi1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} +static int _clk_ssi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi1_clk[] = { + { + __INIT_CLK_DEBUG(ssi1_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi1_set_parent, + .secondary = &ssi1_clk[1], + .get_rate = _clk_ssi1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &ssi1_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi1_clk_2) + .id = 0, + .parent = &aips_tz2_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk[0], +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static unsigned long _clk_ssi2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_ssi2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi2_clk[] = { + { + __INIT_CLK_DEBUG(ssi2_clk_0) + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi2_set_parent, + .secondary = &ssi2_clk[1], + .get_rate = _clk_ssi2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi2_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &ssi2_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi2_clk_2) + .id = 1, + .parent = &spba_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk[0], +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static int _clk_ssi3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI3_CLK_SEL; + + if (parent == &ssi1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_SSI3_CLK_SEL; + else if (parent == &ssi2_clk[0]) + reg |= MXC_CCM_CSCMR1_SSI3_CLK_SEL; + else { + printk(KERN_ERR"Set ssi3 clock parent failed!\n"); + printk(KERN_ERR"ssi3 only support"); + printk(KERN_ERR"ssi1 and ssi2 as parent clock\n"); + return -1; + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk ssi3_clk[] = { + { + __INIT_CLK_DEBUG(ssi3_clk_0) + .id = 2, + .parent = &ssi1_clk[0], + .set_parent = _clk_ssi3_set_parent, + .secondary = &ssi3_clk[1], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi3_clk_1) + .id = 2, + .parent = &ipg_clk, + .secondary = &ssi3_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi3_clk_2) + .id = 2, + .parent = &aips_tz2_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &emi_intr_clk, +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static unsigned long _clk_ssi_ext1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ssi_ext1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 512) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK | + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static int _clk_ssi_ext1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &ssi1_clk[0]) { + reg |= MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &ssi_lp_apm_clk); + reg = (reg & ~MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_ssi_ext1_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk ssi_ext1_clk = { + __INIT_CLK_DEBUG(ssi_ext1_clk) + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext1_set_parent, + .set_rate = _clk_ssi_ext1_set_rate, + .round_rate = _clk_ssi_ext1_round_rate, + .get_rate = _clk_ssi_ext1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_ssi_ext2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ssi_ext2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &ssi2_clk[0]) { + reg |= MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &ssi_lp_apm_clk); + reg = (reg & ~MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_ext2_clk = { + __INIT_CLK_DEBUG(ssi_ext2_clk) + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext2_set_parent, + .get_rate = _clk_ssi_ext2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_esai_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (parent == &pll1_sw_clk || parent == &pll2_sw_clk || + parent == &pll3_sw_clk) { + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + NULL); + reg &= ~MXC_CCM_CSCMR2_ESAI_PRE_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_ESAI_PRE_SEL_OFFSET; + reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK; + reg |= 0 << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET; + /* divider setting */ + } else { + mux = _get_mux(parent, &ssi1_clk[0], &ssi2_clk[0], &ckih_clk, + &ckih2_clk); + reg &= ~MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK; + reg |= (mux + 1) << MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET; + /* divider setting */ + } + + __raw_writel(reg, MXC_CCM_CSCMR2); + + /* set podf = 0 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static unsigned long _clk_esai_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + if (clk->parent == &pll1_sw_clk || clk->parent == &pll2_sw_clk || + clk->parent == &pll3_sw_clk) { + pred = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (pred * podf); + } else { + podf = ((reg & MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / podf; + } +} + +static struct clk esai_clk[] = { + { + __INIT_CLK_DEBUG(esai_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_esai_set_parent, + .get_rate = _clk_esai_get_rate, + .secondary = &esai_clk[1], + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esai_clk_1) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk iim_clk = { + __INIT_CLK_DEBUG(iim_clk) + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, +}; + +static struct clk tmax1_clk = { + __INIT_CLK_DEBUG(tmax1_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }; + +static struct clk tmax2_clk = { + __INIT_CLK_DEBUG(tmax2_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk tmax3_clk = { + __INIT_CLK_DEBUG(tmax3_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_usboh3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_usboh3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk usboh3_clk[] = { + { + __INIT_CLK_DEBUG(usboh3_clk_0) + .parent = &pll3_sw_clk, + .set_parent = _clk_usboh3_set_parent, + .get_rate = _clk_usboh3_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, + .secondary = &usboh3_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(usboh3_clk_1) + .parent = &tmax2_clk, +#if defined(CONFIG_USB_STATIC_IRAM) \ + || defined(CONFIG_USB_STATIC_IRAM_PPH) + .secondary = &emi_intr_clk[0], +#else + .secondary = &emi_fast_clk, +#endif + }, +}; + +static struct clk usb_ahb_clk = { + __INIT_CLK_DEBUG(usb_ahb_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_usb_phy_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + if (clk->parent == &pll3_sw_clk) { + reg = __raw_readl(MXC_CCM_CDCDR); + prediv = ((reg & MXC_CCM_CDCDR_USB_PHY_PRED_MASK) >> + MXC_CCM_CDCDR_USB_PHY_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CDCDR_USB_PHY_PODF_MASK) >> + MXC_CCM_CDCDR_USB_PHY_PODF_OFFSET) + 1; + + div = (prediv * podf); + } + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usb_phy_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &osc_clk) + reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + else if (parent == &pll3_sw_clk) + reg |= MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + else + BUG(); + + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk usb_phy_clk[] = { + { + __INIT_CLK_DEBUG(usb_phy_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &tmax3_clk, + .set_parent = _clk_usb_phy_set_parent, + .get_rate = _clk_usb_phy_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(usb_phy_clk_1) + .id = 1, + .parent = &pll3_sw_clk, + .secondary = &tmax3_clk, + .set_parent = _clk_usb_phy_set_parent, + .get_rate = _clk_usb_phy_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk esdhc_dep_clks = { + __INIT_CLK_DEBUG(esdhc_dep_clks) + .parent = &spba_clk, + .secondary = &emi_fast_clk, +}; + +static unsigned long _clk_esdhc1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_esdhc1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + + +static int _clk_sdhc1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk esdhc1_clk[] = { + { + __INIT_CLK_DEBUG(esdhc1_clk_0) + .id = 0, + .parent = &pll2_sw_clk, + .set_parent = _clk_esdhc1_set_parent, + .get_rate = _clk_esdhc1_get_rate, + .set_rate = _clk_sdhc1_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[1], + }, + { + __INIT_CLK_DEBUG(esdhc1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &esdhc1_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc1_clk_2) + .id = 0, + .parent = &tmax3_clk, + .secondary = &esdhc_dep_clks, + }, + +}; + +static unsigned long _clk_esdhc2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + if (cpu_is_mx51()) { + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); + } + return clk_get_rate(clk->parent); +} + +static int _clk_esdhc2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (cpu_is_mx51()) { + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET; + } else { /* MX53 */ + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC2_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC2_CLK_SEL; + else + BUG(); + } + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static int _clk_esdhc2_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + if (cpu_is_mx51()) { + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << + MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + } + return 0; +} + +static struct clk esdhc2_clk[] = { + { + __INIT_CLK_DEBUG(esdhc2_clk_0) + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_esdhc2_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[1], + }, + { + __INIT_CLK_DEBUG(esdhc2_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &esdhc2_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc2_clk_2) + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (cpu_is_mx51()) { + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51; + else if (parent == &esdhc2_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51; + else + BUG(); + } else { /* MX53 */ + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET; + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_esdhc3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_sdhc3_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + if (cpu_is_mx53()) { + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + } + return 0; +} + + +static struct clk esdhc3_clk[] = { + { + __INIT_CLK_DEBUG(esdhc3_clk_0) + .id = 2, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc3_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc3_clk[1], + }, + { + __INIT_CLK_DEBUG(esdhc3_clk_1) + .id = 2, + .parent = &ipg_clk, + .secondary = &esdhc3_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc3_clk_2) + .id = 0, + .parent = &ahb_max_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + if (cpu_is_mx51()) { + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc2_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + BUG(); + } else {/*MX53 */ + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MXC_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + BUG(); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc4_clk[] = { + { + __INIT_CLK_DEBUG(esdhc4_clk_0) + .id = 3, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc4_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc4_clk[1], + }, + { + __INIT_CLK_DEBUG(esdhc4_clk_1) + .id = 3, + .parent = &ipg_clk, + .secondary = &esdhc4_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc4_clk_2) + .id = 0, + .parent = &tmax3_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static struct clk sata_clk = { + __INIT_CLK_DEBUG(sata_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ieee_1588_clk = { + __INIT_CLK_DEBUG(ieee_1588_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, +}; + +static struct clk mlb_clk[] = { + { + __INIT_CLK_DEBUG(mlb_clk_0) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + .secondary = &mlb_clk[1], + }, + { + __INIT_CLK_DEBUG(mlb_clk_1) + .parent = &emi_fast_clk, + .secondary = &emi_intr_clk[1], + }, +}; + +static int _can_root_clk_set(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &ipg_clk, &ckih_clk, &ckih2_clk, &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_CAN_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_CAN_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static struct clk can1_clk[] = { + { + __INIT_CLK_DEBUG(can1_clk_0) + .id = 0, + .parent = &lp_apm_clk, + .set_parent = _can_root_clk_set, + .enable = _clk_enable, + .secondary = &can1_clk[1], + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(can1_clk_1) + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk can2_clk[] = { + { + __INIT_CLK_DEBUG(can2_clk_0) + .id = 1, + .parent = &lp_apm_clk, + .set_parent = _can_root_clk_set, + .enable = _clk_enable, + .secondary = &can2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(can2_clk_1) + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_sim_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_SIM_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR2_SIM_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_sim_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + pred = ((reg & MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / (pred * podf); +} + +static unsigned long _clk_sim_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_sim_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set SIM clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR2) & + ~(MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK | + MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; + +} + +static struct clk sim_clk[] = { + { + __INIT_CLK_DEBUG(sim_clk_0) + .parent = &pll3_sw_clk, + .set_parent = _clk_sim_set_parent, + .secondary = &sim_clk[1], + .get_rate = _clk_sim_get_rate, + .round_rate = _clk_sim_round_rate, + .set_rate = _clk_sim_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(sim_clk_1) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_nfc_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_NFC_PODF_MASK) >> + MXC_CCM_CBCDR_NFC_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_nfc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + /* + * Compute the divider we'd have to use to reach the target rate. + */ + + div = parent_rate / rate; + if (div == 0) + div++; + if (parent_rate / div > MAX_NFC_CLK) + div++; + + /* + * The divider for this clock is 3 bits wide, so we can't possibly + * divide the parent by more than eight. + */ + + if (div > 8) + return -EINVAL; + + return parent_rate / div; + +} + +static int _clk_nfc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + struct timespec nstimeofday; + struct timespec curtime; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + if (emi_fast_clk.usecount == 0) + emi_fast_clk.enable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.enable(&emi_slow_clk); + + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY){ + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("_clk_nfc_set_rate failed\n"); + } + if (emi_fast_clk.usecount == 0) + emi_fast_clk.disable(&emi_fast_clk); + if (emi_slow_clk.usecount == 0) + emi_slow_clk.disable(&emi_slow_clk); + + return 0; +} + +static struct clk emi_enfc_clk = { + __INIT_CLK_DEBUG(emi_enfc_clk) + .parent = &emi_slow_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .disable = _clk_disable_inwait, + .get_rate = _clk_nfc_get_rate, + .round_rate = _clk_nfc_round_rate, + .set_rate = _clk_nfc_set_rate, +}; + +static int _clk_spdif_xtal_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &osc_clk, &ckih_clk, &ckih2_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SPDIF_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SPDIF_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk spdif_xtal_clk = { + __INIT_CLK_DEBUG(spdif_xtal_clk) + .parent = &osc_clk, + .set_parent = _clk_spdif_xtal_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_spdif0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + reg |= MXC_CCM_CSCMR2_SPDIF0_COM; + if (parent != &ssi1_clk[0]) { + reg &= ~MXC_CCM_CSCMR2_SPDIF0_COM; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &spdif_xtal_clk); + reg = (reg & ~MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_OFFSET); + } + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_spdif0_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + u32 div = 1; + + if (clk->parent != &ssi1_clk[0]) { + reg = __raw_readl(MXC_CCM_CDCDR); + pred = ((reg & MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK) >> + MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK) >> + MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET) + 1; + div = (pred * podf); + } + return clk_get_rate(clk->parent) / div; +} + +static struct clk spdif0_clk[] = { + { + __INIT_CLK_DEBUG(spdif0_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_spdif0_set_parent, + .get_rate = _clk_spdif0_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(spdif0_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_spdif1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2); + reg |= MXC_CCM_CSCMR2_SPDIF1_COM; + if (parent != &ssi2_clk[0]) { + reg &= ~MXC_CCM_CSCMR2_SPDIF1_COM; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &spdif_xtal_clk); + reg = (reg & ~MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_OFFSET); + } + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_spdif1_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + u32 div = 1; + + if (clk->parent != &ssi2_clk[0]) { + reg = __raw_readl(MXC_CCM_CDCDR); + pred = ((reg & MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK) >> + MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK) >> + MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET) + 1; + div = (pred * podf); + } + return clk_get_rate(clk->parent) / div; +} + +static struct clk spdif1_clk[] = { + { + __INIT_CLK_DEBUG(spdif1_clk_0) + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_spdif1_set_parent, + .get_rate = _clk_spdif1_get_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(spdif1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, + }, +}; + +static int _clk_ddr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, reg2, mux; + struct timespec nstimeofday; + struct timespec curtime; + + reg = __raw_readl(MXC_CCM_CBCMR); + reg2 = __raw_readl(MXC_CCM_CBCDR); + if (cpu_is_mx51()) { + clk->parent = &ddr_hf_clk; + mux = _get_mux_ddr(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk, &ddr_hf_clk); + } else { + clk->parent = &axi_a_clk; + mux = _get_mux_ddr(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk, NULL); + } + if (mux < 4) { + reg = (reg & ~MXC_CCM_CBCMR_DDR_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + if (cpu_is_mx51()) + reg2 = (reg2 & ~MXC_CCM_CBCDR_DDR_HF_SEL); + } else { + reg2 = (reg2 & ~MXC_CCM_CBCDR_DDR_HF_SEL) | + (MXC_CCM_CBCDR_DDR_HF_SEL); + } + if (cpu_is_mx51()) { + __raw_writel(reg2, MXC_CCM_CBCDR); + getnstimeofday(&nstimeofday); + while (__raw_readl(MXC_CCM_CDHIPR) & + MXC_CCM_CDHIPR_DDR_HF_CLK_SEL_BUSY){ + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("_clk_ddr_set_parent failed\n"); + } + } + return 0; +} + +static struct clk ddr_clk = { + __INIT_CLK_DEBUG(ddr_clk) + .parent = &axi_b_clk, + .set_parent = _clk_ddr_set_parent, +}; + +static int _clk_arm_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk arm_axi_clk = { + __INIT_CLK_DEBUG(arm_axi_clk) + .parent = &axi_a_clk, + .set_parent = _clk_arm_axi_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_vpu_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk vpu_clk[] = { + { + __INIT_CLK_DEBUG(vpu_clk_0) + .set_parent = _clk_vpu_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + .secondary = &vpu_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(vpu_clk_1) + .set_parent = _clk_vpu_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + .secondary = &vpu_clk[2], + }, + { + __INIT_CLK_DEBUG(vpu_clk_2) + .parent = &emi_fast_clk, + } +}; + +static int _clk_lpsr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + reg = __raw_readl(MXC_CCM_CLPCR); + mux = _get_mux(parent, &ckil_clk, &osc_clk, NULL, NULL); + reg = (reg & ~MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK) | + (mux << MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static struct clk lpsr_clk = { + __INIT_CLK_DEBUG(lpsr_clk) + .parent = &ckil_clk, + .set_parent = _clk_lpsr_set_parent, +}; + +static unsigned long _clk_pgc_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = (reg & MXC_CCM_CSCDR1_PGC_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_PGC_CLK_PODF_OFFSET; + div = 1 >> div; + return clk_get_rate(clk->parent) / div; +} + +static struct clk pgc_clk = { + __INIT_CLK_DEBUG(pgc_clk) + .parent = &ipg_clk, + .get_rate = _clk_pgc_get_rate, +}; + +static unsigned long _clk_usb_get_rate(struct clk *clk) +{ + return 60000000; +} + +/*usb OTG clock */ +static struct clk usb_clk = { + __INIT_CLK_DEBUG(usb_clk) + .get_rate = _clk_usb_get_rate, +}; + +static struct clk usb_utmi_clk = { + __INIT_CLK_DEBUG(usb_utmi_clk) + .enable = _clk_enable, + .enable_reg = MXC_CCM_CSCMR1, + .enable_shift = MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET, + .disable = _clk_disable, +}; + +static struct clk rtc_clk = { + __INIT_CLK_DEBUG(rtc_clk) + .parent = &ckil_clk, + .secondary = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, +}; + +static struct clk ata_clk = { + __INIT_CLK_DEBUG(ata_clk) + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk owire_clk = { + __INIT_CLK_DEBUG(owire_clk) + .parent = &ipg_perclk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, +}; + + +static struct clk fec_clk[] = { + { + __INIT_CLK_DEBUG(fec_clk_0) + .parent = &ipg_clk, + .secondary = &fec_clk[1], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(fec_clk_1) + .parent = &tmax2_clk, + .secondary = &fec_clk[2], + }, + { + __INIT_CLK_DEBUG(fec_clk_2) + .parent = &aips_tz2_clk, + .secondary = &emi_fast_clk, + }, +}; + +static struct clk scc_clk[] = { + { + __INIT_CLK_DEBUG(sahara_clk_0) + .parent = &ahb_clk, + .secondary = &scc_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(sahara_clk_1) + .parent = &tmax1_clk, + .secondary = &scc_clk[2], + }, + { + .parent = &emi_fast_clk, + .secondary = &emi_intr_clk[0], + } +}; + +static struct clk sahara_clk[] = { + { + __INIT_CLK_DEBUG(scc_clk_0) + .parent = &ahb_clk, + .secondary = &sahara_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(scc_clk_1) + .parent = &tmax1_clk, + .secondary = &sahara_clk[2], + }, + { + .parent = &scc_clk, + .secondary = &emi_fast_clk, + } +}; + + +static int _clk_gpu3d_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_GPU_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_GPU_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + + +static struct clk garb_clk = { + __INIT_CLK_DEBUG(garb_clk) + .parent = &axi_a_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, +}; + +static struct clk gpu3d_clk = { + __INIT_CLK_DEBUG(gpu3d_clk) + .parent = &axi_a_clk, + .set_parent = _clk_gpu3d_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + .secondary = &garb_clk, +}; + +static int _clk_gpu2d_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &emi_slow_clk, &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu2d_clk = { + __INIT_CLK_DEBUG(gpu2d_clk) + .parent = &axi_a_clk, + .set_parent = _clk_gpu2d_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long cko1_get_rate(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg = reg >> MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + return clk_get_rate(clk->parent) / (reg + 1); +} + +static int cko1_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg |= MXC_CCM_CCOSR_CKOL_EN; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static void cko1_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_EN; + __raw_writel(reg, MXC_CCM_CCOSR); +} + +static int cko1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = (parent_rate/rate - 1) & 0x7; + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg |= div << MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long cko1_round_rate(struct clk *clk, unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + div = div < 1 ? 1 : div; + div = div > 8 ? 8 : div; + return parent_rate / div; +} + +static int cko1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg; + + if (parent == &cpu_clk) + sel = 0; + else if (parent == &pll1_sw_clk) + sel = 1; + else if (parent == &pll2_sw_clk) + sel = 2; + else if (parent == &pll3_sw_clk) + sel = 3; + else if (parent == &emi_slow_clk) + sel = 4; + else if (parent == &pll4_sw_clk) + sel = 5; + else if (parent == &emi_enfc_clk) + sel = 6; + else if (parent == &ipu_di_clk[0]) + sel = 8; + else if (parent == &ahb_clk) + sel = 11; + else if (parent == &ipg_clk) + sel = 12; + else if (parent == &ipg_perclk) + sel = 13; + else if (parent == &ckil_clk) + sel = 14; + else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_SEL_MASK; + reg |= sel << MXC_CCM_CCOSR_CKOL_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} +static struct clk cko1_clk = { + __INIT_CLK_DEBUG(cko1_clk) + .get_rate = cko1_get_rate, + .enable = cko1_enable, + .disable = cko1_disable, + .set_rate = cko1_set_rate, + .round_rate = cko1_round_rate, + .set_parent = cko1_set_parent, +}; +static int _clk_asrc_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR2); + if (parent == &pll4_sw_clk) + reg |= MXC_CCM_CSCMR2_ASRC_CLK_SEL; + else + reg &= ~MXC_CCM_CSCMR2_ASRC_CLK_SEL; + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_asrc_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_ASRC_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_ASRC_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_ASRC_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_ASRC_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_asrc_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CSCDR2) & + ~(MXC_CCM_CSCDR2_ASRC_CLK_PRED_MASK | + MXC_CCM_CSCDR2_ASRC_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR2_ASRC_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR2_ASRC_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static unsigned long _clk_asrc_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk asrc_clk[] = { + { + __INIT_CLK_DEBUG(asrc_clk_0) + .id = 0, + .parent = &pll4_sw_clk, + .set_parent = _clk_asrc_set_parent, + .get_rate = _clk_asrc_get_rate, + .set_rate = _clk_asrc_set_rate, + .round_rate = _clk_asrc_round_rate, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(asrc_clk_1) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + } + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK(NULL, "osc", osc_clk), + _REGISTER_CLOCK(NULL, "ckih", ckih_clk), + _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk), + _REGISTER_CLOCK(NULL, "ckil", ckil_clk), + _REGISTER_CLOCK(NULL, "pll1_main_clk", pll1_main_clk), + _REGISTER_CLOCK(NULL, "pll1_sw_clk", pll1_sw_clk), + _REGISTER_CLOCK(NULL, "pll2", pll2_sw_clk), + _REGISTER_CLOCK(NULL, "pll3", pll3_sw_clk), + _REGISTER_CLOCK(NULL, "gpc_dvfs_clk", gpc_dvfs_clk), + _REGISTER_CLOCK(NULL, "lp_apm", lp_apm_clk), + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk), + _REGISTER_CLOCK(NULL, "periph_apm_clk", periph_apm_clk), + _REGISTER_CLOCK(NULL, "main_bus_clk", main_bus_clk), + _REGISTER_CLOCK(NULL, "axi_a_clk", axi_a_clk), + _REGISTER_CLOCK(NULL, "axi_b_clk", axi_b_clk), + _REGISTER_CLOCK(NULL, "ahb_clk", ahb_clk), + _REGISTER_CLOCK(NULL, "ahb_max_clk", ahb_max_clk), + _REGISTER_CLOCK(NULL, "vpu_clk", vpu_clk[0]), + _REGISTER_CLOCK(NULL, "vpu_core_clk", vpu_clk[1]), + _REGISTER_CLOCK(NULL, "nfc_clk", emi_enfc_clk), + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk[0]), + _REGISTER_CLOCK(NULL, "ipu1_clk", ipu_clk[0]), + _REGISTER_CLOCK(NULL, "ipu1_di0_clk", ipu_di_clk[0]), + _REGISTER_CLOCK(NULL, "ipu1_di1_clk", ipu_di_clk[1]), + _REGISTER_CLOCK(NULL, "csi_mclk1", csi0_clk), + _REGISTER_CLOCK(NULL, "csi_mclk2", csi1_clk), + _REGISTER_CLOCK(NULL, "tve_clk", tve_clk), + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk[0]), + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk[0]), + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk[0]), + _REGISTER_CLOCK(NULL, "i2c_clk", i2c_clk[0]), + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk[1]), + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk[0]), + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk[0]), + _REGISTER_CLOCK(NULL, "ssi_lp_apm_clk", ssi_lp_apm_clk), + _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk[0]), + _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk[0]), + _REGISTER_CLOCK("imx-ssi.2", NULL, ssi3_clk[0]), + _REGISTER_CLOCK(NULL, "ssi_ext1_clk", ssi_ext1_clk), + _REGISTER_CLOCK(NULL, "ssi_ext2_clk", ssi_ext2_clk), + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), + _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk[0]), + _REGISTER_CLOCK(NULL, "usb_ahb_clk", usb_ahb_clk), + _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy_clk[0]), + _REGISTER_CLOCK(NULL, "usb_utmi_clk", usb_utmi_clk), + _REGISTER_CLOCK(NULL, "usb_clk", usb_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk[0]), + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk[0]), + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk[0]), + _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk[0]), + _REGISTER_CLOCK(NULL, "emi_slow_clk", emi_slow_clk), + _REGISTER_CLOCK(NULL, "ddr_clk", ddr_clk), + _REGISTER_CLOCK(NULL, "emi_enfc_clk", emi_enfc_clk), + _REGISTER_CLOCK(NULL, "emi_fast_clk", emi_fast_clk), + _REGISTER_CLOCK(NULL, "emi_intr_clk.0", emi_intr_clk[0]), + _REGISTER_CLOCK(NULL, "emi_intr_clk.1", emi_intr_clk[1]), + _REGISTER_CLOCK(NULL, "spdif_xtal_clk", spdif_xtal_clk), + _REGISTER_CLOCK("mxc_spdif.0", NULL, spdif0_clk[0]), + _REGISTER_CLOCK("mxc_vpu.0", NULL, vpu_clk[0]), + _REGISTER_CLOCK(NULL, "lpsr_clk", lpsr_clk), + _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk), + _REGISTER_CLOCK("pata_fsl", NULL, ata_clk), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), + _REGISTER_CLOCK(NULL, "sahara_clk", sahara_clk[0]), + _REGISTER_CLOCK(NULL, "gpu3d_clk", gpu3d_clk), + _REGISTER_CLOCK(NULL, "garb_clk", garb_clk), + _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_clk), + _REGISTER_CLOCK("mxc_scc.0", NULL, scc_clk[0]), + _REGISTER_CLOCK(NULL, "cko1", cko1_clk), + _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]), + _REGISTER_CLOCK("fec.0", NULL, fec_clk[0]), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), +}; + +static struct clk_lookup mx51_lookups[] = { + _REGISTER_CLOCK("mxc_i2c_hs.3", NULL, hsi2c_serial_clk), + _REGISTER_CLOCK("mxc_sim.0", NULL, sim_clk[0]), + _REGISTER_CLOCK("mxc_spdif.0", NULL, spdif1_clk[0]), + _REGISTER_CLOCK(NULL, "mipi_hsp_clk", mipi_hsp_clk), + _REGISTER_CLOCK(NULL, "ddr_hf_clk", ddr_hf_clk), + _REGISTER_CLOCK("imx51-ecspi.0", NULL, cspi1_clk[0]), + _REGISTER_CLOCK("imx51-ecspi.1", NULL, cspi2_clk[0]), + _REGISTER_CLOCK("imx51-cspi.0", NULL, cspi3_clk), +}; + +static struct clk_lookup mx53_lookups[] = { + _REGISTER_CLOCK(NULL, "pll4", pll4_sw_clk), + _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk[0]), + _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk[0]), + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk[2]), + _REGISTER_CLOCK(NULL, "usb_phy2_clk", usb_phy_clk[1]), + _REGISTER_CLOCK(NULL, "ocram_clk", ocram_clk), + _REGISTER_CLOCK(NULL, "imx_sata_clk", sata_clk), + _REGISTER_CLOCK(NULL, "ieee_1588_clk", ieee_1588_clk), + _REGISTER_CLOCK(NULL, "ieee_rtc_clk", ieee_rtc_clk), + _REGISTER_CLOCK("mxc_mlb.0", NULL, mlb_clk[0]), + _REGISTER_CLOCK("FlexCAN.0", "can_clk", can1_clk[0]), + _REGISTER_CLOCK("FlexCAN.1", "can_clk", can2_clk[0]), + _REGISTER_CLOCK(NULL, "ldb_di0_clk", ldb_di_clk[0]), + _REGISTER_CLOCK(NULL, "ldb_di1_clk", ldb_di_clk[1]), + _REGISTER_CLOCK(NULL, "esai_clk", esai_clk[0]), + _REGISTER_CLOCK(NULL, "esai_ipg_clk", esai_clk[1]), + _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk[1]), + _REGISTER_CLOCK(NULL, "asrc_serial_clk", asrc_clk[0]), + _REGISTER_CLOCK("imx53-ecspi.0", NULL, cspi1_clk[0]), + _REGISTER_CLOCK("imx53-ecspi.1", NULL, cspi2_clk[0]), + _REGISTER_CLOCK("imx53-cspi.0", NULL, cspi3_clk), +}; + +static void clk_tree_init(void) +{ + u32 reg, dp_ctl; + + ipg_perclk.set_parent(&ipg_perclk, &lp_apm_clk); + + /* + *Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at + * 8MHz, its derived from lp_apm. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + /* set pll1_main_clk parent */ + pll1_main_clk.parent = &osc_clk; + + /* set pll2_sw_clk parent */ + pll2_sw_clk.parent = &osc_clk; + + /* set pll3_clk parent */ + pll3_sw_clk.parent = &osc_clk; + + if (cpu_is_mx51()) { + dp_ctl = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll1_main_clk.parent = &fpm_clk; + + dp_ctl = __raw_readl(pll2_base + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll2_sw_clk.parent = &fpm_clk; + + dp_ctl = __raw_readl(pll3_base + MXC_PLL_DP_CTL); + if ((dp_ctl & MXC_PLL_DP_CTL_REF_CLK_SEL_MASK) == 0) + pll3_sw_clk.parent = &fpm_clk; + } else { + /* set pll4_clk parent */ + pll4_sw_clk.parent = &osc_clk; + } + + /* set emi_slow_clk parent */ + emi_slow_clk.parent = &main_bus_clk; + reg = __raw_readl(MXC_CCM_CBCDR); + if ((reg & MXC_CCM_CBCDR_EMI_CLK_SEL) != 0) + emi_slow_clk.parent = &ahb_clk; + + /* set ipg_perclk parent */ + ipg_perclk.parent = &lp_apm_clk; + reg = __raw_readl(MXC_CCM_CBCMR); + if ((reg & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL) != 0) { + ipg_perclk.parent = &ipg_clk; + } else { + if ((reg & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL) == 0) + ipg_perclk.parent = &main_bus_clk; + } +} + + +int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2) +{ + __iomem void *base; + struct clk *tclk; + int i = 0, j = 0, reg; + int op_cnt = 0; + u32 pll1_rate; + + pll1_base = MX51_DPLL1_BASE; + pll2_base = MX51_DPLL2_BASE; + pll3_base = MX51_DPLL3_BASE; + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 1 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } + __raw_writel(0, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(1 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR4); + + __raw_writel(1 << MXC_CCM_CCGRx_CG2_OFFSET | + 1 << MXC_CCM_CCGR5_CG6_1_OFFSET | + 1 << MXC_CCM_CCGR5_CG6_2_OFFSET | + 3 << MXC_CCM_CCGRx_CG7_OFFSET | + 1 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG10_OFFSET | + 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(1 << MXC_CCM_CCGRx_CG4_OFFSET, MXC_CCM_CCGR6); + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + /* Fix up clocks unique to MX51. */ + esdhc2_clk[0].get_rate = _clk_esdhc2_get_rate; + esdhc2_clk[0].set_rate = _clk_esdhc2_set_rate; + + clk_tree_init(); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + clk_debug_register(lookups[i].clk); + } + + for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++) { + clkdev_add(&mx51_lookups[i]); + clk_debug_register(mx51_lookups[i].clk); + } + + max_axi_a_clk = MAX_AXI_A_CLK_MX51; + max_axi_b_clk = MAX_AXI_B_CLK_MX51; + max_ahb_clk = MAX_AHB_CLK_MX51; + max_emi_slow_clk = MAX_AHB_CLK_MX51; + + /* set DDR clock parent */ + reg = 0; + if (mx51_revision() >= IMX_CHIP_REVISION_2_0) { + reg = __raw_readl(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_DDR_HF_SEL; + reg >>= MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET; + + if (reg) + tclk = &ddr_hf_clk; + } + if (reg == 0) { + reg = __raw_readl(MXC_CCM_CBCMR) & + MXC_CCM_CBCMR_DDR_CLK_SEL_MASK; + reg >>= MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET; + + if (reg == 0) { + tclk = &axi_a_clk; + } else if (reg == 1) { + tclk = &axi_b_clk; + } else if (reg == 2) { + tclk = &emi_slow_clk; + } else { + tclk = &ahb_clk; + } + } + clk_set_parent(&ddr_clk, tclk); + + /*Setup the LPM bypass bits */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS + | MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX51 + | MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51; + __raw_writel(reg, MXC_CCM_CLPCR); + + /* Disable the handshake with HSC block as its not + * initialised right now. + */ + reg = __raw_readl(MXC_CCM_CCDR); + reg |= MXC_CCM_CCDR_HSC_HS_MASK; + __raw_writel(reg, MXC_CCM_CCDR); + + clk_enable(&cpu_clk); + + /* Set SDHC parents to be PLL2 */ + clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk); + clk_set_parent(&esdhc2_clk[0], &pll2_sw_clk); + + /* set SDHC root clock as 166.25MHZ*/ + clk_set_rate(&esdhc1_clk[0], 166250000); + clk_set_rate(&esdhc2_clk[0], 166250000); + + /* Initialise the parents to be axi_b, parents are set to + * axi_a when the clocks are enabled. + */ + clk_set_parent(&vpu_clk[0], &axi_a_clk); + clk_set_parent(&vpu_clk[1], &axi_a_clk); + clk_set_parent(&gpu3d_clk, &axi_a_clk); + clk_set_parent(&gpu2d_clk, &axi_a_clk); + + /* move cspi to 24MHz */ + clk_set_parent(&cspi_main_clk, &lp_apm_clk); + clk_set_rate(&cspi_main_clk, 12000000); + /*move the spdif0 to spdif_xtal_ckl */ + clk_set_parent(&spdif0_clk[0], &spdif_xtal_clk); + /*set the SPDIF dividers to 1 */ + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK; + reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK; + __raw_writel(reg, MXC_CCM_CDCDR); + + /* move the spdif1 to 24MHz */ + clk_set_parent(&spdif1_clk[0], &spdif_xtal_clk); + /* set the spdif1 dividers to 1 */ + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK; + reg &= ~MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK; + __raw_writel(reg, MXC_CCM_CDCDR); + + /* Move SSI clocks to SSI_LP_APM clock */ + clk_set_parent(&ssi_lp_apm_clk, &lp_apm_clk); + + clk_set_parent(&ssi1_clk[0], &ssi_lp_apm_clk); + /* set the SSI dividers to divide by 2 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + clk_set_parent(&ssi2_clk[0], &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS2CDR); + + /* + * SSI3 has no clock divide register, + * we always set SSI3 parent clock to SSI1 and freq same to SSI1 + */ + clk_set_parent(&ssi3_clk[0], &ssi1_clk[0]); + + /* Change the SSI_EXT1_CLK to be sourced from SSI1_CLK_ROOT */ + clk_set_parent(&ssi_ext1_clk, &ssi1_clk[0]); + clk_set_parent(&ssi_ext2_clk, &ssi2_clk[0]); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy_clk[0], &osc_clk); + + /* set usboh3_clk to pll2 */ + clk_set_parent(&usboh3_clk[0], &pll2_sw_clk); + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK; + reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET; + reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + mx51_cpu_op_init(); + /* Set the current working point. */ + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + /* Update the cpu working point table based on the PLL1 freq + * at boot time + */ + pll1_rate = clk_get_rate(&pll1_main_clk); + if (pll1_rate <= cpu_op_tbl[cpu_op_nr - 1].cpu_rate) + op_cnt = 1; + else if (pll1_rate <= cpu_op_tbl[1].cpu_rate && + pll1_rate > cpu_op_tbl[2].cpu_rate) + op_cnt = cpu_op_nr - 1; + else + op_cnt = cpu_op_nr; + + cpu_op_tbl[0].cpu_rate = pll1_rate; + + if (op_cnt == 1) { + cpu_op_tbl[0] = cpu_op_tbl[cpu_op_nr - 1]; + memset(&cpu_op_tbl[cpu_op_nr - 1], 0, sizeof(struct cpu_op)); + memset(&cpu_op_tbl[cpu_op_nr - 2], 0, sizeof(struct cpu_op)); + } else if (op_cnt < cpu_op_nr) { + for (i = 0; i < op_cnt; i++) + cpu_op_tbl[i] = cpu_op_tbl[i+1]; + memset(&cpu_op_tbl[i], 0, sizeof(struct cpu_op)); + } + + if (op_cnt < cpu_op_nr) { + set_num_cpu_op(op_cnt); + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + } + + pll1_rate = clk_get_rate(&pll1_main_clk); + for (j = 0; j < cpu_op_nr; j++) { + if ((ddr_clk.parent == &ddr_hf_clk)) { + /* Change the CPU podf divider based on the boot up + * pll1 rate. + */ + cpu_op_tbl[j].cpu_podf = + (pll1_rate / cpu_op_tbl[j].cpu_rate) + - 1; + if (pll1_rate / (cpu_op_tbl[j].cpu_podf + 1) > + cpu_op_tbl[j].cpu_rate) { + cpu_op_tbl[j].cpu_podf++; + cpu_op_tbl[j].cpu_rate = + pll1_rate / + (1000 * (cpu_op_tbl[j].cpu_podf + 1)); + cpu_op_tbl[j].cpu_rate *= 1000; + } + if (pll1_rate / (cpu_op_tbl[j].cpu_podf + 1) < + cpu_op_tbl[j].cpu_rate) { + cpu_op_tbl[j].cpu_rate = pll1_rate; + } + } + cpu_op_tbl[j].pll_rate = pll1_rate; + } + /* Set the current working point. */ + for (i = 0; i < cpu_op_nr; i++) { + if (clk_get_rate(&cpu_clk) == cpu_op_tbl[i].cpu_rate) { + cpu_curr_op = i; + break; + } + } + if (i > cpu_op_nr) + BUG(); + + clk_set_parent(&arm_axi_clk, &axi_a_clk); + clk_set_parent(&ipu_clk[0], &axi_b_clk); + + if (uart_at_24) { + /* Move UART to run from lp_apm */ + clk_set_parent(&uart_main_clk, &lp_apm_clk); + + /* Set the UART dividers to divide, so the UART_CLK is 24MHz. */ + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; + reg |= (0 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | + (0 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CSCDR1); + } else { + clk_set_parent(&uart_main_clk, &pll2_sw_clk); + + /* Set the UART dividers to divide, so the UART_CLK is 66.5MHz. */ + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_UART_CLK_PRED_MASK; + reg |= (4 << MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) | + (1 << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + __raw_writel(reg, MXC_CCM_CSCDR1); + } + + clk_set_parent(&emi_slow_clk, &ahb_clk); + clk_set_rate(&emi_slow_clk, clk_round_rate(&emi_slow_clk, 130000000)); + + /* Change the NFC clock rate to be 1:4 ratio with emi clock. */ + clk_set_rate(&emi_enfc_clk, clk_round_rate(&emi_enfc_clk, + (clk_get_rate(&emi_slow_clk))/4)); + + /* System timer */ + mxc_timer_init(&gpt_clk[0], MX51_IO_ADDRESS(MX51_GPT1_BASE_ADDR), + MX51_MXC_INT_GPT); + + return 0; +} + +int __init mx53_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1, unsigned long ckih2) +{ + __iomem void *base; + struct clk *tclk; + int i = 0, j = 0, reg; + u32 pll1_rate; + + pll1_base = MX53_DPLL1_BASE; + pll2_base = MX53_DPLL2_BASE; + pll3_base = MX53_DPLL3_BASE; + pll4_base = MX53_DPLL4_BASE; + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 1 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 1 << MXC_CCM_CCGRx_CG1_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } + + __raw_writel(0, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(1 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR4); + + __raw_writel(1 << MXC_CCM_CCGRx_CG2_OFFSET | + 1 << MXC_CCM_CCGRx_CG6_OFFSET | + 3 << MXC_CCM_CCGRx_CG7_OFFSET | + 1 << MXC_CCM_CCGRx_CG8_OFFSET | + 1 << MXC_CCM_CCGRx_CG9_OFFSET | + 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 1 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG12_OFFSET | + 3 << MXC_CCM_CCGRx_CG13_OFFSET , MXC_CCM_CCGR6); + + __raw_writel(0, MXC_CCM_CCGR7); + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + usb_phy_clk[0].enable_reg = MXC_CCM_CCGR4; + usb_phy_clk[0].enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + + ipumux1_clk.enable_reg = MXC_CCM_CCGR5; + ipumux1_clk.enable_shift = MXC_CCM_CCGRx_CG6_OFFSET; + ipumux2_clk.enable_reg = MXC_CCM_CCGR6; + ipumux2_clk.enable_shift = MXC_CCM_CCGRx_CG0_OFFSET; + + esdhc3_clk[0].get_rate = _clk_esdhc3_get_rate; + esdhc3_clk[0].set_rate = _clk_sdhc3_set_rate; + + vpu_clk[2].secondary = &emi_intr_clk[0]; + +#if defined(CONFIG_USB_STATIC_IRAM) \ + || defined(CONFIG_USB_STATIC_IRAM_PPH) + usboh3_clk[1].secondary = &emi_intr_clk[1]; +#endif +#ifdef CONFIG_SND_MXC_SOC_IRAM + ssi2_clk[2].secondary = &emi_intr_clk[1]; + ssi1_clk[2].secondary = &emi_intr_clk[1]; +#endif +#ifdef CONFIG_SDMA_IRAM + sdma_clk[1].secondary = &emi_intr_clk[1]; +#endif + + clk_tree_init(); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + clk_debug_register(lookups[i].clk); + } + + for (i = 0; i < ARRAY_SIZE(mx53_lookups); i++) { + clkdev_add(&mx53_lookups[i]); + clk_debug_register(mx53_lookups[i].clk); + } + + clk_set_parent(&esai_clk[0], &ckih_clk); + + ldb_di_clk[0].parent = ldb_di_clk[1].parent = + tve_clk.parent = &pll4_sw_clk; + + max_axi_a_clk = MAX_AXI_A_CLK_MX53; + max_axi_b_clk = MAX_AXI_B_CLK_MX53; + max_ahb_clk = MAX_AHB_CLK_MX53; + max_emi_slow_clk = MAX_AHB_CLK_MX53; + + + /* set DDR clock parent */ + reg = __raw_readl(MXC_CCM_CBCMR) & + MXC_CCM_CBCMR_DDR_CLK_SEL_MASK; + reg >>= MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET; + if (reg == 0) { + tclk = &axi_a_clk; + } else if (reg == 1) { + tclk = &axi_b_clk; + } else if (reg == 2) { + tclk = &emi_slow_clk; + } else { + tclk = &ahb_clk; + } + clk_set_parent(&ddr_clk, tclk); + + clk_set_parent(&esdhc1_clk[2], &tmax2_clk); + clk_set_parent(&esdhc2_clk[0], &esdhc1_clk[0]); + clk_set_parent(&esdhc3_clk[0], &pll2_sw_clk); + +#if 0 + /*Setup the LPM bypass bits */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS + | MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS + | MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +#endif + + clk_enable(&cpu_clk); + + clk_enable(&main_bus_clk); + + /* Set AXI_B_CLK to be 200MHz */ + clk_set_rate(&axi_b_clk, 200000000); + + /* Initialise the parents to be axi_b, parents are set to + * axi_a when the clocks are enabled. + */ + + clk_set_parent(&vpu_clk[0], &axi_b_clk); + clk_set_parent(&vpu_clk[1], &axi_b_clk); + + /* move cspi to 24MHz */ + clk_set_parent(&cspi_main_clk, &lp_apm_clk); + clk_set_rate(&cspi_main_clk, 12000000); + /*move the spdif0 to spdif_xtal_ckl */ + clk_set_parent(&spdif0_clk[0], &spdif_xtal_clk); + /*set the SPDIF dividers to 1 */ + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK; + reg &= ~MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK; + __raw_writel(reg, MXC_CCM_CDCDR); + + /* Move SSI clocks to SSI_LP_APM clock */ + clk_set_parent(&ssi_lp_apm_clk, &lp_apm_clk); + + clk_set_parent(&ssi1_clk[0], &ssi_lp_apm_clk); + /* set the SSI dividers to divide by 2 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + clk_set_parent(&ssi2_clk[0], &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS2CDR); + + /* Change the SSI_EXT1_CLK to be sourced from PLL2 for camera */ + clk_set_parent(&ssi_ext1_clk, &pll2_sw_clk); + clk_set_rate(&ssi_ext1_clk, 24000000); + clk_set_parent(&ssi_ext2_clk, &ssi2_clk[0]); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy_clk[0], &osc_clk); + clk_set_parent(&usb_phy_clk[1], &osc_clk); + + /* set usboh3_clk to pll2 */ + clk_set_parent(&usboh3_clk[0], &pll2_sw_clk); + reg = __raw_readl(MXC_CCM_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK; + reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK; + reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET; + reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + /* set SDHC root clock as 200MHZ*/ + clk_set_rate(&esdhc1_clk[0], 200000000); + clk_set_rate(&esdhc3_clk[0], 200000000); + + /* Set the 1588 RTC input clocks as 108MHZ */ + clk_set_parent(&ieee_rtc_clk, &pll3_sw_clk); + clk_set_rate(&ieee_rtc_clk, 108000000); + + /* The CPU working point should be set according to part number + * information. But part number information is not clear now. + * So update the cpu working point table based on the PLL1 freq + * at boot time + */ + pll1_rate = clk_get_rate(&pll1_main_clk); + + mx53_cpu_op_init(); + if (pll1_rate > 1000000000) + mx53_set_cpu_part_number(IMX53_CEC_1_2G); + else if (pll1_rate > 800000000) + mx53_set_cpu_part_number(IMX53_CEC); + else + mx53_set_cpu_part_number(IMX53_AEC); + + /* Set the current working point. */ + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + for (i = 0; i < cpu_op_nr; i++) { + if (clk_get_rate(&cpu_clk) == cpu_op_tbl[i].cpu_rate) { + cpu_curr_op = i; + break; + } + } + if (i > cpu_op_nr) + BUG(); + + clk_set_parent(&arm_axi_clk, &axi_b_clk); + clk_set_parent(&ipu_clk[0], &axi_b_clk); + clk_set_parent(&gpu3d_clk, &axi_b_clk); + clk_set_parent(&gpu2d_clk, &axi_b_clk); + + clk_set_parent(&emi_slow_clk, &ahb_clk); + clk_set_rate(&emi_slow_clk, clk_round_rate(&emi_slow_clk, 133333333)); + + clk_set_rate(&emi_enfc_clk, clk_round_rate(&emi_enfc_clk, + MAX_NFC_CLK)); + + /* set the freq of asrc_serial_clk */ + clk_set_rate(&asrc_clk[0], clk_round_rate(&asrc_clk[0], + 1190000)); + + /* System timer */ + mxc_timer_init(&gpt_clk[0], MX53_IO_ADDRESS(MX53_GPT1_BASE_ADDR), + MX53_INT_GPT); + return 0; +} + +/*! + * Setup cpu clock based on working point. + * @param op cpu freq working point + * @return 0 on success or error code on failure. + */ +static int cpu_clk_set_op(int op) +{ + struct cpu_op *p; + u32 reg, pll_hfsm; + u32 stat; + + if (op == cpu_curr_op) + return 0; + + p = &cpu_op_tbl[op]; + + /* + * If DDR clock is sourced from PLL1, we cannot drop PLL1 freq. + * Use the ARM_PODF to change the freq of the core, leave the PLL1 + * freq unchanged. Meanwhile, if pll_rate is same, use the ARM_PODF + * to change the freq of core + */ + if ((ddr_clk.parent == &ddr_hf_clk) || + (p->pll_rate == cpu_op_tbl[cpu_curr_op].pll_rate)) { + reg = __raw_readl(MXC_CCM_CACRR); + reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; + reg |= cpu_op_tbl[op].cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CACRR); + cpu_curr_op = op; + } else { + struct timespec nstimeofday; + struct timespec curtime; + + /* Change the ARM clock to requested frequency */ + /* First move the ARM clock to step clock which is running + * at 24MHz. + */ + + /* Change the source of pll1_sw_clk to be the step_clk */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + + /* Stop the PLL */ + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + reg &= ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + + reg = __raw_readl(MXC_CCM_CACRR); + reg = (reg & ~MXC_CCM_CACRR_ARM_PODF_MASK) + | p->cpu_podf; + __raw_writel(reg, MXC_CCM_CACRR); + + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + pll_hfsm = reg & MXC_PLL_DP_CTL_HFSM; + /* PDF and MFI */ + reg = p->pdf | p->mfi << MXC_PLL_DP_OP_MFI_OFFSET; + if (pll_hfsm == 0) { + __raw_writel(reg, pll1_base + MXC_PLL_DP_OP); + __raw_writel(p->mfd, pll1_base + MXC_PLL_DP_MFD); + __raw_writel(p->mfn, pll1_base + MXC_PLL_DP_MFN); + } else { + __raw_writel(reg, pll1_base + MXC_PLL_DP_HFS_OP); + __raw_writel(p->mfd, pll1_base + MXC_PLL_DP_HFS_MFD); + __raw_writel(p->mfn, pll1_base + MXC_PLL_DP_HFS_MFN); + } + + reg = __raw_readl(pll1_base + MXC_PLL_DP_CTL); + reg |= MXC_PLL_DP_CTL_UPEN; + /* Set the UPEN bits */ + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + /* Forcefully restart the PLL */ + reg |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg, pll1_base + MXC_PLL_DP_CTL); + + /* Wait for the PLL to lock */ + getnstimeofday(&nstimeofday); + do { + getnstimeofday(&curtime); + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > SPIN_DELAY) + panic("pll1 relock failed\n"); + stat = __raw_readl(pll1_base + MXC_PLL_DP_CTL) & + MXC_PLL_DP_CTL_LRF; + } while (!stat); + + reg = __raw_readl(MXC_CCM_CCSR); + /* Move the PLL1 back to the pll1_main_clk */ + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + + cpu_curr_op = op; + } + +#if defined(CONFIG_CPU_FREQ) + cpufreq_trig_needed = 1; +#endif + return 0; +} diff --git a/arch/arm/mach-mx5/clock_mx50.c b/arch/arm/mach-mx5/clock_mx50.c new file mode 100755 index 00000000..4d2c2b9b --- /dev/null +++ b/arch/arm/mach-mx5/clock_mx50.c @@ -0,0 +1,3608 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/time.h> +#include <linux/hrtimer.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/sdram_autogating.h> + +#include "crm_regs.h" +#include "cpu_op-mx50.h" + +/* External clock values passed-in by the board code */ +static unsigned long external_high_reference, external_low_reference; +static unsigned long oscillator_reference, ckih2_reference; + +static struct clk pll1_main_clk; +static struct clk pll1_sw_clk; +static struct clk pll2_sw_clk; +static struct clk pll3_sw_clk; +static struct clk apbh_dma_clk; +static struct clk apll_clk; +static struct clk pfd0_clk; +static struct clk pfd1_clk; +static struct clk pfd2_clk; +static struct clk pfd3_clk; +static struct clk pfd4_clk; +static struct clk pfd5_clk; +static struct clk pfd6_clk; +static struct clk pfd7_clk; +static struct clk lp_apm_clk; +static struct clk weim_clk[]; +static struct clk ddr_clk; +static struct clk axi_a_clk; +static struct clk axi_b_clk; +static struct clk gpu2d_clk; +static int cpu_curr_op; +static struct cpu_op *cpu_op_tbl; + +static void __iomem *pll1_base; +static void __iomem *pll2_base; +static void __iomem *pll3_base; +void __iomem *apll_base; + +static int cpu_op_nr; +extern int lp_high_freq; +extern int lp_med_freq; + +void __iomem *databahn; + +#define UART1_DMA_ENABLE 0 +#define UART2_DMA_ENABLE 0 +#define UART3_DMA_ENABLE 0 +#define UART4_DMA_ENABLE 0 +#define UART5_DMA_ENABLE 0 + +#define DDR_SYNC_MODE 0x30000 +#define SPIN_DELAY 1000000 /* in nanoseconds */ +#define WAIT(exp, timeout) \ +({ \ + struct timespec nstimeofday; \ + struct timespec curtime; \ + int result = 1; \ + getnstimeofday(&nstimeofday); \ + while (!(exp)) { \ + getnstimeofday(&curtime); \ + if ((curtime.tv_nsec - nstimeofday.tv_nsec) > (timeout)) { \ + result = 0; \ + break; \ + } \ + } \ + result; \ +}) + +#define MAX_AXI_A_CLK_MX50 400000000 +#define MAX_AXI_B_CLK_MX50 200000000 +#define MAX_AHB_CLK 133333333 +#define MAX_EMI_SLOW_CLK 133000000 + +#ifdef CONFIG_CLK_DEBUG +#define __INIT_CLK_DEBUG(n) .name = #n, +#else +#define __INIT_CLK_DEBUG(n) +#endif + +extern int mxc_jtag_enabled; +extern int uart_at_24; +extern int cpufreq_trig_needed; +extern int low_bus_freq_mode; +extern int med_bus_freq_mode; + +static int cpu_clk_set_op(int wp); +extern struct cpu_op *(*get_cpu_op)(int *op); +extern void (*set_num_cpu_op)(int num); + +static struct clk esdhc3_clk[]; + +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + if (div >= 512) { + *pre = 8; + *post = 64; + } else if (div >= 8) { + min_pre = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = (div + *pre - 1) / *pre; + } else if (div < 8) { + *pre = div; + *post = 1; + } +} + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg |= MXC_CCM_CCGRx_CG_MASK << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq++; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq++; + + return 0; +} + +static int _clk_enable_inrun(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); + + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq--; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq--; +} + +static void _clk_disable_inwait(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(MXC_CCM_CCGRx_CG_MASK << clk->enable_shift); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); +} + +static unsigned long _clk_round_rate_div(struct clk *clk, + unsigned long rate, + u32 max_div, + u32 *new_div) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = DIV_ROUND_UP(parent_rate, rate); + if (div > max_div) + div = max_div; + else if (div == 0) + div++; + if (new_div != NULL) + *new_div = div; + + return parent_rate / div; +} +/* + * For the 4-to-1 muxed input clock + */ +static inline u32 _get_mux(struct clk *parent, struct clk *m0, + struct clk *m1, struct clk *m2, struct clk *m3) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else + BUG(); + + return 0; +} + +/* + * For the 4-to-1 muxed input clock + */ +static inline u32 _get_mux8(struct clk *parent, struct clk *m0, struct clk *m1, + struct clk *m2, struct clk *m3, struct clk *m4, + struct clk *m5, struct clk *m6, struct clk *m7) +{ + if (parent == m0) + return 0; + else if (parent == m1) + return 1; + else if (parent == m2) + return 2; + else if (parent == m3) + return 3; + else if (parent == m4) + return 4; + else if (parent == m5) + return 5; + else if (parent == m6) + return 6; + else if (parent == m7) + return 7; + else + BUG(); + + return 0; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_main_clk) + return pll1_base; + else if (pll == &pll2_sw_clk) + return pll2_base; + else if (pll == &pll3_sw_clk) + return pll3_base; + else + BUG(); + + return NULL; +} + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +static unsigned long get_oscillator_reference_clock_rate(struct clk *clk) +{ + return oscillator_reference; +} + +static unsigned long get_ckih2_reference_clock_rate(struct clk *clk) +{ + return ckih2_reference; +} + +/* External high frequency clock */ +static struct clk ckih_clk = { + __INIT_CLK_DEBUG(ckih_clk) + .get_rate = get_high_reference_clock_rate, +}; + +static struct clk ckih2_clk = { + __INIT_CLK_DEBUG(ckih2_clk) + .get_rate = get_ckih2_reference_clock_rate, +}; + +static struct clk osc_clk = { + __INIT_CLK_DEBUG(osc_clk) + .get_rate = get_oscillator_reference_clock_rate, +}; + +/* External low frequency (32kHz) clock */ +static struct clk ckil_clk = { + __INIT_CLK_DEBUG(ckil_clk) + .get_rate = get_low_reference_clock_rate, +}; + +static int apll_enable(struct clk *clk) +{ + /* Set bit to flush multiple edges out of PLL vco */ + __raw_writel(MXC_ANADIG_PLL_HOLD_RING_OFF, + apll_base + MXC_ANADIG_MISC_SET); + + __raw_writel(MXC_ANADIG_PLL_POWERUP, apll_base + MXC_ANADIG_MISC_SET); + + if (!WAIT(__raw_readl(apll_base + MXC_ANADIG_PLLCTRL) + & MXC_ANADIG_APLL_LOCK, 80000)) + panic("apll_enable failed!\n"); + + /* Clear after relocking, then wait 10 us */ + __raw_writel(MXC_ANADIG_PLL_HOLD_RING_OFF, + apll_base + MXC_ANADIG_MISC_CLR); + + udelay(10); + + return 0; +} + +static void apll_disable(struct clk *clk) +{ + __raw_writel(MXC_ANADIG_PLL_POWERUP, apll_base + MXC_ANADIG_MISC_CLR); +} + +static unsigned long apll_get_rate(struct clk *clk) +{ + return 480000000; +} + +static struct clk apll_clk = { + __INIT_CLK_DEBUG(apll_clk) + .get_rate = apll_get_rate, + .enable = apll_enable, + .disable = apll_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + tmp = (u64)clk_get_rate(clk->parent) * 18; + do_div(tmp, rate); + frac = tmp; + frac = frac < 18 ? 18 : frac; + frac = frac > 35 ? 35 : frac; + do_div(tmp, frac); + return tmp; +} + +static int pfd_set_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + tmp = (u64)clk_get_rate(clk->parent) * 18; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + do_div(tmp, rate); + frac = tmp; + frac = frac < 18 ? 18 : frac; + frac = frac > 35 ? 35 : frac; + /* clear clk frac bits */ + __raw_writel(MXC_ANADIG_PFD_FRAC_MASK << clk->enable_shift, + apll_base + (int)clk->enable_reg + 8); + /* set clk frac bits */ + __raw_writel(frac << clk->enable_shift, + apll_base + (int)clk->enable_reg + 4); + + tmp = (u64)clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + return 0; +} + +static int pfd_enable(struct clk *clk) +{ + int index; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + index = _get_mux8(clk, &pfd0_clk, &pfd1_clk, &pfd2_clk, &pfd3_clk, + &pfd4_clk, &pfd5_clk, &pfd6_clk, &pfd7_clk); + /* clear clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + apll_base + (int)clk->enable_reg + 8); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + return 0; +} + +static void pfd_disable(struct clk *clk) +{ + int index; + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + index = _get_mux8(clk, &pfd0_clk, &pfd1_clk, &pfd2_clk, &pfd3_clk, + &pfd4_clk, &pfd5_clk, &pfd6_clk, &pfd7_clk); + /* set clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + apll_base + (int)clk->enable_reg + 4); + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); +} + +static struct clk pfd0_clk = { + __INIT_CLK_DEBUG(pfd0_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD0_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd1_clk = { + __INIT_CLK_DEBUG(pfd1_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD1_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd2_clk = { + __INIT_CLK_DEBUG(pfd2_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD2_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd3_clk = { + __INIT_CLK_DEBUG(pfd3_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC0, + .enable_shift = MXC_ANADIG_PFD3_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd4_clk = { + __INIT_CLK_DEBUG(pfd4_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD4_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd5_clk = { + __INIT_CLK_DEBUG(pfd5_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD5_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd6_clk = { + __INIT_CLK_DEBUG(pfd6_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD6_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk pfd7_clk = { + __INIT_CLK_DEBUG(pfd7_clk) + .parent = &apll_clk, + .enable_reg = (void *)MXC_ANADIG_FRAC1, + .enable_shift = MXC_ANADIG_PFD7_FRAC_OFFSET, + .set_rate = pfd_set_rate, + .round_rate = pfd_round_rate, + .enable = pfd_enable, + .disable = pfd_disable, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_pll_get_rate(struct clk *clk) +{ + long mfi, mfn, mfd, pdf, ref_clk, mfn_abs; + unsigned long dp_op, dp_mfd, dp_mfn, dp_ctl, pll_hfsm, dbl; + void __iomem *pllbase; + s64 temp; + + pllbase = _get_pll_base(clk); + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN; + + if (pll_hfsm == 0) { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN); + } else { + dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP); + dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD); + dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN); + } + pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK; + mfi = (dp_op & MXC_PLL_DP_OP_MFI_MASK) >> MXC_PLL_DP_OP_MFI_OFFSET; + mfi = (mfi <= 5) ? 5 : mfi; + mfd = dp_mfd & MXC_PLL_DP_MFD_MASK; + mfn = mfn_abs = dp_mfn & MXC_PLL_DP_MFN_MASK; + /* Sign extend to 32-bits */ + if (mfn >= 0x04000000) { + mfn |= 0xFC000000; + mfn_abs = -mfn; + } + + ref_clk = 2 * clk_get_rate(clk->parent); + if (dbl != 0) + ref_clk *= 2; + + ref_clk /= (pdf + 1); + temp = (u64) ref_clk * mfn_abs; + do_div(temp, mfd + 1); + if (mfn < 0) + temp = -temp; + temp = (ref_clk * mfi) + temp; + + return temp; +} + +static int _clk_pll_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, reg1; + void __iomem *pllbase; + + long mfi, pdf, mfn, mfd = 999999; + s64 temp64; + unsigned long quad_parent_rate; + unsigned long pll_hfsm, dp_ctl; + + pllbase = _get_pll_base(clk); + + quad_parent_rate = 4 * clk_get_rate(clk->parent); + pdf = mfi = -1; + while (++pdf < 16 && mfi < 5) + mfi = rate * (pdf+1) / quad_parent_rate; + if (mfi > 15) + return -1; + pdf--; + + temp64 = rate*(pdf+1) - quad_parent_rate*mfi; + do_div(temp64, quad_parent_rate/1000000); + mfn = (long)temp64; + + dp_ctl = __raw_readl(pllbase + MXC_PLL_DP_CTL); + /* use dpdck0_2 */ + __raw_writel(dp_ctl | 0x1000L, pllbase + MXC_PLL_DP_CTL); + pll_hfsm = dp_ctl & MXC_PLL_DP_CTL_HFSM; + if (pll_hfsm == 0) { + reg = mfi<<4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_MFN); + } else { + reg = mfi<<4 | pdf; + __raw_writel(reg, pllbase + MXC_PLL_DP_HFS_OP); + __raw_writel(mfd, pllbase + MXC_PLL_DP_HFS_MFD); + __raw_writel(mfn, pllbase + MXC_PLL_DP_HFS_MFN); + } + /* If auto restart is disabled, restart the PLL and + * wait for it to lock. + */ + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + if (reg & MXC_PLL_DP_CTL_UPEN) { + reg = __raw_readl(pllbase + MXC_PLL_DP_CONFIG); + if (!(reg & MXC_PLL_DP_CONFIG_AREN)) { + reg1 = __raw_readl(pllbase + MXC_PLL_DP_CTL); + reg1 |= MXC_PLL_DP_CTL_RST; + __raw_writel(reg1, pllbase + MXC_PLL_DP_CTL); + } + /* Wait for lock */ + if (!WAIT(__raw_readl(pllbase + MXC_PLL_DP_CTL) + & MXC_PLL_DP_CTL_LRF, SPIN_DELAY)) + panic("pll_set_rate: pll relock failed\n"); + } + return 0; +} + +static int _clk_pll_enable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL); + + if (reg & MXC_PLL_DP_CTL_UPEN) + return 0; + + reg |= MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); + + /* Wait for lock */ + if (!WAIT(__raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_LRF, + SPIN_DELAY)) + panic("pll relock failed\n"); + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + u32 reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + reg = __raw_readl(pllbase + MXC_PLL_DP_CTL) & ~MXC_PLL_DP_CTL_UPEN; + __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); +} + +static struct clk pll1_main_clk = { + __INIT_CLK_DEBUG(pll1_main_clk) + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .set_rate = _clk_pll_set_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .flags = RATE_PROPAGATES, +}; + +static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll1_main_clk) { + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set the step_clk parent to be lp_apm, to save power. */ + mux = _get_mux(&lp_apm_clk, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + } else { + if (parent == &lp_apm_clk) { + mux = _get_mux(parent, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CCSR); + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + } else { + mux = _get_mux(parent, &lp_apm_clk, NULL, &pll2_sw_clk, + &pll3_sw_clk); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL_MASK) | + (mux << MXC_CCM_CCSR_STEP_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CCSR); + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + + } + } + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static unsigned long _clk_pll1_sw_get_rate(struct clk *clk) +{ + u32 reg, div; + div = 1; + reg = __raw_readl(MXC_CCM_CCSR); + + if (clk->parent == &pll2_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL2_PODF_MASK) >> + MXC_CCM_CCSR_PLL2_PODF_OFFSET) + 1; + } else if (clk->parent == &pll3_sw_clk) { + div = ((reg & MXC_CCM_CCSR_PLL3_PODF_MASK) >> + MXC_CCM_CCSR_PLL3_PODF_OFFSET) + 1; + } + return clk_get_rate(clk->parent) / div; +} + +/* pll1 switch clock */ +static struct clk pll1_sw_clk = { + __INIT_CLK_DEBUG(pll1_sw_clk) + .parent = &pll1_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = _clk_pll1_sw_get_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_pll2_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll2_sw_clk) { + reg &= ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } else { + reg = (reg & ~MXC_CCM_CCSR_PLL2_SW_CLK_SEL); + reg |= MXC_CCM_CCSR_PLL2_SW_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CCSR); + return 0; +} + +/* same as pll2_main_clk. These two clocks should always be the same */ +static struct clk pll2_sw_clk = { + __INIT_CLK_DEBUG(pll2_sw_clk) + .parent = &osc_clk, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll_set_rate, + .set_parent = _clk_pll2_sw_set_parent, + .flags = RATE_PROPAGATES, +}; + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_sw_clk = { + __INIT_CLK_DEBUG(pll3_sw_clk) + .parent = &osc_clk, + .set_rate = _clk_pll_set_rate, + .get_rate = _clk_pll_get_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .flags = RATE_PROPAGATES, +}; + +static int _clk_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + if (parent == &osc_clk) + reg = __raw_readl(MXC_CCM_CCSR) & ~MXC_CCM_CCSR_LP_APM_SEL; + else if (parent == &apll_clk) + reg = __raw_readl(MXC_CCM_CCSR) | MXC_CCM_CCSR_LP_APM_SEL; + else + return -EINVAL; + + __raw_writel(reg, MXC_CCM_CCSR); + + return 0; +} + +static struct clk lp_apm_clk = { + __INIT_CLK_DEBUG(lp_apm_clk) + .parent = &osc_clk, + .set_parent = _clk_lp_apm_set_parent, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_arm_get_rate(struct clk *clk) +{ + u32 cacrr, div; + + cacrr = __raw_readl(MXC_CCM_CACRR); + div = (cacrr & MXC_CCM_CACRR_ARM_PODF_MASK) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_cpu_set_rate(struct clk *clk, unsigned long rate) +{ + u32 i; + + for (i = 0; i < cpu_op_nr; i++) { + if (rate == cpu_op_tbl[i].cpu_rate) + break; + } + if (i >= cpu_op_nr) + return -EINVAL; + cpu_clk_set_op(i); + + return 0; +} + +static unsigned long _clk_cpu_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 i; + u32 wp; + + for (i = 0; i < cpu_op_nr; i++) { + if (rate == cpu_op_tbl[i].cpu_rate) + break; + } + + if (i > cpu_op_nr) + wp = 0; + + return cpu_op_tbl[wp].cpu_rate; +} + + +static struct clk cpu_clk = { + __INIT_CLK_DEBUG(cpu_clk) + .parent = &pll1_sw_clk, + .get_rate = _clk_arm_get_rate, + .set_rate = _clk_cpu_set_rate, + .round_rate = _clk_cpu_round_rate, +}; + +/* TODO: Need to sync with GPC to determine if DVFS is in place so that + * the DVFS_PODF divider can be applied in CDCR register. + */ +static unsigned long _clk_main_bus_get_rate(struct clk *clk) +{ + u32 div = 0; + + if (med_bus_freq_mode) + div = (__raw_readl(MXC_CCM_CDCR) & 0x3); + return clk_get_rate(clk->parent) / (div + 1); +} + +static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CBCDR) & ~MX50_CCM_CBCDR_PERIPH_CLK_SEL_MASK; + reg |= (mux << MX50_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + return 0; +} + +static struct clk main_bus_clk = { + __INIT_CLK_DEBUG(main_bus_clk) + .parent = &pll2_sw_clk, + .set_parent = _clk_main_bus_set_parent, + .get_rate = _clk_main_bus_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_axi_a_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_A_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_A_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_a_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_A_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_A_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_AXI_A_PODF_BUSY), SPIN_DELAY)) + panic("pll _clk_axi_a_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_axi_a_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + + if (div > 8) + div = 8; + else if (div == 0) + div++; + + return parent_rate / div; +} + + +static struct clk axi_a_clk = { + __INIT_CLK_DEBUG(axi_a_clk) + .parent = &main_bus_clk, + .get_rate = _clk_axi_a_get_rate, + .set_rate = _clk_axi_a_set_rate, + .round_rate = _clk_axi_a_round_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_axi_b_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AXI_B_PODF_MASK) >> + MXC_CCM_CBCDR_AXI_B_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_axi_b_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AXI_B_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_B_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_AXI_B_PODF_BUSY), SPIN_DELAY)) + panic("_clk_axi_b_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_axi_b_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + + if (div > 8) + div = 8; + else if (div == 0) + div++; + + return parent_rate / div; +} + + +static struct clk axi_b_clk = { + __INIT_CLK_DEBUG(axi_b_clk) + .parent = &main_bus_clk, + .get_rate = _clk_axi_b_get_rate, + .set_rate = _clk_axi_b_set_rate, + .round_rate = _clk_axi_b_round_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ahb_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >> + MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + + +static int _clk_ahb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_AHB_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AHB_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_AHB_PODF_BUSY), + SPIN_DELAY)) + panic("_clk_ahb_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_ahb_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + if (parent_rate / div > MAX_AHB_CLK) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + + +static struct clk ahb_clk = { + __INIT_CLK_DEBUG(ahb_clk) + .parent = &main_bus_clk, + .get_rate = _clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, + .flags = RATE_PROPAGATES, +}; + +static int _clk_max_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with MAX when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + + +static void _clk_max_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable_inwait(clk); + + /* No Handshake with MAX when LPM is entered as its disabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk ahb_max_clk = { + __INIT_CLK_DEBUG(ahb_max_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_max_enable, + .disable = _clk_max_disable, +}; + +static struct clk ahbmux1_clk = { + __INIT_CLK_DEBUG(ahbmux1_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, +}; + +static unsigned long _clk_ipg_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >> + MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static struct clk ipg_clk = { + __INIT_CLK_DEBUG(ipg_clk) + .parent = &ahb_clk, + .get_rate = _clk_ipg_get_rate, + .flags = RATE_PROPAGATES, +}; + +static unsigned long _clk_ipg_per_get_rate(struct clk *clk) +{ + u32 reg, prediv1, prediv2, podf; + + if (clk->parent == &main_bus_clk || clk->parent == &lp_apm_clk) { + /* the main_bus_clk is the one before the DVFS engine */ + reg = __raw_readl(MXC_CCM_CBCDR); + prediv1 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET) + 1; + prediv2 = ((reg & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >> + MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET) + 1; + podf = ((reg & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >> + MXC_CCM_CBCDR_PERCLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / (prediv1 * prediv2 * podf); + } else if (clk->parent == &ipg_clk) { + return clk_get_rate(&ipg_clk); + } + BUG(); + return 0; +} + +static int _clk_ipg_per_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &main_bus_clk, &lp_apm_clk, &ipg_clk, NULL); + if (mux == 2) { + reg |= MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + } else { + reg &= ~MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL; + if (mux == 0) + reg &= ~MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + else + reg |= MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL; + } + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk ipg_perclk = { + __INIT_CLK_DEBUG(ipg_perclk) + .parent = &lp_apm_clk, + .get_rate = _clk_ipg_per_get_rate, + .set_parent = _clk_ipg_per_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk ipmux1_clk = { + __INIT_CLK_DEBUG(ipmux1_clk) + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk ipmux2_clk = { + __INIT_CLK_DEBUG(ipmux2_clk) + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_sys_clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~(MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK | + MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK); + if (__raw_readl(MXC_CCM_CLKSEQ_BYPASS) & 0x1) + reg |= MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK; + else + reg |= MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_CLK_SYS); + return 0; +} + +static void _clk_sys_clk_disable(struct clk *clk) +{ + u32 reg, reg1; + + reg1 = (__raw_readl(databahn + DATABAHN_CTL_REG55)) + & DDR_SYNC_MODE; + reg = __raw_readl(MXC_CCM_CLK_SYS); + reg &= ~(MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK | + MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK); + if (__raw_readl(MXC_CCM_CLKSEQ_BYPASS) & 0x1) + reg |= 1 << MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET; + else { + /* If DDR is sourced from SYS_CLK (in Sync mode), we cannot + * gate its clock when ARM is in wait if the DDR is not in + * self refresh. + */ + if (reg1 == DDR_SYNC_MODE) + reg |= 3 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET; + else + reg |= 1 << MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET; + } + __raw_writel(reg, MXC_CCM_CLK_SYS); +} + +static struct clk sys_clk = { + __INIT_CLK_DEBUG(sys_clk) + .enable = _clk_sys_clk_enable, + .disable = _clk_sys_clk_disable, +}; + + +static int _clk_weim_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CBCDR); + if (parent == &ahb_clk) + reg |= MX50_CCM_CBCDR_WEIM_CLK_SEL; + else if (parent == &main_bus_clk) + reg &= ~MX50_CCM_CBCDR_WEIM_CLK_SEL; + else + BUG(); + __raw_writel(reg, MXC_CCM_CBCDR); + + return 0; +} + +static int _clk_weim_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_EMI_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) & MXC_CCM_CDHIPR_EMI_PODF_BUSY), + SPIN_DELAY)) + panic("_clk_emi_slow_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_weim_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div > 8) + div = 8; + else if (div == 0) + div++; + return parent_rate / div; +} + +static struct clk weim_clk[] = { + { + __INIT_CLK_DEBUG(weim_clk_0) + .parent = &main_bus_clk, + .set_parent = _clk_weim_set_parent, + .set_rate = _clk_weim_set_rate, + .round_rate = _clk_weim_round_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable_inwait, + .flags = RATE_PROPAGATES, + .secondary = &weim_clk[1], + }, + { + __INIT_CLK_DEBUG(weim_clk_1) + .parent = &ipg_clk, + .secondary = &sys_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .disable = _clk_disable_inwait, + } +}; + +static int _clk_ocram_enable(struct clk *clk) +{ + return 0; +} + +static void _clk_ocram_disable(struct clk *clk) +{ +} + +static struct clk ocram_clk = { + __INIT_CLK_DEBUG(ocram_clk) + .parent = &sys_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_ocram_enable, + .disable = _clk_ocram_disable, +}; + +static struct clk aips_tz1_clk = { + __INIT_CLK_DEBUG(aips_tz1_clk) + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz2_clk = { + __INIT_CLK_DEBUG(aips_tz2_clk) + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk gpc_dvfs_clk = { + __INIT_CLK_DEBUG(gpc_dvfs_clk) + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_sdma_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Handshake with SDMA when LPM is entered. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg &= ~MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); + + return 0; +} + +static void _clk_sdma_disable(struct clk *clk) +{ + u32 reg; + + _clk_disable(clk); + /* No handshake with SDMA as its not enabled. */ + reg = __raw_readl(MXC_CCM_CLPCR); + reg |= MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS; + __raw_writel(reg, MXC_CCM_CLPCR); +} + + +static struct clk sdma_clk[] = { + { + __INIT_CLK_DEBUG(sdma_clk_0) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_sdma_enable, + .disable = _clk_sdma_disable, + }, + { + __INIT_CLK_DEBUG(sdma_clk_1) + .parent = &ipg_clk, +#ifdef CONFIG_SDMA_IRAM + .secondary = &ocram_clk, +#else + .secondary = &ddr_clk, +#endif + }, +}; + +static struct clk spba_clk = { + __INIT_CLK_DEBUG(spba_clk) + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_uart_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent)/(prediv * podf) ; +} + +static int _clk_uart_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_UART_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk uart_main_clk = { + __INIT_CLK_DEBUG(uart_main_clk) + .parent = &pll2_sw_clk, + .get_rate = _clk_uart_get_rate, + .set_parent = _clk_uart_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk uart1_clk[] = { + { + __INIT_CLK_DEBUG(uart1_clk_0) + .id = 0, + .parent = &uart_main_clk, + .secondary = &uart1_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART1_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart1_clk_1) + .id = 0, + .parent = &ipg_clk, +#if UART1_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart2_clk[] = { + { + __INIT_CLK_DEBUG(uart2_clk_0) + .id = 1, + .parent = &uart_main_clk, + .secondary = &uart2_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART2_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart2_clk_1) + .id = 1, + .parent = &ipg_clk, +#if UART2_DMA_ENABLE + .secondary = &aips_tz1_clk, +#endif + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart3_clk[] = { + { + __INIT_CLK_DEBUG(uart3_clk_0) + .id = 2, + .parent = &uart_main_clk, + .secondary = &uart3_clk[1], + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART3_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart3_clk_1) + .id = 2, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart4_clk[] = { + { + __INIT_CLK_DEBUG(uart4_clk_0) + .id = 3, + .parent = &uart_main_clk, + .secondary = &uart4_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART4_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart4_clk_1) + .id = 3, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk uart5_clk[] = { + { + __INIT_CLK_DEBUG(uart5_clk_0) + .id = 4, + .parent = &uart_main_clk, + .secondary = &uart5_clk[1], + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +#if UART5_DMA_ENABLE + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#endif + }, + { + __INIT_CLK_DEBUG(uart5_clk_1) + .id = 4, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk gpt_clk[] = { + { + __INIT_CLK_DEBUG(gpt_clk_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(gpt_clk_1) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(gpt_clk_2) + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm1_clk[] = { + { + __INIT_CLK_DEBUG(pwm1_clk_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm1_clk[1], + }, + { + __INIT_CLK_DEBUG(pwm1_clk_1) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm1_clk_2) + .id = 0, + .parent = &ckil_clk, + }, +}; + +static struct clk pwm2_clk[] = { + { + __INIT_CLK_DEBUG(pwm2_clk_0) + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &pwm2_clk[1], + }, + { + __INIT_CLK_DEBUG(pwm2_clk_1) + .id = 1, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm2_clk_2) + .id = 1, + .parent = &ckil_clk, + }, +}; + +static struct clk i2c_clk[] = { + { + __INIT_CLK_DEBUG(i2c_clk_0) + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_1) + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_2) + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_cspi_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR2); + prediv = ((reg & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) >> + MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) >> + MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_cspi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk cspi_main_clk = { + __INIT_CLK_DEBUG(cspi_main_clk) + .parent = &pll3_sw_clk, + .get_rate = _clk_cspi_get_rate, + .set_parent = _clk_cspi_set_parent, + .flags = RATE_PROPAGATES, +}; + +static struct clk cspi1_clk[] = { + { + __INIT_CLK_DEBUG(cspi1_clk_0) + .id = 0, + .parent = &cspi_main_clk, + .secondary = &cspi1_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(cspi1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi2_clk[] = { + { + __INIT_CLK_DEBUG(cspi2_clk_0) + .id = 1, + .parent = &cspi_main_clk, + .secondary = &cspi2_clk[1], + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(cspi2_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &aips_tz2_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable_inrun, /*Active only when ARM is running. */ + .disable = _clk_disable, + }, +}; + +static struct clk cspi3_clk = { + __INIT_CLK_DEBUG(cspi3_clk) + .id = 2, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &aips_tz2_clk, +}; + +static int _clk_ssi_lp_apm_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &ckih_clk, &lp_apm_clk, &ckih2_clk, NULL); + reg = __raw_readl(MXC_CCM_CSCMR1) & + ~MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_lp_apm_clk = { + __INIT_CLK_DEBUG(ssi_lp_apm_clk) + .parent = &ckih_clk, + .set_parent = _clk_ssi_lp_apm_set_parent, +}; + +static unsigned long _clk_ssi1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} +static int _clk_ssi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi1_clk[] = { + { + __INIT_CLK_DEBUG(ssi1_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi1_set_parent, + .secondary = &ssi1_clk[1], + .get_rate = _clk_ssi1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &ssi1_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi1_clk_2) + .id = 0, + .parent = &aips_tz2_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &ocram_clk, +#else + .secondary = &ddr_clk, +#endif + }, +}; + +static unsigned long _clk_ssi2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_ssi2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi2_clk[] = { + { + __INIT_CLK_DEBUG(ssi2_clk_0) + .id = 1, + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi2_set_parent, + .secondary = &ssi2_clk[1], + .get_rate = _clk_ssi2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi2_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &ssi2_clk[2], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ssi2_clk_2) + .id = 1, + .parent = &spba_clk, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &ocram_clk, +#else + .secondary = &ddr_clk, +#endif + }, +}; + +static unsigned long _clk_ssi_ext1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS1CDR); + prediv = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK) >> + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ssi_ext1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 512) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK | + MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static int _clk_ssi_ext1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &ssi1_clk[0]) { + reg |= MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &ssi_lp_apm_clk); + reg = (reg & ~MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_ssi_ext1_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (parent_rate % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk ssi_ext1_clk = { + __INIT_CLK_DEBUG(ssi_ext1_clk) + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext1_set_parent, + .set_rate = _clk_ssi_ext1_set_rate, + .round_rate = _clk_ssi_ext1_round_rate, + .get_rate = _clk_ssi_ext1_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static unsigned long _clk_ssi_ext2_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + u32 div = 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if ((reg & MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL) == 0) { + reg = __raw_readl(MXC_CCM_CS2CDR); + prediv = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_OFFSET) + 1; + if (prediv == 1) + BUG(); + podf = ((reg & MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK) >> + MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET) + 1; + div = prediv * podf; + } + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ssi_ext2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &ssi2_clk[0]) { + reg |= MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL; + } else { + reg &= ~MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL; + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &ssi_lp_apm_clk); + reg = (reg & ~MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_MASK) | + (mux << MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET); + } + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi_ext2_clk = { + __INIT_CLK_DEBUG(ssi_ext2_clk) + .parent = &pll3_sw_clk, + .set_parent = _clk_ssi_ext2_set_parent, + .get_rate = _clk_ssi_ext2_get_rate, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk tmax2_clk = { + __INIT_CLK_DEBUG(tmax2_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &ahb_max_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk usb_ahb_clk = { + __INIT_CLK_DEBUG(usb_ahb_clk) + .parent = &ipg_clk, + .secondary = &ddr_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk usb_phy_clk[] = { + { + __INIT_CLK_DEBUG(usb_phy_clk_0) + .id = 0, + .parent = &osc_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(usb_phy_clk_1) + .id = 1, + .parent = &osc_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk esdhc_dep_clks = { + __INIT_CLK_DEBUG(esdhc_dep_clks) + .parent = &spba_clk, + .secondary = &ddr_clk, +}; + +static unsigned long _clk_esdhc1_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_esdhc1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + mux = _get_mux(parent, &pll1_sw_clk, &pll2_sw_clk, &pll3_sw_clk, + &lp_apm_clk); + reg = reg & ~MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK; + reg |= mux << MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + + +static int _clk_esdhc1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk esdhc1_clk[] = { + { + __INIT_CLK_DEBUG(esdhc1_clk_0) + .id = 0, + .parent = &pll2_sw_clk, + .set_parent = _clk_esdhc1_set_parent, + .get_rate = _clk_esdhc1_get_rate, + .set_rate = _clk_esdhc1_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(esdhc1_clk_1) + .id = 0, + .parent = &ipg_clk, + .secondary = &esdhc1_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc1_clk_2) + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, + +}; + +static int _clk_esdhc2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MX50_CCM_CSCMR1_ESDHC2_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MX50_CCM_CSCMR1_ESDHC2_CLK_SEL; + else + BUG(); + __raw_writel(reg, MXC_CCM_CSCMR1); + return 0; +} + +static struct clk esdhc2_clk[] = { + { + __INIT_CLK_DEBUG(esdhc2_clk_0) + .id = 1, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc2_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(esdhc2_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &esdhc2_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc2_clk_2) + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1); + mux = _get_mux8(parent, &pll1_sw_clk, &pll2_sw_clk, + &pll3_sw_clk, &lp_apm_clk, &pfd0_clk, + &pfd1_clk, &pfd4_clk, &osc_clk); + reg = reg & ~MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK; + reg |= mux << MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_esdhc3_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_CSCDR1); + prediv = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static int _clk_esdhc3_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if ((parent_rate / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set sdhc1 clock divider */ + reg = __raw_readl(MXC_CCM_CSCDR1) & + ~(MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK | + MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + + +static struct clk esdhc3_clk[] = { + { + __INIT_CLK_DEBUG(esdhc3_clk_0) + .id = 2, + .parent = &pll2_sw_clk, + .set_parent = _clk_esdhc3_set_parent, + .get_rate = _clk_esdhc3_get_rate, + .set_rate = _clk_esdhc3_set_rate, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc3_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(esdhc3_clk_1) + .id = 2, + .parent = &ipg_clk, + .secondary = &esdhc3_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc3_clk_2) + .id = 0, + .parent = &ahb_max_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_esdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + if (parent == &esdhc1_clk[0]) + reg &= ~MX50_CCM_CSCMR1_ESDHC4_CLK_SEL; + else if (parent == &esdhc3_clk[0]) + reg |= MX50_CCM_CSCMR1_ESDHC4_CLK_SEL; + else + BUG(); + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk esdhc4_clk[] = { + { + __INIT_CLK_DEBUG(esdhc4_clk_0) + .id = 3, + .parent = &esdhc1_clk[0], + .set_parent = _clk_esdhc4_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc4_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(esdhc4_clk_1) + .id = 3, + .parent = &ipg_clk, + .secondary = &esdhc4_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(esdhc4_clk_2) + .id = 0, + .parent = &tmax2_clk, + .secondary = &esdhc_dep_clks, + }, +}; + +static int _clk_ddr_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CLK_DDR); + if (parent == &pfd0_clk) + reg |= MXC_CCM_CLK_DDR_DDR_PFD_SEL; + else if (parent == &pll1_sw_clk) + reg &= ~MXC_CCM_CLK_DDR_DDR_PFD_SEL; + else + return -EINVAL; + __raw_writel(reg, MXC_CCM_CLK_DDR); + return 0; +} + +static unsigned long _clk_ddr_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CLK_DDR); + div = (reg & MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK) >> + MXC_CCM_CLK_DDR_DDR_DIV_PLL_OFFSET; + if (div) + return clk_get_rate(clk->parent) / div; + + return 0; +} + +static int _clk_ddr_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + reg = (__raw_readl(databahn + DATABAHN_CTL_REG55)) & + DDR_SYNC_MODE; + if (reg != DDR_SYNC_MODE) { + reg = __raw_readl(MXC_CCM_CLK_DDR); + reg |= MXC_CCM_CLK_DDR_DDR_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_CLK_DDR); + } + return 0; +} + +static void _clk_ddr_disable(struct clk *clk) +{ + _clk_disable_inwait(clk); +} + + +static struct clk ddr_clk = { + __INIT_CLK_DEBUG(ddr_clk) + .parent = &pll1_sw_clk, + .secondary = &sys_clk, + .set_parent = _clk_ddr_set_parent, + .get_rate = _clk_ddr_get_rate, + .enable = _clk_ddr_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_ddr_disable, +}; + +static unsigned long _clk_pgc_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = (reg & MXC_CCM_CSCDR1_PGC_CLK_PODF_MASK) >> + MXC_CCM_CSCDR1_PGC_CLK_PODF_OFFSET; + div = 1 >> div; + return clk_get_rate(clk->parent) / div; +} + +static struct clk pgc_clk = { + __INIT_CLK_DEBUG(pgc_clk) + .parent = &ipg_clk, + .get_rate = _clk_pgc_get_rate, +}; + +static unsigned long _clk_usb_get_rate(struct clk *clk) +{ + return 60000000; +} + +/*usb OTG clock */ +static struct clk usb_clk = { + __INIT_CLK_DEBUG(usb_clk) + .get_rate = _clk_usb_get_rate, +}; + +static struct clk rtc_clk = { + __INIT_CLK_DEBUG(rtc_clk) + .parent = &ckil_clk, + .secondary = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, +}; + +struct clk rng_clk = { + __INIT_CLK_DEBUG(rng_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk owire_clk = { + __INIT_CLK_DEBUG(owire_clk) + .parent = &ipg_perclk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, +}; + +static struct clk fec_clk[] = { + { + __INIT_CLK_DEBUG(fec_clk_0) + .parent = &ipg_clk, + .secondary = &fec_clk[1], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(fec_clk_1) + .parent = &aips_tz2_clk, + .secondary = &ddr_clk, + }, +}; + +static int gpmi_clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_GPMI); + reg |= MXC_CCM_GPMI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_GPMI); + _clk_enable(clk); + return 0; +} + +static void gpmi_clk_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_GPMI); + reg &= ~MXC_CCM_GPMI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_GPMI); + _clk_disable(clk); +} + +static int bch_clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_BCH); + reg |= MXC_CCM_BCH_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_BCH); + _clk_enable(clk); + return 0; +} + +static void bch_clk_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_BCH); + reg &= ~MXC_CCM_BCH_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_BCH); + _clk_disable(clk); +} + +static int gpmi_set_parent(struct clk *clk, struct clk *parent) +{ + /* Setting for ONFI nand which need PLL1(800MHZ) */ + if (parent == &pll1_main_clk) { + u32 reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_MASK) | + (0x2 << MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_OFFSET); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_MASK) | + (0x2 << MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + /* change to the new Parent */ + clk->parent = parent; + } else + printk(KERN_WARNING "You should not call the %s\n", __func__); + return 0; +} + +static int gpmi_set_rate(struct clk *clk, unsigned long rate) +{ + /* Setting for ONFI nand which in different mode */ + if (clk->parent == &pll1_main_clk) { + u32 value; + u32 reg; + + value = clk_get_rate(clk->parent); + value /= rate; + value /= 2; /* HW_GPMI_CTRL1's GPMI_CLK_DIV2_EN will be set */ + + /* set GPMI clock */ + reg = __raw_readl(MXC_CCM_GPMI); + reg = (reg & ~MXC_CCM_GPMI_CLK_DIV_MASK) | value; + __raw_writel(reg, MXC_CCM_GPMI); + + /* set BCH clock */ + reg = __raw_readl(MXC_CCM_BCH); + reg = (reg & ~MXC_CCM_BCH_CLK_DIV_MASK) | value; + __raw_writel(reg, MXC_CCM_BCH); + } else + printk(KERN_WARNING "You should not call the %s\n", __func__); + return 0; +} + +static struct clk gpmi_nfc_clk[] = { + { /* gpmi_io_clk */ + __INIT_CLK_DEBUG(gpmi_io_clk) + .parent = &osc_clk, + .secondary = &gpmi_nfc_clk[1], + .set_parent = gpmi_set_parent, + .set_rate = gpmi_set_rate, + .enable = gpmi_clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .disable = gpmi_clk_disable, + }, + { /* gpmi_apb_clk */ + __INIT_CLK_DEBUG(gpmi_apb_clk) + .parent = &apbh_dma_clk, + .secondary = &gpmi_nfc_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .disable = _clk_disable, + }, + { /* bch_clk */ + __INIT_CLK_DEBUG(gpmi_bch_clk) + .parent = &osc_clk, + .secondary = &gpmi_nfc_clk[3], + .enable = bch_clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = bch_clk_disable, + }, + { /* bch_apb_clk */ + __INIT_CLK_DEBUG(gpmi_bch_apb_clk) + .parent = &apbh_dma_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_ocotp_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent); +} + +static struct clk ocotp_clk = { + __INIT_CLK_DEBUG(ocotp_clk) + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + .get_rate = _clk_ocotp_get_rate, +}; + +static int _clk_gpu2d_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CBCMR); + mux = _get_mux(parent, &axi_a_clk, &axi_b_clk, &weim_clk[0], &ahb_clk); + reg = (reg & ~MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK) | + (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu2d_clk = { + __INIT_CLK_DEBUG(gpu2d_clk) + .parent = &axi_a_clk, + .secondary = &ddr_clk, + .set_parent = _clk_gpu2d_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk apbh_dma_clk = { + __INIT_CLK_DEBUG(apbh_dma_clk) + .parent = &ahb_clk, + .secondary = &ddr_clk, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, +}; + +struct clk dcp_clk = { + __INIT_CLK_DEBUG(dcp_clk) + .parent = &ahb_clk, + .secondary = &apbh_dma_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR7, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .disable = _clk_disable, +}; + +static int _clk_display_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd2_clk, &pll1_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_display_axi_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_DISPLAY_AXI); + div &= MXC_CCM_DISPLAY_AXI_DIV_MASK; + if (div == 0) { /* gated off */ + return clk_get_rate(clk->parent); + } else { + return clk_get_rate(clk->parent) / div; + } +} + +static unsigned long _clk_display_axi_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 max_div = (2 << 6) - 1; + return _clk_round_rate_div(clk, rate, max_div, NULL); +} + +static int _clk_display_axi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div, max_div; + u32 reg; + + max_div = (2 << 6) - 1; + _clk_round_rate_div(clk, rate, max_div, &new_div); + + reg = __raw_readl(MXC_CCM_DISPLAY_AXI); + reg &= ~MXC_CCM_DISPLAY_AXI_DIV_MASK; + reg |= new_div << MXC_CCM_DISPLAY_AXI_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_DISPLAY_AXI); + + while (__raw_readl(MXC_CCM_CSR2) & MXC_CCM_CSR2_DISPLAY_AXI_BUSY) + ; + return 0; +} + +static struct clk display_axi_clk = { + __INIT_CLK_DEBUG(display_axi_clk) + .parent = &osc_clk, + .secondary = &apbh_dma_clk, + .set_parent = _clk_display_axi_set_parent, + .get_rate = _clk_display_axi_get_rate, + .set_rate = _clk_display_axi_set_rate, + .round_rate = _clk_display_axi_round_rate, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_DISPLAY_AXI, + .enable_shift = MXC_CCM_DISPLAY_AXI_CLKGATE_OFFSET, + .flags = RATE_PROPAGATES | AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_pxp_axi_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + /* Set the auto-slow bits */ + reg = __raw_readl(MXC_CCM_DISPLAY_AXI); + reg |= (MXC_CCM_DISPLAY_AXI_PXP_ASM_EN); + reg |= (5 << MXC_CCM_DISPLAY_AXI_PXP_ASM_DIV_OFFSET); + __raw_writel(reg, MXC_CCM_DISPLAY_AXI); + + return 0; +} + +static void _clk_pxp_axi_disable(struct clk *clk) +{ + u32 reg; + + /* clear the auto-slow bits */ + reg = __raw_readl(MXC_CCM_DISPLAY_AXI); + reg &= ~MXC_CCM_DISPLAY_AXI_PXP_ASM_EN; + __raw_writel(reg, MXC_CCM_DISPLAY_AXI); + + _clk_disable(clk); +} + + +/* TODO: check Auto-Slow Mode */ +static struct clk pxp_axi_clk = { + __INIT_CLK_DEBUG(pxp_axi_clk) + .parent = &display_axi_clk, + .enable = _clk_pxp_axi_enable, + .disable = _clk_pxp_axi_disable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk elcdif_axi_clk = { + __INIT_CLK_DEBUG(elcdif_axi_clk) + .parent = &display_axi_clk, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_elcdif_pix_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd6_clk, &pll1_sw_clk, &ckih_clk); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_elcdif_pix_get_rate(struct clk *clk) +{ + u32 reg, prediv, podf; + + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + prediv = ((reg & MXC_CCM_ELCDIFPIX_CLK_PRED_MASK) >> + MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_ELCDIFPIX_CLK_PODF_MASK) >> + MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (prediv * podf); +} + +static unsigned long _clk_elcdif_pix_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 max_div = (2 << 12) - 1; + return _clk_round_rate_div(clk, rate, max_div, NULL); +} + +static int _clk_elcdif_pix_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div, max_div; + u32 reg; + + max_div = (2 << 12) - 1; + _clk_round_rate_div(clk, rate, max_div, &new_div); + + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + /* Pre-divider set to 1 - only use PODF for clk dividing */ + reg &= ~MXC_CCM_ELCDIFPIX_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET; + reg &= ~MXC_CCM_ELCDIFPIX_CLK_PODF_MASK; + reg |= new_div << MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_ELCDIFPIX); + + return 0; +} + +static int _clk_elcdif_pix_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + reg |= 0x3 << MXC_CCM_ELCDIFPIX_CLKGATE_OFFSET; + __raw_writel(reg, MXC_CCM_ELCDIFPIX); + return 0; +} + +static void _clk_elcdif_pix_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_ELCDIFPIX); + reg &= ~MXC_CCM_ELCDIFPIX_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_ELCDIFPIX); + _clk_disable(clk); +} + +static struct clk elcdif_pix_clk = { + __INIT_CLK_DEBUG(elcdif_pix_clk) + .parent = &osc_clk, + .secondary = &ddr_clk, + .enable = _clk_elcdif_pix_enable, + .disable = _clk_elcdif_pix_disable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .set_parent = _clk_elcdif_pix_set_parent, + .get_rate = _clk_elcdif_pix_get_rate, + .round_rate = _clk_elcdif_pix_round_rate, + .set_rate = _clk_elcdif_pix_set_rate, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_epdc_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd3_clk, &pll1_sw_clk, NULL); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_epdc_axi_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_EPDC_AXI); + div &= MXC_CCM_EPDC_AXI_DIV_MASK; + if (div == 0) { /* gated off */ + return clk_get_rate(clk->parent); + } else { + return clk_get_rate(clk->parent) / div; + } +} + +static unsigned long _clk_epdc_axi_round_rate_div(struct clk *clk, + unsigned long rate, + u32 *new_div) +{ + u32 div, max_div; + + max_div = (2 << 6) - 1; + div = DIV_ROUND_UP(clk_get_rate(clk->parent), rate); + if (div > max_div) + div = max_div; + else if (div == 0) + div++; + if (new_div != NULL) + *new_div = div; + return clk_get_rate(clk->parent) / div; +} + +static unsigned long _clk_epdc_axi_round_rate(struct clk *clk, + unsigned long rate) +{ + return _clk_epdc_axi_round_rate_div(clk, rate, NULL); +} + +static int _clk_epdc_axi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div; + u32 reg; + + _clk_epdc_axi_round_rate_div(clk, rate, &new_div); + + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg &= ~MXC_CCM_EPDC_AXI_DIV_MASK; + reg |= new_div << MXC_CCM_EPDC_AXI_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + while (__raw_readl(MXC_CCM_CSR2) & MXC_CCM_CSR2_EPDC_AXI_BUSY) + ; + + return 0; +} + +static int _clk_epdc_axi_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg |= MXC_CCM_EPDC_AXI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + /* Set the auto-slow bits */ + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg |= (MXC_CCM_EPDC_AXI_ASM_EN); + reg |= (5 << MXC_CCM_EPDC_AXI_ASM_DIV_OFFSET); + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + return 0; +} + +static void _clk_epdc_axi_disable(struct clk *clk) +{ + u32 reg; + + /* clear the auto-slow bits */ + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg &= ~MXC_CCM_EPDC_AXI_ASM_EN; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + + reg = __raw_readl(MXC_CCM_EPDC_AXI); + reg &= ~MXC_CCM_EPDC_AXI_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDC_AXI); + _clk_disable(clk); +} + +/* TODO: check Auto-Slow Mode */ +static struct clk epdc_axi_clk = { + __INIT_CLK_DEBUG(epdc_axi_clk) + .parent = &osc_clk, + .secondary = &apbh_dma_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .set_parent = _clk_epdc_axi_set_parent, + .get_rate = _clk_epdc_axi_get_rate, + .set_rate = _clk_epdc_axi_set_rate, + .round_rate = _clk_epdc_axi_round_rate, + .enable = _clk_epdc_axi_enable, + .disable = _clk_epdc_axi_disable, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + + +static int _clk_epdc_pix_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CLKSEQ_BYPASS); + mux = _get_mux(parent, &osc_clk, &pfd5_clk, &pll1_sw_clk, &ckih_clk); + reg = (reg & ~MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_MASK) | + (mux << MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CLKSEQ_BYPASS); + + return 0; +} + +static unsigned long _clk_epdc_pix_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_EPDCPIX); + div &= MXC_CCM_EPDC_PIX_CLK_PODF_MASK; + if (div == 0) { /* gated off */ + return clk_get_rate(clk->parent); + } else { + return clk_get_rate(clk->parent) / div; + } +} + +static unsigned long _clk_epdc_pix_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 max_div = (2 << 12) - 1; + return _clk_round_rate_div(clk, rate, max_div, NULL); +} + +static int _clk_epdc_pix_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div, max_div; + u32 reg; + + max_div = (2 << 12) - 1; + _clk_round_rate_div(clk, rate, max_div, &new_div); + + reg = __raw_readl(MXC_CCM_EPDCPIX); + /* Pre-divider set to 1 - only use PODF for clk dividing */ + reg &= ~MXC_CCM_EPDC_PIX_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_EPDC_PIX_CLK_PRED_OFFSET; + reg &= ~MXC_CCM_EPDC_PIX_CLK_PODF_MASK; + reg |= new_div << MXC_CCM_EPDC_PIX_CLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_EPDCPIX); + + while (__raw_readl(MXC_CCM_CSR2) & MXC_CCM_CSR2_EPDC_PIX_BUSY) + ; + + return 0; +} + +static int _clk_epdc_pix_enable(struct clk *clk) +{ + u32 reg; + + _clk_enable(clk); + reg = __raw_readl(MXC_CCM_EPDCPIX); + reg |= MXC_CCM_EPDC_PIX_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDCPIX); + + return 0; +} + +static void _clk_epdc_pix_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_EPDCPIX); + reg &= ~MXC_CCM_EPDC_PIX_CLKGATE_MASK; + __raw_writel(reg, MXC_CCM_EPDCPIX); + _clk_disable(clk); +} + +/* TODO: check Auto-Slow Mode */ +static struct clk epdc_pix_clk = { + __INIT_CLK_DEBUG(epdc_pix_clk) + .parent = &osc_clk, + .secondary = &apbh_dma_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .set_parent = _clk_epdc_pix_set_parent, + .get_rate = _clk_epdc_pix_get_rate, + .set_rate = _clk_epdc_pix_set_rate, + .round_rate = _clk_epdc_pix_round_rate, + .enable = _clk_epdc_pix_enable, + .disable = _clk_epdc_pix_disable, + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long cko1_get_rate(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= MX50_CCM_CCOSR_CKO1_DIV_MASK; + reg = reg >> MX50_CCM_CCOSR_CKO1_DIV_OFFSET; + return clk_get_rate(clk->parent) / (reg + 1); +} + +static int cko1_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg |= MX50_CCM_CCOSR_CKO1_EN; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static void cko1_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MX50_CCM_CCOSR_CKO1_EN; + __raw_writel(reg, MXC_CCM_CCOSR); +} + +static int cko1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = (parent_rate/rate - 1) & 0x7; + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MX50_CCM_CCOSR_CKO1_DIV_MASK; + reg |= div << MX50_CCM_CCOSR_CKO1_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long cko1_round_rate(struct clk *clk, unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + div = div < 1 ? 1 : div; + div = div > 8 ? 8 : div; + return parent_rate / div; +} + +static int cko1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg, fast; + + if (parent == &cpu_clk) { + sel = 0; + fast = 1; + } else if (parent == &pll1_sw_clk) { + sel = 1; + fast = 1; + } else if (parent == &pll2_sw_clk) { + sel = 2; + fast = 1; + } else if (parent == &pll3_sw_clk) { + sel = 3; + fast = 1; + } else if (parent == &apll_clk) { + sel = 0; + fast = 0; + } else if (parent == &pfd0_clk) { + sel = 1; + fast = 0; + } else if (parent == &pfd1_clk) { + sel = 2; + fast = 0; + } else if (parent == &pfd2_clk) { + sel = 3; + fast = 0; + } else if (parent == &pfd3_clk) { + sel = 4; + fast = 0; + } else if (parent == &pfd4_clk) { + sel = 5; + fast = 0; + } else if (parent == &pfd5_clk) { + sel = 6; + fast = 0; + } else if (parent == &pfd6_clk) { + sel = 7; + fast = 0; + } else if (parent == &weim_clk[0]) { + sel = 10; + fast = 0; + } else if (parent == &ahb_clk) { + sel = 11; + fast = 0; + } else if (parent == &ipg_clk) { + sel = 12; + fast = 0; + } else if (parent == &ipg_perclk) { + sel = 13; + fast = 0; + } else if (parent == &pfd7_clk) { + sel = 15; + fast = 0; + } else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MX50_CCM_CCOSR_CKO1_SEL_MASK; + reg |= sel << MX50_CCM_CCOSR_CKO1_SEL_OFFSET; + if (fast) + reg &= ~MX50_CCM_CCOSR_CKO1_SLOW_SEL; + else + reg |= MX50_CCM_CCOSR_CKO1_SLOW_SEL; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static struct clk cko1_clk = { + __INIT_CLK_DEBUG(cko1_clk) + .parent = &pll1_sw_clk, + .get_rate = cko1_get_rate, + .enable = cko1_enable, + .disable = cko1_disable, + .set_rate = cko1_set_rate, + .round_rate = cko1_round_rate, + .set_parent = cko1_set_parent, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + } + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK(NULL, "osc", osc_clk), + _REGISTER_CLOCK(NULL, "ckih", ckih_clk), + _REGISTER_CLOCK(NULL, "ckih2", ckih2_clk), + _REGISTER_CLOCK(NULL, "ckil", ckil_clk), + _REGISTER_CLOCK(NULL, "pll1_main_clk", pll1_main_clk), + _REGISTER_CLOCK(NULL, "pll1_sw_clk", pll1_sw_clk), + _REGISTER_CLOCK(NULL, "pll2", pll2_sw_clk), + _REGISTER_CLOCK(NULL, "pll3", pll3_sw_clk), + _REGISTER_CLOCK(NULL, "apll", apll_clk), + _REGISTER_CLOCK(NULL, "pfd0", pfd0_clk), + _REGISTER_CLOCK(NULL, "pfd1", pfd1_clk), + _REGISTER_CLOCK(NULL, "pfd2", pfd2_clk), + _REGISTER_CLOCK(NULL, "pfd3", pfd3_clk), + _REGISTER_CLOCK(NULL, "pfd4", pfd4_clk), + _REGISTER_CLOCK(NULL, "pfd5", pfd5_clk), + _REGISTER_CLOCK(NULL, "pfd6", pfd6_clk), + _REGISTER_CLOCK(NULL, "pfd7", pfd7_clk), + _REGISTER_CLOCK(NULL, "gpc_dvfs_clk", gpc_dvfs_clk), + _REGISTER_CLOCK(NULL, "lp_apm", lp_apm_clk), + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk), + _REGISTER_CLOCK(NULL, "main_bus_clk", main_bus_clk), + _REGISTER_CLOCK(NULL, "axi_a_clk", axi_a_clk), + _REGISTER_CLOCK(NULL, "axi_b_clk", axi_b_clk), + _REGISTER_CLOCK(NULL, "ahb_clk", ahb_clk), + _REGISTER_CLOCK(NULL, "ahb_max_clk", ahb_max_clk), + _REGISTER_CLOCK("mxc_sdma", "sdma_ahb_clk", sdma_clk[0]), + _REGISTER_CLOCK("mxc_sdma", "sdma_ipg_clk", sdma_clk[1]), + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk[0]), + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk[0]), + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk[0]), + _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk[0]), + _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk[0]), + _REGISTER_CLOCK(NULL, "i2c_clk", i2c_clk[0]), + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk[1]), + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk[2]), + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk[0]), + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk[0]), + _REGISTER_CLOCK("imx50-cspi.1", NULL, cspi1_clk[0]), + _REGISTER_CLOCK("imx50-cspi.2", NULL, cspi2_clk[0]), + _REGISTER_CLOCK("imx50-cspi.3", NULL, cspi3_clk), + _REGISTER_CLOCK(NULL, "ssi_lp_apm_clk", ssi_lp_apm_clk), + _REGISTER_CLOCK("mxc_ssi.0", NULL, ssi1_clk[0]), + _REGISTER_CLOCK("mxc_ssi.1", NULL, ssi2_clk[0]), + _REGISTER_CLOCK(NULL, "ssi_ext1_clk", ssi_ext1_clk), + _REGISTER_CLOCK(NULL, "ssi_ext2_clk", ssi_ext2_clk), + _REGISTER_CLOCK(NULL, "usb_ahb_clk", usb_ahb_clk), + _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy_clk[0]), + _REGISTER_CLOCK(NULL, "usb_phy2_clk", usb_phy_clk[1]), + _REGISTER_CLOCK(NULL, "usb_clk", usb_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk[0]), + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk[0]), + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk[0]), + _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_clk[0]), + _REGISTER_CLOCK(NULL, "ddr_clk", ddr_clk), + _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), + _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_clk), + _REGISTER_CLOCK(NULL, "cko1", cko1_clk), + _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]), + _REGISTER_CLOCK("fec.0", NULL, fec_clk[0]), + _REGISTER_CLOCK(NULL, "fec_sec1_clk", fec_clk[1]), + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk), + _REGISTER_CLOCK("imx50-gpmi-nfc.0", NULL, gpmi_nfc_clk[0]), + _REGISTER_CLOCK(NULL, "gpmi-apb", gpmi_nfc_clk[1]), + _REGISTER_CLOCK(NULL, "bch", gpmi_nfc_clk[2]), + _REGISTER_CLOCK(NULL, "bch-apb", gpmi_nfc_clk[3]), + _REGISTER_CLOCK(NULL, "rng_clk", rng_clk), + _REGISTER_CLOCK(NULL, "dcp_clk", dcp_clk), + _REGISTER_CLOCK(NULL, "ocotp_ctrl_ahb_clk", ocotp_clk), + _REGISTER_CLOCK(NULL, "ocram_clk", ocram_clk), + _REGISTER_CLOCK("mxs-dma-apbh", NULL, apbh_dma_clk), + _REGISTER_CLOCK(NULL, "sys_clk", sys_clk), + _REGISTER_CLOCK(NULL, "elcdif_pix", elcdif_pix_clk), + _REGISTER_CLOCK(NULL, "display_axi", display_axi_clk), + _REGISTER_CLOCK(NULL, "elcdif_axi", elcdif_axi_clk), + _REGISTER_CLOCK(NULL, "pxp_axi", pxp_axi_clk), + _REGISTER_CLOCK(NULL, "epdc_axi", epdc_axi_clk), + _REGISTER_CLOCK(NULL, "epdc_pix", epdc_pix_clk), +}; + +/*static struct mxc_clk mxc_clks[ARRAY_SIZE(lookups)];*/ + +static void clk_tree_init(void) +{ + u32 reg; + + ipg_perclk.set_parent(&ipg_perclk, &lp_apm_clk); + + /* + *Initialise the IPG PER CLK dividers to 3. IPG_PER_CLK should be at + * 8MHz, its derived from lp_apm. + */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED1_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PRED2_MASK; + reg &= ~MXC_CCM_CBCDR_PERCLK_PODF_MASK; + reg |= (2 << MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + /* set pll1_main_clk parent */ + pll1_main_clk.parent = &osc_clk; + + /* set pll2_sw_clk parent */ + pll2_sw_clk.parent = &osc_clk; + + /* set pll3_clk parent */ + pll3_sw_clk.parent = &osc_clk; + + /* set weim_clk parent */ + weim_clk[0].parent = &main_bus_clk; + reg = __raw_readl(MXC_CCM_CBCDR); + if ((reg & MX50_CCM_CBCDR_WEIM_CLK_SEL) != 0) + weim_clk[0].parent = &ahb_clk; + + /* set ipg_perclk parent */ + ipg_perclk.parent = &lp_apm_clk; + reg = __raw_readl(MXC_CCM_CBCMR); + if ((reg & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL) != 0) { + ipg_perclk.parent = &ipg_clk; + } else { + if ((reg & MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL) == 0) + ipg_perclk.parent = &main_bus_clk; + } +} + +int __init mx50_clocks_init(unsigned long ckil, unsigned long osc, unsigned long ckih1) +{ + __iomem void *base; + int i = 0, j = 0, reg; + int wp_cnt = 0; + u32 pll1_rate; + + pll1_base = MX50_DPLL1_BASE; + pll2_base = MX50_DPLL2_BASE; + pll3_base = MX50_DPLL3_BASE; + apll_base = ioremap(MX50_ANATOP_BASE_ADDR, SZ_4K); + + /* Turn off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG4_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 1 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG3_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET | + 1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG14_OFFSET, MXC_CCM_CCGR0); + } + + __raw_writel(0, MXC_CCM_CCGR1); + __raw_writel(0, MXC_CCM_CCGR2); + __raw_writel(0, MXC_CCM_CCGR3); + __raw_writel(0, MXC_CCM_CCGR4); + + __raw_writel(3 << MXC_CCM_CCGRx_CG6_OFFSET | + 1 << MXC_CCM_CCGRx_CG8_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(3 << MXC_CCM_CCGRx_CG0_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 2 << MXC_CCM_CCGRx_CG14_OFFSET | + 3 << MXC_CCM_CCGRx_CG15_OFFSET, MXC_CCM_CCGR6); + + __raw_writel(0, MXC_CCM_CCGR7); + + external_low_reference = ckil; + external_high_reference = ckih1; + oscillator_reference = osc; + + usb_phy_clk[0].enable_reg = MXC_CCM_CCGR4; + usb_phy_clk[0].enable_shift = MXC_CCM_CCGRx_CG5_OFFSET; + clk_tree_init(); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + clk_debug_register(lookups[i].clk); + } + + /* set DDR clock parent */ + reg = __raw_readl(MXC_CCM_CLK_DDR) & + MXC_CCM_CLK_DDR_DDR_PFD_SEL; + if (reg) + clk_set_parent(&ddr_clk, &pfd0_clk); + else + clk_set_parent(&ddr_clk, &pll1_sw_clk); + + clk_set_parent(&esdhc1_clk[0], &pll2_sw_clk); + clk_set_parent(&esdhc1_clk[2], &tmax2_clk); + clk_set_parent(&esdhc2_clk[0], &esdhc1_clk[0]); + clk_set_parent(&esdhc3_clk[0], &pll2_sw_clk); + + clk_enable(&cpu_clk); + + clk_enable(&main_bus_clk); + + databahn = ioremap(MX50_DATABAHN_BASE_ADDR, SZ_16K); + + /* Initialise the parents to be axi_b, parents are set to + * axi_a when the clocks are enabled. + */ + + clk_set_parent(&gpu2d_clk, &axi_a_clk); + + /* move cspi to 24MHz */ + clk_set_parent(&cspi_main_clk, &lp_apm_clk); + clk_set_rate(&cspi_main_clk, 12000000); + + /* + * Set DISPLAY_AXI to 200Mhz + * For Display AXI, source clocks must be + * enabled before dividers can be changed + */ + clk_enable(&display_axi_clk); + clk_enable(&elcdif_axi_clk); + clk_enable(&pxp_axi_clk); + clk_set_parent(&display_axi_clk, &pfd2_clk); + clk_set_rate(&display_axi_clk, 200000000); + clk_disable(&display_axi_clk); + clk_disable(&pxp_axi_clk); + clk_disable(&elcdif_axi_clk); + + clk_enable(&elcdif_pix_clk); + clk_set_parent(&elcdif_pix_clk, &pll1_sw_clk); + clk_disable(&elcdif_pix_clk); + + /* + * Enable and set EPDC AXI to 200MHz + * For EPDC AXI, source clocks must be + * enabled before dividers can be changed + */ + clk_enable(&epdc_axi_clk); + clk_set_parent(&epdc_axi_clk, &pfd3_clk); + clk_set_rate(&epdc_axi_clk, 200000000); + clk_disable(&epdc_axi_clk); + + clk_set_parent(&epdc_pix_clk, &pfd5_clk); + + /* Move SSI clocks to SSI_LP_APM clock */ + clk_set_parent(&ssi_lp_apm_clk, &lp_apm_clk); + + clk_set_parent(&ssi1_clk[0], &ssi_lp_apm_clk); + /* set the SSI dividers to divide by 2 */ + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS1CDR); + + clk_set_parent(&ssi2_clk[0], &ssi_lp_apm_clk); + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK; + reg &= ~MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK; + reg |= 1 << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET; + __raw_writel(reg, MXC_CCM_CS2CDR); + + /* Change the SSI_EXT1_CLK to be sourced from SSI1_CLK_ROOT */ + clk_set_parent(&ssi_ext1_clk, &ssi1_clk[0]); + clk_set_parent(&ssi_ext2_clk, &ssi2_clk[0]); + + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy_clk[0], &osc_clk); + clk_set_parent(&usb_phy_clk[1], &osc_clk); + + /* move gpmi-nfc to 24MHz */ + clk_set_parent(&gpmi_nfc_clk[0], &osc_clk); + + /* set SDHC root clock as 200MHZ*/ + clk_set_rate(&esdhc1_clk[0], 200000000); + clk_set_rate(&esdhc3_clk[0], 200000000); + + clk_set_parent(&uart_main_clk, &lp_apm_clk); + + clk_set_parent(&gpu2d_clk, &axi_b_clk); + + clk_set_parent(&weim_clk[0], &ahb_clk); + clk_set_rate(&weim_clk[0], clk_round_rate(&weim_clk[0], 130000000)); + + /* Do the following just to disable the PLL since its not used */ + clk_enable(&pll3_sw_clk); + clk_disable(&pll3_sw_clk); + + /* Get the CPU operating points table. */ + mx50_cpu_op_init(); + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + + base = MX50_IO_ADDRESS(MX50_GPT1_BASE_ADDR); + mxc_timer_init(&gpt_clk[0], base, MX50_INT_GPT); + + return 0; +} + +/*! + * Setup cpu clock based on working point. + * @param wp cpu freq working point + * @return 0 on success or error code on failure. + */ +static int cpu_clk_set_op(int wp) +{ + struct cpu_op *p; + u32 reg; + + if (wp == cpu_curr_op) + return 0; + + p = &cpu_op_tbl[wp]; + + /* + * leave the PLL1 freq unchanged. + */ + reg = __raw_readl(MXC_CCM_CACRR); + reg &= ~MXC_CCM_CACRR_ARM_PODF_MASK; + reg |= cpu_op_tbl[wp].cpu_podf << MXC_CCM_CACRR_ARM_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CACRR); + cpu_curr_op = wp; + +#if defined(CONFIG_CPU_FREQ) + cpufreq_trig_needed = 1; +#endif + return 0; +} diff --git a/arch/arm/mach-mx5/cpu.c b/arch/arm/mach-mx5/cpu.c new file mode 100755 index 00000000..94a69be9 --- /dev/null +++ b/arch/arm/mach-mx5/cpu.c @@ -0,0 +1,292 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * This file contains the CPU initialization code. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/iram_alloc.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> + +#include <mach/hardware.h> +#include <asm/io.h> + +#define CORTEXA8_PLAT_AMC 0x18 +#define SRPG_NEON_PUPSCR 0x284 +#define SRPG_NEON_PDNSCR 0x288 +#define SRPG_ARM_PUPSCR 0x2A4 +#define SRPG_ARM_PDNSCR 0x2A8 +#define SRPG_EMPGC0_PUPSCR 0x2E4 +#define SRPG_EMPGC0_PDNSCR 0x2E8 +#define SRPG_EMPGC1_PUPSCR 0x304 +#define SRPG_EMPGC1_PDNSCR 0x308 + +void __iomem *arm_plat_base; +void __iomem *gpc_base; +void __iomem *ccm_base; +struct cpu_op *(*get_cpu_op)(int *op); + +extern void init_ddr_settings(void); + +static int cpu_silicon_rev = -1; + +#define IIM_SREV 0x24 +#define MX50_HW_ADADIG_DIGPROG 0xB0 + +static int get_mx51_srev(void) +{ + void __iomem *iim_base = MX51_IO_ADDRESS(MX51_IIM_BASE_ADDR); + u32 rev = readl(iim_base + IIM_SREV) & 0xff; + + if (rev == 0x0) + return IMX_CHIP_REVISION_2_0; + else if (rev == 0x10) + return IMX_CHIP_REVISION_3_0; + return 0; +} + +/* + * Returns: + * the silicon revision of the cpu + * -EINVAL - not a mx51 + */ +int mx51_revision(void) +{ + if (!cpu_is_mx51()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + cpu_silicon_rev = get_mx51_srev(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx51_revision); + +void mx51_display_revision(void) +{ + int rev; + char *srev; + rev = mx51_revision(); + + switch (rev) { + case IMX_CHIP_REVISION_2_0: + srev = IMX_CHIP_REVISION_2_0_STRING; + break; + case IMX_CHIP_REVISION_3_0: + srev = IMX_CHIP_REVISION_3_0_STRING; + break; + default: + srev = IMX_CHIP_REVISION_UNKNOWN_STRING; + } + printk(KERN_INFO "CPU identified as i.MX51, silicon rev %s\n", srev); +} +EXPORT_SYMBOL(mx51_display_revision); + +#ifdef CONFIG_NEON + +/* + * All versions of the silicon before Rev. 3 have broken NEON implementations. + * Dependent on link order - so the assumption is that vfp_init is called + * before us. + */ +static int __init mx51_neon_fixup(void) +{ + if (!cpu_is_mx51()) + return 0; + + if (mx51_revision() < IMX_CHIP_REVISION_3_0 && (elf_hwcap & HWCAP_NEON)) { + elf_hwcap &= ~HWCAP_NEON; + pr_info("Turning off NEON support, detected broken NEON implementation\n"); + } + return 0; +} + +late_initcall(mx51_neon_fixup); +#endif + +static int get_mx53_srev(void) +{ + void __iomem *iim_base = MX51_IO_ADDRESS(MX53_IIM_BASE_ADDR); + u32 rev = readl(iim_base + IIM_SREV) & 0xff; + + switch (rev) { + case 0x0: + return IMX_CHIP_REVISION_1_0; + case 0x2: + return IMX_CHIP_REVISION_2_0; + case 0x3: + return IMX_CHIP_REVISION_2_1; + default: + return IMX_CHIP_REVISION_UNKNOWN; + } +} + +/* + * Returns: + * the silicon revision of the cpu + * -EINVAL - not a mx53 + */ +int mx53_revision(void) +{ + if (!cpu_is_mx53()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + cpu_silicon_rev = get_mx53_srev(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx53_revision); +#define MX50_HW_ADADIG_DIGPROG 0xB0 + +static int get_mx50_srev(void) +{ + void __iomem *anatop = ioremap(MX50_ANATOP_BASE_ADDR, SZ_8K); + u32 rev; + + if (!anatop) { + cpu_silicon_rev = -EINVAL; + return 0; + } + + rev = readl(anatop + MX50_HW_ADADIG_DIGPROG); + rev &= 0xff; + + iounmap(anatop); + if (rev == 0x0) + return IMX_CHIP_REVISION_1_0; + else if (rev == 0x1) + return IMX_CHIP_REVISION_1_1; + return 0; +} + +/* + * Returns: + * the silicon revision of the cpu + * -EINVAL - not a mx50 + */ +int mx50_revision(void) +{ + if (!cpu_is_mx50()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + cpu_silicon_rev = get_mx50_srev(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx50_revision); + +void mx53_display_revision(void) +{ + int rev; + char *srev; + rev = mx53_revision(); + + switch (rev) { + case IMX_CHIP_REVISION_1_0: + srev = IMX_CHIP_REVISION_1_0_STRING; + break; + case IMX_CHIP_REVISION_2_0: + srev = IMX_CHIP_REVISION_2_0_STRING; + break; + case IMX_CHIP_REVISION_2_1: + srev = IMX_CHIP_REVISION_2_1_STRING; + break; + default: + srev = IMX_CHIP_REVISION_UNKNOWN_STRING; + } + printk(KERN_INFO "CPU identified as i.MX53, silicon rev %s\n", srev); +} +EXPORT_SYMBOL(mx53_display_revision); + +static int __init post_cpu_init(void) +{ + unsigned int reg; + void __iomem *base; + struct clk *gpcclk = clk_get(NULL, "gpc_dvfs_clk"); + + if (cpu_is_mx51()) { + ccm_base = MX51_IO_ADDRESS(MX51_CCM_BASE_ADDR); + gpc_base = MX51_IO_ADDRESS(MX51_GPC_BASE_ADDR); + arm_plat_base = MX51_IO_ADDRESS(MX51_ARM_BASE_ADDR); + iram_init(MX51_IRAM_BASE_ADDR, MX51_IRAM_SIZE); + } else if (cpu_is_mx53()) { + ccm_base = MX53_IO_ADDRESS(MX53_CCM_BASE_ADDR); + gpc_base = MX53_IO_ADDRESS(MX53_GPC_BASE_ADDR); + arm_plat_base = MX53_IO_ADDRESS(MX53_ARM_BASE_ADDR); + iram_init(MX53_IRAM_BASE_ADDR, MX53_IRAM_SIZE); + } else { + ccm_base = MX50_IO_ADDRESS(MX50_CCM_BASE_ADDR); + gpc_base = MX50_IO_ADDRESS(MX50_GPC_BASE_ADDR); + arm_plat_base = MX50_IO_ADDRESS(MX50_ARM_BASE_ADDR); + iram_init(MX50_IRAM_BASE_ADDR, MX50_IRAM_SIZE); + } + + if (cpu_is_mx51() || cpu_is_mx53()) { + if (cpu_is_mx51()) { + base = MX51_IO_ADDRESS(MX51_AIPS1_BASE_ADDR); + } else { + base = MX53_IO_ADDRESS(MX53_AIPS1_BASE_ADDR); + } + + __raw_writel(0x0, base + 0x40); + __raw_writel(0x0, base + 0x44); + __raw_writel(0x0, base + 0x48); + __raw_writel(0x0, base + 0x4C); + reg = __raw_readl(base + 0x50) & 0x00FFFFFF; + __raw_writel(reg, base + 0x50); + + if (cpu_is_mx51()) + base = MX51_IO_ADDRESS(MX51_AIPS2_BASE_ADDR); + else + base = MX53_IO_ADDRESS(MX53_AIPS2_BASE_ADDR); + + __raw_writel(0x0, base + 0x40); + __raw_writel(0x0, base + 0x44); + __raw_writel(0x0, base + 0x48); + __raw_writel(0x0, base + 0x4C); + reg = __raw_readl(base + 0x50) & 0x00FFFFFF; + __raw_writel(reg, base + 0x50); + } + clk_enable(gpcclk); + + /* Setup the number of clock cycles to wait for SRPG + * power up and power down requests. + */ + __raw_writel(0x010F0201, gpc_base + SRPG_ARM_PUPSCR); + __raw_writel(0x010F0201, gpc_base + SRPG_NEON_PUPSCR); + __raw_writel(0x00000008, gpc_base + SRPG_EMPGC0_PUPSCR); + __raw_writel(0x00000008, gpc_base + SRPG_EMPGC1_PUPSCR); + + __raw_writel(0x01010101, gpc_base + SRPG_ARM_PDNSCR); + __raw_writel(0x01010101, gpc_base + SRPG_NEON_PDNSCR); + __raw_writel(0x00000018, gpc_base + SRPG_EMPGC0_PDNSCR); + __raw_writel(0x00000018, gpc_base + SRPG_EMPGC1_PDNSCR); + + clk_disable(gpcclk); + clk_put(gpcclk); + + /* Set ALP bits to 000. Set ALP_EN bit in Arm Memory Controller reg. */ + reg = 0x8; + __raw_writel(reg, arm_plat_base + CORTEXA8_PLAT_AMC); + + if (cpu_is_mx50()) + init_ddr_settings(); + + return 0; +} + +postcore_initcall(post_cpu_init); diff --git a/arch/arm/mach-mx5/cpu_op-mx50.c b/arch/arm/mach-mx5/cpu_op-mx50.c new file mode 100755 index 00000000..f916ae41 --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx50.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/types.h> +#include <mach/hardware.h> +#include <linux/kernel.h> +#include <mach/mxc_dvfs.h> + +static int num_cpu_op; + +extern struct cpu_op *(*get_cpu_op)(int *op); +extern struct dvfs_op *(*get_dvfs_core_op)(int *wp); + +/* working point(wp): 0 - 800MHz; 1 - 400MHz, 2 - 160MHz; */ +static struct cpu_op mx50_cpu_op[] = { + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 400000000, + .cpu_podf = 1, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .cpu_podf = 4, + .cpu_voltage = 850000,}, +}; + +static struct dvfs_op dvfs_core_setpoint[] = { + {33, 13, 33, 10, 10, 0x08}, /* 800MHz*/ + {28, 8, 33, 10, 10, 0x08}, /* 400MHz */ + {20, 0, 33, 20, 10, 0x08}, /* 160MHz*/ + {28, 8, 33, 20, 30, 0x08}, /*160MHz, AHB 133MHz, LPAPM mode*/ + {29, 0, 33, 20, 10, 0x08},}; /* 160MHz, AHB 24MHz */ + +struct cpu_op *mx50_get_cpu_op(int *op) +{ + *op = ARRAY_SIZE(mx50_cpu_op); + return mx50_cpu_op; +} + +static struct dvfs_op *mx50_get_dvfs_core_table(int *wp) +{ + *wp = ARRAY_SIZE(dvfs_core_setpoint); + return dvfs_core_setpoint; +} + +void mx50_cpu_op_init(void) +{ + get_cpu_op = mx50_get_cpu_op; + num_cpu_op = ARRAY_SIZE(mx50_cpu_op); + get_dvfs_core_op = mx50_get_dvfs_core_table; +} diff --git a/arch/arm/mach-mx5/cpu_op-mx50.h b/arch/arm/mach-mx5/cpu_op-mx50.h new file mode 100755 index 00000000..e9844c8e --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx50.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +void mx50_cpu_op_init(void); + diff --git a/arch/arm/mach-mx5/cpu_op-mx51.c b/arch/arm/mach-mx5/cpu_op-mx51.c new file mode 100755 index 00000000..640e4189 --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx51.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> + +extern struct cpu_op *(*get_cpu_op)(int *op); +extern void (*set_num_cpu_op)(int num); +extern struct dvfs_op *(*get_dvfs_core_op)(int *wp); + +static int num_cpu_op; + +/* working point(wp): 0 - 800MHz; 1 - 166.25MHz; */ +static struct cpu_op mx51_cpu_op[] = { + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1175000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1100000, + }, + { + .pll_rate = 800000000, + .cpu_rate = 400000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 1, + .cpu_voltage = 950000, + }, + { + .pll_rate = 800000000, + .cpu_rate = 166250000, + .cpu_podf = 4, + .cpu_voltage = 850000, + }, +}; + +static struct dvfs_op dvfs_core_setpoint[] = { + {33, 13, 33, 10, 10, 0x08}, /* 800MHz*/ + {28, 8, 33, 10, 10, 0x08}, /* 400MHz */ + {20, 0, 33, 20, 10, 0x08}, /* 160MHz*/ + {28, 8, 33, 20, 30, 0x08}, /*160MHz, AHB 133MHz, LPAPM mode*/ + {29, 0, 33, 20, 10, 0x08},}; /* 160MHz, AHB 24MHz */ + +struct cpu_op *mx51_get_cpu_op(int *op) +{ + *op = num_cpu_op; + return mx51_cpu_op; +} + +void mx51_set_num_cpu_op(int num) +{ + num_cpu_op = num; + return; +} + + +static struct dvfs_op *mx51_get_dvfs_core_table(int *wp) +{ + *wp = ARRAY_SIZE(dvfs_core_setpoint); + return dvfs_core_setpoint; +} + +void mx51_cpu_op_init(void) +{ + get_cpu_op = mx51_get_cpu_op; + set_num_cpu_op = mx51_set_num_cpu_op; + num_cpu_op = ARRAY_SIZE(mx51_cpu_op); + get_dvfs_core_op = mx51_get_dvfs_core_table; +} diff --git a/arch/arm/mach-mx5/cpu_op-mx51.h b/arch/arm/mach-mx5/cpu_op-mx51.h new file mode 100755 index 00000000..54c1345d --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx51.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +void mx51_cpu_op_init(void); diff --git a/arch/arm/mach-mx5/cpu_op-mx53.c b/arch/arm/mach-mx5/cpu_op-mx53.c new file mode 100755 index 00000000..debe1bc4 --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx53.c @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include "cpu_op-mx53.h" + +/*! + * @file mach-mx5/cpu_op-mx53.c + * + * @brief This file contains the information about MX53 CPU working points. + * + * @ingroup MSL_MX53 + */ +extern struct cpu_op *(*get_cpu_op)(int *op); +extern void (*set_num_cpu_op)(int num); +extern struct dvfs_op *(*get_dvfs_core_op)(int *wp); + +static int num_cpu_op; +static struct cpu_op *cpu_op_table; + +static struct dvfs_op *dvfs_core_setpoint; +static int num_dvfs_core_setpoint; + +/* Place holder for dvfs_core setpoints for AEC parts */ +static struct dvfs_op dvfs_core_setpoint_aec[] = { + {33, 0, 33, 10, 10, 0x08} }; /*800MHz*/ + +/* Place holder for dvfs_core setpoints for 1.2GHz parts */ +static struct dvfs_op dvfs_core_setpoint_ces_1_2G[] = { + {33, 25, 33, 10, 10, 0x08}, /*1_2GHz*/ + {30, 18, 33, 20, 10, 0x08}, /* 800MHz */ + {25, 8, 33, 20, 10, 0x08}, /* 400MHz */ + {28, 8, 33, 20, 30, 0x08}, /* 400MHZ, 133MHz */ + {29, 0, 33, 20, 10, 0x08},}; /* 400MHZ, 50MHz. */ + +/* Place holder for dvfs_core setpoints for 1 GHz parts */ +static struct dvfs_op dvfs_core_setpoint_ces[] = { + {33, 25, 33, 10, 10, 0x08}, /*1GHz*/ + {30, 18, 33, 20, 10, 0x08}, /* 800MHz */ + {25, 8, 33, 20, 10, 0x08}, /* 400MHz */ + {28, 8, 33, 20, 30, 0x08}, /* 400MHz, 133MHz */ + {29, 0, 33, 20, 10, 0x08},}; /* 400MHz, 50MHz. */ + +/* working point for auto*/ +static struct cpu_op cpu_op_aec[] = { + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, +}; + +/* working point for consumer 1G*/ +static struct cpu_op cpu_op_ces[] = { + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1200000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 400000000, + .cpu_podf = 1, + .cpu_voltage = 950000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .cpu_podf = 4, + .cpu_voltage = 900000,}, +}; + +/* working point for consumer 1.2G*/ +static struct cpu_op cpu_op_ces_1_2g[] = { + { + .pll_rate = 1200000000, + .cpu_rate = 1200000000, + .pdf = 0, + .mfi = 12, + .mfd = 1, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1300000,}, + { + .pll_rate = 1000000000, + .cpu_rate = 1000000000, + .pdf = 0, + .mfi = 10, + .mfd = 11, + .mfn = 5, + .cpu_podf = 0, + .cpu_voltage = 1200000,}, + { + .pll_rate = 800000000, + .cpu_rate = 800000000, + .pdf = 0, + .mfi = 8, + .mfd = 2, + .mfn = 1, + .cpu_podf = 0, + .cpu_voltage = 1050000,}, + { + .pll_rate = 800000000, + .cpu_rate = 400000000, + .cpu_podf = 1, + .cpu_voltage = 950000,}, + { + .pll_rate = 800000000, + .cpu_rate = 160000000, + .cpu_podf = 4, + .cpu_voltage = 900000,}, +}; + +static struct dvfs_op *mx53_get_dvfs_core_table(int *wp) +{ + /* Add 2 to num_cpu_wp to handle LPAPM mode transitions. */ + *wp = num_dvfs_core_setpoint; + return dvfs_core_setpoint; +} + +struct cpu_op *mx53_get_cpu_op(int *op) +{ + *op = num_cpu_op; + return cpu_op_table; +} + +void mx53_set_num_cpu_op(int num) +{ + num_cpu_op = num; + return; +} + +void mx53_cpu_op_init() +{ + get_cpu_op = mx53_get_cpu_op; + set_num_cpu_op = mx53_set_num_cpu_op; + get_dvfs_core_op = mx53_get_dvfs_core_table; +} + +void mx53_set_cpu_part_number(enum mx53_cpu_part_number part_num) +{ + switch (part_num) { + case IMX53_CEC_1_2G: + cpu_op_table = cpu_op_ces_1_2g; + num_cpu_op = ARRAY_SIZE(cpu_op_ces_1_2g); + dvfs_core_setpoint = dvfs_core_setpoint_ces_1_2G; + num_dvfs_core_setpoint = + ARRAY_SIZE(dvfs_core_setpoint_ces_1_2G); + break; + case IMX53_CEC: + cpu_op_table = cpu_op_ces; + num_cpu_op = ARRAY_SIZE(cpu_op_ces); + dvfs_core_setpoint = dvfs_core_setpoint_ces; + num_dvfs_core_setpoint = + ARRAY_SIZE(dvfs_core_setpoint_ces); + break; + case IMX53_AEC: + default: + cpu_op_table = cpu_op_aec; + num_cpu_op = ARRAY_SIZE(cpu_op_aec); + dvfs_core_setpoint = dvfs_core_setpoint_aec; + num_dvfs_core_setpoint = + ARRAY_SIZE(dvfs_core_setpoint_aec); + break; + } +} + + diff --git a/arch/arm/mach-mx5/cpu_op-mx53.h b/arch/arm/mach-mx5/cpu_op-mx53.h new file mode 100755 index 00000000..eba0feda --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx53.h @@ -0,0 +1,45 @@ +extern void mx51_cpu_op_init(void); +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef __ARCH_ARM_MACH_MX53_WP_H__ +#define __ARCH_ARM_MACH_MX53_WP_H__ +#include <linux/types.h> + +/*! + * @file mach-mx5/cpu_op-mx53.h + * + * @brief This file contains the information about MX53 CPU working points. + * + * @ingroup MSL_MX53 + */ +enum mx53_cpu_part_number { + IMX53_AEC, /* automative and infotainment AP */ + IMX53_CEC, /* Consumer AP, CPU freq is up to 1G */ + IMX53_CEC_1_2G, /* Consumer AP, CPU freq is up to 1.2GHZ */ +}; + +void mx53_set_cpu_part_number(enum mx53_cpu_part_number part_num); +void mx53_cpu_op_init(void); + +#endif /*__ARCH_ARM_MACH_MX53_WP_H__ */ + + + diff --git a/arch/arm/mach-mx5/cpu_regulator-mx5.c b/arch/arm/mach-mx5/cpu_regulator-mx5.c new file mode 100644 index 00000000..b7d01e91 --- /dev/null +++ b/arch/arm/mach-mx5/cpu_regulator-mx5.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <mach/hardware.h> +#include <linux/err.h> +#include <linux/regulator/consumer.h> + +struct regulator *cpu_regulator; +char *gp_reg_id; + + +void mx5_cpu_regulator_init(void) +{ + cpu_regulator = regulator_get(NULL, gp_reg_id); + if (IS_ERR(cpu_regulator)) + printk(KERN_ERR "%s: failed to get cpu regulator\n", __func__); +} + diff --git a/arch/arm/mach-mx5/crm_regs.h b/arch/arm/mach-mx5/crm_regs.h new file mode 100755 index 00000000..c32d19f6 --- /dev/null +++ b/arch/arm/mach-mx5/crm_regs.h @@ -0,0 +1,868 @@ +/* + * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#ifndef __ARCH_ARM_MACH_MX51_CRM_REGS_H__ +#define __ARCH_ARM_MACH_MX51_CRM_REGS_H__ + +#define MXC_CCM_BASE MX51_IO_ADDRESS(MX51_CCM_BASE_ADDR) + +#define MX51_DPLL1_BASE MX51_IO_ADDRESS(MX51_PLL1_BASE_ADDR) +#define MX51_DPLL2_BASE MX51_IO_ADDRESS(MX51_PLL2_BASE_ADDR) +#define MX51_DPLL3_BASE MX51_IO_ADDRESS(MX51_PLL3_BASE_ADDR) + +#define MX53_DPLL1_BASE MX53_IO_ADDRESS(MX53_PLL1_BASE_ADDR) +#define MX53_DPLL2_BASE MX53_IO_ADDRESS(MX53_PLL2_BASE_ADDR) +#define MX53_DPLL3_BASE MX53_IO_ADDRESS(MX53_PLL3_BASE_ADDR) +#define MX53_DPLL4_BASE MX53_IO_ADDRESS(MX53_PLL4_BASE_ADDR) + +#define MX50_DPLL1_BASE MX50_IO_ADDRESS(MX50_PLL1_BASE_ADDR) +#define MX50_DPLL2_BASE MX50_IO_ADDRESS(MX50_PLL2_BASE_ADDR) +#define MX50_DPLL3_BASE MX50_IO_ADDRESS(MX50_PLL3_BASE_ADDR) +#define MX50_ANATOP_BASE MX50_IO_ADDRESS(MX50_ANATOP_BASE_ADDR) + +/* PLL Register Offsets */ +#define MXC_PLL_DP_CTL 0x00 +#define MXC_PLL_DP_CONFIG 0x04 +#define MXC_PLL_DP_OP 0x08 +#define MXC_PLL_DP_MFD 0x0C +#define MXC_PLL_DP_MFN 0x10 +#define MXC_PLL_DP_MFNMINUS 0x14 +#define MXC_PLL_DP_MFNPLUS 0x18 +#define MXC_PLL_DP_HFS_OP 0x1C +#define MXC_PLL_DP_HFS_MFD 0x20 +#define MXC_PLL_DP_HFS_MFN 0x24 +#define MXC_PLL_DP_MFN_TOGC 0x28 +#define MXC_PLL_DP_DESTAT 0x2c + +/* PLL Register Bit definitions */ +#define MXC_PLL_DP_CTL_MUL_CTRL 0x2000 +#define MXC_PLL_DP_CTL_DPDCK0_2_EN 0x1000 +#define MXC_PLL_DP_CTL_DPDCK0_2_OFFSET 12 +#define MXC_PLL_DP_CTL_ADE 0x800 +#define MXC_PLL_DP_CTL_REF_CLK_DIV 0x400 +#define MXC_PLL_DP_CTL_REF_CLK_SEL_MASK (3 << 8) +#define MXC_PLL_DP_CTL_REF_CLK_SEL_OFFSET 8 +#define MXC_PLL_DP_CTL_HFSM 0x80 +#define MXC_PLL_DP_CTL_PRE 0x40 +#define MXC_PLL_DP_CTL_UPEN 0x20 +#define MXC_PLL_DP_CTL_RST 0x10 +#define MXC_PLL_DP_CTL_RCP 0x8 +#define MXC_PLL_DP_CTL_PLM 0x4 +#define MXC_PLL_DP_CTL_BRM0 0x2 +#define MXC_PLL_DP_CTL_LRF 0x1 + +#define MXC_PLL_DP_CONFIG_BIST 0x8 +#define MXC_PLL_DP_CONFIG_SJC_CE 0x4 +#define MXC_PLL_DP_CONFIG_AREN 0x2 +#define MXC_PLL_DP_CONFIG_LDREQ 0x1 + +#define MXC_PLL_DP_OP_MFI_OFFSET 4 +#define MXC_PLL_DP_OP_MFI_MASK (0xF << 4) +#define MXC_PLL_DP_OP_PDF_OFFSET 0 +#define MXC_PLL_DP_OP_PDF_MASK 0xF + +#define MXC_PLL_DP_MFD_OFFSET 0 +#define MXC_PLL_DP_MFD_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_OFFSET 0x0 +#define MXC_PLL_DP_MFN_MASK 0x07FFFFFF + +#define MXC_PLL_DP_MFN_TOGC_TOG_DIS (1 << 17) +#define MXC_PLL_DP_MFN_TOGC_TOG_EN (1 << 16) +#define MXC_PLL_DP_MFN_TOGC_CNT_OFFSET 0x0 +#define MXC_PLL_DP_MFN_TOGC_CNT_MASK 0xFFFF + +#define MXC_PLL_DP_DESTAT_TOG_SEL (1 << 31) +#define MXC_PLL_DP_DESTAT_MFN 0x07FFFFFF + +/* Register addresses of apll and pfd*/ +#define MXC_ANADIG_FRAC0 0x10 +#define MXC_ANADIG_FRAC0_SET 0x14 +#define MXC_ANADIG_FRAC0_CLR 0x18 +#define MXC_ANADIG_FRAC1 0x20 +#define MXC_ANADIG_FRAC1_SET 0x24 +#define MXC_ANADIG_FRAC1_CLR 0x28 +#define MXC_ANADIG_MISC 0x60 +#define MXC_ANADIG_MISC_SET 0x64 +#define MXC_ANADIG_MISC_CLR 0x68 +#define MXC_ANADIG_PLLCTRL 0x70 +#define MXC_ANADIG_PLLCTRL_SET 0x74 +#define MXC_ANADIG_PLLCTRL_CLR 0x78 + +/* apll and pfd Register Bit definitions */ + +#define MXC_ANADIG_PFD3_CLKGATE (1 << 31) +#define MXC_ANADIG_PFD3_STABLE (1 << 30) +#define MXC_ANADIG_PFD3_FRAC_OFFSET 24 +#define MXC_ANADIG_PFD_FRAC_MASK 0x3F +#define MXC_ANADIG_PFD2_CLKGATE (1 << 23) +#define MXC_ANADIG_PFD2_STABLE (1 << 22) +#define MXC_ANADIG_PFD2_FRAC_OFFSET 16 +#define MXC_ANADIG_PFD1_CLKGATE (1 << 15) +#define MXC_ANADIG_PFD1_STABLE (1 << 14) +#define MXC_ANADIG_PFD1_FRAC_OFFSET 8 +#define MXC_ANADIG_PFD0_CLKGATE (1 << 7) +#define MXC_ANADIG_PFD0_STABLE (1 << 6) +#define MXC_ANADIG_PFD0_FRAC_OFFSET 0 + +#define MXC_ANADIG_PFD7_CLKGATE (1 << 31) +#define MXC_ANADIG_PFD7_STABLE (1 << 30) +#define MXC_ANADIG_PFD7_FRAC_OFFSET 24 +#define MXC_ANADIG_PFD6_CLKGATE (1 << 23) +#define MXC_ANADIG_PFD6_STABLE (1 << 22) +#define MXC_ANADIG_PFD6_FRAC_OFFSET 16 +#define MXC_ANADIG_PFD5_CLKGATE (1 << 15) +#define MXC_ANADIG_PFD5_STABLE (1 << 14) +#define MXC_ANADIG_PFD5_FRAC_OFFSET 8 +#define MXC_ANADIG_PFD4_CLKGATE (1 << 7) +#define MXC_ANADIG_PFD4_STABLE (1 << 6) +#define MXC_ANADIG_PFD4_FRAC_OFFSET 0 + +#define MXC_ANADIG_REF_SELFBIAS_OFF (1 << 20) +#define MXC_ANADIG_PLL_HOLD_RING_OFF (1 << 7) +#define MXC_ANADIG_PLL_POWERUP (1 << 0) + +#define MXC_ANADIG_APLL_LOCK (1 << 31) +#define MXC_ANADIG_APLL_FORCE_LOCK (1 << 30) +#define MXC_ANADIG_PFD_DIS_OFFSET 16 +#define MXC_ANADIG_PFD_DIS_MASK 0xff +#define MXC_ANADIG_APLL_LOCK_CNT_OFFSET 0 +#define MXC_ANADIG_APLL_LOCK_CNT_MASK 0xffff + +/* Register addresses of CCM*/ +#define MXC_CCM_CCR (MXC_CCM_BASE + 0x00) +#define MXC_CCM_CCDR (MXC_CCM_BASE + 0x04) +#define MXC_CCM_CSR (MXC_CCM_BASE + 0x08) +#define MXC_CCM_CCSR (MXC_CCM_BASE + 0x0C) +#define MXC_CCM_CACRR (MXC_CCM_BASE + 0x10) +#define MXC_CCM_CBCDR (MXC_CCM_BASE + 0x14) +#define MXC_CCM_CBCMR (MXC_CCM_BASE + 0x18) +#define MXC_CCM_CSCMR1 (MXC_CCM_BASE + 0x1C) +#define MXC_CCM_CSCMR2 (MXC_CCM_BASE + 0x20) +#define MXC_CCM_CSCDR1 (MXC_CCM_BASE + 0x24) +#define MXC_CCM_CS1CDR (MXC_CCM_BASE + 0x28) +#define MXC_CCM_CS2CDR (MXC_CCM_BASE + 0x2C) +#define MXC_CCM_CDCDR (MXC_CCM_BASE + 0x30) +#define MXC_CCM_CHSCDR (MXC_CCM_BASE + 0x34) +#define MXC_CCM_CSCDR2 (MXC_CCM_BASE + 0x38) +#define MXC_CCM_CSCDR3 (MXC_CCM_BASE + 0x3C) +#define MXC_CCM_CSCDR4 (MXC_CCM_BASE + 0x40) +#define MXC_CCM_CWDR (MXC_CCM_BASE + 0x44) +#define MXC_CCM_CDHIPR (MXC_CCM_BASE + 0x48) +#define MXC_CCM_CDCR (MXC_CCM_BASE + 0x4C) +#define MXC_CCM_CTOR (MXC_CCM_BASE + 0x50) +#define MXC_CCM_CLPCR (MXC_CCM_BASE + 0x54) +#define MXC_CCM_CISR (MXC_CCM_BASE + 0x58) +#define MXC_CCM_CIMR (MXC_CCM_BASE + 0x5C) +#define MXC_CCM_CCOSR (MXC_CCM_BASE + 0x60) +#define MXC_CCM_CGPR (MXC_CCM_BASE + 0x64) +#define MXC_CCM_CCGR0 (MXC_CCM_BASE + 0x68) +#define MXC_CCM_CCGR1 (MXC_CCM_BASE + 0x6C) +#define MXC_CCM_CCGR2 (MXC_CCM_BASE + 0x70) +#define MXC_CCM_CCGR3 (MXC_CCM_BASE + 0x74) +#define MXC_CCM_CCGR4 (MXC_CCM_BASE + 0x78) +#define MXC_CCM_CCGR5 (MXC_CCM_BASE + 0x7C) +#define MXC_CCM_CCGR6 (MXC_CCM_BASE + 0x80) +#define MXC_CCM_CCGR7 (MXC_CCM_BASE + 0x84) +#define MXC_CCM_CMEOR (MXC_CCM_BASE + 0x88) +#define MXC_CCM_CSR2 (MXC_CCM_BASE + 0x8C) +#define MXC_CCM_CLKSEQ_BYPASS (MXC_CCM_BASE + 0x90) +#define MXC_CCM_CLK_SYS (MXC_CCM_BASE + 0x94) +#define MXC_CCM_CLK_DDR (MXC_CCM_BASE + 0x98) +#define MXC_CCM_ELCDIFPIX (MXC_CCM_BASE + 0x9C) +#define MXC_CCM_EPDCPIX (MXC_CCM_BASE + 0xA0) +#define MXC_CCM_DISPLAY_AXI (MXC_CCM_BASE + 0xA4) +#define MXC_CCM_EPDC_AXI (MXC_CCM_BASE + 0xA8) +#define MXC_CCM_GPMI (MXC_CCM_BASE + 0xAC) +#define MXC_CCM_BCH (MXC_CCM_BASE + 0xB0) +#define MXC_CCM_MSHC_XMSCKI (MXC_CCM_BASE + 0xB4) + +/* CCM Register Offsets. */ +#define MXC_CCM_CDCR_OFFSET 0x4C +#define MXC_CCM_CACRR_OFFSET 0x10 +#define MXC_CCM_CDHIPR_OFFSET 0x48 + +/* Define the bits in register CCR */ +#define MXC_CCM_CCR_COSC_EN (1 << 12) +#define MXC_CCM_CCR_FPM_MULT_MASK (1 << 11) +#define MXC_CCM_CCR_CAMP2_EN (1 << 10) +#define MXC_CCM_CCR_CAMP1_EN (1 << 9) +#define MXC_CCM_CCR_FPM_EN (1 << 8) +#define MXC_CCM_CCR_OSCNT_OFFSET (0) +#define MXC_CCM_CCR_OSCNT_MASK (0xFF) + +/* Define the bits in register CCDR */ +/* MX51 */ +#define MXC_CCM_CCDR_HSC_HS_MASK (0x1 << 18) +#define MXC_CCM_CCDR_IPU_HS_MASK (0x1 << 17) +#define MXC_CCM_CCDR_EMI_HS_MASK (0x1 << 16) +/* MX53 */ +#define MXC_CCM_CCDR_IPU_HS_MX53_MASK (0x1 << 21) +#define MXC_CCM_CCDR_EMI_HS_INT2_MASK (0x1 << 20) +#define MXC_CCM_CCDR_EMI_HS_INT1_MASK (0x1 << 19) +#define MXC_CCM_CCDR_EMI_HS_SLOW_MASK (0x1 << 18) +#define MXC_CCM_CCDR_EMI_HS_FAST_MASK (0x1 << 17) +#define MXC_CCM_CCDR_EMI_HS_MASK (0x1 << 16) + +/* Define the bits in register CSR */ +#define MXC_CCM_CSR_COSR_READY (1 << 5) +#define MXC_CCM_CSR_LVS_VALUE (1 << 4) +#define MXC_CCM_CSR_CAMP2_READY (1 << 3) +#define MXC_CCM_CSR_CAMP1_READY (1 << 2) +#define MXC_CCM_CSR_FPM_READY (1 << 1) +#define MXC_CCM_CSR_TEMP_MON_ALARM (1 << 1) +#define MXC_CCM_CSR_REF_EN_B (1 << 0) + +/* Define the bits in register CCSR */ +#define MXC_CCM_CCSR_PLL3_PFD_EN (0x1 << 13) +#define MXC_CCM_CCSR_PLL2_PFD_EN (0x1 << 12) +#define MXC_CCM_CCSR_PLL1_PFD_EN (0x1 << 11) +#define MXC_CCM_CCSR_LP_APM_SEL (0x1 << 10) +#define MXC_CCM_CCSR_LP_APM_SE_MX51L (0x1 << 9) +#define MXC_CCM_CCSR_PLL4_SW_CLK_SEL (1 << 9) +#define MXC_CCM_CCSR_STEP_SEL_OFFSET (7) +#define MXC_CCM_CCSR_STEP_SEL_MASK (0x3 << 7) +#define MXC_CCM_CCSR_STEP_SEL_LP_APM 0 +#define MXC_CCM_CCSR_STEP_SEL_PLL1_BYPASS 1 /* Only when JTAG connected? */ +#define MXC_CCM_CCSR_STEP_SEL_PLL2_DIVIDED 2 +#define MXC_CCM_CCSR_STEP_SEL_PLL3_DIVIDED 3 +#define MXC_CCM_CCSR_PLL2_PODF_OFFSET (5) +#define MXC_CCM_CCSR_PLL2_PODF_MASK (0x3 << 5) +#define MXC_CCM_CCSR_PLL3_PODF_OFFSET (3) +#define MXC_CCM_CCSR_PLL3_PODF_MASK (0x3 << 3) +#define MXC_CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2) /* 0: pll1_main_clk, + 1: step_clk */ +#define MXC_CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1) +#define MXC_CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0) + +/* Define the bits in register CACRR */ +#define MXC_CCM_CACRR_ARM_PODF_OFFSET (0) +#define MXC_CCM_CACRR_ARM_PODF_MASK (0x7) + +/* Define the bits in register CBCDR */ +#define MX50_CCM_CBCDR_WEIM_CLK_SEL (0x1 << 27) +#define MXC_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26) +#define MXC_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) +#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_OFFSET (25) +#define MX50_CCM_CBCDR_PERIPH_CLK_SEL_MASK (0x3 << 25) +#define MXC_CCM_CBCDR_DDR_HF_SEL_OFFSET (30) +#define MXC_CCM_CBCDR_DDR_HF_SEL (0x1 << 30) +#define MXC_CCM_CBCDR_DDR_PODF_OFFSET (27) +#define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27) +#define MX50_CCM_CBCDR_WEIM_PODF_OFFSET (22) +#define MX50_CCM_CBCDR_WEIM_PODF_MASK (0x7 << 22) +#define MXC_CCM_CBCDR_EMI_PODF_OFFSET (22) +#define MXC_CCM_CBCDR_EMI_PODF_MASK (0x7 << 22) +#define MXC_CCM_CBCDR_AXI_B_PODF_OFFSET (19) +#define MXC_CCM_CBCDR_AXI_B_PODF_MASK (0x7 << 19) +#define MXC_CCM_CBCDR_AXI_A_PODF_OFFSET (16) +#define MXC_CCM_CBCDR_AXI_A_PODF_MASK (0x7 << 16) +#define MXC_CCM_CBCDR_NFC_PODF_OFFSET (13) +#define MXC_CCM_CBCDR_NFC_PODF_MASK (0x7 << 13) +#define MXC_CCM_CBCDR_AHB_PODF_OFFSET (10) +#define MXC_CCM_CBCDR_AHB_PODF_MASK (0x7 << 10) +#define MXC_CCM_CBCDR_IPG_PODF_OFFSET (8) +#define MXC_CCM_CBCDR_IPG_PODF_MASK (0x3 << 8) +#define MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET (6) +#define MXC_CCM_CBCDR_PERCLK_PRED1_MASK (0x3 << 6) +#define MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET (3) +#define MXC_CCM_CBCDR_PERCLK_PRED2_MASK (0x7 << 3) +#define MXC_CCM_CBCDR_PERCLK_PODF_OFFSET (0) +#define MXC_CCM_CBCDR_PERCLK_PODF_MASK (0x7) + +/* Define the bits in register CBCMR */ +#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET (16) +#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET (14) +#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET (12) +#define MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET (10) +#define MXC_CCM_CBCMR_DDR_CLK_SEL_MASK (0x3 << 10) +#define MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_OFFSET (8) +#define MXC_CCM_CBCMR_ARM_AXI_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_OFFSET (6) +#define MXC_CCM_CBCMR_IPU_HSP_CLK_SEL_MASK (0x3 << 6) +#define MXC_CCM_CBCMR_GPU_CLK_SEL_OFFSET (4) +#define MXC_CCM_CBCMR_GPU_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_OFFSET (2) +#define MXC_CCM_CBCMR_DBG_APB_CLK_SEL_MASK (0x3 << 2) +#define MXC_CCM_CBCMR_PERCLK_LP_APM_CLK_SEL (0x1 << 1) +#define MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL (0x1 << 0) + +/* Define the bits in register CSCMR1 */ +#define MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_OFFSET (30) +#define MXC_CCM_CSCMR1_SSI_EXT2_CLK_SEL_MASK (0x3 << 30) +#define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_OFFSET (28) +#define MXC_CCM_CSCMR1_SSI_EXT1_CLK_SEL_MASK (0x3 << 28) +#define MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET (26) +#define MXC_CCM_CSCMR1_USB_PHY_CLK_SEL (0x1 << 26) +#define MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET (24) +#define MXC_CCM_CSCMR1_UART_CLK_SEL_MASK (0x3 << 24) +#define MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET (22) +#define MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK (0x3 << 22) +#define MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_OFFSET (20) +#define MXC_CCM_CSCMR1_ESDHC1_MSHC2_CLK_SEL_MASK (0x3 << 20) +#define MXC_CCM_CSCMR1_ESDHC3_CLK_SEL_MX51 (0x1 << 19) +#define MXC_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 19) +#define MXC_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 18) +#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_OFFSET (21) +#define MX50_CCM_CSCMR1_ESDHC1_CLK_SEL_MASK (0x3 << 21) +#define MX50_CCM_CSCMR1_ESDHC2_CLK_SEL (0x1 << 20) +#define MX50_CCM_CSCMR1_ESDHC4_CLK_SEL (0x1 << 19) +#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_OFFSET (16) +#define MX50_CCM_CSCMR1_ESDHC3_CLK_SEL_MASK (0x7 << 16) +#define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_OFFSET (16) +#define MXC_CCM_CSCMR1_ESDHC3_MSHC2_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET (12) +#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CSCMR1_SSI3_CLK_SEL (0x1 << 11) +#define MXC_CCM_CSCMR1_VPU_RCLK_SEL (0x1 << 10) +#define MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_OFFSET (8) +#define MXC_CCM_CSCMR1_SSI_APM_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CSCMR1_TVE_CLK_SEL (0x1 << 7) +#define MXC_CCM_CSCMR1_TVE_EXT_CLK_SEL (0x1 << 6) +#define MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET (4) +#define MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CSCMR1_SPDIF_CLK_SEL_OFFSET (2) +#define MXC_CCM_CSCMR1_SPDIF_CLK_SEL_MASK (0x3 << 2) +#define MXC_CCM_CSCMR1_SSI_EXT2_COM_CLK_SEL (0x1 << 1) +#define MXC_CCM_CSCMR1_SSI_EXT1_COM_CLK_SEL (0x1) + +/* Define the bits in register CSCMR2 */ +#define MXC_CCM_CSCMR2_DI_CLK_SEL_OFFSET(n) (26+n*3) +#define MXC_CCM_CSCMR2_DI_CLK_SEL_MASK(n) (0x7 << (26+n*3)) +#define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_OFFSET (24) +#define MXC_CCM_CSCMR2_CSI_MCLK2_CLK_SEL_MASK (0x3 << 24) +#define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_OFFSET (22) +#define MXC_CCM_CSCMR2_CSI_MCLK1_CLK_SEL_MASK (0x3 << 22) +/* MX51 */ +#define MXC_CCM_CSCMR2_ESC_CLK_SEL_OFFSET (20) +#define MXC_CCM_CSCMR2_ESC_CLK_SEL_MASK (0x3 << 20) +#define MXC_CCM_CSCMR2_HSC2_CLK_SEL_OFFSET (18) +#define MXC_CCM_CSCMR2_HSC2_CLK_SEL_MASK (0x3 << 18) +#define MXC_CCM_CSCMR2_HSC1_CLK_SEL_OFFSET (16) +#define MXC_CCM_CSCMR2_HSC1_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CSCMR2_HSI2C_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCMR2_HSI2C_CLK_SEL_MASK (0x3 << 14) +/* MX53 */ +#define MXC_CCM_CSCMR2_ASRC_CLK_SEL (1<<21) +#define MXC_CCM_CSCMR2_ESAI_PRE_SEL_OFFSET (19) +#define MXC_CCM_CSCMR2_ESAI_PRE_SEL_MASK (0x3 << 19) +#define MXC_CCM_CSCMR2_ESAI_POST_SEL_OFFSET (16) +#define MXC_CCM_CSCMR2_ESAI_POST_SEL_MASK (0x7 << 16) +#define MXC_CCM_CSCMR2_IEEE_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCMR2_IEEE_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CSCMR2_FIRI_CLK_SEL_OFFSET (12) +#define MXC_CCM_CSCMR2_FIRI_CLK_SEL_MASK (0x3 << 12) +/* MX51 */ +#define MXC_CCM_CSCMR2_SIM_CLK_SEL_OFFSET (10) +#define MXC_CCM_CSCMR2_SIM_CLK_SEL_MASK (0x3 << 10) +#define MXC_CCM_CSCMR2_SLIMBUS_COM (0x1 << 9) +#define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCMR2_SLIMBUS_CLK_SEL_MASK (0x7 << 6) +/* MX53 */ +#define MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV (0x1 << 11) +#define MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV (0x1 << 10) +#define MXC_CCM_CSCMR2_LDB_DI1_CLK_SEL (0x1 << 9) +#define MXC_CCM_CSCMR2_LDB_DI0_CLK_SEL (0x1 << 8) +#define MXC_CCM_CSCMR2_CAN_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCMR2_CAN_CLK_SEL_MASK (0x3 << 6) +#define MXC_CCM_CSCMR2_SPDIF1_COM (1 << 5) +#define MXC_CCM_CSCMR2_SPDIF0_COM (1 << 4) +#define MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_OFFSET (2) +#define MXC_CCM_CSCMR2_SPDIF1_CLK_SEL_MASK (0x3 << 2) +#define MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_OFFSET (0) +#define MXC_CCM_CSCMR2_SPDIF0_CLK_SEL_MASK (0x3) + +/* Define the bits in register CSCDR1 */ +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_OFFSET (22) +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR1_ESDHC2_MSHC2_CLK_PODF_MASK (0x7 << 19) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_OFFSET (22) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR1_ESDHC3_MSHC2_CLK_PODF_MASK (0x7 << 19) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CSCDR1_PGC_CLK_PODF_OFFSET (14) +#define MXC_CCM_CSCDR1_PGC_CLK_PODF_MASK (0x3 << 14) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_OFFSET (11) +#define MXC_CCM_CSCDR1_ESDHC1_MSHC2_CLK_PODF_MASK (0x7 << 11) +#define MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET (8) +#define MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK (0x7 << 8) +#define MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET (6) +#define MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK (0x3 << 6) +#define MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET (3) +#define MXC_CCM_CSCDR1_UART_CLK_PRED_MASK (0x7 << 3) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK (0x7) + +/* Define the bits in register CS1CDR and CS2CDR */ +#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET (25) +#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK (0x3F << 25) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_OFFSET (22) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_OFFSET (16) +#define MXC_CCM_CS1CDR_SSI_EXT1_CLK_PODF_MASK (0x3F << 16) +#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET (9) +#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK (0x7 << 9) +#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET (0) +#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK (0x3F) + +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_OFFSET (22) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_OFFSET (16) +#define MXC_CCM_CS2CDR_SSI_EXT2_CLK_PODF_MASK (0x3F << 16) +#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET (6) +#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET (0) +#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK (0x3F) + +/* Define the bits in register CDCDR */ +#define MXC_CCM_CDCDR_TVE_CLK_PRED_OFFSET (28) +#define MXC_CCM_CDCDR_TVE_CLK_PRED_MASK (0x7 << 28) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET (25) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK (0x7 << 25) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET (19) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK (0x3F << 19) +/* MX51 */ +#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET (16) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK (0x7 << 16) +/* MX53 */ +#define MXC_CCM_CDCDR_DI_PLL4_PODF_OFFSET (16) +#define MXC_CCM_CDCDR_DI_PLL4_PODF_MASK (0x7 << 16) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET (9) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CDCDR_DI1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CDCDR_DI1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CDCDR_USB_PHY_PRED_OFFSET (3) +#define MXC_CCM_CDCDR_USB_PHY_PRED_MASK (0x7 << 3) +#define MXC_CCM_CDCDR_USB_PHY_PODF_OFFSET (0) +#define MXC_CCM_CDCDR_USB_PHY_PODF_MASK (0x7) + +/* Define the bits in register CHSCCDR */ +/* MX51 */ +#define MXC_CCM_CHSCCDR_ESC_CLK_PRED_OFFSET (12) +#define MXC_CCM_CHSCCDR_ESC_CLK_PRED_MASK (0x7 << 12) +#define MXC_CCM_CHSCCDR_ESC_CLK_PODF_OFFSET (6) +#define MXC_CCM_CHSCCDR_ESC_CLK_PODF_MASK (0x3F << 6) +#define MXC_CCM_CHSCCDR_HSC2_CLK_PODF_OFFSET (3) +#define MXC_CCM_CHSCCDR_HSC2_CLK_PODF_MASK (0x7 << 3) +#define MXC_CCM_CHSCCDR_HSC1_CLK_PODF_OFFSET (0) +#define MXC_CCM_CHSCCDR_HSC1_CLK_PODF_MASK (0x7) +/* MX53 */ +#define MXC_CCM_CHSCCDR_ESAI_HCKT_SEL_OFFSET (6) +#define MXC_CCM_CHSCCDR_ESAI_HCKT_SEL_MASK (0x3 << 6) +#define MXC_CCM_CHSCCDR_ESAI_HCKR_SEL_OFFSET (4) +#define MXC_CCM_CHSCCDR_ESAI_HCKR_SEL_MASK (0x3 << 4) +#define MXC_CCM_CHSCCDR_SSI2_MLB_SPDIF_SRC_OFFSET (2) +#define MXC_CCM_CHSCCDR_SSI2_MLB_SPDIF_SRC_MASK (0x3 << 2) +#define MXC_CCM_CHSCCDR_SSI1_MLB_SPDIF_SRC_OFFSET (0) +#define MXC_CCM_CHSCCDR_SSI1_MLB_SPDIF_SRC_MASK (0x3) + +/* Define the bits in register CSCDR2 */ +#define MXC_CCM_CSCDR2_ASRC_CLK_PRED_OFFSET (28) +#define MXC_CCM_CSCDR2_ASRC_CLK_PRED_MASK (0x7 << 28) +#define MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET (25) +#define MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK (0x7 << 25) +#define MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK (0x3F << 19) +/* MX51 */ +#define MXC_CCM_CSCDR2_SIM_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR2_SIM_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CSCDR2_SIM_CLK_PODF_OFFSET (9) +#define MXC_CCM_CSCDR2_SIM_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CSCDR2_SLIMBUS_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSCDR2_SLIMBUS_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSCDR2_SLIMBUS_PODF_OFFSET (0) +#define MXC_CCM_CSCDR2_SLIMBUS_PODF_MASK (0x3F) +/* MX53 */ +#define MXC_CCM_CSCDR2_ASRC_CLK_PODF_OFFSET (9) +#define MXC_CCM_CSCDR2_ASRC_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CSCDR2_IEEE_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSCDR2_IEEE_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSCDR2_IEEE_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSCDR2_IEEE_CLK_PODF_MASK (0x3F) + +/* Define the bits in register CSCDR3 */ +#define MXC_CCM_CSCDR3_HSI2C_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR3_HSI2C_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CSCDR3_HSI2C_CLK_PODF_OFFSET (9) +#define MXC_CCM_CSCDR3_HSI2C_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CSCDR3_FIRI_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSCDR3_FIRI_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSCDR3_FIRI_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSCDR3_FIRI_CLK_PODF_MASK (0x3F) + +/* Define the bits in register CSCDR4 */ +#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_OFFSET (16) +#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PRED_MASK (0x7 << 16) +#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_OFFSET (9) +#define MXC_CCM_CSCDR4_CSI_MCLK2_CLK_PODF_MASK (0x3F << 9) +#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_OFFSET (0) +#define MXC_CCM_CSCDR4_CSI_MCLK1_CLK_PODF_MASK (0x3F) + +/* Define the bits in register CDHIPR */ +#define MXC_CCM_CDHIPR_ARM_PODF_BUSY (1 << 16) +#define MXC_CCM_CDHIPR_DDR_HF_CLK_SEL_BUSY (1 << 8) +#define MXC_CCM_CDHIPR_DDR_PODF_BUSY (1 << 7) +#define MXC_CCM_CDHIPR_EMI_CLK_SEL_BUSY (1 << 6) +#define MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY (1 << 5) +#define MXC_CCM_CDHIPR_NFC_IPG_INT_MEM_PODF_BUSY (1 << 4) +#define MXC_CCM_CDHIPR_AHB_PODF_BUSY (1 << 3) +#define MXC_CCM_CDHIPR_EMI_PODF_BUSY (1 << 2) +#define MXC_CCM_CDHIPR_AXI_B_PODF_BUSY (1 << 1) +#define MXC_CCM_CDHIPR_AXI_A_PODF_BUSY (1 << 0) + +/* Define the bits in register CDCR */ +#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ_STATUS (0x1 << 7) +#define MX50_CCM_CDCR_SW_PERIPH_CLK_DIV_REQ (0x1 << 6) +#define MX50_CCM_CDCR_SW_DVFS_EN (0x1 << 5) +#define MXC_CCM_CDCR_ARM_FREQ_SHIFT_DIVIDER (0x1 << 2) +#define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_OFFSET (0) +#define MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK (0x3) + +/* Define the bits in register CLPCR */ +/* MX51 */ +#define MXC_CCM_CLPCR_BYPASS_HSC_LPM_HS (0x1 << 23) +#define MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX51 (0x1 << 22) +#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS_MX51 (0x1 << 21) +#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS_MX51 (0x1 << 20) +/* MX53 */ +#define MXC_CCM_CLPCR_BYPASS_CAN2_LPM_HS (0x1 << 27) +#define MXC_CCM_CLPCR_BYPASS_CAN1_LPM_HS (0x1 << 27) +#define MXC_CCM_CLPCR_BYPASS_SCC_LPM_HS_MX53 (0x1 << 26) +#define MXC_CCM_CLPCR_BYPASS_MAX_LPM_HS (0x1 << 25) +#define MXC_CCM_CLPCR_BYPASS_SDMA_LPM_HS (0x1 << 24) +#define MXC_CCM_CLPCR_BYPASS_EMI_INT2_LPM_HS (0x1 << 23) +#define MX50_CCM_CLPCR_BYPASS_RNGB_LPM_HS (0x1 << 23) +#define MXC_CCM_CLPCR_BYPASS_EMI_INT1_LPM_HS (0x1 << 22) +#define MXC_CCM_CLPCR_BYPASS_EMI_SLOW_LPM_HS (0x1 << 21) +#define MXC_CCM_CLPCR_BYPASS_EMI_FAST_LPM_HS (0x1 << 20) +#define MXC_CCM_CLPCR_BYPASS_EMI_LPM_HS (0x1 << 19) +#define MXC_CCM_CLPCR_BYPASS_IPU_LPM_HS (0x1 << 18) +#define MXC_CCM_CLPCR_BYPASS_RTIC_LPM_HS (0x1 << 17) +#define MXC_CCM_CLPCR_BYPASS_RNGC_LPM_HS (0x1 << 16) +#define MXC_CCM_CLPCR_COSC_PWRDOWN (0x1 << 11) +#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET (9) +#define MXC_CCM_CLPCR_STBY_COUNT_MASK (0x3 << 9) +#define MXC_CCM_CLPCR_VSTBY (0x1 << 8) +#define MXC_CCM_CLPCR_DIS_REF_OSC (0x1 << 7) +#define MXC_CCM_CLPCR_SBYOS (0x1 << 6) +#define MXC_CCM_CLPCR_ARM_CLK_DIS_ON_LPM (0x1 << 5) +#define MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET (3) +#define MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK (0x3 << 3) +#define MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY (0x1 << 2) +#define MXC_CCM_CLPCR_LPM_OFFSET (0) +#define MXC_CCM_CLPCR_LPM_MASK (0x3) + +/* Define the bits in register CISR */ +#define MXC_CCM_CISR_ARM_PODF_LOADED_MX51 (0x1 << 25) +#define MXC_CCM_CISR_ARM_PODF_LOADED (0x1 << 26) +#define MXC_CCM_CISR_TEMP_MON_ALARM (0x1 << 25) +#define MXC_CCM_CISR_EMI_CLK_SEL_LOADED (0x1 << 23) +#define MXC_CCM_CISR_PER_CLK_SEL_LOADED (0x1 << 22) +#define MXC_CCM_CISR_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21) +#define MXC_CCM_CISR_AHB_PODF_LOADED (0x1 << 20) +#define MXC_CCM_CISR_EMI_PODF_LOADED (0x1 << 19) +#define MXC_CCM_CISR_AXI_B_PODF_LOADED (0x1 << 18) +#define MXC_CCM_CISR_AXI_A_PODF_LOADED (0x1 << 17) +#define MXC_CCM_CISR_DIVIDER_LOADED (0x1 << 16) +#define MXC_CCM_CISR_COSC_READY (0x1 << 6) +#define MXC_CCM_CISR_CKIH2_READY (0x1 << 5) +#define MXC_CCM_CISR_CKIH_READY (0x1 << 4) +#define MX50_CCM_CISR_CAMP1_READY (0x1 << 4) +#define MXC_CCM_CISR_FPM_READY (0x1 << 3) +#define MXC_CCM_CISR_LRF_PLL3 (0x1 << 2) +#define MXC_CCM_CISR_LRF_PLL2 (0x1 << 1) +#define MXC_CCM_CISR_LRF_PLL1 (0x1) + +/* Define the bits in register CIMR */ +#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED_MX51 (0x1 << 25) +#define MXC_CCM_CIMR_MASK_EMI_PODF_LOADED_MX51 (0x1 << 20) +#define MXC_CCM_CIMR_MASK_AXI_C_PODF_LOADED_MX51 (0x1 << 19) +#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED (0x1 << 26) +#define MXC_CCM_CIMR_MASK_TEMP_MON_ALARM (0x1 << 25) +#define MXC_CCM_CIMR_MASK_EMI_CLK_SEL_LOADED (0x1 << 23) +#define MXC_CCM_CIMR_MASK_PER_CLK_SEL_LOADED (0x1 << 22) +#define MXC_CCM_CIMR_MASK_NFC_IPG_INT_MEM_PODF_LOADED (0x1 << 21) +#define MXC_CCM_CIMR_MASK_AHB_PODF_LOADED_MX53 (0x1 << 20) +#define MXC_CCM_CIMR_MASK_EMI_SLOW_PODF_LOADED_MX53 (0x1 << 19) +#define MX50_CCM_CIMR_MASK_WEIM_PODF_LOADED (0x1 << 19) +#define MXC_CCM_CIMR_MASK_AXI_B_PODF_LOADED (0x1 << 18) +#define MXC_CCM_CIMR_MASK_AXI_A_PODF_LOADED (0x1 << 17) +#define MXC_CCM_CIMR_MASK_DIVIDER_LOADED (0x1 << 16) +/* MX51 */ +#define MXC_CCM_CIMR_MASK_COSC_READY_MX51 (0x1 << 5) +#define MXC_CCM_CIMR_MASK_CKIH_READY (0x1 << 4) +#define MXC_CCM_CIMR_MASK_FPM_READY (0x1 << 3) +/* MX53/MX50 */ +#define MXC_CCM_CIMR_MASK_COSC_READY (0x1 << 6) +#define MXC_CCM_CIMR_MASK_CAMP2_READY (0x1 << 5) +#define MXC_CCM_CIMR_MASK_CAMP1_READY (0x1 << 4) +#define MXC_CCM_CIMR_MASK_LRF_PLL4 (0x1 << 3) +#define MXC_CCM_CIMR_MASK_LRF_PLL3 (0x1 << 2) +#define MXC_CCM_CIMR_MASK_LRF_PLL2 (0x1 << 1) +#define MXC_CCM_CIMR_MASK_LRF_PLL1 (0x1) + +/* Define the bits in register CCOSR */ +#define MXC_CCM_CCOSR_CKO2_EN_OFFSET (0x1 << 24) +#define MXC_CCM_CCOSR_CKO2_DIV_OFFSET (21) +#define MXC_CCM_CCOSR_CKO2_DIV_MASK (0x7 << 21) +#define MXC_CCM_CCOSR_CKO2_SEL_OFFSET (16) +#define MXC_CCM_CCOSR_CKO2_SEL_MASK (0x1F << 16) +#define MXC_CCM_CCOSR_CKOL_EN (0x1 << 7) +#define MXC_CCM_CCOSR_CKOL_DIV_OFFSET (4) +#define MXC_CCM_CCOSR_CKOL_DIV_MASK (0x7 << 4) +#define MXC_CCM_CCOSR_CKOL_SEL_OFFSET (0) +#define MXC_CCM_CCOSR_CKOL_SEL_MASK (0xF) + +/* Define the bits in registers CGPR */ +#define MXC_CCM_CGPR_ARM_CLK_INPUT_SEL (0x1 << 24) +#define MXC_CCM_CGPR_ARM_ASYNC_REF_EN (0x1 << 23) +#define MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE (0x1 << 4) +#define MXC_CCM_CGPR_FPM_SEL (0x1 << 3) +#define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_OFFSET (0) +#define MXC_CCM_CGPR_VL_L2BIST_CLKDIV_MASK (0x7) + +#define MX50_CCM_CCOSR_CKO1_SLOW_SEL (0x1 << 8) +#define MX50_CCM_CCOSR_CKO1_EN (0x1 << 7) +#define MX50_CCM_CCOSR_CKO1_DIV_OFFSET (4) +#define MX50_CCM_CCOSR_CKO1_DIV_MASK (0x7 << 4) +#define MX50_CCM_CCOSR_CKO1_SEL_OFFSET (0) +#define MX50_CCM_CCOSR_CKO1_SEL_MASK (0xF) + +/* Define the bits in registers CCGRx */ +#define MXC_CCM_CCGRx_CG_MASK 0x3 +#define MXC_CCM_CCGRx_MOD_OFF 0x0 +#define MXC_CCM_CCGRx_MOD_ON 0x3 +#define MXC_CCM_CCGRx_MOD_IDLE 0x1 + +#define MXC_CCM_CCGRx_CG15_MASK (0x3 << 30) +#define MXC_CCM_CCGRx_CG14_MASK (0x3 << 28) +#define MXC_CCM_CCGRx_CG13_MASK (0x3 << 26) +#define MXC_CCM_CCGRx_CG12_MASK (0x3 << 24) +#define MXC_CCM_CCGRx_CG11_MASK (0x3 << 22) +#define MXC_CCM_CCGRx_CG10_MASK (0x3 << 20) +#define MXC_CCM_CCGRx_CG9_MASK (0x3 << 18) +#define MXC_CCM_CCGRx_CG8_MASK (0x3 << 16) +#define MXC_CCM_CCGRx_CG5_MASK (0x3 << 10) +#define MXC_CCM_CCGRx_CG4_MASK (0x3 << 8) +#define MXC_CCM_CCGRx_CG3_MASK (0x3 << 6) +#define MXC_CCM_CCGRx_CG2_MASK (0x3 << 4) +#define MXC_CCM_CCGRx_CG1_MASK (0x3 << 2) +#define MXC_CCM_CCGRx_CG0_MASK (0x3 << 0) + +#define MXC_CCM_CCGRx_CG15_OFFSET 30 +#define MXC_CCM_CCGRx_CG14_OFFSET 28 +#define MXC_CCM_CCGRx_CG13_OFFSET 26 +#define MXC_CCM_CCGRx_CG12_OFFSET 24 +#define MXC_CCM_CCGRx_CG11_OFFSET 22 +#define MXC_CCM_CCGRx_CG10_OFFSET 20 +#define MXC_CCM_CCGRx_CG9_OFFSET 18 +#define MXC_CCM_CCGRx_CG8_OFFSET 16 +#define MXC_CCM_CCGRx_CG7_OFFSET 14 +#define MXC_CCM_CCGRx_CG6_OFFSET 12 +#define MXC_CCM_CCGRx_CG5_OFFSET 10 +#define MXC_CCM_CCGRx_CG4_OFFSET 8 +#define MXC_CCM_CCGRx_CG3_OFFSET 6 +#define MXC_CCM_CCGRx_CG2_OFFSET 4 +#define MXC_CCM_CCGRx_CG1_OFFSET 2 +#define MXC_CCM_CCGRx_CG0_OFFSET 0 + +#define MXC_CCM_CCGR5_CG6_1_OFFSET 12 +#define MXC_CCM_CCGR5_CG6_2_OFFSET 13 + +/* Define the bits in registers CSR2 */ +#define MXC_CCM_CSR2_ELCDIF_PIX_BUSY (0x1 << 9) +#define MXC_CCM_CSR2_EPDC_PIX_BUSY (0x1 << 8) +#define MXC_CCM_CSR2_EPDC_AXI_BUSY (0x1 << 4) +#define MXC_CCM_CSR2_DISPLAY_AXI_BUSY (0x1 << 3) + +/* Define the bits in registers CLKSEQ_BYPASS */ +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_OFFSET 14 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_ELCDIF_PIX_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_OFFSET 12 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_PIX_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_OFFSET 6 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_GPMI_CLK_SEL_MASK (0x3 << 6) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_OFFSET 8 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_BCH_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_OFFSET 4 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_EPDC_AXI_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_OFFSET 2 +#define MXC_CCM_CLKSEQ_BYPASS_BYPASS_DISPLAY_AXI_CLK_SEL_MASK (0x3 << 2) + +/* Define the bits in registers CLK_SYS */ +#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_OFFSET (30) +#define MXC_CCM_CLK_SYS_SYS_XTAL_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_OFFSET (28) +#define MXC_CCM_CLK_SYS_SYS_PLL_CLKGATE_MASK (0x3 << 28) +#define MXC_CCM_CLK_SYS_DIV_XTAL_OFFSET (6) +#define MXC_CCM_CLK_SYS_DIV_XTAL_MASK (0xF << 6) +#define MXC_CCM_CLK_SYS_DIV_PLL_OFFSET (0) +#define MXC_CCM_CLK_SYS_DIV_PLL_MASK (0x3F) + +/* Define the bits in registers CLK_DDR */ +#define MXC_CCM_CLK_DDR_DDR_CLKGATE_OFFSET (30) +#define MXC_CCM_CLK_DDR_DDR_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_CLK_DDR_DDR_PFD_SEL (1 << 6) +#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_OFFSET (0) +#define MXC_CCM_CLK_DDR_DDR_DIV_PLL_MASK (0x3F) + +/* Define the bits in register DISPLAY_AXI */ +#define MXC_CCM_DISPLAY_AXI_CLKGATE_OFFSET (30) +#define MXC_CCM_DISPLAY_AXI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_DISPLAY_AXI_PXP_ASM_EN (1 << 13) +#define MXC_CCM_DISPLAY_AXI_PXP_ASM_DIV_MASK (0x7 << 10) +#define MXC_CCM_DISPLAY_AXI_PXP_ASM_DIV_OFFSET 10 +#define MXC_CCM_DISPLAY_AXI_DIV_OFFSET (0) +#define MXC_CCM_DISPLAY_AXI_DIV_MASK (0x3F) + +/* Define the bits in register EPDC_AXI */ +#define MXC_CCM_EPDC_AXI_CLKGATE_OFFSET (30) +#define MXC_CCM_EPDC_AXI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_EPDC_AXI_ASM_EN (1 << 9) +#define MXC_CCM_EPDC_AXI_ASM_DIV_OFFSET (6) +#define MXC_CCM_EPDC_AXI_ASM_DIV_MASK (0x7 << 6) +#define MXC_CCM_EPDC_AXI_DIV_OFFSET (0) +#define MXC_CCM_EPDC_AXI_DIV_MASK (0x3F) + +/* Define the bits in register EPDCPIX */ +#define MXC_CCM_EPDC_PIX_CLKGATE_OFFSET (30) +#define MXC_CCM_EPDC_PIX_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_EPDC_PIX_CLK_PRED_OFFSET (12) +#define MXC_CCM_EPDC_PIX_CLK_PRED_MASK (0x3 << 12) +#define MXC_CCM_EPDC_PIX_CLK_PODF_OFFSET (0) +#define MXC_CCM_EPDC_PIX_CLK_PODF_MASK (0xFFF) + +/* Define the bits in register ELCDIFPIX */ +#define MXC_CCM_ELCDIFPIX_CLKGATE_OFFSET (30) +#define MXC_CCM_ELCDIFPIX_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_ELCDIFPIX_CLK_PRED_OFFSET (12) +#define MXC_CCM_ELCDIFPIX_CLK_PRED_MASK (0x3 << 12) +#define MXC_CCM_ELCDIFPIX_CLK_PODF_OFFSET (0) +#define MXC_CCM_ELCDIFPIX_CLK_PODF_MASK (0xFFF) + + +/* Define the bits in register GPMI */ +#define MXC_CCM_GPMI_CLKGATE_OFFSET (30) +#define MXC_CCM_GPMI_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_GPMI_CLK_DIV_OFFSET (0) +#define MXC_CCM_GPMI_CLK_DIV_MASK (0x3F) + +/* Define the bits in register BCH */ +#define MXC_CCM_BCH_CLKGATE_OFFSET (30) +#define MXC_CCM_BCH_CLKGATE_MASK (0x3 << 30) +#define MXC_CCM_BCH_CLK_DIV_OFFSET (0) +#define MXC_CCM_BCH_CLK_DIV_MASK (0x3F) + +#define MXC_GPC_BASE (MX51_IO_ADDRESS(MX51_GPC_BASE_ADDR)) +#define MXC_DPTC_LP_BASE (MXC_GPC_BASE + 0x80) +#define MXC_DPTC_GP_BASE (MXC_GPC_BASE + 0x100) +#define MXC_DVFS_CORE_BASE (MXC_GPC_BASE + 0x180) +#define MXC_DVFS_PER_BASE (MXC_GPC_BASE + 0x1C4) +#define MXC_PGC_IPU_BASE (MXC_GPC_BASE + 0x220) +#define MXC_PGC_VPU_BASE (MXC_GPC_BASE + 0x240) +#define MXC_PGC_GPU_BASE (MXC_GPC_BASE + 0x260) +#define MXC_SRPG_NEON_BASE (MXC_GPC_BASE + 0x280) +#define MXC_SRPG_ARM_BASE (MXC_GPC_BASE + 0x2A0) +#define MXC_SRPG_EMPGC0_BASE (MXC_GPC_BASE + 0x2C0) +#define MXC_SRPG_EMPGC1_BASE (MXC_GPC_BASE + 0x2D0) +#define MXC_SRPG_MEGAMIX_BASE (MXC_GPC_BASE + 0x2E0) +#define MXC_SRPG_EMI_BASE (MXC_GPC_BASE + 0x300) + +/* CORTEXA8 platform */ +extern void __iomem *arm_plat_base; +#define MXC_CORTEXA8_BASE (arm_plat_base) +#define MXC_CORTEXA8_PLAT_PVID (arm_plat_base + 0x0) +#define MXC_CORTEXA8_PLAT_GPC (arm_plat_base + 0x4) +#define MXC_CORTEXA8_PLAT_PIC (arm_plat_base + 0x8) +#define MXC_CORTEXA8_PLAT_LPC (arm_plat_base + 0xC) +#define MXC_CORTEXA8_PLAT_NEON_LPC (arm_plat_base + 0x10) +#define MXC_CORTEXA8_PLAT_ICGC (arm_plat_base + 0x14) +#define MXC_CORTEXA8_PLAT_AMC (arm_plat_base + 0x18) +#define MXC_CORTEXA8_PLAT_NMC (arm_plat_base + 0x20) +#define MXC_CORTEXA8_PLAT_NMS (arm_plat_base + 0x24) + +/* DVFS CORE */ +#define MXC_DVFSTHRS (MXC_DVFS_CORE_BASE + 0x00) +#define MXC_DVFSCOUN (MXC_DVFS_CORE_BASE + 0x04) +#define MXC_DVFSSIG1 (MXC_DVFS_CORE_BASE + 0x08) +#define MXC_DVFSSIG0 (MXC_DVFS_CORE_BASE + 0x0C) +#define MXC_DVFSGPC0 (MXC_DVFS_CORE_BASE + 0x10) +#define MXC_DVFSGPC1 (MXC_DVFS_CORE_BASE + 0x14) +#define MXC_DVFSGPBT (MXC_DVFS_CORE_BASE + 0x18) +#define MXC_DVFSEMAC (MXC_DVFS_CORE_BASE + 0x1C) +#define MXC_DVFSCNTR (MXC_DVFS_CORE_BASE + 0x20) +#define MXC_DVFSLTR0_0 (MXC_DVFS_CORE_BASE + 0x24) +#define MXC_DVFSLTR0_1 (MXC_DVFS_CORE_BASE + 0x28) +#define MXC_DVFSLTR1_0 (MXC_DVFS_CORE_BASE + 0x2C) +#define MXC_DVFSLTR1_1 (MXC_DVFS_CORE_BASE + 0x30) +#define MXC_DVFSPT0 (MXC_DVFS_CORE_BASE + 0x34) +#define MXC_DVFSPT1 (MXC_DVFS_CORE_BASE + 0x38) +#define MXC_DVFSPT2 (MXC_DVFS_CORE_BASE + 0x3C) +#define MXC_DVFSPT3 (MXC_DVFS_CORE_BASE + 0x40) + +/* DVFS PER */ +#define MXC_DVFSPER_LTR0 (MXC_DVFS_PER_BASE) +#define MXC_DVFSPER_LTR1 (MXC_DVFS_PER_BASE + 0x04) +#define MXC_DVFSPER_LTR2 (MXC_DVFS_PER_BASE + 0x08) +#define MXC_DVFSPER_LTR3 (MXC_DVFS_PER_BASE + 0x0C) +#define MXC_DVFSPER_LTBR0 (MXC_DVFS_PER_BASE + 0x10) +#define MXC_DVFSPER_LTBR1 (MXC_DVFS_PER_BASE + 0x14) +#define MXC_DVFSPER_PMCR0 (MXC_DVFS_PER_BASE + 0x18) +#define MXC_DVFSPER_PMCR1 (MXC_DVFS_PER_BASE + 0x1C) + +/* GPC */ +#define MXC_GPC_CNTR (MXC_GPC_BASE + 0x0) +#define MXC_GPC_PGR (MXC_GPC_BASE + 0x4) +#define MXC_GPC_VCR (MXC_GPC_BASE + 0x8) +#define MXC_GPC_CNTR_OFFSET 0x0 +#define MXC_GPC_PGR_OFFSET 0x4 +#define MXC_GPC_VCR_OFFSET 0x8 + +#define MXC_CORTEXA8_PLAT_LPC_DSM (1 << 0) +#define MXC_CORTEXA8_PLAT_LPC_DBG_DSM (1 << 1) + +/* SRPG */ +#define MXC_SRPG_NEON_SRPGCR (MXC_SRPG_NEON_BASE + 0x0) +#define MXC_SRPG_NEON_PUPSCR (MXC_SRPG_NEON_BASE + 0x4) +#define MXC_SRPG_NEON_PDNSCR (MXC_SRPG_NEON_BASE + 0x8) + +#define MXC_SRPG_ARM_SRPGCR (MXC_SRPG_ARM_BASE + 0x0) +#define MXC_SRPG_ARM_PUPSCR (MXC_SRPG_ARM_BASE + 0x4) +#define MXC_SRPG_ARM_PDNSCR (MXC_SRPG_ARM_BASE + 0x8) + +#define MXC_SRPG_EMPGC0_SRPGCR (MXC_SRPG_EMPGC0_BASE + 0x0) +#define MXC_SRPG_EMPGC0_PUPSCR (MXC_SRPG_EMPGC0_BASE + 0x4) +#define MXC_SRPG_EMPGC0_PDNSCR (MXC_SRPG_EMPGC0_BASE + 0x8) + +#define MXC_SRPG_EMPGC1_SRPGCR (MXC_SRPG_EMPGC1_BASE + 0x0) +#define MXC_SRPG_EMPGC1_PUPSCR (MXC_SRPG_EMPGC1_BASE + 0x4) +#define MXC_SRPG_EMPGC1_PDNSCR (MXC_SRPG_EMPGC1_BASE + 0x8) + +#define MXC_SRPG_MEGAMIX_SRPGCR (MXC_SRPG_MEGAMIX_BASE + 0x0) +#define MXC_SRPG_MEGAMIX_PUPSCR (MXC_SRPG_MEGAMIX_BASE + 0x4) +#define MXC_SRPG_MEGAMIX_PDNSCR (MXC_SRPG_MEGAMIX_BASE + 0x8) + +#define MXC_SRPGC_EMI_SRPGCR (MXC_SRPGC_EMI_BASE + 0x0) +#define MXC_SRPGC_EMI_PUPSCR (MXC_SRPGC_EMI_BASE + 0x4) +#define MXC_SRPGC_EMI_PDNSCR (MXC_SRPGC_EMI_BASE + 0x8) + +#endif /* __ARCH_ARM_MACH_MX51_CRM_REGS_H__ */ diff --git a/arch/arm/mach-mx5/devices-imx50.h b/arch/arm/mach-mx5/devices-imx50.h new file mode 100755 index 00000000..8cba79c4 --- /dev/null +++ b/arch/arm/mach-mx5/devices-imx50.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2010-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <mach/mx50.h> +#include <mach/devices-common.h> + +extern const struct imx_imx_uart_1irq_data imx50_imx_uart_data[]; +#define imx50_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx50_imx_uart_data[id], pdata) + +extern const struct imx_srtc_data imx50_imx_srtc_data __initconst; +#define imx50_add_srtc() \ + imx_add_srtc(&imx50_imx_srtc_data) + +extern const struct imx_dma_res_data imx50_dma_res_data __initconst; +#define imx50_add_dma() imx_add_dma(&imx50_dma_res_data); + +extern const struct imx_fec_data imx50_fec_data; +#define imx50_add_fec(pdata) \ + imx_add_fec(&imx50_fec_data, pdata) + +extern const struct imx_imx_i2c_data imx50_imx_i2c_data[]; +#define imx50_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx50_imx_i2c_data[id], pdata) +extern const struct imx_mxc_gpu_data imx50_gpu_data __initconst; +extern const struct imx_pxp_data imx50_pxp_data __initconst; +#define imx50_add_imx_pxp() \ + imx_add_imx_pxp(&imx50_pxp_data) + +#define imx50_add_imx_pxp_client() \ + imx_add_imx_pxp_client() + +extern const struct imx_epdc_data imx50_epdc_data __initconst; +#define imx50_add_imx_epdc(pdata) \ + imx_add_imx_epdc(&imx50_epdc_data, pdata) + +#define imx50_add_mxc_gpu(pdata) \ + imx_add_mxc_gpu(&imx50_gpu_data, pdata) +extern const struct imx_sdhci_esdhc_imx_data imx50_sdhci_esdhc_imx_data[] __initconst; +#define imx50_add_sdhci_esdhc_imx(id, pdata) \ + imx_add_sdhci_esdhc_imx(&imx50_sdhci_esdhc_imx_data[id], pdata) + +extern const struct imx_otp_data imx50_otp_data __initconst; +#define imx50_add_otp() \ + imx_add_otp(&imx50_otp_data); + +extern const struct imx_viim_data imx50_viim_data __initconst; +#define imx50_add_viim() \ + imx_add_viim(&imx50_viim_data) + +extern const struct imx_dcp_data imx50_dcp_data __initconst; +#define imx50_add_dcp() \ + imx_add_dcp(&imx50_dcp_data); + +extern const struct imx_rngb_data imx50_rngb_data __initconst; +#define imx50_add_rngb() \ + imx_add_rngb(&imx50_rngb_data); +extern const struct imx_perfmon_data imx50_perfmon_data __initconst; +#define imx50_add_perfmon() \ + imx_add_perfmon(&imx50_perfmon_data); +#define imx50_add_gpmi(platform_data) imx_add_gpmi(platform_data); + +extern const struct imx_perfmon_data imx50_perfmon_data __initconst; +#define imx50_add_perfmon() \ + imx_add_perfmon(&imx50_perfmon_data); + +extern const struct imx_spi_imx_data imx50_cspi_data[] __initconst; +#define imx50_add_cspi(id, pdata) \ + imx_add_spi_imx(&imx50_cspi_data[id], pdata) + +extern const struct imx_dvfs_core_data imx50_dvfs_core_data __initconst; +#define imx50_add_dvfs_core(pdata) \ + imx_add_dvfs_core(&imx50_dvfs_core_data, pdata) + +#define imx50_add_busfreq(pdata) imx_add_busfreq(pdata) + + diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h new file mode 100755 index 00000000..421e9f68 --- /dev/null +++ b/arch/arm/mach-mx5/devices-imx51.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * 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. + */ +#include <mach/mx51.h> +#include <mach/devices-common.h> + +extern const struct imx_fec_data imx51_fec_data; +#define imx51_add_fec(pdata) \ + imx_add_fec(&imx51_fec_data, pdata) + +extern const struct imx_imx_i2c_data imx51_imx_i2c_data[]; +#define imx51_add_imx_i2c(id, pdata) \ +extern const struct imx_srtc_data imx51_imx_srtc_data __initconst; +#define imx51_add_srtc() \ + imx_add_srtc(&imx51_imx_srtc_data) + + imx_add_imx_i2c(&imx51_imx_i2c_data[id], pdata) + +extern const struct imx_imx_ssi_data imx51_imx_ssi_data[]; +#define imx51_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx51_imx_ssi_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx51_imx_uart_data[]; +#define imx51_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx51_imx_uart_data[id], pdata) + +extern const struct imx_mxc_nand_data imx51_mxc_nand_data; +#define imx51_add_mxc_nand(pdata) \ + imx_add_mxc_nand(&imx51_mxc_nand_data, pdata) + +extern const struct imx_sdhci_esdhc_imx_data imx51_sdhci_esdhc_imx_data[]; +#define imx51_add_sdhci_esdhc_imx(id, pdata) \ + imx_add_sdhci_esdhc_imx(&imx51_sdhci_esdhc_imx_data[id], pdata) + +extern const struct imx_spi_imx_data imx51_cspi_data; +#define imx51_add_cspi(pdata) \ + imx_add_spi_imx(&imx51_cspi_data, pdata) + +extern const struct imx_spi_imx_data imx51_ecspi_data[]; +#define imx51_add_ecspi(id, pdata) \ + imx_add_spi_imx(&imx51_ecspi_data[id], pdata) + +extern const struct imx_imx2_wdt_data imx51_imx2_wdt_data[]; +#define imx51_add_imx2_wdt(id, pdata) \ + imx_add_imx2_wdt(&imx51_imx2_wdt_data[id]) + +extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[]; +#define imx51_add_mxc_pwm(id) \ + imx_add_mxc_pwm(&imx51_mxc_pwm_data[id]) + +extern const struct imx_imx_keypad_data imx51_imx_keypad_data; +#define imx51_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx51_imx_keypad_data, pdata) +extern const struct imx_mxc_gpu_data imx51_gpu_data __initconst; +#define imx51_add_mxc_gpu(pdata) \ + imx_add_mxc_gpu(&imx51_gpu_data, pdata) + +extern const struct imx_mxc_scc2_data imx51_mxc_scc2_data __initconst; +#define imx51_add_mxc_scc2() \ + imx_add_mxc_scc2(&imx51_mxc_scc2_data) + +extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst; +#define imx51_add_mxc_pwm(id) \ + imx_add_mxc_pwm(&imx51_mxc_pwm_data[id]) + +#define imx51_add_mxc_pwm_backlight(id, pdata) \ + platform_device_register_resndata(NULL, "pwm-backlight",\ + id, NULL, 0, pdata, sizeof(*pdata)); + +extern const struct imx_ipuv3_data imx51_ipuv3_data __initconst; +#define imx51_add_ipuv3(id, pdata) imx_add_ipuv3(id, &imx51_ipuv3_data, pdata) +#define imx51_add_ipuv3fb(id, pdata) imx_add_ipuv3_fb(id, pdata) + +extern const struct imx_vpu_data imx51_vpu_data __initconst; +#define imx51_add_vpu() imx_add_vpu(&imx51_vpu_data) + +extern const struct imx_tve_data imx51_tve_data __initconst; +#define imx51_add_tve(pdata) \ + imx_add_tve(&imx51_tve_data, pdata) + +#define imx51_add_lcdif(pdata) \ + platform_device_register_resndata(NULL, "mxc_lcdif",\ + 0, NULL, 0, pdata, sizeof(*pdata)); + +#define imx51_add_v4l2_output(id) \ + platform_device_register_resndata(NULL, "mxc_v4l2_output",\ + id, NULL, 0, NULL, 0); + +#define imx51_add_v4l2_capture(id) \ + platform_device_register_resndata(NULL, "mxc_v4l2_capture",\ + id, NULL, 0, NULL, 0); + +extern const struct imx_spdif_data imx51_imx_spdif_data __initconst; +#define imx51_add_spdif(pdata) imx_add_spdif(&imx51_imx_spdif_data, pdata) + +extern const struct imx_spdif_dai_data imx51_spdif_dai_data __initconst; +#define imx51_add_spdif_dai() imx_add_spdif_dai(&imx51_spdif_dai_data) + +#define imx51_add_spdif_audio_device(pdata) imx_add_spdif_audio_device() + +extern const struct imx_dvfs_core_data imx51_dvfs_core_data __initconst; +#define imx51_add_dvfs_core(pdata) \ + imx_add_dvfs_core(&imx51_dvfs_core_data, pdata) + +#define imx51_add_busfreq(pdata) imx_add_busfreq(pdata) + diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h new file mode 100755 index 00000000..50b52146 --- /dev/null +++ b/arch/arm/mach-mx5/devices-imx53.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010 Yong Shen. <Yong.Shen@linaro.org> + * + * 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. + */ +#include <mach/mx53.h> +#include <mach/devices-common.h> + +extern const struct imx_fec_data imx53_fec_data; +#define imx53_add_fec(pdata) \ + imx_add_fec(&imx53_fec_data, pdata) + +extern const struct imx_imx_uart_1irq_data imx53_imx_uart_data[]; +#define imx53_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx53_imx_uart_data[id], pdata) + + +extern const struct imx_imx_i2c_data imx53_imx_i2c_data[]; +#define imx53_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx53_imx_i2c_data[id], pdata) + +extern const struct imx_sdhci_esdhc_imx_data imx53_sdhci_esdhc_imx_data[]; +#define imx53_add_sdhci_esdhc_imx(id, pdata) \ + imx_add_sdhci_esdhc_imx(&imx53_sdhci_esdhc_imx_data[id], pdata) + +extern const struct imx_spi_imx_data imx53_ecspi_data[]; +#define imx53_add_ecspi(id, pdata) \ + imx_add_spi_imx(&imx53_ecspi_data[id], pdata) + +extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[]; +#define imx53_add_imx2_wdt(id, pdata) \ + imx_add_imx2_wdt(&imx53_imx2_wdt_data[id]) + +extern const struct imx_mxc_pwm_data imx53_mxc_pwm_data[] __initconst; +#define imx53_add_mxc_pwm(id) \ + imx_add_mxc_pwm(&imx53_mxc_pwm_data[id]) + +#define imx53_add_mxc_pwm_backlight(id, pdata) \ + platform_device_register_resndata(NULL, "pwm-backlight",\ + id, NULL, 0, pdata, sizeof(*pdata)); + +extern const struct imx_ipuv3_data imx53_ipuv3_data __initconst; +#define imx53_add_ipuv3(id, pdata) imx_add_ipuv3(id, &imx53_ipuv3_data, pdata) +#define imx53_add_ipuv3fb(id, pdata) imx_add_ipuv3_fb(id, pdata) + +extern const struct imx_vpu_data imx53_vpu_data __initconst; +#define imx53_add_vpu() imx_add_vpu(&imx53_vpu_data) + +extern const struct imx_tve_data imx53_tve_data __initconst; +#define imx53_add_tve(pdata) \ + imx_add_tve(&imx53_tve_data, pdata) + +extern const struct imx_dvfs_core_data imx53_dvfs_core_data __initconst; +#define imx53_add_dvfs_core(pdata) \ + imx_add_dvfs_core(&imx53_dvfs_core_data, pdata) + +#define imx53_add_busfreq(pdata) imx_add_busfreq(pdata) + +extern const struct imx_srtc_data imx53_imx_srtc_data __initconst; +#define imx53_add_srtc() \ + imx_add_srtc(&imx53_imx_srtc_data) + +#define imx53_add_lcdif(pdata) \ + platform_device_register_resndata(NULL, "mxc_lcdif",\ + 0, NULL, 0, pdata, sizeof(*pdata)); + +#define imx53_add_v4l2_output(id) \ + platform_device_register_resndata(NULL, "mxc_v4l2_output",\ + id, NULL, 0, NULL, 0); + +#define imx53_add_v4l2_capture(id) \ + platform_device_register_resndata(NULL, "mxc_v4l2_capture",\ + id, NULL, 0, NULL, 0); + +extern const struct imx_ahci_data imx53_ahci_data[] __initconst; +#define imx53_add_ahci(id, pdata) \ + imx_add_ahci(&imx53_ahci_data[id], pdata) + +extern const struct imx_imx_ssi_data imx53_imx_ssi_data[] __initconst; +#define imx53_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx53_imx_ssi_data[id], pdata) + +extern const struct imx_iim_data imx53_imx_iim_data __initconst; +#define imx53_add_iim(pdata) \ + imx_add_iim(&imx53_imx_iim_data, pdata) + +extern const struct imx_mxc_gpu_data imx53_gpu_data __initconst; +#define imx53_add_mxc_gpu(pdata) \ + imx_add_mxc_gpu(&imx53_gpu_data, pdata) + +extern const struct imx_ldb_data imx53_ldb_data __initconst; +#define imx53_add_ldb(pdata) \ + imx_add_ldb(&imx53_ldb_data, pdata); + +extern const struct imx_mxc_scc2_data imx53_mxc_scc2_data __initconst; +#define imx53_add_mxc_scc2() \ + imx_add_mxc_scc2(&imx53_mxc_scc2_data) + +extern const struct imx_spdif_data imx53_imx_spdif_data __initconst; +#define imx53_add_spdif(pdata) imx_add_spdif(&imx53_imx_spdif_data, pdata) + +extern const struct imx_spdif_dai_data imx53_spdif_dai_data __initconst; +#define imx53_add_spdif_dai() imx_add_spdif_dai(&imx53_spdif_dai_data) + +#define imx53_add_spdif_audio_device(pdata) imx_add_spdif_audio_device() +extern const struct imx_imx_esai_data imx53_imx_esai_data[] __initconst; +#define imx53_add_imx_esai(id, pdata) \ + imx_add_imx_esai(&imx53_imx_esai_data[id], pdata) + +extern struct platform_device imx_ahci_device_hwmon; diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c new file mode 100755 index 00000000..f6f3f68e --- /dev/null +++ b/arch/arm/mach-mx5/devices.c @@ -0,0 +1,283 @@ +/* + * Copyright 2009 Amit Kucheria <amit.kucheria@canonical.com> + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <mach/hardware.h> +#include <mach/imx-uart.h> +#include <mach/irqs.h> + +static struct resource mxc_hsi2c_resources[] = { + { + .start = MX51_HSI2C_DMA_BASE_ADDR, + .end = MX51_HSI2C_DMA_BASE_ADDR + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_HS_I2C, + .end = MX51_MXC_INT_HS_I2C, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_hsi2c_device = { + .name = "imx-i2c", + .id = 2, + .num_resources = ARRAY_SIZE(mxc_hsi2c_resources), + .resource = mxc_hsi2c_resources +}; + +struct platform_device mxc_pm_device = { + .name = "mx5_pm", + .id = 0, +}; + +static u64 usb_dma_mask = DMA_BIT_MASK(32); + +static struct resource usbotg_udc_resources[] = { + { + .start = MX51_OTG_BASE_ADDR, + .end = MX51_OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +/* OTG gadget device */ +struct platform_device mxc_usbdr_udc_device = { + .name = "fsl-usb2-udc", + .id = -1, + .num_resources = ARRAY_SIZE(usbotg_udc_resources), + .resource = usbotg_udc_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource usbotg_host_resources[] = { + { + .start = MX51_OTG_BASE_ADDR, + .end = MX51_OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_usbdr_host_device = { + .name = "fsl-ehci", + .id = 0, + .num_resources = ARRAY_SIZE(usbotg_host_resources), + .resource = usbotg_host_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource usbotg_wakeup_resources[] = { + { + .start = MX51_MXC_INT_USB_OTG,/* wakeup irq */ + .flags = IORESOURCE_IRQ, + }, + { + .start = MX51_MXC_INT_USB_OTG,/* usb core irq */ + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_usbdr_wakeup_device = { + .name = "usb_wakeup", + .id = 0, + .num_resources = ARRAY_SIZE(usbotg_wakeup_resources), + .resource = usbotg_wakeup_resources, +}; + +static struct resource usbotg_xcvr_resources[] = { + { + .start = MX51_OTG_BASE_ADDR, + .end = MX51_OTG_BASE_ADDR + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_OTG, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_usbdr_otg_device = { + .name = "fsl-usb2-otg", + .id = -1, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, + .resource = usbotg_xcvr_resources, + .num_resources = ARRAY_SIZE(usbotg_xcvr_resources), +}; + +static struct resource usbh1_resources[] = { + { + .start = MX51_OTG_BASE_ADDR + 0x200, + .end = MX51_OTG_BASE_ADDR + 0x200 + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_H1, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_usbh1_device = { + .name = "fsl-ehci", + .id = 1, + .num_resources = ARRAY_SIZE(usbh1_resources), + .resource = usbh1_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource usbh1_wakeup_resources[] = { + { + .start = MX51_MXC_INT_USB_H1, /*wakeup irq*/ + .flags = IORESOURCE_IRQ, + }, + { + .start = MX51_MXC_INT_USB_H1, + .flags = IORESOURCE_IRQ,/* usb core irq */ + }, +}; + +struct platform_device mxc_usbh1_wakeup_device = { + .name = "usb_wakeup", + .id = 1, + .num_resources = ARRAY_SIZE(usbh1_wakeup_resources), + .resource = usbh1_wakeup_resources, +}; + +static struct resource usbh2_resources[] = { + { + .start = MX51_OTG_BASE_ADDR + 0x400, + .end = MX51_OTG_BASE_ADDR + 0x400 + 0x1ff, + .flags = IORESOURCE_MEM, + }, + { + .start = MX51_MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ, + }, +}; + +struct platform_device mxc_usbh2_device = { + .name = "fsl-ehci", + .id = 2, + .num_resources = ARRAY_SIZE(usbh2_resources), + .resource = usbh2_resources, + .dev = { + .dma_mask = &usb_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +static struct resource usbh2_wakeup_resources[] = { + { + .start = MX51_MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ,/* wakeup irq */ + }, + { + .start = MX51_MXC_INT_USB_H2, + .flags = IORESOURCE_IRQ,/* usb core irq */ + }, +}; + +struct platform_device mxc_usbh2_wakeup_device = { + .name = "usb_wakeup", + .id = 2, + .num_resources = ARRAY_SIZE(usbh2_wakeup_resources), + .resource = usbh2_wakeup_resources, +}; + +struct platform_device imx_ahci_device_hwmon = { + .name = "imx-ahci-hwmon", + .id = -1, +}; + +static struct mxc_gpio_port mxc_gpio_ports[] = { + { + .chip.label = "gpio-0", + .base = MX51_IO_ADDRESS(MX51_GPIO1_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO1_LOW, + .irq_high = MX51_MXC_INT_GPIO1_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + }, + { + .chip.label = "gpio-1", + .base = MX51_IO_ADDRESS(MX51_GPIO2_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO2_LOW, + .irq_high = MX51_MXC_INT_GPIO2_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1 + }, + { + .chip.label = "gpio-2", + .base = MX51_IO_ADDRESS(MX51_GPIO3_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO3_LOW, + .irq_high = MX51_MXC_INT_GPIO3_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2 + }, + { + .chip.label = "gpio-3", + .base = MX51_IO_ADDRESS(MX51_GPIO4_BASE_ADDR), + .irq = MX51_MXC_INT_GPIO4_LOW, + .irq_high = MX51_MXC_INT_GPIO4_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3 + }, + { + .chip.label = "gpio-4", + .base = MX53_IO_ADDRESS(MX53_GPIO5_BASE_ADDR), + .irq = MX53_INT_GPIO5_LOW, + .irq_high = MX53_INT_GPIO5_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 4 + }, + { + .chip.label = "gpio-5", + .base = MX53_IO_ADDRESS(MX53_GPIO6_BASE_ADDR), + .irq = MX53_INT_GPIO6_LOW, + .irq_high = MX53_INT_GPIO6_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 5 + }, + { + .chip.label = "gpio-6", + .base = MX53_IO_ADDRESS(MX53_GPIO7_BASE_ADDR), + .irq = MX53_INT_GPIO7_LOW, + .irq_high = MX53_INT_GPIO7_HIGH, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 6 + }, +}; + +int __init imx51_register_gpios(void) +{ + return mxc_gpio_init(mxc_gpio_ports, 4); +} + +int __init imx53_register_gpios(void) +{ + return mxc_gpio_init(mxc_gpio_ports, ARRAY_SIZE(mxc_gpio_ports)); +} + diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h new file mode 100755 index 00000000..53ee4748 --- /dev/null +++ b/arch/arm/mach-mx5/devices.h @@ -0,0 +1,14 @@ +extern struct platform_device mxc_usbdr_host_device; +extern struct platform_device mxc_usbh1_device; +extern struct platform_device mxc_usbh2_device; +extern struct platform_device mxc_usbdr_udc_device; +extern struct platform_device mxc_hsi2c_device; +extern struct platform_device mxc_pwm1_backlight_device; +extern struct platform_device mxc_pwm2_backlight_device; +extern struct platform_device mxc_v4l2cap_device; +extern struct platform_device mxc_v4l2out_device; +extern struct platform_device mxc_pm_device; +extern struct platform_device mxc_usbdr_otg_device; +extern struct platform_device mxc_usbdr_wakeup_device; +extern struct platform_device mxc_usbh1_wakeup_device; +extern struct platform_device mxc_usbh2_wakeup_device; diff --git a/arch/arm/mach-mx5/efika.h b/arch/arm/mach-mx5/efika.h new file mode 100644 index 00000000..014aa985 --- /dev/null +++ b/arch/arm/mach-mx5/efika.h @@ -0,0 +1,10 @@ +#ifndef _EFIKA_H +#define _EFIKA_H + +#define EFIKA_WLAN_EN IMX_GPIO_NR(2, 16) +#define EFIKA_WLAN_RESET IMX_GPIO_NR(2, 10) +#define EFIKA_USB_PHY_RESET IMX_GPIO_NR(2, 9) + +void __init efika_board_common_init(void); + +#endif diff --git a/arch/arm/mach-mx5/ehci.c b/arch/arm/mach-mx5/ehci.c new file mode 100644 index 00000000..7ce12c80 --- /dev/null +++ b/arch/arm/mach-mx5/ehci.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * 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. + * + * This program is distributed in the hope that 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. + */ + +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/mxc_ehci.h> + +#define MXC_OTG_OFFSET 0 +#define MXC_H1_OFFSET 0x200 +#define MXC_H2_OFFSET 0x400 + +/* USB_CTRL */ +#define MXC_OTG_UCTRL_OWIE_BIT (1 << 27) /* OTG wakeup intr enable */ +#define MXC_OTG_UCTRL_OPM_BIT (1 << 24) /* OTG power mask */ +#define MXC_H1_UCTRL_H1UIE_BIT (1 << 12) /* Host1 ULPI interrupt enable */ +#define MXC_H1_UCTRL_H1WIE_BIT (1 << 11) /* HOST1 wakeup intr enable */ +#define MXC_H1_UCTRL_H1PM_BIT (1 << 8) /* HOST1 power mask */ + +/* USB_PHY_CTRL_FUNC */ +#define MXC_OTG_PHYCTRL_OC_DIS_BIT (1 << 8) /* OTG Disable Overcurrent Event */ +#define MXC_H1_OC_DIS_BIT (1 << 5) /* UH1 Disable Overcurrent Event */ + +/* USBH2CTRL */ +#define MXC_H2_UCTRL_H2UIE_BIT (1 << 8) +#define MXC_H2_UCTRL_H2WIE_BIT (1 << 7) +#define MXC_H2_UCTRL_H2PM_BIT (1 << 4) + +#define MXC_USBCMD_OFFSET 0x140 + +/* USBCMD */ +#define MXC_UCMD_ITC_NO_THRESHOLD_MASK (~(0xff << 16)) /* Interrupt Threshold Control */ + +int mx51_initialize_usb_hw(int port, unsigned int flags) +{ + unsigned int v; + void __iomem *usb_base; + void __iomem *usbotg_base; + void __iomem *usbother_base; + int ret = 0; + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) { + printk(KERN_ERR "%s(): ioremap failed\n", __func__); + return -ENOMEM; + } + + switch (port) { + case 0: /* OTG port */ + usbotg_base = usb_base + MXC_OTG_OFFSET; + break; + case 1: /* Host 1 port */ + usbotg_base = usb_base + MXC_H1_OFFSET; + break; + case 2: /* Host 2 port */ + usbotg_base = usb_base + MXC_H2_OFFSET; + break; + default: + printk(KERN_ERR"%s no such port %d\n", __func__, port); + ret = -ENOENT; + goto error; + } + usbother_base = usb_base + MX5_USBOTHER_REGS_OFFSET; + + switch (port) { + case 0: /*OTG port */ + if (flags & MXC_EHCI_INTERNAL_PHY) { + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); + + if (flags & MXC_EHCI_POWER_PINS_ENABLED) { + /* OC/USBPWR is not used */ + v |= MXC_OTG_PHYCTRL_OC_DIS_BIT; + } else { + /* OC/USBPWR is used */ + v &= ~MXC_OTG_PHYCTRL_OC_DIS_BIT; + } + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); + + v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET); + if (flags & MXC_EHCI_WAKEUP_ENABLED) + v |= MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup enable */ + else + v &= ~MXC_OTG_UCTRL_OWIE_BIT;/* OTG wakeup disable */ + if (flags & MXC_EHCI_POWER_PINS_ENABLED) + v |= MXC_OTG_UCTRL_OPM_BIT; + else + v &= ~MXC_OTG_UCTRL_OPM_BIT; + __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET); + } + break; + case 1: /* Host 1 */ + /*Host ULPI */ + v = __raw_readl(usbother_base + MXC_USBCTRL_OFFSET); + if (flags & MXC_EHCI_WAKEUP_ENABLED) { + /* HOST1 wakeup/ULPI intr enable */ + v |= (MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT); + } else { + /* HOST1 wakeup/ULPI intr disable */ + v &= ~(MXC_H1_UCTRL_H1WIE_BIT | MXC_H1_UCTRL_H1UIE_BIT); + } + + if (flags & MXC_EHCI_POWER_PINS_ENABLED) + v &= ~MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/ + else + v |= MXC_H1_UCTRL_H1PM_BIT; /* HOST1 power mask used*/ + __raw_writel(v, usbother_base + MXC_USBCTRL_OFFSET); + + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); + if (flags & MXC_EHCI_POWER_PINS_ENABLED) + v &= ~MXC_H1_OC_DIS_BIT; /* OC is used */ + else + v |= MXC_H1_OC_DIS_BIT; /* OC is not used */ + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC_OFFSET); + + v = __raw_readl(usbotg_base + MXC_USBCMD_OFFSET); + if (flags & MXC_EHCI_ITC_NO_THRESHOLD) + /* Interrupt Threshold Control:Immediate (no threshold) */ + v &= MXC_UCMD_ITC_NO_THRESHOLD_MASK; + __raw_writel(v, usbotg_base + MXC_USBCMD_OFFSET); + break; + case 2: /* Host 2 ULPI */ + v = __raw_readl(usbother_base + MXC_USBH2CTRL_OFFSET); + if (flags & MXC_EHCI_WAKEUP_ENABLED) { + /* HOST1 wakeup/ULPI intr enable */ + v |= (MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT); + } else { + /* HOST1 wakeup/ULPI intr disable */ + v &= ~(MXC_H2_UCTRL_H2WIE_BIT | MXC_H2_UCTRL_H2UIE_BIT); + } + + if (flags & MXC_EHCI_POWER_PINS_ENABLED) + v &= ~MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/ + else + v |= MXC_H2_UCTRL_H2PM_BIT; /* HOST2 power mask used*/ + __raw_writel(v, usbother_base + MXC_USBH2CTRL_OFFSET); + break; + } + +error: + iounmap(usb_base); + return ret; +} + diff --git a/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c new file mode 100644 index 00000000..97292d20 --- /dev/null +++ b/arch/arm/mach-mx5/eukrea_mbimx51-baseboard.c @@ -0,0 +1,219 @@ +/* + * + * Copyright (C) 2010 Eric Bénard <eric@eukrea.com> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/i2c/tsc2007.h> +#include <linux/leds.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +#include <asm/mach/arch.h> + +#include "devices-imx51.h" +#include "devices.h" + +#define MBIMX51_TSC2007_GPIO IMX_GPIO_NR(3, 30) +#define MBIMX51_TSC2007_IRQ (MXC_INTERNAL_IRQS + MBIMX51_TSC2007_GPIO) +#define MBIMX51_LED0 IMX_GPIO_NR(3, 5) +#define MBIMX51_LED1 IMX_GPIO_NR(3, 6) +#define MBIMX51_LED2 IMX_GPIO_NR(3, 7) +#define MBIMX51_LED3 IMX_GPIO_NR(3, 8) + +static struct gpio_led mbimx51_leds[] = { + { + .name = "led0", + .default_trigger = "heartbeat", + .active_low = 1, + .gpio = MBIMX51_LED0, + }, + { + .name = "led1", + .default_trigger = "nand-disk", + .active_low = 1, + .gpio = MBIMX51_LED1, + }, + { + .name = "led2", + .default_trigger = "mmc0", + .active_low = 1, + .gpio = MBIMX51_LED2, + }, + { + .name = "led3", + .default_trigger = "default-on", + .active_low = 1, + .gpio = MBIMX51_LED3, + }, +}; + +static struct gpio_led_platform_data mbimx51_leds_info = { + .leds = mbimx51_leds, + .num_leds = ARRAY_SIZE(mbimx51_leds), +}; + +static struct platform_device mbimx51_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mbimx51_leds_info, + }, +}; + +static struct platform_device *devices[] __initdata = { + &mbimx51_leds_gpio, +}; + +static iomux_v3_cfg_t mbimx51_pads[] = { + /* UART2 */ + MX51_PAD_UART2_RXD__UART2_RXD, + MX51_PAD_UART2_TXD__UART2_TXD, + + /* UART3 */ + MX51_PAD_UART3_RXD__UART3_RXD, + MX51_PAD_UART3_TXD__UART3_TXD, + MX51_PAD_KEY_COL4__UART3_RTS, + MX51_PAD_KEY_COL5__UART3_CTS, + + /* TSC2007 IRQ */ + MX51_PAD_NANDF_D10__GPIO3_30, + + /* LEDS */ + MX51_PAD_DISPB2_SER_DIN__GPIO3_5, + MX51_PAD_DISPB2_SER_DIO__GPIO3_6, + MX51_PAD_DISPB2_SER_CLK__GPIO3_7, + MX51_PAD_DISPB2_SER_RS__GPIO3_8, + + /* KPP */ + MX51_PAD_KEY_ROW0__KEY_ROW0, + MX51_PAD_KEY_ROW1__KEY_ROW1, + MX51_PAD_KEY_ROW2__KEY_ROW2, + MX51_PAD_KEY_ROW3__KEY_ROW3, + MX51_PAD_KEY_COL0__KEY_COL0, + MX51_PAD_KEY_COL1__KEY_COL1, + MX51_PAD_KEY_COL2__KEY_COL2, + MX51_PAD_KEY_COL3__KEY_COL3, + + /* SD 1 */ + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + + /* SD 2 */ + MX51_PAD_SD2_CMD__SD2_CMD, + MX51_PAD_SD2_CLK__SD2_CLK, + MX51_PAD_SD2_DATA0__SD2_DATA0, + MX51_PAD_SD2_DATA1__SD2_DATA1, + MX51_PAD_SD2_DATA2__SD2_DATA2, + MX51_PAD_SD2_DATA3__SD2_DATA3, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static int mbimx51_keymap[] = { + KEY(0, 0, KEY_1), + KEY(0, 1, KEY_2), + KEY(0, 2, KEY_3), + KEY(0, 3, KEY_UP), + + KEY(1, 0, KEY_4), + KEY(1, 1, KEY_5), + KEY(1, 2, KEY_6), + KEY(1, 3, KEY_LEFT), + + KEY(2, 0, KEY_7), + KEY(2, 1, KEY_8), + KEY(2, 2, KEY_9), + KEY(2, 3, KEY_RIGHT), + + KEY(3, 0, KEY_0), + KEY(3, 1, KEY_DOWN), + KEY(3, 2, KEY_ESC), + KEY(3, 3, KEY_ENTER), +}; + +static const struct matrix_keymap_data mbimx51_map_data __initconst = { + .keymap = mbimx51_keymap, + .keymap_size = ARRAY_SIZE(mbimx51_keymap), +}; + +static int tsc2007_get_pendown_state(void) +{ + return !gpio_get_value(MBIMX51_TSC2007_GPIO); +} + +struct tsc2007_platform_data tsc2007_data = { + .model = 2007, + .x_plate_ohms = 180, + .get_pendown_state = tsc2007_get_pendown_state, +}; + +static struct i2c_board_info mbimx51_i2c_devices[] = { + { + I2C_BOARD_INFO("tsc2007", 0x49), + .irq = MBIMX51_TSC2007_IRQ, + .platform_data = &tsc2007_data, + }, { + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +/* + * baseboard initialization. + */ +void __init eukrea_mbimx51_baseboard_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mbimx51_pads, + ARRAY_SIZE(mbimx51_pads)); + + imx51_add_imx_uart(1, NULL); + imx51_add_imx_uart(2, &uart_pdata); + + gpio_request(MBIMX51_LED0, "LED0"); + gpio_direction_output(MBIMX51_LED0, 1); + gpio_free(MBIMX51_LED0); + gpio_request(MBIMX51_LED1, "LED1"); + gpio_direction_output(MBIMX51_LED1, 1); + gpio_free(MBIMX51_LED1); + gpio_request(MBIMX51_LED2, "LED2"); + gpio_direction_output(MBIMX51_LED2, 1); + gpio_free(MBIMX51_LED2); + gpio_request(MBIMX51_LED3, "LED3"); + gpio_direction_output(MBIMX51_LED3, 1); + gpio_free(MBIMX51_LED3); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + imx51_add_imx_keypad(&mbimx51_map_data); + + gpio_request(MBIMX51_TSC2007_GPIO, "tsc2007_irq"); + gpio_direction_input(MBIMX51_TSC2007_GPIO); + irq_set_irq_type(MBIMX51_TSC2007_IRQ, IRQF_TRIGGER_FALLING); + i2c_register_board_info(1, mbimx51_i2c_devices, + ARRAY_SIZE(mbimx51_i2c_devices)); + + imx51_add_sdhci_esdhc_imx(0, NULL); + imx51_add_sdhci_esdhc_imx(1, NULL); +} diff --git a/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c new file mode 100644 index 00000000..31c871ec --- /dev/null +++ b/arch/arm/mach-mx5/eukrea_mbimxsd-baseboard.c @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2010 Eric Benard - eric@eukrea.com + * + * Based on pcm970-baseboard.c which is : + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * 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. + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/types.h> +#include <linux/init.h> + +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/leds.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/i2c.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx51.h> +#include <mach/audmux.h> + +#include "devices-imx51.h" +#include "devices.h" + +static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = { + /* LED */ + MX51_PAD_NANDF_D10__GPIO3_30, + /* SWITCH */ + _MX51_PAD_NANDF_D9__GPIO3_31 | MUX_PAD_CTRL(PAD_CTL_PUS_22K_UP | + PAD_CTL_PKE | PAD_CTL_SRE_FAST | + PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS), + /* UART2 */ + MX51_PAD_UART2_RXD__UART2_RXD, + MX51_PAD_UART2_TXD__UART2_TXD, + /* UART 3 */ + MX51_PAD_UART3_RXD__UART3_RXD, + MX51_PAD_UART3_TXD__UART3_TXD, + MX51_PAD_KEY_COL4__UART3_RTS, + MX51_PAD_KEY_COL5__UART3_CTS, + /* SD */ + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + /* SD1 CD */ + _MX51_PAD_GPIO1_0__SD1_CD | MUX_PAD_CTRL(PAD_CTL_PUS_22K_UP | + PAD_CTL_PKE | PAD_CTL_SRE_FAST | + PAD_CTL_DSE_HIGH | PAD_CTL_PUE | PAD_CTL_HYS), +}; + +#define GPIO_LED1 IMX_GPIO_NR(3, 30) +#define GPIO_SWITCH1 IMX_GPIO_NR(3, 31) + +static struct gpio_led eukrea_mbimxsd_leds[] = { + { + .name = "led1", + .default_trigger = "heartbeat", + .active_low = 1, + .gpio = GPIO_LED1, + }, +}; + +static struct gpio_led_platform_data eukrea_mbimxsd_led_info = { + .leds = eukrea_mbimxsd_leds, + .num_leds = ARRAY_SIZE(eukrea_mbimxsd_leds), +}; + +static struct platform_device eukrea_mbimxsd_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &eukrea_mbimxsd_led_info, + }, +}; + +static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = { + { + .gpio = GPIO_SWITCH1, + .code = BTN_0, + .desc = "BP1", + .active_low = 1, + .wakeup = 1, + }, +}; + +static const struct gpio_keys_platform_data + eukrea_mbimxsd_button_data __initconst = { + .buttons = eukrea_mbimxsd_gpio_buttons, + .nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons), +}; + +static struct platform_device *platform_devices[] __initdata = { + &eukrea_mbimxsd_leds_gpio, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = { + { + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +/* + * system init for baseboard usage. Will be called by cpuimx51sd init. + * + * Add platform devices present on this baseboard and init + * them from CPU side as far as required to use them later on + */ +void __init eukrea_mbimxsd51_baseboard_init(void) +{ + if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads, + ARRAY_SIZE(eukrea_mbimxsd_pads))) + printk(KERN_ERR "error setting mbimxsd pads !\n"); + + imx51_add_imx_uart(1, NULL); + imx51_add_imx_uart(2, &uart_pdata); + + imx51_add_sdhci_esdhc_imx(0, NULL); + + gpio_request(GPIO_LED1, "LED1"); + gpio_direction_output(GPIO_LED1, 1); + gpio_free(GPIO_LED1); + + gpio_request(GPIO_SWITCH1, "SWITCH1"); + gpio_direction_input(GPIO_SWITCH1); + gpio_free(GPIO_SWITCH1); + + i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices, + ARRAY_SIZE(eukrea_mbimxsd_i2c_devices)); + + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx_add_gpio_keys(&eukrea_mbimxsd_button_data); +} diff --git a/arch/arm/mach-mx5/imx_bt_rfkill.c b/arch/arm/mach-mx5/imx_bt_rfkill.c new file mode 100755 index 00000000..372ba0fe --- /dev/null +++ b/arch/arm/mach-mx5/imx_bt_rfkill.c @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/*! + * @file imx_bt_rfkill.c + * + * @brief This driver is implement a rfkill control interface of bluetooth + * chip on i.MX serial boards. Register the power regulator function and + * reset function in platform data. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/suspend.h> +#include <linux/init.h> +#include <linux/rfkill.h> +#include <mach/hardware.h> +#include <mach/imx_rfkill.h> + +static int system_in_suspend; + +static int imx_bt_set_block(void *rfkdata, bool blocked) +{ + struct imx_bt_rfkill_platform_data *data = rfkdata; + int ret; + + /* Bluetooth stack will reset the bluetooth chip during + * resume, since we keep bluetooth's power during suspend, + * don't let rfkill to actually reset the chip. */ + if (system_in_suspend) + return 0; + + pr_info("rfkill: Bluetooth RF turn %s\n", blocked ? "off" : "on"); + if (!blocked) + ret = data->power_change(1); + else + ret = data->power_change(0); + + return ret; +} + +static const struct rfkill_ops imx_bt_rfkill_ops = { + .set_block = imx_bt_set_block, +}; + +static int imx_bt_power_event(struct notifier_block *this, + unsigned long event, void *dummy) +{ + switch (event) { + case PM_SUSPEND_PREPARE: + system_in_suspend = 1; + /* going to suspend, don't reset chip */ + break; + case PM_POST_SUSPEND: + system_in_suspend = 0; + /* System is resume, can reset chip */ + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block imx_bt_power_notifier = { + .notifier_call = imx_bt_power_event, +}; + +static int imx_bt_rfkill_probe(struct platform_device *dev) +{ + int rc; + struct rfkill *rfk; + + struct imx_bt_rfkill_platform_data *data = dev->dev.platform_data; + + if (data->power_change == NULL) { + rc = -EINVAL; + dev_err(&dev->dev, "no power_change function\n"); + goto error_check_func; + } + + rc = register_pm_notifier(&imx_bt_power_notifier); + if (rc) + goto error_check_func; + + rfk = rfkill_alloc("imx-bt", &dev->dev, RFKILL_TYPE_BLUETOOTH, + &imx_bt_rfkill_ops, data); + + if (!rfk) { + rc = -ENOMEM; + goto error_rfk_alloc; + } + + rc = rfkill_register(rfk); + if (rc) + goto error_rfkill; + + platform_set_drvdata(dev, rfk); + printk(KERN_INFO "imx_bt_rfkill driver success loaded\n"); + return 0; + +error_rfkill: + rfkill_destroy(rfk); +error_rfk_alloc: +error_check_func: + return rc; +} + +static int __devexit imx_bt_rfkill_remove(struct platform_device *dev) +{ + struct imx_bt_rfkill_platform_data *data = dev->dev.platform_data; + struct rfkill *rfk = platform_get_drvdata(dev); + + platform_set_drvdata(dev, NULL); + + if (rfk) { + rfkill_unregister(rfk); + rfkill_destroy(rfk); + } + + data->power_change(0); + + return 0; +} + +static struct platform_driver imx_bt_rfkill_drv = { + .driver = { + .name = "imx_bt_rfkill", + }, + + .probe = imx_bt_rfkill_probe, + .remove = __devexit_p(imx_bt_rfkill_remove), +}; + +static int __init imx_bt_rfkill_init(void) +{ + return platform_driver_register(&imx_bt_rfkill_drv); +} + +module_init(imx_bt_rfkill_init); + +static void __exit imx_bt_rfkill_exit(void) +{ + platform_driver_unregister(&imx_bt_rfkill_drv); +} + +module_exit(imx_bt_rfkill_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("RFKill control interface of BT on MX53 SMD"); diff --git a/arch/arm/mach-mx5/mm-mx50.c b/arch/arm/mach-mx5/mm-mx50.c new file mode 100644 index 00000000..b9c363b5 --- /dev/null +++ b/arch/arm/mach-mx5/mm-mx50.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Create static mapping between physical to virtual memory. + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-v3.h> +#include <mach/gpio.h> +#include <mach/irqs.h> + +/* + * Define the MX50 memory map. + */ +static struct map_desc mx50_io_desc[] __initdata = { + imx_map_entry(MX50, TZIC, MT_DEVICE), + imx_map_entry(MX50, SPBA0, MT_DEVICE), + imx_map_entry(MX50, AIPS1, MT_DEVICE), + imx_map_entry(MX50, AIPS2, MT_DEVICE), +}; + +/* + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory mappings + * for the IO modules. + */ +void __init mx50_map_io(void) +{ + iotable_init(mx50_io_desc, ARRAY_SIZE(mx50_io_desc)); +} + +void __init imx50_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX50); + mxc_iomux_v3_init(MX50_IO_ADDRESS(MX50_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(MX50_IO_ADDRESS(MX50_WDOG_BASE_ADDR)); +} + +static struct mxc_gpio_port imx50_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 0, 1, MX50_INT_GPIO1_LOW, MX50_INT_GPIO1_HIGH), + DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 1, 2, MX50_INT_GPIO2_LOW, MX50_INT_GPIO2_HIGH), + DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 2, 3, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH), + DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 3, 4, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH), + DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 4, 5, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH), + DEFINE_IMX_GPIO_PORT_IRQ_HIGH(MX50, 5, 6, MX50_INT_GPIO3_LOW, MX50_INT_GPIO3_HIGH), +}; + +void __init mx50_init_irq(void) +{ + tzic_init_irq(MX50_IO_ADDRESS(MX50_TZIC_BASE_ADDR)); + mxc_gpio_init(imx50_gpio_ports, ARRAY_SIZE(imx50_gpio_ports)); +} diff --git a/arch/arm/mach-mx5/mm.c b/arch/arm/mach-mx5/mm.c new file mode 100644 index 00000000..ff557301 --- /dev/null +++ b/arch/arm/mach-mx5/mm.c @@ -0,0 +1,107 @@ +/* + * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * Create static mapping between physical to virtual memory. + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-v3.h> + +/* + * Define the MX51 memory map. + */ +static struct map_desc mx51_io_desc[] __initdata = { + imx_map_entry(MX51, IRAM, MT_DEVICE), + imx_map_entry(MX51, DEBUG, MT_DEVICE), + imx_map_entry(MX51, AIPS1, MT_DEVICE), + imx_map_entry(MX51, SPBA0, MT_DEVICE), + imx_map_entry(MX51, AIPS2, MT_DEVICE), +}; + +/* + * Define the MX53 memory map. + */ +static struct map_desc mx53_io_desc[] __initdata = { + imx_map_entry(MX53, AIPS1, MT_DEVICE), + imx_map_entry(MX53, SPBA0, MT_DEVICE), + imx_map_entry(MX53, AIPS2, MT_DEVICE), +}; + +/* + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory mappings + * for the IO modules. + */ +void __init mx51_map_io(void) +{ + iotable_init(mx51_io_desc, ARRAY_SIZE(mx51_io_desc)); +} + +void __init imx51_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX51); + mxc_iomux_v3_init(MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(MX51_IO_ADDRESS(MX51_WDOG1_BASE_ADDR)); +} + +void __init mx53_map_io(void) +{ + iotable_init(mx53_io_desc, ARRAY_SIZE(mx53_io_desc)); +} + +void __init imx53_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX53); + mxc_iomux_v3_init(MX53_IO_ADDRESS(MX53_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(MX53_IO_ADDRESS(MX53_WDOG1_BASE_ADDR)); +} + +int imx51_register_gpios(void); + +void __init mx51_init_irq(void) +{ + unsigned long tzic_addr; + void __iomem *tzic_virt; + + if (mx51_revision() < IMX_CHIP_REVISION_2_0) + tzic_addr = MX51_TZIC_BASE_ADDR_TO1; + else + tzic_addr = MX51_TZIC_BASE_ADDR; + + tzic_virt = ioremap(tzic_addr, SZ_16K); + if (!tzic_virt) + panic("unable to map TZIC interrupt controller\n"); + + tzic_init_irq(tzic_virt); + imx51_register_gpios(); +} + +int imx53_register_gpios(void); + +void __init mx53_init_irq(void) +{ + unsigned long tzic_addr; + void __iomem *tzic_virt; + + tzic_addr = MX53_TZIC_BASE_ADDR; + + tzic_virt = ioremap(tzic_addr, SZ_16K); + if (!tzic_virt) + panic("unable to map TZIC interrupt controller\n"); + + tzic_init_irq(tzic_virt); + imx53_register_gpios(); +} diff --git a/arch/arm/mach-mx5/mx50_ddr_freq.S b/arch/arm/mach-mx5/mx50_ddr_freq.S new file mode 100755 index 00000000..06bb4fa5 --- /dev/null +++ b/arch/arm/mach-mx5/mx50_ddr_freq.S @@ -0,0 +1,393 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> + +/* + * mx50_ddr_freq_change + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx50_ddr_freq_change) + stmfd sp!, {r4,r5,r6, r7, r8, r9} @ Save registers + + mov r6, r0 @save CCM address + mov r5, r1 @save DataBahn address + mov r4, r2 @save new freq requested + mov r8, r3 @save the DRAM settings array + + /* Make sure no TLB miss will occur when the DDR is in self refresh. */ + /* Invalidate TLB single entry to ensure that the address is not + * already in the TLB. + */ + adr r3, LoopCKE2 @Address in this function. + mcr p15, 0, r3, c8, c7, 1 @ Make sure freq code address + @ is not already in TLB. + mcr p15, 0, r6, c8, c7, 1 @ Make sure CCM address + @ is not already in TLB. + mcr p15, 0, r5, c8, c7, 1 @ make sure Databahn address + @ is not already in TLB. + mcr p15, 0, r8, c8, c7, 1 @ make sure Databahn settings + @ arrayis not already in TLB. + + mrc p15, 0, r0, c10, c0, 0 @ Read the TLB lockdown register + orr r0, r0, #1 @ Set the Preserve bit. + mcr p15, 0, r0, c10, c0, 0 @ Write to the lockdown register + ldr r2, [r6] @ TLB will miss, + @CCM address will be loaded + ldr r2, [r5] @ TLB will miss, + @Databahn address will be loaded + ldr r2, [r8] @ TLB will miss, + @Databahn settings will be loaded + + ldr r2, [r3] @ TLB will miss + mrc p15, 0, r0, c10, c0, 0 @ Read the lockdown register + @ (victim will be incremented) + bic r0, r0, #1 @ Clear the preserve bit + mcr p15, 0, r0, c10, c0, 0 @ Write to the lockdown register. + + /* If Databahn is in LPM4, exit that mode first. */ + ldr r9,[r5, #0x50] @Store LPM mode in r9 + mov r0, r9 + bic r0, #0x1F + str r0,[r5, #0x50] + +LoopCKE2: + /*Wait for CKE = 1 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + bne LoopCKE2 + +/* Wait for the databahn to idle + Meaning, no access to the databahn is + being made. +*/ +NotIdle: + ldr r0,[r5, #0x13c] + and r0, r0, #0x100 + ldr r2, =0x100 + cmp r0, r2 + beq NotIdle + + /* + * Make sure the DDR is self-refresh, before switching its frequency + * and clock source + */ + + /* Step 1: Enter self-refresh mode */ + ldr r0,[r5, #0x4c] + orr r0,r0,#0x1 + str r0,[r5, #0x4c] + + /* Step 2: Poll the CKE_STATUS bit. */ +LoopCKE0: + /* Wait for CKE = 0 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + beq LoopCKE0 + + /* Step 3: Mask the DLL lock state change, set bit 8 in int_mask. */ + ldr r0, [r5, #0xac] + orr r0, r0, #0x100 + str r0, [r5, #0xac] + + /* Step 4: Stop the Controller. */ + ldr r0,[r5] + bic r0, r0, #0x1 + str r0,[r5] + + /* Step 5: Clear the DLL lock state change bit 8 in int_ack */ + ldr r0, [r5, #0xa8] + orr r0, r0, #0x1000000 + str r0, [r5, #0xa8] + + /* Step 6: Clear the interrupt mask for DLL lock state. + * Bit 8 in int_mask */ + ldr r0, [r5, #0xac] + bic r0, r0, #0x100 + str r0, [r5, #0xac] + + /* Change the freq now */ + /* If the freq req is below 24MHz, set DDR to synchronous mode. + * else set to async mode. */ + ldr r0, =24000000 + cmp r4, r0 + bgt Async_Mode + + /* Set the DDR to be Synchronous + mode. */ + /* Set the Databahn to sync mode. */ + ldr r0, [r5, #0xdc] + orr r0, r0, #0x30000 + str r0, [r5, #0xdc] + + /* Turn OFF the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + /* Check if XTAL can source the DDR. */ + ldr r0, =24000000 + cmp r4, r0 + ble databahn_ddr_24 + + /*Source DDR from PLL1. Setup the dividers accordingly. */ + ldr r0, =800000000 + ldr r3, =1 +Loop1: + sub r0, r0, r4 + cmp r0, r4 + blt Div_Found + add r3, r3, #1 + bgt Loop1 + +Div_Found: + ldr r0, [r6, #0x94] + bic r0, r0, #0x3f + orr r0, r0, r3 + str r0, [r6, #0x94] + /* Set the DDR to sourced from PLL1 in sync path */ + ldr r0, [r6, #0x90] + orr r0, r0, #0x3 + str r0, [r6, #0x90] + + /* Turn OFF the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + ldr r0, =24000000 + cmp r4, r0 + beq databahn_ddr_24 + + b Ddr_not_24 + +databahn_ddr_24: + /* Restore from the ddr settings array */ + ldr r1, [r8] @size of array + add r8, r8, #8 @skip first eight bytes in array +update_ddr: + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_ddr + + /* Set SYS_CLK to be sourced from 24MHz. */ + /* Set the SYS_XTAL_DIV */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x3c0 + orr r0, r0, #0x40 + str r0, [r6, #0x94] + + /* Enable SYS_XTAL_CLKGATE. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x94] + + /* set SYS_CLK to be sourced from XTAL. */ + ldr r0, [r6, #0x90] + bic r0, r0, #0x1 + str r0, [r6, #0x90] + + /* Disable SYS_PLL_CLKGATE.*/ + ldr r0, [r6, #0x94] + bic r0, r0, #0x30000000 + str r0, [r6, #0x94] + b Setup_Done + +Ddr_not_24: +Async_Mode: + /* If SYS_CLK is running at 24MHz, increase + * it to 200MHz. + */ + /* r7 indicates that we are moving from 133Mhz<-> 266MHz */ + ldr r7, =1 + ldr r0, [r6, #0x90] + and r0, r0, #0x1 + cmp r0, #0 + bne Sys_Clk_Not_24 + ldr r7, =0 + + /* Disable SYS_PLL_CLKGATE. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x30000000 + str r0, [r6, #0x94] + + /* Set the new divider. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x3f + orr r0, r0, #4 + str r0, [r6, #0x94] + + /* Enable SYS_PLL_CLKGATE. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0x30000000 + str r0, [r6, #0x94] + + /* SYS_CLK to be sourced from PLL1. */ + ldr r0, [r6, #0x90] + orr r0, r0, #0x3 + str r0, [r6, #0x90] + + /* Disable SYS_XTAL_CLKGATE. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x94] + +Sys_Clk_Not_24: + /* Set the Databahn to async mode. */ + ldr r0, [r5, #0xdc] + and r0, r0, #0xfffcffff + str r0, [r5, #0xdc] + + /*Source DDR from PLL1. Setup the dividers accordingly. */ + ldr r0, =800000000 + ldr r3, =1 +Loop2: + sub r0, r0, r4 + cmp r0, r4 + blt Div_Found1 + add r3, r3, #1 + bgt Loop2 + +Div_Found1: + /* Turn OFF the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + bic r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + ldr r0, [r6, #0x98] + bic r0, r0, #0x3f + orr r0, r0, r3 + str r0, [r6, #0x98] + + /* Set the DDR to sourced from PLL1 in async path */ + ldr r0, [r6, #0x98] + bic r0, r0, #0x40 + str r0, [r6, #0x98] + + /* Turn ON the DDR_CKLGATE_MASK in MXC_CCM_DDR */ + ldr r0, [r6, #0x98] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x98] + + ldr r0, =24000000 + cmp r4, r0 + beq databahn_ddr_24 + + cmp r7, #1 + beq just_set_tref + + /* Restore from the ddr settings array */ + ldr r1, [r8] @size of array + add r8, r8, #8 @skip first eight bytes in array +update_ddr1: + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_ddr1 + + b Setup_Done + +just_set_tref: + /* Check for mDDR v LPDDR2 memory type */ + ldr r0, [r5] + ldr r2, =0x100 + and r0, r0, #0xF00 + cmp r0, r2 + beq mddr_133_200 + +lpddr2_133_266: + ldr r0, =133333333 + cmp r4, r0 + bgt ddr_266 + ldr r0, =0x00050180 + b tref_done +ddr_266: + ldr r0, =0x00050300 +tref_done: + str r0, [r5, #0x40] + b Setup_Done + +mddr_133_200: + ldr r0, =133333333 + cmp r4, r0 + bgt mddr_200 + ldr r0, =0x00050208 + b tref_done1 +mddr_200: + ldr r0, =0x0005030f +tref_done1: + str r0, [r5, #0x40] + +Setup_Done: + /* Start controller */ + ldr r0,[r5] + orr r0, r0,#0x1 + str r0,[r5] + + /* Poll the DLL lock state change in int_status reg*/ + /* DLL is bypassed in the 24MHz mode, so no waiting for DLL to lock. */ + ldr r0, =24000000 + cmp r4, r0 + beq Exit_Self_Refresh + +DllLock: + ldr r0, [r5, #0xa8] + and r0, r0, #0x100 + ldr r2, =0x100 + cmp r0, r2 + bne DllLock + + /*Leave self-refresh mode */ +Exit_Self_Refresh: + ldr r0,[r5, #0x4c] + and r0,r0,#0xfffffffe + str r0,[r5, #0x4c] + +LoopCKE1: + /*Wait for CKE = 1 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + bne LoopCKE1 + + /* Put the databahn back to into the LPM mode. */ + str r9,[r5, #0x50] + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6, r7, r8, r9} + mov pc, lr + + .type mx50_do_ddr_freq_change, #object +ENTRY(mx50_do_ddr_freq_change) + .word mx50_ddr_freq_change + .size mx50_ddr_freq_change, . - mx50_ddr_freq_change diff --git a/arch/arm/mach-mx5/mx50_freq.c b/arch/arm/mach-mx5/mx50_freq.c new file mode 100755 index 00000000..de9fd7bc --- /dev/null +++ b/arch/arm/mach-mx5/mx50_freq.c @@ -0,0 +1,434 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file mx50_ddr.c + * + * @brief MX50 DDR specific information file. + * + * + * + * @ingroup PM + */ +#include <asm/io.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/iram_alloc.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <asm/mach/map.h> +#include <asm/mach-types.h> +#include <asm/cacheflush.h> +#include <asm/tlb.h> + +#define LP_APM_CLK 24000000 +#define HW_QOS_DISABLE 0x70 +#define HW_QOS_DISABLE_SET 0x74 +#define HW_QOS_DISABLE_CLR 0x78 + +static struct clk *epdc_clk; + +/* DDR settings */ +unsigned long (*iram_ddr_settings)[2]; +unsigned long (*normal_databahn_settings)[2]; +unsigned int mx50_ddr_type; +void *ddr_freq_change_iram_base; +void __iomem *databahn_base; + +void (*change_ddr_freq)(void *ccm_addr, void *databahn_addr, + u32 freq, void *iram_ddr_settings) = NULL; +void *wait_in_iram_base; +void (*wait_in_iram)(void *ccm_addr, void *databahn_addr, u32 sys_clk_count); + +extern void mx50_wait(u32 ccm_base, u32 databahn_addr, u32 sys_clk_count); +extern int ddr_med_rate; +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; +extern void mx50_ddr_freq_change(u32 ccm_base, + u32 databahn_addr, u32 freq); + +static void __iomem *qosc_base; +static int ddr_settings_size; + +unsigned long lpddr2_databhan_regs_offsets[][2] = { + {0x8, 0x0}, + {0xc, 0x0}, + {0x10, 0x0}, + {0x14, 0x0}, + {0x18, 0x0}, + {0x1c, 0x0}, + {0x20, 0x0}, + {0x24, 0x0}, + {0x28, 0x0}, + {0x2c, 0x0}, + {0x34, 0x0}, + {0x38, 0x0}, + {0x3c, 0x0}, + {0x40, 0x0}, + {0x48, 0x0}, + {0x6c, 0x0}, + {0x78, 0x0}, + {0x80, 0x0}, + {0x84, 0x0}, + {0x88, 0x0}, + {0x8c, 0x0}, + {0xcc, 0x0}, + {0xd4, 0x0}, + {0xd8, 0x0}, + {0x104, 0x0}, + {0x108, 0x0}, + {0x10c, 0x0}, + {0x110, 0x0}, + {0x114, 0x0}, + {0x200, 0x0}, + {0x204, 0x0}, + {0x208, 0x0}, + {0x20c, 0x0}, + {0x210, 0x0}, + {0x214, 0x0}, + {0x218, 0x0}, + {0x21c, 0x0}, + {0x220, 0x0}, + {0x224, 0x0}, + {0x228, 0x0}, + {0x22c, 0x0}, + {0x234, 0x0}, + {0x238, 0x0}, + {0x23c, 0x0}, + {0x240, 0x0}, + {0x244, 0x0}, + {0x248, 0x0}, + {0x24c, 0x0}, + {0x250, 0x0}, + {0x254, 0x0}, + {0x258, 0x0}, + {0x25c, 0x0} }; + +unsigned long lpddr2_24[][2] = { + {0x08, 0x00000003}, + {0x0c, 0x000012c0}, + {0x10, 0x00000018}, + {0x14, 0x000000f0}, + {0x18, 0x02030b0c}, + {0x1c, 0x02020104}, + {0x20, 0x05010102}, + {0x24, 0x00068005}, + {0x28, 0x01000103}, + {0x2c, 0x04030101}, + {0x34, 0x00000202}, + {0x38, 0x00000001}, + {0x3c, 0x00000401}, + {0x40, 0x00030050}, + {0x48, 0x00040004}, + {0x6c, 0x00040022}, + {0x78, 0x00040022}, + {0x80, 0x00180000}, + {0x84, 0x00000009}, + {0x88, 0x02400003}, + {0x8c, 0x01000200}, + {0xcc, 0x00000000}, + {0xd4, 0x01010301}, + {0xd8, 0x00000101}, + {0x104, 0x02000602}, + {0x108, 0x00560000}, + {0x10c, 0x00560056}, + {0x110, 0x00560056}, + {0x114, 0x03060056}, + {0x200, 0x00000000}, + {0x204, 0x00000000}, + {0x208, 0xf3003a27}, + {0x20c, 0x074002c1}, + {0x210, 0xf3003a27}, + {0x214, 0x074002c1}, + {0x218, 0xf3003a27}, + {0x21c, 0x074002c1}, + {0x220, 0xf3003a27}, + {0x224, 0x074002c1}, + {0x228, 0xf3003a27}, + {0x22c, 0x074002c1}, + {0x234, 0x00810004}, + {0x238, 0x30219fd3}, + {0x23c, 0x00219fc1}, + {0x240, 0x30219fd3}, + {0x244, 0x00219fc1}, + {0x248, 0x30219fd3}, + {0x24c, 0x00219fc1}, + {0x250, 0x30219fd3}, + {0x254, 0x00219fc1}, + {0x258, 0x30219fd3}, + {0x25c, 0x00219fc1} }; + +unsigned long mddr_databhan_regs_offsets[][2] = { + {0x08, 0x0}, + {0x14, 0x0}, + {0x18, 0x0}, + {0x1c, 0x0}, + {0x20, 0x0}, + {0x24, 0x0}, + {0x28, 0x0}, + {0x2c, 0x0}, + {0x34, 0x0}, + {0x38, 0x0}, + {0x3c, 0x0}, + {0x40, 0x0}, + {0x48, 0x0}, + {0x6c, 0x0}, + {0xd4, 0x0}, + {0x108, 0x0}, + {0x10c, 0x0}, + {0x110, 0x0}, + {0x114, 0x0}, + {0x200, 0x0}, + {0x204, 0x0}, + {0x208, 0x0}, + {0x20c, 0x0}, + {0x210, 0x0}, + {0x214, 0x0}, + {0x218, 0x0}, + {0x21c, 0x0}, + {0x220, 0x0}, + {0x224, 0x0}, + {0x228, 0x0}, + {0x22c, 0x0}, + {0x234, 0x0}, + {0x238, 0x0}, + {0x23c, 0x0}, + {0x240, 0x0}, + {0x244, 0x0}, + {0x248, 0x0}, + {0x24c, 0x0}, + {0x250, 0x0}, + {0x254, 0x0}, + {0x258, 0x0}, + {0x25c, 0x0} }; + + +unsigned long mddr_24[][2] = { + {0x08, 0x000012c0}, + {0x14, 0x02000000}, + {0x18, 0x01010506}, + {0x1c, 0x01020101}, + {0x20, 0x02000103}, + {0x24, 0x01069002}, + {0x28, 0x01000101}, + {0x2c, 0x02010101}, + {0x34, 0x00000602}, + {0x38, 0x00000001}, + {0x3c, 0x00000301}, + {0x40, 0x000500b0}, + {0x48, 0x00030003}, + {0x6c, 0x00000000}, + {0xd4, 0x00000200}, + {0x108, 0x00b30000}, + {0x10c, 0x00b300b3}, + {0x110, 0x00b300b3}, + {0x114, 0x010300b3}, + {0x200, 0x00000100}, + {0x204, 0x00000000}, + {0x208, 0xf4003a27}, + {0x20c, 0x074002c0}, + {0x210, 0xf4003a27}, + {0x214, 0x074002c0}, + {0x218, 0xf4003a27}, + {0x21c, 0x074002c0}, + {0x220, 0xf4003a27}, + {0x224, 0x074002c0}, + {0x228, 0xf4003a27}, + {0x22c, 0x074002c0}, + {0x234, 0x00800005}, + {0x238, 0x30319f14}, + {0x23c, 0x00319f01}, + {0x240, 0x30319f14}, + {0x244, 0x00319f01}, + {0x248, 0x30319f14}, + {0x24c, 0x00319f01}, + {0x250, 0x30319f14}, + {0x254, 0x00319f01}, + {0x258, 0x30319f14}, + {0x25c, 0x00319f01} }; + +int can_change_ddr_freq(void) +{ + if (clk_get_usecount(epdc_clk) == 0) + return 1; + return 0; +} + +int update_ddr_freq(int ddr_rate) +{ + int i; + unsigned int reg; + + if (!can_change_ddr_freq()) + return -1; + + local_flush_tlb_all(); + flush_cache_all(); + + iram_ddr_settings[0][0] = ddr_settings_size; + if (ddr_rate == LP_APM_CLK) { + if (mx50_ddr_type == MX50_LPDDR2) { + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + iram_ddr_settings[i + 1][0] = + lpddr2_24[i][0]; + iram_ddr_settings[i + 1][1] = + lpddr2_24[i][1]; + } + } else { + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + iram_ddr_settings[i + 1][0] + = mddr_24[i][0]; + iram_ddr_settings[i + 1][1] + = mddr_24[i][1]; + } + } + } else { + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + iram_ddr_settings[i + 1][0] = + normal_databahn_settings[i][0]; + iram_ddr_settings[i + 1][1] = + normal_databahn_settings[i][1]; + } + if (ddr_rate == ddr_med_rate) { + /*Change the tref setting */ + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + if (iram_ddr_settings[i + 1][0] == 0x40) { + if (mx50_ddr_type == MX50_LPDDR2) + /* LPDDR2 133MHz. */ + iram_ddr_settings[i + 1][1] = + 0x00050180; + else + /* mDDR 133MHz. */ + iram_ddr_settings[i + 1][1] = + 0x00050208; + break; + } + } + } + } + /* Disable all masters from accessing the DDR. */ + reg = __raw_readl(qosc_base + HW_QOS_DISABLE); + reg |= 0xFFE; + __raw_writel(reg, qosc_base + HW_QOS_DISABLE_SET); + udelay(100); + + /* Set the DDR to default freq. */ + change_ddr_freq(ccm_base, databahn_base, ddr_rate, + iram_ddr_settings); + + /* Enable all masters to access the DDR. */ + __raw_writel(reg, qosc_base + HW_QOS_DISABLE_CLR); + + return 0; +} + +void init_ddr_settings(void) +{ + unsigned long iram_paddr; + unsigned int reg; + int i; + struct clk *ddr_clk = clk_get(NULL, "ddr_clk"); + + databahn_base = ioremap(MX50_DATABAHN_BASE_ADDR, SZ_16K); + + /* Find the memory type, LPDDR2 or mddr. */ + mx50_ddr_type = __raw_readl(databahn_base) & 0xF00; + if (mx50_ddr_type == MX50_LPDDR2) { + normal_databahn_settings = lpddr2_databhan_regs_offsets; + ddr_settings_size = ARRAY_SIZE(lpddr2_databhan_regs_offsets); + } + else if (mx50_ddr_type == MX50_MDDR) { + normal_databahn_settings = mddr_databhan_regs_offsets; + ddr_settings_size = ARRAY_SIZE(mddr_databhan_regs_offsets); + } else { + printk(KERN_DEBUG + "%s: Unsupported memory type\n", __func__); + return; + } + + /* Copy the databhan settings into the iram location. */ + for (i = 0; i < ddr_settings_size; i++) { + normal_databahn_settings[i][1] = + __raw_readl(databahn_base + + normal_databahn_settings[i][0]); + } + /* Store the size of the array in iRAM also, + * increase the size by 8 bytes. + */ + iram_ddr_settings = iram_alloc(ddr_settings_size + 8, &iram_paddr); + if (iram_ddr_settings == NULL) { + printk(KERN_DEBUG + "%s: failed to allocate iRAM memory for ddr settings\n", + __func__); + return; + } + + /* Allocate IRAM for the DDR freq change code. */ + iram_alloc(SZ_8K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + ddr_freq_change_iram_base = __arm_ioremap(iram_paddr, + SZ_8K, MT_MEMORY); + memcpy(ddr_freq_change_iram_base, mx50_ddr_freq_change, SZ_8K); + change_ddr_freq = (void *)ddr_freq_change_iram_base; + + qosc_base = ioremap(MX50_QOSC_BASE_ADDR, SZ_4K); + /* Enable the QoSC */ + reg = __raw_readl(qosc_base); + reg &= ~0xC0000000; + __raw_writel(reg, qosc_base); + + /* Allocate IRAM to run the WFI code from iram, since + * we can turn off the DDR clocks when ARM is in WFI. + */ + iram_alloc(SZ_4K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + wait_in_iram_base = __arm_ioremap(iram_paddr, + SZ_4K, MT_MEMORY); + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + + clk_enable(ddr_clk); + + /* Set the DDR to enter automatic self-refresh. */ + /* Set the DDR to automatically enter lower power mode 4. */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG22); + reg &= ~LOWPOWER_AUTOENABLE_MASK; + reg |= 1 << 1; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG22); + + /* set the counter for entering mode 4. */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG21); + reg &= ~LOWPOWER_EXTERNAL_CNT_MASK; + reg = 128 << LOWPOWER_EXTERNAL_CNT_OFFSET; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG21); + + /* Enable low power mode 4 */ + reg = __raw_readl(databahn_base + DATABAHN_CTL_REG20); + reg &= ~LOWPOWER_CONTROL_MASK; + reg |= 1 << 1; + __raw_writel(reg, databahn_base + DATABAHN_CTL_REG20); + clk_disable(ddr_clk); + + epdc_clk = clk_get(NULL, "epdc_axi"); + if (IS_ERR(epdc_clk)) { + printk(KERN_DEBUG "%s: failed to get epdc_axi_clk\n", + __func__); + return; + } +} diff --git a/arch/arm/mach-mx5/mx50_rdp_pmic_mc13892.c b/arch/arm/mach-mx5/mx50_rdp_pmic_mc13892.c new file mode 100644 index 00000000..b5946772 --- /dev/null +++ b/arch/arm/mach-mx5/mx50_rdp_pmic_mc13892.c @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/consumer.h> +#include <linux/gpio.h> +#include <mach/irqs.h> +#include <mach/iomux-mx50.h> + + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +/* Coin cell charger enable */ +#define COINCHEN_LSH 23 +#define COINCHEN_WID 1 +/* Coin cell charger voltage setting */ +#define VCOIN_LSH 20 +#define VCOIN_WID 3 + +/* Coin Charger voltage */ +#define VCOIN_2_5V 0x0 +#define VCOIN_2_7V 0x1 +#define VCOIN_2_8V 0x2 +#define VCOIN_2_9V 0x3 +#define VCOIN_3_0V 0x4 +#define VCOIN_3_1V 0x5 +#define VCOIN_3_2V 0x6 +#define VCOIN_3_3V 0x7 + +/* Keeps VSRTC and CLK32KMCU on for all states */ +#define DRM_LSH 4 +#define DRM_WID 1 + +/* regulator standby mask */ +#define GEN1_STBY_MASK (1 << 1) +#define IOHI_STBY_MASK (1 << 4) +#define DIG_STBY_MASK (1 << 10) +#define GEN2_STBY_MASK (1 << 13) +#define PLL_STBY_MASK (1 << 16) +#define USB2_STBY_MASK (1 << 19) + +#define GEN3_STBY_MASK (1 << 1) +#define CAM_STBY_MASK (1 << 7) +#define VIDEO_STBY_MASK (1 << 13) +#define AUDIO_STBY_MASK (1 << 16) +#define SD_STBY_MASK (1 << 19) + +#define REG_MODE_0_ALL_MASK (DIG_STBY_MASK | GEN1_STBY_MASK\ + | PLL_STBY_MASK | IOHI_STBY_MASK) +#define REG_MODE_1_ALL_MASK (CAM_STBY_MASK | VIDEO_STBY_MASK |\ + AUDIO_STBY_MASK | GEN3_STBY_MASK) + +/* switch mode setting */ +#define SW1MODE_LSB 0 +#define SW2MODE_LSB 10 +#define SW3MODE_LSB 0 +#define SW4MODE_LSB 8 + +#define SWMODE_MASK 0xF +#define SWMODE_AUTO 0x8 + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vddgp", + } +}; + +static struct regulator_consumer_supply sw2_consumers[] = { + { + .supply = "lp_vcc", + } +}; + +static struct regulator_consumer_supply sw4_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDA", + .dev_name = "1-000a", + }, +}; + +static struct regulator_consumer_supply vgen1_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDIO", + .dev_name = "1-000a", + }, +}; + +static struct regulator_consumer_supply vsd_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), +}; + +static struct regulator_consumer_supply vgen2_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), +}; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw2_consumers), + .consumer_supplies = sw2_consumers, +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + }, +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2775), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vsd_consumers), + .consumer_supplies = vsd_consumers, +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen2_consumers), + .consumer_supplies = vgen2_consumers, +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct mc13xxx_regulator_init_data mx50_rdp_regulators[] = { + { .id = MC13892_SW1, .init_data = &sw1_init }, + { .id = MC13892_SW2, .init_data = &sw2_init }, + { .id = MC13892_SW3, .init_data = &sw3_init }, + { .id = MC13892_SW4, .init_data = &sw4_init }, + { .id = MC13892_SWBST, .init_data = &swbst_init }, + { .id = MC13892_VIOHI, .init_data = &viohi_init }, + { .id = MC13892_VPLL, .init_data = &vpll_init }, + { .id = MC13892_VDIG, .init_data = &vdig_init }, + { .id = MC13892_VSD, .init_data = &vsd_init }, + { .id = MC13892_VUSB2, .init_data = &vusb2_init }, + { .id = MC13892_VVIDEO, .init_data = &vvideo_init }, + { .id = MC13892_VAUDIO, .init_data = &vaudio_init }, + { .id = MC13892_VCAM, .init_data = &vcam_init }, + { .id = MC13892_VGEN1, .init_data = &vgen1_init }, + { .id = MC13892_VGEN2, .init_data = &vgen2_init }, + { .id = MC13892_VGEN3, .init_data = &vgen3_init }, + { .id = MC13892_VUSB, .init_data = &vusb_init }, + { .id = MC13892_GPO1, .init_data = &gpo1_init }, + { .id = MC13892_GPO2, .init_data = &gpo2_init }, + { .id = MC13892_GPO3, .init_data = &gpo3_init }, + { .id = MC13892_GPO4, .init_data = &gpo4_init }, +}; + +static struct mc13xxx_platform_data mx50_rdp_mc13892_data = { + .flags = MC13XXX_USE_RTC | MC13XXX_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx50_rdp_regulators), + .regulators = mx50_rdp_regulators, +}; + + +static struct spi_board_info mx50_rdp_spi_device_info[] __initdata = { + { + .modalias = "mc13892", + .irq = gpio_to_irq(114), + .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */ + .bus_num = 3, + .chip_select = 0, + .platform_data = &mx50_rdp_mc13892_data, + }, +}; + + +int __init mx50_rdp_init_mc13892(void) +{ + return spi_register_board_info(mx50_rdp_spi_device_info, + ARRAY_SIZE(mx50_rdp_spi_device_info)); +} diff --git a/arch/arm/mach-mx5/mx50_suspend.S b/arch/arm/mach-mx5/mx50_suspend.S new file mode 100755 index 00000000..1ba15c8a --- /dev/null +++ b/arch/arm/mach-mx5/mx50_suspend.S @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> + +#define ARM_CTRL_DCACHE 1 << 2 +#define ARM_CTRL_ICACHE 1 << 12 +#define ARM_AUXCR_L2EN 1 << 1 + +/* + * mx50_suspend + * + * Suspend the processor (eg, wait for interrupt). + * Set the DDR into Self Refresh + * IRQs are already disabled. + */ +ENTRY(mx50_suspend) + stmfd sp!, {r4,r5,r6,r7,r8, r9,r10,r11} @ Save registers + + mov r6, r0 @save databahn address + +/* Before putting DDR into self-refresh, make sure + any LPM mode that the DDR might be in is exited. +*/ + /* If Databahn is in LPM4, exit that mode first. */ + ldr r8,[r6, #0x50] @Store LPM mode in r8 + mov r0, r8 + bic r0, r0, #0x1F + str r0,[r6, #0x50] + + + /* Disable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + bic r0, r0, #ARM_CTRL_ICACHE @ Disable ICache + bic r0, r0, #ARM_CTRL_DCACHE @ Disable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedClean + mov r10, #0 +Loop1Clean: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache Type + @ for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipClean @ No cache or only instruction cache + @ at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset + @ (log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the + @ way size (right aligned) + clz r5, r4 @ R5 is the bit position of the way + @ size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the index + @ size (right aligned) +Loop2Clean: + mov r9, r4 @ R9 working copy of the max way size + @ (right aligned) +Loop3Clean: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache + @ number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c14, 2 @ Clean and invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Clean + subs r7, r7, #1 @ Decrement the index + bge Loop2Clean +SkipClean: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Clean + +FinishedClean: + + /* Disable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + bic r0, r0, #ARM_AUXCR_L2EN @ Disable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + +/* Wait for the databahn to idle + Meaning, no access to the databahn is + being made. +*/ +EnterWFI: + ldr r0,[r6, #0x13c] + and r0, r0, #0x100 + ldr r2, =0x100 + cmp r0, r2 + beq EnterWFI + + /* Enter self-refresh mode */ + ldr r0,[r6, #0x4c] + orr r0,r0,#0x1 + str r0,[r6, #0x4c] + +LoopCKE0: + /* Wait for CKE = 0 */ + ldr r0,[r6, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + beq LoopCKE0 + + /* Stop controller */ + ldr r0,[r6] + bic r0, r0, #0x1 + str r0,[r6] + + .long 0xe320f003 @ Opcode for WFI + + /* Start controller */ + ldr r0,[r6] + orr r0,r0,#0x1 + str r0,[r6] + +LoopPHY: + /* Wait for PHY ready */ + ldr r0,[r6, #0x264] + and r0, r0, #0xfffffffe + ldr r2, =0x0 + cmp r0, r2 + beq LoopPHY + + /*Leave self-refresh mode */ + ldr r0,[r6, #0x4c] + and r0,r0,#0xfffffffe + str r0,[r6, #0x4c] + +LoopCKE1: + /*Wait for CKE = 1 */ + ldr r0,[r6, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + bne LoopCKE1 + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ Invalidate inst cache + +/* Invalidate data caches */ + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedInvalidate + mov r10, #0 +Loop1Invalidate: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache + @ Type for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipInvalidate @ No cache or only instruction cache + @at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset + @(log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the way + @size (right aligned) + clz r5, r4 @ R5 is the bit position of the way + @ size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the + @ index size (right aligned) +Loop2Invalidate: + mov r9, r4 @ R9 working copy of the max way + @ size (right aligned) +Loop3Invalidate: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache + @ number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c6, 2 @ Invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Invalidate + subs r7, r7, #1 @ Decrement the index + bge Loop2Invalidate +SkipInvalidate: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Invalidate + +FinishedInvalidate: + + /* Enable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + orr r0, r0, #ARM_AUXCR_L2EN @ Enable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + + /* Enable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + orr r0, r0, #ARM_CTRL_ICACHE @ Enable ICache + orr r0, r0, #ARM_CTRL_DCACHE @ Enable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + /* restore LPM mode. */ + str r8, [r6, #0x50] + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6,r7,r8,r9,r10,r11} + mov pc, lr + + .type mx50_do_suspend, #object +ENTRY(mx50_do_suspend) + .word mx50_suspend + .size mx50_suspend, . - mx50_suspend diff --git a/arch/arm/mach-mx5/mx50_wfi.S b/arch/arm/mach-mx5/mx50_wfi.S new file mode 100755 index 00000000..a3bf20dd --- /dev/null +++ b/arch/arm/mach-mx5/mx50_wfi.S @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include <linux/linkage.h> + +/* + * mx50_wait + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx50_wait) + stmfd sp!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} @ Save registers + + mov r6, r0 @save CCM address + mov r5, r1 @save DataBahn address + mov r7, r2 @save sys_clk usecount + + /* + * Make sure the DDR is self-refresh, before setting the clock bits. + */ + + /* Step 2: Poll the CKE_STATUS bit. */ +LoopCKE0: + /* Wait for CKE = 0 */ + ldr r0,[r5, #0xfc] + and r0, r0, #0x10000 + ldr r2, =0x10000 + cmp r0, r2 + beq LoopCKE0 + + /* Check if Databahn is in SYNC or ASYNC mode. */ + ldr r4, [r5, #0xdc] + and r4, r4, #0x30000 + cmp r4, #0x30000 + beq Sync_mode + + /* Set the DDR_CLKGATE to 0x1. */ + ldr r0, [r6, #0x98] + bic r0, r0, #0x80000000 + str r0, [r6, #0x98] + + .long 0xe320f003 @ Opcode for WFI + + /* Set the DDR_CLKGATE to 0x3. */ + ldr r0, [r6, #0x98] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x98] + b Wfi_Done + +Sync_mode: + /* If usecount of sys_clk is greater than 0, donot gate it. */ + cmp r7, #0 + bgt do_wfi + + /* Check if PLL1 is sourcing SYS_CLK. */ + ldr r5, [r6, #0x90] + and r5, r0, #0x1 + cmp r5, #0x1 + beq pll1_source + + /* Set the SYS_XTAL_CLKGATE to 0x1. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x80000000 + str r0, [r6, #0x94] + + /* Set the SYS_XTAL_DIV to 0xF (1.6MHz) to reduce power. + * since this clock is not gated when ARM is in WFI. + */ + + ldr r0, [r6, #0x94] + orr r0, r0, #0x3c0 + str r0, [r6, #0x94] + + b do_wfi +pll1_source: + /* Set the SYS_PLL_CLKGATE to 0x1. */ + ldr r0, [r6, #0x94] + bic r0, r0, #0x40000000 + str r0, [r6, #0x94] + +do_wfi: + .long 0xe320f003 @ Opcode for WFI + + cmp r7, #0 + bgt Wfi_Done + + cmp r5, #1 + beq pll1_source1 + /* Set the SYS_XTAL_DIV to 24MHz.*/ + ldr r0, [r6, #0x94] + bic r0, r0, #0x3c0 + orr r0, r0, #0x40 + str r0, [r6, #0x94] + + /* Set the SYS_XTAL_CLKGATE to 0x3. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0xC0000000 + str r0, [r6, #0x94] + b Wfi_Done + +pll1_source1: + /* Set the SYS_PLL_CLKGATE to 0x3. */ + ldr r0, [r6, #0x94] + orr r0, r0, #0x30000000 + str r0, [r6, #0x94] + +Wfi_Done: + /* Restore registers */ + ldmfd sp!, {r3,r4,r5,r6,r7,r8,r9,r10,r11} + mov pc, lr + + .type mx50_do_wait, #object +ENTRY(mx50_do_wait) + .word mx50_wait + .size mx50_wait, . - mx50_wait diff --git a/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c new file mode 100644 index 00000000..fcdc03bc --- /dev/null +++ b/arch/arm/mach-mx5/mx51_babbage_pmic_mc13892.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * 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. + + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * mx51-babbage-pmic-mc13892.c -- i.MX51 Babbage Driver for Atlas MC13892 PMIC + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/pmic_external.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13892.h> +#include <mach/irqs.h> +#include <mach/hardware.h> +#include <linux/gpio.h> +#include <mach/iomux-mx51.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_consumer_supply vdig_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDA", + .dev_name = "1-000a", + }, +}; + +static struct regulator_consumer_supply vvideo_consumers[] = { + { + /* sgtl5000 */ + .supply = "VDDIO", + .dev_name = "1-000a", + }, +}; + +struct mc13892; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = mV_to_uV(600), + .max_uV = mV_to_uV(1375), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = mV_to_uV(900), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = mV_to_uV(1100), + .max_uV = mV_to_uV(1850), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = mV_to_uV(1650), + .max_uV = mV_to_uV(1650), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vdig_consumers), + .consumer_supplies = vdig_consumers, +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1050), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2400), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = mV_to_uV(2775), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vvideo_consumers), + .consumer_supplies = vvideo_consumers, +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = mV_to_uV(2300), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1200), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3150), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = mV_to_uV(1800), + .max_uV = mV_to_uV(2900), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .always_on = 1, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static struct mc13xxx_regulator_init_data mx51_bbg_regulators[] = { + { .id = MC13892_SW1, .init_data = &sw1_init }, + { .id = MC13892_SW2, .init_data = &sw2_init }, + { .id = MC13892_SW3, .init_data = &sw3_init }, + { .id = MC13892_SW4, .init_data = &sw4_init }, + { .id = MC13892_SWBST, .init_data = &swbst_init }, + { .id = MC13892_VIOHI, .init_data = &viohi_init }, + { .id = MC13892_VPLL, .init_data = &vpll_init }, + { .id = MC13892_VDIG, .init_data = &vdig_init }, + { .id = MC13892_VSD, .init_data = &vsd_init }, + { .id = MC13892_VUSB2, .init_data = &vusb2_init }, + { .id = MC13892_VVIDEO, .init_data = &vvideo_init }, + { .id = MC13892_VAUDIO, .init_data = &vaudio_init }, + { .id = MC13892_VCAM, .init_data = &vcam_init }, + { .id = MC13892_VGEN1, .init_data = &vgen1_init }, + { .id = MC13892_VGEN2, .init_data = &vgen2_init }, + { .id = MC13892_VGEN3, .init_data = &vgen3_init }, + { .id = MC13892_VUSB, .init_data = &vusb_init }, + { .id = MC13892_GPO1, .init_data = &gpo1_init }, + { .id = MC13892_GPO2, .init_data = &gpo2_init }, + { .id = MC13892_GPO3, .init_data = &gpo3_init }, + { .id = MC13892_GPO4, .init_data = &gpo4_init }, +}; + +static struct mc13xxx_platform_data mc13892_plat = { + .flags = MC13XXX_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx51_bbg_regulators), + .regulators = mx51_bbg_regulators, +}; + +#define MC13892_SPI_IRQ gpio_to_irq(8) +static struct spi_board_info __initdata mc13892_spi_device = { + .modalias = "mc13892", + .irq = MC13892_SPI_IRQ, + .max_speed_hz = 6000000, /* max spi SCK clock speed in HZ */ + .bus_num = 0, + .chip_select = 0, + .platform_data = &mc13892_plat, +}; + + +int __init mx51_babbage_init_mc13892(void) +{ + return spi_register_board_info(&mc13892_spi_device, 1); +} + diff --git a/arch/arm/mach-mx5/mx51_efika.c b/arch/arm/mach-mx5/mx51_efika.c new file mode 100644 index 00000000..56739c23 --- /dev/null +++ b/arch/arm/mach-mx5/mx51_efika.c @@ -0,0 +1,634 @@ +/* + * based on code from the following + * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2009-2010 Pegatron Corporation. All Rights Reserved. + * Copyright 2009-2010 Genesi USA, Inc. All Rights Reserved. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/spi/flash.h> +#include <linux/spi/spi.h> +#include <linux/mfd/mc13892.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/consumer.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx51.h> + +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <mach/ulpi.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include "devices-imx51.h" +#include "devices.h" +#include "efika.h" +#include "cpu_op-mx51.h" + +#define MX51_USB_CTRL_1_OFFSET 0x10 +#define MX51_USB_CTRL_UH1_EXT_CLK_EN (1 << 25) +#define MX51_USB_PLL_DIV_19_2_MHZ 0x01 + +#define EFIKAMX_USB_HUB_RESET IMX_GPIO_NR(1, 5) +#define EFIKAMX_USBH1_STP IMX_GPIO_NR(1, 27) + +#define EFIKAMX_SPI_CS0 IMX_GPIO_NR(4, 24) +#define EFIKAMX_SPI_CS1 IMX_GPIO_NR(4, 25) + +#define EFIKAMX_PMIC IMX_GPIO_NR(1, 6) + +static iomux_v3_cfg_t mx51efika_pads[] = { + /* UART1 */ + MX51_PAD_UART1_RXD__UART1_RXD, + MX51_PAD_UART1_TXD__UART1_TXD, + MX51_PAD_UART1_RTS__UART1_RTS, + MX51_PAD_UART1_CTS__UART1_CTS, + + /* SD 1 */ + MX51_PAD_SD1_CMD__SD1_CMD, + MX51_PAD_SD1_CLK__SD1_CLK, + MX51_PAD_SD1_DATA0__SD1_DATA0, + MX51_PAD_SD1_DATA1__SD1_DATA1, + MX51_PAD_SD1_DATA2__SD1_DATA2, + MX51_PAD_SD1_DATA3__SD1_DATA3, + + /* SD 2 */ + MX51_PAD_SD2_CMD__SD2_CMD, + MX51_PAD_SD2_CLK__SD2_CLK, + MX51_PAD_SD2_DATA0__SD2_DATA0, + MX51_PAD_SD2_DATA1__SD2_DATA1, + MX51_PAD_SD2_DATA2__SD2_DATA2, + MX51_PAD_SD2_DATA3__SD2_DATA3, + + /* SD/MMC WP/CD */ + MX51_PAD_GPIO1_0__SD1_CD, + MX51_PAD_GPIO1_1__SD1_WP, + MX51_PAD_GPIO1_7__SD2_WP, + MX51_PAD_GPIO1_8__SD2_CD, + + /* spi */ + MX51_PAD_CSPI1_MOSI__ECSPI1_MOSI, + MX51_PAD_CSPI1_MISO__ECSPI1_MISO, + MX51_PAD_CSPI1_SS0__GPIO4_24, + MX51_PAD_CSPI1_SS1__GPIO4_25, + MX51_PAD_CSPI1_RDY__ECSPI1_RDY, + MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK, + MX51_PAD_GPIO1_6__GPIO1_6, + + /* USB HOST1 */ + MX51_PAD_USBH1_CLK__USBH1_CLK, + MX51_PAD_USBH1_DIR__USBH1_DIR, + MX51_PAD_USBH1_NXT__USBH1_NXT, + MX51_PAD_USBH1_DATA0__USBH1_DATA0, + MX51_PAD_USBH1_DATA1__USBH1_DATA1, + MX51_PAD_USBH1_DATA2__USBH1_DATA2, + MX51_PAD_USBH1_DATA3__USBH1_DATA3, + MX51_PAD_USBH1_DATA4__USBH1_DATA4, + MX51_PAD_USBH1_DATA5__USBH1_DATA5, + MX51_PAD_USBH1_DATA6__USBH1_DATA6, + MX51_PAD_USBH1_DATA7__USBH1_DATA7, + + /* USB HUB RESET */ + MX51_PAD_GPIO1_5__GPIO1_5, + + /* WLAN */ + MX51_PAD_EIM_A22__GPIO2_16, + MX51_PAD_EIM_A16__GPIO2_10, + + /* USB PHY RESET */ + MX51_PAD_EIM_D27__GPIO2_9, +}; + +/* Serial ports */ +static const struct imxuart_platform_data uart_pdata = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* This function is board specific as the bit mask for the plldiv will also + * be different for other Freescale SoCs, thus a common bitmask is not + * possible and cannot get place in /plat-mxc/ehci.c. + */ +static int initialize_otg_port(struct platform_device *pdev) +{ + u32 v; + void __iomem *usb_base; + void __iomem *usbother_base; + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + if (!usb_base) + return -ENOMEM; + usbother_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET); + + /* Set the PHY clock to 19.2MHz */ + v = __raw_readl(usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + v &= ~MX5_USB_UTMI_PHYCTRL1_PLLDIV_MASK; + v |= MX51_USB_PLL_DIV_19_2_MHZ; + __raw_writel(v, usbother_base + MXC_USB_PHY_CTR_FUNC2_OFFSET); + iounmap(usb_base); + + mdelay(10); + + return mx51_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY); +} + +static struct mxc_usbh_platform_data dr_utmi_config = { + .init = initialize_otg_port, + .portsc = MXC_EHCI_UTMI_16BIT, +}; + +static int initialize_usbh1_port(struct platform_device *pdev) +{ + iomux_v3_cfg_t usbh1stp = MX51_PAD_USBH1_STP__USBH1_STP; + iomux_v3_cfg_t usbh1gpio = MX51_PAD_USBH1_STP__GPIO1_27; + u32 v; + void __iomem *usb_base; + void __iomem *socregs_base; + + mxc_iomux_v3_setup_pad(usbh1gpio); + gpio_request(EFIKAMX_USBH1_STP, "usbh1_stp"); + gpio_direction_output(EFIKAMX_USBH1_STP, 0); + msleep(1); + gpio_set_value(EFIKAMX_USBH1_STP, 1); + msleep(1); + + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); + socregs_base = (void __iomem *)(usb_base + MX5_USBOTHER_REGS_OFFSET); + + /* The clock for the USBH1 ULPI port will come externally */ + /* from the PHY. */ + v = __raw_readl(socregs_base + MX51_USB_CTRL_1_OFFSET); + __raw_writel(v | MX51_USB_CTRL_UH1_EXT_CLK_EN, + socregs_base + MX51_USB_CTRL_1_OFFSET); + + iounmap(usb_base); + + gpio_free(EFIKAMX_USBH1_STP); + mxc_iomux_v3_setup_pad(usbh1stp); + + mdelay(10); + + return mx51_initialize_usb_hw(0, MXC_EHCI_ITC_NO_THRESHOLD); +} + +static struct mxc_usbh_platform_data usbh1_config = { + .init = initialize_usbh1_port, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static void mx51_efika_hubreset(void) +{ + gpio_request(EFIKAMX_USB_HUB_RESET, "usb_hub_rst"); + gpio_direction_output(EFIKAMX_USB_HUB_RESET, 1); + msleep(1); + gpio_set_value(EFIKAMX_USB_HUB_RESET, 0); + msleep(1); + gpio_set_value(EFIKAMX_USB_HUB_RESET, 1); +} + +static void __init mx51_efika_usb(void) +{ + mx51_efika_hubreset(); + + /* pulling it low, means no USB at all... */ + gpio_request(EFIKA_USB_PHY_RESET, "usb_phy_reset"); + gpio_direction_output(EFIKA_USB_PHY_RESET, 0); + msleep(1); + gpio_set_value(EFIKA_USB_PHY_RESET, 1); + + usbh1_config.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT | ULPI_OTG_EXTVBUSIND); + + mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config); + if (usbh1_config.otg) + mxc_register_device(&mxc_usbh1_device, &usbh1_config); +} + +static struct mtd_partition mx51_efika_spi_nor_partitions[] = { + { + .name = "u-boot", + .offset = 0, + .size = SZ_256K, + }, + { + .name = "config", + .offset = MTDPART_OFS_APPEND, + .size = SZ_64K, + }, +}; + +static struct flash_platform_data mx51_efika_spi_flash_data = { + .name = "spi_flash", + .parts = mx51_efika_spi_nor_partitions, + .nr_parts = ARRAY_SIZE(mx51_efika_spi_nor_partitions), + .type = "sst25vf032b", +}; + +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_consumer_supply vdig_consumers[] = { + /* sgtl5000 */ + REGULATOR_SUPPLY("VDDA", "1-000a"), + REGULATOR_SUPPLY("VDDD", "1-000a"), +}; + +static struct regulator_consumer_supply vvideo_consumers[] = { + /* sgtl5000 */ + REGULATOR_SUPPLY("VDDIO", "1-000a"), +}; + +static struct regulator_consumer_supply vsd_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), +}; + +static struct regulator_consumer_supply pwgt1_consumer[] = { + { + .supply = "pwgt1", + } +}; + +static struct regulator_consumer_supply pwgt2_consumer[] = { + { + .supply = "pwgt2", + } +}; + +static struct regulator_consumer_supply coincell_consumer[] = { + { + .supply = "coincell", + } +}; + +static struct regulator_init_data sw1_init = { + .constraints = { + .name = "SW1", + .min_uV = 600000, + .max_uV = 1375000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 850000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = 900000, + .max_uV = 1850000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .state_mem = { + .uV = 950000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = 1100000, + .max_uV = 1850000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", + .min_uV = 1100000, + .max_uV = 1850000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data viohi_init = { + .constraints = { + .name = "VIOHI", + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + } +}; + +static struct regulator_init_data vdig_init = { + .constraints = { + .name = "VDIG", + .min_uV = 1050000, + .max_uV = 1800000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vdig_consumers), + .consumer_supplies = vdig_consumers, +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = 1050000, + .max_uV = 1800000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = 2400000, + .max_uV = 2775000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vvideo_init = { + .constraints = { + .name = "VVIDEO", + .min_uV = 2775000, + .max_uV = 2775000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .apply_uV = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vvideo_consumers), + .consumer_supplies = vvideo_consumers, +}; + +static struct regulator_init_data vaudio_init = { + .constraints = { + .name = "VAUDIO", + .min_uV = 2300000, + .max_uV = 3000000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + } +}; + +static struct regulator_init_data vsd_init = { + .constraints = { + .name = "VSD", + .min_uV = 1800000, + .max_uV = 3150000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vsd_consumers), + .consumer_supplies = vsd_consumers, +}; + +static struct regulator_init_data vcam_init = { + .constraints = { + .name = "VCAM", + .min_uV = 2500000, + .max_uV = 3000000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_FAST | REGULATOR_MODE_NORMAL, + .boot_on = 1, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = 1200000, + .max_uV = 3150000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = 1200000, + .max_uV = 3150000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = 1800000, + .max_uV = 2900000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data gpo1_init = { + .constraints = { + .name = "GPO1", + } +}; + +static struct regulator_init_data gpo2_init = { + .constraints = { + .name = "GPO2", + } +}; + +static struct regulator_init_data gpo3_init = { + .constraints = { + .name = "GPO3", + } +}; + +static struct regulator_init_data gpo4_init = { + .constraints = { + .name = "GPO4", + } +}; + +static struct regulator_init_data pwgt1_init = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(pwgt1_consumer), + .consumer_supplies = pwgt1_consumer, +}; + +static struct regulator_init_data pwgt2_init = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(pwgt2_consumer), + .consumer_supplies = pwgt2_consumer, +}; + +static struct regulator_init_data vcoincell_init = { + .constraints = { + .name = "COINCELL", + .min_uV = 3000000, + .max_uV = 3000000, + .valid_ops_mask = + REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(coincell_consumer), + .consumer_supplies = coincell_consumer, +}; + +static struct mc13xxx_regulator_init_data mx51_efika_regulators[] = { + { .id = MC13892_SW1, .init_data = &sw1_init }, + { .id = MC13892_SW2, .init_data = &sw2_init }, + { .id = MC13892_SW3, .init_data = &sw3_init }, + { .id = MC13892_SW4, .init_data = &sw4_init }, + { .id = MC13892_SWBST, .init_data = &swbst_init }, + { .id = MC13892_VIOHI, .init_data = &viohi_init }, + { .id = MC13892_VPLL, .init_data = &vpll_init }, + { .id = MC13892_VDIG, .init_data = &vdig_init }, + { .id = MC13892_VSD, .init_data = &vsd_init }, + { .id = MC13892_VUSB2, .init_data = &vusb2_init }, + { .id = MC13892_VVIDEO, .init_data = &vvideo_init }, + { .id = MC13892_VAUDIO, .init_data = &vaudio_init }, + { .id = MC13892_VCAM, .init_data = &vcam_init }, + { .id = MC13892_VGEN1, .init_data = &vgen1_init }, + { .id = MC13892_VGEN2, .init_data = &vgen2_init }, + { .id = MC13892_VGEN3, .init_data = &vgen3_init }, + { .id = MC13892_VUSB, .init_data = &vusb_init }, + { .id = MC13892_GPO1, .init_data = &gpo1_init }, + { .id = MC13892_GPO2, .init_data = &gpo2_init }, + { .id = MC13892_GPO3, .init_data = &gpo3_init }, + { .id = MC13892_GPO4, .init_data = &gpo4_init }, + { .id = MC13892_PWGT1SPI, .init_data = &pwgt1_init }, + { .id = MC13892_PWGT2SPI, .init_data = &pwgt2_init }, + { .id = MC13892_VCOINCELL, .init_data = &vcoincell_init }, +}; + +static struct mc13xxx_platform_data mx51_efika_mc13892_data = { + .flags = MC13XXX_USE_RTC | MC13XXX_USE_REGULATOR, + .regulators = { + .num_regulators = ARRAY_SIZE(mx51_efika_regulators), + .regulators = mx51_efika_regulators, + }, +}; + +static struct spi_board_info mx51_efika_spi_board_info[] __initdata = { + { + .modalias = "m25p80", + .max_speed_hz = 25000000, + .bus_num = 0, + .chip_select = 1, + .platform_data = &mx51_efika_spi_flash_data, + .irq = -1, + }, + { + .modalias = "mc13892", + .max_speed_hz = 1000000, + .bus_num = 0, + .chip_select = 0, + .platform_data = &mx51_efika_mc13892_data, + .irq = gpio_to_irq(EFIKAMX_PMIC), + }, +}; + +static int mx51_efika_spi_cs[] = { + EFIKAMX_SPI_CS0, + EFIKAMX_SPI_CS1, +}; + +static const struct spi_imx_master mx51_efika_spi_pdata __initconst = { + .chipselect = mx51_efika_spi_cs, + .num_chipselect = ARRAY_SIZE(mx51_efika_spi_cs), +}; + +void __init efika_board_common_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx51efika_pads, + ARRAY_SIZE(mx51efika_pads)); + imx51_add_imx_uart(0, &uart_pdata); + mx51_efika_usb(); + imx51_add_sdhci_esdhc_imx(0, NULL); + + /* FIXME: comes from original code. check this. */ + if (mx51_revision() < IMX_CHIP_REVISION_2_0) + sw2_init.constraints.state_mem.uV = 1100000; + else if (mx51_revision() == IMX_CHIP_REVISION_2_0) { + sw2_init.constraints.state_mem.uV = 1250000; + sw1_init.constraints.state_mem.uV = 1000000; + } + if (machine_is_mx51_efikasb()) + vgen1_init.constraints.max_uV = 1200000; + + gpio_request(EFIKAMX_PMIC, "pmic irq"); + gpio_direction_input(EFIKAMX_PMIC); + spi_register_board_info(mx51_efika_spi_board_info, + ARRAY_SIZE(mx51_efika_spi_board_info)); + imx51_add_ecspi(0, &mx51_efika_spi_pdata); + +#if defined(CONFIG_CPU_FREQ_IMX) + get_cpu_op = mx51_get_cpu_op; +#endif +} + diff --git a/arch/arm/mach-mx5/mx53_loco_pmic_da9053.c b/arch/arm/mach-mx5/mx53_loco_pmic_da9053.c new file mode 100755 index 00000000..9259fd01 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_loco_pmic_da9053.c @@ -0,0 +1,300 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +/* + * mx53_loco_pmic_da9053.c -- i.MX53 LOCO driver for pmic da9053 + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/pm.h> +#include <linux/mfd/da9052/led.h> +#include <linux/mfd/da9052/tsi.h> +#include <mach/irqs.h> +#include <mach/iomux-mx53.h> +#include <mach/gpio.h> + +#define DA9052_LDO(max, min, rname, suspend_mv, num_consumers, consumers) \ +{\ + .constraints = {\ + .name = (rname), \ + .max_uV = (max) * 1000,\ + .min_uV = (min) * 1000,\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\ + |REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\ + .valid_modes_mask = REGULATOR_MODE_NORMAL,\ + .state_mem = { \ + .uV = suspend_mv * 1000, \ + .mode = REGULATOR_MODE_NORMAL, \ + .enabled = (0 == suspend_mv) ? 0 : 1, \ + .disabled = 0, \ + }, \ + },\ + .num_consumer_supplies = (num_consumers), \ + .consumer_supplies = (consumers), \ +} + +#ifdef CONFIG_SND_SOC_SGTL5000 + +static struct regulator_consumer_supply sgtl5000_consumer[] = { + REGULATOR_SUPPLY("VDDA", NULL), + REGULATOR_SUPPLY("VDDIO", NULL), +}; + +static struct regulator_init_data sgtl5000_reg_initdata = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sgtl5000_consumer), + .consumer_supplies = &sgtl5000_consumer[0], +}; + +static struct fixed_voltage_config sgtl5000_reg_config = { + .supply_name = "VDDA", + .microvolts = 3200000, + .gpio = -1, + .init_data = &sgtl5000_reg_initdata, +}; + +static struct platform_device sgtl5000_reg_devices = { + + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &sgtl5000_reg_config, + }, +}; +#endif /* CONFIG_SND_SOC_SGTL5000 */ + +/* CPU */ +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "cpu_vddgp", + } +}; + +/* currently the suspend_mv here takes no effects for DA9053 +preset-voltage have to be done in the latest stage during +suspend*/ +static struct regulator_init_data da9052_regulators_init[] = { + DA9052_LDO(DA9052_LDO1_VOLT_UPPER, + DA9052_LDO1_VOLT_LOWER, "DA9052_LDO1", 1300, 0, NULL), + DA9052_LDO(DA9052_LDO2_VOLT_UPPER, + DA9052_LDO2_VOLT_LOWER, "DA9052_LDO2", 1300, 0, NULL), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO3", 3300, 0, NULL), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO4", 2775, 0, NULL), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO5", 1300, 0, NULL), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO6", 1200, 0, NULL), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO7", 2750, 0, NULL), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO8", 1800, 0, NULL), + DA9052_LDO(DA9052_LDO9_VOLT_UPPER, + DA9052_LDO9_VOLT_LOWER, "DA9052_LDO9", 2500, 0, NULL), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO10", 1200, 0, NULL), + + /* BUCKS */ + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_CORE", 850, + ARRAY_SIZE(sw1_consumers), sw1_consumers), + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_PRO", 950, + 0, NULL), + DA9052_LDO(DA9052_BUCK_MEM_VOLT_UPPER, + DA9052_BUCK_MEM_VOLT_LOWER, "DA9052_BUCK_MEM", 1500, 0, NULL), + DA9052_LDO(DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, "DA9052_BUCK_PERI", 2500, 0, NULL) +}; + + +static struct da9052_tsi_platform_data da9052_tsi = { + .pen_up_interval = 50, + .tsi_delay_bit_shift = 6, + .tsi_skip_bit_shift = 3, + .num_gpio_tsi_register = 3, + .tsi_supply_voltage = 2500, + /* This is the DA9052 LDO number used for powering the TSI */ + .tsi_ref_source = 9, + .max_tsi_delay = TSI_DELAY_4SLOTS, + .max_tsi_skip_slot = TSI_SKIP_330SLOTS, +}; + +static struct da9052_led_platform_data da9052_gpio_led[] = { + { + .id = DA9052_LED_4, + .name = "LED_GPIO14", + }, + { + .id = DA9052_LED_5, + .name = "LED_GPIO15", + }, +}; + +static struct da9052_leds_platform_data da9052_gpio_leds = { + .num_leds = ARRAY_SIZE(da9052_gpio_led), + .led = da9052_gpio_led, +}; + + +static void da9052_init_ssc_cache(struct da9052 *da9052) +{ + unsigned char cnt; + + /* First initialize all registers as Non-volatile */ + for (cnt = 0; cnt < DA9052_REG_CNT; cnt++) { + da9052->ssc_cache[cnt].type = NON_VOLATILE; + da9052->ssc_cache[cnt].status = INVALID; + da9052->ssc_cache[cnt].val = 0; + } + + /* Now selectively set type for all Volatile registers */ + /* Reg 1 - 9 */ + da9052->ssc_cache[DA9052_STATUSA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_FAULTLOG_REG].type = VOLATILE; + + /* Reg 15 */ + da9052->ssc_cache[DA9052_CONTROLB_REG].type = VOLATILE; + /* Reg - 17 */ + da9052->ssc_cache[DA9052_CONTROLD_REG].type = VOLATILE; + /* Reg - 60 */ + da9052->ssc_cache[DA9052_SUPPLY_REG].type = VOLATILE; + /* Reg - 62 */ + da9052->ssc_cache[DA9052_CHGBUCK_REG].type = VOLATILE; + + /* Reg 67 - 68 */ + da9052->ssc_cache[DA9052_INPUTCONT_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_CHGTIME_REG].type = VOLATILE; + + /* Reg - 70 */ + da9052->ssc_cache[DA9052_BOOST_REG].type = VOLATILE; + + /* Reg - 81 */ + da9052->ssc_cache[DA9052_ADCMAN_REG].type = VOLATILE; + + /* Reg - 83 - 85 */ + da9052->ssc_cache[DA9052_ADCRESL_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ADCRESH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_VDDRES_REG].type = VOLATILE; + + /* Reg - 87 */ + da9052->ssc_cache[DA9052_ICHGAV_REG].type = VOLATILE; + + /* Reg - 90 */ + da9052->ssc_cache[DA9052_TBATRES_REG].type = VOLATILE; + + /* Reg - 95 */ + da9052->ssc_cache[DA9052_ADCIN4RES_REG].type = VOLATILE; + + /* Reg - 98 */ + da9052->ssc_cache[DA9052_ADCIN5RES_REG].type = VOLATILE; + + /* Reg - 101 */ + da9052->ssc_cache[DA9052_ADCIN6RES_REG].type = VOLATILE; + + /* Reg - 104 */ + da9052->ssc_cache[DA9052_TJUNCRES_REG].type = VOLATILE; + + /* Reg 106 - 110 */ + da9052->ssc_cache[DA9052_TSICONTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIXMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIYMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSILSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIZMSB_REG].type = VOLATILE; + + /* Reg 111 - 117 */ + da9052->ssc_cache[DA9052_COUNTS_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMI_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMO_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTY_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ALARMMI_REG].type = VOLATILE; + + /* Reg 122 - 125 */ + da9052->ssc_cache[DA9052_SECONDA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDD_REG].type = VOLATILE; + + /* Following addresses are not assigned to any register */ + da9052->ssc_cache[126].type = VOLATILE; + da9052->ssc_cache[127].type = VOLATILE; +} + + +#define MX53_LOCO_DA9052_IRQ (6*32 + 11) /* GPIO7_11 */ + +static int __init loco_da9052_init(struct da9052 *da9052) +{ + /* Configuring for DA9052 interrupt servce */ + /* s3c_gpio_setpull(DA9052_IRQ_PIN, S3C_GPIO_PULL_UP);*/ + + /* Set interrupt as LOW LEVEL interrupt source */ + set_irq_type(gpio_to_irq(MX53_LOCO_DA9052_IRQ), IRQF_TRIGGER_LOW); + + da9052_init_ssc_cache(da9052); + +#ifdef CONFIG_SND_SOC_SGTL5000 + platform_device_register(&sgtl5000_reg_devices); +#endif + + return 0; +} + +static struct da9052_platform_data __initdata da9052_plat = { + .init = loco_da9052_init, + .num_regulators = ARRAY_SIZE(da9052_regulators_init), + .regulators = da9052_regulators_init, + .led_data = &da9052_gpio_leds, + .tsi_data = &da9052_tsi, + /* .bat_data = &da9052_bat, */ + /* .gpio_base = GPIO_BOARD_START, */ +}; + + +static struct i2c_board_info __initdata da9052_i2c_device = { + I2C_BOARD_INFO(DA9052_SSC_I2C_DEVICE_NAME, DA9052_I2C_ADDR >> 1), + .irq = gpio_to_irq(MX53_LOCO_DA9052_IRQ), + .platform_data = &da9052_plat, +}; + +int __init mx53_loco_init_da9052(void) +{ + return i2c_register_board_info(0, &da9052_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/mx53_loco_pmic_mc34708.c b/arch/arm/mach-mx5/mx53_loco_pmic_mc34708.c new file mode 100644 index 00000000..f88a184a --- /dev/null +++ b/arch/arm/mach-mx5/mx53_loco_pmic_mc34708.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc-pmic.h> +#include <mach/irqs.h> +#include <mach/iomux-mx53.h> + +/* + * Convenience conversion. + * Here atm, maybe there is somewhere better for this. + */ +#define mV_to_uV(mV) (mV * 1000) +#define uV_to_mV(uV) (uV / 1000) +#define V_to_uV(V) (mV_to_uV(V * 1000)) +#define uV_to_V(uV) (uV_to_mV(uV) / 1000) + +#define MC34708_I2C_DEVICE_NAME "mc34708" +/* 7-bit I2C bus slave address */ +#define MC34708_I2C_ADDR (0x08) + + +static struct regulator_init_data sw1a_init = { + .constraints = { + .name = "SW1", + .min_uV = 650000, + .max_uV = 1437500, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw1b_init = { + .constraints = { + .name = "SW1B", + .min_uV = 650000, + .max_uV = 1437500, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", + .min_uV = 650000, + .max_uV = 1437500, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + } +}; + +static struct regulator_init_data sw3_init = { + .constraints = { + .name = "SW3", + .min_uV = 650000, + .max_uV = 1425000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4a_init = { + .constraints = { + .name = "SW4A", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3300), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw4b_init = { + .constraints = { + .name = "SW4B", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(3300), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data sw5_init = { + .constraints = { + .name = "SW5", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1975), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vrefddr_init = { + .constraints = { + .name = "VREFDDR", + .always_on = 1, + .boot_on = 1, + } +}; + +static struct regulator_init_data vusb_init = { + .constraints = { + .name = "VUSB", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vpll_init = { + .constraints = { + .name = "VPLL", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1800), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vdac_init = { + .constraints = { + .name = "VDAC", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(2775), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vusb2_init = { + .constraints = { + .name = "VUSB2", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3000), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", + .min_uV = mV_to_uV(1200), + .max_uV = mV_to_uV(1550), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + } +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", + .min_uV = mV_to_uV(2500), + .max_uV = mV_to_uV(3300), + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .always_on = 1, + } +}; + +static struct mc_pmic_regulator_init_data mx53_loco_mc34708_regulators[] = { + { .id = MC34708_SW1A, .init_data = &sw1a_init}, + { .id = MC34708_SW1B, .init_data = &sw1b_init}, + { .id = MC34708_SW2, .init_data = &sw2_init}, + { .id = MC34708_SW3, .init_data = &sw3_init}, + { .id = MC34708_SW4A, .init_data = &sw4a_init}, + { .id = MC34708_SW4B, .init_data = &sw4b_init}, + { .id = MC34708_SW5, .init_data = &sw5_init}, + { .id = MC34708_SWBST, .init_data = &swbst_init}, + { .id = MC34708_VPLL, .init_data = &vpll_init}, + { .id = MC34708_VREFDDR, .init_data = &vrefddr_init}, + { .id = MC34708_VUSB, .init_data = &vusb_init}, + { .id = MC34708_VUSB2, .init_data = &vusb2_init}, + { .id = MC34708_VDAC, .init_data = &vdac_init}, + { .id = MC34708_VGEN1, .init_data = &vgen1_init}, + { .id = MC34708_VGEN2, .init_data = &vgen2_init}, + +}; + + +static struct mc_pmic_platform_data mc34708_plat = { + .flags = MC_PMIC_USE_RTC | MC_PMIC_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx53_loco_mc34708_regulators), + .regulators = mx53_loco_mc34708_regulators, +}; + +static struct i2c_board_info __initdata mc34708_i2c_device = { + I2C_BOARD_INFO(MC34708_I2C_DEVICE_NAME, MC34708_I2C_ADDR), + .platform_data = &mc34708_plat, +}; + +int __init mx53_loco_init_mc34708(u32 int_gpio) +{ + mc34708_i2c_device.irq = gpio_to_irq(int_gpio);/*update INT gpio*/ + return i2c_register_board_info(0, &mc34708_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/mx53_smd_pmic_da9053.c b/arch/arm/mach-mx5/mx53_smd_pmic_da9053.c new file mode 100755 index 00000000..ae39b845 --- /dev/null +++ b/arch/arm/mach-mx5/mx53_smd_pmic_da9053.c @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. + * + * This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + + +/* + * mx53_smd_pmic_da9053.c -- i.MX53 SMD driver for pmic da9053 + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/da9052/da9052.h> +#include <linux/mfd/da9052/pm.h> +#include <linux/mfd/da9052/led.h> +#include <linux/mfd/da9052/tsi.h> +#include <mach/irqs.h> +#include <mach/iomux-mx53.h> +#include <mach/gpio.h> + +#define DA9052_LDO(max, min, rname, suspend_mv) \ +{\ + .constraints = {\ + .name = (rname), \ + .max_uV = (max) * 1000,\ + .min_uV = (min) * 1000,\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE\ + |REGULATOR_CHANGE_STATUS | REGULATOR_CHANGE_MODE,\ + .valid_modes_mask = REGULATOR_MODE_NORMAL,\ + .state_mem = { \ + .uV = suspend_mv * 1000, \ + .mode = REGULATOR_MODE_NORMAL, \ + .enabled = (0 == suspend_mv) ? 0 : 1, \ + .disabled = 0, \ + }, \ + },\ +} + +/* currently the suspend_mv field here takes no effects for DA9053 +preset-voltage have to be done in the latest stage during +suspend*/ +static struct regulator_init_data da9052_regulators_init[] = { + DA9052_LDO(DA9052_LDO1_VOLT_UPPER, + DA9052_LDO1_VOLT_LOWER, "DA9052_LDO1", 1300), + DA9052_LDO(DA9052_LDO2_VOLT_UPPER, + DA9052_LDO2_VOLT_LOWER, "DA9052_LDO2", 1300), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO3", 3300), + DA9052_LDO(DA9052_LDO34_VOLT_UPPER, + DA9052_LDO34_VOLT_LOWER, "DA9052_LDO4", 2775), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO5", 1300), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO6", 1200), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO7", 2750), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO8", 1800), + DA9052_LDO(DA9052_LDO9_VOLT_UPPER, + DA9052_LDO9_VOLT_LOWER, "DA9052_LDO9", 2500), + DA9052_LDO(DA9052_LDO567810_VOLT_UPPER, + DA9052_LDO567810_VOLT_LOWER, "DA9052_LDO10", 1200), + + /* BUCKS */ + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_CORE", 850), + DA9052_LDO(DA9052_BUCK_CORE_PRO_VOLT_UPPER, + DA9052_BUCK_CORE_PRO_VOLT_LOWER, "DA9052_BUCK_PRO", 950), + DA9052_LDO(DA9052_BUCK_MEM_VOLT_UPPER, + DA9052_BUCK_MEM_VOLT_LOWER, "DA9052_BUCK_MEM", 1500), + DA9052_LDO(DA9052_BUCK_PERI_VOLT_UPPER, + DA9052_BUCK_PERI_VOLT_LOWER, "DA9052_BUCK_PERI", 2500) +}; + + +#define MX53_SMD_WiFi_BT_PWR_EN (2*32 + 10) /*GPIO_3_10 */ +struct regulator_init_data wifi_bt_reg_initdata = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +}; + +static struct fixed_voltage_config wifi_bt_reg_config = { + .supply_name = "wifi_bt", + .microvolts = 3300000, + .gpio = MX53_SMD_WiFi_BT_PWR_EN, + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &wifi_bt_reg_initdata, +}; + +static struct platform_device wifi_bt_reg_device = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &wifi_bt_reg_config, + }, +}; + +#ifdef CONFIG_SND_SOC_SGTL5000 + +static struct regulator_consumer_supply sgtl5000_consumer[] = { + REGULATOR_SUPPLY("VDDA", NULL), + REGULATOR_SUPPLY("VDDIO", NULL), +}; + +static struct regulator_init_data sgtl5000_reg_initdata = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sgtl5000_consumer), + .consumer_supplies = &sgtl5000_consumer[0], +}; + +static struct fixed_voltage_config sgtl5000_reg_config = { + .supply_name = "VDDA", + .microvolts = 3300000, + .gpio = -1, + .init_data = &sgtl5000_reg_initdata, +}; + +static struct platform_device sgtl5000_reg_devices = { + + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &sgtl5000_reg_config, + }, +}; +#endif /* CONFIG_SND_SOC_SGTL5000 */ + +static struct da9052_tsi_platform_data da9052_tsi = { + .pen_up_interval = 50, + .tsi_delay_bit_shift = 6, + .tsi_skip_bit_shift = 3, + .num_gpio_tsi_register = 3, + .tsi_supply_voltage = 2500, + /* This is the DA9052 LDO number used for powering the TSI */ + .tsi_ref_source = 9, + .max_tsi_delay = TSI_DELAY_4SLOTS, + .max_tsi_skip_slot = TSI_SKIP_330SLOTS, +}; + +static struct da9052_led_platform_data da9052_gpio_led[] = { + { + .id = DA9052_LED_4, + .name = "LED_GPIO14", + }, + { + .id = DA9052_LED_5, + .name = "LED_GPIO15", + }, +}; + +static struct da9052_leds_platform_data da9052_gpio_leds = { + .num_leds = ARRAY_SIZE(da9052_gpio_led), + .led = da9052_gpio_led, +}; + + +static void da9052_init_ssc_cache(struct da9052 *da9052) +{ + unsigned char cnt; + + /* First initialize all registers as Non-volatile */ + for (cnt = 0; cnt < DA9052_REG_CNT; cnt++) { + da9052->ssc_cache[cnt].type = NON_VOLATILE; + da9052->ssc_cache[cnt].status = INVALID; + da9052->ssc_cache[cnt].val = 0; + } + + /* Now selectively set type for all Volatile registers */ + /* Reg 1 - 9 */ + da9052->ssc_cache[DA9052_STATUSA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_STATUSD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_EVENTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_FAULTLOG_REG].type = VOLATILE; + + /* Reg 15 */ + da9052->ssc_cache[DA9052_CONTROLB_REG].type = VOLATILE; + /* Reg - 17 */ + da9052->ssc_cache[DA9052_CONTROLD_REG].type = VOLATILE; + /* Reg - 60 */ + da9052->ssc_cache[DA9052_SUPPLY_REG].type = VOLATILE; + /* Reg - 62 */ + da9052->ssc_cache[DA9052_CHGBUCK_REG].type = VOLATILE; + + /* Reg 67 - 68 */ + da9052->ssc_cache[DA9052_INPUTCONT_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_CHGTIME_REG].type = VOLATILE; + + /* Reg - 70 */ + da9052->ssc_cache[DA9052_BOOST_REG].type = VOLATILE; + + /* Reg - 81 */ + da9052->ssc_cache[DA9052_ADCMAN_REG].type = VOLATILE; + + /* Reg - 83 - 85 */ + da9052->ssc_cache[DA9052_ADCRESL_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ADCRESH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_VDDRES_REG].type = VOLATILE; + + /* Reg - 87 */ + da9052->ssc_cache[DA9052_ICHGAV_REG].type = VOLATILE; + + /* Reg - 90 */ + da9052->ssc_cache[DA9052_TBATRES_REG].type = VOLATILE; + + /* Reg - 95 */ + da9052->ssc_cache[DA9052_ADCIN4RES_REG].type = VOLATILE; + + /* Reg - 98 */ + da9052->ssc_cache[DA9052_ADCIN5RES_REG].type = VOLATILE; + + /* Reg - 101 */ + da9052->ssc_cache[DA9052_ADCIN6RES_REG].type = VOLATILE; + + /* Reg - 104 */ + da9052->ssc_cache[DA9052_TJUNCRES_REG].type = VOLATILE; + + /* Reg 106 - 110 */ + da9052->ssc_cache[DA9052_TSICONTB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIXMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIYMSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSILSB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_TSIZMSB_REG].type = VOLATILE; + + /* Reg 111 - 117 */ + da9052->ssc_cache[DA9052_COUNTS_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMI_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTH_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTD_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTMO_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_COUNTY_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_ALARMMI_REG].type = VOLATILE; + + /* Reg 122 - 125 */ + da9052->ssc_cache[DA9052_SECONDA_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDB_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDC_REG].type = VOLATILE; + da9052->ssc_cache[DA9052_SECONDD_REG].type = VOLATILE; + + /* Following addresses are not assigned to any register */ + da9052->ssc_cache[126].type = VOLATILE; + da9052->ssc_cache[127].type = VOLATILE; +} + + +#define MX53_SMD_DA9052_IRQ (6*32 + 11) /* GPIO7_11 */ + +static int __init smd_da9052_init(struct da9052 *da9052) +{ + /* Configuring for DA9052 interrupt servce */ + /* s3c_gpio_setpull(DA9052_IRQ_PIN, S3C_GPIO_PULL_UP);*/ + int ret; + /* Set interrupt as LOW LEVEL interrupt source */ + set_irq_type(gpio_to_irq(MX53_SMD_DA9052_IRQ), IRQF_TRIGGER_LOW); + + da9052_init_ssc_cache(da9052); +#ifdef CONFIG_SND_SOC_SGTL5000 + platform_device_register(&sgtl5000_reg_devices); +#endif + ret = platform_device_register(&wifi_bt_reg_device); + + return 0; +} + +static struct da9052_platform_data __initdata da9052_plat = { + .init = smd_da9052_init, + .num_regulators = ARRAY_SIZE(da9052_regulators_init), + .regulators = da9052_regulators_init, + .led_data = &da9052_gpio_leds, + .tsi_data = &da9052_tsi, + /* .bat_data = &da9052_bat, */ + /* .gpio_base = GPIO_BOARD_START, */ +}; + + +static struct i2c_board_info __initdata da9052_i2c_device = { + I2C_BOARD_INFO(DA9052_SSC_I2C_DEVICE_NAME, DA9052_I2C_ADDR >> 1), + .irq = gpio_to_irq(MX53_SMD_DA9052_IRQ), + .platform_data = &da9052_plat, +}; + +int __init mx53_smd_init_da9052(void) +{ + return i2c_register_board_info(0, &da9052_i2c_device, 1); +} diff --git a/arch/arm/mach-mx5/pm.c b/arch/arm/mach-mx5/pm.c new file mode 100755 index 00000000..9240b7ae --- /dev/null +++ b/arch/arm/mach-mx5/pm.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/suspend.h> +#include <linux/regulator/machine.h> +#include <linux/proc_fs.h> +#include <linux/cpufreq.h> +#include <linux/iram_alloc.h> +#include <linux/fsl_devices.h> +#include <asm/mach-types.h> +#include <asm/cacheflush.h> +#include <asm/tlb.h> +#include <asm/delay.h> +#include <asm/mach/map.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#ifdef CONFIG_ARCH_MX50 +#include <mach/iomux-mx50.h> +#endif +#include "crm_regs.h" + +#define DATABAHN_CTL_REG0 0 +#define DATABAHN_CTL_REG19 0x4c +#define DATABAHN_CTL_REG79 0x13c +#define DATABAHN_PHY_REG25 0x264 +#define MX53_OFFSET 0x20000000 + +static struct cpu_op *cpu_op_tbl; +static int cpu_op_nr; +static struct clk *cpu_clk; +static struct mxc_pm_platform_data *pm_data; + +#if defined(CONFIG_CPU_FREQ) +static int org_freq; +extern int set_cpu_freq(int wp); +#endif + + +static struct device *pm_dev; +struct clk *gpc_dvfs_clk; +extern void cpu_do_suspend_workaround(u32 sdclk_iomux_addr); +extern void mx50_suspend(u32 databahn_addr); +extern struct cpu_op *(*get_cpu_op)(int *wp); +extern void __iomem *databahn_base; +extern void da9053_suspend_cmd(void); +extern void da9053_resume_dump(void); +extern void pm_da9053_i2c_init(u32 base_addr); + +extern int iram_ready; +void *suspend_iram_base; +void (*suspend_in_iram)(void *sdclk_iomux_addr) = NULL; +void __iomem *suspend_param1; + +#define TZIC_WAKEUP0_OFFSET 0x0E00 +#define TZIC_WAKEUP1_OFFSET 0x0E04 +#define TZIC_WAKEUP2_OFFSET 0x0E08 +#define TZIC_WAKEUP3_OFFSET 0x0E0C +#define GPIO7_0_11_IRQ_BIT (0x1<<11) + +static void mx53_smd_loco_irq_wake_fixup(void) +{ + void __iomem *tzic_base; + tzic_base = ioremap(MX53_TZIC_BASE_ADDR, SZ_4K); + if (NULL == tzic_base) { + pr_err("fail to map MX53_TZIC_BASE_ADDR\n"); + return; + } + __raw_writel(0, tzic_base + TZIC_WAKEUP0_OFFSET); + __raw_writel(0, tzic_base + TZIC_WAKEUP1_OFFSET); + __raw_writel(0, tzic_base + TZIC_WAKEUP2_OFFSET); + /* only enable irq wakeup for da9053 */ + __raw_writel(GPIO7_0_11_IRQ_BIT, tzic_base + TZIC_WAKEUP3_OFFSET); + iounmap(tzic_base); + pr_debug("only da9053 irq is wakeup-enabled\n"); +} + +static int mx5_suspend_enter(suspend_state_t state) +{ + if (gpc_dvfs_clk == NULL) + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); + /* gpc clock is needed for SRPG */ + clk_enable(gpc_dvfs_clk); + switch (state) { + case PM_SUSPEND_MEM: + mxc_cpu_lp_set(STOP_POWER_OFF); + break; + case PM_SUSPEND_STANDBY: + mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + break; + default: + return -EINVAL; + } + + if (tzic_enable_wake(0) != 0) + return -EAGAIN; + + if (state == PM_SUSPEND_MEM) { + local_flush_tlb_all(); + flush_cache_all(); + + if (pm_data && pm_data->suspend_enter) + pm_data->suspend_enter(); + + suspend_in_iram(suspend_param1); + + if (pm_data && pm_data->suspend_exit) + pm_data->suspend_exit(); + } else { + cpu_do_idle(); + } + clk_disable(gpc_dvfs_clk); + + return 0; +} + + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int mx5_suspend_prepare(void) +{ +#if defined(CONFIG_CPU_FREQ) +#define MX53_SUSPEND_CPU_WP 1000000000 + struct cpufreq_freqs freqs; + u32 suspend_wp = 0; + org_freq = clk_get_rate(cpu_clk); + /* workaround for mx53 to suspend on 400MHZ wp */ + if (cpu_is_mx53()) + for (suspend_wp = 0; suspend_wp < cpu_op_nr; suspend_wp++) + if (cpu_op_tbl[suspend_wp].cpu_rate + == MX53_SUSPEND_CPU_WP) + break; + if (suspend_wp == cpu_op_nr) + suspend_wp = 0; + pr_info("suspend wp cpu=%d\n", cpu_op_tbl[suspend_wp].cpu_rate); + freqs.old = org_freq / 1000; + freqs.new = cpu_op_tbl[suspend_wp].cpu_rate / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + if (clk_get_rate(cpu_clk) != cpu_op_tbl[suspend_wp].cpu_rate) { + set_cpu_freq(cpu_op_tbl[suspend_wp].cpu_rate); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } +#endif + return 0; +} + +/* + * Called before devices are re-setup. + */ +static void mx5_suspend_finish(void) +{ +#if defined(CONFIG_CPU_FREQ) + struct cpufreq_freqs freqs; + + freqs.old = clk_get_rate(cpu_clk) / 1000; + freqs.new = org_freq / 1000; + freqs.cpu = 0; + freqs.flags = 0; + + + if (org_freq != clk_get_rate(cpu_clk)) { + set_cpu_freq(org_freq); + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } +#endif +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ +static void mx5_suspend_end(void) +{ +} + +static int mx5_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + +struct platform_suspend_ops mx5_suspend_ops = { + .valid = mx5_pm_valid, + .prepare = mx5_suspend_prepare, + .enter = mx5_suspend_enter, + .finish = mx5_suspend_finish, + .end = mx5_suspend_end, +}; + +static int __devinit mx5_pm_probe(struct platform_device *pdev) +{ + pm_dev = &pdev->dev; + pm_data = pdev->dev.platform_data; + + return 0; +} + +static struct platform_driver mx5_pm_driver = { + .driver = { + .name = "mx5_pm", + }, + .probe = mx5_pm_probe, +}; + +static int __init pm_init(void) +{ + unsigned long iram_paddr, cpaddr; + + pr_info("Static Power Management for Freescale i.MX5\n"); + if (platform_driver_register(&mx5_pm_driver) != 0) { + printk(KERN_ERR "mx5_pm_driver register failed\n"); + return -ENODEV; + } + suspend_set_ops(&mx5_suspend_ops); + /* Move suspend routine into iRAM */ + cpaddr = iram_alloc(SZ_4K, &iram_paddr); + /* Need to remap the area here since we want the memory region + to be executable. */ + suspend_iram_base = __arm_ioremap(iram_paddr, SZ_4K, + MT_HIGH_VECTORS); + pr_info("cpaddr = %x suspend_iram_base=%x\n", cpaddr, suspend_iram_base); + + if (cpu_is_mx51() || cpu_is_mx53()) { + suspend_param1 = MX51_IO_ADDRESS(MX51_IOMUXC_BASE_ADDR + 0x4b8); + memcpy(cpaddr, cpu_do_suspend_workaround, + SZ_4K); + } else if (cpu_is_mx50()) { + /* + * Need to run the suspend code from IRAM as the DDR needs + * to be put into self refresh mode manually. + */ + memcpy(cpaddr, mx50_suspend, SZ_4K); + + suspend_param1 = databahn_base; + } + suspend_in_iram = (void *)suspend_iram_base; + + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_DEBUG "%s: failed to get cpu_clk\n", __func__); + return PTR_ERR(cpu_clk); + } + printk(KERN_INFO "PM driver module loaded\n"); + + return 0; +} + + +static void __exit pm_cleanup(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&mx5_pm_driver); +} + +module_init(pm_init); +module_exit(pm_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("PM driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx5/sdram_autogating.c b/arch/arm/mach-mx5/sdram_autogating.c new file mode 100755 index 00000000..ca75739e --- /dev/null +++ b/arch/arm/mach-mx5/sdram_autogating.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2009-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/*! + * @file sdram_autogating.c + * + * @brief Enable auto clock gating of the EMI_FAST clock using M4IF. + * + * The APIs are for enabling and disabling automatic clock gating of EMI_FAST. + * + * @ingroup PM + */ +#include <asm/io.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <mach/sdram_autogating.h> +#include "crm_regs.h" + +static struct device *sdram_autogating_dev; +#define M4IF_CNTL_REG0 0x8c +#define M4IF_CNTL_REG1 0x90 + +/* Flag used to indicate if SDRAM M4IF autoclock gating feature is active. */ +static int sdram_autogating_is_active; +static int sdram_autogating_paused; +static void __iomem *m4if_base; + +void start_sdram_autogating(void); +void stop_sdram_autogating(void); +int sdram_autogating_active(void); + +static void enable(void) +{ + u32 reg; + + /* Set the Fast arbitration Power saving timer */ + reg = __raw_readl(m4if_base + M4IF_CNTL_REG1); + reg &= ~0xFF; + reg |= 0x09; + __raw_writel(reg, m4if_base + M4IF_CNTL_REG1); + /*Allow for automatic gating of the EMI internal clock. + * If this is done, emi_intr CCGR bits should be set to 11. + */ + reg = __raw_readl(m4if_base + M4IF_CNTL_REG0); + reg &= ~0x5; + __raw_writel(reg, m4if_base + M4IF_CNTL_REG0); + + sdram_autogating_is_active = 1; +} + +static void disable(void) +{ + u32 reg; + + reg = __raw_readl(m4if_base + M4IF_CNTL_REG0); + reg |= 0x4; + __raw_writel(reg, m4if_base + M4IF_CNTL_REG0); + sdram_autogating_is_active = 0; +} + +int sdram_autogating_active() +{ + return sdram_autogating_is_active; +} + +void start_sdram_autogating() +{ + if (cpu_is_mx50()) + return; + if (sdram_autogating_paused) { + enable(); + sdram_autogating_paused = 0; + } +} + +void stop_sdram_autogating() +{ + if (cpu_is_mx50()) + return; + + if (sdram_autogating_is_active) { + sdram_autogating_paused = 1; + disable(); + } +} + +static ssize_t sdram_autogating_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (sdram_autogating_is_active) + return sprintf(buf, + "M4IF autoclock gating for EMI_FAST enabled\n"); + else + return sprintf(buf, + "M4IF autoclock gating for EMI_FAST disabled\n"); +} + +static ssize_t sdram_autogating_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + if (strstr(buf, "1") != NULL) + enable(); + else if (strstr(buf, "0") != NULL) { + if (sdram_autogating_is_active) + disable(); + } + return size; +} + +static DEVICE_ATTR(enable, 0644, sdram_autogating_enable_show, + sdram_autogating_enable_store); + +/*! + * This is the probe routine for the auto clockgating of sdram driver. + * + * @param pdev The platform device structure + * + * @return The function returns 0 on success + * + */ +static int __devinit sdram_autogating_probe(struct platform_device *pdev) +{ + struct resource *res; + int err = 0; + + sdram_autogating_dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + return -ENOMEM; + } + m4if_base = ioremap(res->start, res->end - res->start + 1); + + err = sysfs_create_file(&sdram_autogating_dev->kobj, + &dev_attr_enable.attr); + if (err) { + printk(KERN_ERR + "Unable to register sysdev entry for sdram_autogating"); + return err; + } + + sdram_autogating_is_active = 0; + + return 0; +} + +static struct platform_driver sdram_autogating_driver = { + .driver = { + .name = "sdram_autogating", + }, + .probe = sdram_autogating_probe, +}; + +/*! + * Initialise the sdram_autogating_driver. + * + * @return The function always returns 0. + */ + +static int __init sdram_autogating_init(void) +{ + if (platform_driver_register(&sdram_autogating_driver) != 0) { + printk(KERN_ERR "sdram_autogating_driver register failed\n"); + return -ENODEV; + } + + printk(KERN_INFO "sdram autogating driver module loaded\n"); + return 0; +} + +static void __exit sdram_autogating_cleanup(void) +{ + sysfs_remove_file(&sdram_autogating_dev->kobj, &dev_attr_enable.attr); + + /* Unregister the device structure */ + platform_driver_unregister(&sdram_autogating_driver); +} + +module_init(sdram_autogating_init); +module_exit(sdram_autogating_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("sdram_autogating driver"); +MODULE_LICENSE("GPL"); + diff --git a/arch/arm/mach-mx5/suspend.S b/arch/arm/mach-mx5/suspend.S new file mode 100755 index 00000000..c7937ec9 --- /dev/null +++ b/arch/arm/mach-mx5/suspend.S @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/linkage.h> + +#define ARM_CTRL_DCACHE 1 << 2 +#define ARM_CTRL_ICACHE 1 << 12 +#define ARM_AUXCR_L2EN 1 << 1 + + +/* + * cpu_do_suspend_workaround() + * + * Suspend the processor (eg, wait for interrupt). + * + * IRQs are already disabled. + */ +ENTRY(cpu_do_suspend_workaround) + stmfd sp!, {r4,r5,r6,r7,r9,r10,r11} @ Save registers + + mov r6, r0 @save iomux address + /* Disable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + bic r0, r0, #ARM_CTRL_ICACHE @ Disable ICache + bic r0, r0, #ARM_CTRL_DCACHE @ Disable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedClean + mov r10, #0 +Loop1Clean: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache Type for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipClean @ No cache or only instruction cache at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset (log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the way size (right aligned) + clz r5, r4 @ R5 is the bit position of the way size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the index size (right aligned) +Loop2Clean: + mov r9, r4 @ R9 working copy of the max way size (right aligned) +Loop3Clean: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c14, 2 @ Clean and invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Clean + subs r7, r7, #1 @ Decrement the index + bge Loop2Clean +SkipClean: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Clean + +FinishedClean: + + /* Disable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + bic r0, r0, #ARM_AUXCR_L2EN @ Disable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + +#if 0 + /*Set the DDR drive strength to low */ + ldr r10, [r6] + and r10, r10, #0xF1 @ clear bits 2-1 + str r10, [r6] +#endif + + .long 0xe320f003 @ Opcode for WFI + +#if 0 + /*Set the DDR drive strength to max */ + orr r10, r10, #0x06 @ set bits 2-1 + str r10, [r6] +#endif + + ldr r11, =0x0000fFFF +TestLoop: + subs r11,r11, #1 @ Decrement the index + bge TestLoop + + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ Invalidate inst cache + + /* Invalidate data caches */ + mrc p15, 1, r0, c0, c0, 1 @ Read CLIDR + ands r3, r0, #0x7000000 @ Isolate level of coherency + mov r3, r3, lsr #23 @ Cache level value (naturally aligned) + beq FinishedInvalidate + mov r10, #0 +Loop1Invalidate: + add r2, r10, r10, lsr #1 @ Work out cache level + mov r1, r0, lsr r2 @ R0 bottom 3 bits = Cache Type for this level + and r1, r1, #7 @ Get those 3 bits alone + cmp r1, #2 + blt SkipInvalidate @ No cache or only instruction cache at this level + mcr p15, 2, r10, c0, c0, 0 @ Write the Cache Size selection register + mov r1, #0 + .long 0xF57FF06F @ ISB + mrc p15, 1, r1, c0, c0, 0 @ Reads current Cache Size ID register + and r2, r1, #7 @ Extract the line length field + add r2, r2, #4 @ Add 4 for the line length offset (log2 16 bytes) + ldr r4, =0x3FF + ands r4, r4, r1, lsr #3 @ R4 is the max number on the way size (right aligned) + clz r5, r4 @ R5 is the bit position of the way size increment + ldr r7, =0x00007FFF + ands r7, r7, r1, lsr #13 @ R7 is the max number of the index size (right aligned) +Loop2Invalidate: + mov r9, r4 @ R9 working copy of the max way size (right aligned) +Loop3Invalidate: + orr r11, r10, r9, lsl r5 @ Factor in the way number and cache number into R11 + orr r11, r11, r7, lsl r2 @ Factor in the index number + mcr p15, 0, r11, c7, c6, 2 @ Invalidate by set/way + subs r9, r9, #1 @ Decrement the way number + bge Loop3Invalidate + subs r7, r7, #1 @ Decrement the index + bge Loop2Invalidate +SkipInvalidate: + add r10, r10, #2 @ Increment the cache number + cmp r3, r10 + bgt Loop1Invalidate + +FinishedInvalidate: + + /* Enable L2 cache */ + mrc p15, 0, r0, c1, c0, 1 @ R0 = auxiliary control reg + orr r0, r0, #ARM_AUXCR_L2EN @ Enable L2 cache + mcr p15, 0, r0, c1, c0, 1 @ Update aux control reg + + /* Enable L1 caches */ + mrc p15, 0, r0, c1, c0, 0 @ R0 = system control reg + orr r0, r0, #ARM_CTRL_ICACHE @ Enable ICache + orr r0, r0, #ARM_CTRL_DCACHE @ Enable DCache + mcr p15, 0, r0, c1, c0, 0 @ Update system control reg + + /* Restore registers */ + ldmfd sp!, {r4,r5,r6,r7,r9,r10,r11} + mov pc, lr + + .type cpu_do_suspend, #object +ENTRY(cpu_do_suspend) + .word cpu_do_suspend_workaround + .size cpu_do_suspend_workaround, . - cpu_do_suspend_workaround diff --git a/arch/arm/mach-mx5/system.c b/arch/arm/mach-mx5/system.c new file mode 100755 index 00000000..70667446 --- /dev/null +++ b/arch/arm/mach-mx5/system.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ +#include <linux/platform_device.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include "crm_regs.h" + +/* set cpu low power mode before WFI instruction. This function is called + * mx5 because it can be used for mx50, mx51, and mx53.*/ + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <asm/io.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <asm/proc-fns.h> +#include <asm/system.h> +#include "crm_regs.h" + +/*! + * @defgroup MSL_MX51 i.MX51 Machine Specific Layer (MSL) + */ + +/*! + * @file mach-mx51/system.c + * @brief This file contains idle and reset functions. + * + * @ingroup MSL_MX51 + */ + +extern int mxc_jtag_enabled; +extern int iram_ready; +extern int dvfs_core_is_active; +extern void __iomem *ccm_base; +extern void __iomem *databahn_base; +extern int low_bus_freq_mode; +extern void (*wait_in_iram)(void *ccm_addr, void *databahn_addr); +extern void mx50_wait(u32 ccm_base, u32 databahn_addr); +extern void stop_dvfs(void); +extern void *wait_in_iram_base; +extern void __iomem *apll_base; + +static struct clk *gpc_dvfs_clk; +static struct regulator *vpll; +static struct clk *pll1_sw_clk; +static struct clk *osc; +static struct clk *pll1_main_clk; +static struct clk *ddr_clk ; +static int dvfs_core_paused; + +/* set cpu low power mode before WFI instruction */ +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) +{ + u32 plat_lpc, arm_srpgcr, ccm_clpcr; + u32 empgc0, empgc1; + int stop_mode = 0; + + /* always allow platform to issue a deep sleep mode request */ + plat_lpc = __raw_readl(MXC_CORTEXA8_PLAT_LPC) & + ~(MXC_CORTEXA8_PLAT_LPC_DSM); + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); + arm_srpgcr = __raw_readl(MXC_SRPG_ARM_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgc0 = __raw_readl(MXC_SRPG_EMPGC0_SRPGCR) & ~(MXC_SRPGCR_PCR); + empgc1 = __raw_readl(MXC_SRPG_EMPGC1_SRPGCR) & ~(MXC_SRPGCR_PCR); + + switch (mode) { + case WAIT_CLOCKED: + break; + case WAIT_UNCLOCKED: + ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET; + break; + case WAIT_UNCLOCKED_POWER_OFF: + case STOP_POWER_OFF: + plat_lpc |= MXC_CORTEXA8_PLAT_LPC_DSM + | MXC_CORTEXA8_PLAT_LPC_DBG_DSM; + if (mode == WAIT_UNCLOCKED_POWER_OFF) { + ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET; + ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + stop_mode = 0; + } else { + ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET; + ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET; + ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; + ccm_clpcr |= MXC_CCM_CLPCR_SBYOS; + stop_mode = 1; + } + arm_srpgcr |= MXC_SRPGCR_PCR; + + if (tzic_enable_wake(1) != 0) + return; + break; + case STOP_POWER_ON: + ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET; + break; + default: + printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode); + return; + } + + __raw_writel(plat_lpc, MXC_CORTEXA8_PLAT_LPC); + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + __raw_writel(arm_srpgcr, MXC_SRPG_ARM_SRPGCR); + + /* Enable NEON SRPG for all but MX50TO1.0. */ + if (mx50_revision() != IMX_CHIP_REVISION_1_0) + __raw_writel(arm_srpgcr, MXC_SRPG_NEON_SRPGCR); + + if (stop_mode) { + empgc0 |= MXC_SRPGCR_PCR; + empgc1 |= MXC_SRPGCR_PCR; + + __raw_writel(empgc0, MXC_SRPG_EMPGC0_SRPGCR); + __raw_writel(empgc1, MXC_SRPG_EMPGC1_SRPGCR); + } +} + +/* To change the idle power mode, need to set arch_idle_mode to a different + * power mode as in enum mxc_cpu_pwr_mode. + * May allow dynamically changing the idle mode. + */ +static int arch_idle_mode = WAIT_UNCLOCKED_POWER_OFF; +/*! + * This function puts the CPU into idle mode. It is called by default_idle() + * in process.c file. + */ +void arch_idle(void) +{ + if (likely(!mxc_jtag_enabled)) { + if (ddr_clk == NULL) + ddr_clk = clk_get(NULL, "ddr_clk"); + if (gpc_dvfs_clk == NULL) + gpc_dvfs_clk = clk_get(NULL, "gpc_dvfs_clk"); + /* gpc clock is needed for SRPG */ + clk_enable(gpc_dvfs_clk); + mxc_cpu_lp_set(arch_idle_mode); + + if (cpu_is_mx50() && (clk_get_usecount(ddr_clk) == 0)) { + memcpy(wait_in_iram_base, mx50_wait, SZ_4K); + wait_in_iram = (void *)wait_in_iram_base; + if (low_bus_freq_mode) { + u32 reg, cpu_podf; + + reg = __raw_readl(apll_base + 0x50); + reg = 0x120490; + __raw_writel(reg, apll_base + 0x50); + reg = __raw_readl(apll_base + 0x80); + reg |= 1; + __raw_writel(reg, apll_base + 0x80); + + /* Move ARM to be sourced from 24MHz XTAL. + * when ARM is in WFI. + */ + if (pll1_sw_clk == NULL) + pll1_sw_clk = clk_get(NULL, + "pll1_sw_clk"); + if (osc == NULL) + osc = clk_get(NULL, "lp_apm"); + if (pll1_main_clk == NULL) + pll1_main_clk = clk_get(NULL, + "pll1_main_clk"); + + clk_set_parent(pll1_sw_clk, osc); + /* Set the ARM-PODF divider to 1. */ + cpu_podf = __raw_readl(MXC_CCM_CACRR); + __raw_writel(0x01, MXC_CCM_CACRR); + + wait_in_iram(ccm_base, databahn_base); + + /* Set the ARM-POD divider back + * to the original. + */ + __raw_writel(cpu_podf, MXC_CCM_CACRR); + clk_set_parent(pll1_sw_clk, pll1_main_clk); + } else + wait_in_iram(ccm_base, databahn_base); + } else + cpu_do_idle(); + clk_disable(gpc_dvfs_clk); + clk_put(ddr_clk); + } +} + +static int __mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + u32 c; + int timeout; + + /* the process of software reset of IP block is done + in several steps: + + - clear SFTRST and wait for block is enabled; + - clear clock gating (CLKGATE bit); + - set the SFTRST again and wait for block is in reset; + - clear SFTRST and wait for reset completion. + */ + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + + if (!just_enable) { + c = __raw_readl(hwreg); + c |= (1 << 31); /* now again set SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* poll until CLKGATE set */ + if (__raw_readl(hwreg) & (1 << 30)) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when resetting\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 31); /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 31)) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling " + "after reset\n", __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~(1 << 30); /* clear CLKGATE */ + __raw_writel(c, hwreg); + } + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & (1 << 30)) == 0) + break; + + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when unclockgating\n", + __func__, hwreg); + return -ETIME; + } + + return 0; +} + +int mxs_reset_block(void __iomem *hwreg, int just_enable) +{ + int try = 10; + int r; + + while (try--) { + r = __mxs_reset_block(hwreg, just_enable); + if (!r) + break; + pr_debug("%s: try %d failed\n", __func__, 10 - try); + } + return r; +} diff --git a/arch/arm/mach-mx5/usb.h b/arch/arm/mach-mx5/usb.h new file mode 100755 index 00000000..c059f740 --- /dev/null +++ b/arch/arm/mach-mx5/usb.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <mach/common.h> +#include "devices.h" + +extern int usbotg_init(struct platform_device *pdev); +extern void usbotg_uninit(struct fsl_usb2_platform_data *pdata); +extern struct platform_device *host_pdev_register(struct resource *res, + int n_res, struct fsl_usb2_platform_data *config); + +extern int fsl_usb_host_init(struct platform_device *pdev); +extern void fsl_usb_host_uninit(struct fsl_usb2_platform_data *pdata); +extern int gpio_usbotg_utmi_active(void); +extern void gpio_usbotg_utmi_inactive(void); + +extern void __init mx5_usb_dr_init(void); +extern void __init mx5_usbh1_init(void); +extern void __init mx5_usbh2_init(void); + +typedef void (*driver_vbus_func)(bool); +extern void mx5_set_host1_vbus_func(driver_vbus_func); +extern void mx5_set_otghost_vbus_func(driver_vbus_func); +/* + * Used to set pdata->operating_mode before registering the platform_device. + * If OTG is configured, the controller operates in OTG mode, + * otherwise it's either host or device. + */ +#ifdef CONFIG_USB_OTG +#define DR_UDC_MODE FSL_USB2_DR_OTG +#define DR_HOST_MODE FSL_USB2_DR_OTG +#else +#define DR_UDC_MODE FSL_USB2_DR_DEVICE +#define DR_HOST_MODE FSL_USB2_DR_HOST +#endif + +extern void __iomem *imx_otg_base; diff --git a/arch/arm/mach-mx5/usb_dr.c b/arch/arm/mach-mx5/usb_dr.c new file mode 100755 index 00000000..7f0d9026 --- /dev/null +++ b/arch/arm/mach-mx5/usb_dr.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <mach/arc_otg.h> +#include <mach/hardware.h> +#include <linux/delay.h> +#include <asm/mach-types.h> +#include "usb.h" +static int usbotg_init_ext(struct platform_device *pdev); +static void usbotg_uninit_ext(struct platform_device *pdev); +static void usbotg_clock_gate(bool on); + +static struct clk *usb_phy1_clk; +static struct clk *usb_oh3_clk; +static struct clk *usb_ahb_clk; +static void usbotg_wakeup_event_clear(void); +extern int clk_get_usecount(struct clk *clk); + +/* Beginning of Common operation for DR port */ + +/* + * platform data structs + * - Which one to use is determined by CONFIG options in usb.h + * - operating_mode plugged at run time + */ +static struct fsl_usb2_platform_data dr_utmi_config = { + .name = "DR", + .init = usbotg_init_ext, + .exit = usbotg_uninit_ext, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, + .power_budget = 500, /* 500 mA max power */ + .usb_clock_for_pm = usbotg_clock_gate, + .transceiver = "utmi", +}; + +/* Platform data for wakeup operation */ +static struct fsl_usb2_wakeup_platform_data dr_wakeup_config = { + .name = "DR wakeup", + .usb_clock_for_pm = usbotg_clock_gate, + .usb_wakeup_exhandle = usbotg_wakeup_event_clear, +}; +/* Notes: configure USB clock*/ +static int usbotg_init_ext(struct platform_device *pdev) +{ + struct clk *usb_clk; + + /* the usb_ahb_clk will be enabled in usb_otg_init */ + usb_ahb_clk = clk_get(NULL, "usb_ahb_clk"); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_enable(usb_clk); + usb_phy1_clk = usb_clk; + + return usbotg_init(pdev); +} + +static void usbotg_uninit_ext(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + clk_disable(usb_phy1_clk); + clk_put(usb_phy1_clk); + + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + + /* usb_ahb_clk will be disabled at usb_common.c */ + usbotg_uninit(pdata); + clk_put(usb_ahb_clk); +} + +/* Below two macros are used at otg mode to indicate usb mode*/ +#define ENABLED_BY_HOST (0x1 << 0) +#define ENABLED_BY_DEVICE (0x1 << 1) +static u32 wakeup_irq_enable_src; /* only useful at otg mode */ +static void __wakeup_irq_enable(bool on, int source) + { + /* otg host and device share the OWIE bit, only when host and device + * all enable the wakeup irq, we can enable the OWIE bit + */ + if (on) { +#ifdef CONFIG_USB_OTG + wakeup_irq_enable_src |= source; + if (wakeup_irq_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { + USBCTRL |= UCTRL_OWIE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; + } +#else + USBCTRL |= UCTRL_OWIE; + USB_PHY_CTR_FUNC |= USB_UTMI_PHYCTRL_CONF2; +#endif + } else { + USB_PHY_CTR_FUNC &= ~USB_UTMI_PHYCTRL_CONF2; + USBCTRL &= ~UCTRL_OWIE; + wakeup_irq_enable_src &= ~source; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static u32 low_power_enable_src; /* only useful at otg mode */ +static void __phy_lowpower_suspend(bool enable, int source) +{ + if (enable) { + low_power_enable_src |= source; +#ifdef CONFIG_USB_OTG + if (low_power_enable_src == (ENABLED_BY_HOST | ENABLED_BY_DEVICE)) { + pr_debug("phy lowpower enabled\n"); + UOG_PORTSC1 |= PORTSC_PHCD; + } +#else + UOG_PORTSC1 |= PORTSC_PHCD; +#endif + } else { + pr_debug("phy lowpower disable\n"); + UOG_PORTSC1 &= ~PORTSC_PHCD; + low_power_enable_src &= ~source; + } +} + +static void usbotg_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_ahb_clk); + clk_enable(usb_oh3_clk); + clk_enable(usb_phy1_clk); + } else { + clk_disable(usb_phy1_clk); + clk_disable(usb_oh3_clk); + clk_disable(usb_ahb_clk); + } + pr_debug("usb_ahb_ref_count:%d, usb_phy_clk1_ref_count:%d\n", clk_get_usecount(usb_ahb_clk), clk_get_usecount(usb_phy1_clk)); +} + +void mx5_set_otghost_vbus_func(driver_vbus_func driver_vbus) +{ + dr_utmi_config.platform_driver_vbus = driver_vbus; +} + +/* The wakeup operation for DR port, it will clear the wakeup irq status + * and re-enable the wakeup + */ +static void usbotg_wakeup_event_clear(void) +{ + int wakeup_req = USBCTRL & UCTRL_OWIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC); + /* Disable OWIE to clear OWIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USBCTRL &= ~UCTRL_OWIE; + udelay(100); + USBCTRL |= UCTRL_OWIE; + } +} +/* End of Common operation for DR port */ + + +#ifdef CONFIG_USB_EHCI_ARC_OTG +/* Beginning of host related operation for DR port */ +static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_HOST); + /* host only care the ID change wakeup event */ + if (enable) { + pr_debug("host wakeup enable\n"); + USBCTRL_HOST2 |= UCTRL_H2OIDWK_EN; + } else { + pr_debug("host wakeup disable\n"); + USBCTRL_HOST2 &= ~UCTRL_H2OIDWK_EN; + /* The interrupt must be disabled for at least 3 clock + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_HOST); +} + +static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdata) +{ + u32 wakeup_req = USBCTRL & UCTRL_OWIR; + u32 otgsc = UOG_OTGSC; + + /* if ID change sts, it is a host wakeup event */ + if (wakeup_req && (otgsc & OTGSC_IS_USB_ID)) { + printk(KERN_INFO "otg host ID wakeup\n"); + /* if host ID wakeup, we must clear the b session change sts */ + UOG_OTGSC = otgsc & (~OTGSC_IS_USB_ID); + return WAKEUP_EVENT_ID; + } + if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) { + printk(KERN_INFO "otg host Remote wakeup\n"); + return WAKEUP_EVENT_DPDM; + } + + return WAKEUP_EVENT_INVALID; +} + +static void host_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _host_wakeup_enable(pdata, false); + _host_phy_lowpower_suspend(pdata, false); +} +/* End of host related operation for DR port */ +#endif /* CONFIG_USB_EHCI_ARC_OTG */ + + +#ifdef CONFIG_USB_GADGET_ARC +/* Beginning of device related operation for DR port */ +static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __wakeup_irq_enable(enable, ENABLED_BY_DEVICE); + /* if udc is not used by any gadget, we can not enable the vbus wakeup */ + if (!pdata->port_enables) { + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + return; + } + if (enable) { + pr_debug("device wakeup enable\n"); + USBCTRL_HOST2 |= UCTRL_H2OVBWK_EN; + } else { + pr_debug("device wakeup disable\n"); + USBCTRL_HOST2 &= ~UCTRL_H2OVBWK_EN; + } +} + +static void _device_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __phy_lowpower_suspend(enable, ENABLED_BY_DEVICE); +} + +static enum usb_wakeup_event _is_device_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_OWIR; + + pr_debug("the otgsc is 0x%x, usbsts is 0x%x, portsc is 0x%x, wakeup_irq is 0x%x\n", UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, wakeup_req); + + /* if ID=1, it is a device wakeup event */ + if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && (UOG_USBSTS & USBSTS_URI)) { + printk(KERN_INFO "otg udc wakeup, host sends reset signal\n"); + return WAKEUP_EVENT_DPDM; + } + if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && \ + ((UOG_USBSTS & USBSTS_PCI) || (UOG_PORTSC1 & PORTSC_PORT_FORCE_RESUME))) { + /* + * When the line state from J to K, the Port Change Detect bit + * in the USBSTS register is also set to '1'. + */ + printk(KERN_INFO "otg udc wakeup, host sends resume signal\n"); + return WAKEUP_EVENT_DPDM; + } + if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && (UOG_OTGSC & OTGSC_STS_A_VBUS_VALID) \ + && (UOG_OTGSC & OTGSC_IS_B_SESSION_VALID)) { + printk(KERN_INFO "otg udc vbus rising wakeup\n"); + return WAKEUP_EVENT_VBUS; + } + if (wakeup_req && (UOG_OTGSC & OTGSC_STS_USB_ID) && !(UOG_OTGSC & OTGSC_STS_A_VBUS_VALID)) { + printk(KERN_INFO "otg udc vbus falling wakeup\n"); + return WAKEUP_EVENT_VBUS; + } + + return WAKEUP_EVENT_INVALID; +} + +static void device_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _device_wakeup_enable(pdata, false); + _device_phy_lowpower_suspend(pdata, false); +} + +/* end of device related operation for DR port */ +#endif /* CONFIG_USB_GADGET_ARC */ + +#define MX53_OFFSET 0x20000000 + +void __init mx5_usb_dr_init(void) +{ + int ret = 0; +#ifdef CONFIG_USB_OTG + if (cpu_is_mx53() || cpu_is_mx50()) { + mxc_usbdr_otg_device.resource[0].start -= MX53_OFFSET; + mxc_usbdr_otg_device.resource[0].end -= MX53_OFFSET; + } + /* wake_up_enalbe is useless, just for usb_register_remote_wakeup execution*/ + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.operating_mode = FSL_USB2_DR_OTG; + dr_utmi_config.wakeup_pdata = &dr_wakeup_config; + ret |= platform_device_add_data(&mxc_usbdr_otg_device, &dr_utmi_config, sizeof(dr_utmi_config)); + if (!machine_is_mx53_loco()) { + ret |= platform_device_register(&mxc_usbdr_otg_device); + } + dr_wakeup_config.usb_pdata[0] = mxc_usbdr_otg_device.dev.platform_data; +#endif +#ifdef CONFIG_USB_EHCI_ARC_OTG + if (cpu_is_mx53() || cpu_is_mx50()) { + mxc_usbdr_host_device.resource[0].start -= MX53_OFFSET; + mxc_usbdr_host_device.resource[0].end -= MX53_OFFSET; + } + dr_utmi_config.operating_mode = DR_HOST_MODE; + dr_utmi_config.wake_up_enable = _host_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _host_phy_lowpower_suspend; + dr_utmi_config.is_wakeup_event = _is_host_wakeup; + dr_utmi_config.wakeup_pdata = &dr_wakeup_config; + dr_utmi_config.wakeup_handler = host_wakeup_handler; + ret |= platform_device_add_data(&mxc_usbdr_host_device, &dr_utmi_config, sizeof(dr_utmi_config)); + ret |= platform_device_register(&mxc_usbdr_host_device); + dr_wakeup_config.usb_pdata[1] = mxc_usbdr_host_device.dev.platform_data; +#endif +#ifdef CONFIG_USB_GADGET_ARC + if (cpu_is_mx53() || cpu_is_mx50()) { + mxc_usbdr_udc_device.resource[0].start -= MX53_OFFSET; + mxc_usbdr_udc_device.resource[0].end -= MX53_OFFSET; + } + dr_utmi_config.operating_mode = DR_UDC_MODE; + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.phy_lowpower_suspend = _device_phy_lowpower_suspend; + dr_utmi_config.is_wakeup_event = _is_device_wakeup; + dr_utmi_config.wakeup_pdata = &dr_wakeup_config; + dr_utmi_config.wakeup_handler = device_wakeup_handler; + ret |= platform_device_add_data(&mxc_usbdr_udc_device, &dr_utmi_config, sizeof(dr_utmi_config)); + ret |= platform_device_register(&mxc_usbdr_udc_device); + dr_wakeup_config.usb_pdata[2] = mxc_usbdr_udc_device.dev.platform_data; +#endif + ret |= mxc_register_device(&mxc_usbdr_wakeup_device, &dr_wakeup_config); + if (ret) + printk(KERN_ERR "%s(%d): error occures while init usb dr \n", __func__, __LINE__); +} diff --git a/arch/arm/mach-mx5/usb_h1.c b/arch/arm/mach-mx5/usb_h1.c new file mode 100755 index 00000000..e291fb7b --- /dev/null +++ b/arch/arm/mach-mx5/usb_h1.c @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/gpio.h> + +#include <asm/delay.h> +#include <mach/arc_otg.h> +#include <mach/iomux-mx51.h> +#include <mach/iomux-mx53.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include "usb.h" + +static struct clk *usb_phy2_clk; +static struct clk *usb_oh3_clk; +static struct clk *usb_ahb_clk; +extern int clk_get_usecount(struct clk *clk); + +#define MX5X_USBH1_STP IMX_GPIO_NR(1, 27) +#define MX51_3DS_PHY_RESET IMX_GPIO_NR(2, 5) + +/* + * USB Host1 HS port + */ +static int gpio_usbh1_active(void) +{ + iomux_v3_cfg_t usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO1_27; + iomux_v3_cfg_t phyreset_gpio = MX51_PAD_EIM_D17__GPIO2_1; + int ret; + + /* Set USBH1_STP to GPIO and toggle it */ + mxc_iomux_v3_setup_pad(usbh1stp_gpio); + ret = gpio_request(MX5X_USBH1_STP, "usbh1_stp"); + + if (ret) { + pr_debug("failed to get MX51_PAD_USBH1_STP__GPIO_1_27: %d\n", ret); + return ret; + } + gpio_direction_output(MX5X_USBH1_STP, 0); + gpio_set_value(MX5X_USBH1_STP, 1); + + /* Signal only used on MX51-3DS for reset to PHY.*/ + if (machine_is_mx51_3ds()) { + mxc_iomux_v3_setup_pad(phyreset_gpio); + ret = gpio_request(MX51_3DS_PHY_RESET, "eim_d17"); + if (ret) { + pr_debug("failed to get MX51_PAD_EIM_D17__GPIO2_1: %d\n", ret); + return ret; + } + gpio_direction_output(MX51_3DS_PHY_RESET, 0); + gpio_set_value(MX51_3DS_PHY_RESET, 1); + } + + msleep(100); + + return 0; +} + +static void gpio_usbh1_inactive(void) +{ + /* Signal only used on MX51-3DS for reset to PHY.*/ + if (machine_is_mx51_3ds()) { + gpio_free(MX51_3DS_PHY_RESET); + } + gpio_free(MX5X_USBH1_STP); +} + + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + pr_debug("host1, %s, enable is %d\n", __func__, enable); + if (enable) + USBCTRL |= UCTRL_H1WIE; + else { + USBCTRL &= ~UCTRL_H1WIE; + /* The interrupt must be disabled for at least 3 + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + pr_debug("host1, %s, enable is %d\n", __func__, enable); + if (enable) { + UH1_PORTSC1 |= PORTSC_PHCD; + } else { + UH1_PORTSC1 &= ~PORTSC_PHCD; + } +} + +static void usbh1_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_ahb_clk); + clk_enable(usb_oh3_clk); + clk_enable(usb_phy2_clk); + } else { + clk_disable(usb_phy2_clk); + clk_disable(usb_oh3_clk); + clk_disable(usb_ahb_clk); + } +} + +static enum usb_wakeup_event _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_H1WIR; + + if (wakeup_req) + return WAKEUP_EVENT_DPDM; + + return WAKEUP_EVENT_INVALID; +} + +static void h1_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _wake_up_enable(pdata, false); + _phy_lowpower_suspend(pdata, false); +} + +static void usbh1_wakeup_event_clear(void) +{ + int wakeup_req = USBCTRL & UCTRL_H1WIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC); + /* Disable H1WIE to clear H1WIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USBCTRL &= ~UCTRL_H1WIE; + udelay(100); + USBCTRL |= UCTRL_H1WIE; + } +} +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret; + struct clk *usb_clk; + + /* the usb_ahb_clk will be enabled in usb_otg_init */ + usb_ahb_clk = clk_get(NULL, "usb_ahb_clk"); + + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + usb_clk = clk_get(NULL, "usb_phy2_clk"); + clk_enable(usb_clk); + usb_phy2_clk = usb_clk; + } else if (cpu_is_mx50()) { + usb_clk = clk_get(NULL, "usb_phy2_clk"); + clk_enable(usb_clk); + usb_phy2_clk = usb_clk; + } else if (cpu_is_mx51()) { + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + } + + ret = fsl_usb_host_init(pdev); + if (ret) + return ret; + + if (cpu_is_mx51()) { + /* setback USBH1_STP to be function */ +#if 0 /* Jasper: Need to do... */ + mxc_request_iomux(MX51_PIN_USBH1_STP, IOMUX_CONFIG_ALT0); + mxc_iomux_set_pad(MX51_PIN_USBH1_STP, PAD_CTL_SRE_FAST | + PAD_CTL_DRV_HIGH | PAD_CTL_ODE_OPENDRAIN_NONE | + PAD_CTL_PUE_KEEPER | PAD_CTL_PKE_ENABLE | + PAD_CTL_HYS_ENABLE | PAD_CTL_DDR_INPUT_CMOS | + PAD_CTL_DRV_VOT_LOW); + gpio_free(IOMUX_TO_GPIO(MX51_PIN_USBH1_STP)); +#endif + } + + /* disable remote wakeup irq */ + USBCTRL &= ~UCTRL_H1WIE; + return 0; +} + +static void fsl_usb_host_uninit_ext(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + if (cpu_is_mx53()) { + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + + clk_disable(usb_phy2_clk); + clk_put(usb_phy2_clk); + } else if (cpu_is_mx50()) { + clk_disable(usb_phy2_clk); + clk_put(usb_phy2_clk); + } else if (cpu_is_mx51()) { + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + } + + fsl_usb_host_uninit(pdata); + /* usb_ahb_clk will be disabled at usb_common.c */ + clk_put(usb_ahb_clk); +} + +static struct fsl_usb2_platform_data usbh1_config = { + .name = "Host 1", + .init = fsl_usb_host_init_ext, + .exit = fsl_usb_host_uninit_ext, + .operating_mode = FSL_USB2_MPH_HOST, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, + .power_budget = 500, /* 500 mA max power */ + .wake_up_enable = _wake_up_enable, + .usb_clock_for_pm = usbh1_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .is_wakeup_event = _is_usbh1_wakeup, + .wakeup_handler = h1_wakeup_handler, + .transceiver = "utmi", +}; +static struct fsl_usb2_wakeup_platform_data usbh1_wakeup_config = { + .name = "USBH1 wakeup", + .usb_clock_for_pm = usbh1_clock_gate, + .usb_pdata = {&usbh1_config, NULL, NULL}, + .usb_wakeup_exhandle = usbh1_wakeup_event_clear, +}; + +void mx5_set_host1_vbus_func(driver_vbus_func driver_vbus) +{ + usbh1_config.platform_driver_vbus = driver_vbus; +} + +#define MX53_OFFSET 0x20000000 +void __init mx5_usbh1_init(void) +{ + if (cpu_is_mx51()) { + usbh1_config.phy_mode = FSL_USB2_PHY_ULPI; + usbh1_config.transceiver = "isp1504"; + usbh1_config.gpio_usb_active = gpio_usbh1_active; + usbh1_config.gpio_usb_inactive = gpio_usbh1_inactive; + } + if (cpu_is_mx53() || cpu_is_mx50()) { + mxc_usbh1_device.resource[0].start -= MX53_OFFSET; + mxc_usbh1_device.resource[0].end -= MX53_OFFSET; + } + mxc_register_device(&mxc_usbh1_device, &usbh1_config); + usbh1_config.wakeup_pdata = &usbh1_wakeup_config; + mxc_register_device(&mxc_usbh1_wakeup_device, &usbh1_wakeup_config); +} + diff --git a/arch/arm/mach-mx5/usb_h2.c b/arch/arm/mach-mx5/usb_h2.c new file mode 100755 index 00000000..1f7d0a70 --- /dev/null +++ b/arch/arm/mach-mx5/usb_h2.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> + +#include <mach/arc_otg.h> +#include <mach/iomux-mx51.h> +#include <mach/iomux-mx53.h> +#include "usb.h" + +#define MX5X_USBH2_STP IMX_GPIO_NR(2, 20) + +/* + * USB Host2 HS port + */ +static int gpio_usbh2_active(void) +{ + iomux_v3_cfg_t usbh2stp_gpio = MX51_PAD_EIM_A26__GPIO2_20; + int ret = 0; + + /* Set USBH2_STP to GPIO and toggle it */ + mxc_iomux_v3_setup_pad(usbh2stp_gpio); + ret = gpio_request(MX5X_USBH2_STP, "eim_a26"); + if (ret) { + pr_debug("failed to get MX51_PAD_EIM_A26__GPIO2_20: %d\n", ret); + return ret; + } + + gpio_direction_output(MX5X_USBH2_STP, 0); + gpio_set_value(MX5X_USBH2_STP, 1); + msleep(100); + + return 0; +} + +static void gpio_usbh2_inactive(void) +{ + gpio_free(MX5X_USBH2_STP); +} + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + printk(KERN_DEBUG "host2, %s, enable is %d\n", __func__, enable); + if (enable) + USBCTRL_HOST2 |= UCTRL_H2WIE; + else { + USBCTRL_HOST2 &= ~UCTRL_H2WIE; + /* The interrupt must be disabled for at least 3 + * cycles of the standby clock(32k Hz) , that is 0.094 ms*/ + udelay(100); + } +} + +static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + printk(KERN_DEBUG "host2, %s, enable is %d\n", __func__, enable); + if (enable) { + UH2_PORTSC1 |= PORTSC_PHCD; + } else { + UH2_PORTSC1 &= ~PORTSC_PHCD; + } +} + +static void fsl_usbh2_clock_gate(bool on) +{ + struct clk *usb_clk; + if (on) { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } else { + usb_clk = clk_get(NULL, "usb_ahb_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } +} + +static enum usb_wakeup_event _is_usbh2_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = USBCTRL & UCTRL_H2WIR; + + if (wakeup_req) + return WAKEUP_EVENT_DPDM; + + return WAKEUP_EVENT_INVALID; +} + +static void h2_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _wake_up_enable(pdata, false); + _phy_lowpower_suspend(pdata, false); +} + +static void usbh2_wakeup_event_clear(void) +{ + int wakeup_req = USBCTRL & UCTRL_H2WIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(OTGSC 0x%x)\n", UOG_OTGSC); + /* Disable H2WIE to clear H2WIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USBCTRL &= ~UCTRL_H2WIE; + udelay(100); + USBCTRL |= UCTRL_H2WIE; + } +} +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret = 0; + struct clk *usb_clk; + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + + /* on mx53, there is a hardware limitation that when switch the host2's clk mode + * ,usb phy1 clk must be on, after finish switching this clk can be off */ + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_enable(usb_clk); + clk_put(usb_clk); + } + + ret = fsl_usb_host_init(pdev); + + if (cpu_is_mx53()) { + usb_clk = clk_get(NULL, "usb_phy1_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + } + + /* setback USBH2_STP to be function */ + mxc_iomux_v3_setup_pad(MX51_PAD_EIM_A26__USBH2_STP); + + return ret; +} + +static void fsl_usb_host_uninit_ext(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + struct clk *usb_clk; + + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_disable(usb_clk); + clk_put(usb_clk); + + fsl_usb_host_uninit(pdata); +} + +static struct fsl_usb2_platform_data usbh2_config = { + .name = "Host 2", + .init = fsl_usb_host_init_ext, + .exit = fsl_usb_host_uninit_ext, + .operating_mode = FSL_USB2_MPH_HOST, + .phy_mode = FSL_USB2_PHY_ULPI, + .power_budget = 500, /* 500 mA max power */ + .wake_up_enable = _wake_up_enable, + .usb_clock_for_pm = fsl_usbh2_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .gpio_usb_active = gpio_usbh2_active, + .gpio_usb_inactive = gpio_usbh2_inactive, + .is_wakeup_event = _is_usbh2_wakeup, + .wakeup_handler = h2_wakeup_handler, + .transceiver = "isp1504", +}; +static struct fsl_usb2_wakeup_platform_data usbh2_wakeup_config = { + .name = "USBH2 wakeup", + .usb_clock_for_pm = fsl_usbh2_clock_gate, + .usb_pdata = {&usbh2_config, NULL, NULL}, + .usb_wakeup_exhandle = usbh2_wakeup_event_clear, +}; + +#define MX53_OFFSET 0x20000000 +void __init mx5_usbh2_init(void) +{ + if (cpu_is_mx53() || cpu_is_mx50()) { + mxc_usbh2_device.resource[0].start -= MX53_OFFSET; + mxc_usbh2_device.resource[0].end -= MX53_OFFSET; + } + usbh2_config.wakeup_pdata = &usbh2_wakeup_config; + mxc_register_device(&mxc_usbh2_device, &usbh2_config); + mxc_register_device(&mxc_usbh2_wakeup_device, &usbh2_wakeup_config); +} |