diff options
Diffstat (limited to 'arch/arm/mach-mx6')
67 files changed, 49165 insertions, 0 deletions
diff --git a/arch/arm/mach-mx6/Kconfig b/arch/arm/mach-mx6/Kconfig new file mode 100644 index 00000000..a8dc8bc1 --- /dev/null +++ b/arch/arm/mach-mx6/Kconfig @@ -0,0 +1,382 @@ +if ARCH_MX6 + +config ARCH_MX6Q + bool + select USB_ARCH_HAS_EHCI + select ARCH_MXC_IOMUX_V3 + select ARCH_MXC_AUDMUX_V2 + select ARCH_SUPPORTS_MSI + select ARM_GIC + select ARCH_HAS_CPUFREQ + select OC_ETM + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_IMX_IPUV3 + select IMX_HAVE_PLATFORM_MXC_PWM + select IMX_HAVE_PLATFORM_LDB + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_IMX_VDOA + +config FORCE_MAX_ZONEORDER + int "MAX_ORDER" + default "13" + +config SOC_IMX6Q + bool + +config SOC_IMX6SL + bool + +config MACH_MX6Q_ARM2 + bool "Support i.MX 6Quad Armadillo2 platform" + select ARCH_MX6Q + select SOC_IMX6Q + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_GPMI_NFC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_ESAI + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_MXC_HDMI + select IMX_HAVE_PLATFORM_IMX_ASRC + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_IMX_MIPI_DSI + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_IMX_MIPI_CSI2 + select IMX_HAVE_PLATFORM_PERFMON + select IMX_HAVE_PLATFORM_MXC_MLB + select IMX_HAVE_PLATFORM_IMX_EPDC +# select IMX_HAVE_PLATFORM_IMX_ELCDIF + select IMX_HAVE_PLATFORM_IMX_PXP + select IMX_HAVE_PLATFORM_IMX_PCIE + select IMX_HAVE_PLATFORM_IMX_CAAM + help + Include support for i.MX 6Quad Armadillo2 platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6SL_ARM2 + bool "Support i.MX 6SoloLite Armadillo2 platform" + select ARCH_MX6Q + select SOC_IMX6SL + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_PERFMON + select IMX_HAVE_PLATFORM_IMX_EPDC + select IMX_HAVE_PLATFORM_IMX_SPDC + select IMX_HAVE_PLATFORM_IMX_PXP + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_DCP + select IMX_HAVE_PLATFORM_RANDOM_RNGC + select ARCH_HAS_RNGC + help + Include support for i.MX 6Sololite Armadillo2 platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6SL_EVK + bool "Support i.MX 6SoloLite EVK platform" + select ARCH_MX6Q + select SOC_IMX6SL + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_PERFMON + select IMX_HAVE_PLATFORM_IMX_EPDC + select IMX_HAVE_PLATFORM_IMX_SPDC + select IMX_HAVE_PLATFORM_IMX_PXP + select IMX_HAVE_PLATFORM_IMX_FSL_CSI + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_DCP + select IMX_HAVE_PLATFORM_RANDOM_RNGC + select ARCH_HAS_RNGC + help + Include support for i.MX 6Sololite EVK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6SL_NTX + bool "Support i.MX 6SoloLite NTX platform" + select ARCH_MX6Q + select SOC_IMX6SL + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_PERFMON + select IMX_HAVE_PLATFORM_IMX_EPDC + select IMX_HAVE_PLATFORM_IMX_SPDC + select IMX_HAVE_PLATFORM_IMX_PXP + select IMX_HAVE_PLATFORM_IMX_FSL_CSI + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_DCP + select IMX_HAVE_PLATFORM_RANDOM_RNGC + select ARCH_HAS_RNGC + help + Include support for i.MX 6Sololite NTX platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6Q_SABRELITE + bool "Support i.MX 6Quad SABRE Lite platform" + select ARCH_MX6Q + select SOC_IMX6Q + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_GPMI_NFC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_MXC_HDMI + select IMX_HAVE_PLATFORM_IMX_ASRC + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_IMX_CAAM + help + Include support for i.MX 6Quad SABRE Lite platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6Q_SABRESD + bool "Support i.MX 6Quad SABRESD platform" + select ARCH_MX6Q + select SOC_IMX6Q + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_GPMI_NFC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_MXC_HDMI + select IMX_HAVE_PLATFORM_IMX_ASRC + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_IMX_PCIE + select IMX_HAVE_PLATFORM_IMX_CAAM + help + Include support for i.MX 6Quad SABRE SD platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6Q_SABREAUTO + bool "Support i.MX 6Quad SABRE Auto platform" + select ARCH_MX6Q + select SOC_IMX6Q + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_GPMI_NFC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_ESAI + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_MXC_HDMI + select IMX_HAVE_PLATFORM_IMX_ASRC + select IMX_HAVE_PLATFORM_IMX_SPDIF + select IMX_HAVE_PLATFORM_IMX_MIPI_DSI + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_IMX_MIPI_CSI2 + select IMX_HAVE_PLATFORM_IMX_PCIE + select IMX_HAVE_PLATFORM_IMX_CAAM + help + Include support for i.MX 6Quad SABRE Auto platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX6Q_HDMIDONGLE + bool "Support i.MX 6Quad HDMIDONGLE platform" + select ARCH_MX6Q + select SOC_IMX6Q + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_DMA + select IMX_HAVE_PLATFORM_GPMI_NFC + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select IMX_HAVE_PLATFORM_SPI_IMX + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_VIV_GPU + select IMX_HAVE_PLATFORM_IMX_VPU + select IMX_HAVE_PLATFORM_IMX_DVFS + select IMX_HAVE_PLATFORM_IMX_ANATOP_THERMAL + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_FSL_OTG + select IMX_HAVE_PLATFORM_FSL_USB_WAKEUP + select IMX_HAVE_PLATFORM_AHCI + select IMX_HAVE_PLATFORM_IMX_OCOTP + select IMX_HAVE_PLATFORM_IMX_VIIM + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_SNVS_RTC + select IMX_HAVE_PLATFORM_IMX_PM + select IMX_HAVE_PLATFORM_MXC_HDMI + select IMX_HAVE_PLATFORM_IMX_PCIE + help + Include support for i.MX 6Quad HDMI Dongle platform. This includes specific + configurations for the board and its peripherals. + +comment "MX6 Options:" + +config IMX_PCIE + bool "PCI Express support" + select PCI + +config IMX_PCIE_EP_MODE_IN_EP_RC_SYS + bool "PCI Express EP mode in the IMX6 RC/EP interconnection system" + depends on IMX_PCIE + +config IMX_PCIE_RC_MODE_IN_EP_RC_SYS + bool "PCI Express RC mode in the IMX6 RC/EP interconnection system" + depends on IMX_PCIE + +config USB_EHCI_ARC_H1 + tristate "USB Host 1 support" + depends on USB_EHCI_ARC + +config USB_FSL_ARC_OTG + tristate "FSL USB OTG support" + +config USB_ID_WAKEUP_ENABLE + bool "Enable USB ID Pin As System Wakeup Source" + depends on SOC_IMX6SL + default n + +config MX6_INTER_LDO_BYPASS + bool "Internal LDO in MX6Q/DL bypass" + depends on REGULATOR_PFUZE100 && CPU_FREQ_IMX && ARCH_MX6 + default n + help + This is choosed for bypass internal LDO in MX6. If choose it, internal + LDO will replaced by external pmic regulator(e.g. pfuze100), VDDCORE + can be adjust automatically adjust by cpu frequency. + +config MX6_CLK_FOR_BOOTUI_TRANS + bool "MX6 clk setting for smooth UI transtion from bootloader to kernel" + depends on MXC_IPU_V3H + default n + help + This is choosed to keep enable IPU related clocks and PWM clocks and + avoid setting IPU related clocks' parents when initializing clock tree + so that bootloader splashimage can transition to kernel smoothly. + + +config MX6_ENET_IRQ_TO_GPIO + bool "Route ENET interrupts to GPIO" + default n + help + Enabling this will direct all the ENET interrupts to a board specific GPIO. + This will allow the system to enter WAIT mode when ENET is active. + +config SDMA_IRAM + bool "Use Internal RAM for SDMA data structures" + depends on IMX_SDMA && SOC_IMX6SL + help + SDMA buffer or control structures are stored in the IRAM/OCRAM + + +endif diff --git a/arch/arm/mach-mx6/Makefile b/arch/arm/mach-mx6/Makefile new file mode 100644 index 00000000..14fbbde2 --- /dev/null +++ b/arch/arm/mach-mx6/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. +obj-y := cpu.o mm.o system.o devices.o dummy_gpio.o irq.o bus_freq.o usb_h2.o usb_h3.o\ +pm.o cpu_op-mx6.o mx6_wfi.o mx6_fec.o mx6_anatop_regulator.o cpu_regulator-mx6.o \ +mx6_mmdc.o mx6_ddr_freq.o mx6sl_ddr.o mx6sl_wfi.o etm.o + +obj-$(CONFIG_ARCH_MX6) += clock.o mx6_suspend.o clock_mx6sl.o +obj-$(CONFIG_MACH_MX6Q_ARM2) += board-mx6q_arm2.o +obj-$(CONFIG_MACH_MX6SL_ARM2) += board-mx6sl_arm2.o mx6sl_arm2_pmic_pfuze100.o +obj-$(CONFIG_MACH_MX6SL_EVK) += board-mx6sl_evk.o mx6sl_evk_pmic_pfuze100.o +obj-$(CONFIG_MACH_MX6SL_NTX) += board-mx6sl_ntx.o mx6sl_ntx_pmic_pfuze100.o mx6sl_ntx_io.o +obj-$(CONFIG_MACH_MX6Q_SABRELITE) += board-mx6q_sabrelite.o +obj-$(CONFIG_MACH_MX6Q_SABRESD) += board-mx6q_sabresd.o mx6q_sabresd_pmic_pfuze100.o +obj-$(CONFIG_MACH_MX6Q_SABREAUTO) += board-mx6q_sabreauto.o mx6q_sabreauto_pmic_pfuze100.o +obj-$(CONFIG_MACH_MX6Q_HDMIDONGLE) += board-mx6q_hdmidongle.o +obj-$(CONFIG_SMP) += plat_hotplug.o platsmp.o headsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o +obj-$(CONFIG_IMX_PCIE) += pcie.o +obj-$(CONFIG_USB_FSL_ARC_OTG) += usb_dr.o +obj-$(CONFIG_USB_EHCI_ARC_H1) += usb_h1.o +obj-$(CONFIG_PCI_MSI) += msi.o + diff --git a/arch/arm/mach-mx6/Makefile.boot b/arch/arm/mach-mx6/Makefile.boot new file mode 100644 index 00000000..dc006a84 --- /dev/null +++ b/arch/arm/mach-mx6/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-$(CONFIG_ARCH_MX6Q) := 0x10008000 +params_phys-$(CONFIG_ARCH_MX6Q) := 0x10000100 +initrd_phys-$(CONFIG_ARCH_MX6Q) := 0x10800000 diff --git a/arch/arm/mach-mx6/board-mx6dl_arm2.h b/arch/arm/mach-mx6/board-mx6dl_arm2.h new file mode 100644 index 00000000..dd7e6658 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6dl_arm2.h @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2012-2013 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/iomux-mx6dl.h> + +static iomux_v3_cfg_t mx6dl_arm2_pads[] = { + + /* UART4 for debug */ + MX6DL_PAD_KEY_COL0__UART4_TXD, + MX6DL_PAD_KEY_ROW0__UART4_RXD, + /* USB HSIC ports use the same pin with ENET */ +#ifdef CONFIG_USB_EHCI_ARC_HSIC + /* USB H2 strobe/data pin */ + MX6DL_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE, + MX6DL_PAD_RGMII_TXC__USBOH3_H2_DATA, + + /* USB H3 strobe/data pin */ + MX6DL_PAD_RGMII_RXC__USBOH3_H3_STROBE, + MX6DL_PAD_RGMII_RX_CTL__USBOH3_H3_DATA, + /* ENET */ +#else + MX6DL_PAD_KEY_COL1__ENET_MDIO, + MX6DL_PAD_KEY_COL2__ENET_MDC, + MX6DL_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6DL_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6DL_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6DL_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6DL_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6DL_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6DL_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6DL_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6DL_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6DL_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6DL_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6DL_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6DL_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, +#ifdef CONFIG_FEC_1588 + MX6DL_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, +#endif +#endif + /* MCLK for csi0 */ + MX6DL_PAD_GPIO_0__CCM_CLKO, + MX6DL_PAD_GPIO_3__CCM_CLKO2, + + /* SD1 */ + MX6DL_PAD_SD1_CLK__USDHC1_CLK, + MX6DL_PAD_SD1_CMD__USDHC1_CMD, + MX6DL_PAD_SD1_DAT0__USDHC1_DAT0, + MX6DL_PAD_SD1_DAT1__USDHC1_DAT1, + MX6DL_PAD_SD1_DAT2__USDHC1_DAT2, + MX6DL_PAD_SD1_DAT3__USDHC1_DAT3, + /* SD2 */ + MX6DL_PAD_SD2_CLK__USDHC2_CLK, + MX6DL_PAD_SD2_CMD__USDHC2_CMD, + MX6DL_PAD_SD2_DAT0__USDHC2_DAT0, + MX6DL_PAD_SD2_DAT1__USDHC2_DAT1, + MX6DL_PAD_SD2_DAT2__USDHC2_DAT2, + MX6DL_PAD_SD2_DAT3__USDHC2_DAT3, + /* SD3 */ + MX6DL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6DL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6DL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6DL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6DL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6DL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6DL_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6DL_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6DL_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6DL_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6DL_PAD_SD3_RST__USDHC3_RST, + /* SD3 VSelect */ + MX6DL_PAD_GPIO_18__USDHC3_VSELECT, + /* SD3_CD and SD3_WP */ + MX6DL_PAD_NANDF_CS0__GPIO_6_11, + MX6DL_PAD_NANDF_CS1__GPIO_6_14, + /* SD4 */ + MX6DL_PAD_SD4_CLK__USDHC4_CLK_50MHZ, + MX6DL_PAD_SD4_CMD__USDHC4_CMD_50MHZ, + MX6DL_PAD_SD4_DAT0__USDHC4_DAT0_50MHZ, + MX6DL_PAD_SD4_DAT1__USDHC4_DAT1_50MHZ, + MX6DL_PAD_SD4_DAT2__USDHC4_DAT2_50MHZ, + MX6DL_PAD_SD4_DAT3__USDHC4_DAT3_50MHZ, + MX6DL_PAD_SD4_DAT4__USDHC4_DAT4_50MHZ, + MX6DL_PAD_SD4_DAT5__USDHC4_DAT5_50MHZ, + MX6DL_PAD_SD4_DAT6__USDHC4_DAT6_50MHZ, + MX6DL_PAD_SD4_DAT7__USDHC4_DAT7_50MHZ, + MX6DL_PAD_NANDF_ALE__USDHC4_RST, + /* eCSPI1 */ + MX6DL_PAD_EIM_EB2__ECSPI1_SS0, + MX6DL_PAD_EIM_D16__ECSPI1_SCLK, + MX6DL_PAD_EIM_D17__ECSPI1_MISO, + MX6DL_PAD_EIM_D18__ECSPI1_MOSI, + MX6DL_PAD_EIM_D19__ECSPI1_SS1, + MX6DL_PAD_EIM_EB2__GPIO_2_30, /*SS0*/ + MX6DL_PAD_EIM_D19__GPIO_3_19, /*SS1*/ + + /* ESAI */ + MX6DL_PAD_ENET_RXD0__ESAI1_HCKT, + MX6DL_PAD_ENET_CRS_DV__ESAI1_SCKT, + MX6DL_PAD_ENET_RXD1__ESAI1_FST, + MX6DL_PAD_ENET_TX_EN__ESAI1_TX3_RX2, + MX6DL_PAD_ENET_TXD1__ESAI1_TX2_RX3, + MX6DL_PAD_ENET_TXD0__ESAI1_TX4_RX1, + MX6DL_PAD_ENET_MDC__ESAI1_TX5_RX0, + MX6DL_PAD_NANDF_CS2__ESAI1_TX0, + MX6DL_PAD_NANDF_CS3__ESAI1_TX1, + + /* I2C1 */ + MX6DL_PAD_CSI0_DAT8__I2C1_SDA, + MX6DL_PAD_CSI0_DAT9__I2C1_SCL, + + /* I2C2 */ + MX6DL_PAD_KEY_COL3__I2C2_SCL, + MX6DL_PAD_KEY_ROW3__I2C2_SDA, + + /* DISPLAY */ + MX6DL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6DL_PAD_DI0_PIN15__IPU1_DI0_PIN15, + MX6DL_PAD_DI0_PIN2__IPU1_DI0_PIN2, + MX6DL_PAD_DI0_PIN3__IPU1_DI0_PIN3, + MX6DL_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6DL_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6DL_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6DL_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6DL_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6DL_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6DL_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6DL_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6DL_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6DL_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6DL_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6DL_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6DL_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6DL_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6DL_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6DL_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6DL_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6DL_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6DL_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6DL_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6DL_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20, + MX6DL_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + MX6DL_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22, + MX6DL_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23, + + MX6DL_PAD_EIM_D24__GPIO_3_24, + + /* UART2 */ + MX6DL_PAD_EIM_D26__UART2_RXD, + MX6DL_PAD_EIM_D27__UART2_TXD, + MX6DL_PAD_EIM_D28__UART2_RTS, + MX6DL_PAD_EIM_D29__UART2_CTS, + + /* PWM1 */ + MX6DL_PAD_GPIO_9__PWM1_PWMO, + + /* DISP0 DET */ + MX6DL_PAD_EIM_D31__GPIO_3_31, + + /* DISP0 RESET */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, + + /* HDMI */ + MX6DL_PAD_EIM_A25__HDMI_TX_CEC_LINE, + MX6DL_PAD_SD1_DAT1__HDMI_TX_OPHYDTB_0, + MX6DL_PAD_SD1_DAT0__HDMI_TX_OPHYDTB_1, + + /* USBOTG ID pin */ + MX6DL_PAD_GPIO_1__USBOTG_ID, + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6DL_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, +#else + /* MLB150 */ + MX6DL_PAD_GPIO_3__MLB_MLBCLK, + MX6DL_PAD_GPIO_6__MLB_MLBSIG, + MX6DL_PAD_GPIO_2__MLB_MLBDAT, +#endif +}; + +static iomux_v3_cfg_t mx6dl_arm2_epdc_pads[] = { + MX6DL_PAD_EIM_A17__GPIO_2_21, + MX6DL_PAD_EIM_D17__GPIO_3_17, + MX6DL_PAD_EIM_A18__GPIO_2_20, +}; + +static iomux_v3_cfg_t mx6dl_arm2_i2c3_pads[] = { + MX6DL_PAD_GPIO_5__I2C3_SCL, + MX6DL_PAD_GPIO_16__I2C3_SDA, +}; + +static iomux_v3_cfg_t mx6dl_arm2_spdif_pads[] = { + /* SPDIF */ + MX6DL_PAD_GPIO_16__SPDIF_IN1, + MX6DL_PAD_GPIO_17__SPDIF_OUT1, +}; + +static iomux_v3_cfg_t mx6dl_arm2_can_pads[] = { + /* CAN1 */ + MX6DL_PAD_GPIO_7__CAN1_TXCAN, + MX6DL_PAD_KEY_ROW2__CAN1_RXCAN, + MX6DL_PAD_GPIO_17__GPIO_7_12, /* CAN1 STBY */ + MX6DL_PAD_GPIO_18__GPIO_7_13, /* CAN1 EN */ + + /* CAN2 */ + MX6DL_PAD_KEY_COL4__CAN2_TXCAN, + MX6DL_PAD_KEY_ROW4__CAN2_RXCAN, + MX6DL_PAD_CSI0_DAT6__GPIO_5_24, /* CAN2 EN */ +}; + +static iomux_v3_cfg_t mx6dl_arm2_esai_record_pads[] = { + MX6DL_PAD_ENET_RX_ER__ESAI1_HCKR, + MX6DL_PAD_ENET_MDIO__ESAI1_SCKR, + MX6DL_PAD_ENET_REF_CLK__ESAI1_FSR, +}; + +static iomux_v3_cfg_t mx6dl_arm2_csi0_sensor_pads[] = { + MX6DL_PAD_GPIO_0__CCM_CLKO, + /* ipu1 csi0 */ + MX6DL_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6DL_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6DL_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6DL_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6DL_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6DL_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6DL_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6DL_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6DL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + MX6DL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6DL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + /* camera reset */ + MX6DL_PAD_GPIO_19__GPIO_4_5, + /* camera powerdown */ + MX6DL_PAD_CSI0_DAT5__GPIO_5_23, +}; + +static iomux_v3_cfg_t mx6dl_arm2_csi0_tvin_pads[] = { + /* ipu1 csi0 */ + MX6DL_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6DL_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6DL_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6DL_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6DL_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6DL_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6DL_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6DL_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6DL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + MX6DL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6DL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + /* camera reset */ + MX6DL_PAD_CSI0_DAT7__GPIO_5_25, + /* camera powerdown */ + MX6DL_PAD_CSI0_DAT5__GPIO_5_23, +}; + +static iomux_v3_cfg_t mx6dl_arm2_mipi_sensor_pads[] = { + MX6DL_PAD_CSI0_MCLK__CCM_CLKO, +}; + +static iomux_v3_cfg_t mx6dl_arm2_audmux_pads[] = { + + /* AUDMUX */ + MX6DL_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC, + MX6DL_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD, + MX6DL_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS, + MX6DL_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD, +}; + +#define MX6DL_USDHC_PAD_SETTING(id, speed) \ +mx6dl_sd##id##_##speed##mhz[] = { \ + MX6DL_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6DL_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT4__USDHC##id##_DAT4_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT5__USDHC##id##_DAT5_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT6__USDHC##id##_DAT6_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT7__USDHC##id##_DAT7_##speed##MHZ, \ +} + +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(3, 50); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(3, 100); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(3, 200); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(4, 50); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(4, 100); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(4, 200); + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx6dl_gpmi_nand[] __initdata = { + MX6DL_PAD_NANDF_CLE__RAWNAND_CLE, + MX6DL_PAD_NANDF_ALE__RAWNAND_ALE, + MX6DL_PAD_NANDF_CS0__RAWNAND_CE0N, + MX6DL_PAD_NANDF_CS1__RAWNAND_CE1N, + MX6DL_PAD_NANDF_CS2__RAWNAND_CE2N, + MX6DL_PAD_NANDF_CS3__RAWNAND_CE3N, + MX6DL_PAD_NANDF_RB0__RAWNAND_READY0, + MX6DL_PAD_SD4_DAT0__RAWNAND_DQS, + MX6DL_PAD_NANDF_D0__RAWNAND_D0, + MX6DL_PAD_NANDF_D1__RAWNAND_D1, + MX6DL_PAD_NANDF_D2__RAWNAND_D2, + MX6DL_PAD_NANDF_D3__RAWNAND_D3, + MX6DL_PAD_NANDF_D4__RAWNAND_D4, + MX6DL_PAD_NANDF_D5__RAWNAND_D5, + MX6DL_PAD_NANDF_D6__RAWNAND_D6, + MX6DL_PAD_NANDF_D7__RAWNAND_D7, + MX6DL_PAD_SD4_CMD__RAWNAND_RDN, + MX6DL_PAD_SD4_CLK__RAWNAND_WRN, + MX6DL_PAD_NANDF_WP_B__RAWNAND_RESETN, +}; + +static iomux_v3_cfg_t mx6dl_arm2_hdmi_ddc_pads[] = { + MX6DL_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6DL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6dl_arm2_i2c2_pads[] = { + MX6DL_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6DL_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; diff --git a/arch/arm/mach-mx6/board-mx6dl_hdmidongle.h b/arch/arm/mach-mx6/board-mx6dl_hdmidongle.h new file mode 100644 index 00000000..b46b6e16 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6dl_hdmidongle.h @@ -0,0 +1,342 @@ +/* + * 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. + */ + +#ifndef _BOARD_MX6DL_HDMIDONGLE_H +#define _BOARD_MX6DL_HDMIDONGLE_H +#include <mach/iomux-mx6dl.h> + +static iomux_v3_cfg_t mx6dl_hdmidongle_rev_a_pads[] = { + /* SPI2 for PMIC communication port */ + MX6DL_PAD_EIM_OE__ECSPI2_MISO, + MX6DL_PAD_EIM_RW__ECSPI2_SS0, + MX6DL_PAD_EIM_CS0__ECSPI2_SCLK, + MX6DL_PAD_EIM_CS1__ECSPI2_MOSI, + + /*USB_OTG_DET(USB OTG cable plug detect) */ + MX6DL_PAD_EIM_A16__GPIO_2_22, + /*BT_WAKEUP_HOST(Combo module BT wake-up output) */ + MX6DL_PAD_EIM_A25__GPIO_5_2, + /* HOST_WAKEUP_BT(CPU wakeup BT signal)*/ + MX6DL_PAD_EIM_D16__GPIO_3_16, + + /* I2C3 */ + MX6DL_PAD_EIM_D17__I2C3_SCL, + MX6DL_PAD_EIM_D18__I2C3_SDA, + + /* USB OC pin */ + MX6DL_PAD_EIM_D21__USBOH3_USBOTG_OC, + /* WLAN_WAKEUP_HOST(Combo module WLAN host wake-up output) */ + MX6DL_PAD_EIM_D22__GPIO_3_22, + + /* BT_UART2 */ + MX6DL_PAD_EIM_D26__UART2_TXD, + MX6DL_PAD_EIM_D27__UART2_RXD, + MX6DL_PAD_EIM_D28__UART2_CTS, + MX6DL_PAD_EIM_D29__UART2_RTS, + + /*BT_nRST(Combo module BT reset signal)*/ + MX6DL_PAD_EIM_DA7__GPIO_3_7, + + /*BT_REG_ON(Combo module BT Internal regulators power enable/disable)*/ + MX6DL_PAD_EIM_DA9__GPIO_3_9, + + /*WL_REG_ON(Combo module WLAN Internal regulators power enable/disable)*/ + MX6DL_PAD_EIM_DA10__GPIO_3_10, + + /* GPIO2 */ + MX6DL_PAD_EIM_A22__GPIO_2_16, /* Boot Mode Select */ + MX6DL_PAD_EIM_A21__GPIO_2_17, /* Boot Mode Select */ + MX6DL_PAD_EIM_A20__GPIO_2_18, /* Boot Mode Select */ + MX6DL_PAD_EIM_A19__GPIO_2_19, /* Boot Mode Select */ + MX6DL_PAD_EIM_A18__GPIO_2_20, /* Boot Mode Select */ + MX6DL_PAD_EIM_A17__GPIO_2_21, /* Boot Mode Select */ + MX6DL_PAD_EIM_RW__GPIO_2_26, /* Boot Mode Select */ + MX6DL_PAD_EIM_LBA__GPIO_2_27, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB0__GPIO_2_28, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB1__GPIO_2_29, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB2__GPIO_2_30, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB3__GPIO_2_31, /* Boot Mode Select */ + + /* GPIO3 */ + MX6DL_PAD_EIM_DA0__GPIO_3_0, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA1__GPIO_3_1, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA2__GPIO_3_2, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA3__GPIO_3_3, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA4__GPIO_3_4, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA5__GPIO_3_5, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA6__GPIO_3_6, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA8__GPIO_3_8, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA11__GPIO_3_11, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA12__GPIO_3_12, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA13__GPIO_3_13, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA14__GPIO_3_14, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA15__GPIO_3_15, /* Boot Mode Select */ + + /* GPIO5 */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, /* Boot Mode Select */ + MX6DL_PAD_EIM_A24__GPIO_5_4, /* Boot Mode Select */ + + /* GPIO6 */ + MX6DL_PAD_EIM_A23__GPIO_6_6, /* Boot Mode Select */ + + /* I2C1 */ + MX6DL_PAD_CSI0_DAT8__I2C1_SDA, + MX6DL_PAD_CSI0_DAT9__I2C1_SCL, + + /* UART1 for debug */ + MX6DL_PAD_CSI0_DAT10__UART1_TXD, + MX6DL_PAD_CSI0_DAT11__UART1_RXD, + + /* SD1 (Combo module WLAN SDIO )*/ + MX6DL_PAD_SD1_CLK__USDHC1_CLK, + MX6DL_PAD_SD1_CMD__USDHC1_CMD, + MX6DL_PAD_SD1_DAT0__USDHC1_DAT0, + MX6DL_PAD_SD1_DAT1__USDHC1_DAT1, + MX6DL_PAD_SD1_DAT2__USDHC1_DAT2, + MX6DL_PAD_SD1_DAT3__USDHC1_DAT3, + + /* SD2 (MicroSD SDIO CMD)*/ + MX6DL_PAD_SD2_CLK__USDHC2_CLK, + MX6DL_PAD_SD2_CMD__USDHC2_CMD, + MX6DL_PAD_SD2_DAT0__USDHC2_DAT0, + MX6DL_PAD_SD2_DAT1__USDHC2_DAT1, + MX6DL_PAD_SD2_DAT2__USDHC2_DAT2, + MX6DL_PAD_SD2_DAT3__USDHC2_DAT3, + /*SD_DET (SD plug-in detect interrupt)*/ + MX6DL_PAD_GPIO_4__GPIO_1_4, + + /* SD3 (eMMC SDIO)*/ + MX6DL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6DL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6DL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6DL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6DL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6DL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6DL_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6DL_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6DL_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6DL_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6DL_PAD_SD3_RST__USDHC3_RST, + + /* UART4 for debug */ + MX6DL_PAD_KEY_COL0__UART4_TXD, + MX6DL_PAD_KEY_ROW0__UART4_RXD, + + /*HDMI CEC communication PIN*/ + MX6DL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, + + /* I2C2 */ + MX6DL_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ + MX6DL_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ + + /*DCDC5V_PWREN(5V DCDC BOOST control signal)*/ + MX6DL_PAD_KEY_COL4__GPIO_4_14, + + /*USB_OTG_PWREN(USB OTG power change control signal)*/ + MX6DL_PAD_KEY_ROW4__GPIO_4_15, + + /* USBOTG ID pin */ + MX6DL_PAD_GPIO_1__USBOTG_ID, + + /* I2C3 */ + MX6DL_PAD_GPIO_5__I2C3_SCL, + MX6DL_PAD_GPIO_16__I2C3_SDA, + + /*WDOG(Watch dog output)*/ + MX6DL_PAD_GPIO_9__GPIO_1_9, + + /*PMIC_nINT(PMIC interrupt signal)*/ + MX6DL_PAD_NANDF_CS0__GPIO_6_11, + + /*GPIO_nRST(GPIO shutdown control)*/ + MX6DL_PAD_NANDF_CS1__GPIO_6_14, + + /*PWRKEY_DET(Power key press detection)*/ + MX6DL_PAD_NANDF_CS3__GPIO_6_16, + + /*CHG_SYS_ON(Charger auto power on control signal)*/ + MX6DL_PAD_NANDF_D6__GPIO_2_6, + + /*IR_RC*/ + MX6DL_PAD_SD4_DAT6__GPIO_2_14, +}; + +static iomux_v3_cfg_t mx6dl_hdmidongle_rev_b_pads[] = { + /* SPI2 for PMIC communication port */ + MX6DL_PAD_EIM_OE__ECSPI2_MISO, + MX6DL_PAD_EIM_RW__ECSPI2_SS0, + MX6DL_PAD_EIM_CS0__ECSPI2_SCLK, + MX6DL_PAD_EIM_CS1__ECSPI2_MOSI, + + /*USB_OTG_DET(USB OTG cable plug detect) */ + MX6DL_PAD_EIM_A16__GPIO_2_22, + /*WLAN_CLKREQn*/ + MX6DL_PAD_EIM_A25__GPIO_5_2, + + /* WLAN_ACT */ + MX6DL_PAD_EIM_D17__GPIO_3_17, + + /*BT_PERI*/ + MX6DL_PAD_EIM_D18__GPIO_3_18, + + /* USB OC pin */ + MX6DL_PAD_EIM_D21__USBOH3_USBOTG_OC, + + /* WLAN_WAKEn (PM event, OD, used to reactivate the PCIe main PWR and REF CLK) */ + MX6DL_PAD_EIM_D22__GPIO_3_22, + + + /*WLAN_PERSTn (PCIe rst signal, avtive LOW)*/ + MX6DL_PAD_EIM_DA9__GPIO_3_9, + + /*WLAN_PDn (Externally shutdown RTL8192)*/ + MX6DL_PAD_EIM_DA10__GPIO_3_10, + + /* GPIO2 */ + MX6DL_PAD_EIM_A22__GPIO_2_16, /* Boot Mode Select */ + MX6DL_PAD_EIM_A21__GPIO_2_17, /* Boot Mode Select */ + MX6DL_PAD_EIM_A20__GPIO_2_18, /* Boot Mode Select */ + MX6DL_PAD_EIM_A19__GPIO_2_19, /* Boot Mode Select */ + MX6DL_PAD_EIM_A18__GPIO_2_20, /* Boot Mode Select */ + MX6DL_PAD_EIM_A17__GPIO_2_21, /* Boot Mode Select */ + MX6DL_PAD_EIM_RW__GPIO_2_26, /* Boot Mode Select */ + MX6DL_PAD_EIM_LBA__GPIO_2_27, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB0__GPIO_2_28, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB1__GPIO_2_29, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB2__GPIO_2_30, /* Boot Mode Select */ + MX6DL_PAD_EIM_EB3__GPIO_2_31, /* Boot Mode Select */ + + /* GPIO3 */ + MX6DL_PAD_EIM_DA0__GPIO_3_0, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA1__GPIO_3_1, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA2__GPIO_3_2, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA3__GPIO_3_3, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA4__GPIO_3_4, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA5__GPIO_3_5, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA6__GPIO_3_6, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA8__GPIO_3_8, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA11__GPIO_3_11, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA12__GPIO_3_12, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA13__GPIO_3_13, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA14__GPIO_3_14, /* Boot Mode Select */ + MX6DL_PAD_EIM_DA15__GPIO_3_15, /* Boot Mode Select */ + + /* GPIO5 */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, /* Boot Mode Select */ + MX6DL_PAD_EIM_A24__GPIO_5_4, /* Boot Mode Select */ + + /* GPIO6 */ + MX6DL_PAD_EIM_A23__GPIO_6_6, /* Boot Mode Select */ + + /* SD2 (MicroSD SDIO CMD)*/ + MX6DL_PAD_SD2_CLK__USDHC2_CLK, + MX6DL_PAD_SD2_CMD__USDHC2_CMD, + MX6DL_PAD_SD2_DAT0__USDHC2_DAT0, + MX6DL_PAD_SD2_DAT1__USDHC2_DAT1, + MX6DL_PAD_SD2_DAT2__USDHC2_DAT2, + MX6DL_PAD_SD2_DAT3__USDHC2_DAT3, + /*SD_DET (SD plug-in detect interrupt)*/ + MX6DL_PAD_GPIO_4__GPIO_1_4, + + /* SD3 (eMMC SDIO)*/ + MX6DL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6DL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6DL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6DL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6DL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6DL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6DL_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6DL_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6DL_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6DL_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6DL_PAD_SD3_RST__USDHC3_RST, + + /* UART4 for debug */ + MX6DL_PAD_KEY_COL0__UART4_TXD, + MX6DL_PAD_KEY_ROW0__UART4_RXD, + + /*SD2_VSELECT (SD2 SDXC power exchange control signal)*/ + MX6DL_PAD_KEY_ROW1__GPIO_4_9, + + /*HDMI CEC communication PIN*/ + MX6DL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, + + /*PWRKEY_DET (Pwr button detection interrupt)*/ + MX6DL_PAD_ENET_RXD0__GPIO_1_27, + + /*USB_OTG_PWREN(USB OTG power change control signal)*/ + MX6DL_PAD_KEY_ROW4__GPIO_4_15, + + /* USBOTG ID pin */ + MX6DL_PAD_GPIO_1__USBOTG_ID, + + /* I2C2 */ + MX6DL_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ + MX6DL_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ + + /* I2C3 */ + MX6DL_PAD_GPIO_5__I2C3_SCL, + MX6DL_PAD_GPIO_16__I2C3_SDA, + + /*WDOG(Watch dog output)*/ + MX6DL_PAD_GPIO_9__GPIO_1_9, + + /*PMIC_nINT(PMIC interrupt signal)*/ + MX6DL_PAD_SD4_DAT3__GPIO_2_11, + + /*GPIO_nRST(GPIO shutdown control)*/ + MX6DL_PAD_SD4_DAT1__GPIO_2_9, + + /*CHG_SYS_ON(Charger auto power on control signal)*/ + MX6DL_PAD_SD4_DAT6__GPIO_2_14, +}; + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx6dl_gpmi_nand[] __initdata = { + MX6DL_PAD_NANDF_CLE__RAWNAND_CLE, + MX6DL_PAD_NANDF_ALE__RAWNAND_ALE, + MX6DL_PAD_NANDF_CS0__RAWNAND_CE0N, + MX6DL_PAD_NANDF_CS1__RAWNAND_CE1N, + MX6DL_PAD_NANDF_CS2__RAWNAND_CE2N, + MX6DL_PAD_NANDF_CS3__RAWNAND_CE3N, + MX6DL_PAD_NANDF_RB0__RAWNAND_READY0, + MX6DL_PAD_SD4_DAT0__RAWNAND_DQS, + MX6DL_PAD_NANDF_D0__RAWNAND_D0, + MX6DL_PAD_NANDF_D1__RAWNAND_D1, + MX6DL_PAD_NANDF_D2__RAWNAND_D2, + MX6DL_PAD_NANDF_D3__RAWNAND_D3, + MX6DL_PAD_NANDF_D4__RAWNAND_D4, + MX6DL_PAD_NANDF_D5__RAWNAND_D5, + MX6DL_PAD_NANDF_D6__RAWNAND_D6, + MX6DL_PAD_NANDF_D7__RAWNAND_D7, + MX6DL_PAD_SD4_CMD__RAWNAND_RDN, + MX6DL_PAD_SD4_CLK__RAWNAND_WRN, + MX6DL_PAD_NANDF_WP_B__RAWNAND_RESETN, +}; + +static iomux_v3_cfg_t mx6dl_hdmidongle_hdmi_ddc_pads[] = { + MX6DL_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6DL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6dl_hdmidongle_i2c2_pads[] = { + MX6DL_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6DL_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; + +#endif diff --git a/arch/arm/mach-mx6/board-mx6dl_sabresd.h b/arch/arm/mach-mx6/board-mx6dl_sabresd.h new file mode 100644 index 00000000..4e2d322f --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6dl_sabresd.h @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2012-2013 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 _BOARD_MX6DL_SABRESD_H +#define _BOARD_MX6DL_SABRESD_H +#include <mach/iomux-mx6dl.h> + +static iomux_v3_cfg_t mx6dl_sabresd_pads[] = { + /* AUDMUX */ + MX6DL_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC, + MX6DL_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD, + MX6DL_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS, + MX6DL_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD, + + /* CSPI */ + MX6DL_PAD_KEY_COL0__ECSPI1_SCLK, + MX6DL_PAD_KEY_ROW0__ECSPI1_MOSI, + MX6DL_PAD_KEY_COL1__ECSPI1_MISO, + MX6DL_PAD_KEY_ROW1__GPIO_4_9, + + /* ENET */ + MX6DL_PAD_ENET_MDIO__ENET_MDIO, + MX6DL_PAD_ENET_MDC__ENET_MDC, + MX6DL_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6DL_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6DL_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6DL_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6DL_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6DL_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6DL_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6DL_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6DL_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6DL_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6DL_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6DL_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6DL_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, + /* RGMII_nRST */ + MX6DL_PAD_ENET_CRS_DV__GPIO_1_25, + /* IEEE 1588 clock */ + MX6DL_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, + /* RGMII Interrupt */ + MX6DL_PAD_ENET_RXD1__GPIO_1_26, + + /* I2C1 */ + MX6DL_PAD_CSI0_DAT8__I2C1_SDA, + MX6DL_PAD_CSI0_DAT9__I2C1_SCL, + + /* I2C2 */ + MX6DL_PAD_KEY_COL3__I2C2_SCL, + MX6DL_PAD_KEY_ROW3__I2C2_SDA, + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6DL_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, +#else + /* I2C3 */ + MX6DL_PAD_GPIO_3__I2C3_SCL, + MX6DL_PAD_GPIO_6__I2C3_SDA, +#endif + + /* DISPLAY */ + MX6DL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6DL_PAD_DI0_PIN15__IPU1_DI0_PIN15, /* DE */ + MX6DL_PAD_DI0_PIN2__IPU1_DI0_PIN2, /* HSync */ + MX6DL_PAD_DI0_PIN3__IPU1_DI0_PIN3, /* VSync */ + MX6DL_PAD_DI0_PIN4__IPU1_DI0_PIN4, /* Contrast */ + MX6DL_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6DL_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6DL_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6DL_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6DL_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6DL_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6DL_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6DL_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6DL_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6DL_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6DL_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6DL_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6DL_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6DL_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6DL_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6DL_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6DL_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6DL_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6DL_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6DL_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6DL_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20, + MX6DL_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + MX6DL_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22, + MX6DL_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23, + + /* FlexCAN */ + MX6DL_PAD_GPIO_7__CAN1_TXCAN, + MX6DL_PAD_GPIO_8__CAN1_RXCAN, + /* CAN1_STBY */ + MX6DL_PAD_GPIO_19__GPIO_4_5, + + /* UART1 for debug */ + MX6DL_PAD_CSI0_DAT10__UART1_TXD, + MX6DL_PAD_CSI0_DAT11__UART1_RXD, + + /* UART3 for gps */ + MX6DL_PAD_EIM_D24__UART3_TXD, + MX6DL_PAD_EIM_D25__UART3_RXD, + + /* USB */ + MX6DL_PAD_ENET_RX_ER__ANATOP_USBOTG_ID, + MX6DL_PAD_EIM_D21__USBOH3_USBOTG_OC, + /* USB_OTG_PWR_EN */ + MX6DL_PAD_EIM_D22__GPIO_3_22, + MX6DL_PAD_EIM_D30__USBOH3_USBH1_OC, + /*USB_H1 PWR EN*/ + MX6DL_PAD_ENET_TXD1__GPIO_1_29, + + /* USDHC2 */ + MX6DL_PAD_SD2_CLK__USDHC2_CLK, + MX6DL_PAD_SD2_CMD__USDHC2_CMD, + MX6DL_PAD_SD2_DAT0__USDHC2_DAT0, + MX6DL_PAD_SD2_DAT1__USDHC2_DAT1, + MX6DL_PAD_SD2_DAT2__USDHC2_DAT2, + MX6DL_PAD_SD2_DAT3__USDHC2_DAT3, + MX6DL_PAD_NANDF_D4__USDHC2_DAT4, + MX6DL_PAD_NANDF_D5__USDHC2_DAT5, + MX6DL_PAD_NANDF_D6__USDHC2_DAT6, + MX6DL_PAD_NANDF_D7__USDHC2_DAT7, + /* SD2_CD */ + MX6DL_PAD_NANDF_D2__GPIO_2_2, + /* SD2_WP */ + MX6DL_PAD_NANDF_D3__GPIO_2_3, + + /* USDHC3 */ + MX6DL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6DL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6DL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6DL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6DL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6DL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6DL_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6DL_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6DL_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6DL_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + /* SD3_CD */ + MX6DL_PAD_NANDF_D0__GPIO_2_0, + /* SD3_WP */ + MX6DL_PAD_NANDF_D1__GPIO_2_1, + + /* USDHC4 */ + MX6DL_PAD_SD4_CLK__USDHC4_CLK_50MHZ, + MX6DL_PAD_SD4_CMD__USDHC4_CMD_50MHZ, + MX6DL_PAD_SD4_DAT0__USDHC4_DAT0_50MHZ, + MX6DL_PAD_SD4_DAT1__USDHC4_DAT1_50MHZ, + MX6DL_PAD_SD4_DAT2__USDHC4_DAT2_50MHZ, + MX6DL_PAD_SD4_DAT3__USDHC4_DAT3_50MHZ, + MX6DL_PAD_SD4_DAT4__USDHC4_DAT4_50MHZ, + MX6DL_PAD_SD4_DAT5__USDHC4_DAT5_50MHZ, + MX6DL_PAD_SD4_DAT6__USDHC4_DAT6_50MHZ, + MX6DL_PAD_SD4_DAT7__USDHC4_DAT7_50MHZ, + + /* HDMI_CEC_IN*/ + MX6DL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, + + /* CCM - Audio, Camera clock */ + MX6DL_PAD_GPIO_0__CCM_CLKO, + /* MICROPHONE_DET */ + MX6DL_PAD_GPIO_9__GPIO_1_9, + /* CODEC_PWR_EN */ + MX6DL_PAD_KEY_COL2__GPIO_4_10, + /* HEADPHONE_DET */ + MX6DL_PAD_SD3_RST__GPIO_7_8, + + /* GPS_RESET_B */ + MX6DL_PAD_EIM_EB0__GPIO_2_28, + /* GPS_PWREN */ + MX6DL_PAD_EIM_DA0__GPIO_3_0, + /* GPS AUX_3V15_EN*/ + MX6DL_PAD_NANDF_WP_B__GPIO_6_9, + /* GPS_PPS */ + MX6DL_PAD_EIM_D18__GPIO_3_18, + + /* DISP0_RST_B */ + MX6DL_PAD_EIM_DA8__GPIO_3_8, + /* DI0_D0_CS */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, + /* DI1_D0_CS */ + MX6DL_PAD_EIM_BCLK__GPIO_6_31, + /* DISP_PWM */ + MX6DL_PAD_SD1_DAT3__PWM1_PWMO, + /* DISP0 power enable */ + MX6DL_PAD_ENET_TXD0__GPIO_1_30, + /* DISP0_RD */ + MX6DL_PAD_EIM_D28__GPIO_3_28, + /* DISP_RST_B */ + MX6DL_PAD_NANDF_CS0__GPIO_6_11, + /* DISP_PWR_EN */ + MX6DL_PAD_NANDF_CS1__GPIO_6_14, + /* CABC_EN0 */ + MX6DL_PAD_NANDF_CS2__GPIO_6_15, + /* CABC_EN1 */ + MX6DL_PAD_NANDF_CS3__GPIO_6_16, + /* DISP0_WR */ + MX6DL_PAD_NANDF_WP_B__GPIO_6_9, + + /* ALS INT */ + MX6DL_PAD_EIM_DA9__GPIO_3_9, + /* BARO_INT */ + MX6DL_PAD_EIM_DA15__GPIO_3_15, + + /* SW4 , SW5 & SW1 */ + /* Volume Up */ + MX6DL_PAD_GPIO_4__GPIO_1_4, + /* Volume Down */ + MX6DL_PAD_GPIO_5__GPIO_1_5, + /* power off */ + MX6DL_PAD_EIM_D29__GPIO_3_29, + + /* CAP_TCH_INT1 */ + MX6DL_PAD_NANDF_CLE__GPIO_6_7, + + /* CAP_TCH_INT0 */ + MX6DL_PAD_NANDF_ALE__GPIO_6_8, + + /* AUX_5V Enable */ + MX6DL_PAD_NANDF_RB0__GPIO_6_10, + + /* PCIE_RST_B */ + MX6DL_PAD_GPIO_17__GPIO_7_12, + /* PCIE_PWR_EN */ + MX6DL_PAD_EIM_D19__GPIO_3_19, + /* PCIE_WAKE_B */ + MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20, + /* PCIE_DIS_B */ + MX6DL_PAD_KEY_COL4__GPIO_4_14, + + /* PMIC_INT_B */ + MX6DL_PAD_GPIO_18__GPIO_7_13, + + /* Charge */ + MX6DL_PAD_EIM_A25__GPIO_5_2, /* FLT_1_B */ + MX6DL_PAD_EIM_D23__GPIO_3_23, /* CHG_1_B */ + MX6DL_PAD_EIM_DA13__GPIO_3_13, /* CHG_2_B */ + MX6DL_PAD_EIM_DA14__GPIO_3_14, /* FLT_2_B */ + + MX6DL_PAD_ENET_RXD0__GPIO_1_27, /* UOK_B */ + MX6DL_PAD_EIM_CS1__GPIO_2_24, /* DOK_B */ + + /* TS_INT - MAX11801 */ + MX6DL_PAD_EIM_D26__GPIO_3_26, + /* eCompass int */ + MX6DL_PAD_EIM_D16__GPIO_3_16, + + /* SENSOR_PWR_EN */ + MX6DL_PAD_EIM_EB3__GPIO_2_31, + /* ACCL_INT_INT */ + MX6DL_PAD_SD1_CMD__GPIO_1_18, + + /*WDOG_B to reset pmic*/ + MX6DL_PAD_GPIO_1__WDOG2_WDOG_B, + /* USR_DEF_RED_LED */ + MX6DL_PAD_GPIO_2__GPIO_1_2, +}; + +static iomux_v3_cfg_t mx6dl_sabresd_csi0_sensor_pads[] = { + /* IPU1 Camera */ + MX6DL_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6DL_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6DL_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6DL_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6DL_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6DL_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6DL_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6DL_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6DL_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN, + MX6DL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6DL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + MX6DL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + + MX6DL_PAD_GPIO_0__CCM_CLKO, /* camera clk */ + + MX6DL_PAD_SD1_DAT0__GPIO_1_16, /* camera PWDN */ + MX6DL_PAD_SD1_DAT1__GPIO_1_17, /* camera RESET */ +}; + +static iomux_v3_cfg_t mx6dl_sabresd_mipi_sensor_pads[] = { + MX6DL_PAD_GPIO_0__CCM_CLKO, /* camera clk */ + + MX6DL_PAD_SD1_DAT2__GPIO_1_19, /* camera PWDN */ + MX6DL_PAD_SD1_CLK__GPIO_1_20, /* camera RESET */ +}; + +static iomux_v3_cfg_t mx6dl_sabresd_epdc_enable_pads[] = { + /* EPDC */ + MX6DL_PAD_EIM_A16__EPDC_SDDO_0, + MX6DL_PAD_EIM_DA10__EPDC_SDDO_1, + MX6DL_PAD_EIM_DA12__EPDC_SDDO_2, + MX6DL_PAD_EIM_DA11__EPDC_SDDO_3, + MX6DL_PAD_EIM_LBA__EPDC_SDDO_4, + MX6DL_PAD_EIM_EB2__EPDC_SDDO_5, + MX6DL_PAD_EIM_CS0__EPDC_SDDO_6, + MX6DL_PAD_EIM_RW__EPDC_SDDO_7, + MX6DL_PAD_EIM_A21__EPDC_GDCLK, + MX6DL_PAD_EIM_A22__EPDC_GDSP, + MX6DL_PAD_EIM_A23__EPDC_GDOE, + MX6DL_PAD_EIM_A24__EPDC_GDRL, + MX6DL_PAD_EIM_D31__EPDC_SDCLK, + MX6DL_PAD_EIM_D27__EPDC_SDOE, + MX6DL_PAD_EIM_DA1__EPDC_SDLE, + MX6DL_PAD_EIM_EB1__EPDC_SDSHR, + MX6DL_PAD_EIM_DA2__EPDC_BDR_0, + MX6DL_PAD_EIM_DA4__EPDC_SDCE_0, + MX6DL_PAD_EIM_DA5__EPDC_SDCE_1, + MX6DL_PAD_EIM_DA6__EPDC_SDCE_2, + + /* EPD PMIC (Maxim 17135) pins */ + MX6DL_PAD_EIM_A17__GPIO_2_21, /* EPDC_PWRSTAT */ + MX6DL_PAD_EIM_D17__GPIO_3_17, /* EPDC_VCOM0 */ + MX6DL_PAD_EIM_A18__GPIO_2_20, /* EPDC_PWRCTRL0 */ + MX6DL_PAD_EIM_D20__GPIO_3_20, /* EPDC_PMIC_WAKEUP */ + /* + * Depopulate R121, R123, R133, R138, R139, + * R167, R168, and R627 when using E-BOOK + * Card in 16-bit Data Mode. Meanwhile, comments + * the conflict PIN configurations in above tables + */ + /* + MX6DL_PAD_EIM_CS1__EPDC_SDDO_8, + MX6DL_PAD_EIM_DA15__EPDC_SDDO_9, + MX6DL_PAD_EIM_D16__EPDC_SDDO_10, + MX6DL_PAD_EIM_D23__EPDC_SDDO_11 + MX6DL_PAD_EIM_D19__EPDC_SDDO_12, + MX6DL_PAD_EIM_DA13__EPDC_SDDO_13, + MX6DL_PAD_EIM_DA14__EPDC_SDDO_14, + MX6DL_PAD_EIM_A25__EPDC_SDDO_15, + */ +}; + +static iomux_v3_cfg_t mx6dl_sabresd_epdc_disable_pads[] = { + /* EPDC */ + MX6DL_PAD_EIM_A16__GPIO_2_22, + MX6DL_PAD_EIM_DA10__GPIO_3_10, + MX6DL_PAD_EIM_DA12__GPIO_3_12, + MX6DL_PAD_EIM_DA11__GPIO_3_11, + MX6DL_PAD_EIM_LBA__GPIO_2_27, + MX6DL_PAD_EIM_EB2__GPIO_2_30, + MX6DL_PAD_EIM_CS0__GPIO_2_23, + MX6DL_PAD_EIM_RW__GPIO_2_26, + MX6DL_PAD_EIM_A21__GPIO_2_17, + MX6DL_PAD_EIM_A22__GPIO_2_16, + MX6DL_PAD_EIM_A23__GPIO_6_6, + MX6DL_PAD_EIM_A24__GPIO_5_4, + MX6DL_PAD_EIM_D31__GPIO_3_31, + MX6DL_PAD_EIM_D27__GPIO_3_27, + MX6DL_PAD_EIM_DA1__GPIO_3_1, + MX6DL_PAD_EIM_EB1__GPIO_2_29, + MX6DL_PAD_EIM_DA2__GPIO_3_2, + MX6DL_PAD_EIM_DA4__GPIO_3_4, + MX6DL_PAD_EIM_DA5__GPIO_3_5, + MX6DL_PAD_EIM_DA6__GPIO_3_6, + + /* + * Depopulate R121, R123, R133, R138, R139, + * R167, R168, and R627 when using E-BOOK + * Card in 16-bit Data Mode. Meanwhile, comments + * the conflict PIN configurations in above tables + */ + /* + MX6DL_PAD_EIM_CS1__EPDC_SDDO_8, + MX6DL_PAD_EIM_DA15__EPDC_SDDO_9, + MX6DL_PAD_EIM_D16__EPDC_SDDO_10, + MX6DL_PAD_EIM_D23__EPDC_SDDO_11 + MX6DL_PAD_EIM_D19__EPDC_SDDO_12, + MX6DL_PAD_EIM_DA13__EPDC_SDDO_13, + MX6DL_PAD_EIM_DA14__EPDC_SDDO_14, + MX6DL_PAD_EIM_A25__EPDC_SDDO_15, + */ +}; + +static iomux_v3_cfg_t mx6dl_arm2_elan_pads[] = { + MX6DL_PAD_EIM_A20__GPIO_2_18, + MX6DL_PAD_EIM_DA8__GPIO_3_8, + MX6DL_PAD_EIM_D28__GPIO_3_28, +}; + +static iomux_v3_cfg_t mx6dl_sabresd_hdmi_ddc_pads[] = { + MX6DL_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6DL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6dl_sabresd_i2c2_pads[] = { + MX6DL_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6DL_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; +#endif diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.c b/arch/arm/mach-mx6/board-mx6q_arm2.c new file mode 100644 index 00000000..250ef90a --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_arm2.c @@ -0,0 +1,2303 @@ +/* + * Copyright (C) 2011-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/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/smsc911x.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/ion.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> +#include <sound/pcm.h> +#include <linux/mxc_asrc.h> +#include <linux/mfd/mxc-hdmi-core.h> + + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.h> +#include <mach/ahci_sata.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_hdmi.h> +#include <mach/mxc_asrc.h> +#include <mach/mipi_dsi.h> +#include <mach/mipi_csi2.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 "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6q_arm2.h" +#include "board-mx6dl_arm2.h" + +/* GPIO PIN, sort by PORT/BIT */ +#define MX6_ARM2_LDB_BACKLIGHT IMX_GPIO_NR(1, 9) +#define MX6_ARM2_ECSPI1_CS0 IMX_GPIO_NR(2, 30) +#define MX6_ARM2_ECSPI1_CS1 IMX_GPIO_NR(3, 19) +#define MX6_ARM2_USB_OTG_PWR IMX_GPIO_NR(3, 22) +#define MX6_ARM2_DISP0_PWR IMX_GPIO_NR(3, 24) +#define MX6_ARM2_DISP0_I2C_EN IMX_GPIO_NR(3, 28) +#define MX6_ARM2_CAP_TCH_INT IMX_GPIO_NR(3, 31) +#define MX6_ARM2_DISP0_DET_INT IMX_GPIO_NR(3, 31) +#define MX6_ARM2_CSI0_RST IMX_GPIO_NR(4, 5) +#define MX6_ARM2_DISP0_RESET IMX_GPIO_NR(5, 0) +#define MX6_ARM2_CSI0_PWN IMX_GPIO_NR(5, 23) +#define MX6_ARM2_CAN2_EN IMX_GPIO_NR(5, 24) +#define MX6_ARM2_CSI0_RST_TVIN IMX_GPIO_NR(5, 25) +#define MX6_ARM2_SD3_CD IMX_GPIO_NR(6, 11) +#define MX6_ARM2_SD3_WP IMX_GPIO_NR(6, 14) +#define MX6_ARM2_CAN1_STBY IMX_GPIO_NR(7, 12) +#define MX6_ARM2_CAN1_EN IMX_GPIO_NR(7, 13) +#define MX6_ARM2_MAX7310_1_BASE_ADDR IMX_GPIO_NR(8, 0) +#define MX6_ARM2_MAX7310_2_BASE_ADDR IMX_GPIO_NR(8, 8) +#define MX6DL_ARM2_EPDC_SDDO_0 IMX_GPIO_NR(2, 22) +#define MX6DL_ARM2_EPDC_SDDO_1 IMX_GPIO_NR(3, 10) +#define MX6DL_ARM2_EPDC_SDDO_2 IMX_GPIO_NR(3, 12) +#define MX6DL_ARM2_EPDC_SDDO_3 IMX_GPIO_NR(3, 11) +#define MX6DL_ARM2_EPDC_SDDO_4 IMX_GPIO_NR(2, 27) +#define MX6DL_ARM2_EPDC_SDDO_5 IMX_GPIO_NR(2, 30) +#define MX6DL_ARM2_EPDC_SDDO_6 IMX_GPIO_NR(2, 23) +#define MX6DL_ARM2_EPDC_SDDO_7 IMX_GPIO_NR(2, 26) +#define MX6DL_ARM2_EPDC_SDDO_8 IMX_GPIO_NR(2, 24) +#define MX6DL_ARM2_EPDC_SDDO_9 IMX_GPIO_NR(3, 15) +#define MX6DL_ARM2_EPDC_SDDO_10 IMX_GPIO_NR(3, 16) +#define MX6DL_ARM2_EPDC_SDDO_11 IMX_GPIO_NR(3, 23) +#define MX6DL_ARM2_EPDC_SDDO_12 IMX_GPIO_NR(3, 19) +#define MX6DL_ARM2_EPDC_SDDO_13 IMX_GPIO_NR(3, 13) +#define MX6DL_ARM2_EPDC_SDDO_14 IMX_GPIO_NR(3, 14) +#define MX6DL_ARM2_EPDC_SDDO_15 IMX_GPIO_NR(5, 2) +#define MX6DL_ARM2_EPDC_GDCLK IMX_GPIO_NR(2, 17) +#define MX6DL_ARM2_EPDC_GDSP IMX_GPIO_NR(2, 16) +#define MX6DL_ARM2_EPDC_GDOE IMX_GPIO_NR(6, 6) +#define MX6DL_ARM2_EPDC_GDRL IMX_GPIO_NR(5, 4) +#define MX6DL_ARM2_EPDC_SDCLK IMX_GPIO_NR(3, 31) +#define MX6DL_ARM2_EPDC_SDOEZ IMX_GPIO_NR(3, 30) +#define MX6DL_ARM2_EPDC_SDOED IMX_GPIO_NR(3, 26) +#define MX6DL_ARM2_EPDC_SDOE IMX_GPIO_NR(3, 27) +#define MX6DL_ARM2_EPDC_SDLE IMX_GPIO_NR(3, 1) +#define MX6DL_ARM2_EPDC_SDCLKN IMX_GPIO_NR(3, 0) +#define MX6DL_ARM2_EPDC_SDSHR IMX_GPIO_NR(2, 29) +#define MX6DL_ARM2_EPDC_PWRCOM IMX_GPIO_NR(2, 28) +#define MX6DL_ARM2_EPDC_PWRSTAT IMX_GPIO_NR(2, 21) +#define MX6DL_ARM2_EPDC_PWRCTRL0 IMX_GPIO_NR(2, 20) +#define MX6DL_ARM2_EPDC_PWRCTRL1 IMX_GPIO_NR(2, 19) +#define MX6DL_ARM2_EPDC_PWRCTRL2 IMX_GPIO_NR(2, 18) +#define MX6DL_ARM2_EPDC_PWRCTRL3 IMX_GPIO_NR(3, 28) +#define MX6DL_ARM2_EPDC_BDR0 IMX_GPIO_NR(3, 2) +#define MX6DL_ARM2_EPDC_BDR1 IMX_GPIO_NR(3, 3) +#define MX6DL_ARM2_EPDC_SDCE0 IMX_GPIO_NR(3, 4) +#define MX6DL_ARM2_EPDC_SDCE1 IMX_GPIO_NR(3, 5) +#define MX6DL_ARM2_EPDC_SDCE2 IMX_GPIO_NR(3, 6) +#define MX6DL_ARM2_EPDC_SDCE3 IMX_GPIO_NR(3, 7) +#define MX6DL_ARM2_EPDC_SDCE4 IMX_GPIO_NR(3, 8) +#define MX6DL_ARM2_EPDC_SDCE5 IMX_GPIO_NR(3, 9) +#define MX6DL_ARM2_EPDC_PMIC_WAKE IMX_GPIO_NR(2, 31) +#define MX6DL_ARM2_EPDC_PMIC_INT IMX_GPIO_NR(2, 25) +#define MX6DL_ARM2_EPDC_VCOM IMX_GPIO_NR(3, 17) + +#define MX6_ARM2_IO_EXP_GPIO1(x) (MX6_ARM2_MAX7310_1_BASE_ADDR + (x)) +#define MX6_ARM2_IO_EXP_GPIO2(x) (MX6_ARM2_MAX7310_2_BASE_ADDR + (x)) + +#define MX6_ARM2_PCIE_PWR_EN MX6_ARM2_IO_EXP_GPIO1(2) +#define MX6_ARM2_PCIE_RESET MX6_ARM2_IO_EXP_GPIO2(2) + +#define MX6_ARM2_CAN2_STBY MX6_ARM2_IO_EXP_GPIO2(1) + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO +#define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) +#define IOMUX_OBSRV_MUX1_OFFSET 0x3c +#define OBSRV_MUX1_MASK 0x3f +#define OBSRV_MUX1_ENET_IRQ 0x9 +#endif + +#define BMCR_PDOWN 0x0800 /* PHY Powerdown */ + +void __init early_console_setup(unsigned long base, struct clk *clk); +static struct clk *sata_clk; +static int esai_record; +static int sgtl5000_en; +static int spdif_en; +static int flexcan_en; +static int disable_mipi_dsi; + +extern struct regulator *(*get_cpu_regulator)(void); +extern void (*put_cpu_regulator)(void); +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; +extern int epdc_enabled; +extern void mx6_cpu_regulator_init(void); +static int max17135_regulator_init(struct max17135 *max17135); + +enum sd_pad_mode { + SD_PAD_MODE_LOW_SPEED, + SD_PAD_MODE_MED_SPEED, + SD_PAD_MODE_HIGH_SPEED, +}; + +static int plt_sd_pad_change(unsigned int index, int clock) +{ + /* LOW speed is the default state of SD pads */ + static enum sd_pad_mode pad_mode = SD_PAD_MODE_LOW_SPEED; + + iomux_v3_cfg_t *sd_pads_200mhz = NULL; + iomux_v3_cfg_t *sd_pads_100mhz = NULL; + iomux_v3_cfg_t *sd_pads_50mhz = NULL; + + u32 sd_pads_200mhz_cnt; + u32 sd_pads_100mhz_cnt; + u32 sd_pads_50mhz_cnt; + + switch (index) { + case 2: + if (cpu_is_mx6q()) { + sd_pads_200mhz = mx6q_sd3_200mhz; + sd_pads_100mhz = mx6q_sd3_100mhz; + sd_pads_50mhz = mx6q_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6q_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6q_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6q_sd3_50mhz); + } else if (cpu_is_mx6dl()) { + sd_pads_200mhz = mx6dl_sd3_200mhz; + sd_pads_100mhz = mx6dl_sd3_100mhz; + sd_pads_50mhz = mx6dl_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6dl_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6dl_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6dl_sd3_50mhz); + } + break; + case 3: + if (cpu_is_mx6q()) { + sd_pads_200mhz = mx6q_sd4_200mhz; + sd_pads_100mhz = mx6q_sd4_100mhz; + sd_pads_50mhz = mx6q_sd4_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6q_sd4_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6q_sd4_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6q_sd4_50mhz); + } else if (cpu_is_mx6dl()) { + sd_pads_200mhz = mx6dl_sd4_200mhz; + sd_pads_100mhz = mx6dl_sd4_100mhz; + sd_pads_50mhz = mx6dl_sd4_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6dl_sd4_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6dl_sd4_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6dl_sd4_50mhz); + } + break; + default: + printk(KERN_ERR "no such SD host controller index %d\n", index); + return -EINVAL; + } + + if (clock > 100000000) { + if (pad_mode == SD_PAD_MODE_HIGH_SPEED) + return 0; + BUG_ON(!sd_pads_200mhz); + pad_mode = SD_PAD_MODE_HIGH_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_200mhz, + sd_pads_200mhz_cnt); + } else if (clock > 52000000) { + if (pad_mode == SD_PAD_MODE_MED_SPEED) + return 0; + BUG_ON(!sd_pads_100mhz); + pad_mode = SD_PAD_MODE_MED_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_100mhz, + sd_pads_100mhz_cnt); + } else { + if (pad_mode == SD_PAD_MODE_LOW_SPEED) + return 0; + BUG_ON(!sd_pads_50mhz); + pad_mode = SD_PAD_MODE_LOW_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_50mhz, + sd_pads_50mhz_cnt); + } +} + +static const struct esdhc_platform_data mx6_arm2_sd3_data __initconst = { + .cd_gpio = MX6_ARM2_SD3_CD, + .wp_gpio = MX6_ARM2_SD3_WP, + .support_18v = 1, + .support_8bit = 1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .platform_pad_change = plt_sd_pad_change, +}; + +/* No card detect signal for SD4 on ARM2 board*/ +static const struct esdhc_platform_data mx6_arm2_sd4_data __initconst = { + .always_present = 1, + .support_8bit = 1, + .keep_power_at_suspend = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +static int __init gpmi_nand_platform_init(void) +{ + iomux_v3_cfg_t *nand_pads = NULL; + u32 nand_pads_cnt; + + if (cpu_is_mx6q()) { + nand_pads = mx6q_gpmi_nand; + nand_pads_cnt = ARRAY_SIZE(mx6dl_gpmi_nand); + } else if (cpu_is_mx6dl()) { + nand_pads = mx6dl_gpmi_nand; + nand_pads_cnt = ARRAY_SIZE(mx6dl_gpmi_nand); + + } + BUG_ON(!nand_pads); + return mxc_iomux_v3_setup_multiple_pads(nand_pads, nand_pads_cnt); +} + +static struct gpmi_nand_platform_data +mx6_gpmi_nand_platform_data __initdata = { + .platform_init = gpmi_nand_platform_init, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 1, + .enable_bbt = 1, + .enable_ddr = 0, +}; + +static int __init board_support_onfi_nand(char *p) +{ + mx6_gpmi_nand_platform_data.enable_ddr = 1; + return 0; +} + +early_param("onfi_support", board_support_onfi_nand); + +static const struct anatop_thermal_platform_data + mx6_arm2_anatop_thermal_data __initconst = { + .name = "anatop_thermal", +}; + +static const struct imxuart_platform_data mx6_arm2_uart1_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS | IMXUART_USE_DCEDTE | IMXUART_SDMA, + .dma_req_rx = MX6Q_DMA_REQ_UART2_RX, + .dma_req_tx = MX6Q_DMA_REQ_UART2_TX, +}; + +static inline void mx6_arm2_init_uart(void) +{ + imx6q_add_imx_uart(3, NULL); + imx6q_add_imx_uart(1, &mx6_arm2_uart1_data); +} + +static int mx6_arm2_fec_phy_init(struct phy_device *phydev) +{ + unsigned short val; + + /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ + phy_write(phydev, 0xd, 0x7); + phy_write(phydev, 0xe, 0x8016); + phy_write(phydev, 0xd, 0x4007); + val = phy_read(phydev, 0xe); + + val &= 0xffe3; + val |= 0x18; + phy_write(phydev, 0xe, val); + + /* introduce tx clock delay */ + phy_write(phydev, 0x1d, 0x5); + val = phy_read(phydev, 0x1e); + val |= 0x0100; + phy_write(phydev, 0x1e, val); + + /*check phy power*/ + val = phy_read(phydev, 0x0); + if (val & BMCR_PDOWN) + phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); + return 0; +} + +static int mx6_arm2_fec_power_hibernate(struct phy_device *phydev) +{ + unsigned short val; + + /*set AR8031 debug reg 0xb to hibernate power*/ + phy_write(phydev, 0x1d, 0xb); + val = phy_read(phydev, 0x1e); + + val |= 0x8000; + phy_write(phydev, 0x1e, val); + + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6_arm2_fec_phy_init, + .power_hibernate = mx6_arm2_fec_power_hibernate, + .phy = PHY_INTERFACE_MODE_RGMII, +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + .gpio_irq = MX6_ENET_IRQ, +#endif +}; + +static int mx6_arm2_spi_cs[] = { + MX6_ARM2_ECSPI1_CS0, + MX6_ARM2_ECSPI1_CS1, +}; + +static const struct spi_imx_master mx6_arm2_spi_data __initconst = { + .chipselect = mx6_arm2_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6_arm2_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition m25p32_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00100000, + }, { + .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) + { + /* 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 int max7310_1_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + int max7310_gpio_value[] = { 0, 1, 0, 1, 0, 0, 0, 0 }; + + int n; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 1 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]); + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data max7310_platdata = { + .gpio_base = MX6_ARM2_MAX7310_1_BASE_ADDR, + .invert = 0, + .setup = max7310_1_setup, +}; + +static int max7310_u48_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + int max7310_gpio_value[] = { 1, 1, 1, 1, 0, 1, 0, 0 }; + + int n; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 U48 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]); + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data max7310_u48_platdata = { + .gpio_base = MX6_ARM2_MAX7310_2_BASE_ADDR, + .invert = 0, + .setup = max7310_u48_setup, +}; + +static void ddc_dvi_init(void) +{ + /* enable DVI I2C */ + gpio_set_value(MX6_ARM2_DISP0_I2C_EN, 1); + + /* DISP0 Detect */ + gpio_request(MX6_ARM2_DISP0_DET_INT, "disp0-detect"); + gpio_direction_input(MX6_ARM2_DISP0_DET_INT); +} + +static int ddc_dvi_update(void) +{ + /* DVI cable state */ + if (gpio_get_value(MX6_ARM2_DISP0_DET_INT) == 1) + return 1; + return 0; +} + +static struct fsl_mxc_dvi_platform_data sabr_ddc_dvi_data = { + .ipu_id = 0, + .disp_id = 0, + .init = ddc_dvi_init, + .update = ddc_dvi_update, +}; + +static void mx6_csi0_io_init(void) +{ + if (0 == sgtl5000_en) { + iomux_v3_cfg_t *sensor_pads = NULL; + u32 sensor_pads_cnt; + + if (cpu_is_mx6q()) { + sensor_pads = mx6q_arm2_csi0_sensor_pads; + sensor_pads_cnt = \ + ARRAY_SIZE(mx6q_arm2_csi0_sensor_pads); + } else if (cpu_is_mx6dl()) { + sensor_pads = mx6dl_arm2_csi0_sensor_pads; + sensor_pads_cnt = \ + ARRAY_SIZE(mx6dl_arm2_csi0_sensor_pads); + } + + BUG_ON(!sensor_pads); + mxc_iomux_v3_setup_multiple_pads(sensor_pads, sensor_pads_cnt); + } + /* Camera reset */ + gpio_request(MX6_ARM2_CSI0_RST, "cam-reset"); + gpio_direction_output(MX6_ARM2_CSI0_RST, 1); + + /* Camera power down */ + gpio_request(MX6_ARM2_CSI0_PWN, "cam-pwdn"); + gpio_direction_output(MX6_ARM2_CSI0_PWN, 1); + msleep(1); + gpio_set_value(MX6_ARM2_CSI0_PWN, 0); + + /* For MX6Q: + * GPR1 bit19 and bit20 meaning: + * Bit19: 0 - Enable mipi to IPU1 CSI0 + * virtual channel is fixed to 0 + * 1 - Enable parallel interface to IPU1 CSI0 + * Bit20: 0 - Enable mipi to IPU2 CSI1 + * virtual channel is fixed to 3 + * 1 - Enable parallel interface to IPU2 CSI1 + * IPU1 CSI1 directly connect to mipi csi2, + * virtual channel is fixed to 1 + * IPU2 CSI0 directly connect to mipi csi2, + * virtual channel is fixed to 2 + * + * For MX6DL: + * GPR1 bit 21 and GPR13 bit 0-5, RM has detail information + */ + if (cpu_is_mx6q()) + mxc_iomux_set_gpr_register(1, 19, 1, 1); + else if (cpu_is_mx6dl()) + mxc_iomux_set_gpr_register(13, 0, 3, 4); +} + +static struct fsl_mxc_camera_platform_data camera_data = { + .analog_regulator = "DA9052_LDO7", + .core_regulator = "DA9052_LDO9", + .mclk = 24000000, + .mclk_source = 0, + .csi = 0, + .io_init = mx6_csi0_io_init, +}; + +static void mx6_csi0_tvin_io_init(void) +{ + if (0 == sgtl5000_en) { + iomux_v3_cfg_t *tvin_pads = NULL; + u32 tvin_pads_cnt; + + if (cpu_is_mx6q()) { + tvin_pads = mx6q_arm2_csi0_tvin_pads; + tvin_pads_cnt = \ + ARRAY_SIZE(mx6q_arm2_csi0_tvin_pads); + } else if (cpu_is_mx6dl()) { + tvin_pads = mx6dl_arm2_csi0_tvin_pads; + tvin_pads_cnt = \ + ARRAY_SIZE(mx6dl_arm2_csi0_tvin_pads); + } + + BUG_ON(!tvin_pads); + mxc_iomux_v3_setup_multiple_pads(tvin_pads, tvin_pads_cnt); + } + /* Tvin reset */ + gpio_request(MX6_ARM2_CSI0_RST_TVIN, "tvin-reset"); + gpio_direction_output(MX6_ARM2_CSI0_RST_TVIN, 1); + + /* Tvin power down */ + gpio_request(MX6_ARM2_CSI0_PWN, "cam-pwdn"); + gpio_direction_output(MX6_ARM2_CSI0_PWN, 0); + msleep(1); + gpio_set_value(MX6_ARM2_CSI0_PWN, 1); + + if (cpu_is_mx6q()) + mxc_iomux_set_gpr_register(1, 19, 1, 1); + else if (cpu_is_mx6dl()) + mxc_iomux_set_gpr_register(13, 0, 3, 4); +} + +static struct fsl_mxc_tvin_platform_data tvin_data = { + .io_init = mx6_csi0_tvin_io_init, + .cvbs = false, +}; + +static void mx6_mipi_sensor_io_init(void) +{ + iomux_v3_cfg_t *mipi_sensor_pads = NULL; + u32 mipi_sensor_pads_cnt; + + if (cpu_is_mx6q()) { + mipi_sensor_pads = mx6q_arm2_mipi_sensor_pads; + mipi_sensor_pads_cnt = ARRAY_SIZE(mx6q_arm2_mipi_sensor_pads); + } else if (cpu_is_mx6dl()) { + mipi_sensor_pads = mx6dl_arm2_mipi_sensor_pads; + mipi_sensor_pads_cnt = ARRAY_SIZE(mx6dl_arm2_mipi_sensor_pads); + + } + BUG_ON(!mipi_sensor_pads); + mxc_iomux_v3_setup_multiple_pads(mipi_sensor_pads, + mipi_sensor_pads_cnt); + + /*for mx6dl, mipi virtual channel 1 connect to csi 1*/ + if (cpu_is_mx6dl()) + mxc_iomux_set_gpr_register(13, 3, 3, 1); +} + +static struct fsl_mxc_camera_platform_data ov5640_mipi_data = { + .mclk = 24000000, + .csi = 1, + .mclk_source = 0, + .io_init = mx6_mipi_sensor_io_init, +}; + +static struct mxc_audio_codec_platform_data cs42888_data = { + .rates = (SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_176400), +}; + +#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 = MX6DL_ARM2_EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = MX6DL_ARM2_EPDC_VCOM, + .gpio_pmic_wakeup = MX6DL_ARM2_EPDC_PMIC_WAKE, + .gpio_pmic_v3p3 = MX6DL_ARM2_EPDC_PWRCTRL0, + .gpio_pmic_intr = MX6DL_ARM2_EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int __init max17135_regulator_init(struct max17135 *max17135) +{ + struct max17135_platform_data *pdata = &max17135_pdata; + int i, ret; + + if (!epdc_enabled) { + printk(KERN_DEBUG + "max17135_regulator_init abort: EPDC not enabled\n"); + return 0; + } + + 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 int sii902x_get_pins(void) +{ + /* Sii902x HDMI controller */ + gpio_request(MX6_ARM2_DISP0_RESET, "disp0-reset"); + gpio_direction_output(MX6_ARM2_DISP0_RESET, 0); + gpio_request(MX6_ARM2_DISP0_DET_INT, "disp0-detect"); + gpio_direction_input(MX6_ARM2_DISP0_DET_INT); + return 1; +} + +static void sii902x_put_pins(void) +{ + gpio_free(MX6_ARM2_DISP0_RESET); + gpio_free(MX6_ARM2_DISP0_DET_INT); +} + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(MX6_ARM2_DISP0_RESET, 0); + msleep(10); + gpio_set_value(MX6_ARM2_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, + .get_pins = sii902x_get_pins, + .put_pins = sii902x_put_pins, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("cs42888", 0x48), + .platform_data = (void *)&cs42888_data, + }, { + I2C_BOARD_INFO("ov5640", 0x3c), + .platform_data = (void *)&camera_data, + }, { + I2C_BOARD_INFO("adv7180", 0x21), + .platform_data = (void *)&tvin_data, + }, +}; + +static struct imxi2c_platform_data mx6_arm2_i2c0_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_arm2_i2c1_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_arm2_i2c2_data = { + .bitrate = 400000, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0x48), + .platform_data = &max17135_pdata, + }, { + I2C_BOARD_INFO("max7310", 0x1F), + .platform_data = &max7310_platdata, + }, { + I2C_BOARD_INFO("max7310", 0x1B), + .platform_data = &max7310_u48_platdata, + }, { + I2C_BOARD_INFO("mxc_dvi", 0x50), + .platform_data = &sabr_ddc_dvi_data, + .irq = gpio_to_irq(MX6_ARM2_DISP0_DET_INT), + }, { + I2C_BOARD_INFO("egalax_ts", 0x4), + .irq = gpio_to_irq(MX6_ARM2_CAP_TCH_INT), + }, { + I2C_BOARD_INFO("sii902x", 0x39), + .platform_data = &sii902x_hdmi_data, + .irq = gpio_to_irq(MX6_ARM2_DISP0_DET_INT), + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("egalax_ts", 0x4), + .irq = gpio_to_irq(MX6_ARM2_CAP_TCH_INT), + }, { + I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50), + }, { + I2C_BOARD_INFO("ov5640_mipi", 0x3c), + .platform_data = (void *)&ov5640_mipi_data, + }, { + I2C_BOARD_INFO("sgtl5000", 0x0a), + }, +}; + +static int epdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for EPDC pins - used during power up/down */ + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_0, "epdc_d0"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_1, "epdc_d1"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_2, "epdc_d2"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_3, "epdc_d3"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_4, "epdc_d4"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_5, "epdc_d5"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_6, "epdc_d6"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDDO_7, "epdc_d7"); + ret |= gpio_request(MX6DL_ARM2_EPDC_GDCLK, "epdc_gdclk"); + ret |= gpio_request(MX6DL_ARM2_EPDC_GDSP, "epdc_gdsp"); + ret |= gpio_request(MX6DL_ARM2_EPDC_GDOE, "epdc_gdoe"); + ret |= gpio_request(MX6DL_ARM2_EPDC_GDRL, "epdc_gdrl"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDCLK, "epdc_sdclk"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDOE, "epdc_sdoe"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDLE, "epdc_sdle"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDSHR, "epdc_sdshr"); + ret |= gpio_request(MX6DL_ARM2_EPDC_BDR0, "epdc_bdr0"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDCE0, "epdc_sdce0"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDCE1, "epdc_sdce1"); + ret |= gpio_request(MX6DL_ARM2_EPDC_SDCE2, "epdc_sdce2"); + + return ret; +} + +static void epdc_put_pins(void) +{ + gpio_free(MX6DL_ARM2_EPDC_SDDO_0); + gpio_free(MX6DL_ARM2_EPDC_SDDO_1); + gpio_free(MX6DL_ARM2_EPDC_SDDO_2); + gpio_free(MX6DL_ARM2_EPDC_SDDO_3); + gpio_free(MX6DL_ARM2_EPDC_SDDO_4); + gpio_free(MX6DL_ARM2_EPDC_SDDO_5); + gpio_free(MX6DL_ARM2_EPDC_SDDO_6); + gpio_free(MX6DL_ARM2_EPDC_SDDO_7); + gpio_free(MX6DL_ARM2_EPDC_GDCLK); + gpio_free(MX6DL_ARM2_EPDC_GDSP); + gpio_free(MX6DL_ARM2_EPDC_GDOE); + gpio_free(MX6DL_ARM2_EPDC_GDRL); + gpio_free(MX6DL_ARM2_EPDC_SDCLK); + gpio_free(MX6DL_ARM2_EPDC_SDOE); + gpio_free(MX6DL_ARM2_EPDC_SDLE); + gpio_free(MX6DL_ARM2_EPDC_SDSHR); + gpio_free(MX6DL_ARM2_EPDC_BDR0); + gpio_free(MX6DL_ARM2_EPDC_SDCE0); + gpio_free(MX6DL_ARM2_EPDC_SDCE1); + gpio_free(MX6DL_ARM2_EPDC_SDCE2); +} + +static iomux_v3_cfg_t mx6dl_epdc_pads_enabled[] = { + MX6DL_PAD_EIM_A16__EPDC_SDDO_0, + MX6DL_PAD_EIM_DA10__EPDC_SDDO_1, + MX6DL_PAD_EIM_DA12__EPDC_SDDO_2, + MX6DL_PAD_EIM_DA11__EPDC_SDDO_3, + MX6DL_PAD_EIM_LBA__EPDC_SDDO_4, + MX6DL_PAD_EIM_EB2__EPDC_SDDO_5, + MX6DL_PAD_EIM_CS0__EPDC_SDDO_6, + MX6DL_PAD_EIM_RW__EPDC_SDDO_7, + MX6DL_PAD_EIM_CS1__EPDC_SDDO_8, + MX6DL_PAD_EIM_DA15__EPDC_SDDO_9, + MX6DL_PAD_EIM_D16__EPDC_SDDO_10, + MX6DL_PAD_EIM_D23__EPDC_SDDO_11, + MX6DL_PAD_EIM_D19__EPDC_SDDO_12, + MX6DL_PAD_EIM_DA13__EPDC_SDDO_13, + MX6DL_PAD_EIM_DA14__EPDC_SDDO_14, + MX6DL_PAD_EIM_A25__EPDC_SDDO_15, + MX6DL_PAD_EIM_A21__EPDC_GDCLK, + MX6DL_PAD_EIM_A22__EPDC_GDSP, + MX6DL_PAD_EIM_A23__EPDC_GDOE, + MX6DL_PAD_EIM_A24__EPDC_GDRL, + MX6DL_PAD_EIM_D31__EPDC_SDCLK, + MX6DL_PAD_EIM_D27__EPDC_SDOE, + MX6DL_PAD_EIM_DA1__EPDC_SDLE, + MX6DL_PAD_EIM_EB1__EPDC_SDSHR, + MX6DL_PAD_EIM_DA2__EPDC_BDR_0, + MX6DL_PAD_EIM_DA4__EPDC_SDCE_0, + MX6DL_PAD_EIM_DA5__EPDC_SDCE_1, + MX6DL_PAD_EIM_DA6__EPDC_SDCE_2, +}; + +static iomux_v3_cfg_t mx6dl_epdc_pads_disabled[] = { + MX6DL_PAD_EIM_A16__GPIO_2_22, + MX6DL_PAD_EIM_DA10__GPIO_3_10, + MX6DL_PAD_EIM_DA12__GPIO_3_12, + MX6DL_PAD_EIM_DA11__GPIO_3_11, + MX6DL_PAD_EIM_LBA__GPIO_2_27, + MX6DL_PAD_EIM_EB2__GPIO_2_30, + MX6DL_PAD_EIM_CS0__GPIO_2_23, + MX6DL_PAD_EIM_RW__GPIO_2_26, + MX6DL_PAD_EIM_CS1__GPIO_2_24, + MX6DL_PAD_EIM_DA15__GPIO_3_15, + MX6DL_PAD_EIM_D16__GPIO_3_16, + MX6DL_PAD_EIM_D23__GPIO_3_23, + MX6DL_PAD_EIM_D19__GPIO_3_19, + MX6DL_PAD_EIM_DA13__GPIO_3_13, + MX6DL_PAD_EIM_DA14__GPIO_3_14, + MX6DL_PAD_EIM_A25__GPIO_5_2, + MX6DL_PAD_EIM_A21__GPIO_2_17, + MX6DL_PAD_EIM_A22__GPIO_2_16, + MX6DL_PAD_EIM_A23__GPIO_6_6, + MX6DL_PAD_EIM_A24__GPIO_5_4, + MX6DL_PAD_EIM_D31__GPIO_3_31, + MX6DL_PAD_EIM_D27__GPIO_3_27, + MX6DL_PAD_EIM_DA1__GPIO_3_1, + MX6DL_PAD_EIM_EB1__GPIO_2_29, + MX6DL_PAD_EIM_DA2__GPIO_3_2, + MX6DL_PAD_EIM_DA4__GPIO_3_4, + MX6DL_PAD_EIM_DA5__GPIO_3_5, + MX6DL_PAD_EIM_DA6__GPIO_3_6, +}; +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6dl_epdc_pads_enabled, \ + ARRAY_SIZE(mx6dl_epdc_pads_enabled)); + + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_0); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_1); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_2); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_3); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_4); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_5); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_6); + gpio_direction_input(MX6DL_ARM2_EPDC_SDDO_7); + gpio_direction_input(MX6DL_ARM2_EPDC_GDCLK); + gpio_direction_input(MX6DL_ARM2_EPDC_GDSP); + gpio_direction_input(MX6DL_ARM2_EPDC_GDOE); + gpio_direction_input(MX6DL_ARM2_EPDC_GDRL); + gpio_direction_input(MX6DL_ARM2_EPDC_SDCLK); + gpio_direction_input(MX6DL_ARM2_EPDC_SDOE); + gpio_direction_input(MX6DL_ARM2_EPDC_SDLE); + gpio_direction_input(MX6DL_ARM2_EPDC_SDSHR); + gpio_direction_input(MX6DL_ARM2_EPDC_BDR0); + gpio_direction_input(MX6DL_ARM2_EPDC_SDCE0); + gpio_direction_input(MX6DL_ARM2_EPDC_SDCE1); + gpio_direction_input(MX6DL_ARM2_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(mx6dl_epdc_pads_disabled, \ + ARRAY_SIZE(mx6dl_epdc_pads_disabled)); + + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_0, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_1, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_2, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_3, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_4, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_5, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_6, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDDO_7, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_GDCLK, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_GDSP, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_GDOE, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_GDRL, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDCLK, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDOE, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDLE, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDSHR, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_BDR0, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDCE0, 0); + gpio_direction_output(MX6DL_ARM2_EPDC_SDCE1, 0); + gpio_direction_output(MX6DL_ARM2_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, + .refresh = 85, + .xres = 800, + .yres = 600, +}; +static struct fb_videomode e060scm_mode = { + .name = "E060SCM", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 26666667, + .left_margin = 8, + .right_margin = 100, + .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 */ + }, + { + &e060scm_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 419, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 5, /* 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 void imx6_arm2_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(MX6_ARM2_USB_OTG_PWR, 1); + else + gpio_set_value(MX6_ARM2_USB_OTG_PWR, 0); +} + +static void __init mx6_arm2_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + + /* disable external charger detect, + * or it will affect signal quality at dp. + */ + + ret = gpio_request(MX6_ARM2_USB_OTG_PWR, "usb-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_ARM2_USB_OTG_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_ARM2_USB_OTG_PWR, 0); + mxc_iomux_set_gpr_register(1, 13, 1, 1); + + mx6_set_otghost_vbus_func(imx6_arm2_usbotg_vbus); +#ifdef CONFIG_USB_EHCI_ARC_HSIC + mx6_usb_h2_init(); + mx6_usb_h3_init(); +#endif +} + +static struct viv_gpu_platform_data imx6_gpu_pdata __initdata = { + .reserved_mem_size = SZ_128M + SZ_64M, +}; + +/* HW Initialization, if return 0, initialization is successful. */ +static int mx6_arm2_sata_init(struct device *dev, void __iomem *addr) +{ + u32 tmpdata; + int ret = 0; + struct clk *clk; + + /* Enable SATA PWR CTRL_0 of MAX7310 */ + gpio_request(MX6_ARM2_MAX7310_1_BASE_ADDR, "SATA_PWR_EN"); + gpio_direction_output(MX6_ARM2_MAX7310_1_BASE_ADDR, 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; + } + + /* Set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write is 0x07FFFFFD, + * and the other one write for setting the mpll_clk_off_b + *.rx_eq_val_0(iomuxc_gpr13[26:24]), + *.los_lvl(iomuxc_gpr13[23:19]), + *.rx_dpll_mode_0(iomuxc_gpr13[18:16]), + *.sata_speed(iomuxc_gpr13[15]), + *.mpll_ss_en(iomuxc_gpr13[14]), + *.tx_atten_0(iomuxc_gpr13[13:11]), + *.tx_boost_0(iomuxc_gpr13[10:7]), + *.tx_lvl(iomuxc_gpr13[6:2]), + *.mpll_ck_off(iomuxc_gpr13[1]), + *.tx_edgerate_0(iomuxc_gpr13[0]), + */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13); + + /* enable SATA_PHY PLL */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13); + + /* Get the AHB clock rate, and configure the TIMER1MS reg later */ + clk = clk_get(NULL, "ahb"); + if (IS_ERR(clk)) { + dev_err(dev, "no ahb clock.\n"); + ret = PTR_ERR(clk); + goto release_sata_clk; + } + tmpdata = clk_get_rate(clk) / 1000; + clk_put(clk); + + ret = sata_init(addr, tmpdata); + if (ret == 0) + return ret; + +release_sata_clk: + clk_disable(sata_clk); +put_sata_clk: + clk_put(sata_clk); + /* Disable SATA PWR CTRL_0 of MAX7310 */ + gpio_request(MX6_ARM2_MAX7310_1_BASE_ADDR, "SATA_PWR_EN"); + gpio_direction_output(MX6_ARM2_MAX7310_1_BASE_ADDR, 0); + + return ret; +} + +static void mx6_arm2_sata_exit(struct device *dev) +{ + clk_disable(sata_clk); + clk_put(sata_clk); + + /* Disable SATA PWR CTRL_0 of MAX7310 */ + gpio_request(MX6_ARM2_MAX7310_1_BASE_ADDR, "SATA_PWR_EN"); + gpio_direction_output(MX6_ARM2_MAX7310_1_BASE_ADDR, 0); + +} + +static struct ahci_platform_data mx6_arm2_sata_data = { + .init = mx6_arm2_sata_init, + .exit = mx6_arm2_sata_exit, +}; + +static struct imx_asrc_platform_data imx_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static void mx6_arm2_reset_mipi_dsi(void) +{ + gpio_set_value(MX6_ARM2_DISP0_PWR, 1); + gpio_set_value(MX6_ARM2_DISP0_RESET, 1); + udelay(10); + gpio_set_value(MX6_ARM2_DISP0_RESET, 0); + udelay(50); + gpio_set_value(MX6_ARM2_DISP0_RESET, 1); + + /* + * it needs to delay 120ms minimum for reset complete + */ + msleep(120); +} + +static struct mipi_dsi_platform_data mipi_dsi_pdata = { + .ipu_id = 1, + .disp_id = 1, + .lcd_panel = "TRULY-WVGA", + .reset = mx6_arm2_reset_mipi_dsi, +}; + +static struct ipuv3_fb_platform_data sabr_fb_data[] = { + { /*fb0*/ + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + }, { + .disp_dev = "mipi_dsi", + .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .mode_str = "TRULY-WVGA", + .default_bpp = 24, + .int_clk = false, + }, { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + }, { + .disp_dev = "lcd", + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .default_bpp = 16, + .int_clk = false, + } +}; + +static void hdmi_init(int ipu_id, int disp_id) +{ + int hdmi_mux_setting; + int max_ipu_id = cpu_is_mx6q() ? 1 : 0; + + if ((ipu_id > max_ipu_id) || (ipu_id < 0)) { + pr_err("Invalid IPU select for HDMI: %d. Set to 0\n", ipu_id); + ipu_id = 0; + } + + if ((disp_id > 1) || (disp_id < 0)) { + pr_err("Invalid DI select for HDMI: %d. Set to 0\n", disp_id); + disp_id = 0; + } + + /* Configure the connection between IPU1/2 and HDMI */ + hdmi_mux_setting = 2 * ipu_id + disp_id; + + /* GPR3, bits 2-3 = HDMI_MUX_CTL */ + mxc_iomux_set_gpr_register(3, 2, 2, hdmi_mux_setting); + + /* Set HDMI event as SDMA event2 while Chip version later than TO1.2 */ + if (hdmi_SDMA_check()) + mxc_iomux_set_gpr_register(0, 0, 1, 1); +} + +/* On mx6x arm2 board i2c2 iomux with hdmi ddc, + * the pins default work at i2c2 function, + when hdcp enable, the pins should work at ddc function */ + +static void hdmi_enable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_arm2_hdmi_ddc_pads, + ARRAY_SIZE(mx6dl_arm2_hdmi_ddc_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_arm2_hdmi_ddc_pads, + ARRAY_SIZE(mx6q_arm2_hdmi_ddc_pads)); +} + +static void hdmi_disable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_arm2_i2c2_pads, + ARRAY_SIZE(mx6dl_arm2_i2c2_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_arm2_i2c2_pads, + ARRAY_SIZE(mx6q_arm2_i2c2_pads)); +} + +static struct fsl_mxc_hdmi_platform_data hdmi_data = { + .init = hdmi_init, + .enable_pins = hdmi_enable_ddc_pin, + .disable_pins = hdmi_disable_ddc_pin, +}; + +static struct fsl_mxc_hdmi_core_platform_data hdmi_core_data = { + .ipu_id = 0, + .disp_id = 0, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 1, + .disp_id = 0, + .ext_ref = 1, + .mode = LDB_SEP0, + .sec_ipu_id = 0, + .sec_disp_id = 1, +}; + +static struct imx_ipuv3_platform_data ipu_data[] = { + { + .rev = 4, + .csi_clk[0] = "clko_clk", + }, { + .rev = 4, + .csi_clk[0] = "clko_clk", + }, +}; + +static struct platform_pwm_backlight_data mx6_arm2_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct ion_platform_data imx_ion_data = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .name = "vpu_ion", + .size = SZ_64M, + }, + }, +}; + +static struct gpio mx6_flexcan_gpios[] = { + { MX6_ARM2_CAN1_EN, GPIOF_OUT_INIT_LOW, "flexcan1-en" }, + { MX6_ARM2_CAN1_STBY, GPIOF_OUT_INIT_LOW, "flexcan1-stby" }, + { MX6_ARM2_CAN2_EN, GPIOF_OUT_INIT_LOW, "flexcan2-en" }, +}; + +static void mx6_flexcan0_switch(int enable) +{ + if (enable) { + gpio_set_value(MX6_ARM2_CAN1_EN, 1); + gpio_set_value(MX6_ARM2_CAN1_STBY, 1); + } else { + gpio_set_value(MX6_ARM2_CAN1_EN, 0); + gpio_set_value(MX6_ARM2_CAN1_STBY, 0); + } +} + +static void mx6_flexcan1_switch(int enable) +{ + if (enable) { + gpio_set_value(MX6_ARM2_CAN2_EN, 1); + gpio_set_value_cansleep(MX6_ARM2_CAN2_STBY, 1); + } else { + gpio_set_value(MX6_ARM2_CAN2_EN, 0); + gpio_set_value_cansleep(MX6_ARM2_CAN2_STBY, 0); + } +} + +static const struct flexcan_platform_data + mx6_arm2_flexcan_pdata[] __initconst = { + { + .transceiver_switch = mx6_flexcan0_switch, + }, { + .transceiver_switch = mx6_flexcan1_switch, + } +}; + +static struct mipi_csi2_platform_data mipi_csi2_pdata = { + .ipu_id = 0, + .csi_id = 0, + .v_channel = 0, + .lanes = 2, + .dphy_clk = "mipi_pllref_clk", + .pixel_clk = "emi_clk", +}; + +static struct fsl_mxc_capture_platform_data capture_data[] = { + { + .csi = 0, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 0, + }, { + .csi = 1, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 1, + }, +}; + + +static void arm2_suspend_enter(void) +{ + /* suspend preparation */ +} + +static void arm2_suspend_exit(void) +{ + /* resmue resore */ +} +static const struct pm_platform_data mx6_arm2_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = arm2_suspend_enter, + .suspend_exit = arm2_suspend_exit, +}; + +static const struct asrc_p2p_params esai_p2p = { + .p2p_rate = 44100, + .p2p_width = ASRC_WIDTH_24_BIT, +}; + +static struct mxc_audio_platform_data sab_audio_data = { + .sysclk = 16934400, + .priv = (void *)&esai_p2p, +}; + +static struct platform_device sab_audio_device = { + .name = "imx-cs42888", +}; + +static struct imx_esai_platform_data sab_esai_pdata = { + .flags = IMX_ESAI_NET, +}; + +static struct regulator_consumer_supply arm2_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; + +static struct regulator_init_data arm2_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(arm2_vmmc_consumers), + .consumer_supplies = arm2_vmmc_consumers, +}; + +static struct fixed_voltage_config arm2_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &arm2_vmmc_init, +}; + +static struct platform_device arm2_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &arm2_vmmc_reg_config, + }, +}; + +#ifdef CONFIG_SND_SOC_CS42888 + +static struct regulator_consumer_supply cs42888_arm2_consumer_va = { + .supply = "VA", + .dev_name = "0-0048", +}; + +static struct regulator_consumer_supply cs42888_arm2_consumer_vd = { + .supply = "VD", + .dev_name = "0-0048", +}; + +static struct regulator_consumer_supply cs42888_arm2_consumer_vls = { + .supply = "VLS", + .dev_name = "0-0048", +}; + +static struct regulator_consumer_supply cs42888_arm2_consumer_vlc = { + .supply = "VLC", + .dev_name = "0-0048", +}; + +static struct regulator_init_data cs42888_arm2_va_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_arm2_consumer_va, +}; + +static struct regulator_init_data cs42888_arm2_vd_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_arm2_consumer_vd, +}; + +static struct regulator_init_data cs42888_arm2_vls_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_arm2_consumer_vls, +}; + +static struct regulator_init_data cs42888_arm2_vlc_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_arm2_consumer_vlc, +}; + +static struct fixed_voltage_config cs42888_arm2_va_reg_config = { + .supply_name = "VA", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_arm2_va_reg_initdata, +}; + +static struct fixed_voltage_config cs42888_arm2_vd_reg_config = { + .supply_name = "VD", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_arm2_vd_reg_initdata, +}; + +static struct fixed_voltage_config cs42888_arm2_vls_reg_config = { + .supply_name = "VLS", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_arm2_vls_reg_initdata, +}; + +static struct fixed_voltage_config cs42888_arm2_vlc_reg_config = { + .supply_name = "VLC", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_arm2_vlc_reg_initdata, +}; + +static struct platform_device cs42888_arm2_va_reg_devices = { + .name = "reg-fixed-voltage", + .id = 3, + .dev = { + .platform_data = &cs42888_arm2_va_reg_config, + }, +}; + +static struct platform_device cs42888_arm2_vd_reg_devices = { + .name = "reg-fixed-voltage", + .id = 4, + .dev = { + .platform_data = &cs42888_arm2_vd_reg_config, + }, +}; + +static struct platform_device cs42888_arm2_vls_reg_devices = { + .name = "reg-fixed-voltage", + .id = 5, + .dev = { + .platform_data = &cs42888_arm2_vls_reg_config, + }, +}; + +static struct platform_device cs42888_arm2_vlc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 6, + .dev = { + .platform_data = &cs42888_arm2_vlc_reg_config, + }, +}; + +#endif /* CONFIG_SND_SOC_CS42888 */ + +#ifdef CONFIG_SND_SOC_SGTL5000 + +static struct regulator_consumer_supply sgtl5000_arm2_consumer_vdda = { + .supply = "VDDA", + .dev_name = "1-000a", +}; + +static struct regulator_consumer_supply sgtl5000_arm2_consumer_vddio = { + .supply = "VDDIO", + .dev_name = "1-000a", +}; + +static struct regulator_consumer_supply sgtl5000_arm2_consumer_vddd = { + .supply = "VDDD", + .dev_name = "1-000a", +}; + +static struct regulator_init_data sgtl5000_arm2_vdda_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &sgtl5000_arm2_consumer_vdda, +}; + +static struct regulator_init_data sgtl5000_arm2_vddio_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &sgtl5000_arm2_consumer_vddio, +}; + +static struct regulator_init_data sgtl5000_arm2_vddd_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &sgtl5000_arm2_consumer_vddd, +}; + +static struct fixed_voltage_config sgtl5000_arm2_vdda_reg_config = { + .supply_name = "VDDA", + .microvolts = 1800000, + .gpio = -1, + .init_data = &sgtl5000_arm2_vdda_reg_initdata, +}; + +static struct fixed_voltage_config sgtl5000_arm2_vddio_reg_config = { + .supply_name = "VDDIO", + .microvolts = 3300000, + .gpio = -1, + .init_data = &sgtl5000_arm2_vddio_reg_initdata, +}; + +static struct fixed_voltage_config sgtl5000_arm2_vddd_reg_config = { + .supply_name = "VDDD", + .microvolts = 0, + .gpio = -1, + .init_data = &sgtl5000_arm2_vddd_reg_initdata, +}; + +static struct platform_device sgtl5000_arm2_vdda_reg_devices = { + .name = "reg-fixed-voltage", + .id = 7, + .dev = { + .platform_data = &sgtl5000_arm2_vdda_reg_config, + }, +}; + +static struct platform_device sgtl5000_arm2_vddio_reg_devices = { + .name = "reg-fixed-voltage", + .id = 8, + .dev = { + .platform_data = &sgtl5000_arm2_vddio_reg_config, + }, +}; + +static struct platform_device sgtl5000_arm2_vddd_reg_devices = { + .name = "reg-fixed-voltage", + .id = 9, + .dev = { + .platform_data = &sgtl5000_arm2_vddd_reg_config, + }, +}; + +#endif /* CONFIG_SND_SOC_SGTL5000 */ + +static struct mxc_audio_platform_data mx6_arm2_audio_data; + +static int mx6_arm2_sgtl5000_init(void) +{ + + mx6_arm2_audio_data.sysclk = 12000000; + + return 0; +} + +static struct imx_ssi_platform_data mx6_arm2_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct mxc_audio_platform_data mx6_arm2_audio_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .init = mx6_arm2_sgtl5000_init, + .hp_gpio = -1, +}; + +static struct platform_device mx6_arm2_audio_device = { + .name = "imx-sgtl5000", +}; + +static int __init mx6_arm2_init_audio(void) +{ + struct clk *pll3_pfd, *esai_clk; + mxc_register_device(&sab_audio_device, &sab_audio_data); + imx6q_add_imx_esai(0, &sab_esai_pdata); + + esai_clk = clk_get(NULL, "esai_clk"); + if (IS_ERR(esai_clk)) + return PTR_ERR(esai_clk); + + pll3_pfd = clk_get(NULL, "pll3_pfd_508M"); + if (IS_ERR(pll3_pfd)) + return PTR_ERR(pll3_pfd); + + clk_set_parent(esai_clk, pll3_pfd); + clk_set_rate(esai_clk, 101647058); + +#ifdef CONFIG_SND_SOC_CS42888 + platform_device_register(&cs42888_arm2_va_reg_devices); + platform_device_register(&cs42888_arm2_vd_reg_devices); + platform_device_register(&cs42888_arm2_vls_reg_devices); + platform_device_register(&cs42888_arm2_vlc_reg_devices); +#endif + + if (sgtl5000_en) { + /* SSI audio init part */ + mxc_register_device(&mx6_arm2_audio_device, + &mx6_arm2_audio_data); + imx6q_add_imx_ssi(1, &mx6_arm2_ssi_pdata); + + /* + * AUDMUX3 and CSI0_Camera use the same pin + * MX6x_PAD_CSI0_DAT5 + */ + if (cpu_is_mx6q()) { + mxc_iomux_v3_setup_multiple_pads(mx6q_arm2_audmux_pads, + ARRAY_SIZE(mx6q_arm2_audmux_pads)); + } else if (cpu_is_mx6dl()) { + mxc_iomux_v3_setup_multiple_pads(mx6dl_arm2_audmux_pads, + ARRAY_SIZE(mx6dl_arm2_audmux_pads)); + } + +#ifdef CONFIG_SND_SOC_SGTL5000 + platform_device_register(&sgtl5000_arm2_vdda_reg_devices); + platform_device_register(&sgtl5000_arm2_vddio_reg_devices); + platform_device_register(&sgtl5000_arm2_vddd_reg_devices); +#endif + } + + return 0; +} + +static int __init early_use_esai_record(char *p) +{ + esai_record = 1; + return 0; +} + +early_param("esai_record", early_use_esai_record); + +static struct mxc_mlb_platform_data mx6_arm2_mlb150_data = { + .reg_nvcc = NULL, + .mlb_clk = "mlb150_clk", + .mlb_pll_clk = "pll6", +}; + +static struct mxc_dvfs_platform_data arm2_dvfscore_data = { + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 void __init mx6_arm2_fixup(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static int __init early_enable_sgtl5000(char *p) +{ + sgtl5000_en = 1; + return 0; +} + +early_param("sgtl5000", early_enable_sgtl5000); + +static int __init early_enable_spdif(char *p) +{ + spdif_en = 1; + return 0; +} + +early_param("spdif", early_enable_spdif); + +static int __init early_enable_can(char *p) +{ + flexcan_en = 1; + return 0; +} + +early_param("flexcan", early_enable_can); + +static int spdif_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long rate_actual; + rate_actual = clk_round_rate(clk, rate); + clk_set_rate(clk, rate_actual); + return 0; +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, /* enable tx */ + .spdif_rx = 1, /* enable rx */ + /* + * spdif0_clk will be 454.7MHz divided by ccm dividers. + * + * 44.1KHz: 454.7MHz / 7 (ccm) / 23 (spdif) = 44,128 Hz ~ 0.06% error + * 48KHz: 454.7MHz / 4 (ccm) / 37 (spdif) = 48,004 Hz ~ 0.01% error + * 32KHz: 454.7MHz / 6 (ccm) / 37 (spdif) = 32,003 Hz ~ 0.01% error + */ + .spdif_clk_44100 = 1, /* tx clk from spdif0_clk_root */ + .spdif_clk_48000 = 1, /* tx clk from spdif0_clk_root */ + .spdif_div_44100 = 23, + .spdif_div_48000 = 37, + .spdif_div_32000 = 37, + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk_set_rate = spdif_clk_set_rate, + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static const struct imx_pcie_platform_data mx6_arm2_pcie_data __initconst = { + .pcie_pwr_en = MX6_ARM2_PCIE_PWR_EN, + .pcie_rst = MX6_ARM2_PCIE_RESET, + .pcie_wake_up = -EINVAL, + .pcie_dis = -EINVAL, +}; + +static int __init early_disable_mipi_dsi(char *p) +{ + /*enable on board HDMI*/ + /*mulplex pin with mipi disp0_reset we should disable mipi reset*/ + disable_mipi_dsi = 1; + return 0; +} + +early_param("disable_mipi_dsi", early_disable_mipi_dsi); + +/*! + * Board specific initialization. + */ +static void __init mx6_arm2_init(void) +{ + int i; + int ret; + + iomux_v3_cfg_t *common_pads = NULL; + iomux_v3_cfg_t *esai_rec_pads = NULL; + iomux_v3_cfg_t *spdif_pads = NULL; + iomux_v3_cfg_t *flexcan_pads = NULL; + iomux_v3_cfg_t *i2c3_pads = NULL; + iomux_v3_cfg_t *epdc_pads = NULL; + + int common_pads_cnt; + int esai_rec_pads_cnt; + int spdif_pads_cnt; + int flexcan_pads_cnt; + int i2c3_pads_cnt; + int epdc_pads_cnt; + + + /* + * common pads: pads are non-shared with others on this board + * feature_pds: pads are shared with others on this board + */ + + if (cpu_is_mx6q()) { + common_pads = mx6q_arm2_pads; + esai_rec_pads = mx6q_arm2_esai_record_pads; + spdif_pads = mx6q_arm2_spdif_pads; + flexcan_pads = mx6q_arm2_can_pads; + i2c3_pads = mx6q_arm2_i2c3_pads; + + common_pads_cnt = ARRAY_SIZE(mx6q_arm2_pads); + esai_rec_pads_cnt = ARRAY_SIZE(mx6q_arm2_esai_record_pads); + spdif_pads_cnt = ARRAY_SIZE(mx6q_arm2_spdif_pads); + flexcan_pads_cnt = ARRAY_SIZE(mx6q_arm2_can_pads); + i2c3_pads_cnt = ARRAY_SIZE(mx6q_arm2_i2c3_pads); + } else if (cpu_is_mx6dl()) { + common_pads = mx6dl_arm2_pads; + esai_rec_pads = mx6dl_arm2_esai_record_pads; + spdif_pads = mx6dl_arm2_spdif_pads; + flexcan_pads = mx6dl_arm2_can_pads; + i2c3_pads = mx6dl_arm2_i2c3_pads; + epdc_pads = mx6dl_arm2_epdc_pads; + + common_pads_cnt = ARRAY_SIZE(mx6dl_arm2_pads); + esai_rec_pads_cnt = ARRAY_SIZE(mx6dl_arm2_esai_record_pads); + spdif_pads_cnt = ARRAY_SIZE(mx6dl_arm2_spdif_pads); + flexcan_pads_cnt = ARRAY_SIZE(mx6dl_arm2_can_pads); + i2c3_pads_cnt = ARRAY_SIZE(mx6dl_arm2_i2c3_pads); + epdc_pads_cnt = ARRAY_SIZE(mx6dl_arm2_epdc_pads); + } + + BUG_ON(!common_pads); + mxc_iomux_v3_setup_multiple_pads(common_pads, common_pads_cnt); + + if (esai_record) { + BUG_ON(!esai_rec_pads); + mxc_iomux_v3_setup_multiple_pads(esai_rec_pads, + esai_rec_pads_cnt); + } + + /* + * IEEE-1588 ts_clk, S/PDIF in and i2c3 are mutually exclusive + * because all of them use GPIO_16. + * S/PDIF out and can1 stby are mutually exclusive because both + * use GPIO_17. + */ +#ifndef CONFIG_FEC_1588 + if (spdif_en) { + BUG_ON(!spdif_pads); + mxc_iomux_v3_setup_multiple_pads(spdif_pads, spdif_pads_cnt); + } else { + BUG_ON(!i2c3_pads); + mxc_iomux_v3_setup_multiple_pads(i2c3_pads, i2c3_pads_cnt); + } +#else + /* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock + * For MX6 GPR1 bit21 meaning: + * Bit21: 0 - GPIO_16 pad output + * 1 - GPIO_16 pad input + */ + mxc_iomux_set_gpr_register(1, 21, 1, 1); +#endif + + if (!spdif_en && flexcan_en) { + BUG_ON(!flexcan_pads); + mxc_iomux_v3_setup_multiple_pads(flexcan_pads, + flexcan_pads_cnt); + } + + /* + * the following is the common devices support on the shared ARM2 boards + * Since i.MX6DQ/DL share the same memory/Register layout, we don't + * need to diff the i.MX6DQ or i.MX6DL here. We can simply use the + * mx6q_add_features() for the shared devices. For which only exist + * on each indivual SOC, we can use cpu_is_mx6q/6dl() to diff it. + */ + + gp_reg_id = arm2_dvfscore_data.reg_id; + soc_reg_id = arm2_dvfscore_data.soc_id; + pu_reg_id = arm2_dvfscore_data.pu_id; + mx6_arm2_init_uart(); + + + imx6q_add_mipi_csi2(&mipi_csi2_pdata); + imx6q_add_mxc_hdmi_core(&hdmi_core_data); + + imx6q_add_ipuv3(0, &ipu_data[0]); + if (cpu_is_mx6q()) + imx6q_add_ipuv3(1, &ipu_data[1]); + + if (cpu_is_mx6dl()) { + mipi_dsi_pdata.ipu_id = 0; + mipi_dsi_pdata.disp_id = 1; + ldb_data.ipu_id = 0; + ldb_data.disp_id = 0; + for (i = 0; i < ARRAY_SIZE(sabr_fb_data) / 2; i++) + imx6q_add_ipuv3fb(i, &sabr_fb_data[i]); + } else { + for (i = 0; i < ARRAY_SIZE(sabr_fb_data); i++) + imx6q_add_ipuv3fb(i, &sabr_fb_data[i]); + } + + if (!disable_mipi_dsi) + imx6q_add_mipi_dsi(&mipi_dsi_pdata); + imx6q_add_vdoa(); + imx6q_add_lcdif(&lcdif_data); + imx6q_add_ldb(&ldb_data); + imx6q_add_v4l2_output(0); + imx6q_add_v4l2_capture(0, &capture_data[0]); + imx6q_add_v4l2_capture(1, &capture_data[1]); + + imx6q_add_imx_snvs_rtc(); + + imx6q_add_imx_caam(); + + imx6q_add_imx_i2c(0, &mx6_arm2_i2c0_data); + imx6q_add_imx_i2c(1, &mx6_arm2_i2c1_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)); + if (!spdif_en) { + if (disable_mipi_dsi) + mx6_arm2_i2c2_data.bitrate = 100000; + imx6q_add_imx_i2c(2, &mx6_arm2_i2c2_data); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + } + + /* SPI */ + imx6q_add_ecspi(0, &mx6_arm2_spi_data); + spi_device_init(); + + imx6q_add_mxc_hdmi(&hdmi_data); + + imx6q_add_anatop_thermal_imx(1, &mx6_arm2_anatop_thermal_data); + + if (!esai_record) { + imx6_init_fec(fec_data); +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); +#endif + } + + imx6q_add_pm_imx(0, &mx6_arm2_pm_data); + imx6q_add_sdhci_usdhc_imx(3, &mx6_arm2_sd4_data); + imx6q_add_sdhci_usdhc_imx(2, &mx6_arm2_sd3_data); + imx_add_viv_gpu(&imx6_gpu_data, &imx6_gpu_pdata); + if (cpu_is_mx6q()) + imx6q_add_ahci(0, &mx6_arm2_sata_data); + imx6q_add_vpu(); + mx6_arm2_init_usb(); + mx6_arm2_init_audio(); + platform_device_register(&arm2_vmmc_reg_devices); + mx6_cpu_regulator_init(); + + imx_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + imx_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + imx6q_add_asrc(&imx_asrc_data); + + /* DISP0 Reset - Assert for i2c disabled mode */ + gpio_request(MX6_ARM2_DISP0_RESET, "disp0-reset"); + gpio_direction_output(MX6_ARM2_DISP0_RESET, 0); + + /* DISP0 I2C enable */ + if (!disable_mipi_dsi) { + gpio_request(MX6_ARM2_DISP0_I2C_EN, "disp0-i2c"); + gpio_direction_output(MX6_ARM2_DISP0_I2C_EN, 0); + } + gpio_request(MX6_ARM2_DISP0_PWR, "disp0-pwr"); + gpio_direction_output(MX6_ARM2_DISP0_PWR, 1); + + gpio_request(MX6_ARM2_LDB_BACKLIGHT, "ldb-backlight"); + gpio_direction_output(MX6_ARM2_LDB_BACKLIGHT, 1); + imx6q_add_otp(); + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + imx6q_add_dma(); + imx6q_add_gpmi(&mx6_gpmi_nand_platform_data); + + imx6q_add_dvfs_core(&arm2_dvfscore_data); + + imx6q_add_ion(0, &imx_ion_data, + sizeof(imx_ion_data) + sizeof(struct ion_platform_heap)); + + imx6q_add_mxc_pwm(0); + imx6q_add_mxc_pwm_backlight(0, &mx6_arm2_pwm_backlight_data); + + if (spdif_en) { + mxc_spdif_data.spdif_core_clk = clk_get_sys("mxc_spdif.0", NULL); + clk_put(mxc_spdif_data.spdif_core_clk); + imx6q_add_spdif(&mxc_spdif_data); + imx6q_add_spdif_dai(); + imx6q_add_spdif_audio_device(); + } else if (flexcan_en) { + ret = gpio_request_array(mx6_flexcan_gpios, + ARRAY_SIZE(mx6_flexcan_gpios)); + if (ret) { + pr_err("failed to request flexcan-gpios: %d\n", ret); + } else { + imx6q_add_flexcan0(&mx6_arm2_flexcan_pdata[0]); + imx6q_add_flexcan1(&mx6_arm2_flexcan_pdata[1]); + } + } + + imx6q_add_hdmi_soc(); + imx6q_add_hdmi_soc_dai(); + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); + imx6q_add_mlb150(&mx6_arm2_mlb150_data); + + if (cpu_is_mx6dl() && epdc_enabled) { + BUG_ON(!epdc_pads); + mxc_iomux_v3_setup_multiple_pads(epdc_pads, epdc_pads_cnt); + imx6dl_add_imx_pxp(); + imx6dl_add_imx_pxp_client(); + mxc_register_device(&max17135_sensor_device, NULL); + imx6dl_add_imx_epdc(&epdc_data); + } + /* Add PCIe RC interface support */ + imx6q_add_pcie(&mx6_arm2_pcie_data); + imx6q_add_busfreq(); +} + +extern void __iomem *twd_base; +static void __init mx6_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART4_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx6_timer_init, +}; + +static void __init mx6_arm2_reserve(void) +{ + phys_addr_t phys; +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + if (imx6_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base( + imx6_gpu_pdata.reserved_mem_size, SZ_4K, SZ_2G); + memblock_remove(phys, imx6_gpu_pdata.reserved_mem_size); + imx6_gpu_pdata.reserved_mem_base = phys; + } +#endif + +#if defined(CONFIG_ION) + if (imx_ion_data.heaps[0].size) { + phys = memblock_alloc(imx_ion_data.heaps[0].size, SZ_4K); + memblock_free(phys, imx_ion_data.heaps[0].size); + memblock_remove(phys, imx_ion_data.heaps[0].size); + imx_ion_data.heaps[0].base = phys; + } +#endif +} + +MACHINE_START(MX6Q_ARM2, "Freescale i.MX 6Quad/Solo/DualLite Armadillo2 Board") + .boot_params = MX6_PHYS_OFFSET + 0x100, + .fixup = mx6_arm2_fixup, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_arm2_init, + .timer = &mxc_timer, + .reserve = mx6_arm2_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6q_arm2.h b/arch/arm/mach-mx6/board-mx6q_arm2.h new file mode 100644 index 00000000..2a6a2052 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_arm2.h @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2012, 2013 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/iomux-mx6q.h> + +static iomux_v3_cfg_t mx6q_arm2_pads[] = { + + /* UART4 for debug */ + MX6Q_PAD_KEY_COL0__UART4_TXD, + MX6Q_PAD_KEY_ROW0__UART4_RXD, + /* USB HSIC ports use the same pin with ENET */ +#ifdef CONFIG_USB_EHCI_ARC_HSIC + /* USB H2 strobe/data pin */ + MX6Q_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE, + MX6Q_PAD_RGMII_TXC__USBOH3_H2_DATA, + + /* USB H3 strobe/data pin */ + MX6Q_PAD_RGMII_RXC__USBOH3_H3_STROBE, + MX6Q_PAD_RGMII_RX_CTL__USBOH3_H3_DATA, + /* ENET */ +#else + MX6Q_PAD_KEY_COL1__ENET_MDIO, + MX6Q_PAD_KEY_COL2__ENET_MDC, + MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6Q_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6Q_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, +#ifdef CONFIG_FEC_1588 + MX6Q_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, +#endif +#endif + /* MCLK for csi0 */ + MX6Q_PAD_GPIO_0__CCM_CLKO, + MX6Q_PAD_GPIO_3__CCM_CLKO2, + + /* SD1 */ + MX6Q_PAD_SD1_CLK__USDHC1_CLK, + MX6Q_PAD_SD1_CMD__USDHC1_CMD, + MX6Q_PAD_SD1_DAT0__USDHC1_DAT0, + MX6Q_PAD_SD1_DAT1__USDHC1_DAT1, + MX6Q_PAD_SD1_DAT2__USDHC1_DAT2, + MX6Q_PAD_SD1_DAT3__USDHC1_DAT3, + /* SD2 */ + MX6Q_PAD_SD2_CLK__USDHC2_CLK, + MX6Q_PAD_SD2_CMD__USDHC2_CMD, + MX6Q_PAD_SD2_DAT0__USDHC2_DAT0, + MX6Q_PAD_SD2_DAT1__USDHC2_DAT1, + MX6Q_PAD_SD2_DAT2__USDHC2_DAT2, + MX6Q_PAD_SD2_DAT3__USDHC2_DAT3, + /* SD3 */ + MX6Q_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6Q_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6Q_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6Q_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6Q_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6Q_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6Q_PAD_SD3_RST__USDHC3_RST, + /* SD3 VSelect */ + MX6Q_PAD_GPIO_18__USDHC3_VSELECT, + /* SD3_CD and SD3_WP */ + MX6Q_PAD_NANDF_CS0__GPIO_6_11, + MX6Q_PAD_NANDF_CS1__GPIO_6_14, + /* SD4 */ + MX6Q_PAD_SD4_CLK__USDHC4_CLK_50MHZ, + MX6Q_PAD_SD4_CMD__USDHC4_CMD_50MHZ, + MX6Q_PAD_SD4_DAT0__USDHC4_DAT0_50MHZ, + MX6Q_PAD_SD4_DAT1__USDHC4_DAT1_50MHZ, + MX6Q_PAD_SD4_DAT2__USDHC4_DAT2_50MHZ, + MX6Q_PAD_SD4_DAT3__USDHC4_DAT3_50MHZ, + MX6Q_PAD_SD4_DAT4__USDHC4_DAT4_50MHZ, + MX6Q_PAD_SD4_DAT5__USDHC4_DAT5_50MHZ, + MX6Q_PAD_SD4_DAT6__USDHC4_DAT6_50MHZ, + MX6Q_PAD_SD4_DAT7__USDHC4_DAT7_50MHZ, + MX6Q_PAD_NANDF_ALE__USDHC4_RST, + /* eCSPI1 */ + MX6Q_PAD_EIM_EB2__ECSPI1_SS0, + MX6Q_PAD_EIM_D16__ECSPI1_SCLK, + MX6Q_PAD_EIM_D17__ECSPI1_MISO, + MX6Q_PAD_EIM_D18__ECSPI1_MOSI, + MX6Q_PAD_EIM_D19__ECSPI1_SS1, + MX6Q_PAD_EIM_EB2__GPIO_2_30, /*SS0*/ + MX6Q_PAD_EIM_D19__GPIO_3_19, /*SS1*/ + + /* ESAI */ + MX6Q_PAD_ENET_RXD0__ESAI1_HCKT, + MX6Q_PAD_ENET_CRS_DV__ESAI1_SCKT, + MX6Q_PAD_ENET_RXD1__ESAI1_FST, + MX6Q_PAD_ENET_TX_EN__ESAI1_TX3_RX2, + MX6Q_PAD_ENET_TXD1__ESAI1_TX2_RX3, + MX6Q_PAD_ENET_TXD0__ESAI1_TX4_RX1, + MX6Q_PAD_ENET_MDC__ESAI1_TX5_RX0, + MX6Q_PAD_NANDF_CS2__ESAI1_TX0, + MX6Q_PAD_NANDF_CS3__ESAI1_TX1, + + /* I2C1 */ + MX6Q_PAD_CSI0_DAT8__I2C1_SDA, + MX6Q_PAD_CSI0_DAT9__I2C1_SCL, + + /* I2C2 */ + MX6Q_PAD_KEY_COL3__I2C2_SCL, + MX6Q_PAD_KEY_ROW3__I2C2_SDA, + + /* DISPLAY */ + MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15, + MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2, + MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3, + MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20, + MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22, + MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23, + + MX6Q_PAD_EIM_D24__GPIO_3_24, + + /* UART2 */ + MX6Q_PAD_EIM_D26__UART2_RXD, + MX6Q_PAD_EIM_D27__UART2_TXD, + MX6Q_PAD_EIM_D28__UART2_RTS, + MX6Q_PAD_EIM_D29__UART2_CTS, + + /* PWM1 */ + MX6Q_PAD_GPIO_9__PWM1_PWMO, + + /* DISP0 DET */ + MX6Q_PAD_EIM_D31__GPIO_3_31, + + /* DISP0 RESET */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, + + /* HDMI */ + MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE, + MX6Q_PAD_SD1_DAT1__HDMI_TX_OPHYDTB_0, + MX6Q_PAD_SD1_DAT0__HDMI_TX_OPHYDTB_1, + + /* USBOTG ID pin */ + MX6Q_PAD_GPIO_1__USBOTG_ID, + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, +#else + /* MLB150 */ + MX6Q_PAD_GPIO_3__MLB_MLBCLK, + MX6Q_PAD_GPIO_6__MLB_MLBSIG, + MX6Q_PAD_GPIO_2__MLB_MLBDAT, +#endif +}; + +static iomux_v3_cfg_t mx6q_arm2_i2c3_pads[] = { + MX6Q_PAD_GPIO_5__I2C3_SCL, + MX6Q_PAD_GPIO_16__I2C3_SDA, +}; + +static iomux_v3_cfg_t mx6q_arm2_spdif_pads[] = { + /* SPDIF */ + MX6Q_PAD_GPIO_16__SPDIF_IN1, + MX6Q_PAD_GPIO_17__SPDIF_OUT1, +}; + +static iomux_v3_cfg_t mx6q_arm2_can_pads[] = { + /* CAN1 */ + MX6Q_PAD_GPIO_7__CAN1_TXCAN, + MX6Q_PAD_KEY_ROW2__CAN1_RXCAN, + MX6Q_PAD_GPIO_17__GPIO_7_12, /* CAN1 STBY */ + MX6Q_PAD_GPIO_18__GPIO_7_13, /* CAN1 EN */ + + /* CAN2 */ + MX6Q_PAD_KEY_COL4__CAN2_TXCAN, + MX6Q_PAD_KEY_ROW4__CAN2_RXCAN, + MX6Q_PAD_CSI0_DAT6__GPIO_5_24, /* CAN2 EN */ +}; + +static iomux_v3_cfg_t mx6q_arm2_esai_record_pads[] = { + MX6Q_PAD_ENET_RX_ER__ESAI1_HCKR, + MX6Q_PAD_ENET_MDIO__ESAI1_SCKR, + MX6Q_PAD_ENET_REF_CLK__ESAI1_FSR, +}; + +static iomux_v3_cfg_t mx6q_arm2_csi0_sensor_pads[] = { + MX6Q_PAD_GPIO_0__CCM_CLKO, + /* ipu1 csi0 */ + MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + /* camera reset */ + MX6Q_PAD_GPIO_19__GPIO_4_5, + /* camera powerdown */ + MX6Q_PAD_CSI0_DAT5__GPIO_5_23, +}; + +static iomux_v3_cfg_t mx6q_arm2_csi0_tvin_pads[] = { + /* ipu1 csi0 */ + MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + /* camera reset */ + MX6Q_PAD_CSI0_DAT7__GPIO_5_25, + /* camera powerdown */ + MX6Q_PAD_CSI0_DAT5__GPIO_5_23, +}; + +static iomux_v3_cfg_t mx6q_arm2_mipi_sensor_pads[] = { + MX6Q_PAD_CSI0_MCLK__CCM_CLKO, +}; + +static iomux_v3_cfg_t mx6q_arm2_audmux_pads[] = { + + /* AUDMUX */ + MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC, + MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD, + MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS, + MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD, +}; + +#define MX6Q_USDHC_PAD_SETTING(id, speed) \ +mx6q_sd##id##_##speed##mhz[] = { \ + MX6Q_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6Q_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT4__USDHC##id##_DAT4_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT5__USDHC##id##_DAT5_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT6__USDHC##id##_DAT6_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT7__USDHC##id##_DAT7_##speed##MHZ, \ +} + +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 50); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 100); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 200); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(4, 50); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(4, 100); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(4, 200); + + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx6q_gpmi_nand[] __initdata = { + MX6Q_PAD_NANDF_CLE__RAWNAND_CLE, + MX6Q_PAD_NANDF_ALE__RAWNAND_ALE, + MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N, + MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N, + MX6Q_PAD_NANDF_CS2__RAWNAND_CE2N, + MX6Q_PAD_NANDF_CS3__RAWNAND_CE3N, + MX6Q_PAD_NANDF_RB0__RAWNAND_READY0, + MX6Q_PAD_SD4_DAT0__RAWNAND_DQS, + MX6Q_PAD_NANDF_D0__RAWNAND_D0, + MX6Q_PAD_NANDF_D1__RAWNAND_D1, + MX6Q_PAD_NANDF_D2__RAWNAND_D2, + MX6Q_PAD_NANDF_D3__RAWNAND_D3, + MX6Q_PAD_NANDF_D4__RAWNAND_D4, + MX6Q_PAD_NANDF_D5__RAWNAND_D5, + MX6Q_PAD_NANDF_D6__RAWNAND_D6, + MX6Q_PAD_NANDF_D7__RAWNAND_D7, + MX6Q_PAD_SD4_CMD__RAWNAND_RDN, + MX6Q_PAD_SD4_CLK__RAWNAND_WRN, + MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN, +}; + +static iomux_v3_cfg_t mx6q_arm2_hdmi_ddc_pads[] = { + MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6q_arm2_i2c2_pads[] = { + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; diff --git a/arch/arm/mach-mx6/board-mx6q_hdmidongle.c b/arch/arm/mach-mx6/board-mx6q_hdmidongle.c new file mode 100644 index 00000000..ffd8d9af --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_hdmidongle.c @@ -0,0 +1,800 @@ +/* + * Copyright (C) 2012-2013 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/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/mxc-hdmi-core.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6q.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_hdmi.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#ifdef CONFIG_MFD_WM831X +#include <linux/mfd/wm831x/core.h> +#include <linux/mfd/wm831x/pdata.h> +#include <linux/mfd/wm831x/regulator.h> +#include <linux/mfd/wm831x/gpio.h> +#endif + +#include "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6q_hdmidongle.h" +#include "board-mx6dl_hdmidongle.h" + +#define HDMIDONGLE_USB_OTG_PWR IMX_GPIO_NR(4, 15) +#define HDMIDONGLE_USB_H1_PWR IMX_GPIO_NR(4, 14) +#define HDMIDONGLE_ECSPI2_CS0 IMX_GPIO_NR(2, 26) +#define HDMIDONGLE_HDMI_CEC_IN IMX_GPIO_NR(4, 11) + + +#define HDMIDONGLE_BT_RST IMX_GPIO_NR(3, 7) +#define HDMIDONGLE_BT_EN IMX_GPIO_NR(3, 9) +#define HDMIDONGLE_WL_EN IMX_GPIO_NR(3, 10) + +#define HDMIDONGLE_SD2_CD IMX_GPIO_NR(1, 4) +#define HDMIDONGLE_REVA_POWER_KEY IMX_GPIO_NR(6, 16) +#define HDMIDONGLE_REVB_POWER_KEY IMX_GPIO_NR(1, 27) + +#ifdef CONFIG_IMX_PCIE +#define HDMIDONGLE_PCIE_PWR_EN IMX_GPIO_NR(3, 7) /*fake pcie power enable */ +#define HDMIDONGLE_PCIE_RST IMX_GPIO_NR(3, 9) +#define HDMIDONGLE_PCIE_WAKE IMX_GPIO_NR(3, 22) +#define HDMIDONGLE_PCIE_DIS IMX_GPIO_NR(3, 10) +#endif + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; + +static const struct esdhc_platform_data mx6q_hdmidongle_sd1_data __initconst = { + .always_present = 1, +}; + +static const struct esdhc_platform_data mx6q_hdmidongle_sd2_data __initconst = { + .cd_gpio = HDMIDONGLE_SD2_CD, + .keep_power_at_suspend = 1, + .support_8bit = 0, + .delay_line = 0, + .cd_type = ESDHC_CD_CONTROLLER, +}; + +static const struct esdhc_platform_data mx6q_hdmidongle_sd3_data __initconst = { + .always_present = 1, + .keep_power_at_suspend = 1, + .support_8bit = 1, + .delay_line = 0, + .cd_type = ESDHC_CD_PERMANENT, +}; + +static const struct esdhc_platform_data mx6q_hdmidongle_revc_sd3_data __initconst = { + .always_present = 1, + .keep_power_at_suspend = 1, + .support_8bit = 0, + .delay_line = 0, + .cd_type = ESDHC_CD_PERMANENT, +}; + + +static int __init gpmi_nand_platform_init(void) +{ + iomux_v3_cfg_t *nand_pads = NULL; + u32 nand_pads_cnt; + + if (cpu_is_mx6q()) { + nand_pads = mx6q_gpmi_nand; + nand_pads_cnt = ARRAY_SIZE(mx6q_gpmi_nand); + } else if (cpu_is_mx6dl()) { + nand_pads = mx6dl_gpmi_nand; + nand_pads_cnt = ARRAY_SIZE(mx6dl_gpmi_nand); + + } + BUG_ON(!nand_pads); + return mxc_iomux_v3_setup_multiple_pads(nand_pads, nand_pads_cnt); +} + +static struct gpmi_nand_platform_data +mx6_gpmi_nand_platform_data __initdata = { + .platform_init = gpmi_nand_platform_init, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 1, + .enable_bbt = 1, + .enable_ddr = 0, +}; + +static int __init board_support_onfi_nand(char *p) +{ + mx6_gpmi_nand_platform_data.enable_ddr = 1; + return 0; +} + +early_param("onfi_support", board_support_onfi_nand); + + +static const struct anatop_thermal_platform_data + mx6q_hdmidongle_anatop_thermal_data __initconst = { + .name = "anatop_thermal", +}; + +static inline void mx6q_hdmidongle_init_uart(void) +{ + if (board_is_mx6_reva()) + imx6q_add_imx_uart(1, NULL); + imx6q_add_imx_uart(0, NULL); + imx6q_add_imx_uart(3, NULL); +} + +static int mx6q_hdmidongle_spi_cs[] = { + HDMIDONGLE_ECSPI2_CS0, +}; + +static const struct spi_imx_master mx6q_hdmidongle_spi_data __initconst = { + .chipselect = mx6q_hdmidongle_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6q_hdmidongle_spi_cs), +}; + + + +#ifdef CONFIG_MFD_WM831X +#if 0 +/* 1.4125, 1.4125. 1.5 */ +#define WM831X_DC1_ON_CONFIG_VAL (0x48<<WM831X_DC1_ON_VSEL_SHIFT) +#define WM831X_DC2_ON_CONFIG_VAL (0x48<<WM831X_DC2_ON_VSEL_SHIFT) +#define WM831X_DC3_ON_CONFIG_VAL (0x1A<<WM831X_DC3_ON_VSEL_SHIFT) +#else +/* 1.375, 1.375. 1.5 */ + +#define WM831X_DC1_ON_CONFIG_VAL (0x44<<WM831X_DC1_ON_VSEL_SHIFT) +#define WM831X_DC2_ON_CONFIG_VAL (0x44<<WM831X_DC2_ON_VSEL_SHIFT) +#define WM831X_DC3_ON_CONFIG_VAL (0x1A<<WM831X_DC3_ON_VSEL_SHIFT) + +#endif + +#define WM831X_DC1_DVS_MODE_VAL (0x02<<WM831X_DC1_DVS_SRC_SHIFT) +#define WM831X_DC2_DVS_MODE_VAL (0x02<<WM831X_DC2_DVS_SRC_SHIFT) + +#define WM831X_DC1_DVS_CONTROL_VAL (0x20<<WM831X_DC1_DVS_VSEL_SHIFT) +#define WM831X_DC2_DVS_CONTROL_VAL (0x20<<WM831X_DC2_DVS_VSEL_SHIFT) + +#define WM831X_DC1_DVS_MASK (WM831X_DC1_DVS_SRC_MASK|WM831X_DC1_DVS_VSEL_MASK) +#define WM831X_DC2_DVS_MASK (WM831X_DC2_DVS_SRC_MASK|WM831X_DC1_DVS_VSEL_MASK) + +#define WM831X_DC1_DVS_VAL (WM831X_DC1_DVS_MODE_VAL|WM831X_DC1_DVS_CONTROL_VAL) +#define WM831X_DC2_DVS_VAL (WM831X_DC2_DVS_MODE_VAL|WM831X_DC2_DVS_CONTROL_VAL) + +#define WM831X_GPN_FN_VAL_HW_EN (0x0A<<WM831X_GPN_FN_SHIFT) +#define WM831X_GPN_FN_VAL_HW_CTL (0x0C<<WM831X_GPN_FN_SHIFT) +#define WM831X_GPN_FN_VAL_DVS1 (0x08<<WM831X_GPN_FN_SHIFT) + +#define WM831X_GPN_DIR_VAL (0x1<<WM831X_GPN_DIR_SHIFT) +#define WM831X_GPN_PULL_VAL (0x3<<WM831X_GPN_PULL_SHIFT) +#define WM831X_GPN_INT_MODE_VAL (0x1<<WM831X_GPN_INT_MODE_SHIFT) +#define WM831X_GPN_POL_VAL (0x1<<WM831X_GPN_POL_SHIFT) +#define WM831X_GPN_ENA_VAL (0x1<<WM831X_GPN_ENA_SHIFT) + +#define WM831X_GPIO7_8_9_MASK (WM831X_GPN_DIR_MASK|WM831X_GPN_INT_MODE_MASK|WM831X_GPN_PULL_MASK|WM831X_GPN_POL_MASK|WM831X_GPN_FN_MASK) + + +#define WM831X_GPIO7_VAL (WM831X_GPN_DIR_VAL|WM831X_GPN_PULL_VAL|WM831X_GPN_INT_MODE_VAL|WM831X_GPN_POL_VAL|WM831X_GPN_ENA_VAL|WM831X_GPN_FN_VAL_HW_EN) +#define WM831X_GPIO8_VAL (WM831X_GPN_DIR_VAL|WM831X_GPN_PULL_VAL|WM831X_GPN_INT_MODE_VAL|WM831X_GPN_POL_VAL|WM831X_GPN_ENA_VAL|WM831X_GPN_FN_VAL_HW_CTL) +#define WM831X_GPIO9_VAL (WM831X_GPN_DIR_VAL|WM831X_GPN_PULL_VAL|WM831X_GPN_INT_MODE_VAL|WM831X_GPN_POL_VAL|WM831X_GPN_ENA_VAL|WM831X_GPN_FN_VAL_DVS1) + +#define WM831X_STATUS_LED_MASK 0xC000 +#define WM831X_STATUS_LED_ON (0x1 << 14) +#define WM831X_STATUS_LED_OFF (0x0 << 14) + +static int wm8326_post_init(struct wm831x *wm831x) +{ + wm831x_set_bits(wm831x, WM831X_DC1_ON_CONFIG, WM831X_DC1_ON_VSEL_MASK, WM831X_DC1_ON_CONFIG_VAL); + wm831x_set_bits(wm831x, WM831X_DC2_ON_CONFIG, WM831X_DC2_ON_VSEL_MASK, WM831X_DC2_ON_CONFIG_VAL); + wm831x_set_bits(wm831x, WM831X_DC3_ON_CONFIG, WM831X_DC3_ON_VSEL_MASK, WM831X_DC3_ON_CONFIG_VAL); + + wm831x_set_bits(wm831x, WM831X_DC1_DVS_CONTROL, WM831X_DC1_DVS_MASK, WM831X_DC1_DVS_VAL); + wm831x_set_bits(wm831x, WM831X_DC2_DVS_CONTROL, WM831X_DC2_DVS_MASK, WM831X_DC2_DVS_VAL); + + wm831x_set_bits(wm831x, WM831X_GPIO7_CONTROL, WM831X_GPIO7_8_9_MASK, WM831X_GPIO7_VAL); + wm831x_set_bits(wm831x, WM831X_GPIO8_CONTROL, WM831X_GPIO7_8_9_MASK, WM831X_GPIO8_VAL); + wm831x_set_bits(wm831x, WM831X_GPIO9_CONTROL, WM831X_GPIO7_8_9_MASK, WM831X_GPIO9_VAL); + + wm831x_set_bits(wm831x, WM831X_STATUS_LED_1 , WM831X_STATUS_LED_MASK, WM831X_STATUS_LED_OFF); + wm831x_set_bits(wm831x, WM831X_STATUS_LED_2 , WM831X_STATUS_LED_MASK, WM831X_STATUS_LED_ON); + return 0; +} + +static struct wm831x_pdata hdmidongle_wm8326_pdata = { + .post_init = wm8326_post_init, +}; +#endif + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { +#ifdef CONFIG_MFD_WM831X + I2C_BOARD_INFO("wm8326", 0x34), + .platform_data = &hdmidongle_wm8326_pdata, +#endif + }, +}; + +static struct spi_board_info wm8326_spi1_board_info[] __initdata = { +#if defined(CONFIG_MFD_WM831X_SPI) + { + /* The modalias must be the same as spi device driver name */ + .modalias = "wm8326", + .max_speed_hz = 20000000, + .bus_num = 1, + .chip_select = 0, + }, +#endif +}; + +static void spi_device_init(void) +{ + spi_register_board_info(wm8326_spi1_board_info, + ARRAY_SIZE(wm8326_spi1_board_info)); +} + +static struct imxi2c_platform_data mx6q_hdmidongle_i2c_data = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50), + }, +}; + + +static void imx6q_hdmidongle_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(HDMIDONGLE_USB_OTG_PWR, 1); + else + gpio_set_value(HDMIDONGLE_USB_OTG_PWR, 0); +} + +static void __init imx6q_hdmidongle_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + /* disable external charger detect, + * or it will affect signal quality at dp . + */ + ret = gpio_request(HDMIDONGLE_USB_OTG_PWR, "usb-pwr"); + if (ret) { + pr_err("failed to get GPIO HDMIDONGLE_USB_OTG_PWR: %d\n", + ret); + return; + } + gpio_direction_output(HDMIDONGLE_USB_OTG_PWR, 0); + /* keep USB host1 VBUS always on */ + if (board_is_mx6_reva()) { + ret = gpio_request(HDMIDONGLE_USB_H1_PWR, "usb-h1-pwr"); + if (ret) { + pr_err("failed to get GPIO HDMIDONGLE_USB_H1_PWR: %d\n", + ret); + return; + } + gpio_direction_output(HDMIDONGLE_USB_H1_PWR, 1); + } + mxc_iomux_set_gpr_register(1, 13, 1, 1); + + mx6_set_otghost_vbus_func(imx6q_hdmidongle_usbotg_vbus); +} + + +static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_128M + SZ_64M, +}; + + +static struct ipuv3_fb_platform_data hdmidongle_fb_data[] = { + {/*fb0*/ + .disp_dev = "hdmi", + .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .mode_str = "1920x1080M@60", + .default_bpp = 32, + .int_clk = false, + }, +}; + +static void hdmi_init(int ipu_id, int disp_id) +{ + int hdmi_mux_setting; + + if ((ipu_id > 1) || (ipu_id < 0)) { + pr_err("Invalid IPU select for HDMI: %d. Set to 0\n", ipu_id); + ipu_id = 0; + } + + if ((disp_id > 1) || (disp_id < 0)) { + pr_err("Invalid DI select for HDMI: %d. Set to 0\n", disp_id); + disp_id = 0; + } + + /* Configure the connection between IPU1/2 and HDMI */ + hdmi_mux_setting = 2*ipu_id + disp_id; + + /* GPR3, bits 2-3 = HDMI_MUX_CTL */ + mxc_iomux_set_gpr_register(3, 2, 2, hdmi_mux_setting); + /* Set HDMI event as SDMA event2 while Chip version later than TO1.2 */ + if (hdmi_SDMA_check()) + mxc_iomux_set_gpr_register(0, 0, 1, 1); +} + +/* On mx6x sabresd board i2c2 iomux with hdmi ddc, + * the pins default work at i2c2 function, + when hdcp enable, the pins should work at ddc function */ + +static void hdmi_enable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_hdmidongle_hdmi_ddc_pads, + ARRAY_SIZE(mx6dl_hdmidongle_hdmi_ddc_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_hdmidongle_hdmi_ddc_pads, + ARRAY_SIZE(mx6q_hdmidongle_hdmi_ddc_pads)); +} + +static void hdmi_disable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_hdmidongle_i2c2_pads, + ARRAY_SIZE(mx6dl_hdmidongle_i2c2_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_hdmidongle_i2c2_pads, + ARRAY_SIZE(mx6q_hdmidongle_i2c2_pads)); +} + + +static struct fsl_mxc_hdmi_platform_data hdmi_data = { + .init = hdmi_init, + .enable_pins = hdmi_enable_ddc_pin, + .disable_pins = hdmi_disable_ddc_pin, + .phy_reg_vlev = 0x0294, + .phy_reg_cksymtx = 0x800d, +}; + +static struct fsl_mxc_hdmi_core_platform_data hdmi_core_data = { + .ipu_id = 0, + .disp_id = 0, +}; + +static struct imx_ipuv3_platform_data ipu_data[] = { + { + .rev = 4, + .csi_clk[0] = "clko_clk", + }, { + .rev = 4, + .csi_clk[0] = "clko_clk", + }, +}; + +static void hdmidongle_suspend_enter(void) +{ + /* suspend preparation */ +} + +static void hdmidongle_suspend_exit(void) +{ + /* resume restore */ +} +static const struct pm_platform_data mx6q_hdmidongle_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = hdmidongle_suspend_enter, + .suspend_exit = hdmidongle_suspend_exit, +}; + +static struct regulator_consumer_supply hdmidongle_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; + +static struct regulator_init_data hdmidongle_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(hdmidongle_vmmc_consumers), + .consumer_supplies = hdmidongle_vmmc_consumers, +}; + +static struct fixed_voltage_config hdmidongle_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &hdmidongle_vmmc_init, +}; + +static struct platform_device hdmidongle_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 3, + .dev = { + .platform_data = &hdmidongle_vmmc_reg_config, + }, +}; + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ + .debounce_interval = debounce, \ +} + +static struct gpio_keys_button hdmidongle_reva_buttons[] = { + GPIO_BUTTON(HDMIDONGLE_REVA_POWER_KEY, KEY_POWER, 1, "power", 1, 1), +}; + +static struct gpio_keys_platform_data hdmidongle_reva_button_data = { + .buttons = hdmidongle_reva_buttons, + .nbuttons = ARRAY_SIZE(hdmidongle_reva_buttons), +}; + +static struct platform_device hdmidongle_reva_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &hdmidongle_reva_button_data, + } +}; + +static struct gpio_keys_button hdmidongle_revb_buttons[] = { + GPIO_BUTTON(HDMIDONGLE_REVB_POWER_KEY, KEY_POWER, 1, "power", 1, 1), +}; + +static struct gpio_keys_platform_data hdmidongle_revb_button_data = { + .buttons = hdmidongle_revb_buttons, + .nbuttons = ARRAY_SIZE(hdmidongle_revb_buttons), +}; + +static struct platform_device hdmidongle_revb_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &hdmidongle_revb_button_data, + } +}; + + +static void __init imx6q_add_device_buttons(void) +{ + if (board_is_mx6_reva()) + platform_device_register(&hdmidongle_reva_button_device); + else + platform_device_register(&hdmidongle_revb_button_device); +} +#else +static void __init imx6q_add_device_buttons(void) {} +#endif + +static struct mxc_dvfs_platform_data hdmidongle_dvfscore_data = { + #ifdef CONFIG_MX6_INTER_LDO_BYPASS + .reg_id = "VDDCORE", + #else + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", + #endif + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + char *str; + struct tag *t; + int i = 0; + struct ipuv3_fb_platform_data *pdata_fb = hdmidongle_fb_data; + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "fbmem="); + if (str != NULL) { + str += 6; + pdata_fb[i++].res_size[0] = memparse(str, &str); + while (*str == ',' && + i < ARRAY_SIZE(hdmidongle_fb_data)) { + str++; + pdata_fb[i++].res_size[0] = memparse(str, &str); + } + } + break; + } + } +} + +#define SNVS_LPCR 0x38 +static void mx6_snvs_poweroff(void) +{ + + void __iomem *mx6_snvs_base = MX6_IO_ADDRESS(MX6Q_SNVS_BASE_ADDR); + u32 value; + value = readl(mx6_snvs_base + SNVS_LPCR); + /*set TOP and DP_EN bit*/ + writel(value | 0x60, mx6_snvs_base + SNVS_LPCR); +} + +#ifdef CONFIG_IMX_PCIE +static const struct imx_pcie_platform_data mx6_hdmidongle_pcie_data __initconst = { + .pcie_pwr_en = HDMIDONGLE_PCIE_PWR_EN, + .pcie_rst = HDMIDONGLE_PCIE_RST, + .pcie_wake_up = HDMIDONGLE_PCIE_WAKE, + .pcie_dis = HDMIDONGLE_PCIE_DIS, +}; +#endif + +/*! + * Board specific initialization. + */ +static void __init mx6_hdmidongle_board_init(void) +{ + int i; + + if (cpu_is_mx6q()) { + if (board_is_mx6_revb() || board_is_mx6_revc()) + mxc_iomux_v3_setup_multiple_pads(mx6q_hdmidongle_rev_b_pads, + ARRAY_SIZE(mx6q_hdmidongle_rev_b_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_hdmidongle_rev_a_pads, + ARRAY_SIZE(mx6q_hdmidongle_rev_a_pads)); + } else if (cpu_is_mx6dl()) { + if (board_is_mx6_revb() || board_is_mx6_revc()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_hdmidongle_rev_b_pads, + ARRAY_SIZE(mx6dl_hdmidongle_rev_b_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6dl_hdmidongle_rev_a_pads, + ARRAY_SIZE(mx6dl_hdmidongle_rev_a_pads)); + } + + gp_reg_id = hdmidongle_dvfscore_data.reg_id; + soc_reg_id = hdmidongle_dvfscore_data.soc_id; + pu_reg_id = hdmidongle_dvfscore_data.pu_id; + mx6q_hdmidongle_init_uart(); + + /* + * MX6DL/Solo only supports single IPU + * The following codes are used to change ipu id + * and display id information for MX6DL/Solo. Then + * register 1 IPU device and up to 2 displays for + * MX6DL/Solo + */ + if (cpu_is_mx6dl()) + hdmi_core_data.disp_id = 0; + + imx6q_add_mxc_hdmi_core(&hdmi_core_data); + + imx6q_add_ipuv3(0, &ipu_data[0]); + if (cpu_is_mx6q()) + imx6q_add_ipuv3(1, &ipu_data[1]); + for (i = 0; i < ARRAY_SIZE(hdmidongle_fb_data); i++) + imx6q_add_ipuv3fb(i, &hdmidongle_fb_data[i]); + + imx6q_add_vdoa(); + + imx6q_add_v4l2_output(0); + + imx6q_add_imx_snvs_rtc(); + + imx6q_add_imx_i2c(1, &mx6q_hdmidongle_i2c_data); + imx6q_add_imx_i2c(2, &mx6q_hdmidongle_i2c_data); + + 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)); + + + /* SPI */ + imx6q_add_ecspi(1, &mx6q_hdmidongle_spi_data); + spi_device_init(); + + imx6q_add_mxc_hdmi(&hdmi_data); + + imx6q_add_anatop_thermal_imx(1, &mx6q_hdmidongle_anatop_thermal_data); + imx6q_add_pm_imx(0, &mx6q_hdmidongle_pm_data); + /* Move sd3 to first because sd3 connect to emmc. + Mfgtools want emmc is mmcblk0 and other sd card is mmcblk1. + */ + if (board_is_mx6_revc()) + imx6q_add_sdhci_usdhc_imx(2, &mx6q_hdmidongle_revc_sd3_data); + else + imx6q_add_sdhci_usdhc_imx(2, &mx6q_hdmidongle_sd3_data); + imx6q_add_sdhci_usdhc_imx(1, &mx6q_hdmidongle_sd2_data); + if (board_is_mx6_reva()) + imx6q_add_sdhci_usdhc_imx(0, &mx6q_hdmidongle_sd1_data); + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + imx6q_hdmidongle_init_usb(); + + imx6q_add_vpu(); + + platform_device_register(&hdmidongle_vmmc_reg_devices); + + imx6q_add_otp(); + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + imx6q_add_dma(); + if (board_is_mx6_revb() || board_is_mx6_revc()) + imx6q_add_gpmi(&mx6_gpmi_nand_platform_data); + + imx6q_add_dvfs_core(&hdmidongle_dvfscore_data); + #ifndef CONFIG_MX6_INTER_LDO_BYPASS + mx6_cpu_regulator_init(); + #endif + + imx6q_add_device_buttons(); + + imx6q_add_hdmi_soc(); + imx6q_add_hdmi_soc_dai(); + + if (board_is_mx6_reva()) { + gpio_request(HDMIDONGLE_BT_RST, "bt_reset"); + gpio_direction_output(HDMIDONGLE_BT_RST, 1); + gpio_set_value(HDMIDONGLE_BT_RST, 1); + msleep(1000); + gpio_request(HDMIDONGLE_BT_EN, "bt_en"); + gpio_direction_output(HDMIDONGLE_BT_EN, 1); + gpio_set_value(HDMIDONGLE_BT_EN, 1); + + msleep(1000); + gpio_request(HDMIDONGLE_WL_EN, "wl_en"); + gpio_direction_output(HDMIDONGLE_WL_EN, 1); + gpio_set_value(HDMIDONGLE_WL_EN, 1); + msleep(1000); + } else if (board_is_mx6_revb() || board_is_mx6_revc()) { + /* Add PCIe RC interface support */ +#ifdef CONFIG_IMX_PCIE + imx6q_add_pcie(&mx6_hdmidongle_pcie_data); +#endif + } + pm_power_off = mx6_snvs_poweroff; + imx6q_add_busfreq(); +} + +extern void __iomem *twd_base; +static void __init mx6_hdmidongle_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART4_BASE_ADDR, uart_clk); +} + +static struct sys_timer mx6_hdmidongle_timer = { + .init = mx6_hdmidongle_timer_init, +}; + +static void __init mx6q_hdmidongle_reserve(void) +{ + phys_addr_t phys; + int i; + +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, SZ_1G); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif +#if defined(CONFIG_ION) + if (imx_ion_data.heaps[0].size) { + phys = memblock_alloc(imx_ion_data.heaps[0].size, SZ_4K); + memblock_remove(phys, imx_ion_data.heaps[0].size); + imx_ion_data.heaps[0].base = phys; + } +#endif + + for (i = 0; i < ARRAY_SIZE(hdmidongle_fb_data); i++) + if (hdmidongle_fb_data[i].res_size[0]) { + /* reserve for background buffer */ + phys = memblock_alloc(hdmidongle_fb_data[i].res_size[0], + SZ_4K); + memblock_remove(phys, hdmidongle_fb_data[i].res_size[0]); + hdmidongle_fb_data[i].res_base[0] = phys; + } +} + +/* + * initialize __mach_desc_MX6Q_HDMIDONGLE data structure. + */ +MACHINE_START(MX6Q_HDMIDONGLE, "Freescale i.MX 6Quad/DualLite HDMI Dongle Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX6_PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_hdmidongle_board_init, + .timer = &mx6_hdmidongle_timer, + .reserve = mx6q_hdmidongle_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6q_hdmidongle.h b/arch/arm/mach-mx6/board-mx6q_hdmidongle.h new file mode 100644 index 00000000..9338c3e6 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_hdmidongle.h @@ -0,0 +1,343 @@ +/* + * 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. + */ + +#ifndef _BOARD_MX6Q_HDMIDONGLE_H +#define _BOARD_MX6Q_HDMIDONGLE_H +#include <mach/iomux-mx6q.h> + +static iomux_v3_cfg_t mx6q_hdmidongle_rev_a_pads[] = { + /* SPI2 for PMIC communication port */ + MX6Q_PAD_EIM_OE__ECSPI2_MISO, + MX6Q_PAD_EIM_RW__ECSPI2_SS0, + MX6Q_PAD_EIM_CS0__ECSPI2_SCLK, + MX6Q_PAD_EIM_CS1__ECSPI2_MOSI, + + /*USB_OTG_DET(USB OTG cable plug detect) */ + MX6Q_PAD_EIM_A16__GPIO_2_22, + /*BT_WAKEUP_HOST(Combo module BT wake-up output) */ + MX6Q_PAD_EIM_A25__GPIO_5_2, + /* HOST_WAKEUP_BT(CPU wakeup BT signal)*/ + MX6Q_PAD_EIM_D16__GPIO_3_16, + + /* I2C3 */ + MX6Q_PAD_EIM_D17__I2C3_SCL, + MX6Q_PAD_EIM_D18__I2C3_SDA, + + /* USB OC pin */ + MX6Q_PAD_EIM_D21__USBOH3_USBOTG_OC, + /* WLAN_WAKEUP_HOST(Combo module WLAN host wake-up output) */ + MX6Q_PAD_EIM_D22__GPIO_3_22, + + /* BT_UART2 */ + MX6Q_PAD_EIM_D26__UART2_TXD, + MX6Q_PAD_EIM_D27__UART2_RXD, + MX6Q_PAD_EIM_D28__UART2_CTS, + MX6Q_PAD_EIM_D29__UART2_RTS, + + /*BT_nRST(Combo module BT reset signal)*/ + MX6Q_PAD_EIM_DA7__GPIO_3_7, + + /*BT_REG_ON(Combo module BT Internal regulators power enable/disable)*/ + MX6Q_PAD_EIM_DA9__GPIO_3_9, + + /*WL_REG_ON(Combo module WLAN Internal regulators power enable/disable)*/ + MX6Q_PAD_EIM_DA10__GPIO_3_10, + + /* GPIO2 */ + MX6Q_PAD_EIM_A22__GPIO_2_16, /* Boot Mode Select */ + MX6Q_PAD_EIM_A21__GPIO_2_17, /* Boot Mode Select */ + MX6Q_PAD_EIM_A20__GPIO_2_18, /* Boot Mode Select */ + MX6Q_PAD_EIM_A19__GPIO_2_19, /* Boot Mode Select */ + MX6Q_PAD_EIM_A18__GPIO_2_20, /* Boot Mode Select */ + MX6Q_PAD_EIM_A17__GPIO_2_21, /* Boot Mode Select */ + MX6Q_PAD_EIM_RW__GPIO_2_26, /* Boot Mode Select */ + MX6Q_PAD_EIM_LBA__GPIO_2_27, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB0__GPIO_2_28, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB1__GPIO_2_29, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB2__GPIO_2_30, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB3__GPIO_2_31, /* Boot Mode Select */ + + /* GPIO3 */ + MX6Q_PAD_EIM_DA0__GPIO_3_0, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA1__GPIO_3_1, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA2__GPIO_3_2, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA3__GPIO_3_3, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA4__GPIO_3_4, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA5__GPIO_3_5, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA6__GPIO_3_6, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA8__GPIO_3_8, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA11__GPIO_3_11, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA12__GPIO_3_12, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA13__GPIO_3_13, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA14__GPIO_3_14, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA15__GPIO_3_15, /* Boot Mode Select */ + + /* GPIO5 */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, /* Boot Mode Select */ + MX6Q_PAD_EIM_A24__GPIO_5_4, /* Boot Mode Select */ + + /* GPIO6 */ + MX6Q_PAD_EIM_A23__GPIO_6_6, /* Boot Mode Select */ + + /* I2C1 */ + MX6Q_PAD_CSI0_DAT8__I2C1_SDA, + MX6Q_PAD_CSI0_DAT9__I2C1_SCL, + + /* UART1 for debug */ + MX6Q_PAD_CSI0_DAT10__UART1_TXD, + MX6Q_PAD_CSI0_DAT11__UART1_RXD, + + /* SD1 (Combo module WLAN SDIO )*/ + MX6Q_PAD_SD1_CLK__USDHC1_CLK, + MX6Q_PAD_SD1_CMD__USDHC1_CMD, + MX6Q_PAD_SD1_DAT0__USDHC1_DAT0, + MX6Q_PAD_SD1_DAT1__USDHC1_DAT1, + MX6Q_PAD_SD1_DAT2__USDHC1_DAT2, + MX6Q_PAD_SD1_DAT3__USDHC1_DAT3, + + /* SD2 (MicroSD SDIO CMD)*/ + MX6Q_PAD_SD2_CLK__USDHC2_CLK, + MX6Q_PAD_SD2_CMD__USDHC2_CMD, + MX6Q_PAD_SD2_DAT0__USDHC2_DAT0, + MX6Q_PAD_SD2_DAT1__USDHC2_DAT1, + MX6Q_PAD_SD2_DAT2__USDHC2_DAT2, + MX6Q_PAD_SD2_DAT3__USDHC2_DAT3, + /*SD_DET (SD plug-in detect interrupt)*/ + MX6Q_PAD_GPIO_4__GPIO_1_4, + + /* SD3 (eMMC SDIO)*/ + MX6Q_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6Q_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6Q_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6Q_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6Q_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6Q_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6Q_PAD_SD3_RST__USDHC3_RST, + + /* UART4 for debug */ + MX6Q_PAD_KEY_COL0__UART4_TXD, + MX6Q_PAD_KEY_ROW0__UART4_RXD, + + /*HDMI CEC communication PIN*/ + MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, + + /* I2C2 */ + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ + + /*DCDC5V_PWREN(5V DCDC BOOST control signal)*/ + MX6Q_PAD_KEY_COL4__GPIO_4_14, + + /*USB_OTG_PWREN(USB OTG power change control signal)*/ + MX6Q_PAD_KEY_ROW4__GPIO_4_15, + + /* USBOTG ID pin */ + MX6Q_PAD_GPIO_1__USBOTG_ID, + + /* I2C3 */ + MX6Q_PAD_GPIO_5__I2C3_SCL, + MX6Q_PAD_GPIO_16__I2C3_SDA, + + /*WDOG(Watch dog output)*/ + MX6Q_PAD_GPIO_9__GPIO_1_9, + + /*PMIC_nINT(PMIC interrupt signal)*/ + MX6Q_PAD_NANDF_CS0__GPIO_6_11, + + /*GPIO_nRST(GPIO shutdown control)*/ + MX6Q_PAD_NANDF_CS1__GPIO_6_14, + + /*PWRKEY_DET(Power key press detection)*/ + MX6Q_PAD_NANDF_CS3__GPIO_6_16, + + /*CHG_SYS_ON(Charger auto power on control signal)*/ + MX6Q_PAD_NANDF_D6__GPIO_2_6, + + /*IR_RC*/ + MX6Q_PAD_SD4_DAT6__GPIO_2_14, +}; + +static iomux_v3_cfg_t mx6q_hdmidongle_rev_b_pads[] = { + /* SPI2 for PMIC communication port */ + MX6Q_PAD_EIM_OE__ECSPI2_MISO, + MX6Q_PAD_EIM_RW__ECSPI2_SS0, + MX6Q_PAD_EIM_CS0__ECSPI2_SCLK, + MX6Q_PAD_EIM_CS1__ECSPI2_MOSI, + + /*USB_OTG_DET(USB OTG cable plug detect) */ + MX6Q_PAD_EIM_A16__GPIO_2_22, + /*WLAN_CLKREQn*/ + MX6Q_PAD_EIM_A25__GPIO_5_2, + + /* WLAN_ACT */ + MX6Q_PAD_EIM_D17__GPIO_3_17, + + /*BT_PERI*/ + MX6Q_PAD_EIM_D18__GPIO_3_18, + + /* USB OC pin */ + MX6Q_PAD_EIM_D21__USBOH3_USBOTG_OC, + + /* WLAN_WAKEn (PM event, OD, used to reactivate the PCIe main PWR and REF CLK) */ + MX6Q_PAD_EIM_D22__GPIO_3_22, + + + /*WLAN_PERSTn (PCIe rst signal, avtive LOW)*/ + MX6Q_PAD_EIM_DA9__GPIO_3_9, + + /*WLAN_PDn (Externally shutdown RTL8192)*/ + MX6Q_PAD_EIM_DA10__GPIO_3_10, + + /* GPIO2 */ + MX6Q_PAD_EIM_A22__GPIO_2_16, /* Boot Mode Select */ + MX6Q_PAD_EIM_A21__GPIO_2_17, /* Boot Mode Select */ + MX6Q_PAD_EIM_A20__GPIO_2_18, /* Boot Mode Select */ + MX6Q_PAD_EIM_A19__GPIO_2_19, /* Boot Mode Select */ + MX6Q_PAD_EIM_A18__GPIO_2_20, /* Boot Mode Select */ + MX6Q_PAD_EIM_A17__GPIO_2_21, /* Boot Mode Select */ + MX6Q_PAD_EIM_RW__GPIO_2_26, /* Boot Mode Select */ + MX6Q_PAD_EIM_LBA__GPIO_2_27, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB0__GPIO_2_28, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB1__GPIO_2_29, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB2__GPIO_2_30, /* Boot Mode Select */ + MX6Q_PAD_EIM_EB3__GPIO_2_31, /* Boot Mode Select */ + + /* GPIO3 */ + MX6Q_PAD_EIM_DA0__GPIO_3_0, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA1__GPIO_3_1, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA2__GPIO_3_2, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA3__GPIO_3_3, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA4__GPIO_3_4, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA5__GPIO_3_5, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA6__GPIO_3_6, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA8__GPIO_3_8, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA11__GPIO_3_11, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA12__GPIO_3_12, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA13__GPIO_3_13, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA14__GPIO_3_14, /* Boot Mode Select */ + MX6Q_PAD_EIM_DA15__GPIO_3_15, /* Boot Mode Select */ + + /* GPIO5 */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, /* Boot Mode Select */ + MX6Q_PAD_EIM_A24__GPIO_5_4, /* Boot Mode Select */ + + /* GPIO6 */ + MX6Q_PAD_EIM_A23__GPIO_6_6, /* Boot Mode Select */ + + + /* SD2 (MicroSD SDIO CMD)*/ + MX6Q_PAD_SD2_CLK__USDHC2_CLK, + MX6Q_PAD_SD2_CMD__USDHC2_CMD, + MX6Q_PAD_SD2_DAT0__USDHC2_DAT0, + MX6Q_PAD_SD2_DAT1__USDHC2_DAT1, + MX6Q_PAD_SD2_DAT2__USDHC2_DAT2, + MX6Q_PAD_SD2_DAT3__USDHC2_DAT3, + /*SD_DET (SD plug-in detect interrupt)*/ + MX6Q_PAD_GPIO_4__GPIO_1_4, + + /* SD3 (eMMC SDIO)*/ + MX6Q_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6Q_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6Q_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6Q_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6Q_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6Q_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6Q_PAD_SD3_RST__USDHC3_RST, + + /* UART4 for debug */ + MX6Q_PAD_KEY_COL0__UART4_TXD, + MX6Q_PAD_KEY_ROW0__UART4_RXD, + + /*SD2_VSELECT (SD2 SDXC power exchange control signal)*/ + MX6Q_PAD_KEY_ROW1__GPIO_4_9, + + /*HDMI CEC communication PIN*/ + MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, + + /*PWRKEY_DET (Pwr button detection interrupt)*/ + MX6Q_PAD_ENET_RXD0__GPIO_1_27, + + /*USB_OTG_PWREN(USB OTG power change control signal)*/ + MX6Q_PAD_KEY_ROW4__GPIO_4_15, + + /* USBOTG ID pin */ + MX6Q_PAD_GPIO_1__USBOTG_ID, + + /* I2C2 */ + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ + + /* I2C3 */ + MX6Q_PAD_GPIO_5__I2C3_SCL, + MX6Q_PAD_GPIO_16__I2C3_SDA, + + /*WDOG(Watch dog output)*/ + MX6Q_PAD_GPIO_9__GPIO_1_9, + + /*PMIC_nINT(PMIC interrupt signal)*/ + MX6Q_PAD_SD4_DAT3__GPIO_2_11, + + /*GPIO_nRST(GPIO shutdown control)*/ + MX6Q_PAD_SD4_DAT1__GPIO_2_9, + + /*CHG_SYS_ON(Charger auto power on control signal)*/ + MX6Q_PAD_SD4_DAT6__GPIO_2_14, +}; + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx6q_gpmi_nand[] __initdata = { + MX6Q_PAD_NANDF_CLE__RAWNAND_CLE, + MX6Q_PAD_NANDF_ALE__RAWNAND_ALE, + MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N, + MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N, + MX6Q_PAD_NANDF_CS2__RAWNAND_CE2N, + MX6Q_PAD_NANDF_CS3__RAWNAND_CE3N, + MX6Q_PAD_NANDF_RB0__RAWNAND_READY0, + MX6Q_PAD_SD4_DAT0__RAWNAND_DQS, + MX6Q_PAD_NANDF_D0__RAWNAND_D0, + MX6Q_PAD_NANDF_D1__RAWNAND_D1, + MX6Q_PAD_NANDF_D2__RAWNAND_D2, + MX6Q_PAD_NANDF_D3__RAWNAND_D3, + MX6Q_PAD_NANDF_D4__RAWNAND_D4, + MX6Q_PAD_NANDF_D5__RAWNAND_D5, + MX6Q_PAD_NANDF_D6__RAWNAND_D6, + MX6Q_PAD_NANDF_D7__RAWNAND_D7, + MX6Q_PAD_SD4_CMD__RAWNAND_RDN, + MX6Q_PAD_SD4_CLK__RAWNAND_WRN, + MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN, +}; + +static iomux_v3_cfg_t mx6q_hdmidongle_hdmi_ddc_pads[] = { + MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6q_hdmidongle_i2c2_pads[] = { + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; + +#endif diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.c b/arch/arm/mach-mx6/board-mx6q_sabreauto.c new file mode 100644 index 00000000..01b07faf --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.c @@ -0,0 +1,1764 @@ +/* + * Copyright (C) 2011-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/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/smsc911x.h> +#include <linux/spi/spi.h> +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +#include <linux/spi/flash.h> +#else +#include <linux/mtd/physmap.h> +#endif +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/ion.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mxc_asrc.h> +#include <sound/pcm.h> +#include <linux/mfd/mxc-hdmi-core.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6q.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.h> +#include <mach/ahci_sata.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_hdmi.h> +#include <mach/mxc_asrc.h> +#include <mach/mipi_dsi.h> +#include <mach/mipi_csi2.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 "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6q_sabreauto.h" +#include "board-mx6solo_sabreauto.h" + +/* sorted by GPIO_NR */ +#define SABREAUTO_SD1_CD IMX_GPIO_NR(1, 1) +#define SABREAUTO_ESAI_INT IMX_GPIO_NR(1, 10) +#define SABREAUTO_ANDROID_HOME IMX_GPIO_NR(1, 11) +#define SABREAUTO_ANDROID_BACK IMX_GPIO_NR(1, 12) +#define SABREAUTO_SD3_WP IMX_GPIO_NR(1, 13) +#define SABREAUTO_I2C_EXP_RST IMX_GPIO_NR(1, 15) +#define SABREAUTO_USB_OTG_OC IMX_GPIO_NR(2, 8) +#define SABREAUTO_LDB_BACKLIGHT3 IMX_GPIO_NR(2, 9) +#define SABREAUTO_LDB_BACKLIGHT4 IMX_GPIO_NR(2, 10) +#define SABREAUTO_ANDROID_MENU IMX_GPIO_NR(2, 12) +#define SABREAUTO_ANDROID_VOLUP IMX_GPIO_NR(2, 15) +#define SABREAUTO_CAP_TCH_INT IMX_GPIO_NR(2, 28) +#define SABREAUTO_ECSPI1_CS1 IMX_GPIO_NR(3, 19) +#define SABREAUTO_DISP0_PWR IMX_GPIO_NR(3, 24) +#define SABREAUTO_DISP0_I2C_EN IMX_GPIO_NR(3, 28) +#define SABREAUTO_DISP0_DET_INT IMX_GPIO_NR(3, 31) +#define SABREAUTO_DISP0_RESET IMX_GPIO_NR(5, 0) +#define SABREAUTO_I2C3_STEER IMX_GPIO_NR(5, 4) +#define SABREAUTO_WEIM_NOR_WDOG1 IMX_GPIO_NR(4, 29) +#define SABREAUTO_ANDROID_VOLDOWN IMX_GPIO_NR(5, 14) +#define SABREAUTO_PMIC_INT IMX_GPIO_NR(5, 16) +#define SABREAUTO_ALS_INT IMX_GPIO_NR(5, 17) +#define SABREAUTO_SD1_WP IMX_GPIO_NR(5, 20) +#define SABREAUTO_USB_HOST1_OC IMX_GPIO_NR(5, 0) +#define SABREAUTO_SD3_CD IMX_GPIO_NR(6, 15) + +#define SABREAUTO_MAX7310_1_BASE_ADDR IMX_GPIO_NR(8, 0) +#define SABREAUTO_MAX7310_2_BASE_ADDR IMX_GPIO_NR(8, 8) +#define SABREAUTO_MAX7310_3_BASE_ADDR IMX_GPIO_NR(8, 16) + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO +#define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) +#define IOMUX_OBSRV_MUX1_OFFSET 0x3c +#define OBSRV_MUX1_MASK 0x3f +#define OBSRV_MUX1_ENET_IRQ 0x9 +#endif + +#define SABREAUTO_IO_EXP_GPIO1(x) (SABREAUTO_MAX7310_1_BASE_ADDR + (x)) +#define SABREAUTO_IO_EXP_GPIO2(x) (SABREAUTO_MAX7310_2_BASE_ADDR + (x)) +#define SABREAUTO_IO_EXP_GPIO3(x) (SABREAUTO_MAX7310_3_BASE_ADDR + (x)) + +#define SABREAUTO_PCIE_RST_B_REVB (SABREAUTO_MAX7310_1_BASE_ADDR + 2) +/* + * CAN2 STBY and EN lines are the same as the CAN1. These lines are not + * independent. + */ +#define SABREAUTO_PER_RST SABREAUTO_IO_EXP_GPIO1(3) +#define SABREAUTO_VIDEOIN_PWR SABREAUTO_IO_EXP_GPIO2(2) +#define SABREAUTO_CAN1_STEER SABREAUTO_IO_EXP_GPIO2(3) +#define SABREAUTO_CAN_STBY SABREAUTO_IO_EXP_GPIO2(5) +#define SABREAUTO_CAN_EN SABREAUTO_IO_EXP_GPIO2(6) +#define SABREAUTO_USB_HOST1_PWR SABREAUTO_IO_EXP_GPIO2(7) +#define SABREAUTO_USB_OTG_PWR SABREAUTO_IO_EXP_GPIO3(1) +#define BMCR_PDOWN 0x0800 /* PHY Powerdown */ + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; + +static int mma8451_position = 3; +static struct clk *sata_clk; +static int mipi_sensor; +static int can0_enable; +static int uart3_en; +static int tuner_en; +static int spinor_en; +static int weimnor_en; + +static int __init spinor_enable(char *p) +{ + spinor_en = 1; + return 0; +} +early_param("spi-nor", spinor_enable); + +static int __init weimnor_enable(char *p) +{ + weimnor_en = 1; + return 0; +} +early_param("weim-nor", weimnor_enable); + +static int __init uart3_enable(char *p) +{ + uart3_en = 1; + return 0; +} +early_param("uart3", uart3_enable); + +static int __init tuner_enable(char *p) +{ + tuner_en = 1; + return 0; +} +early_param("tuner", tuner_enable); + +enum sd_pad_mode { + SD_PAD_MODE_LOW_SPEED, + SD_PAD_MODE_MED_SPEED, + SD_PAD_MODE_HIGH_SPEED, +}; + +#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 ard_buttons[] = { + GPIO_BUTTON(SABREAUTO_ANDROID_HOME, KEY_HOME, 1, "home", 0), + GPIO_BUTTON(SABREAUTO_ANDROID_BACK, KEY_BACK, 1, "back", 0), + GPIO_BUTTON(SABREAUTO_ANDROID_MENU, KEY_MENU, 1, "menu", 0), + GPIO_BUTTON(SABREAUTO_ANDROID_VOLUP, KEY_VOLUMEUP, 1, "volume-up", 0), + GPIO_BUTTON(SABREAUTO_ANDROID_VOLDOWN, KEY_VOLUMEDOWN, 1, "volume-down", 0), +}; + +static struct gpio_keys_platform_data ard_android_button_data = { + .buttons = ard_buttons, + .nbuttons = ARRAY_SIZE(ard_buttons), +}; + +static struct platform_device ard_android_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &ard_android_button_data, + } +}; + +static void __init imx6q_add_android_device_buttons(void) +{ + platform_device_register(&ard_android_button_device); +} +#else +static void __init imx6q_add_android_device_buttons(void) {} +#endif + +static int plt_sd_pad_change(unsigned int index, int clock) +{ + /* LOW speed is the default state of SD pads */ + static enum sd_pad_mode pad_mode = SD_PAD_MODE_LOW_SPEED; + + iomux_v3_cfg_t *sd_pads_200mhz = NULL; + iomux_v3_cfg_t *sd_pads_100mhz = NULL; + iomux_v3_cfg_t *sd_pads_50mhz = NULL; + + u32 sd_pads_200mhz_cnt; + u32 sd_pads_100mhz_cnt; + u32 sd_pads_50mhz_cnt; + + if (index != 2) { + printk(KERN_ERR"no such SD host controller index %d\n", index); + return -EINVAL; + } + + if (cpu_is_mx6q()) { + sd_pads_200mhz = mx6q_sd3_200mhz; + sd_pads_100mhz = mx6q_sd3_100mhz; + sd_pads_50mhz = mx6q_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6q_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6q_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6q_sd3_50mhz); + } else if (cpu_is_mx6dl()) { + sd_pads_200mhz = mx6dl_sd3_200mhz; + sd_pads_100mhz = mx6dl_sd3_100mhz; + sd_pads_50mhz = mx6dl_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6dl_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6dl_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6dl_sd3_50mhz); + } + + if (clock > 100000000) { + if (pad_mode == SD_PAD_MODE_HIGH_SPEED) + return 0; + BUG_ON(!sd_pads_200mhz); + pad_mode = SD_PAD_MODE_HIGH_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_200mhz, + sd_pads_200mhz_cnt); + } else if (clock > 52000000) { + if (pad_mode == SD_PAD_MODE_MED_SPEED) + return 0; + BUG_ON(!sd_pads_100mhz); + pad_mode = SD_PAD_MODE_MED_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_100mhz, + sd_pads_100mhz_cnt); + } else { + if (pad_mode == SD_PAD_MODE_LOW_SPEED) + return 0; + BUG_ON(!sd_pads_50mhz); + pad_mode = SD_PAD_MODE_LOW_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_50mhz, + sd_pads_50mhz_cnt); + } +} + +static const struct esdhc_platform_data mx6q_sabreauto_sd3_data __initconst = { + .cd_gpio = SABREAUTO_SD3_CD, + .wp_gpio = SABREAUTO_SD3_WP, + .keep_power_at_suspend = 1, + .support_18v = 1, + .support_8bit = 1, + .delay_line = 0, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct esdhc_platform_data mx6q_sabreauto_sd1_data __initconst = { + .cd_gpio = SABREAUTO_SD1_CD, + .wp_gpio = SABREAUTO_SD1_WP, + .keep_power_at_suspend = 1, +}; + + +static int __init gpmi_nand_platform_init(void) +{ + iomux_v3_cfg_t *nand_pads = NULL; + u32 nand_pads_cnt; + + if (cpu_is_mx6q()) { + nand_pads = mx6q_gpmi_nand; + nand_pads_cnt = ARRAY_SIZE(mx6q_gpmi_nand); + } else if (cpu_is_mx6dl()) { + nand_pads = mx6dl_gpmi_nand; + nand_pads_cnt = ARRAY_SIZE(mx6dl_gpmi_nand); + + } + BUG_ON(!nand_pads); + return mxc_iomux_v3_setup_multiple_pads(nand_pads, nand_pads_cnt); +} + +static const struct gpmi_nand_platform_data +mx6q_gpmi_nand_platform_data __initconst = { + .platform_init = gpmi_nand_platform_init, + .min_prop_delay_in_ns = 5, + .max_prop_delay_in_ns = 9, + .max_chip_count = 1, +}; + +static const struct anatop_thermal_platform_data +mx6q_sabreauto_anatop_thermal_data __initconst = { + .name = "anatop_thermal", +}; + +static const struct imxuart_platform_data mx6_bt_uart_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS | IMXUART_SDMA, + .dma_req_rx = MX6Q_DMA_REQ_UART3_RX, + .dma_req_tx = MX6Q_DMA_REQ_UART3_TX, +}; + +static inline void mx6q_sabreauto_init_uart(void) +{ + imx6q_add_imx_uart(1, NULL); + imx6q_add_imx_uart(2, &mx6_bt_uart_data); + imx6q_add_imx_uart(3, NULL); +} + +static int mx6q_sabreauto_fec_phy_init(struct phy_device *phydev) +{ + unsigned short val; + + if (!board_is_mx6_reva()) { + /* Ar8031 phy SmartEEE feature cause link status generates + * glitch, which cause ethernet link down/up issue, so + * disable SmartEEE + */ + phy_write(phydev, 0xd, 0x3); + phy_write(phydev, 0xe, 0x805d); + phy_write(phydev, 0xd, 0x4003); + val = phy_read(phydev, 0xe); + val &= ~(0x1 << 8); + phy_write(phydev, 0xe, val); + + /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ + phy_write(phydev, 0xd, 0x7); + phy_write(phydev, 0xe, 0x8016); + phy_write(phydev, 0xd, 0x4007); + val = phy_read(phydev, 0xe); + + val &= 0xffe3; + val |= 0x18; + phy_write(phydev, 0xe, val); + + /* Introduce tx clock delay */ + phy_write(phydev, 0x1d, 0x5); + val = phy_read(phydev, 0x1e); + val |= 0x0100; + phy_write(phydev, 0x1e, val); + + /*check phy power*/ + val = phy_read(phydev, 0x0); + + if (val & BMCR_PDOWN) + phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); + } else { + /* prefer master mode, 1000 Base-T capable */ + phy_write(phydev, 0x9, 0x0f00); + + /* min rx data delay */ + phy_write(phydev, 0x0b, 0x8105); + phy_write(phydev, 0x0c, 0x0000); + + /* max rx/tx clock delay, min rx/tx control delay */ + phy_write(phydev, 0x0b, 0x8104); + phy_write(phydev, 0x0c, 0xf0f0); + phy_write(phydev, 0x0b, 0x104); + } + + return 0; +} + +static int mx6q_sabreauto_fec_power_hibernate(struct phy_device *phydev) +{ + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6q_sabreauto_fec_phy_init, + .power_hibernate = mx6q_sabreauto_fec_power_hibernate, + .phy = PHY_INTERFACE_MODE_RGMII, +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + .gpio_irq = MX6_ENET_IRQ, +#endif +}; + +static int mx6q_sabreauto_spi_cs[] = { + SABREAUTO_ECSPI1_CS1, +}; + +static const struct spi_imx_master mx6q_sabreauto_spi_data __initconst = { + .chipselect = mx6q_sabreauto_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6q_sabreauto_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition m25p32_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, + }, { + .name = "bootenv", + .offset = MTDPART_OFS_APPEND, + .size = SZ_8K, + .mask_flags = MTD_WRITEABLE, + }, { + .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", +}; + +static struct spi_board_info m25p32_spi0_board_info[] __initdata = { +#if defined(CONFIG_MTD_M25P80) + { + /* 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)); +} +#else +static struct mtd_partition mxc_nor_partitions[] = { + { + .name = "Bootloader", + .offset = 0, + .size = 0x00080000, + }, { + .name = "nor.Kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; +static struct resource nor_flash_resource = { + .start = CS0_BASE_ADDR, + .end = CS0_BASE_ADDR + 0x02000000 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct physmap_flash_data nor_flash_data = { + .probe_type = "cfi_probe", + .width = 2, + .parts = mxc_nor_partitions, + .nr_parts = ARRAY_SIZE(mxc_nor_partitions), +}; + +static struct platform_device physmap_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &nor_flash_data, + }, + .resource = &nor_flash_resource, + .num_resources = 1, +}; + +static void mx6q_setup_weimcs(void) +{ + unsigned int reg; + void __iomem *nor_reg = MX6_IO_ADDRESS(WEIM_BASE_ADDR); + void __iomem *ccm_reg = MX6_IO_ADDRESS(CCM_BASE_ADDR); + + /*CCM_BASE_ADDR + CLKCTL_CCGR6*/ + reg = readl(ccm_reg + 0x80); + reg |= 0x00000C00; + writel(reg, ccm_reg + 0x80); + + __raw_writel(0x00620081, nor_reg); + __raw_writel(0x1C022000, nor_reg + 0x00000008); + __raw_writel(0x0804a240, nor_reg + 0x00000010); +} +#endif + +static int max7310_1_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + /* 0 BACKLITE_ON */ + /* 1 SAT_SHUTDN_B */ + /* 2 CPU_PER_RST_B */ + /* 3 MAIN_PER_RST_B */ + /* 4 IPOD_RST_B */ + /* 5 MLB_RST_B */ + /* 6 SSI_STEERING */ + /* 7 GPS_RST_B */ + + int max7310_gpio_value[] = { + 0, 1, 1, 1, 0, 0, 1, 0, + }; + + int n; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 1 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]); + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data max7310_platdata = { + .gpio_base = SABREAUTO_MAX7310_1_BASE_ADDR, + .invert = 0, + .setup = max7310_1_setup, +}; + +static int max7310_u39_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + /* 0 not use */ + /* 1 GPS_PWREN */ + /* 2 VIDEO_ADC_PWRDN_B */ + /* 3 ENET_CAN1_STEER */ + /* 4 EIMD30_BTUART3_STEER */ + /* 5 CAN_STBY */ + /* 6 CAN_EN */ + /* 7 USB_H1_PWR */ + + int max7310_gpio_value[] = { + 0, 1, 0, 0, 0, 1, 1, 1, + }; + + int n; + + if (uart3_en) + max7310_gpio_value[4] = 1; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 U39 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]); + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static int max7310_u43_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + /*0 PORT_EXP_C0*/ + /*1 USB_OTG_PWR_ON */ + /*2 SAT_RST_B*/ + /*3 NAND_BT_WIFI_STEER*/ + + int max7310_gpio_value[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + }; + int n; + + if (uart3_en) + max7310_gpio_value[3] = 1; + + for (n = 0; n < ARRAY_SIZE(max7310_gpio_value); ++n) { + gpio_request(gpio_base + n, "MAX7310 U43 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]); + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data max7310_u39_platdata = { + .gpio_base = SABREAUTO_MAX7310_2_BASE_ADDR, + .invert = 0, + .setup = max7310_u39_setup, +}; + +static struct pca953x_platform_data max7310_u43_platdata = { + .gpio_base = SABREAUTO_MAX7310_3_BASE_ADDR, + .invert = 0, + .setup = max7310_u43_setup, +}; + +static void adv7180_pwdn(int pwdn) +{ + int status = -1; + + status = gpio_request(SABREAUTO_VIDEOIN_PWR, "tvin-pwr"); + + if (pwdn) + gpio_direction_output(SABREAUTO_VIDEOIN_PWR, 0); + else + gpio_direction_output(SABREAUTO_VIDEOIN_PWR, 1); + + gpio_free(SABREAUTO_VIDEOIN_PWR); +} + +static struct fsl_mxc_tvin_platform_data adv7180_data = { + .dvddio_reg = NULL, + .dvdd_reg = NULL, + .avdd_reg = NULL, + .pvdd_reg = NULL, + .pwdn = adv7180_pwdn, + .reset = NULL, + .cvbs = true, +}; + +static struct imxi2c_platform_data mx6q_sabreauto_i2c2_data = { + .bitrate = 400000, +}; + +static struct imxi2c_platform_data mx6q_sabreauto_i2c1_data = { + .bitrate = 100000, +}; + +static struct mxc_audio_codec_platform_data cs42888_data = { + .rates = ( + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000), +}; + +static struct fsl_mxc_lightsensor_platform_data ls_data = { + .rext = 499, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("max7310", 0x30), + .platform_data = &max7310_platdata, + }, { + I2C_BOARD_INFO("max7310", 0x32), + .platform_data = &max7310_u39_platdata, + }, { + I2C_BOARD_INFO("max7310", 0x34), + .platform_data = &max7310_u43_platdata, + }, { + I2C_BOARD_INFO("adv7180", 0x21), + .platform_data = (void *)&adv7180_data, + }, { + I2C_BOARD_INFO("isl29023", 0x44), + .irq = gpio_to_irq(SABREAUTO_ALS_INT), + .platform_data = &ls_data, + }, + { + I2C_BOARD_INFO("mma8451", 0x1c), + .platform_data = (void *)&mma8451_position, + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("egalax_ts", 0x04), + .irq = gpio_to_irq(SABREAUTO_CAP_TCH_INT), + }, { + I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50), + }, { + I2C_BOARD_INFO("cs42888", 0x48), + .platform_data = (void *)&cs42888_data, + }, { + I2C_BOARD_INFO("si4763_i2c", 0x63), + }, +}; + +struct platform_device mxc_si4763_audio_device = { + .name = "imx-tuner-si4763", + .id = 0, +}; + +struct platform_device si4763_codec_device = { + .name = "si4763", + .id = 0, +}; + +static struct imx_ssi_platform_data mx6_sabreauto_ssi1_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; +static struct mxc_audio_platform_data si4763_audio_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 5, +}; +static void imx6q_sabreauto_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value_cansleep(SABREAUTO_USB_OTG_PWR, 1); + else + gpio_set_value_cansleep(SABREAUTO_USB_OTG_PWR, 0); +} + +static void imx6q_sabreauto_usbhost1_vbus(bool on) +{ + if (on) + gpio_set_value_cansleep(SABREAUTO_USB_HOST1_PWR, 1); + else + gpio_set_value_cansleep(SABREAUTO_USB_HOST1_PWR, 0); +} + +static void __init imx6q_sabreauto_init_usb(void) +{ + int ret = 0; + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + + ret = gpio_request(SABREAUTO_USB_OTG_OC, "otg-oc"); + if (ret) { + printk(KERN_ERR"failed to get GPIO SABREAUTO_USB_OTG_OC:" + " %d\n", ret); + return; + } + gpio_direction_input(SABREAUTO_USB_OTG_OC); + + ret = gpio_request(SABREAUTO_USB_HOST1_OC, "usbh1-oc"); + if (ret) { + printk(KERN_ERR"failed to get SABREAUTO_USB_HOST1_OC:" + " %d\n", ret); + return; + } + gpio_direction_input(SABREAUTO_USB_HOST1_OC); + + mxc_iomux_set_gpr_register(1, 13, 1, 0); + mx6_set_otghost_vbus_func(imx6q_sabreauto_usbotg_vbus); + mx6_usb_dr_init(); + mx6_set_host1_vbus_func(imx6q_sabreauto_usbhost1_vbus); +#ifdef CONFIG_USB_EHCI_ARC_HSIC + mx6_usb_h2_init(); + mx6_usb_h3_init(); +#endif +} + +static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_128M + SZ_64M, +}; + +/* HW Initialization, if return 0, initialization is successful. */ +static int mx6q_sabreauto_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; + } + + /* Set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write is 0x07FFFFFD, + * and the other one write for setting the mpll_clk_off_b + *.rx_eq_val_0(iomuxc_gpr13[26:24]), + *.los_lvl(iomuxc_gpr13[23:19]), + *.rx_dpll_mode_0(iomuxc_gpr13[18:16]), + *.sata_speed(iomuxc_gpr13[15]), + *.mpll_ss_en(iomuxc_gpr13[14]), + *.tx_atten_0(iomuxc_gpr13[13:11]), + *.tx_boost_0(iomuxc_gpr13[10:7]), + *.tx_lvl(iomuxc_gpr13[6:2]), + *.mpll_ck_off(iomuxc_gpr13[1]), + *.tx_edgerate_0(iomuxc_gpr13[0]), + */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13); + + /* enable SATA_PHY PLL */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13); + + /* Get the AHB clock rate, and configure the TIMER1MS reg later */ + clk = clk_get(NULL, "ahb"); + if (IS_ERR(clk)) { + dev_err(dev, "no ahb clock.\n"); + ret = PTR_ERR(clk); + goto release_sata_clk; + } + tmpdata = clk_get_rate(clk) / 1000; + clk_put(clk); + +#ifdef CONFIG_SATA_AHCI_PLATFORM + ret = sata_init(addr, tmpdata); + if (ret == 0) + return ret; +#else + usleep_range(1000, 2000); + /* AHCI PHY enter into PDDQ mode if the AHCI module is not enabled */ + tmpdata = readl(addr + PORT_PHY_CTL); + writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, addr + PORT_PHY_CTL); + pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(addr + PORT_PHY_CTL) + >> 20) & 1) ? "enabled" : "disabled"); +#endif + +release_sata_clk: + /* disable SATA_PHY PLL */ + writel((readl(IOMUXC_GPR13) & ~0x2), IOMUXC_GPR13); + clk_disable(sata_clk); +put_sata_clk: + clk_put(sata_clk); + + return ret; +} + +#ifdef CONFIG_SATA_AHCI_PLATFORM +static void mx6q_sabreauto_sata_exit(struct device *dev) +{ + clk_disable(sata_clk); + clk_put(sata_clk); + +} + +static struct ahci_platform_data mx6q_sabreauto_sata_data = { + .init = mx6q_sabreauto_sata_init, + .exit = mx6q_sabreauto_sata_exit, +}; +#endif + +static struct imx_asrc_platform_data imx_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static void mx6q_sabreauto_reset_mipi_dsi(void) +{ + gpio_set_value(SABREAUTO_DISP0_PWR, 1); + gpio_set_value(SABREAUTO_DISP0_RESET, 1); + udelay(10); + gpio_set_value(SABREAUTO_DISP0_RESET, 0); + udelay(50); + gpio_set_value(SABREAUTO_DISP0_RESET, 1); + + /* + * it needs to delay 120ms minimum for reset complete + */ + msleep(120); +} + +static struct mipi_dsi_platform_data mipi_dsi_pdata = { + .ipu_id = 0, + .disp_id = 0, + .lcd_panel = "TRULY-WVGA", + .reset = mx6q_sabreauto_reset_mipi_dsi, +}; + +static struct ipuv3_fb_platform_data sabr_fb_data[] = { + { /*fb0*/ + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + }, { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + }, { + .disp_dev = "lcd", + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static void hdmi_init(int ipu_id, int disp_id) +{ + int hdmi_mux_setting; + + if ((ipu_id > 1) || (ipu_id < 0)) { + printk(KERN_ERR"Invalid IPU select for HDMI: %d. Set to 0\n", + ipu_id); + ipu_id = 0; + } + + if ((disp_id > 1) || (disp_id < 0)) { + printk(KERN_ERR"Invalid DI select for HDMI: %d. Set to 0\n", + disp_id); + disp_id = 0; + } + + /* Configure the connection between IPU1/2 and HDMI */ + hdmi_mux_setting = 2*ipu_id + disp_id; + + /* GPR3, bits 2-3 = HDMI_MUX_CTL */ + mxc_iomux_set_gpr_register(3, 2, 2, hdmi_mux_setting); + + /* Set HDMI event as SDMA event2 while Chip version later than TO1.2 */ + if (hdmi_SDMA_check()) + mxc_iomux_set_gpr_register(0, 0, 1, 1); +} + +/* On mx6x sabreauto board i2c2 iomux with hdmi ddc, + * the pins default work at i2c2 function, + when hdcp enable, the pins should work at ddc function */ + +static void hdmi_enable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabreauto_hdmi_ddc_pads, + ARRAY_SIZE(mx6dl_sabreauto_hdmi_ddc_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_sabreauto_hdmi_ddc_pads, + ARRAY_SIZE(mx6q_sabreauto_hdmi_ddc_pads)); +} + +static void hdmi_disable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabreauto_i2c2_pads, + ARRAY_SIZE(mx6dl_sabreauto_i2c2_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_sabreauto_i2c2_pads, + ARRAY_SIZE(mx6q_sabreauto_i2c2_pads)); +} + +static struct fsl_mxc_hdmi_platform_data hdmi_data = { + .init = hdmi_init, + .enable_pins = hdmi_enable_ddc_pin, + .disable_pins = hdmi_disable_ddc_pin, +}; + +static struct fsl_mxc_hdmi_core_platform_data hdmi_core_data = { + .ipu_id = 0, + .disp_id = 0, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 1, + .disp_id = 0, + .ext_ref = 1, + .mode = LDB_SEP0, + .sec_ipu_id = 1, + .sec_disp_id = 1, +}; + +static struct imx_ipuv3_platform_data ipu_data[] = { + { + .rev = 4, + .csi_clk[0] = "ccm_clk0", + }, { + .rev = 4, + .csi_clk[0] = "ccm_clk0", + }, +}; + +/* Backlight PWM for CPU board lvds*/ +static struct platform_pwm_backlight_data mx6_arm2_pwm_backlight_data3 = { + .pwm_id = 2, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct ion_platform_data imx_ion_data = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .name = "vpu_ion", + .size = SZ_64M, + }, + }, +}; + +/* Backlight PWM for Main board lvds*/ +static struct platform_pwm_backlight_data mx6_arm2_pwm_backlight_data4 = { + .pwm_id = 3, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; +static int flexcan0_en; +static int flexcan1_en; + +static void mx6q_flexcan_switch(void) +{ + if (flexcan0_en || flexcan1_en) { + /* + * The transceiver TJA1041A on sabreauto RevE baseboard will + * fail to transit to Normal state if EN/STBY is high by default + * after board power up. So we set the EN/STBY initial state to low + * first then to high to guarantee the state transition successfully. + */ + gpio_set_value_cansleep(SABREAUTO_CAN_EN, 0); + gpio_set_value_cansleep(SABREAUTO_CAN_STBY, 0); + + gpio_set_value_cansleep(SABREAUTO_CAN_EN, 1); + gpio_set_value_cansleep(SABREAUTO_CAN_STBY, 1); + /* Enable STEER pin if CAN1 interface is required. + * STEER pin is used to switch between ENET_MDC + * and CAN1_TX functionality. By default ENET_MDC + * is active after reset. + */ + if (flexcan0_en) + gpio_set_value_cansleep(SABREAUTO_CAN1_STEER, 1); + + } else { + /* avoid to disable CAN xcvr if any of the CAN interfaces + * are down. XCRV will be disabled only if both CAN2 + * interfaces are DOWN. + */ + if (!flexcan0_en && !flexcan1_en) { + gpio_set_value_cansleep(SABREAUTO_CAN_EN, 0); + gpio_set_value_cansleep(SABREAUTO_CAN_STBY, 0); + } + /* turn down STEER pin only if CAN1 is DOWN */ + if (!flexcan0_en) + gpio_set_value_cansleep(SABREAUTO_CAN1_STEER, 0); + + } +} +static void mx6q_flexcan0_switch(int enable) +{ + flexcan0_en = enable; + mx6q_flexcan_switch(); +} + +static void mx6q_flexcan1_switch(int enable) +{ + flexcan1_en = enable; + mx6q_flexcan_switch(); +} + +static const struct flexcan_platform_data + mx6q_sabreauto_flexcan_pdata[] __initconst = { + { + .transceiver_switch = mx6q_flexcan0_switch, + }, { + .transceiver_switch = mx6q_flexcan1_switch, + } +}; + +static struct mipi_csi2_platform_data mipi_csi2_pdata = { + .ipu_id = 0, + .csi_id = 0, + .v_channel = 0, + .lanes = 2, + .dphy_clk = "mipi_pllref_clk", + .pixel_clk = "emi_clk", +}; + +static void sabreauto_suspend_enter(void) +{ + /* suspend preparation */ +} + +static void sabreauto_suspend_exit(void) +{ + /* resmue resore */ +} +static const struct pm_platform_data mx6q_sabreauto_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = sabreauto_suspend_enter, + .suspend_exit = sabreauto_suspend_exit, +}; + +static const struct asrc_p2p_params esai_p2p = { + .p2p_rate = 48000, + .p2p_width = ASRC_WIDTH_24_BIT, +}; + +static struct mxc_audio_platform_data sab_audio_data = { + .sysclk = 24576000, + .codec_name = "cs42888.1-0048", + .priv = (void *)&esai_p2p, +}; + +static struct platform_device sab_audio_device = { + .name = "imx-cs42888", +}; + +static struct imx_esai_platform_data sab_esai_pdata = { + .flags = IMX_ESAI_NET, +}; + +static struct regulator_consumer_supply sabreauto_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; + +static struct regulator_init_data sabreauto_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(sabreauto_vmmc_consumers), + .consumer_supplies = sabreauto_vmmc_consumers, +}; + +static struct fixed_voltage_config sabreauto_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &sabreauto_vmmc_init, +}; + +static struct platform_device sabreauto_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &sabreauto_vmmc_reg_config, + }, +}; + +static struct regulator_consumer_supply cs42888_sabreauto_consumer_va = { + .supply = "VA", + .dev_name = "1-0048", +}; + +static struct regulator_consumer_supply cs42888_sabreauto_consumer_vd = { + .supply = "VD", + .dev_name = "1-0048", +}; + +static struct regulator_consumer_supply cs42888_sabreauto_consumer_vls = { + .supply = "VLS", + .dev_name = "1-0048", +}; + +static struct regulator_consumer_supply cs42888_sabreauto_consumer_vlc = { + .supply = "VLC", + .dev_name = "1-0048", +}; + +static struct regulator_init_data cs42888_sabreauto_va_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_sabreauto_consumer_va, +}; + +static struct regulator_init_data cs42888_sabreauto_vd_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_sabreauto_consumer_vd, +}; + +static struct regulator_init_data cs42888_sabreauto_vls_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_sabreauto_consumer_vls, +}; + +static struct regulator_init_data cs42888_sabreauto_vlc_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &cs42888_sabreauto_consumer_vlc, +}; + +static struct fixed_voltage_config cs42888_sabreauto_va_reg_config = { + .supply_name = "VA", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_sabreauto_va_reg_initdata, +}; + +static struct fixed_voltage_config cs42888_sabreauto_vd_reg_config = { + .supply_name = "VD", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_sabreauto_vd_reg_initdata, +}; + +static struct fixed_voltage_config cs42888_sabreauto_vls_reg_config = { + .supply_name = "VLS", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_sabreauto_vls_reg_initdata, +}; + +static struct fixed_voltage_config cs42888_sabreauto_vlc_reg_config = { + .supply_name = "VLC", + .microvolts = 2800000, + .gpio = -1, + .init_data = &cs42888_sabreauto_vlc_reg_initdata, +}; + +static struct platform_device cs42888_sabreauto_va_reg_devices = { + .name = "reg-fixed-voltage", + .id = 3, + .dev = { + .platform_data = &cs42888_sabreauto_va_reg_config, + }, +}; + +static struct platform_device cs42888_sabreauto_vd_reg_devices = { + .name = "reg-fixed-voltage", + .id = 4, + .dev = { + .platform_data = &cs42888_sabreauto_vd_reg_config, + }, +}; + +static struct platform_device cs42888_sabreauto_vls_reg_devices = { + .name = "reg-fixed-voltage", + .id = 5, + .dev = { + .platform_data = &cs42888_sabreauto_vls_reg_config, + }, +}; + +static struct platform_device cs42888_sabreauto_vlc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 6, + .dev = { + .platform_data = &cs42888_sabreauto_vlc_reg_config, + }, +}; + +static int __init imx6q_init_audio(void) +{ + struct clk *pll4_clk, *esai_clk, *anaclk_2; + + mxc_register_device(&sab_audio_device, &sab_audio_data); + imx6q_add_imx_esai(0, &sab_esai_pdata); + + gpio_request(SABREAUTO_ESAI_INT, "esai-int"); + gpio_direction_input(SABREAUTO_ESAI_INT); + + anaclk_2 = clk_get(NULL, "anaclk_2"); + if (IS_ERR(anaclk_2)) + return PTR_ERR(anaclk_2); + clk_set_rate(anaclk_2, 24576000); + + esai_clk = clk_get(NULL, "esai_clk"); + if (IS_ERR(esai_clk)) + return PTR_ERR(esai_clk); + + pll4_clk = clk_get(NULL, "pll4"); + if (IS_ERR(pll4_clk)) + return PTR_ERR(pll4_clk); + + clk_set_parent(pll4_clk, anaclk_2); + clk_set_parent(esai_clk, pll4_clk); + clk_set_rate(pll4_clk, 786432000); + clk_set_rate(esai_clk, 24576000); + + platform_device_register(&cs42888_sabreauto_va_reg_devices); + platform_device_register(&cs42888_sabreauto_vd_reg_devices); + platform_device_register(&cs42888_sabreauto_vls_reg_devices); + platform_device_register(&cs42888_sabreauto_vlc_reg_devices); + return 0; +} + +static struct mxc_mlb_platform_data mx6_sabreauto_mlb150_data = { + .reg_nvcc = NULL, + .mlb_clk = "mlb150_clk", + .mlb_pll_clk = "pll6", +}; + +static struct mxc_dvfs_platform_data sabreauto_dvfscore_data = { + .reg_id = "VDDCORE", + .soc_id = "VDDSOC", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ +} + +static int __init early_enable_mipi_sensor(char *p) +{ + mipi_sensor = 1; + return 0; +} +early_param("mipi_sensor", early_enable_mipi_sensor); + +static int __init early_enable_can0(char *p) +{ + can0_enable = 1; + return 0; +} +early_param("can0", early_enable_can0); + +static inline void __init mx6q_csi0_io_init(void) +{ + if (cpu_is_mx6q()) + mxc_iomux_set_gpr_register(1, 19, 1, 1); + else if (cpu_is_mx6dl()) + mxc_iomux_set_gpr_register(13, 0, 3, 4); +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 0, /* disable tx */ + .spdif_rx = 1, /* enable rx */ + .spdif_rx_clk = 0, /* rx clk from spdif stream */ + .spdif_clk = NULL, /* spdif bus clk */ +}; + +static struct fsl_mxc_capture_platform_data capture_data[] = { + { + .csi = 0, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 0, + }, { + .csi = 1, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 1, + }, +}; + +static const struct imx_pcie_platform_data mx6_sabreauto_pcie_data __initconst = { + .pcie_pwr_en = -EINVAL, + .pcie_rst = SABREAUTO_PCIE_RST_B_REVB, + .pcie_wake_up = -EINVAL, + .pcie_dis = -EINVAL, +}; + +/*! + * Board specific initialization. + */ +static void __init mx6_board_init(void) +{ + int i; + int ret; + iomux_v3_cfg_t *common_pads = NULL; + iomux_v3_cfg_t *can0_pads = NULL; + iomux_v3_cfg_t *can1_pads = NULL; + iomux_v3_cfg_t *mipi_sensor_pads = NULL; + iomux_v3_cfg_t *i2c3_pads = NULL; + iomux_v3_cfg_t *tuner_pads = NULL; + iomux_v3_cfg_t *spinor_pads = NULL; + iomux_v3_cfg_t *weimnor_pads = NULL; + iomux_v3_cfg_t *bluetooth_pads = NULL; + iomux_v3_cfg_t *extra_pads = NULL; + + int common_pads_cnt; + int can0_pads_cnt; + int can1_pads_cnt; + int mipi_sensor_pads_cnt; + int i2c3_pads_cnt; + int tuner_pads_cnt; + int spinor_pads_cnt; + int weimnor_pads_cnt; + int bluetooth_pads_cnt; + int extra_pads_cnt; + + if (cpu_is_mx6q()) { + common_pads = mx6q_sabreauto_pads; + can0_pads = mx6q_sabreauto_can0_pads; + can1_pads = mx6q_sabreauto_can1_pads; + mipi_sensor_pads = mx6q_sabreauto_mipi_sensor_pads; + tuner_pads = mx6q_tuner_pads; + spinor_pads = mx6q_spinor_pads; + weimnor_pads = mx6q_weimnor_pads; + bluetooth_pads = mx6q_bluetooth_pads; + + common_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_pads); + can0_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_can0_pads); + can1_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_can1_pads); + mipi_sensor_pads_cnt = ARRAY_SIZE(mx6q_sabreauto_mipi_sensor_pads); + tuner_pads_cnt = ARRAY_SIZE(mx6q_tuner_pads); + spinor_pads_cnt = ARRAY_SIZE(mx6q_spinor_pads); + weimnor_pads_cnt = ARRAY_SIZE(mx6q_weimnor_pads); + bluetooth_pads_cnt = ARRAY_SIZE(mx6q_bluetooth_pads); + if (board_is_mx6_reva()) { + i2c3_pads = mx6q_i2c3_pads_rev_a; + i2c3_pads_cnt = ARRAY_SIZE(mx6q_i2c3_pads_rev_a); + mxc_iomux_v3_setup_multiple_pads(i2c3_pads, + i2c3_pads_cnt); + } else { + i2c3_pads = mx6q_i2c3_pads_rev_b; + i2c3_pads_cnt = ARRAY_SIZE(mx6q_i2c3_pads_rev_b); + extra_pads = mx6q_extra_pads_rev_b; + extra_pads_cnt = ARRAY_SIZE(mx6q_extra_pads_rev_b); + mxc_iomux_v3_setup_multiple_pads(extra_pads, + extra_pads_cnt); + } + } else if (cpu_is_mx6dl()) { + common_pads = mx6dl_sabreauto_pads; + can0_pads = mx6dl_sabreauto_can0_pads; + can1_pads = mx6dl_sabreauto_can1_pads; + mipi_sensor_pads = mx6dl_sabreauto_mipi_sensor_pads; + tuner_pads = mx6dl_tuner_pads; + spinor_pads = mx6dl_spinor_pads; + weimnor_pads = mx6dl_weimnor_pads; + bluetooth_pads = mx6dl_bluetooth_pads; + + common_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_pads); + can0_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_can0_pads); + can1_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_can1_pads); + mipi_sensor_pads_cnt = ARRAY_SIZE(mx6dl_sabreauto_mipi_sensor_pads); + tuner_pads_cnt = ARRAY_SIZE(mx6dl_tuner_pads); + spinor_pads_cnt = ARRAY_SIZE(mx6dl_spinor_pads); + weimnor_pads_cnt = ARRAY_SIZE(mx6dl_weimnor_pads); + bluetooth_pads_cnt = ARRAY_SIZE(mx6dl_bluetooth_pads); + + if (board_is_mx6_reva()) { + i2c3_pads = mx6dl_i2c3_pads_rev_a; + i2c3_pads_cnt = ARRAY_SIZE(mx6dl_i2c3_pads_rev_a); + mxc_iomux_v3_setup_multiple_pads(i2c3_pads, + i2c3_pads_cnt); + } else { + i2c3_pads = mx6dl_i2c3_pads_rev_b; + i2c3_pads_cnt = ARRAY_SIZE(mx6dl_i2c3_pads_rev_b); + extra_pads = mx6dl_extra_pads_rev_b; + extra_pads_cnt = ARRAY_SIZE(mx6dl_extra_pads_rev_b); + mxc_iomux_v3_setup_multiple_pads(extra_pads, + extra_pads_cnt); + } + } + + BUG_ON(!common_pads); + mxc_iomux_v3_setup_multiple_pads(common_pads, common_pads_cnt); + + /*If at least one NOR memory is selected we don't + * configure IC23 PADS for rev B */ + if (spinor_en) { + BUG_ON(!spinor_pads); + mxc_iomux_v3_setup_multiple_pads(spinor_pads, spinor_pads_cnt); + } else if (weimnor_en) { + BUG_ON(!weimnor_pads); + mxc_iomux_v3_setup_multiple_pads(weimnor_pads, + weimnor_pads_cnt); + } else { + if (!board_is_mx6_reva()) { + BUG_ON(!i2c3_pads); + mxc_iomux_v3_setup_multiple_pads(i2c3_pads, + i2c3_pads_cnt); + } + if (uart3_en) { + BUG_ON(!bluetooth_pads); + mxc_iomux_v3_setup_multiple_pads(bluetooth_pads, + bluetooth_pads_cnt); + } + } + + if (can0_enable) { + BUG_ON(!can0_pads); + mxc_iomux_v3_setup_multiple_pads(can0_pads, + can0_pads_cnt); + } + + BUG_ON(!can1_pads); + mxc_iomux_v3_setup_multiple_pads(can1_pads, can1_pads_cnt); + + if (tuner_en) { + BUG_ON(!tuner_pads); + mxc_iomux_v3_setup_multiple_pads(tuner_pads, + tuner_pads_cnt); + } + + /* assert i2c-rst */ + gpio_request(SABREAUTO_I2C_EXP_RST, "i2c-rst"); + gpio_direction_output(SABREAUTO_I2C_EXP_RST, 1); + + if (!board_is_mx6_reva()) { + /* enable either EIM_D18 or i2c3_sda route path */ + gpio_request(SABREAUTO_I2C3_STEER, "i2c3-steer"); + if (spinor_en) + gpio_direction_output(SABREAUTO_I2C3_STEER, 0); + else if (weimnor_en) { + /*Put DISP0_DAT8 in ALT5 mode to prevent WDOG1 of + resetting WEIM NOR*/ + gpio_direction_output(SABREAUTO_I2C3_STEER, 0); + + gpio_request(SABREAUTO_WEIM_NOR_WDOG1, "nor-reset"); + gpio_direction_output(SABREAUTO_WEIM_NOR_WDOG1, 1); + } else + gpio_direction_output(SABREAUTO_I2C3_STEER, 1); + /* Set GPIO_16 input for IEEE-1588 ts_clk and + * RMII reference clk + * For MX6 GPR1 bit21 meaning: + * Bit21: 0 - GPIO_16 pad output + * 1 - GPIO_16 pad input + */ + mxc_iomux_set_gpr_register(1, 21, 1, 1); + } + + if (mipi_sensor) { + BUG_ON(!mipi_sensor_pads); + mxc_iomux_v3_setup_multiple_pads(mipi_sensor_pads, + mipi_sensor_pads_cnt); + } + + gp_reg_id = sabreauto_dvfscore_data.reg_id; + soc_reg_id = sabreauto_dvfscore_data.soc_id; + mx6q_sabreauto_init_uart(); + imx6q_add_mipi_csi2(&mipi_csi2_pdata); + if (cpu_is_mx6dl()) { + mipi_dsi_pdata.ipu_id = 0; + mipi_dsi_pdata.disp_id = 1; + ldb_data.ipu_id = 0; + ldb_data.disp_id = 0; + ldb_data.sec_ipu_id = 0; + ldb_data.sec_disp_id = 1; + hdmi_core_data.disp_id = 1; + } + imx6q_add_mxc_hdmi_core(&hdmi_core_data); + + imx6q_add_ipuv3(0, &ipu_data[0]); + if (cpu_is_mx6q()) { + imx6q_add_ipuv3(1, &ipu_data[1]); + for (i = 0; i < ARRAY_SIZE(sabr_fb_data); i++) + imx6q_add_ipuv3fb(i, &sabr_fb_data[i]); + } else if (cpu_is_mx6dl()) + for (i = 0; i < (ARRAY_SIZE(sabr_fb_data) + 1) / 2; i++) + imx6q_add_ipuv3fb(i, &sabr_fb_data[i]); + + imx6q_add_vdoa(); + imx6q_add_mipi_dsi(&mipi_dsi_pdata); + imx6q_add_lcdif(&lcdif_data); + imx6q_add_ldb(&ldb_data); + imx6q_add_v4l2_output(0); + imx6q_add_v4l2_capture(0, &capture_data[0]); + imx6q_add_v4l2_capture(1, &capture_data[1]); + imx6q_add_android_device_buttons(); + + imx6q_add_imx_snvs_rtc(); + + imx6q_add_imx_caam(); + + imx6q_add_imx_i2c(1, &mx6q_sabreauto_i2c1_data); + i2c_register_board_info(1, mxc_i2c1_board_info, + ARRAY_SIZE(mxc_i2c1_board_info)); + imx6q_add_imx_i2c(2, &mx6q_sabreauto_i2c2_data); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + ret = gpio_request(SABREAUTO_PMIC_INT, "pFUZE-int"); + if (ret) { + printk(KERN_ERR"request pFUZE-int error!!\n"); + return; + } else { + gpio_direction_input(SABREAUTO_PMIC_INT); + mx6q_sabreauto_init_pfuze100(SABREAUTO_PMIC_INT); + } + /* SPI */ + imx6q_add_ecspi(0, &mx6q_sabreauto_spi_data); +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + spi_device_init(); +#else + mx6q_setup_weimcs(); + platform_device_register(&physmap_flash_device); +#endif + imx6q_add_mxc_hdmi(&hdmi_data); + + imx6q_add_anatop_thermal_imx(1, &mx6q_sabreauto_anatop_thermal_data); + + if (!can0_enable) { + imx6_init_fec(fec_data); +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); +#endif + + } + imx6q_add_pm_imx(0, &mx6q_sabreauto_pm_data); + + imx6q_add_sdhci_usdhc_imx(2, &mx6q_sabreauto_sd3_data); + imx6q_add_sdhci_usdhc_imx(0, &mx6q_sabreauto_sd1_data); + + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + imx6q_sabreauto_init_usb(); + if (cpu_is_mx6q()) { +#ifdef CONFIG_SATA_AHCI_PLATFORM + imx6q_add_ahci(0, &mx6q_sabreauto_sata_data); +#else + mx6q_sabreauto_sata_init(NULL, + (void __iomem *)ioremap(MX6Q_SATA_BASE_ADDR, SZ_4K)); +#endif + } + imx6q_add_vpu(); + imx6q_init_audio(); + platform_device_register(&sabreauto_vmmc_reg_devices); + imx_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + imx_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + imx6q_add_asrc(&imx_asrc_data); + + if (!mipi_sensor) + mx6q_csi0_io_init(); + + /* DISP0 Detect */ + gpio_request(SABREAUTO_DISP0_DET_INT, "disp0-detect"); + gpio_direction_input(SABREAUTO_DISP0_DET_INT); + + /* DISP0 Reset - Assert for i2c disabled mode */ + gpio_request(SABREAUTO_DISP0_RESET, "disp0-reset"); + gpio_direction_output(SABREAUTO_DISP0_RESET, 0); + + /* DISP0 I2C enable */ + gpio_request(SABREAUTO_DISP0_I2C_EN, "disp0-i2c"); + gpio_direction_output(SABREAUTO_DISP0_I2C_EN, 0); + + gpio_request(SABREAUTO_DISP0_PWR, "disp0-pwr"); + gpio_direction_output(SABREAUTO_DISP0_PWR, 1); + + gpio_request(SABREAUTO_LDB_BACKLIGHT3, "ldb-backlight3"); + gpio_direction_output(SABREAUTO_LDB_BACKLIGHT3, 1); + gpio_request(SABREAUTO_LDB_BACKLIGHT4, "ldb-backlight4"); + gpio_direction_output(SABREAUTO_LDB_BACKLIGHT4, 1); + imx6q_add_otp(); + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + imx6q_add_dma(); + if (!uart3_en) + imx6q_add_gpmi(&mx6q_gpmi_nand_platform_data); + + imx6q_add_dvfs_core(&sabreauto_dvfscore_data); + + imx6q_add_ion(0, &imx_ion_data, + sizeof(imx_ion_data) + sizeof(struct ion_platform_heap)); + imx6q_add_mxc_pwm(2); + imx6q_add_mxc_pwm(3); + imx6q_add_mxc_pwm_backlight(2, &mx6_arm2_pwm_backlight_data3); + imx6q_add_mxc_pwm_backlight(3, &mx6_arm2_pwm_backlight_data4); + + mxc_spdif_data.spdif_core_clk = clk_get_sys("mxc_spdif.0", NULL); + clk_put(mxc_spdif_data.spdif_core_clk); + imx6q_add_spdif(&mxc_spdif_data); + imx6q_add_spdif_dai(); + imx6q_add_spdif_audio_device(); + + if (can0_enable) + imx6q_add_flexcan0(&mx6q_sabreauto_flexcan_pdata[0]); + imx6q_add_flexcan1(&mx6q_sabreauto_flexcan_pdata[1]); + imx6q_add_hdmi_soc(); + imx6q_add_hdmi_soc_dai(); + imx6q_add_mlb150(&mx6_sabreauto_mlb150_data); + + /* Tuner audio interface */ + imx6q_add_imx_ssi(1, &mx6_sabreauto_ssi1_pdata); + mxc_register_device(&si4763_codec_device, NULL); + mxc_register_device(&mxc_si4763_audio_device, &si4763_audio_data); + + imx6q_add_busfreq(); + + /* Add PCIe RC interface support */ + imx6q_add_pcie(&mx6_sabreauto_pcie_data); + + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); +} + +extern void __iomem *twd_base; +static void __init mx6_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART4_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx6_timer_init, +}; + +static void __init mx6q_reserve(void) +{ + phys_addr_t phys; +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, SZ_2G); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif + +#if defined(CONFIG_ION) + if (imx_ion_data.heaps[0].size) { + phys = memblock_alloc(imx_ion_data.heaps[0].size, SZ_4K); + memblock_free(phys, imx_ion_data.heaps[0].size); + memblock_remove(phys, imx_ion_data.heaps[0].size); + imx_ion_data.heaps[0].base = phys; + } +#endif +} + +MACHINE_START(MX6Q_SABREAUTO, "Freescale i.MX 6Quad/DualLite/Solo Sabre Auto Board") + .boot_params = MX6_PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_board_init, + .timer = &mxc_timer, + .reserve = mx6q_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6q_sabreauto.h b/arch/arm/mach-mx6/board-mx6q_sabreauto.h new file mode 100644 index 00000000..cec36d57 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_sabreauto.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2012-2013 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/iomux-mx6q.h> + +static iomux_v3_cfg_t mx6q_sabreauto_pads[] = { + + /* UART4 for debug */ + MX6Q_PAD_KEY_COL0__UART4_TXD, + MX6Q_PAD_KEY_ROW0__UART4_RXD, + /* USB HSIC ports use the same pin with ENET */ +#ifdef CONFIG_USB_EHCI_ARC_HSIC + /* USB H2 strobe/data pin */ + MX6Q_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE, + MX6Q_PAD_RGMII_TXC__USBOH3_H2_DATA, + + /* USB H3 strobe/data pin */ + MX6Q_PAD_RGMII_RXC__USBOH3_H3_STROBE, + MX6Q_PAD_RGMII_RX_CTL__USBOH3_H3_DATA, + /* ENET */ +#else + MX6Q_PAD_KEY_COL1__ENET_MDIO, + MX6Q_PAD_KEY_COL2__ENET_MDC, + MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6Q_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6Q_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, + /*RGMII Phy Interrupt */ + MX6Q_PAD_GPIO_19__GPIO_4_5, +#endif + /* MCLK for csi0 */ + MX6Q_PAD_GPIO_0__CCM_CLKO, + /*MX6Q_PAD_GPIO_3__CCM_CLKO2,i*/ + + /* Android GPIO keys */ + MX6Q_PAD_SD2_CMD__GPIO_1_11, /* home */ + MX6Q_PAD_SD2_DAT3__GPIO_1_12, /* back */ + MX6Q_PAD_SD4_DAT4__GPIO_2_12, /* prog */ + MX6Q_PAD_SD4_DAT7__GPIO_2_15, /* vol up */ + MX6Q_PAD_DISP0_DAT20__GPIO_5_14, /* vol down */ + + /* SD1 */ + MX6Q_PAD_SD1_CLK__USDHC1_CLK_50MHZ_40OHM, + MX6Q_PAD_SD1_CMD__USDHC1_CMD_50MHZ_40OHM, + MX6Q_PAD_SD1_DAT0__USDHC1_DAT0_50MHZ_40OHM, + MX6Q_PAD_SD1_DAT1__USDHC1_DAT1_50MHZ_40OHM, + MX6Q_PAD_SD1_DAT2__USDHC1_DAT2_50MHZ_40OHM, + MX6Q_PAD_SD1_DAT3__USDHC1_DAT3_50MHZ_40OHM, + + /* SD1_CD and SD1_WP */ + MX6Q_PAD_GPIO_1__GPIO_1_1, + MX6Q_PAD_CSI0_DATA_EN__GPIO_5_20, + + /* SD3 */ + MX6Q_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6Q_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6Q_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6Q_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6Q_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6Q_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + + /* SD3 VSelect */ + MX6Q_PAD_GPIO_18__USDHC3_VSELECT, + /* SD3_CD and SD3_WP */ + MX6Q_PAD_NANDF_CS2__GPIO_6_15, + MX6Q_PAD_SD2_DAT2__GPIO_1_13, + + /* ESAI */ + MX6Q_PAD_ENET_CRS_DV__ESAI1_SCKT, + MX6Q_PAD_ENET_RXD1__ESAI1_FST, + MX6Q_PAD_ENET_TX_EN__ESAI1_TX3_RX2, + MX6Q_PAD_GPIO_5__ESAI1_TX2_RX3, + MX6Q_PAD_ENET_TXD0__ESAI1_TX4_RX1, + MX6Q_PAD_ENET_MDC__ESAI1_TX5_RX0, + MX6Q_PAD_GPIO_17__ESAI1_TX0, + MX6Q_PAD_NANDF_CS3__ESAI1_TX1, + MX6Q_PAD_ENET_MDIO__ESAI1_SCKR, + MX6Q_PAD_GPIO_9__ESAI1_FSR, + /* esai interrupt */ + MX6Q_PAD_SD2_CLK__GPIO_1_10, + + /* I2C2 */ + MX6Q_PAD_EIM_EB2__I2C2_SCL, + MX6Q_PAD_KEY_ROW3__I2C2_SDA, + MX6Q_PAD_SD2_DAT0__GPIO_1_15, + + /* DISPLAY */ + MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15, + MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2, + MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3, + MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + + /* LITE_SENS_INT_B */ + MX6Q_PAD_DISP0_DAT23__GPIO_5_17, + /*PMIC INT*/ + MX6Q_PAD_DISP0_DAT22__GPIO_5_16, + + /* ipu1 csi0 */ + MX6Q_PAD_CSI0_DAT4__IPU1_CSI0_D_4, + MX6Q_PAD_CSI0_DAT5__IPU1_CSI0_D_5, + MX6Q_PAD_CSI0_DAT6__IPU1_CSI0_D_6, + MX6Q_PAD_CSI0_DAT7__IPU1_CSI0_D_7, + MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8, + MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9, + MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10, + MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11, + MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + + /* PWM3 and PMW4 */ + MX6Q_PAD_SD4_DAT1__PWM3_PWMO, + MX6Q_PAD_SD4_DAT2__PWM4_PWMO, + + /* DISP0 RESET */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, + + /* SPDIF */ + MX6Q_PAD_KEY_COL3__SPDIF_IN1, + + /* Touchscreen interrupt */ + MX6Q_PAD_EIM_EB0__GPIO_2_28, + + /* USBOTG ID pin */ + MX6Q_PAD_ENET_RX_ER__ANATOP_USBOTG_ID, + + /* VIDEO adv7180 INTRQ */ + MX6Q_PAD_ENET_RXD0__GPIO_1_27, + /* UART 2 */ + MX6Q_PAD_GPIO_7__UART2_TXD, + MX6Q_PAD_GPIO_8__UART2_RXD, + MX6Q_PAD_SD4_DAT6__UART2_CTS, + MX6Q_PAD_SD4_DAT5__UART2_RTS, + + /*USBs OC pin */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, /*HOST1_OC*/ + MX6Q_PAD_SD4_DAT0__GPIO_2_8, /*OTG_OC*/ + + /* DISP0 I2C ENABLE*/ + MX6Q_PAD_EIM_D28__GPIO_3_28, + + /* DISP0 DET */ + MX6Q_PAD_EIM_D31__GPIO_3_31, + + /* DISP0 RESET */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, + + /* HDMI */ + MX6Q_PAD_EIM_A25__HDMI_TX_CEC_LINE, + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, +#else + /* MLB150 */ + MX6Q_PAD_ENET_TXD1__MLB_MLBCLK, + MX6Q_PAD_GPIO_6__MLB_MLBSIG, + MX6Q_PAD_GPIO_2__MLB_MLBDAT, +#endif +}; + +static iomux_v3_cfg_t mx6q_sabreauto_can0_pads[] = { + /* CAN1 */ + MX6Q_PAD_KEY_COL2__CAN1_TXCAN, + MX6Q_PAD_KEY_ROW2__CAN1_RXCAN, +}; + + +static iomux_v3_cfg_t mx6q_sabreauto_can1_pads[] = { + /* CAN2 */ + MX6Q_PAD_KEY_COL4__CAN2_TXCAN, + MX6Q_PAD_KEY_ROW4__CAN2_RXCAN, +}; + +static iomux_v3_cfg_t mx6q_sabreauto_mipi_sensor_pads[] = { + MX6Q_PAD_CSI0_MCLK__CCM_CLKO, +}; + +#define MX6Q_USDHC_PAD_SETTING(id, speed) \ +mx6q_sd##id##_##speed##mhz[] = { \ + MX6Q_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6Q_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT4__USDHC##id##_DAT4_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT5__USDHC##id##_DAT5_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT6__USDHC##id##_DAT6_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT7__USDHC##id##_DAT7_##speed##MHZ, \ +} + +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 50); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 100); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 200); + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx6q_gpmi_nand[] __initdata = { + MX6Q_PAD_NANDF_CLE__RAWNAND_CLE, + MX6Q_PAD_NANDF_ALE__RAWNAND_ALE, + MX6Q_PAD_NANDF_CS0__RAWNAND_CE0N, + MX6Q_PAD_NANDF_CS1__RAWNAND_CE1N, + MX6Q_PAD_NANDF_RB0__RAWNAND_READY0, + MX6Q_PAD_SD4_DAT0__RAWNAND_DQS, + MX6Q_PAD_NANDF_D0__RAWNAND_D0, + MX6Q_PAD_NANDF_D1__RAWNAND_D1, + MX6Q_PAD_NANDF_D2__RAWNAND_D2, + MX6Q_PAD_NANDF_D3__RAWNAND_D3, + MX6Q_PAD_NANDF_D4__RAWNAND_D4, + MX6Q_PAD_NANDF_D5__RAWNAND_D5, + MX6Q_PAD_NANDF_D6__RAWNAND_D6, + MX6Q_PAD_NANDF_D7__RAWNAND_D7, + MX6Q_PAD_SD4_CMD__RAWNAND_RDN, + MX6Q_PAD_SD4_CLK__RAWNAND_WRN, + MX6Q_PAD_NANDF_WP_B__RAWNAND_RESETN, +}; + +static iomux_v3_cfg_t mx6q_i2c3_pads_rev_a[] __initdata = { + MX6Q_PAD_GPIO_3__I2C3_SCL, + MX6Q_PAD_GPIO_16__I2C3_SDA, +}; +static iomux_v3_cfg_t mx6q_i2c3_pads_rev_b[] __initdata = { + MX6Q_PAD_GPIO_3__I2C3_SCL, + MX6Q_PAD_EIM_D18__I2C3_SDA, +}; +static iomux_v3_cfg_t mx6q_tuner_pads[] __initdata = { + MX6Q_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC, + MX6Q_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS, + MX6Q_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD, +}; +static iomux_v3_cfg_t mx6q_extra_pads_rev_b[] __initdata = { + MX6Q_PAD_EIM_A24__GPIO_5_4, + MX6Q_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, +}; +static iomux_v3_cfg_t mx6q_spinor_pads[] __initdata = { + /* eCSPI1 */ + MX6Q_PAD_EIM_D16__ECSPI1_SCLK, + MX6Q_PAD_EIM_D17__ECSPI1_MISO, + MX6Q_PAD_EIM_D18__ECSPI1_MOSI, + MX6Q_PAD_EIM_D19__ECSPI1_SS1, + + MX6Q_PAD_EIM_D19__GPIO_3_19, +}; + +/*Bluetooth is conflicted with GMPI and NOR chips*/ +static iomux_v3_cfg_t mx6q_bluetooth_pads[] __initdata = { + /* UART 3 */ + MX6Q_PAD_SD4_CLK__UART3_RXD, + MX6Q_PAD_SD4_CMD__UART3_TXD, + MX6Q_PAD_EIM_D30__UART3_CTS, + MX6Q_PAD_EIM_EB3__UART3_RTS, +}; + +static iomux_v3_cfg_t mx6q_weimnor_pads[] __initdata = { + /* Parallel NOR */ + MX6Q_PAD_EIM_OE__WEIM_WEIM_OE, + MX6Q_PAD_EIM_RW__WEIM_WEIM_RW, + MX6Q_PAD_EIM_WAIT__WEIM_WEIM_WAIT, + MX6Q_PAD_EIM_CS0__WEIM_WEIM_CS_0, + /*Control NOR reset using gpio mode*/ + MX6Q_PAD_DISP0_DAT8__GPIO_4_29, + + MX6Q_PAD_EIM_LBA__WEIM_WEIM_LBA, + MX6Q_PAD_EIM_BCLK__WEIM_WEIM_BCLK, + /* Parallel Nor Data Bus */ + MX6Q_PAD_EIM_D16__WEIM_WEIM_D_16, + MX6Q_PAD_EIM_D17__WEIM_WEIM_D_17, + MX6Q_PAD_EIM_D18__WEIM_WEIM_D_18, + MX6Q_PAD_EIM_D19__WEIM_WEIM_D_19, + MX6Q_PAD_EIM_D20__WEIM_WEIM_D_20, + MX6Q_PAD_EIM_D21__WEIM_WEIM_D_21, + MX6Q_PAD_EIM_D22__WEIM_WEIM_D_22, + MX6Q_PAD_EIM_D23__WEIM_WEIM_D_23, + MX6Q_PAD_EIM_D24__WEIM_WEIM_D_24, + MX6Q_PAD_EIM_D25__WEIM_WEIM_D_25, + MX6Q_PAD_EIM_D26__WEIM_WEIM_D_26, + MX6Q_PAD_EIM_D27__WEIM_WEIM_D_27, + MX6Q_PAD_EIM_D28__WEIM_WEIM_D_28, + MX6Q_PAD_EIM_D29__WEIM_WEIM_D_29, + MX6Q_PAD_EIM_D30__WEIM_WEIM_D_30, + MX6Q_PAD_EIM_D31__WEIM_WEIM_D_31, + + /* Parallel Nor 25 bit Address Bus */ + MX6Q_PAD_EIM_A24__GPIO_5_4, + MX6Q_PAD_EIM_A23__WEIM_WEIM_A_23, + MX6Q_PAD_EIM_A22__WEIM_WEIM_A_22, + MX6Q_PAD_EIM_A21__WEIM_WEIM_A_21, + MX6Q_PAD_EIM_A20__WEIM_WEIM_A_20, + MX6Q_PAD_EIM_A19__WEIM_WEIM_A_19, + MX6Q_PAD_EIM_A18__WEIM_WEIM_A_18, + MX6Q_PAD_EIM_A17__WEIM_WEIM_A_17, + MX6Q_PAD_EIM_A16__WEIM_WEIM_A_16, + + MX6Q_PAD_EIM_DA15__WEIM_WEIM_DA_A_15, + MX6Q_PAD_EIM_DA14__WEIM_WEIM_DA_A_14, + MX6Q_PAD_EIM_DA13__WEIM_WEIM_DA_A_13, + MX6Q_PAD_EIM_DA12__WEIM_WEIM_DA_A_12, + MX6Q_PAD_EIM_DA11__WEIM_WEIM_DA_A_11, + MX6Q_PAD_EIM_DA10__WEIM_WEIM_DA_A_10, + MX6Q_PAD_EIM_DA9__WEIM_WEIM_DA_A_9, + MX6Q_PAD_EIM_DA8__WEIM_WEIM_DA_A_8, + MX6Q_PAD_EIM_DA7__WEIM_WEIM_DA_A_7, + MX6Q_PAD_EIM_DA6__WEIM_WEIM_DA_A_6, + MX6Q_PAD_EIM_DA5__WEIM_WEIM_DA_A_5, + MX6Q_PAD_EIM_DA4__WEIM_WEIM_DA_A_4, + MX6Q_PAD_EIM_DA3__WEIM_WEIM_DA_A_3, + MX6Q_PAD_EIM_DA2__WEIM_WEIM_DA_A_2, + MX6Q_PAD_EIM_DA1__WEIM_WEIM_DA_A_1, + MX6Q_PAD_EIM_DA0__WEIM_WEIM_DA_A_0, +}; + +static iomux_v3_cfg_t mx6q_sabreauto_hdmi_ddc_pads[] = { + MX6Q_PAD_EIM_EB2__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6q_sabreauto_i2c2_pads[] = { + MX6Q_PAD_EIM_EB2__I2C2_SCL, /* I2C2 SCL */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; diff --git a/arch/arm/mach-mx6/board-mx6q_sabrelite.c b/arch/arm/mach-mx6/board-mx6q_sabrelite.c new file mode 100644 index 00000000..f13a5d47 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_sabrelite.c @@ -0,0 +1,1414 @@ +/* + * Copyright (C) 2011-2013 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/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/ion.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6q.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.h> +#include <mach/ahci_sata.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_hdmi.h> +#include <mach/mxc_asrc.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 "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" + +#define MX6Q_SABRELITE_SD3_CD IMX_GPIO_NR(7, 0) +#define MX6Q_SABRELITE_SD3_WP IMX_GPIO_NR(7, 1) +#define MX6Q_SABRELITE_SD4_CD IMX_GPIO_NR(2, 6) +#define MX6Q_SABRELITE_SD4_WP IMX_GPIO_NR(2, 7) +#define MX6Q_SABRELITE_ECSPI1_CS1 IMX_GPIO_NR(3, 19) +#define MX6Q_SABRELITE_USB_OTG_PWR IMX_GPIO_NR(3, 22) +#define MX6Q_SABRELITE_CAP_TCH_INT1 IMX_GPIO_NR(1, 9) +#define MX6Q_SABRELITE_USB_HUB_RESET IMX_GPIO_NR(7, 12) +#define MX6Q_SABRELITE_CAN1_STBY IMX_GPIO_NR(1, 2) +#define MX6Q_SABRELITE_CAN1_EN IMX_GPIO_NR(1, 4) +#define MX6Q_SABRELITE_MENU_KEY IMX_GPIO_NR(2, 1) +#define MX6Q_SABRELITE_BACK_KEY IMX_GPIO_NR(2, 2) +#define MX6Q_SABRELITE_ONOFF_KEY IMX_GPIO_NR(2, 3) +#define MX6Q_SABRELITE_HOME_KEY IMX_GPIO_NR(2, 4) +#define MX6Q_SABRELITE_VOL_UP_KEY IMX_GPIO_NR(7, 13) +#define MX6Q_SABRELITE_VOL_DOWN_KEY IMX_GPIO_NR(4, 5) +#define MX6Q_SABRELITE_CSI0_RST IMX_GPIO_NR(1, 8) +#define MX6Q_SABRELITE_CSI0_PWN IMX_GPIO_NR(1, 6) + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO +#define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) +#define IOMUX_OBSRV_MUX1_OFFSET 0x3c +#define OBSRV_MUX1_MASK 0x3f +#define OBSRV_MUX1_ENET_IRQ 0x9 +#endif + +#define MX6Q_SABRELITE_SD3_WP_PADCFG (PAD_CTL_PKE | PAD_CTL_PUE | \ + PAD_CTL_PUS_22K_UP | PAD_CTL_SPEED_MED | \ + PAD_CTL_DSE_40ohm | PAD_CTL_HYS) + +void __init early_console_setup(unsigned long base, struct clk *clk); +static struct clk *sata_clk; + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; +static int caam_enabled; + +extern struct regulator *(*get_cpu_regulator)(void); +extern void (*put_cpu_regulator)(void); + +static iomux_v3_cfg_t mx6q_sabrelite_pads[] = { + /* AUDMUX */ + MX6Q_PAD_SD2_DAT0__AUDMUX_AUD4_RXD, + MX6Q_PAD_SD2_DAT3__AUDMUX_AUD4_TXC, + MX6Q_PAD_SD2_DAT2__AUDMUX_AUD4_TXD, + MX6Q_PAD_SD2_DAT1__AUDMUX_AUD4_TXFS, + + /* CAN1 */ + MX6Q_PAD_KEY_ROW2__CAN1_RXCAN, + MX6Q_PAD_KEY_COL2__CAN1_TXCAN, + MX6Q_PAD_GPIO_2__GPIO_1_2, /* STNDBY */ + MX6Q_PAD_GPIO_7__GPIO_1_7, /* NERR */ + MX6Q_PAD_GPIO_4__GPIO_1_4, /* Enable */ + + /* CCM */ + MX6Q_PAD_GPIO_0__CCM_CLKO, /* SGTL500 sys_mclk */ + MX6Q_PAD_GPIO_3__CCM_CLKO2, /* J5 - Camera MCLK */ + + /* ECSPI1 */ + MX6Q_PAD_EIM_D17__ECSPI1_MISO, + MX6Q_PAD_EIM_D18__ECSPI1_MOSI, + MX6Q_PAD_EIM_D16__ECSPI1_SCLK, + MX6Q_PAD_EIM_D19__GPIO_3_19, /*SS1*/ + + /* ENET */ + MX6Q_PAD_ENET_MDIO__ENET_MDIO, + MX6Q_PAD_ENET_MDC__ENET_MDC, + MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6Q_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6Q_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, + MX6Q_PAD_ENET_TX_EN__GPIO_1_28, /* Micrel RGMII Phy Interrupt */ + MX6Q_PAD_EIM_D23__GPIO_3_23, /* RGMII reset */ + + /* GPIO1 */ + MX6Q_PAD_ENET_RX_ER__GPIO_1_24, /* J9 - Microphone Detect */ + + /* GPIO2 */ + MX6Q_PAD_NANDF_D1__GPIO_2_1, /* J14 - Menu Button */ + MX6Q_PAD_NANDF_D2__GPIO_2_2, /* J14 - Back Button */ + MX6Q_PAD_NANDF_D3__GPIO_2_3, /* J14 - Search Button */ + MX6Q_PAD_NANDF_D4__GPIO_2_4, /* J14 - Home Button */ + MX6Q_PAD_EIM_A22__GPIO_2_16, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A21__GPIO_2_17, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A20__GPIO_2_18, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A19__GPIO_2_19, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A18__GPIO_2_20, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A17__GPIO_2_21, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A16__GPIO_2_22, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_RW__GPIO_2_26, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_LBA__GPIO_2_27, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_EB0__GPIO_2_28, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_EB1__GPIO_2_29, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_EB3__GPIO_2_31, /* J12 - Boot Mode Select */ + + /* GPIO3 */ + MX6Q_PAD_EIM_DA0__GPIO_3_0, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA1__GPIO_3_1, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA2__GPIO_3_2, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA3__GPIO_3_3, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA4__GPIO_3_4, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA5__GPIO_3_5, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA6__GPIO_3_6, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA7__GPIO_3_7, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA8__GPIO_3_8, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA9__GPIO_3_9, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA10__GPIO_3_10, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA11__GPIO_3_11, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA12__GPIO_3_12, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA13__GPIO_3_13, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA14__GPIO_3_14, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA15__GPIO_3_15, /* J12 - Boot Mode Select */ + + /* GPIO4 */ + MX6Q_PAD_GPIO_19__GPIO_4_5, /* J14 - Volume Down */ + + /* GPIO5 */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A24__GPIO_5_4, /* J12 - Boot Mode Select */ + + /* GPIO6 */ + MX6Q_PAD_EIM_A23__GPIO_6_6, /* J12 - Boot Mode Select */ + + /* GPIO7 */ + MX6Q_PAD_GPIO_17__GPIO_7_12, /* USB Hub Reset */ + MX6Q_PAD_GPIO_18__GPIO_7_13, /* J14 - Volume Up */ + + /* I2C1, SGTL5000 */ + MX6Q_PAD_EIM_D21__I2C1_SCL, /* GPIO3[21] */ + MX6Q_PAD_EIM_D28__I2C1_SDA, /* GPIO3[28] */ + + /* I2C2 Camera, MIPI */ + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* GPIO4[12] */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* GPIO4[13] */ + + /* I2C3 */ + MX6Q_PAD_GPIO_5__I2C3_SCL, /* GPIO1[5] - J7 - Display card */ +#ifdef CONFIG_FEC_1588 + MX6Q_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, +#else + MX6Q_PAD_GPIO_16__I2C3_SDA, /* GPIO7[11] - J15 - RGB connector */ +#endif + + /* DISPLAY */ + MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15, /* DE */ + MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2, /* HSync */ + MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3, /* VSync */ + MX6Q_PAD_DI0_PIN4__IPU1_DI0_PIN4, /* Contrast */ + MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20, + MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22, + MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23, + MX6Q_PAD_GPIO_7__GPIO_1_7, /* J7 - Display Connector GP */ + MX6Q_PAD_GPIO_9__GPIO_1_9, /* J7 - Display Connector GP */ + MX6Q_PAD_NANDF_D0__GPIO_2_0, /* J6 - LVDS Display contrast */ + + + /* PWM1 */ + MX6Q_PAD_SD1_DAT3__PWM1_PWMO, /* GPIO1[21] */ + + /* PWM2 */ + MX6Q_PAD_SD1_DAT2__PWM2_PWMO, /* GPIO1[19] */ + + /* PWM3 */ + MX6Q_PAD_SD1_DAT1__PWM3_PWMO, /* GPIO1[17] */ + + /* PWM4 */ + MX6Q_PAD_SD1_CMD__PWM4_PWMO, /* GPIO1[18] */ + + /* UART1 */ + MX6Q_PAD_SD3_DAT7__UART1_TXD, + MX6Q_PAD_SD3_DAT6__UART1_RXD, + + /* UART2 for debug */ + MX6Q_PAD_EIM_D26__UART2_TXD, + MX6Q_PAD_EIM_D27__UART2_RXD, + + /* USBOTG ID pin */ + MX6Q_PAD_GPIO_1__USBOTG_ID, + + /* USB OC pin */ + MX6Q_PAD_KEY_COL4__USBOH3_USBOTG_OC, + MX6Q_PAD_EIM_D30__USBOH3_USBH1_OC, + + /* USDHC3 */ + MX6Q_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6Q_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6Q_PAD_SD3_DAT5__GPIO_7_0, /* J18 - SD3_CD */ + NEW_PAD_CTRL(MX6Q_PAD_SD3_DAT4__GPIO_7_1, MX6Q_SABRELITE_SD3_WP_PADCFG), + + /* USDHC4 */ + MX6Q_PAD_SD4_CLK__USDHC4_CLK_50MHZ, + MX6Q_PAD_SD4_CMD__USDHC4_CMD_50MHZ, + MX6Q_PAD_SD4_DAT0__USDHC4_DAT0_50MHZ, + MX6Q_PAD_SD4_DAT1__USDHC4_DAT1_50MHZ, + MX6Q_PAD_SD4_DAT2__USDHC4_DAT2_50MHZ, + MX6Q_PAD_SD4_DAT3__USDHC4_DAT3_50MHZ, + MX6Q_PAD_NANDF_D6__GPIO_2_6, /* J20 - SD4_CD */ + MX6Q_PAD_NANDF_D7__GPIO_2_7, /* SD4_WP */ +}; + +static iomux_v3_cfg_t mx6q_sabrelite_csi0_sensor_pads[] = { + /* IPU1 Camera */ + MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8, + MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9, + MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10, + MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11, + MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN, + MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, +#ifndef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6Q_PAD_GPIO_6__GPIO_1_6, /* J5 - Camera GP */ +#endif + MX6Q_PAD_GPIO_8__GPIO_1_8, /* J5 - Camera Reset */ + MX6Q_PAD_SD1_DAT0__GPIO_1_16, /* J5 - Camera GP */ + MX6Q_PAD_NANDF_D5__GPIO_2_5, /* J16 - MIPI GP */ + MX6Q_PAD_NANDF_WP_B__GPIO_6_9, /* J16 - MIPI GP */ +}; + +static iomux_v3_cfg_t mx6q_sabrelite_hdmi_ddc_pads[] = { + MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6q_sabrelite_i2c2_pads[] = { + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; + +#define MX6Q_USDHC_PAD_SETTING(id, speed) \ +mx6q_sd##id##_##speed##mhz[] = { \ + MX6Q_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6Q_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6Q_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ +} + +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 50); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 100); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(3, 200); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(4, 50); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(4, 100); +static iomux_v3_cfg_t MX6Q_USDHC_PAD_SETTING(4, 200); + +enum sd_pad_mode { + SD_PAD_MODE_LOW_SPEED, + SD_PAD_MODE_MED_SPEED, + SD_PAD_MODE_HIGH_SPEED, +}; + +static int plt_sd_pad_change(unsigned int index, int clock) +{ + /* LOW speed is the default state of SD pads */ + static enum sd_pad_mode pad_mode = SD_PAD_MODE_LOW_SPEED; + + iomux_v3_cfg_t *sd_pads_200mhz = NULL; + iomux_v3_cfg_t *sd_pads_100mhz = NULL; + iomux_v3_cfg_t *sd_pads_50mhz = NULL; + + u32 sd_pads_200mhz_cnt; + u32 sd_pads_100mhz_cnt; + u32 sd_pads_50mhz_cnt; + + switch (index) { + case 2: + sd_pads_200mhz = mx6q_sd3_200mhz; + sd_pads_100mhz = mx6q_sd3_100mhz; + sd_pads_50mhz = mx6q_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6q_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6q_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6q_sd3_50mhz); + break; + case 3: + sd_pads_200mhz = mx6q_sd4_200mhz; + sd_pads_100mhz = mx6q_sd4_100mhz; + sd_pads_50mhz = mx6q_sd4_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6q_sd4_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6q_sd4_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6q_sd4_50mhz); + break; + default: + printk(KERN_ERR "no such SD host controller index %d\n", index); + return -EINVAL; + } + + if (clock > 100000000) { + if (pad_mode == SD_PAD_MODE_HIGH_SPEED) + return 0; + BUG_ON(!sd_pads_200mhz); + pad_mode = SD_PAD_MODE_HIGH_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_200mhz, + sd_pads_200mhz_cnt); + } else if (clock > 52000000) { + if (pad_mode == SD_PAD_MODE_MED_SPEED) + return 0; + BUG_ON(!sd_pads_100mhz); + pad_mode = SD_PAD_MODE_MED_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_100mhz, + sd_pads_100mhz_cnt); + } else { + if (pad_mode == SD_PAD_MODE_LOW_SPEED) + return 0; + BUG_ON(!sd_pads_50mhz); + pad_mode = SD_PAD_MODE_LOW_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_50mhz, + sd_pads_50mhz_cnt); + } +} + +static const struct esdhc_platform_data mx6q_sabrelite_sd3_data __initconst = { + .cd_gpio = MX6Q_SABRELITE_SD3_CD, + .wp_gpio = MX6Q_SABRELITE_SD3_WP, + .keep_power_at_suspend = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct esdhc_platform_data mx6q_sabrelite_sd4_data __initconst = { + .cd_gpio = MX6Q_SABRELITE_SD4_CD, + .wp_gpio = MX6Q_SABRELITE_SD4_WP, + .keep_power_at_suspend = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct anatop_thermal_platform_data + mx6q_sabrelite_anatop_thermal_data __initconst = { + .name = "anatop_thermal", +}; + +static inline void mx6q_sabrelite_init_uart(void) +{ + imx6q_add_imx_uart(0, NULL); + imx6q_add_imx_uart(1, NULL); +} + +static int mx6q_sabrelite_fec_phy_init(struct phy_device *phydev) +{ + /* prefer master mode, disable 1000 Base-T capable */ + phy_write(phydev, 0x9, 0x1c00); + + /* min rx data delay */ + phy_write(phydev, 0x0b, 0x8105); + phy_write(phydev, 0x0c, 0x0000); + + /* max rx/tx clock delay, min rx/tx control delay */ + phy_write(phydev, 0x0b, 0x8104); + phy_write(phydev, 0x0c, 0xf0f0); + phy_write(phydev, 0x0b, 0x104); + + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6q_sabrelite_fec_phy_init, + .phy = PHY_INTERFACE_MODE_RGMII, +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + .gpio_irq = MX6_ENET_IRQ, +#endif +}; + +static int mx6q_sabrelite_spi_cs[] = { + MX6Q_SABRELITE_ECSPI1_CS1, +}; + +static const struct spi_imx_master mx6q_sabrelite_spi_data __initconst = { + .chipselect = mx6q_sabrelite_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6q_sabrelite_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition imx6_sabrelite_spi_nor_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00100000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data imx6_sabrelite__spi_flash_data = { + .name = "m25p80", + .parts = imx6_sabrelite_spi_nor_partitions, + .nr_parts = ARRAY_SIZE(imx6_sabrelite_spi_nor_partitions), + .type = "sst25vf016b", +}; +#endif + +static struct spi_board_info imx6_sabrelite_spi_nor_device[] __initdata = { +#if defined(CONFIG_MTD_M25P80) + { + .modalias = "m25p80", + .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, + .chip_select = 0, + .platform_data = &imx6_sabrelite__spi_flash_data, + }, +#endif +}; + +static void spi_device_init(void) +{ + spi_register_board_info(imx6_sabrelite_spi_nor_device, + ARRAY_SIZE(imx6_sabrelite_spi_nor_device)); +} + +static struct mxc_audio_platform_data mx6_sabrelite_audio_data; + +static int mx6_sabrelite_sgtl5000_init(void) +{ + struct clk *clko; + struct clk *new_parent; + int rate; + + clko = clk_get(NULL, "clko_clk"); + if (IS_ERR(clko)) { + pr_err("can't get CLKO clock.\n"); + return PTR_ERR(clko); + } + new_parent = clk_get(NULL, "ahb"); + if (!IS_ERR(new_parent)) { + clk_set_parent(clko, new_parent); + clk_put(new_parent); + } + rate = clk_round_rate(clko, 16000000); + if (rate < 8000000 || rate > 27000000) { + pr_err("Error:SGTL5000 mclk freq %d out of range!\n", rate); + clk_put(clko); + return -1; + } + + mx6_sabrelite_audio_data.sysclk = rate; + clk_set_rate(clko, rate); + clk_enable(clko); + return 0; +} + +static struct imx_ssi_platform_data mx6_sabrelite_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct mxc_audio_platform_data mx6_sabrelite_audio_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 4, + .init = mx6_sabrelite_sgtl5000_init, + .hp_gpio = -1, +}; + +static struct platform_device mx6_sabrelite_audio_device = { + .name = "imx-sgtl5000", +}; + +static struct imxi2c_platform_data mx6q_sabrelite_i2c_data = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("sgtl5000", 0x0a), + }, +}; + +static void mx6q_csi0_cam_powerdown(int powerdown) +{ + if (powerdown) + gpio_set_value(MX6Q_SABRELITE_CSI0_PWN, 1); + else + gpio_set_value(MX6Q_SABRELITE_CSI0_PWN, 0); + + msleep(2); +} + +static void mx6q_csi0_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_csi0_sensor_pads, + ARRAY_SIZE(mx6q_sabrelite_csi0_sensor_pads)); + + /* Camera power down */ + gpio_request(MX6Q_SABRELITE_CSI0_PWN, "cam-pwdn"); + gpio_direction_output(MX6Q_SABRELITE_CSI0_PWN, 1); + msleep(1); + gpio_set_value(MX6Q_SABRELITE_CSI0_PWN, 0); + + /* Camera reset */ + gpio_request(MX6Q_SABRELITE_CSI0_RST, "cam-reset"); + gpio_direction_output(MX6Q_SABRELITE_CSI0_RST, 1); + + gpio_set_value(MX6Q_SABRELITE_CSI0_RST, 0); + msleep(1); + gpio_set_value(MX6Q_SABRELITE_CSI0_RST, 1); + + /* For MX6Q GPR1 bit19 and bit20 meaning: + * Bit19: 0 - Enable mipi to IPU1 CSI0 + * virtual channel is fixed to 0 + * 1 - Enable parallel interface to IPU1 CSI0 + * Bit20: 0 - Enable mipi to IPU2 CSI1 + * virtual channel is fixed to 3 + * 1 - Enable parallel interface to IPU2 CSI1 + * IPU1 CSI1 directly connect to mipi csi2, + * virtual channel is fixed to 1 + * IPU2 CSI0 directly connect to mipi csi2, + * virtual channel is fixed to 2 + */ + mxc_iomux_set_gpr_register(1, 19, 1, 1); +} + +static struct fsl_mxc_camera_platform_data camera_data = { + .mclk = 24000000, + .mclk_source = 0, + .csi = 0, + .io_init = mx6q_csi0_io_init, + .pwdn = mx6q_csi0_cam_powerdown, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50), + }, + { + I2C_BOARD_INFO("ov564x", 0x3c), + .platform_data = (void *)&camera_data, + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("egalax_ts", 0x4), + .irq = gpio_to_irq(MX6Q_SABRELITE_CAP_TCH_INT1), + }, +}; + +static void imx6q_sabrelite_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(MX6Q_SABRELITE_USB_OTG_PWR, 1); + else + gpio_set_value(MX6Q_SABRELITE_USB_OTG_PWR, 0); +} + +static void __init imx6q_sabrelite_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + /* disable external charger detect, + * or it will affect signal quality at dp . + */ + ret = gpio_request(MX6Q_SABRELITE_USB_OTG_PWR, "usb-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6Q_SABRELITE_USB_OTG_PWR: %d\n", + ret); + return; + } + gpio_direction_output(MX6Q_SABRELITE_USB_OTG_PWR, 0); + mxc_iomux_set_gpr_register(1, 13, 1, 1); + + mx6_set_otghost_vbus_func(imx6q_sabrelite_usbotg_vbus); + mx6_usb_dr_init(); +} + +/* HW Initialization, if return 0, initialization is successful. */ +static int mx6q_sabrelite_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; + } + + /* Set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write is 0x07FFFFFD, + * and the other one write for setting the mpll_clk_off_b + *.rx_eq_val_0(iomuxc_gpr13[26:24]), + *.los_lvl(iomuxc_gpr13[23:19]), + *.rx_dpll_mode_0(iomuxc_gpr13[18:16]), + *.sata_speed(iomuxc_gpr13[15]), + *.mpll_ss_en(iomuxc_gpr13[14]), + *.tx_atten_0(iomuxc_gpr13[13:11]), + *.tx_boost_0(iomuxc_gpr13[10:7]), + *.tx_lvl(iomuxc_gpr13[6:2]), + *.mpll_ck_off(iomuxc_gpr13[1]), + *.tx_edgerate_0(iomuxc_gpr13[0]), + */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13); + + /* enable SATA_PHY PLL */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13); + + /* Get the AHB clock rate, and configure the TIMER1MS reg later */ + clk = clk_get(NULL, "ahb"); + if (IS_ERR(clk)) { + dev_err(dev, "no ahb clock.\n"); + ret = PTR_ERR(clk); + goto release_sata_clk; + } + tmpdata = clk_get_rate(clk) / 1000; + clk_put(clk); + +#ifdef CONFIG_SATA_AHCI_PLATFORM + ret = sata_init(addr, tmpdata); + if (ret == 0) + return ret; +#else + usleep_range(1000, 2000); + /* AHCI PHY enter into PDDQ mode if the AHCI module is not enabled */ + tmpdata = readl(addr + PORT_PHY_CTL); + writel(tmpdata | PORT_PHY_CTL_PDDQ_LOC, addr + PORT_PHY_CTL); + pr_info("No AHCI save PWR: PDDQ %s\n", ((readl(addr + PORT_PHY_CTL) + >> 20) & 1) ? "enabled" : "disabled"); +#endif + +release_sata_clk: + /* disable SATA_PHY PLL */ + writel((readl(IOMUXC_GPR13) & ~0x2), IOMUXC_GPR13); + clk_disable(sata_clk); +put_sata_clk: + clk_put(sata_clk); + + return ret; +} + +#ifdef CONFIG_SATA_AHCI_PLATFORM +static void mx6q_sabrelite_sata_exit(struct device *dev) +{ + clk_disable(sata_clk); + clk_put(sata_clk); +} + +static struct ahci_platform_data mx6q_sabrelite_sata_data = { + .init = mx6q_sabrelite_sata_init, + .exit = mx6q_sabrelite_sata_exit, +}; +#endif + +static struct gpio mx6q_sabrelite_flexcan_gpios[] = { + { MX6Q_SABRELITE_CAN1_EN, GPIOF_OUT_INIT_LOW, "flexcan1-en" }, + { MX6Q_SABRELITE_CAN1_STBY, GPIOF_OUT_INIT_LOW, "flexcan1-stby" }, +}; + +static void mx6q_sabrelite_flexcan0_switch(int enable) +{ + if (enable) { + gpio_set_value(MX6Q_SABRELITE_CAN1_EN, 1); + gpio_set_value(MX6Q_SABRELITE_CAN1_STBY, 1); + } else { + gpio_set_value(MX6Q_SABRELITE_CAN1_EN, 0); + gpio_set_value(MX6Q_SABRELITE_CAN1_STBY, 0); + } +} + +static const struct flexcan_platform_data + mx6q_sabrelite_flexcan0_pdata __initconst = { + .transceiver_switch = mx6q_sabrelite_flexcan0_switch, +}; + +static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_128M + SZ_64M, +}; + +static struct imx_asrc_platform_data imx_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static struct ipuv3_fb_platform_data sabrelite_fb_data[] = { + { /*fb0*/ + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + }, { + .disp_dev = "lcd", + .interface_pix_fmt = IPU_PIX_FMT_RGB565, + .mode_str = "CLAA-WVGA", + .default_bpp = 16, + .int_clk = false, + }, { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-SVGA", + .default_bpp = 16, + .int_clk = false, + }, { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-VGA", + .default_bpp = 16, + .int_clk = false, + }, +}; + +static void hdmi_init(int ipu_id, int disp_id) +{ + int hdmi_mux_setting; + + if ((ipu_id > 1) || (ipu_id < 0)) { + pr_err("Invalid IPU select for HDMI: %d. Set to 0\n", ipu_id); + ipu_id = 0; + } + + if ((disp_id > 1) || (disp_id < 0)) { + pr_err("Invalid DI select for HDMI: %d. Set to 0\n", disp_id); + disp_id = 0; + } + + /* Configure the connection between IPU1/2 and HDMI */ + hdmi_mux_setting = 2*ipu_id + disp_id; + + /* GPR3, bits 2-3 = HDMI_MUX_CTL */ + mxc_iomux_set_gpr_register(3, 2, 2, hdmi_mux_setting); + + /* Set HDMI event as SDMA event2 while Chip version later than TO1.2 */ + if ((mx6q_revision() > IMX_CHIP_REVISION_1_1)) + mxc_iomux_set_gpr_register(0, 0, 1, 1); +} + +/* On mx6x sbarelite board i2c2 iomux with hdmi ddc, + * the pins default work at i2c2 function, + when hdcp enable, the pins should work at ddc function */ + +static void hdmi_enable_ddc_pin(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_hdmi_ddc_pads, + ARRAY_SIZE(mx6q_sabrelite_hdmi_ddc_pads)); +} + +static void hdmi_disable_ddc_pin(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_i2c2_pads, + ARRAY_SIZE(mx6q_sabrelite_i2c2_pads)); +} + +static struct fsl_mxc_hdmi_platform_data hdmi_data = { + .init = hdmi_init, + .enable_pins = hdmi_enable_ddc_pin, + .disable_pins = hdmi_disable_ddc_pin, +}; + +static struct fsl_mxc_hdmi_core_platform_data hdmi_core_data = { + .ipu_id = 0, + .disp_id = 0, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 1, + .disp_id = 0, + .ext_ref = 1, + .mode = LDB_SEP0, + .sec_ipu_id = 1, + .sec_disp_id = 1, +}; + +static struct imx_ipuv3_platform_data ipu_data[] = { + { + .rev = 4, + .csi_clk[0] = "clko2_clk", + }, { + .rev = 4, + .csi_clk[0] = "clko2_clk", + }, +}; + +static struct ion_platform_data imx_ion_data = { + .nr = 1, + .heaps = { + { + .type = ION_HEAP_TYPE_CARVEOUT, + .name = "vpu_ion", + .size = SZ_64M, + }, + }, +}; + +static struct fsl_mxc_capture_platform_data capture_data[] = { + { + .csi = 0, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 0, + }, { + .csi = 1, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 1, + }, +}; + + +struct imx_vout_mem { + resource_size_t res_mbase; + resource_size_t res_msize; +}; + +static struct imx_vout_mem vout_mem __initdata = { + .res_msize = SZ_128M, +}; + + +static void sabrelite_suspend_enter(void) +{ + /* suspend preparation */ +} + +static void sabrelite_suspend_exit(void) +{ + /* resume restore */ +} +static const struct pm_platform_data mx6q_sabrelite_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = sabrelite_suspend_enter, + .suspend_exit = sabrelite_suspend_exit, +}; + +#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 sabrelite_buttons[] = { + GPIO_BUTTON(MX6Q_SABRELITE_ONOFF_KEY, KEY_POWER, 1, "key-power", 1), + GPIO_BUTTON(MX6Q_SABRELITE_MENU_KEY, KEY_MENU, 1, "key-memu", 0), + GPIO_BUTTON(MX6Q_SABRELITE_HOME_KEY, KEY_HOME, 1, "key-home", 0), + GPIO_BUTTON(MX6Q_SABRELITE_BACK_KEY, KEY_BACK, 1, "key-back", 0), + GPIO_BUTTON(MX6Q_SABRELITE_VOL_UP_KEY, KEY_VOLUMEUP, 1, "volume-up", 0), + GPIO_BUTTON(MX6Q_SABRELITE_VOL_DOWN_KEY, KEY_VOLUMEDOWN, 1, "volume-down", 0), +}; + +static struct gpio_keys_platform_data sabrelite_button_data = { + .buttons = sabrelite_buttons, + .nbuttons = ARRAY_SIZE(sabrelite_buttons), +}; + +static struct platform_device sabrelite_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &sabrelite_button_data, + } +}; + +static void __init sabrelite_add_device_buttons(void) +{ + platform_device_register(&sabrelite_button_device); +} +#else +static void __init sabrelite_add_device_buttons(void) {} +#endif + +static struct regulator_consumer_supply sabrelite_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; + +static struct regulator_init_data sabrelite_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(sabrelite_vmmc_consumers), + .consumer_supplies = sabrelite_vmmc_consumers, +}; + +static struct fixed_voltage_config sabrelite_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &sabrelite_vmmc_init, +}; + +static struct platform_device sabrelite_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 3, + .dev = { + .platform_data = &sabrelite_vmmc_reg_config, + }, +}; + +#ifdef CONFIG_SND_SOC_SGTL5000 + +static struct regulator_consumer_supply sgtl5000_sabrelite_consumer_vdda = { + .supply = "VDDA", + .dev_name = "0-000a", +}; + +static struct regulator_consumer_supply sgtl5000_sabrelite_consumer_vddio = { + .supply = "VDDIO", + .dev_name = "0-000a", +}; + +static struct regulator_consumer_supply sgtl5000_sabrelite_consumer_vddd = { + .supply = "VDDD", + .dev_name = "0-000a", +}; + +static struct regulator_init_data sgtl5000_sabrelite_vdda_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &sgtl5000_sabrelite_consumer_vdda, +}; + +static struct regulator_init_data sgtl5000_sabrelite_vddio_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &sgtl5000_sabrelite_consumer_vddio, +}; + +static struct regulator_init_data sgtl5000_sabrelite_vddd_reg_initdata = { + .num_consumer_supplies = 1, + .consumer_supplies = &sgtl5000_sabrelite_consumer_vddd, +}; + +static struct fixed_voltage_config sgtl5000_sabrelite_vdda_reg_config = { + .supply_name = "VDDA", + .microvolts = 2500000, + .gpio = -1, + .init_data = &sgtl5000_sabrelite_vdda_reg_initdata, +}; + +static struct fixed_voltage_config sgtl5000_sabrelite_vddio_reg_config = { + .supply_name = "VDDIO", + .microvolts = 3300000, + .gpio = -1, + .init_data = &sgtl5000_sabrelite_vddio_reg_initdata, +}; + +static struct fixed_voltage_config sgtl5000_sabrelite_vddd_reg_config = { + .supply_name = "VDDD", + .microvolts = 0, + .gpio = -1, + .init_data = &sgtl5000_sabrelite_vddd_reg_initdata, +}; + +static struct platform_device sgtl5000_sabrelite_vdda_reg_devices = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &sgtl5000_sabrelite_vdda_reg_config, + }, +}; + +static struct platform_device sgtl5000_sabrelite_vddio_reg_devices = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &sgtl5000_sabrelite_vddio_reg_config, + }, +}; + +static struct platform_device sgtl5000_sabrelite_vddd_reg_devices = { + .name = "reg-fixed-voltage", + .id = 2, + .dev = { + .platform_data = &sgtl5000_sabrelite_vddd_reg_config, + }, +}; + +#endif /* CONFIG_SND_SOC_SGTL5000 */ + +static int imx6q_init_audio(void) +{ + mxc_register_device(&mx6_sabrelite_audio_device, + &mx6_sabrelite_audio_data); + imx6q_add_imx_ssi(1, &mx6_sabrelite_ssi_pdata); +#ifdef CONFIG_SND_SOC_SGTL5000 + platform_device_register(&sgtl5000_sabrelite_vdda_reg_devices); + platform_device_register(&sgtl5000_sabrelite_vddio_reg_devices); + platform_device_register(&sgtl5000_sabrelite_vddd_reg_devices); +#endif + return 0; +} + +static struct platform_pwm_backlight_data mx6_sabrelite_pwm_backlight_data = { + .pwm_id = 3, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct mxc_dvfs_platform_data sabrelite_dvfscore_data = { + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + char *str; + struct tag *t; + int i = 0; + struct ipuv3_fb_platform_data *pdata_fb = sabrelite_fb_data; + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "fbmem="); + if (str != NULL) { + str += 6; + pdata_fb[i++].res_size[0] = memparse(str, &str); + while (*str == ',' && + i < ARRAY_SIZE(sabrelite_fb_data)) { + str++; + pdata_fb[i++].res_size[0] = memparse(str, &str); + } + } + break; + } + } +} + +static struct mipi_csi2_platform_data mipi_csi2_pdata = { + .ipu_id = 0, + .csi_id = 0, + .v_channel = 0, + .lanes = 2, + .dphy_clk = "mipi_pllref_clk", + .pixel_clk = "emi_clk", +}; + +static int __init caam_setup(char *__unused) +{ + caam_enabled = 1; + return 1; +} +early_param("caam", caam_setup); + +/*! + * Board specific initialization. + */ +static void __init mx6_sabrelite_board_init(void) +{ + int i; + int ret; + struct clk *clko2; + struct clk *new_parent; + int rate; + struct platform_device *voutdev; + + mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_pads, + ARRAY_SIZE(mx6q_sabrelite_pads)); + +#ifdef CONFIG_FEC_1588 + /* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock + * For MX6 GPR1 bit21 meaning: + * Bit21: 0 - GPIO_16 pad output + * 1 - GPIO_16 pad input + */ + mxc_iomux_set_gpr_register(1, 21, 1, 1); +#endif + + gp_reg_id = sabrelite_dvfscore_data.reg_id; + soc_reg_id = sabrelite_dvfscore_data.soc_id; + pu_reg_id = sabrelite_dvfscore_data.pu_id; + mx6q_sabrelite_init_uart(); + imx6q_add_mxc_hdmi_core(&hdmi_core_data); + + imx6q_add_ipuv3(0, &ipu_data[0]); + imx6q_add_ipuv3(1, &ipu_data[1]); + + for (i = 0; i < ARRAY_SIZE(sabrelite_fb_data); i++) + imx6q_add_ipuv3fb(i, &sabrelite_fb_data[i]); + + imx6q_add_vdoa(); + imx6q_add_lcdif(&lcdif_data); + imx6q_add_ldb(&ldb_data); + voutdev = imx6q_add_v4l2_output(0); + if (vout_mem.res_msize && voutdev) { + dma_declare_coherent_memory(&voutdev->dev, + vout_mem.res_mbase, + vout_mem.res_mbase, + vout_mem.res_msize, + (DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE)); + } + + + imx6q_add_v4l2_capture(0, &capture_data[0]); + imx6q_add_v4l2_capture(1, &capture_data[1]); + imx6q_add_mipi_csi2(&mipi_csi2_pdata); + imx6q_add_imx_snvs_rtc(); + + if (1 == caam_enabled) + imx6q_add_imx_caam(); + + imx6q_add_imx_i2c(0, &mx6q_sabrelite_i2c_data); + imx6q_add_imx_i2c(1, &mx6q_sabrelite_i2c_data); + imx6q_add_imx_i2c(2, &mx6q_sabrelite_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)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + /* SPI */ + imx6q_add_ecspi(0, &mx6q_sabrelite_spi_data); + spi_device_init(); + + imx6q_add_mxc_hdmi(&hdmi_data); + + imx6q_add_anatop_thermal_imx(1, &mx6q_sabrelite_anatop_thermal_data); + imx6_init_fec(fec_data); +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); +#endif + imx6q_add_pm_imx(0, &mx6q_sabrelite_pm_data); + imx6q_add_sdhci_usdhc_imx(3, &mx6q_sabrelite_sd4_data); + imx6q_add_sdhci_usdhc_imx(2, &mx6q_sabrelite_sd3_data); + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + imx6q_sabrelite_init_usb(); + + if (cpu_is_mx6q()) { +#ifdef CONFIG_SATA_AHCI_PLATFORM + imx6q_add_ahci(0, &mx6q_sabrelite_sata_data); +#else + mx6q_sabrelite_sata_init(NULL, + (void __iomem *)ioremap(MX6Q_SATA_BASE_ADDR, SZ_4K)); +#endif + } + imx6q_add_vpu(); + imx6q_init_audio(); + platform_device_register(&sabrelite_vmmc_reg_devices); + imx_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + imx_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + imx6q_add_asrc(&imx_asrc_data); + + /* release USB Hub reset */ + gpio_set_value(MX6Q_SABRELITE_USB_HUB_RESET, 1); + + imx6q_add_mxc_pwm(0); + imx6q_add_mxc_pwm(1); + imx6q_add_mxc_pwm(2); + imx6q_add_mxc_pwm(3); + imx6q_add_mxc_pwm_backlight(3, &mx6_sabrelite_pwm_backlight_data); + + imx6q_add_otp(); + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + imx6q_add_dma(); + + imx6q_add_dvfs_core(&sabrelite_dvfscore_data); + + imx6q_add_ion(0, &imx_ion_data, + sizeof(imx_ion_data) + sizeof(struct ion_platform_heap)); + + sabrelite_add_device_buttons(); + + imx6q_add_hdmi_soc(); + imx6q_add_hdmi_soc_dai(); + + ret = gpio_request_array(mx6q_sabrelite_flexcan_gpios, + ARRAY_SIZE(mx6q_sabrelite_flexcan_gpios)); + if (ret) + pr_err("failed to request flexcan1-gpios: %d\n", ret); + else + imx6q_add_flexcan0(&mx6q_sabrelite_flexcan0_pdata); + + clko2 = clk_get(NULL, "clko2_clk"); + if (IS_ERR(clko2)) + pr_err("can't get CLKO2 clock.\n"); + + new_parent = clk_get(NULL, "osc_clk"); + if (!IS_ERR(new_parent)) { + clk_set_parent(clko2, new_parent); + clk_put(new_parent); + } + rate = clk_round_rate(clko2, 24000000); + clk_set_rate(clko2, rate); + clk_enable(clko2); + imx6q_add_busfreq(); + + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); +} + +extern void __iomem *twd_base; +static void __init mx6_sabrelite_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART2_BASE_ADDR, uart_clk); +} + +static struct sys_timer mx6_sabrelite_timer = { + .init = mx6_sabrelite_timer_init, +}; + +static void __init mx6q_sabrelite_reserve(void) +{ + phys_addr_t phys; + int i; +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, SZ_1G); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif + +#if defined(CONFIG_ION) + if (imx_ion_data.heaps[0].size) { + phys = memblock_alloc(imx_ion_data.heaps[0].size, SZ_4K); + memblock_remove(phys, imx_ion_data.heaps[0].size); + imx_ion_data.heaps[0].base = phys; + } +#endif + + for (i = 0; i < ARRAY_SIZE(sabrelite_fb_data); i++) + if (sabrelite_fb_data[i].res_size[0]) { + /* reserve for background buffer */ + phys = memblock_alloc(sabrelite_fb_data[i].res_size[0], + SZ_4K); + memblock_remove(phys, sabrelite_fb_data[i].res_size[0]); + sabrelite_fb_data[i].res_base[0] = phys; + } + if (vout_mem.res_msize) { + phys = memblock_alloc_base(vout_mem.res_msize, + SZ_4K, SZ_1G); + memblock_remove(phys, vout_mem.res_msize); + vout_mem.res_mbase = phys; + } + +} + +/* + * initialize __mach_desc_MX6Q_SABRELITE data structure. + */ +MACHINE_START(MX6Q_SABRELITE, "Freescale i.MX 6Quad Sabre-Lite Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX6_PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_sabrelite_board_init, + .timer = &mx6_sabrelite_timer, + .reserve = mx6q_sabrelite_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.c b/arch/arm/mach-mx6/board-mx6q_sabresd.c new file mode 100644 index 00000000..f3209116 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_sabresd.c @@ -0,0 +1,2046 @@ +/* + * 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/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/ipu.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/ion.h> +#include <linux/etherdevice.h> +#include <linux/power/sabresd_battery.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> +#include <linux/mfd/wm8994/pdata.h> +#include <linux/mfd/wm8994/gpio.h> +#include <sound/wm8962.h> +#include <linux/mfd/mxc-hdmi-core.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6q.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.h> +#include <mach/ahci_sata.h> +#include <mach/ipu-v3.h> +#include <mach/mxc_hdmi.h> +#include <mach/mxc_asrc.h> +#include <mach/mipi_dsi.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 "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6q_sabresd.h" +#include "board-mx6dl_sabresd.h" + +#define SABRESD_USR_DEF_GRN_LED IMX_GPIO_NR(1, 1) +#define SABRESD_USR_DEF_RED_LED IMX_GPIO_NR(1, 2) +#define SABRESD_VOLUME_UP IMX_GPIO_NR(1, 4) +#define SABRESD_VOLUME_DN IMX_GPIO_NR(1, 5) +#define SABRESD_MICROPHONE_DET IMX_GPIO_NR(1, 9) +#define SABRESD_CSI0_PWN IMX_GPIO_NR(1, 16) +#define SABRESD_CSI0_RST IMX_GPIO_NR(1, 17) +#define SABRESD_ACCL_INT IMX_GPIO_NR(1, 18) +#define SABRESD_MIPICSI_PWN IMX_GPIO_NR(1, 19) +#define SABRESD_MIPICSI_RST IMX_GPIO_NR(1, 20) +#define SABRESD_RGMII_RST IMX_GPIO_NR(1, 25) +#define SABRESD_RGMII_INT IMX_GPIO_NR(1, 26) +#define SABRESD_CHARGE_UOK_B IMX_GPIO_NR(1, 27) +#define SABRESD_USBH1_PWR_EN IMX_GPIO_NR(1, 29) +#define SABRESD_DISP0_PWR_EN IMX_GPIO_NR(1, 30) + +#define SABRESD_SD3_CD IMX_GPIO_NR(2, 0) +#define SABRESD_SD3_WP IMX_GPIO_NR(2, 1) +#define SABRESD_SD2_CD IMX_GPIO_NR(2, 2) +#define SABRESD_SD2_WP IMX_GPIO_NR(2, 3) +#define SABRESD_CHARGE_DOK_B IMX_GPIO_NR(2, 24) +#define SABRESD_GPS_RESET IMX_GPIO_NR(2, 28) +#define SABRESD_SENSOR_EN IMX_GPIO_NR(2, 31) + +#define SABRESD_GPS_EN IMX_GPIO_NR(3, 0) +#define SABRESD_DISP0_RST_B IMX_GPIO_NR(3, 8) +#define SABRESD_ALS_INT IMX_GPIO_NR(3, 9) +#define SABRESD_CHARGE_CHG_2_B IMX_GPIO_NR(3, 13) +#define SABRESD_CHARGE_FLT_2_B IMX_GPIO_NR(3, 14) +#define SABRESD_BAR0_INT IMX_GPIO_NR(3, 15) +#define SABRESD_eCOMPASS_INT IMX_GPIO_NR(3, 16) +#define SABRESD_GPS_PPS IMX_GPIO_NR(3, 18) +#define SABRESD_PCIE_PWR_EN IMX_GPIO_NR(3, 19) +#define SABRESD_USB_OTG_PWR IMX_GPIO_NR(3, 22) +#define SABRESD_USB_H1_PWR IMX_GPIO_NR(1, 29) +#define SABRESD_CHARGE_CHG_1_B IMX_GPIO_NR(3, 23) +#define SABRESD_TS_INT IMX_GPIO_NR(3, 26) +#define SABRESD_DISP0_RD IMX_GPIO_NR(3, 28) +#define SABRESD_POWER_OFF IMX_GPIO_NR(3, 29) + +#define SABRESD_CAN1_STBY IMX_GPIO_NR(4, 5) +#define SABRESD_ECSPI1_CS0 IMX_GPIO_NR(4, 9) +#define SABRESD_CODEC_PWR_EN IMX_GPIO_NR(4, 10) +#define SABRESD_HDMI_CEC_IN IMX_GPIO_NR(4, 11) +#define SABRESD_PCIE_DIS_B IMX_GPIO_NR(4, 14) + +#define SABRESD_DI0_D0_CS IMX_GPIO_NR(5, 0) +#define SABRESD_CHARGE_FLT_1_B IMX_GPIO_NR(5, 2) +#define SABRESD_PCIE_WAKE_B IMX_GPIO_NR(5, 20) + +#define SABRESD_CAP_TCH_INT1 IMX_GPIO_NR(6, 7) +#define SABRESD_CAP_TCH_INT0 IMX_GPIO_NR(6, 8) +#define SABRESD_DISP_RST_B IMX_GPIO_NR(6, 11) +#define SABRESD_DISP_PWR_EN IMX_GPIO_NR(6, 14) +#define SABRESD_CABC_EN0 IMX_GPIO_NR(6, 15) +#define SABRESD_CABC_EN1 IMX_GPIO_NR(6, 16) +#define SABRESD_AUX_3V15_EN IMX_GPIO_NR(6, 9) +#define SABRESD_DISP0_WR_REVB IMX_GPIO_NR(6, 9) +#define SABRESD_AUX_5V_EN IMX_GPIO_NR(6, 10) +#define SABRESD_DI1_D0_CS IMX_GPIO_NR(6, 31) + +#define SABRESD_HEADPHONE_DET IMX_GPIO_NR(7, 8) +#define SABRESD_PCIE_RST_B_REVB IMX_GPIO_NR(7, 12) +#define SABRESD_PMIC_INT_B IMX_GPIO_NR(7, 13) +#define SABRESD_PFUZE_INT IMX_GPIO_NR(7, 13) + +#define SABRESD_EPDC_SDDO_0 IMX_GPIO_NR(2, 22) +#define SABRESD_EPDC_SDDO_1 IMX_GPIO_NR(3, 10) +#define SABRESD_EPDC_SDDO_2 IMX_GPIO_NR(3, 12) +#define SABRESD_EPDC_SDDO_3 IMX_GPIO_NR(3, 11) +#define SABRESD_EPDC_SDDO_4 IMX_GPIO_NR(2, 27) +#define SABRESD_EPDC_SDDO_5 IMX_GPIO_NR(2, 30) +#define SABRESD_EPDC_SDDO_6 IMX_GPIO_NR(2, 23) +#define SABRESD_EPDC_SDDO_7 IMX_GPIO_NR(2, 26) +#define SABRESD_EPDC_SDDO_8 IMX_GPIO_NR(2, 24) +#define SABRESD_EPDC_SDDO_9 IMX_GPIO_NR(3, 15) +#define SABRESD_EPDC_SDDO_10 IMX_GPIO_NR(3, 16) +#define SABRESD_EPDC_SDDO_11 IMX_GPIO_NR(3, 23) +#define SABRESD_EPDC_SDDO_12 IMX_GPIO_NR(3, 19) +#define SABRESD_EPDC_SDDO_13 IMX_GPIO_NR(3, 13) +#define SABRESD_EPDC_SDDO_14 IMX_GPIO_NR(3, 14) +#define SABRESD_EPDC_SDDO_15 IMX_GPIO_NR(5, 2) +#define SABRESD_EPDC_GDCLK IMX_GPIO_NR(2, 17) +#define SABRESD_EPDC_GDSP IMX_GPIO_NR(2, 16) +#define SABRESD_EPDC_GDOE IMX_GPIO_NR(6, 6) +#define SABRESD_EPDC_GDRL IMX_GPIO_NR(5, 4) +#define SABRESD_EPDC_SDCLK IMX_GPIO_NR(3, 31) +#define SABRESD_EPDC_SDOEZ IMX_GPIO_NR(3, 30) +#define SABRESD_EPDC_SDOED IMX_GPIO_NR(3, 26) +#define SABRESD_EPDC_SDOE IMX_GPIO_NR(3, 27) +#define SABRESD_EPDC_SDLE IMX_GPIO_NR(3, 1) +#define SABRESD_EPDC_SDCLKN IMX_GPIO_NR(3, 0) +#define SABRESD_EPDC_SDSHR IMX_GPIO_NR(2, 29) +#define SABRESD_EPDC_PWRCOM IMX_GPIO_NR(2, 28) +#define SABRESD_EPDC_PWRSTAT IMX_GPIO_NR(2, 21) +#define SABRESD_EPDC_PWRCTRL0 IMX_GPIO_NR(2, 20) +#define SABRESD_EPDC_PWRCTRL1 IMX_GPIO_NR(2, 19) +#define SABRESD_EPDC_PWRCTRL2 IMX_GPIO_NR(2, 18) +#define SABRESD_EPDC_PWRCTRL3 IMX_GPIO_NR(3, 28) +#define SABRESD_EPDC_BDR0 IMX_GPIO_NR(3, 2) +#define SABRESD_EPDC_BDR1 IMX_GPIO_NR(3, 3) +#define SABRESD_EPDC_SDCE0 IMX_GPIO_NR(3, 4) +#define SABRESD_EPDC_SDCE1 IMX_GPIO_NR(3, 5) +#define SABRESD_EPDC_SDCE2 IMX_GPIO_NR(3, 6) +#define SABRESD_EPDC_SDCE3 IMX_GPIO_NR(3, 7) +#define SABRESD_EPDC_SDCE4 IMX_GPIO_NR(3, 8) +#define SABRESD_EPDC_PMIC_WAKE IMX_GPIO_NR(3, 20) +#define SABRESD_EPDC_PMIC_INT IMX_GPIO_NR(2, 25) +#define SABRESD_EPDC_VCOM IMX_GPIO_NR(3, 17) +#define SABRESD_CHARGE_NOW IMX_GPIO_NR(1, 2) +#define SABRESD_CHARGE_DONE IMX_GPIO_NR(1, 1) +#define SABRESD_ELAN_CE IMX_GPIO_NR(2, 18) +#define SABRESD_ELAN_RST IMX_GPIO_NR(3, 8) +#define SABRESD_ELAN_INT IMX_GPIO_NR(3, 28) + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO +#define MX6_ENET_IRQ IMX_GPIO_NR(1, 6) +#define IOMUX_OBSRV_MUX1_OFFSET 0x3c +#define OBSRV_MUX1_MASK 0x3f +#define OBSRV_MUX1_ENET_IRQ 0x9 +#endif + +static struct clk *sata_clk; +static struct clk *clko; +static int mma8451_position = 1; +static int mag3110_position = 2; +static int max11801_mode = 1; +static int enable_lcd_ldb; + +static int caam_enabled; + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; +extern int epdc_enabled; + +static int max17135_regulator_init(struct max17135 *max17135); + +static const struct esdhc_platform_data mx6q_sabresd_sd2_data __initconst = { + .cd_gpio = SABRESD_SD2_CD, + .wp_gpio = SABRESD_SD2_WP, + .keep_power_at_suspend = 1, + .support_8bit = 1, + .delay_line = 0, + .cd_type = ESDHC_CD_CONTROLLER, + .runtime_pm = 1, +}; + +static const struct esdhc_platform_data mx6q_sabresd_sd3_data __initconst = { + .cd_gpio = SABRESD_SD3_CD, + .wp_gpio = SABRESD_SD3_WP, + .keep_power_at_suspend = 1, + .support_8bit = 1, + .delay_line = 0, + .cd_type = ESDHC_CD_CONTROLLER, +}; + +static const struct esdhc_platform_data mx6q_sabresd_sd4_data __initconst = { + .always_present = 1, + .keep_power_at_suspend = 1, + .support_8bit = 1, + .delay_line = 0, + .cd_type = ESDHC_CD_PERMANENT, +}; + +static const struct anatop_thermal_platform_data + mx6q_sabresd_anatop_thermal_data __initconst = { + .name = "anatop_thermal", +}; + +static inline void mx6q_sabresd_init_uart(void) +{ + imx6q_add_imx_uart(2, NULL); + imx6q_add_imx_uart(0, NULL); +} + +static int mx6q_sabresd_fec_phy_init(struct phy_device *phydev) +{ + unsigned short val; + + /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ + phy_write(phydev, 0xd, 0x7); + phy_write(phydev, 0xe, 0x8016); + phy_write(phydev, 0xd, 0x4007); + val = phy_read(phydev, 0xe); + + val &= 0xffe3; + val |= 0x18; + phy_write(phydev, 0xe, val); + + /* Introduce tx clock delay */ + phy_write(phydev, 0x1d, 0x5); + val = phy_read(phydev, 0x1e); + val |= 0x0100; + phy_write(phydev, 0x1e, val); + + /*check phy power*/ + val = phy_read(phydev, 0x0); + + if (val & BMCR_PDOWN) + phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); + + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6q_sabresd_fec_phy_init, + .phy = PHY_INTERFACE_MODE_RGMII, +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + .gpio_irq = MX6_ENET_IRQ, +#endif +}; + +static int mx6q_sabresd_spi_cs[] = { + SABRESD_ECSPI1_CS0, +}; + +static const struct spi_imx_master mx6q_sabresd_spi_data __initconst = { + .chipselect = mx6q_sabresd_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition imx6_sabresd_spi_nor_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00100000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct flash_platform_data imx6_sabresd__spi_flash_data = { + .name = "m25p80", + .parts = imx6_sabresd_spi_nor_partitions, + .nr_parts = ARRAY_SIZE(imx6_sabresd_spi_nor_partitions), + .type = "sst25vf016b", +}; +#endif + +static struct spi_board_info imx6_sabresd_spi_nor_device[] __initdata = { +#if defined(CONFIG_MTD_M25P80) + { + .modalias = "m25p80", + .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */ + .bus_num = 0, + .chip_select = 0, + .platform_data = &imx6_sabresd__spi_flash_data, + }, +#endif +}; + +static void spi_device_init(void) +{ + spi_register_board_info(imx6_sabresd_spi_nor_device, + ARRAY_SIZE(imx6_sabresd_spi_nor_device)); +} + +static struct imx_ssi_platform_data mx6_sabresd_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct platform_device mx6_sabresd_audio_wm8958_device = { + .name = "imx-wm8958", +}; + +static struct mxc_audio_platform_data wm8958_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_gpio = SABRESD_HEADPHONE_DET, + .hp_active_low = 1, +}; + +static struct wm8994_pdata wm8958_config_data = { + .gpio_defaults = { + [0] = WM8994_GP_FN_GPIO | WM8994_GPN_DB, + [1] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [2] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [3] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [4] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [5] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [7] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [8] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [9] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + [10] = WM8994_GP_FN_GPIO | WM8994_GPN_DB | WM8994_GPN_PD, + }, +}; + +static int mxc_wm8958_init(void) +{ + struct clk *clko; + int rate; + + clko = clk_get(NULL, "clko_clk"); + if (IS_ERR(clko)) { + pr_err("can't get CLKO clock.\n"); + return PTR_ERR(clko); + } + /* both audio codec and comera use CLKO clk*/ + rate = clk_round_rate(clko, 24000000); + + wm8958_data.sysclk = rate; + clk_set_rate(clko, rate); + + /* enable wm8958 4.2v power supply */ + gpio_request(SABRESD_CODEC_PWR_EN, "aud_4v2"); + gpio_direction_output(SABRESD_CODEC_PWR_EN, 1); + msleep(1); + gpio_set_value(SABRESD_CODEC_PWR_EN, 1); + + return 0; +} + +static struct platform_device mx6_sabresd_audio_wm8962_device = { + .name = "imx-wm8962", +}; + +static struct mxc_audio_platform_data wm8962_data; + +static int wm8962_clk_enable(int enable) +{ + if (enable) + clk_enable(clko); + else + clk_disable(clko); + + return 0; +} + +static int mxc_wm8962_init(void) +{ + int rate; + + clko = clk_get(NULL, "clko_clk"); + if (IS_ERR(clko)) { + pr_err("can't get CLKO clock.\n"); + return PTR_ERR(clko); + } + /* both audio codec and comera use CLKO clk*/ + rate = clk_round_rate(clko, 24000000); + clk_set_rate(clko, rate); + + wm8962_data.sysclk = rate; + + return 0; +} + +static struct wm8962_pdata wm8962_config_data = { + .gpio_init = { + [2] = WM8962_GPIO_FN_DMICCLK, + [4] = 0x8000 | WM8962_GPIO_FN_DMICDAT, + }, +}; + +static struct mxc_audio_platform_data wm8962_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_gpio = SABRESD_HEADPHONE_DET, + .hp_active_low = 1, + .mic_gpio = SABRESD_MICROPHONE_DET, + .mic_active_low = 1, + .init = mxc_wm8962_init, + .clock_enable = wm8962_clk_enable, +}; + +static struct regulator_consumer_supply sabresd_vwm8962_consumers[] = { + REGULATOR_SUPPLY("SPKVDD1", "0-001a"), + REGULATOR_SUPPLY("SPKVDD2", "0-001a"), +}; + +static struct regulator_init_data sabresd_vwm8962_init = { + .constraints = { + .name = "SPKVDD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sabresd_vwm8962_consumers), + .consumer_supplies = sabresd_vwm8962_consumers, +}; + +static struct fixed_voltage_config sabresd_vwm8962_reg_config = { + .supply_name = "SPKVDD", + .microvolts = 4200000, + .gpio = SABRESD_CODEC_PWR_EN, + .enable_high = 1, + .enabled_at_boot = 1, + .init_data = &sabresd_vwm8962_init, +}; + +static struct platform_device sabresd_vwm8962_reg_devices = { + .name = "reg-fixed-voltage", + .id = 4, + .dev = { + .platform_data = &sabresd_vwm8962_reg_config, + }, +}; + +static void mx6q_csi0_cam_powerdown(int powerdown) +{ + if (powerdown) + gpio_set_value(SABRESD_CSI0_PWN, 1); + else + gpio_set_value(SABRESD_CSI0_PWN, 0); + + msleep(2); +} + +static void mx6q_csi0_io_init(void) +{ + if (cpu_is_mx6q()) + mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_csi0_sensor_pads, + ARRAY_SIZE(mx6q_sabresd_csi0_sensor_pads)); + else if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_csi0_sensor_pads, + ARRAY_SIZE(mx6dl_sabresd_csi0_sensor_pads)); + + /* Camera reset */ + gpio_request(SABRESD_CSI0_RST, "cam-reset"); + gpio_direction_output(SABRESD_CSI0_RST, 1); + + /* Camera power down */ + gpio_request(SABRESD_CSI0_PWN, "cam-pwdn"); + gpio_direction_output(SABRESD_CSI0_PWN, 1); + msleep(5); + gpio_set_value(SABRESD_CSI0_PWN, 0); + msleep(5); + gpio_set_value(SABRESD_CSI0_RST, 0); + msleep(1); + gpio_set_value(SABRESD_CSI0_RST, 1); + msleep(5); + gpio_set_value(SABRESD_CSI0_PWN, 1); + + /* For MX6Q: + * GPR1 bit19 and bit20 meaning: + * Bit19: 0 - Enable mipi to IPU1 CSI0 + * virtual channel is fixed to 0 + * 1 - Enable parallel interface to IPU1 CSI0 + * Bit20: 0 - Enable mipi to IPU2 CSI1 + * virtual channel is fixed to 3 + * 1 - Enable parallel interface to IPU2 CSI1 + * IPU1 CSI1 directly connect to mipi csi2, + * virtual channel is fixed to 1 + * IPU2 CSI0 directly connect to mipi csi2, + * virtual channel is fixed to 2 + * + * For MX6DL: + * GPR13 bit 0-2 IPU_CSI0_MUX + * 000 MIPI_CSI0 + * 100 IPU CSI0 + */ + if (cpu_is_mx6q()) + mxc_iomux_set_gpr_register(1, 19, 1, 1); + else if (cpu_is_mx6dl()) + mxc_iomux_set_gpr_register(13, 0, 3, 4); +} + +static struct fsl_mxc_camera_platform_data camera_data = { + .mclk = 24000000, + .mclk_source = 0, + .csi = 0, + .io_init = mx6q_csi0_io_init, + .pwdn = mx6q_csi0_cam_powerdown, +}; + +static void mx6q_mipi_powerdown(int powerdown) +{ + if (powerdown) + gpio_set_value(SABRESD_MIPICSI_PWN, 1); + else + gpio_set_value(SABRESD_MIPICSI_PWN, 0); + + msleep(2); +} + +static void mx6q_mipi_sensor_io_init(void) +{ + if (cpu_is_mx6q()) + mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_mipi_sensor_pads, + ARRAY_SIZE(mx6q_sabresd_mipi_sensor_pads)); + else if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_mipi_sensor_pads, + ARRAY_SIZE(mx6dl_sabresd_mipi_sensor_pads)); + + /* Camera reset */ + gpio_request(SABRESD_MIPICSI_RST, "cam-reset"); + gpio_direction_output(SABRESD_MIPICSI_RST, 1); + + /* Camera power down */ + gpio_request(SABRESD_MIPICSI_PWN, "cam-pwdn"); + gpio_direction_output(SABRESD_MIPICSI_PWN, 1); + msleep(5); + gpio_set_value(SABRESD_MIPICSI_PWN, 0); + msleep(5); + gpio_set_value(SABRESD_MIPICSI_RST, 0); + msleep(1); + gpio_set_value(SABRESD_MIPICSI_RST, 1); + msleep(5); + gpio_set_value(SABRESD_MIPICSI_PWN, 1); + + /*for mx6dl, mipi virtual channel 1 connect to csi 1*/ + if (cpu_is_mx6dl()) + mxc_iomux_set_gpr_register(13, 3, 3, 1); +} + +static struct fsl_mxc_camera_platform_data mipi_csi2_data = { + .mclk = 24000000, + .mclk_source = 0, + .csi = 1, + .io_init = mx6q_mipi_sensor_io_init, + .pwdn = mx6q_mipi_powerdown, +}; + +#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 = SABRESD_EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = SABRESD_EPDC_VCOM, + .gpio_pmic_wakeup = SABRESD_EPDC_PMIC_WAKE, + .gpio_pmic_v3p3 = SABRESD_EPDC_PWRCTRL0, + .gpio_pmic_intr = SABRESD_EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int __init max17135_regulator_init(struct max17135 *max17135) +{ + struct max17135_platform_data *pdata = &max17135_pdata; + int i, ret; + + if (!epdc_enabled) { + printk(KERN_DEBUG + "max17135_regulator_init abort: EPDC not enabled\n"); + return 0; + } + + 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; + } + } + + /* + * TODO: We cannot enable full constraints for now, since + * it results in the PFUZE regulators being disabled + * at the end of boot, which disables critical regulators. + */ + /*regulator_has_full_constraints();*/ + + return 0; +} + +static struct imxi2c_platform_data mx6q_sabresd_i2c_data = { + .bitrate = 100000, +}; + +static struct fsl_mxc_lightsensor_platform_data ls_data = { + .rext = 499, /* calibration: 499K->700K */ +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("wm89**", 0x1a), + }, + { + I2C_BOARD_INFO("ov5642", 0x3c), + .platform_data = (void *)&camera_data, + }, + { + I2C_BOARD_INFO("mma8451", 0x1c), + .platform_data = (void *)&mma8451_position, + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50), + }, + { + I2C_BOARD_INFO("ov5640_mipi", 0x3c), + .platform_data = (void *)&mipi_csi2_data, + }, + { + I2C_BOARD_INFO("egalax_ts", 0x4), + .irq = gpio_to_irq(SABRESD_CAP_TCH_INT0), + }, + { + I2C_BOARD_INFO("max11801", 0x48), + .platform_data = (void *)&max11801_mode, + .irq = gpio_to_irq(SABRESD_TS_INT), + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0x48), + .platform_data = &max17135_pdata, + }, + { + I2C_BOARD_INFO("egalax_ts", 0x4), + .irq = gpio_to_irq(SABRESD_CAP_TCH_INT1), + }, + { + I2C_BOARD_INFO("mag3110", 0x0e), + .irq = gpio_to_irq(SABRESD_eCOMPASS_INT), + .platform_data = (void *)&mag3110_position, + }, + { + I2C_BOARD_INFO("isl29023", 0x44), + .irq = gpio_to_irq(SABRESD_ALS_INT), + .platform_data = &ls_data, + }, { + I2C_BOARD_INFO("elan-touch", 0x10), + .irq = gpio_to_irq(SABRESD_ELAN_INT), + }, + { + I2C_BOARD_INFO("mxc_ldb_i2c", 0x50), + .platform_data = (void *)0, + }, +}; + +static int epdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for EPDC pins - used during power up/down */ + ret |= gpio_request(SABRESD_EPDC_SDDO_0, "epdc_d0"); + ret |= gpio_request(SABRESD_EPDC_SDDO_1, "epdc_d1"); + ret |= gpio_request(SABRESD_EPDC_SDDO_2, "epdc_d2"); + ret |= gpio_request(SABRESD_EPDC_SDDO_3, "epdc_d3"); + ret |= gpio_request(SABRESD_EPDC_SDDO_4, "epdc_d4"); + ret |= gpio_request(SABRESD_EPDC_SDDO_5, "epdc_d5"); + ret |= gpio_request(SABRESD_EPDC_SDDO_6, "epdc_d6"); + ret |= gpio_request(SABRESD_EPDC_SDDO_7, "epdc_d7"); + ret |= gpio_request(SABRESD_EPDC_GDCLK, "epdc_gdclk"); + ret |= gpio_request(SABRESD_EPDC_GDSP, "epdc_gdsp"); + ret |= gpio_request(SABRESD_EPDC_GDOE, "epdc_gdoe"); + ret |= gpio_request(SABRESD_EPDC_GDRL, "epdc_gdrl"); + ret |= gpio_request(SABRESD_EPDC_SDCLK, "epdc_sdclk"); + ret |= gpio_request(SABRESD_EPDC_SDOE, "epdc_sdoe"); + ret |= gpio_request(SABRESD_EPDC_SDLE, "epdc_sdle"); + ret |= gpio_request(SABRESD_EPDC_SDSHR, "epdc_sdshr"); + ret |= gpio_request(SABRESD_EPDC_BDR0, "epdc_bdr0"); + ret |= gpio_request(SABRESD_EPDC_SDCE0, "epdc_sdce0"); + ret |= gpio_request(SABRESD_EPDC_SDCE1, "epdc_sdce1"); + ret |= gpio_request(SABRESD_EPDC_SDCE2, "epdc_sdce2"); + + return ret; +} + +static void epdc_put_pins(void) +{ + gpio_free(SABRESD_EPDC_SDDO_0); + gpio_free(SABRESD_EPDC_SDDO_1); + gpio_free(SABRESD_EPDC_SDDO_2); + gpio_free(SABRESD_EPDC_SDDO_3); + gpio_free(SABRESD_EPDC_SDDO_4); + gpio_free(SABRESD_EPDC_SDDO_5); + gpio_free(SABRESD_EPDC_SDDO_6); + gpio_free(SABRESD_EPDC_SDDO_7); + gpio_free(SABRESD_EPDC_GDCLK); + gpio_free(SABRESD_EPDC_GDSP); + gpio_free(SABRESD_EPDC_GDOE); + gpio_free(SABRESD_EPDC_GDRL); + gpio_free(SABRESD_EPDC_SDCLK); + gpio_free(SABRESD_EPDC_SDOE); + gpio_free(SABRESD_EPDC_SDLE); + gpio_free(SABRESD_EPDC_SDSHR); + gpio_free(SABRESD_EPDC_BDR0); + gpio_free(SABRESD_EPDC_SDCE0); + gpio_free(SABRESD_EPDC_SDCE1); + gpio_free(SABRESD_EPDC_SDCE2); +} + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_epdc_enable_pads, \ + ARRAY_SIZE(mx6dl_sabresd_epdc_enable_pads)); + + gpio_direction_input(SABRESD_EPDC_SDDO_0); + gpio_direction_input(SABRESD_EPDC_SDDO_1); + gpio_direction_input(SABRESD_EPDC_SDDO_2); + gpio_direction_input(SABRESD_EPDC_SDDO_3); + gpio_direction_input(SABRESD_EPDC_SDDO_4); + gpio_direction_input(SABRESD_EPDC_SDDO_5); + gpio_direction_input(SABRESD_EPDC_SDDO_6); + gpio_direction_input(SABRESD_EPDC_SDDO_7); + gpio_direction_input(SABRESD_EPDC_GDCLK); + gpio_direction_input(SABRESD_EPDC_GDSP); + gpio_direction_input(SABRESD_EPDC_GDOE); + gpio_direction_input(SABRESD_EPDC_GDRL); + gpio_direction_input(SABRESD_EPDC_SDCLK); + gpio_direction_input(SABRESD_EPDC_SDOE); + gpio_direction_input(SABRESD_EPDC_SDLE); + gpio_direction_input(SABRESD_EPDC_SDSHR); + gpio_direction_input(SABRESD_EPDC_BDR0); + gpio_direction_input(SABRESD_EPDC_SDCE0); + gpio_direction_input(SABRESD_EPDC_SDCE1); + gpio_direction_input(SABRESD_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(mx6dl_sabresd_epdc_disable_pads, \ + ARRAY_SIZE(mx6dl_sabresd_epdc_disable_pads)); + + gpio_direction_output(SABRESD_EPDC_SDDO_0, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_1, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_2, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_3, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_4, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_5, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_6, 0); + gpio_direction_output(SABRESD_EPDC_SDDO_7, 0); + gpio_direction_output(SABRESD_EPDC_GDCLK, 0); + gpio_direction_output(SABRESD_EPDC_GDSP, 0); + gpio_direction_output(SABRESD_EPDC_GDOE, 0); + gpio_direction_output(SABRESD_EPDC_GDRL, 0); + gpio_direction_output(SABRESD_EPDC_SDCLK, 0); + gpio_direction_output(SABRESD_EPDC_SDOE, 0); + gpio_direction_output(SABRESD_EPDC_SDLE, 0); + gpio_direction_output(SABRESD_EPDC_SDSHR, 0); + gpio_direction_output(SABRESD_EPDC_BDR0, 0); + gpio_direction_output(SABRESD_EPDC_SDCE0, 0); + gpio_direction_output(SABRESD_EPDC_SDCE1, 0); + gpio_direction_output(SABRESD_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, + .refresh = 85, + .xres = 800, + .yres = 600, +}; +static struct fb_videomode e060scm_mode = { + .name = "E060SCM", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 26666667, + .left_margin = 8, + .right_margin = 100, + .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 */ + }, + { + &e060scm_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 419, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 5, /* 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 void imx6q_sabresd_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(SABRESD_USB_OTG_PWR, 1); + else + gpio_set_value(SABRESD_USB_OTG_PWR, 0); +} + +static void __init imx6q_sabresd_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + /* disable external charger detect, + * or it will affect signal quality at dp . + */ + ret = gpio_request(SABRESD_USB_OTG_PWR, "usb-pwr"); + if (ret) { + pr_err("failed to get GPIO SABRESD_USB_OTG_PWR: %d\n", + ret); + return; + } + gpio_direction_output(SABRESD_USB_OTG_PWR, 0); + /* keep USB host1 VBUS always on */ + ret = gpio_request(SABRESD_USB_H1_PWR, "usb-h1-pwr"); + if (ret) { + pr_err("failed to get GPIO SABRESD_USB_H1_PWR: %d\n", + ret); + return; + } + gpio_direction_output(SABRESD_USB_H1_PWR, 1); + if (board_is_mx6_reva()) + mxc_iomux_set_gpr_register(1, 13, 1, 1); + else + mxc_iomux_set_gpr_register(1, 13, 1, 0); + + mx6_set_otghost_vbus_func(imx6q_sabresd_usbotg_vbus); +} + +/* HW Initialization, if return 0, initialization is successful. */ +static int mx6q_sabresd_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; + } + + /* Set PHY Paremeters, two steps to configure the GPR13, + * one write for rest of parameters, mask of first write is 0x07FFFFFD, + * and the other one write for setting the mpll_clk_off_b + *.rx_eq_val_0(iomuxc_gpr13[26:24]), + *.los_lvl(iomuxc_gpr13[23:19]), + *.rx_dpll_mode_0(iomuxc_gpr13[18:16]), + *.sata_speed(iomuxc_gpr13[15]), + *.mpll_ss_en(iomuxc_gpr13[14]), + *.tx_atten_0(iomuxc_gpr13[13:11]), + *.tx_boost_0(iomuxc_gpr13[10:7]), + *.tx_lvl(iomuxc_gpr13[6:2]), + *.mpll_ck_off(iomuxc_gpr13[1]), + *.tx_edgerate_0(iomuxc_gpr13[0]), + */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x07FFFFFD) | 0x0593A044), IOMUXC_GPR13); + + /* enable SATA_PHY PLL */ + tmpdata = readl(IOMUXC_GPR13); + writel(((tmpdata & ~0x2) | 0x2), IOMUXC_GPR13); + + /* Get the AHB clock rate, and configure the TIMER1MS reg later */ + clk = clk_get(NULL, "ahb"); + if (IS_ERR(clk)) { + dev_err(dev, "no ahb clock.\n"); + ret = PTR_ERR(clk); + goto release_sata_clk; + } + tmpdata = clk_get_rate(clk) / 1000; + clk_put(clk); + + ret = sata_init(addr, tmpdata); + if (ret == 0) + return ret; + +release_sata_clk: + clk_disable(sata_clk); +put_sata_clk: + clk_put(sata_clk); + + return ret; +} + +static void mx6q_sabresd_sata_exit(struct device *dev) +{ + clk_disable(sata_clk); + clk_put(sata_clk); +} + +static struct ahci_platform_data mx6q_sabresd_sata_data = { + .init = mx6q_sabresd_sata_init, + .exit = mx6q_sabresd_sata_exit, +}; + +static void mx6q_sabresd_flexcan0_switch(int enable) +{ + if (enable) { + gpio_set_value(SABRESD_CAN1_STBY, 1); + } else { + gpio_set_value(SABRESD_CAN1_STBY, 0); + } +} + +static const struct flexcan_platform_data + mx6q_sabresd_flexcan0_pdata __initconst = { + .transceiver_switch = mx6q_sabresd_flexcan0_switch, +}; + +static struct viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_128M + SZ_64M, +}; + +static struct imx_asrc_platform_data imx_asrc_data = { + .channel_bits = 4, + .clk_map_ver = 2, +}; + +static void mx6_reset_mipi_dsi(void) +{ + gpio_set_value(SABRESD_DISP_PWR_EN, 1); + gpio_set_value(SABRESD_DISP_RST_B, 1); + udelay(10); + gpio_set_value(SABRESD_DISP_RST_B, 0); + udelay(50); + gpio_set_value(SABRESD_DISP_RST_B, 1); + + /* + * it needs to delay 120ms minimum for reset complete + */ + msleep(120); +} + +static struct mipi_dsi_platform_data mipi_dsi_pdata = { + .ipu_id = 0, + .disp_id = 1, + .lcd_panel = "TRULY-WVGA", + .reset = mx6_reset_mipi_dsi, +}; + +static struct ipuv3_fb_platform_data sabresd_fb_data[] = { + { /*fb0*/ + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + .late_init = false, + }, { + .disp_dev = "hdmi", + .interface_pix_fmt = IPU_PIX_FMT_RGB24, + .mode_str = "1920x1080M@60", + .default_bpp = 32, + .int_clk = false, + .late_init = false, + }, { + .disp_dev = "ldb", + .interface_pix_fmt = IPU_PIX_FMT_RGB666, + .mode_str = "LDB-XGA", + .default_bpp = 32, + .int_clk = false, + .late_init = false, + }, +}; + +static void hdmi_init(int ipu_id, int disp_id) +{ + int hdmi_mux_setting; + + if ((ipu_id > 1) || (ipu_id < 0)) { + pr_err("Invalid IPU select for HDMI: %d. Set to 0\n", ipu_id); + ipu_id = 0; + } + + if ((disp_id > 1) || (disp_id < 0)) { + pr_err("Invalid DI select for HDMI: %d. Set to 0\n", disp_id); + disp_id = 0; + } + + /* Configure the connection between IPU1/2 and HDMI */ + hdmi_mux_setting = 2*ipu_id + disp_id; + + /* GPR3, bits 2-3 = HDMI_MUX_CTL */ + mxc_iomux_set_gpr_register(3, 2, 2, hdmi_mux_setting); + + /* Set HDMI event as SDMA event2 while Chip version later than TO1.2 */ + if (hdmi_SDMA_check()) + mxc_iomux_set_gpr_register(0, 0, 1, 1); +} + +/* On mx6x sabresd board i2c2 iomux with hdmi ddc, + * the pins default work at i2c2 function, + when hdcp enable, the pins should work at ddc function */ + +static void hdmi_enable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_hdmi_ddc_pads, + ARRAY_SIZE(mx6dl_sabresd_hdmi_ddc_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_hdmi_ddc_pads, + ARRAY_SIZE(mx6q_sabresd_hdmi_ddc_pads)); +} + +static void hdmi_disable_ddc_pin(void) +{ + if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_i2c2_pads, + ARRAY_SIZE(mx6dl_sabresd_i2c2_pads)); + else + mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_i2c2_pads, + ARRAY_SIZE(mx6q_sabresd_i2c2_pads)); +} + +static struct fsl_mxc_hdmi_platform_data hdmi_data = { + .init = hdmi_init, + .enable_pins = hdmi_enable_ddc_pin, + .disable_pins = hdmi_disable_ddc_pin, + .phy_reg_vlev = 0x0294, + .phy_reg_cksymtx = 0x800d, +}; + +static struct fsl_mxc_hdmi_core_platform_data hdmi_core_data = { + .ipu_id = 0, + .disp_id = 0, +}; + +static struct fsl_mxc_lcd_platform_data lcdif_data = { + .ipu_id = 0, + .disp_id = 0, + .default_ifmt = IPU_PIX_FMT_RGB565, +}; + +static struct fsl_mxc_ldb_platform_data ldb_data = { + .ipu_id = 1, + .disp_id = 1, + .ext_ref = 1, + .mode = LDB_SEP1, + .sec_ipu_id = 1, + .sec_disp_id = 0, +}; + +static struct max8903_pdata charger1_data = { + .dok = SABRESD_CHARGE_DOK_B, + .uok = SABRESD_CHARGE_UOK_B, + .chg = SABRESD_CHARGE_CHG_1_B, + .flt = SABRESD_CHARGE_FLT_1_B, + .dcm_always_high = true, + .dc_valid = true, + .usb_valid = true, +}; + +static struct platform_device sabresd_max8903_charger_1 = { + .name = "max8903-charger", + .id = 1, + .dev = { + .platform_data = &charger1_data, + }, +}; + +static struct imx_ipuv3_platform_data ipu_data[] = { + { + .rev = 4, + .csi_clk[0] = "clko_clk", + .bypass_reset = false, + }, { + .rev = 4, + .csi_clk[0] = "clko_clk", + .bypass_reset = false, + }, +}; + +static struct ion_platform_data imx_ion_data = { + .nr = 1, + .heaps = { + { + .id = 0, + .type = ION_HEAP_TYPE_CARVEOUT, + .name = "vpu_ion", + .size = SZ_64M, + }, + }, +}; + +static struct fsl_mxc_capture_platform_data capture_data[] = { + { + .csi = 0, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 0, + }, { + .csi = 1, + .ipu = 0, + .mclk_source = 0, + .is_mipi = 1, + }, +}; + + +struct imx_vout_mem { + resource_size_t res_mbase; + resource_size_t res_msize; +}; + +static struct imx_vout_mem vout_mem __initdata = { + .res_msize = SZ_128M, +}; + +static void sabresd_suspend_enter(void) +{ + /* suspend preparation */ + /* Disable AUX 5V */ + gpio_set_value(SABRESD_AUX_5V_EN, 0); +} + +static void sabresd_suspend_exit(void) +{ + /* resume restore */ + /* Enable AUX 5V */ + gpio_set_value(SABRESD_AUX_5V_EN, 1); +} +static const struct pm_platform_data mx6q_sabresd_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = sabresd_suspend_enter, + .suspend_exit = sabresd_suspend_exit, +}; + +static struct regulator_consumer_supply sabresd_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; + +static struct regulator_init_data sabresd_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(sabresd_vmmc_consumers), + .consumer_supplies = sabresd_vmmc_consumers, +}; + +static struct fixed_voltage_config sabresd_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &sabresd_vmmc_init, +}; + +static struct platform_device sabresd_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 3, + .dev = { + .platform_data = &sabresd_vmmc_reg_config, + }, +}; + +static int __init imx6q_init_audio(void) +{ + if (board_is_mx6_reva()) { + mxc_register_device(&mx6_sabresd_audio_wm8958_device, + &wm8958_data); + imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata); + + mxc_wm8958_init(); + } else { + platform_device_register(&sabresd_vwm8962_reg_devices); + mxc_register_device(&mx6_sabresd_audio_wm8962_device, + &wm8962_data); + imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata); + + mxc_wm8962_init(); + } + + return 0; +} + +#ifndef CONFIG_IMX_PCIE +static void pcie_3v3_power(void) +{ + /* disable PCIE_3V3 first */ + gpio_request(SABRESD_PCIE_PWR_EN, "pcie_3v3_en"); + gpio_direction_output(SABRESD_PCIE_PWR_EN, 0); + mdelay(10); + /* enable PCIE_3V3 again */ + gpio_set_value(SABRESD_PCIE_PWR_EN, 1); + gpio_free(SABRESD_PCIE_PWR_EN); +} + +static void pcie_3v3_reset(void) +{ + /* reset miniPCIe */ + gpio_request(SABRESD_PCIE_RST_B_REVB, "pcie_reset_rebB"); + gpio_direction_output(SABRESD_PCIE_RST_B_REVB, 0); + /* The PCI Express Mini CEM specification states that PREST# is + deasserted minimum 1ms after 3.3vVaux has been applied and stable*/ + mdelay(1); + gpio_set_value(SABRESD_PCIE_RST_B_REVB, 1); + gpio_free(SABRESD_PCIE_RST_B_REVB); +} +#endif + +static void gps_power_on(bool on) +{ + /* Enable/disable aux_3v15 */ + gpio_request(SABRESD_AUX_3V15_EN, "aux_3v15_en"); + gpio_direction_output(SABRESD_AUX_3V15_EN, 1); + gpio_set_value(SABRESD_AUX_3V15_EN, on); + gpio_free(SABRESD_AUX_3V15_EN); + /*Enable/disable gps_en*/ + gpio_request(SABRESD_GPS_EN, "gps_en"); + gpio_direction_output(SABRESD_GPS_EN, 1); + gpio_set_value(SABRESD_GPS_EN, on); + gpio_free(SABRESD_GPS_EN); + +} + +#if defined(CONFIG_LEDS_TRIGGER) || defined(CONFIG_LEDS_GPIO) + +#define GPIO_LED(gpio_led, name_led, act_low, state_suspend, trigger) \ +{ \ + .gpio = gpio_led, \ + .name = name_led, \ + .active_low = act_low, \ + .retain_state_suspended = state_suspend, \ + .default_state = 0, \ + .default_trigger = "max8903-"trigger, \ +} + +/* use to show a external power source is connected + * GPIO_LED(SABRESD_CHARGE_DONE, "chg_detect", 0, 1, "ac-online"), + */ +static struct gpio_led imx6q_gpio_leds[] = { + GPIO_LED(SABRESD_CHARGE_NOW, "chg_now_led", 0, 1, + "charger-charging"), +/* For the latest B4 board, this GPIO_1 is connected to POR_B, +which will reset the whole board if this pin's level is changed, +so, for the latest board, we have to avoid using this pin as +GPIO. + GPIO_LED(SABRESD_CHARGE_DONE, "chg_done_led", 0, 1, + "charger-full"), +*/ +}; + +static struct gpio_led_platform_data imx6q_gpio_leds_data = { + .leds = imx6q_gpio_leds, + .num_leds = ARRAY_SIZE(imx6q_gpio_leds), +}; + +static struct platform_device imx6q_gpio_led_device = { + .name = "leds-gpio", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &imx6q_gpio_leds_data, + } +}; + +static void __init imx6q_add_device_gpio_leds(void) +{ + platform_device_register(&imx6q_gpio_led_device); +} +#else +static void __init imx6q_add_device_gpio_leds(void) {} +#endif + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ + .debounce_interval = debounce, \ +} + +static struct gpio_keys_button imx6q_buttons[] = { + GPIO_BUTTON(SABRESD_VOLUME_UP, KEY_VOLUMEUP, 1, "volume-up", 0, 1), + GPIO_BUTTON(SABRESD_VOLUME_DN, KEY_POWER, 1, "volume-down", 1, 1), +}; + +static struct gpio_keys_platform_data imx6q_button_data = { + .buttons = imx6q_buttons, + .nbuttons = ARRAY_SIZE(imx6q_buttons), +}; + +static struct platform_device imx6q_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &imx6q_button_data, + } +}; + +static void __init imx6q_add_device_buttons(void) +{ + platform_device_register(&imx6q_button_device); +} +#else +static void __init imx6q_add_device_buttons(void) {} +#endif + +static struct platform_pwm_backlight_data mx6_sabresd_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 248, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; + +static struct mxc_dvfs_platform_data sabresd_dvfscore_data = { +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + .reg_id = "VDDCORE", + .soc_id = "VDDSOC", +#else + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", +#endif + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags, + char **cmdline, struct meminfo *mi) +{ + char *str; + struct tag *t; + int i = 0; + struct ipuv3_fb_platform_data *pdata_fb = sabresd_fb_data; + + for_each_tag(t, tags) { + if (t->hdr.tag == ATAG_CMDLINE) { + str = t->u.cmdline.cmdline; + str = strstr(str, "fbmem="); + if (str != NULL) { + str += 6; + pdata_fb[i++].res_size[0] = memparse(str, &str); + while (*str == ',' && + i < ARRAY_SIZE(sabresd_fb_data)) { + str++; + pdata_fb[i++].res_size[0] = memparse(str, &str); + } + } + break; + } + } +} + +static struct mipi_csi2_platform_data mipi_csi2_pdata = { + .ipu_id = 0, + .csi_id = 1, + .v_channel = 0, + .lanes = 2, + .dphy_clk = "mipi_pllref_clk", + .pixel_clk = "emi_clk", +}; + +#define SNVS_LPCR 0x38 +static void mx6_snvs_poweroff(void) +{ + + void __iomem *mx6_snvs_base = MX6_IO_ADDRESS(MX6Q_SNVS_BASE_ADDR); + u32 value; + value = readl(mx6_snvs_base + SNVS_LPCR); + /*set TOP and DP_EN bit*/ + writel(value | 0x60, mx6_snvs_base + SNVS_LPCR); +} + +static const struct imx_pcie_platform_data mx6_sabresd_pcie_data __initconst = { + .pcie_pwr_en = SABRESD_PCIE_PWR_EN, + .pcie_rst = SABRESD_PCIE_RST_B_REVB, + .pcie_wake_up = SABRESD_PCIE_WAKE_B, + .pcie_dis = SABRESD_PCIE_DIS_B, +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS + .type_ep = 1, +#else + .type_ep = 0, +#endif +}; + +static int __init early_enable_lcd_ldb(char *p) +{ + enable_lcd_ldb = 1; + return 0; +} +early_param("enable_lcd_ldb", early_enable_lcd_ldb); + +/*! + * Board specific initialization. + */ +static void __init mx6_sabresd_board_init(void) +{ + int i; + int ret; + struct clk *clko, *clko2; + struct clk *new_parent; + int rate; + struct platform_device *voutdev; + + if (cpu_is_mx6q()) + mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_pads, + ARRAY_SIZE(mx6q_sabresd_pads)); + else if (cpu_is_mx6dl()) { + mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_pads, + ARRAY_SIZE(mx6dl_sabresd_pads)); + } + +#ifdef CONFIG_FEC_1588 + /* Set GPIO_16 input for IEEE-1588 ts_clk and RMII reference clock + * For MX6 GPR1 bit21 meaning: + * Bit21: 0 - GPIO_16 pad output + * 1 - GPIO_16 pad input + */ + mxc_iomux_set_gpr_register(1, 21, 1, 1); +#endif + + gp_reg_id = sabresd_dvfscore_data.reg_id; + soc_reg_id = sabresd_dvfscore_data.soc_id; + pu_reg_id = sabresd_dvfscore_data.pu_id; + mx6q_sabresd_init_uart(); + + /* + * MX6DL/Solo only supports single IPU + * The following codes are used to change ipu id + * and display id information for MX6DL/Solo. Then + * register 1 IPU device and up to 2 displays for + * MX6DL/Solo + */ + if (cpu_is_mx6dl()) { + ldb_data.ipu_id = 0; + ldb_data.disp_id = 1; + hdmi_core_data.disp_id = 0; + mipi_dsi_pdata.ipu_id = 0; + mipi_dsi_pdata.disp_id = 1; + } + imx6q_add_mxc_hdmi_core(&hdmi_core_data); + + imx6q_add_ipuv3(0, &ipu_data[0]); + if (cpu_is_mx6q()) { + imx6q_add_ipuv3(1, &ipu_data[1]); + for (i = 0; i < 4 && i < ARRAY_SIZE(sabresd_fb_data); i++) + imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]); + } else + for (i = 0; i < 2 && i < ARRAY_SIZE(sabresd_fb_data); i++) + imx6q_add_ipuv3fb(i, &sabresd_fb_data[i]); + + imx6q_add_vdoa(); + imx6q_add_mipi_dsi(&mipi_dsi_pdata); + imx6q_add_lcdif(&lcdif_data); + imx6q_add_ldb(&ldb_data); + voutdev = imx6q_add_v4l2_output(0); + if (vout_mem.res_msize && voutdev) { + dma_declare_coherent_memory(&voutdev->dev, + vout_mem.res_mbase, + vout_mem.res_mbase, + vout_mem.res_msize, + (DMA_MEMORY_MAP | + DMA_MEMORY_EXCLUSIVE)); + } + + imx6q_add_v4l2_capture(0, &capture_data[0]); + imx6q_add_v4l2_capture(1, &capture_data[1]); + imx6q_add_mipi_csi2(&mipi_csi2_pdata); + imx6q_add_imx_snvs_rtc(); + + imx6q_add_imx_caam(); + + if (board_is_mx6_reva()) { + strcpy(mxc_i2c0_board_info[0].type, "wm8958"); + mxc_i2c0_board_info[0].platform_data = &wm8958_config_data; + } else { + strcpy(mxc_i2c0_board_info[0].type, "wm8962"); + mxc_i2c0_board_info[0].platform_data = &wm8962_config_data; + } + imx6q_add_device_gpio_leds(); + + imx6q_add_imx_i2c(0, &mx6q_sabresd_i2c_data); + imx6q_add_imx_i2c(1, &mx6q_sabresd_i2c_data); + imx6q_add_imx_i2c(2, &mx6q_sabresd_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)); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + ret = gpio_request(SABRESD_PFUZE_INT, "pFUZE-int"); + if (ret) { + printk(KERN_ERR"request pFUZE-int error!!\n"); + return; + } else { + gpio_direction_input(SABRESD_PFUZE_INT); + mx6q_sabresd_init_pfuze100(SABRESD_PFUZE_INT); + } + /* SPI */ + imx6q_add_ecspi(0, &mx6q_sabresd_spi_data); + spi_device_init(); + + imx6q_add_mxc_hdmi(&hdmi_data); + + imx6q_add_anatop_thermal_imx(1, &mx6q_sabresd_anatop_thermal_data); + imx6_init_fec(fec_data); +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + /* Make sure the IOMUX_OBSRV_MUX1 is set to ENET_IRQ. */ + mxc_iomux_set_specialbits_register(IOMUX_OBSRV_MUX1_OFFSET, + OBSRV_MUX1_ENET_IRQ, OBSRV_MUX1_MASK); +#endif + + imx6q_add_pm_imx(0, &mx6q_sabresd_pm_data); + + /* Move sd4 to first because sd4 connect to emmc. + Mfgtools want emmc is mmcblk0 and other sd card is mmcblk1. + */ + imx6q_add_sdhci_usdhc_imx(3, &mx6q_sabresd_sd4_data); + imx6q_add_sdhci_usdhc_imx(2, &mx6q_sabresd_sd3_data); + imx6q_add_sdhci_usdhc_imx(1, &mx6q_sabresd_sd2_data); + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + imx6q_sabresd_init_usb(); + /* SATA is not supported by MX6DL/Solo */ + if (cpu_is_mx6q()) + imx6q_add_ahci(0, &mx6q_sabresd_sata_data); + imx6q_add_vpu(); + imx6q_init_audio(); + platform_device_register(&sabresd_vmmc_reg_devices); + imx_asrc_data.asrc_core_clk = clk_get(NULL, "asrc_clk"); + imx_asrc_data.asrc_audio_clk = clk_get(NULL, "asrc_serial_clk"); + imx6q_add_asrc(&imx_asrc_data); + + /* + * Disable HannStar touch panel CABC function, + * this function turns the panel's backlight automatically + * according to the content shown on the panel which + * may cause annoying unstable backlight issue. + */ + gpio_request(SABRESD_CABC_EN0, "cabc-en0"); + gpio_direction_output(SABRESD_CABC_EN0, 0); + gpio_request(SABRESD_CABC_EN1, "cabc-en1"); + gpio_direction_output(SABRESD_CABC_EN1, 0); + + imx6q_add_mxc_pwm(0); + imx6q_add_mxc_pwm(1); + imx6q_add_mxc_pwm(2); + imx6q_add_mxc_pwm(3); + imx6q_add_mxc_pwm_backlight(0, &mx6_sabresd_pwm_backlight_data); + + imx6q_add_otp(); + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + imx6q_add_dma(); + + imx6q_add_dvfs_core(&sabresd_dvfscore_data); +#ifndef CONFIG_MX6_INTER_LDO_BYPASS + mx6_cpu_regulator_init(); +#endif + imx6q_add_device_buttons(); + + /* enable sensor 3v3 and 1v8 */ + gpio_request(SABRESD_SENSOR_EN, "sensor-en"); + gpio_direction_output(SABRESD_SENSOR_EN, 1); + + /* enable ecompass intr */ + gpio_request(SABRESD_eCOMPASS_INT, "ecompass-int"); + gpio_direction_input(SABRESD_eCOMPASS_INT); + /* enable light sensor intr */ + gpio_request(SABRESD_ALS_INT, "als-int"); + gpio_direction_input(SABRESD_ALS_INT); + + imx6q_add_hdmi_soc(); + imx6q_add_hdmi_soc_dai(); + + if (cpu_is_mx6dl()) { + imx6dl_add_imx_pxp(); + imx6dl_add_imx_pxp_client(); + if (epdc_enabled) { + mxc_register_device(&max17135_sensor_device, NULL); + imx6dl_add_imx_epdc(&epdc_data); + } + } + /* + ret = gpio_request_array(mx6q_sabresd_flexcan_gpios, + ARRAY_SIZE(mx6q_sabresd_flexcan_gpios)); + if (ret) + pr_err("failed to request flexcan1-gpios: %d\n", ret); + else + imx6q_add_flexcan0(&mx6q_sabresd_flexcan0_pdata); + */ + + clko2 = clk_get(NULL, "clko2_clk"); + if (IS_ERR(clko2)) + pr_err("can't get CLKO2 clock.\n"); + + new_parent = clk_get(NULL, "osc_clk"); + if (!IS_ERR(new_parent)) { + clk_set_parent(clko2, new_parent); + clk_put(new_parent); + } + rate = clk_round_rate(clko2, 24000000); + clk_set_rate(clko2, rate); + clk_enable(clko2); + + /* Camera and audio use osc clock */ + clko = clk_get(NULL, "clko_clk"); + if (!IS_ERR(clko)) + clk_set_parent(clko, clko2); + + /* Enable Aux_5V */ + gpio_request(SABRESD_AUX_5V_EN, "aux_5v_en"); + gpio_direction_output(SABRESD_AUX_5V_EN, 1); + gpio_set_value(SABRESD_AUX_5V_EN, 1); + +#ifndef CONFIG_IMX_PCIE + /* enable pcie 3v3 power without pcie driver */ + pcie_3v3_power(); + mdelay(10); + pcie_3v3_reset(); +#endif + + gps_power_on(true); + /* Register charger chips */ + platform_device_register(&sabresd_max8903_charger_1); + pm_power_off = mx6_snvs_poweroff; + imx6q_add_busfreq(); + + /* Add PCIe RC interface support */ + imx6q_add_pcie(&mx6_sabresd_pcie_data); + if (cpu_is_mx6dl()) { + mxc_iomux_v3_setup_multiple_pads(mx6dl_arm2_elan_pads, + ARRAY_SIZE(mx6dl_arm2_elan_pads)); + + /* ELAN Touchscreen */ + gpio_request(SABRESD_ELAN_INT, "elan-interrupt"); + gpio_direction_input(SABRESD_ELAN_INT); + + gpio_request(SABRESD_ELAN_CE, "elan-cs"); + gpio_direction_output(SABRESD_ELAN_CE, 1); + gpio_direction_output(SABRESD_ELAN_CE, 0); + + gpio_request(SABRESD_ELAN_RST, "elan-rst"); + gpio_direction_output(SABRESD_ELAN_RST, 1); + gpio_direction_output(SABRESD_ELAN_RST, 0); + mdelay(1); + gpio_direction_output(SABRESD_ELAN_RST, 1); + gpio_direction_output(SABRESD_ELAN_CE, 1); + } + + imx6_add_armpmu(); + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); +} + +extern void __iomem *twd_base; +static void __init mx6_sabresd_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART1_BASE_ADDR, uart_clk); +} + +static struct sys_timer mx6_sabresd_timer = { + .init = mx6_sabresd_timer_init, +}; + +static void __init mx6q_sabresd_reserve(void) +{ + phys_addr_t phys; + int i; + +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, SZ_1G); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif + +#if defined(CONFIG_ION) + if (imx_ion_data.heaps[0].size) { + phys = memblock_alloc(imx_ion_data.heaps[0].size, SZ_4K); + memblock_remove(phys, imx_ion_data.heaps[0].size); + imx_ion_data.heaps[0].base = phys; + } +#endif + + for (i = 0; i < ARRAY_SIZE(sabresd_fb_data); i++) + if (sabresd_fb_data[i].res_size[0]) { + /* reserve for background buffer */ + phys = memblock_alloc(sabresd_fb_data[i].res_size[0], + SZ_4K); + memblock_remove(phys, sabresd_fb_data[i].res_size[0]); + sabresd_fb_data[i].res_base[0] = phys; + } + if (vout_mem.res_msize) { + phys = memblock_alloc_base(vout_mem.res_msize, + SZ_4K, SZ_1G); + memblock_remove(phys, vout_mem.res_msize); + vout_mem.res_mbase = phys; + } +} + +/* + * initialize __mach_desc_MX6Q_SABRESD data structure. + */ +MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX6_PHYS_OFFSET + 0x100, + .fixup = fixup_mxc_board, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_sabresd_board_init, + .timer = &mx6_sabresd_timer, + .reserve = mx6q_sabresd_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6q_sabresd.h b/arch/arm/mach-mx6/board-mx6q_sabresd.h new file mode 100644 index 00000000..b2bb8c92 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6q_sabresd.h @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2012-2013 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 _BOARD_MX6Q_SABRESD_H +#define _BOARD_MX6Q_SABRESD_H +#include <mach/iomux-mx6q.h> + +static iomux_v3_cfg_t mx6q_sabresd_pads[] = { + /* AUDMUX */ + MX6Q_PAD_CSI0_DAT4__AUDMUX_AUD3_TXC, + MX6Q_PAD_CSI0_DAT5__AUDMUX_AUD3_TXD, + MX6Q_PAD_CSI0_DAT6__AUDMUX_AUD3_TXFS, + MX6Q_PAD_CSI0_DAT7__AUDMUX_AUD3_RXD, + + /* CAN1 */ + MX6Q_PAD_KEY_ROW2__HDMI_TX_CEC_LINE, + /* MX6Q_PAD_KEY_COL2__CAN1_TXCAN, */ + MX6Q_PAD_GPIO_1__WDOG2_WDOG_B, /*WDOG_B to reset pmic*/ + MX6Q_PAD_GPIO_2__GPIO_1_2, /* user defined red led */ + MX6Q_PAD_GPIO_7__GPIO_1_7, /* NERR */ + + /* CCM */ + MX6Q_PAD_GPIO_0__CCM_CLKO, /* SGTL500 sys_mclk */ + MX6Q_PAD_GPIO_3__CCM_CLKO2, /* J5 - Camera MCLK */ + + /* ECSPI1 */ + MX6Q_PAD_KEY_COL0__ECSPI1_SCLK, + MX6Q_PAD_KEY_ROW0__ECSPI1_MOSI, + MX6Q_PAD_KEY_COL1__ECSPI1_MISO, + MX6Q_PAD_KEY_ROW1__GPIO_4_9, + /* ENET */ + MX6Q_PAD_ENET_MDIO__ENET_MDIO, + MX6Q_PAD_ENET_MDC__ENET_MDC, + MX6Q_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6Q_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6Q_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6Q_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6Q_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6Q_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6Q_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6Q_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6Q_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6Q_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6Q_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6Q_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6Q_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, + MX6Q_PAD_ENET_TX_EN__GPIO_1_28, /* Micrel RGMII Phy Interrupt */ + MX6Q_PAD_EIM_D23__GPIO_3_23, /* RGMII reset */ + MX6Q_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, /* Internal connect for 1588 TS Clock */ + + /* GPIO1 */ + MX6Q_PAD_ENET_RX_ER__GPIO_1_24, /* J9 - Microphone Detect */ + + /* GPIO2 */ + /* MX6Q_PAD_NANDF_D1__GPIO_2_1,*/ /* J14 - Menu Button */ + /* MX6Q_PAD_NANDF_D2__GPIO_2_2,*/ /* J14 - Back Button */ + /* MX6Q_PAD_NANDF_D3__GPIO_2_3,*/ /* J14 - Search Button */ + /* MX6Q_PAD_NANDF_D4__GPIO_2_4,*/ /* J14 - Home Button */ + MX6Q_PAD_EIM_A22__GPIO_2_16, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A21__GPIO_2_17, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A20__GPIO_2_18, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A19__GPIO_2_19, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A18__GPIO_2_20, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A17__GPIO_2_21, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A16__GPIO_2_22, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_RW__GPIO_2_26, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_LBA__GPIO_2_27, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_EB0__GPIO_2_28, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_EB1__GPIO_2_29, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_EB3__GPIO_2_31, /* J12 - Boot Mode Select */ + + /* GPIO3 */ + MX6Q_PAD_EIM_DA0__GPIO_3_0, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA1__GPIO_3_1, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA2__GPIO_3_2, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA3__GPIO_3_3, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA4__GPIO_3_4, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA5__GPIO_3_5, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA6__GPIO_3_6, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA7__GPIO_3_7, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA8__GPIO_3_8, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA9__GPIO_3_9, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA10__GPIO_3_10, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA11__GPIO_3_11, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA12__GPIO_3_12, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA13__GPIO_3_13, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA14__GPIO_3_14, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_DA15__GPIO_3_15, /* J12 - Boot Mode Select */ + + /* SW4 , SW5 & SW1 */ + MX6Q_PAD_GPIO_4__GPIO_1_4, /* Volume Up */ + MX6Q_PAD_GPIO_5__GPIO_1_5, /* Volume Down */ + MX6Q_PAD_EIM_D29__GPIO_3_29, /* power off */ + + /* CAP_TCH_INT1 */ + MX6Q_PAD_NANDF_CLE__GPIO_6_7, + + /* CAP_TCH_INT0 */ + MX6Q_PAD_NANDF_ALE__GPIO_6_8, + + /* eCompass int */ + MX6Q_PAD_EIM_D16__GPIO_3_16, + + /* GPIO5 */ + MX6Q_PAD_EIM_WAIT__GPIO_5_0, /* J12 - Boot Mode Select */ + MX6Q_PAD_EIM_A24__GPIO_5_4, /* J12 - Boot Mode Select */ + + /* GPIO6 */ + MX6Q_PAD_EIM_A23__GPIO_6_6, /* J12 - Boot Mode Select */ + MX6Q_PAD_NANDF_RB0__GPIO_6_10, /* AUX_5V Enable */ + + /* I2C1, WM8958 */ + MX6Q_PAD_CSI0_DAT8__I2C1_SDA, + MX6Q_PAD_CSI0_DAT9__I2C1_SCL, + + /* I2C2, Camera, MIPI */ + MX6Q_PAD_KEY_COL3__I2C2_SCL, + MX6Q_PAD_KEY_ROW3__I2C2_SDA, + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6Q_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, +#else + /* I2C3 */ + MX6Q_PAD_GPIO_3__I2C3_SCL, /* GPIO1[3] */ + MX6Q_PAD_GPIO_6__I2C3_SDA, +#endif + + /* DISPLAY */ + MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15, /* DE */ + MX6Q_PAD_DI0_PIN2__IPU1_DI0_PIN2, /* HSync */ + MX6Q_PAD_DI0_PIN3__IPU1_DI0_PIN3, /* VSync */ + MX6Q_PAD_DI0_PIN4__IPU1_DI0_PIN4, /* Contrast */ + MX6Q_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6Q_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6Q_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6Q_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6Q_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6Q_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6Q_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6Q_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6Q_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6Q_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6Q_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6Q_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6Q_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6Q_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6Q_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6Q_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6Q_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6Q_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6Q_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6Q_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6Q_PAD_DISP0_DAT20__IPU1_DISP0_DAT_20, + MX6Q_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + MX6Q_PAD_DISP0_DAT22__IPU1_DISP0_DAT_22, + MX6Q_PAD_DISP0_DAT23__IPU1_DISP0_DAT_23, + MX6Q_PAD_GPIO_7__GPIO_1_7, /* J7 - Display Connector GP */ + MX6Q_PAD_GPIO_9__GPIO_1_9, /* J7 - Display Connector GP */ + /* MX6Q_PAD_NANDF_D0__GPIO_2_0,*/ /* J6 - LVDS Display contrast */ + + /* DISP_PWM */ + MX6Q_PAD_SD1_DAT3__PWM1_PWMO, /* GPIO1[21] */ + + /* UART1 for debug */ + MX6Q_PAD_CSI0_DAT10__UART1_TXD, + MX6Q_PAD_CSI0_DAT11__UART1_RXD, + + /* UART3 for gps */ + MX6Q_PAD_EIM_D24__UART3_TXD, + MX6Q_PAD_EIM_D25__UART3_RXD, + + /* USBOTG ID pin */ + MX6Q_PAD_ENET_RX_ER__ANATOP_USBOTG_ID, + + /* USB power pin */ + MX6Q_PAD_EIM_D22__GPIO_3_22, + MX6Q_PAD_ENET_TXD1__GPIO_1_29, + + /* USB OC pin */ + MX6Q_PAD_EIM_D21__USBOH3_USBOTG_OC, + MX6Q_PAD_EIM_D30__USBOH3_USBH1_OC, + + /* USDHC2 */ + MX6Q_PAD_SD2_CLK__USDHC2_CLK, + MX6Q_PAD_SD2_CMD__USDHC2_CMD, + MX6Q_PAD_SD2_DAT0__USDHC2_DAT0, + MX6Q_PAD_SD2_DAT1__USDHC2_DAT1, + MX6Q_PAD_SD2_DAT2__USDHC2_DAT2, + MX6Q_PAD_SD2_DAT3__USDHC2_DAT3, + MX6Q_PAD_NANDF_D4__USDHC2_DAT4, + MX6Q_PAD_NANDF_D5__USDHC2_DAT5, + MX6Q_PAD_NANDF_D6__USDHC2_DAT6, + MX6Q_PAD_NANDF_D7__USDHC2_DAT7, + MX6Q_PAD_NANDF_D2__GPIO_2_2, /* SD2_CD */ + MX6Q_PAD_NANDF_D3__GPIO_2_3, /* SD2_WP */ + + /* USDHC3 */ + MX6Q_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6Q_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6Q_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6Q_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6Q_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6Q_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6Q_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6Q_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6Q_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6Q_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + MX6Q_PAD_NANDF_D0__GPIO_2_0, /* SD3_CD */ + MX6Q_PAD_NANDF_D1__GPIO_2_1, /* SD3_WP */ + + /* USDHC4 */ + MX6Q_PAD_SD4_CLK__USDHC4_CLK_50MHZ, + MX6Q_PAD_SD4_CMD__USDHC4_CMD_50MHZ, + MX6Q_PAD_SD4_DAT0__USDHC4_DAT0_50MHZ, + MX6Q_PAD_SD4_DAT1__USDHC4_DAT1_50MHZ, + MX6Q_PAD_SD4_DAT2__USDHC4_DAT2_50MHZ, + MX6Q_PAD_SD4_DAT3__USDHC4_DAT3_50MHZ, + MX6Q_PAD_SD4_DAT4__USDHC4_DAT4_50MHZ, + MX6Q_PAD_SD4_DAT5__USDHC4_DAT5_50MHZ, + MX6Q_PAD_SD4_DAT6__USDHC4_DAT6_50MHZ, + MX6Q_PAD_SD4_DAT7__USDHC4_DAT7_50MHZ, + + /* Charge */ + MX6Q_PAD_EIM_A25__GPIO_5_2, /* FLT_1_B */ + MX6Q_PAD_EIM_D23__GPIO_3_23, /* CHG_1_B */ + MX6Q_PAD_EIM_DA13__GPIO_3_13, /* CHG_2_B */ + MX6Q_PAD_EIM_DA14__GPIO_3_14, /* FLT_2_B */ + + MX6Q_PAD_ENET_RXD0__GPIO_1_27, /* UOK_B */ + MX6Q_PAD_EIM_CS1__GPIO_2_24, /* DOK_B */ + + /* Audio Codec */ + MX6Q_PAD_KEY_COL2__GPIO_4_10, /* CODEC_PWR_EN */ + MX6Q_PAD_SD3_RST__GPIO_7_8, /* HEADPHONE_DET */ + MX6Q_PAD_GPIO_9__GPIO_1_9, /* MICROPHONE_DET */ + + /*GPS AUX_3V15_EN*/ + MX6Q_PAD_NANDF_WP_B__GPIO_6_9, + + /* PCIE */ + MX6Q_PAD_EIM_D19__GPIO_3_19, /* PCIE_PWR_EN */ + + MX6Q_PAD_GPIO_17__GPIO_7_12, /* PCIE_RST */ + MX6Q_PAD_KEY_COL4__GPIO_4_14, /* PCIE_DIS */ + + /* DISP_RST_B */ + MX6Q_PAD_NANDF_CS0__GPIO_6_11, + /* DISP_PWR_EN */ + MX6Q_PAD_NANDF_CS1__GPIO_6_14, + /* CABC_EN0 */ + MX6Q_PAD_NANDF_CS2__GPIO_6_15, + /* CABC_EN1 */ + MX6Q_PAD_NANDF_CS3__GPIO_6_16, +}; + +static iomux_v3_cfg_t mx6q_sabresd_csi0_sensor_pads[] = { + /* IPU1 Camera */ + MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN, + MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + + MX6Q_PAD_GPIO_0__CCM_CLKO, /* camera clk */ + + MX6Q_PAD_SD1_DAT0__GPIO_1_16, /* camera PWDN */ + MX6Q_PAD_SD1_DAT1__GPIO_1_17, /* camera RESET */ +}; + +static iomux_v3_cfg_t mx6q_sabresd_mipi_sensor_pads[] = { + MX6Q_PAD_GPIO_0__CCM_CLKO, /* camera clk */ + + MX6Q_PAD_SD1_DAT2__GPIO_1_19, /* camera PWDN */ + MX6Q_PAD_SD1_CLK__GPIO_1_20, /* camera RESET */ +}; + +static iomux_v3_cfg_t mx6q_sabresd_hdmi_ddc_pads[] = { + MX6Q_PAD_KEY_COL3__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6Q_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6q_sabresd_i2c2_pads[] = { + MX6Q_PAD_KEY_COL3__I2C2_SCL, /* I2C2 SCL */ + MX6Q_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; +#endif diff --git a/arch/arm/mach-mx6/board-mx6sl_arm2.c b/arch/arm/mach-mx6/board-mx6sl_arm2.c new file mode 100755 index 00000000..fbc5d4dd --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6sl_arm2.c @@ -0,0 +1,1313 @@ +/* + * 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/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/smsc911x.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> +#include <sound/wm8962.h> +#include <sound/pcm.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6sl.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.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 "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6sl_common.h" + +static int spdc_sel; +static int max17135_regulator_init(struct max17135 *max17135); +static struct clk *extern_audio_root; + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; +extern int __init mx6sl_arm2_init_pfuze100(u32 int_gpio); + +enum sd_pad_mode { + SD_PAD_MODE_LOW_SPEED, + SD_PAD_MODE_MED_SPEED, + SD_PAD_MODE_HIGH_SPEED, +}; + +static int plt_sd_pad_change(unsigned int index, int clock) +{ + /* LOW speed is the default state of SD pads */ + static enum sd_pad_mode pad_mode = SD_PAD_MODE_LOW_SPEED; + + iomux_v3_cfg_t *sd_pads_200mhz = NULL; + iomux_v3_cfg_t *sd_pads_100mhz = NULL; + iomux_v3_cfg_t *sd_pads_50mhz = NULL; + + u32 sd_pads_200mhz_cnt; + u32 sd_pads_100mhz_cnt; + u32 sd_pads_50mhz_cnt; + + switch (index) { + case 0: + sd_pads_200mhz = mx6sl_sd1_200mhz; + sd_pads_100mhz = mx6sl_sd1_100mhz; + sd_pads_50mhz = mx6sl_sd1_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd1_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd1_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd1_50mhz); + break; + case 1: + sd_pads_200mhz = mx6sl_sd2_200mhz; + sd_pads_100mhz = mx6sl_sd2_100mhz; + sd_pads_50mhz = mx6sl_sd2_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd2_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd2_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd2_50mhz); + break; + case 2: + sd_pads_200mhz = mx6sl_sd3_200mhz; + sd_pads_100mhz = mx6sl_sd3_100mhz; + sd_pads_50mhz = mx6sl_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd3_50mhz); + break; + default: + printk(KERN_ERR "no such SD host controller index %d\n", index); + return -EINVAL; + } + + if (clock > 100000000) { + if (pad_mode == SD_PAD_MODE_HIGH_SPEED) + return 0; + BUG_ON(!sd_pads_200mhz); + pad_mode = SD_PAD_MODE_HIGH_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_200mhz, + sd_pads_200mhz_cnt); + } else if (clock > 52000000) { + if (pad_mode == SD_PAD_MODE_MED_SPEED) + return 0; + BUG_ON(!sd_pads_100mhz); + pad_mode = SD_PAD_MODE_MED_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_100mhz, + sd_pads_100mhz_cnt); + } else { + if (pad_mode == SD_PAD_MODE_LOW_SPEED) + return 0; + BUG_ON(!sd_pads_50mhz); + pad_mode = SD_PAD_MODE_LOW_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_50mhz, + sd_pads_50mhz_cnt); + } +} + +static const struct esdhc_platform_data mx6_arm2_sd1_data __initconst = { + .cd_gpio = MX6_BRD_SD1_CD, + .wp_gpio = MX6_BRD_SD1_WP, + .support_8bit = 1, + .support_18v = 1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct esdhc_platform_data mx6_arm2_sd2_data __initconst = { + .cd_gpio = MX6_BRD_SD2_CD, + .wp_gpio = MX6_BRD_SD2_WP, + .keep_power_at_suspend = 1, + .delay_line = 0, + .support_18v = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct esdhc_platform_data mx6_arm2_sd3_data __initconst = { + .cd_gpio = MX6_BRD_SD3_CD, + .wp_gpio = -1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .support_18v = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +#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 arm2_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), +}; + +static struct regulator_init_data arm2_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(arm2_vmmc_consumers), + .consumer_supplies = arm2_vmmc_consumers, +}; + +static struct fixed_voltage_config arm2_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &arm2_vmmc_init, +}; + +static struct platform_device arm2_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &arm2_vmmc_reg_config, + }, +}; + +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 const struct anatop_thermal_platform_data + mx6sl_anatop_thermal_data __initconst = { + .name = "anatop_thermal", + }; + +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 = MX6SL_BRD_EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = MX6SL_BRD_EPDC_VCOM, + .gpio_pmic_wakeup = MX6SL_BRD_EPDC_PMIC_WAKE, + .gpio_pmic_v3p3 = MX6SL_BRD_EPDC_PWRCTRL0, + .gpio_pmic_intr = MX6SL_BRD_EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int __init 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; + } + } + + /* + * TODO: We cannot enable full constraints for now, since + * it results in the PFUZE regulators being disabled + * at the end of boot, which disables critical regulators. + */ + /*regulator_has_full_constraints();*/ + + return 0; +} + +static int mx6_arm2_spi_cs[] = { + MX6_BRD_ECSPI1_CS0, +}; + +static const struct spi_imx_master mx6_arm2_spi_data __initconst = { + .chipselect = mx6_arm2_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6_arm2_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition m25p32_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00100000, + }, { + .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", +}; + +static struct spi_board_info m25p32_spi0_board_info[] __initdata = { + { + /* The modalias must be the same as spi device driver name */ + .modalias = "m25p80", + .max_speed_hz = 20000000, + .bus_num = 0, + .chip_select = 0, + .platform_data = &m25p32_spi_flash_data, + }, +}; +#endif + +static void spi_device_init(void) +{ +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + spi_register_board_info(m25p32_spi0_board_info, + ARRAY_SIZE(m25p32_spi0_board_info)); +#endif +} + +static struct imx_ssi_platform_data mx6_sabresd_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct mxc_audio_platform_data wm8962_data; + +static struct platform_device mx6_sabresd_audio_wm8962_device = { + .name = "imx-wm8962", +}; + +static struct wm8962_pdata wm8962_config_data = { + +}; + +static int wm8962_clk_enable(int enable) +{ + if (enable) + clk_enable(extern_audio_root); + else + clk_disable(extern_audio_root); + + return 0; +} + +static int mxc_wm8962_init(void) +{ + struct clk *pll4; + int rate; + + extern_audio_root = clk_get(NULL, "extern_audio_clk"); + if (IS_ERR(extern_audio_root)) { + pr_err("can't get extern_audio_root clock.\n"); + return PTR_ERR(extern_audio_root); + } + + pll4 = clk_get(NULL, "pll4"); + if (IS_ERR(pll4)) { + pr_err("can't get pll4 clock.\n"); + return PTR_ERR(pll4); + } + + clk_set_parent(extern_audio_root, pll4); + + rate = 24000000; + clk_set_rate(extern_audio_root, 24000000); + + wm8962_data.sysclk = rate; + + return 0; +} + +static struct mxc_audio_platform_data wm8962_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_gpio = MX6_BRD_HEADPHONE_DET, + .hp_active_low = 1, + .mic_gpio = -1, + .mic_active_low = 1, + .init = mxc_wm8962_init, + .clock_enable = wm8962_clk_enable, +}; + +static struct regulator_consumer_supply sabresd_vwm8962_consumers[] = { + REGULATOR_SUPPLY("SPKVDD1", "1-001a"), + REGULATOR_SUPPLY("SPKVDD2", "1-001a"), +}; + +static struct regulator_init_data sabresd_vwm8962_init = { + .constraints = { + .name = "SPKVDD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sabresd_vwm8962_consumers), + .consumer_supplies = sabresd_vwm8962_consumers, +}; + +static struct fixed_voltage_config sabresd_vwm8962_reg_config = { + .supply_name = "SPKVDD", + .microvolts = 4325000, + .gpio = -1, + .enabled_at_boot = 1, + .init_data = &sabresd_vwm8962_init, +}; + +static struct platform_device sabresd_vwm8962_reg_devices = { + .name = "reg-fixed-voltage", + .id = 4, + .dev = { + .platform_data = &sabresd_vwm8962_reg_config, + }, +}; + +static int __init imx6q_init_audio(void) +{ + platform_device_register(&sabresd_vwm8962_reg_devices); + mxc_register_device(&mx6_sabresd_audio_wm8962_device, + &wm8962_data); + imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata); + + return 0; +} + +static struct imxi2c_platform_data mx6_arm2_i2c0_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_arm2_i2c1_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_arm2_i2c2_data = { + .bitrate = 400000, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0x48), + .platform_data = &max17135_pdata, + }, { + I2C_BOARD_INFO("elan-touch", 0x10), + .irq = gpio_to_irq(MX6SL_BRD_ELAN_INT), + }, { + I2C_BOARD_INFO("mma8450", 0x1c), + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("wm8962", 0x1a), + .platform_data = &wm8962_config_data, + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + }, +}; + +static struct mxc_dvfs_platform_data mx6sl_arm2_dvfscore_data = { +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + .reg_id = "VDDCORE", + .soc_id = "VDDSOC", +#else + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", +#endif + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_32M, +}; + +void __init early_console_setup(unsigned long base, struct clk *clk); + +static inline void mx6_arm2_init_uart(void) +{ + imx6q_add_imx_uart(0, NULL); /* DEBUG UART1 */ +} + +static int mx6sl_arm2_fec_phy_init(struct phy_device *phydev) +{ + int val; + + /* power on FEC phy and reset phy */ + gpio_request(MX6_BRD_FEC_PWR_EN, "fec-pwr"); + gpio_direction_output(MX6_BRD_FEC_PWR_EN, 0); + /* wait RC ms for hw reset */ + msleep(1); + gpio_direction_output(MX6_BRD_FEC_PWR_EN, 1); + + /* check phy power */ + val = phy_read(phydev, 0x0); + if (val & BMCR_PDOWN) { + phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); + } + + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6sl_arm2_fec_phy_init, + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static int epdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for EPDC pins - used during power up/down */ + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_0, "epdc_d0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_1, "epdc_d1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_2, "epdc_d2"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_3, "epdc_d3"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_4, "epdc_d4"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_5, "epdc_d5"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_6, "epdc_d6"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_7, "epdc_d7"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDCLK, "epdc_gdclk"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDSP, "epdc_gdsp"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDOE, "epdc_gdoe"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDRL, "epdc_gdrl"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCLK, "epdc_sdclk"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDOE, "epdc_sdoe"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDLE, "epdc_sdle"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDSHR, "epdc_sdshr"); + ret |= gpio_request(MX6SL_BRD_EPDC_BDR0, "epdc_bdr0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE0, "epdc_sdce0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE1, "epdc_sdce1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE2, "epdc_sdce2"); + + return ret; +} + +static void epdc_put_pins(void) +{ + gpio_free(MX6SL_BRD_EPDC_SDDO_0); + gpio_free(MX6SL_BRD_EPDC_SDDO_1); + gpio_free(MX6SL_BRD_EPDC_SDDO_2); + gpio_free(MX6SL_BRD_EPDC_SDDO_3); + gpio_free(MX6SL_BRD_EPDC_SDDO_4); + gpio_free(MX6SL_BRD_EPDC_SDDO_5); + gpio_free(MX6SL_BRD_EPDC_SDDO_6); + gpio_free(MX6SL_BRD_EPDC_SDDO_7); + gpio_free(MX6SL_BRD_EPDC_GDCLK); + gpio_free(MX6SL_BRD_EPDC_GDSP); + gpio_free(MX6SL_BRD_EPDC_GDOE); + gpio_free(MX6SL_BRD_EPDC_GDRL); + gpio_free(MX6SL_BRD_EPDC_SDCLK); + gpio_free(MX6SL_BRD_EPDC_SDOE); + gpio_free(MX6SL_BRD_EPDC_SDLE); + gpio_free(MX6SL_BRD_EPDC_SDSHR); + gpio_free(MX6SL_BRD_EPDC_BDR0); + gpio_free(MX6SL_BRD_EPDC_SDCE0); + gpio_free(MX6SL_BRD_EPDC_SDCE1); + gpio_free(MX6SL_BRD_EPDC_SDCE2); +} + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_epdc_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_epdc_enable_pads)); + + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_0); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_1); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_2); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_3); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_4); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_5); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_6); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_7); + gpio_direction_input(MX6SL_BRD_EPDC_GDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_GDSP); + gpio_direction_input(MX6SL_BRD_EPDC_GDOE); + gpio_direction_input(MX6SL_BRD_EPDC_GDRL); + gpio_direction_input(MX6SL_BRD_EPDC_SDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDOE); + gpio_direction_input(MX6SL_BRD_EPDC_SDLE); + gpio_direction_input(MX6SL_BRD_EPDC_SDSHR); + gpio_direction_input(MX6SL_BRD_EPDC_BDR0); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE0); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE1); + gpio_direction_input(MX6SL_BRD_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(mx6sl_brd_epdc_disable_pads, \ + ARRAY_SIZE(mx6sl_brd_epdc_disable_pads)); + + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_2, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_3, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_4, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_5, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_6, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_7, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDSP, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDRL, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDLE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDSHR, 0); + gpio_direction_output(MX6SL_BRD_EPDC_BDR0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE1, 0); + gpio_direction_output(MX6SL_BRD_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, + .refresh = 85, + .xres = 800, + .yres = 600, +}; +static struct fb_videomode e060scm_mode = { + .name = "E060SCM", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 26666667, + .left_margin = 8, + .right_margin = 100, + .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 */ + }, + { + &e060scm_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 419, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 5, /* 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 int spdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for SPDC pins - used during power up/down */ + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_0, "SPDC_D0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_1, "SPDC_D1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_2, "SPDC_D2"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_3, "SPDC_D3"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_4, "SPDC_D4"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_5, "SPDC_D5"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_6, "SPDC_D6"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_7, "SPDC_D7"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDOE, "SIPIX_YOE"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_9, "SIPIX_PWR_RDY"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDSP, "SIPIX_YDIO"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDCLK, "SIPIX_YCLK"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDSHR, "SIPIX_XDIO"); + + ret |= gpio_request(MX6SL_BRD_EPDC_SDLE, "SIPIX_LD"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE1, "SIPIX_SOE"); + + ret |= gpio_request(MX6SL_BRD_EPDC_SDCLK, "SIPIX_XCLK"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_10, "SIPIX_SHD_N"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE0, "SIPIX2_CE"); + + return ret; +} + +static void spdc_put_pins(void) +{ + gpio_free(MX6SL_BRD_EPDC_SDDO_0); + gpio_free(MX6SL_BRD_EPDC_SDDO_1); + gpio_free(MX6SL_BRD_EPDC_SDDO_2); + gpio_free(MX6SL_BRD_EPDC_SDDO_3); + gpio_free(MX6SL_BRD_EPDC_SDDO_4); + gpio_free(MX6SL_BRD_EPDC_SDDO_5); + gpio_free(MX6SL_BRD_EPDC_SDDO_6); + gpio_free(MX6SL_BRD_EPDC_SDDO_7); + + gpio_free(MX6SL_BRD_EPDC_GDOE); + gpio_free(MX6SL_BRD_EPDC_SDDO_9); + gpio_free(MX6SL_BRD_EPDC_GDSP); + gpio_free(MX6SL_BRD_EPDC_GDCLK); + gpio_free(MX6SL_BRD_EPDC_SDSHR); + gpio_free(MX6SL_BRD_EPDC_SDLE); + gpio_free(MX6SL_BRD_EPDC_SDCE1); + gpio_free(MX6SL_BRD_EPDC_SDCLK); + gpio_free(MX6SL_BRD_EPDC_SDDO_10); + gpio_free(MX6SL_BRD_EPDC_SDCE0); +} + +static void spdc_enable_pins(void) +{ + /* Configure MUX settings to enable SPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_spdc_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_spdc_enable_pads)); + + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_0); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_1); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_2); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_3); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_4); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_5); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_6); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_7); + gpio_direction_input(MX6SL_BRD_EPDC_GDOE); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_9); + gpio_direction_input(MX6SL_BRD_EPDC_GDSP); + gpio_direction_input(MX6SL_BRD_EPDC_GDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDSHR); + gpio_direction_input(MX6SL_BRD_EPDC_SDLE); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE1); + gpio_direction_input(MX6SL_BRD_EPDC_SDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_10); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE0); +} + +static void spdc_disable_pins(void) +{ + /* Configure MUX settings for SPDC pins to + * GPIO and drive to 0. */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_spdc_disable_pads, \ + ARRAY_SIZE(mx6sl_brd_spdc_disable_pads)); + + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_2, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_3, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_4, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_5, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_6, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_7, 0); + + gpio_direction_output(MX6SL_BRD_EPDC_GDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_9, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDSP, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDSHR, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDLE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_10, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE0, 0); +} + +static struct imx_spdc_panel_init_set spdc_init_set = { + .yoe_pol = false, + .dual_gate = false, + .resolution = 0, + .ud = false, + .rl = false, + .data_filter_n = true, + .power_ready = true, + .rgbw_mode_enable = false, + .hburst_len_en = true, +}; + +static struct fb_videomode erk_1_4_a01 = { + .name = "ERK_1_4_A01", + .refresh = 50, + .xres = 800, + .yres = 600, + .pixclock = 40000000, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct imx_spdc_fb_mode spdc_panel_modes[] = { + { + &erk_1_4_a01, + &spdc_init_set, + .wave_timing = "pvi" + }, +}; + +static struct imx_spdc_fb_platform_data spdc_data = { + .spdc_mode = spdc_panel_modes, + .num_modes = ARRAY_SIZE(spdc_panel_modes), + .get_pins = spdc_get_pins, + .put_pins = spdc_put_pins, + .enable_pins = spdc_enable_pins, + .disable_pins = spdc_disable_pins, +}; + +static int __init early_use_spdc_sel(char *p) +{ + spdc_sel = 1; + return 0; +} +early_param("spdc", early_use_spdc_sel); + +static void setup_spdc(void) +{ + /* GPR0[8]: 0:EPDC, 1:SPDC */ + if (spdc_sel) + mxc_iomux_set_gpr_register(0, 8, 1, 1); +} + +static void imx6_arm2_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(MX6_BRD_USBOTG1_PWR, 1); + else + gpio_set_value(MX6_BRD_USBOTG1_PWR, 0); +} + +static void __init mx6_arm2_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + + /* disable external charger detect, + * or it will affect signal quality at dp. + */ + + ret = gpio_request(MX6_BRD_USBOTG1_PWR, "usbotg-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_BRD_USBOTG1_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_BRD_USBOTG1_PWR, 0); + + ret = gpio_request(MX6_BRD_USBOTG2_PWR, "usbh1-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_BRD_USBOTG2_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_BRD_USBOTG2_PWR, 1); + + mx6_set_otghost_vbus_func(imx6_arm2_usbotg_vbus); +#ifdef CONFIG_USB_EHCI_ARC_HSIC + mxc_iomux_set_specialbits_register(MX6SL_PAD_HSIC_DAT, + PAD_CTL_DDR_SEL_DDR3, PAD_CTL_DDR_SEL_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_HSIC_STROBE, + PAD_CTL_DDR_SEL_DDR3, PAD_CTL_DDR_SEL_MASK); + + mx6_usb_h2_init(); +#endif +} + +static struct platform_pwm_backlight_data mx6_arm2_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; +static struct fb_videomode video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 32MHz */ + "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB24, + .mode_str = "SEIKO-WVGA", + .mode = video_modes, + .num_modes = ARRAY_SIZE(video_modes), + }, +}; + +static struct platform_device lcd_wvga_device = { + .name = "lcd_seiko", +}; + +static int mx6sl_arm2_keymap[] = { + KEY(0, 0, KEY_SELECT), + KEY(0, 1, KEY_BACK), + KEY(0, 2, KEY_F1), + KEY(0, 3, KEY_F2), + + KEY(1, 0, KEY_F3), + KEY(1, 1, KEY_F4), + KEY(1, 2, KEY_POWER), + KEY(1, 3, KEY_MENU), + + KEY(2, 0, KEY_PREVIOUS), + KEY(2, 1, KEY_NEXT), + KEY(2, 2, KEY_HOME), + KEY(2, 3, KEY_NEXT), + + KEY(3, 0, KEY_UP), + KEY(3, 1, KEY_LEFT), + KEY(3, 2, KEY_RIGHT), + KEY(3, 3, KEY_DOWN), +}; + +static const struct matrix_keymap_data mx6sl_arm2_map_data __initconst = { + .keymap = mx6sl_arm2_keymap, + .keymap_size = ARRAY_SIZE(mx6sl_arm2_keymap), +}; +static void __init elan_ts_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_elan_pads, + ARRAY_SIZE(mx6sl_brd_elan_pads)); + + /* ELAN Touchscreen */ + gpio_request(MX6SL_BRD_ELAN_INT, "elan-interrupt"); + gpio_direction_input(MX6SL_BRD_ELAN_INT); + + gpio_request(MX6SL_BRD_ELAN_CE, "elan-cs"); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 0); + + gpio_request(MX6SL_BRD_ELAN_RST, "elan-rst"); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 1); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 0); + mdelay(1); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 1); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); +} + +#define SNVS_LPCR 0x38 +static void mx6_snvs_poweroff(void) +{ + u32 value; + void __iomem *mx6_snvs_base = MX6_IO_ADDRESS(MX6Q_SNVS_BASE_ADDR); + + value = readl(mx6_snvs_base + SNVS_LPCR); + /* set TOP and DP_EN bit */ + writel(value | 0x60, mx6_snvs_base + SNVS_LPCR); +} + +/*! + * Board specific initialization. + */ +static void __init mx6_arm2_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_pads, + ARRAY_SIZE(mx6sl_brd_pads)); + + elan_ts_init(); + +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + gp_reg_id = mx6sl_arm2_dvfscore_data.reg_id; + soc_reg_id = mx6sl_arm2_dvfscore_data.soc_id; +#else + gp_reg_id = mx6sl_arm2_dvfscore_data.reg_id; + soc_reg_id = mx6sl_arm2_dvfscore_data.soc_id; + pu_reg_id = mx6sl_arm2_dvfscore_data.pu_id; + mx6_cpu_regulator_init(); +#endif + + imx6q_add_imx_snvs_rtc(); + + imx6q_add_imx_i2c(0, &mx6_arm2_i2c0_data); + imx6q_add_imx_i2c(1, &mx6_arm2_i2c1_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)); + imx6q_add_imx_i2c(2, &mx6_arm2_i2c2_data); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + + /* SPI */ + imx6q_add_ecspi(0, &mx6_arm2_spi_data); + spi_device_init(); + + mx6sl_arm2_init_pfuze100(0); + + imx6q_add_anatop_thermal_imx(1, &mx6sl_anatop_thermal_data); + + mx6_arm2_init_uart(); + /* get enet tx reference clk from FEC_REF_CLK pad. + * GPR1[14] = 0, GPR1[18:17] = 00 + */ + mxc_iomux_set_gpr_register(1, 14, 1, 0); + mxc_iomux_set_gpr_register(1, 17, 2, 0); + + imx6_init_fec(fec_data); + + platform_device_register(&arm2_vmmc_reg_devices); + imx6q_add_sdhci_usdhc_imx(0, &mx6_arm2_sd1_data); + imx6q_add_sdhci_usdhc_imx(1, &mx6_arm2_sd2_data); + imx6q_add_sdhci_usdhc_imx(2, &mx6_arm2_sd3_data); + + mx6_arm2_init_usb(); + imx6q_add_otp(); + imx6q_add_mxc_pwm(0); + imx6q_add_mxc_pwm_backlight(0, &mx6_arm2_pwm_backlight_data); +#ifdef CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF//[ + imx6dl_add_imx_elcdif(&fb_data[0]); +#endif //]CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF + gpio_request(MX6_BRD_LCD_PWR_EN, "elcdif-power-on"); + gpio_direction_output(MX6_BRD_LCD_PWR_EN, 1); + mxc_register_device(&lcd_wvga_device, NULL); + + imx6dl_add_imx_pxp(); + imx6dl_add_imx_pxp_client(); + mxc_register_device(&max17135_sensor_device, NULL); + setup_spdc(); + if (!spdc_sel) + imx6dl_add_imx_epdc(&epdc_data); + else + imx6sl_add_imx_spdc(&spdc_data); + imx6q_add_dvfs_core(&mx6sl_arm2_dvfscore_data); + + imx6q_init_audio(); + + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + imx6sl_add_imx_keypad(&mx6sl_arm2_map_data); + imx6q_add_busfreq(); + imx6sl_add_dcp(); + imx6sl_add_rngb(); + imx6sl_add_imx_pxp_v4l2(); + + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); + + pm_power_off = mx6_snvs_poweroff; +} + +extern void __iomem *twd_base; +static void __init mx6_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6sl_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART1_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx6_timer_init, +}; + +static void __init mx6_arm2_reserve(void) +{ +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + phys_addr_t phys; + + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, MEMBLOCK_ALLOC_ACCESSIBLE); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif +} + +MACHINE_START(MX6SL_ARM2, "Freescale i.MX 6SoloLite Armadillo2 Board") + .boot_params = MX6SL_PHYS_OFFSET + 0x100, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_arm2_init, + .timer = &mxc_timer, + .reserve = mx6_arm2_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6sl_common.h b/arch/arm/mach-mx6/board-mx6sl_common.h new file mode 100644 index 00000000..4eab0b35 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6sl_common.h @@ -0,0 +1,578 @@ +/* + * 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. + */ + +#ifndef _BOARD_MX6SL_COMMON_H +#define _BOARD_MX6SL_COMMON_H +#include <mach/iomux-mx6sl.h> + +#define MX6_BRD_LCD_RESET IMX_GPIO_NR(2, 19) /* LCD_REST */ + +#define MX6_BRD_USBOTG1_PWR IMX_GPIO_NR(4, 0) /* KEY_COL4 */ +#define MX6_BRD_USBOTG2_PWR IMX_GPIO_NR(4, 2) /* KEY_COL5 */ +#define MX6_BRD_LCD_PWR_EN IMX_GPIO_NR(4, 3) /* KEY_ROW5 */ +#define MX6_BRD_SD1_WP IMX_GPIO_NR(4, 6) /* KEY_COL7 */ +#define MX6_BRD_SD1_CD IMX_GPIO_NR(4, 7) /* KEY_ROW7 */ +#define MX6_BRD_ECSPI1_CS0 IMX_GPIO_NR(4, 11) /* ECSPI1_SS0 */ +#define MX6_BRD_HEADPHONE_DET IMX_GPIO_NR(4, 19) /* FEC_RX_ER */ +#define MX6_BRD_SD2_WP IMX_GPIO_NR(4, 29) /* SD2_DAT6 */ +#define MX6_BRD_SD2_CD IMX_GPIO_NR(5, 0) /* SD2_DAT7 */ +#define MX6_BRD_SD3_CD IMX_GPIO_NR(3, 22) /* REF_CLK_32K */ +#define MX6_BRD_FEC_PWR_EN IMX_GPIO_NR(4, 21) /* FEC_TX_CLK */ +#define MX6_BRD_CHG_FLT IMX_GPIO_NR(4, 14) /* ECSPI2_MISO */ +#define MX6_BRD_CHG_UOK IMX_GPIO_NR(4, 13) /* ECSPI2_MOSI */ +#define MX6_BRD_CHG_DOK IMX_GPIO_NR(4, 13) /* ECSPI2_MOSI */ +#define MX6_BRD_CHG_STATUS IMX_GPIO_NR(4, 15) /* ECSPI2_SS0 */ + +/* EPDC GPIO pins */ +#define MX6SL_BRD_EPDC_SDDO_0 IMX_GPIO_NR(1, 7) +#define MX6SL_BRD_EPDC_SDDO_1 IMX_GPIO_NR(1, 8) +#define MX6SL_BRD_EPDC_SDDO_2 IMX_GPIO_NR(1, 9) +#define MX6SL_BRD_EPDC_SDDO_3 IMX_GPIO_NR(1, 10) +#define MX6SL_BRD_EPDC_SDDO_4 IMX_GPIO_NR(1, 11) +#define MX6SL_BRD_EPDC_SDDO_5 IMX_GPIO_NR(1, 12) +#define MX6SL_BRD_EPDC_SDDO_6 IMX_GPIO_NR(1, 13) +#define MX6SL_BRD_EPDC_SDDO_7 IMX_GPIO_NR(1, 14) +#define MX6SL_BRD_EPDC_SDDO_8 IMX_GPIO_NR(1, 15) +#define MX6SL_BRD_EPDC_SDDO_9 IMX_GPIO_NR(1, 16) +#define MX6SL_BRD_EPDC_SDDO_10 IMX_GPIO_NR(1, 17) +#define MX6SL_BRD_EPDC_SDDO_11 IMX_GPIO_NR(1, 18) +#define MX6SL_BRD_EPDC_SDDO_12 IMX_GPIO_NR(1, 19) +#define MX6SL_BRD_EPDC_SDDO_13 IMX_GPIO_NR(1, 20) +#define MX6SL_BRD_EPDC_SDDO_14 IMX_GPIO_NR(1, 21) +#define MX6SL_BRD_EPDC_SDDO_15 IMX_GPIO_NR(1, 22) +#define MX6SL_BRD_EPDC_GDCLK IMX_GPIO_NR(1, 31) +#define MX6SL_BRD_EPDC_GDSP IMX_GPIO_NR(2, 2) +#define MX6SL_BRD_EPDC_GDOE IMX_GPIO_NR(2, 0) +#define MX6SL_BRD_EPDC_GDRL IMX_GPIO_NR(2, 1) +#define MX6SL_BRD_EPDC_SDCLK IMX_GPIO_NR(1, 23) +#define MX6SL_BRD_EPDC_SDOE IMX_GPIO_NR(1, 25) +#define MX6SL_BRD_EPDC_SDLE IMX_GPIO_NR(1, 24) +#define MX6SL_BRD_EPDC_SDSHR IMX_GPIO_NR(1, 26) +#define MX6SL_BRD_EPDC_PWRCOM IMX_GPIO_NR(2, 11) +#define MX6SL_BRD_EPDC_PWRSTAT IMX_GPIO_NR(2, 13) +#define MX6SL_BRD_EPDC_PWRCTRL0 IMX_GPIO_NR(2, 7) +#define MX6SL_BRD_EPDC_PWRCTRL1 IMX_GPIO_NR(2, 8) +#define MX6SL_BRD_EPDC_PWRCTRL2 IMX_GPIO_NR(2, 9) +#define MX6SL_BRD_EPDC_PWRCTRL3 IMX_GPIO_NR(2, 10) +#define MX6SL_BRD_EPDC_BDR0 IMX_GPIO_NR(2, 5) +#define MX6SL_BRD_EPDC_BDR1 IMX_GPIO_NR(2, 6) +#define MX6SL_BRD_EPDC_SDCE0 IMX_GPIO_NR(1, 27) +#define MX6SL_BRD_EPDC_SDCE1 IMX_GPIO_NR(1, 28) +#define MX6SL_BRD_EPDC_SDCE2 IMX_GPIO_NR(1, 29) +#define MX6SL_BRD_EPDC_SDCE3 IMX_GPIO_NR(1, 30) +#define MX6SL_BRD_EPDC_PMIC_WAKE IMX_GPIO_NR(2, 14) /* EPDC_PWRWAKEUP */ +#define MX6SL_BRD_EPDC_PMIC_INT IMX_GPIO_NR(2, 12) /* EPDC_PWRINT */ +#define MX6SL_BRD_EPDC_VCOM IMX_GPIO_NR(2, 3) +/* ELAN TS */ +#define MX6SL_BRD_ELAN_CE IMX_GPIO_NR(2, 9) +#define MX6SL_BRD_ELAN_INT IMX_GPIO_NR(2, 10) +#define MX6SL_BRD_ELAN_RST IMX_GPIO_NR(4, 4) +/* CSI */ +#define MX6SL_BRD_CSI_PWDN IMX_GPIO_NR(1, 25) +#define MX6SL_BRD_CSI_RST IMX_GPIO_NR(1, 26) + +static iomux_v3_cfg_t mx6sl_brd_pads[] = { + + /* AUDMUX */ + MX6SL_PAD_AUD_TXC__AUDMUX_AUD3_TXC, + MX6SL_PAD_AUD_TXD__AUDMUX_AUD3_TXD, + MX6SL_PAD_AUD_TXFS__AUDMUX_AUD3_TXFS, + MX6SL_PAD_AUD_RXD__AUDMUX_AUD3_RXD, + MX6SL_PAD_AUD_MCLK__AUDMUX_AUDIO_CLK_OUT, + + /* Audio Codec */ + MX6SL_PAD_FEC_RX_ER__GPIO_4_19, /* HEADPHONE_DET */ + + /* SPDIF TX */ + MX6SL_PAD_SD2_DAT4__SPDIF_OUT1, + + /* UART1 */ + MX6SL_PAD_UART1_RXD__UART1_RXD, + MX6SL_PAD_UART1_TXD__UART1_TXD, + + /* USBOTG ID pin */ +#ifndef CONFIG_USB_ID_WAKEUP_ENABLE + MX6SL_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID, +#endif + + /* USBOTG POWER GPIO */ + MX6SL_PAD_KEY_COL4__GPIO_4_0, + MX6SL_PAD_KEY_COL5__GPIO_4_2, + /* USB OC pin */ + MX6SL_PAD_KEY_ROW4__USB_USBOTG1_OC, + MX6SL_PAD_ECSPI2_SCLK__USB_USBOTG2_OC, + /* USB HSIC pin */ + MX6SL_PAD_HSIC_STROBE__USB_H_STROBE, + MX6SL_PAD_HSIC_DAT__USB_H_DATA, + + /* SD1 */ + MX6SL_PAD_SD1_CLK__USDHC1_CLK_50MHZ, + MX6SL_PAD_SD1_CMD__USDHC1_CMD_50MHZ, + MX6SL_PAD_SD1_DAT0__USDHC1_DAT0_50MHZ, + MX6SL_PAD_SD1_DAT1__USDHC1_DAT1_50MHZ, + MX6SL_PAD_SD1_DAT2__USDHC1_DAT2_50MHZ, + MX6SL_PAD_SD1_DAT3__USDHC1_DAT3_50MHZ, + MX6SL_PAD_SD1_DAT4__USDHC1_DAT4_50MHZ, + MX6SL_PAD_SD1_DAT5__USDHC1_DAT5_50MHZ, + MX6SL_PAD_SD1_DAT6__USDHC1_DAT6_50MHZ, + MX6SL_PAD_SD1_DAT7__USDHC1_DAT7_50MHZ, + /* SD1 CD & WP */ + MX6SL_PAD_KEY_ROW7__GPIO_4_7, + MX6SL_PAD_KEY_COL7__GPIO_4_6, + /* SD2 */ + MX6SL_PAD_SD2_CLK__USDHC2_CLK_50MHZ, + MX6SL_PAD_SD2_CMD__USDHC2_CMD_50MHZ, + MX6SL_PAD_SD2_DAT0__USDHC2_DAT0_50MHZ, + MX6SL_PAD_SD2_DAT1__USDHC2_DAT1_50MHZ, + MX6SL_PAD_SD2_DAT2__USDHC2_DAT2_50MHZ, + MX6SL_PAD_SD2_DAT3__USDHC2_DAT3_50MHZ, + /* SD2 CD & WP */ + MX6SL_PAD_SD2_DAT7__GPIO_5_0, + //MX6SL_PAD_SD2_DAT6__GPIO_4_29, + /* SD3 */ + MX6SL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6SL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6SL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6SL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6SL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6SL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + /* SD3 CD */ + MX6SL_PAD_REF_CLK_32K__GPIO_3_22, + + /* FEC */ + MX6SL_PAD_FEC_MDC__FEC_MDC, + MX6SL_PAD_FEC_MDIO__FEC_MDIO, + MX6SL_PAD_FEC_REF_CLK__FEC_REF_OUT, /* clock from anatop */ + MX6SL_PAD_FEC_RX_ER__GPIO_4_19, + MX6SL_PAD_FEC_CRS_DV__FEC_RX_DV, + MX6SL_PAD_FEC_RXD0__FEC_RDATA_0, + MX6SL_PAD_FEC_RXD1__FEC_RDATA_1, + MX6SL_PAD_FEC_TX_EN__FEC_TX_EN, + MX6SL_PAD_FEC_TXD0__FEC_TDATA_0, + MX6SL_PAD_FEC_TXD1__FEC_TDATA_1, + MX6SL_PAD_FEC_TX_CLK__GPIO_4_21, /* Phy power enable */ + + /* I2C */ + MX6SL_PAD_I2C1_SCL__I2C1_SCL, + MX6SL_PAD_I2C1_SDA__I2C1_SDA, + MX6SL_PAD_I2C2_SCL__I2C2_SCL, + MX6SL_PAD_I2C2_SDA__I2C2_SDA, + + /* ECSPI1 */ + MX6SL_PAD_ECSPI1_MISO__ECSPI1_MISO, + MX6SL_PAD_ECSPI1_MOSI__ECSPI1_MOSI, + MX6SL_PAD_ECSPI1_SCLK__ECSPI1_SCLK, + MX6SL_PAD_ECSPI1_SS0__ECSPI1_SS0, + MX6SL_PAD_ECSPI1_SS0__GPIO_4_11, /* SS0 */ + + /* LCD */ +#if 0//[ + + MX6SL_PAD_LCD_CLK__LCDIF_CLK, + MX6SL_PAD_LCD_ENABLE__LCDIF_ENABLE, + MX6SL_PAD_LCD_HSYNC__LCDIF_HSYNC, + MX6SL_PAD_LCD_VSYNC__LCDIF_VSYNC, + MX6SL_PAD_LCD_RESET__LCDIF_RESET, + MX6SL_PAD_LCD_DAT0__LCDIF_DAT_0, + MX6SL_PAD_LCD_DAT1__LCDIF_DAT_1, + MX6SL_PAD_LCD_DAT2__LCDIF_DAT_2, + MX6SL_PAD_LCD_DAT3__LCDIF_DAT_3, + MX6SL_PAD_LCD_DAT4__LCDIF_DAT_4, + MX6SL_PAD_LCD_DAT5__LCDIF_DAT_5, + MX6SL_PAD_LCD_DAT6__LCDIF_DAT_6, + MX6SL_PAD_LCD_DAT7__LCDIF_DAT_7, + MX6SL_PAD_LCD_DAT8__LCDIF_DAT_8, + MX6SL_PAD_LCD_DAT9__LCDIF_DAT_9, + MX6SL_PAD_LCD_DAT10__LCDIF_DAT_10, + MX6SL_PAD_LCD_DAT11__LCDIF_DAT_11, + MX6SL_PAD_LCD_DAT12__LCDIF_DAT_12, + MX6SL_PAD_LCD_DAT13__LCDIF_DAT_13, + MX6SL_PAD_LCD_DAT14__LCDIF_DAT_14, + MX6SL_PAD_LCD_DAT15__LCDIF_DAT_15, + MX6SL_PAD_LCD_DAT16__LCDIF_DAT_16, + MX6SL_PAD_LCD_DAT17__LCDIF_DAT_17, + MX6SL_PAD_LCD_DAT18__LCDIF_DAT_18, + MX6SL_PAD_LCD_DAT19__LCDIF_DAT_19, + MX6SL_PAD_LCD_DAT20__LCDIF_DAT_20, + MX6SL_PAD_LCD_DAT21__LCDIF_DAT_21, + MX6SL_PAD_LCD_DAT22__LCDIF_DAT_22, + MX6SL_PAD_LCD_DAT23__LCDIF_DAT_23, +#else//][! + + MX6SL_PAD_LCD_CLK__GPIO_2_15, + MX6SL_PAD_LCD_ENABLE__GPIO_2_16, + MX6SL_PAD_LCD_HSYNC__GPIO_2_17, + MX6SL_PAD_LCD_VSYNC__GPIO_2_18, + MX6SL_PAD_LCD_RESET__GPIO_2_19, + + MX6SL_PAD_LCD_DAT0__GPIO_2_20, + MX6SL_PAD_LCD_DAT1__GPIO_2_21, + MX6SL_PAD_LCD_DAT2__GPIO_2_22, + MX6SL_PAD_LCD_DAT3__GPIO_2_23, + MX6SL_PAD_LCD_DAT4__GPIO_2_24, + MX6SL_PAD_LCD_DAT5__GPIO_2_25, + MX6SL_PAD_LCD_DAT6__GPIO_2_26, + MX6SL_PAD_LCD_DAT8__GPIO_2_28, + MX6SL_PAD_LCD_DAT9__GPIO_2_29, + MX6SL_PAD_LCD_DAT10__GPIO_2_30, + MX6SL_PAD_LCD_DAT11__GPIO_2_31, + MX6SL_PAD_LCD_DAT12__GPIO_3_0, + MX6SL_PAD_LCD_DAT13__GPIO_3_1, + MX6SL_PAD_LCD_DAT14__GPIO_3_2, + MX6SL_PAD_LCD_DAT15__GPIO_3_3, + MX6SL_PAD_LCD_DAT16__GPIO_3_4, + MX6SL_PAD_LCD_DAT17__GPIO_3_5, + MX6SL_PAD_LCD_DAT18__GPIO_3_6, + MX6SL_PAD_LCD_DAT19__GPIO_3_7, + MX6SL_PAD_LCD_DAT20__GPIO_3_8, + MX6SL_PAD_LCD_DAT21__GPIO_3_9, + MX6SL_PAD_LCD_DAT22__GPIO_3_10, + MX6SL_PAD_LCD_DAT23__GPIO_3_11, + +#endif //] + + /* LCD brightness */ + MX6SL_PAD_PWM1__PWM1_PWMO, + /* LCD power on */ + //MX6SL_PAD_KEY_ROW5__GPIO_4_3, + + /* keypad on E-Ink add-on board */ + MX6SL_PAD_KEY_COL0__KPP_COL_0, + MX6SL_PAD_KEY_COL1__KPP_COL_1, + MX6SL_PAD_KEY_COL2__KPP_COL_2, + MX6SL_PAD_KEY_COL3__KPP_COL_3, + MX6SL_PAD_KEY_ROW0__KPP_ROW_0, + MX6SL_PAD_KEY_ROW1__KPP_ROW_1, + MX6SL_PAD_KEY_ROW2__KPP_ROW_2, + MX6SL_PAD_KEY_ROW3__KPP_ROW_3, + + /* WDOG */ + MX6SL_PAD_WDOG_B__WDOG1_WDOG_B, + + /* Charge */ + MX6SL_PAD_ECSPI2_MISO__GPIO_4_14, /* CHG_FLT */ + MX6SL_PAD_ECSPI2_SS0__GPIO_4_15, /* CHG_STATUS */ + MX6SL_PAD_ECSPI2_MOSI__GPIO_4_13, /* CHG_UOK ,CHG_DOK*/ +}; + +static iomux_v3_cfg_t mx6sl_brd_epdc_enable_pads[] = { + /* EPDC */ + MX6SL_PAD_EPDC_D0__EPDC_SDDO_0, + MX6SL_PAD_EPDC_D1__EPDC_SDDO_1, + MX6SL_PAD_EPDC_D2__EPDC_SDDO_2, + MX6SL_PAD_EPDC_D3__EPDC_SDDO_3, + MX6SL_PAD_EPDC_D4__EPDC_SDDO_4, + MX6SL_PAD_EPDC_D5__EPDC_SDDO_5, + MX6SL_PAD_EPDC_D6__EPDC_SDDO_6, + MX6SL_PAD_EPDC_D7__EPDC_SDDO_7, + MX6SL_PAD_EPDC_D8__EPDC_SDDO_8, + MX6SL_PAD_EPDC_D9__EPDC_SDDO_9, + MX6SL_PAD_EPDC_D10__EPDC_SDDO_10, + MX6SL_PAD_EPDC_D11__EPDC_SDDO_11, + MX6SL_PAD_EPDC_D12__EPDC_SDDO_12, + MX6SL_PAD_EPDC_D13__EPDC_SDDO_13, + MX6SL_PAD_EPDC_D14__EPDC_SDDO_14, + MX6SL_PAD_EPDC_D15__EPDC_SDDO_15, + + MX6SL_PAD_EPDC_GDCLK__EPDC_GDCLK, + MX6SL_PAD_EPDC_GDSP__EPDC_GDSP, + MX6SL_PAD_EPDC_GDOE__EPDC_GDOE, + MX6SL_PAD_EPDC_GDRL__EPDC_GDRL, + MX6SL_PAD_EPDC_SDCLK__EPDC_SDCLK, + MX6SL_PAD_EPDC_SDOE__EPDC_SDOE, + MX6SL_PAD_EPDC_SDLE__EPDC_SDLE, + MX6SL_PAD_EPDC_SDSHR__EPDC_SDSHR, + MX6SL_PAD_EPDC_BDR0__EPDC_BDR_0, + MX6SL_PAD_EPDC_SDCE0__EPDC_SDCE_0, + MX6SL_PAD_EPDC_SDCE1__EPDC_SDCE_1, +// MX6SL_PAD_EPDC_SDCE2__EPDC_SDCE_2, + + /* EPD PMIC (Maxim 17135) pins */ +// MX6SL_PAD_EPDC_VCOM0__GPIO_2_3, +// MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13, +// MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7, +// MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14, +}; + +static iomux_v3_cfg_t mx6sl_brd_epdc_disable_pads[] = { + /* EPDC */ + MX6SL_PAD_EPDC_D0__GPIO_1_7, + MX6SL_PAD_EPDC_D1__GPIO_1_8, + MX6SL_PAD_EPDC_D2__GPIO_1_9, + MX6SL_PAD_EPDC_D3__GPIO_1_10, + MX6SL_PAD_EPDC_D4__GPIO_1_11, + MX6SL_PAD_EPDC_D5__GPIO_1_12, + MX6SL_PAD_EPDC_D6__GPIO_1_13, + MX6SL_PAD_EPDC_D7__GPIO_1_14, + MX6SL_PAD_EPDC_D8__GPIO_1_15, + MX6SL_PAD_EPDC_D9__GPIO_1_16, + MX6SL_PAD_EPDC_D10__GPIO_1_17, + MX6SL_PAD_EPDC_D11__GPIO_1_18, + MX6SL_PAD_EPDC_D12__GPIO_1_19, + MX6SL_PAD_EPDC_D13__GPIO_1_20, + MX6SL_PAD_EPDC_D14__GPIO_1_21, + MX6SL_PAD_EPDC_D15__GPIO_1_22, + + MX6SL_PAD_EPDC_GDCLK__GPIO_1_31, + MX6SL_PAD_EPDC_GDSP__GPIO_2_2, + MX6SL_PAD_EPDC_GDOE__GPIO_2_0, + MX6SL_PAD_EPDC_GDRL__GPIO_2_1, + MX6SL_PAD_EPDC_SDCLK__GPIO_1_23, + MX6SL_PAD_EPDC_SDOE__GPIO_1_25, + MX6SL_PAD_EPDC_SDLE__GPIO_1_24, + MX6SL_PAD_EPDC_SDSHR__GPIO_1_26, + MX6SL_PAD_EPDC_BDR0__GPIO_2_5, + MX6SL_PAD_EPDC_SDCE0__GPIO_1_27, + MX6SL_PAD_EPDC_SDCE1__GPIO_1_28, +// MX6SL_PAD_EPDC_SDCE2__GPIO_1_29, + + /* EPD PMIC (Maxim 17135) pins */ +// MX6SL_PAD_EPDC_VCOM0__GPIO_2_3, +// MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13, +// MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7, +// MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14, +}; + +static iomux_v3_cfg_t mx6sl_brd_spdc_enable_pads[] = { + /* SPDC data*/ + MX6SL_PAD_EPDC_D0__TCON_E_DATA_0, + MX6SL_PAD_EPDC_D1__TCON_E_DATA_1, + MX6SL_PAD_EPDC_D2__TCON_E_DATA_2, + MX6SL_PAD_EPDC_D3__TCON_E_DATA_3, + MX6SL_PAD_EPDC_D4__TCON_E_DATA_4, + MX6SL_PAD_EPDC_D5__TCON_E_DATA_5, + MX6SL_PAD_EPDC_D6__TCON_E_DATA_6, + MX6SL_PAD_EPDC_D7__TCON_E_DATA_7, + + MX6SL_PAD_EPDC_GDOE__TCON_YOEL, /* AUO panel SIPIX_YOE */ + + MX6SL_PAD_EPDC_D9__TCON_E_DATA_9, /* AUO panel SIPIX_PWR_RDY*/ + +// MX6SL_PAD_EPDC_SDCE2__TCON_YDIOUR, /* AUO panel SIPIX_YDIO */ +// MX6SL_PAD_EPDC_SDCE3__TCON_YDIODR, /* AUO panel SIPIX_YDIO */ + MX6SL_PAD_EPDC_GDRL__TCON_YDIOUL, /* AUO panel SIPIX_YDIO */ + MX6SL_PAD_EPDC_GDSP__TCON_YDIODL, /* SIPIX_YDIO/SIPIX2_SPV */ + + MX6SL_PAD_EPDC_GDCLK__TCON_YCKL, /* SIPIX_YCLK/SIPIX2_CKV */ + + MX6SL_PAD_EPDC_SDSHR__TCON_XDIOR, /* AUO panel SIPIX_XDIO */ + MX6SL_PAD_EPDC_SDOE__TCON_XDIOL, /* SIPIX_XDIO/SIPIX2_OE */ + + MX6SL_PAD_EPDC_SDLE__TCON_LD, /* SIPIX_LD/SIPIX2_LE */ + + MX6SL_PAD_EPDC_SDCE1__TCON_YOER, /* AUO panel SIPIX_SOE */ + MX6SL_PAD_EPDC_BDR0__TCON_RL, /* AUO panel SIPIX_SOE */ + MX6SL_PAD_EPDC_BDR1__TCON_UD, /* AUO panel SIPIX_SOE */ + + MX6SL_PAD_EPDC_SDCLK__TCON_CL, /* SIPIX_XCLK/SIPIX2_CL */ + + MX6SL_PAD_EPDC_D10__TCON_E_DATA_10, /* AUO panel SIPIX_SHD_N */ + + MX6SL_PAD_EPDC_SDCE0__TCON_YCKR, /* LG panel SIPIX2_CE */ + + /* EPD PMIC (Maxim 17135) pins */ + MX6SL_PAD_EPDC_VCOM0__GPIO_2_3, /* PMICA_CEN */ + MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13, + MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7, + MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14, +}; + +static iomux_v3_cfg_t mx6sl_brd_spdc_disable_pads[] = { + MX6SL_PAD_EPDC_D0__GPIO_1_7, + MX6SL_PAD_EPDC_D1__GPIO_1_8, + MX6SL_PAD_EPDC_D2__GPIO_1_9, + MX6SL_PAD_EPDC_D3__GPIO_1_10, + MX6SL_PAD_EPDC_D4__GPIO_1_11, + MX6SL_PAD_EPDC_D5__GPIO_1_12, + MX6SL_PAD_EPDC_D6__GPIO_1_13, + MX6SL_PAD_EPDC_D7__GPIO_1_14, + + MX6SL_PAD_EPDC_SDCE1__GPIO_1_28, + MX6SL_PAD_EPDC_GDOE__GPIO_2_0, + MX6SL_PAD_EPDC_D9__GPIO_1_16, +// MX6SL_PAD_EPDC_SDCE2__GPIO_1_29, +// MX6SL_PAD_EPDC_SDCE3__GPIO_1_30, + MX6SL_PAD_EPDC_GDRL__GPIO_2_1, + MX6SL_PAD_EPDC_GDSP__GPIO_2_2, + MX6SL_PAD_EPDC_GDCLK__GPIO_1_31, + MX6SL_PAD_EPDC_SDSHR__GPIO_1_26, + MX6SL_PAD_EPDC_SDOE__GPIO_1_25, + MX6SL_PAD_EPDC_SDLE__GPIO_1_24, + MX6SL_PAD_EPDC_SDCE1__GPIO_1_28, + MX6SL_PAD_EPDC_BDR0__GPIO_2_5, + MX6SL_PAD_EPDC_BDR1__GPIO_2_6, + MX6SL_PAD_EPDC_SDCLK__GPIO_1_23, + MX6SL_PAD_EPDC_D10__GPIO_1_17, + MX6SL_PAD_EPDC_SDCE0__GPIO_1_27, + + /* EPD PMIC (Maxim 17135) pins */ + MX6SL_PAD_EPDC_VCOM0__GPIO_2_3, + MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13, + MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7, + MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14, +}; + +static iomux_v3_cfg_t mx6sl_brd_elan_pads[] = { + MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, /* INT */ + MX6SL_PAD_EPDC_PWRCTRL2__GPIO_2_9, /* CE */ + MX6SL_PAD_KEY_COL6__GPIO_4_4, /* RST */ +}; + +static iomux_v3_cfg_t suspend_enter_pads[] = { + /* Audio pads. */ + MX6SL_PAD_AUD_MCLK__GPIO_1_6, + MX6SL_PAD_AUD_RXC__GPIO_1_1, + MX6SL_PAD_AUD_RXD__GPIO_1_2, + MX6SL_PAD_AUD_RXFS__GPIO_1_0, + MX6SL_PAD_AUD_TXC__GPIO_1_3, + MX6SL_PAD_AUD_TXD__GPIO_1_5, + MX6SL_PAD_AUD_TXFS__GPIO_1_4, + /* ECSPI pads. */ + MX6SL_PAD_ECSPI1_MISO__GPIO_4_10, + MX6SL_PAD_ECSPI1_MOSI__GPIO_4_9, + MX6SL_PAD_ECSPI1_SCLK__GPIO_4_8, + MX6SL_PAD_ECSPI1_SS0__GPIO_4_11, + MX6SL_PAD_ECSPI2_SCLK__GPIO_4_12, + /* FEC pad*/ + MX6SL_PAD_FEC_CRS_DV__GPIO_4_25, + MX6SL_PAD_FEC_MDC__GPIO_4_23, + MX6SL_PAD_FEC_MDIO__GPIO_4_20, + MX6SL_PAD_FEC_REF_CLK__GPIO_4_26, + MX6SL_PAD_FEC_RXD0__GPIO_4_17, + MX6SL_PAD_FEC_RXD1__GPIO_4_18, + MX6SL_PAD_FEC_TXD0__GPIO_4_24, + MX6SL_PAD_FEC_TXD1__GPIO_4_16, + MX6SL_PAD_FEC_TX_CLK__GPIO_4_21, + MX6SL_PAD_FEC_TX_EN__GPIO_4_22, + /* I2C pads */ + MX6SL_PAD_I2C1_SCL__GPIO_3_12, + MX6SL_PAD_I2C1_SDA__GPIO_3_13, + MX6SL_PAD_I2C2_SCL__GPIO_3_14, + MX6SL_PAD_I2C2_SDA__GPIO_3_15, + /* LCD pads*/ + MX6SL_PAD_LCD_CLK__GPIO_2_15, + MX6SL_PAD_LCD_DAT0__GPIO_2_20, + MX6SL_PAD_LCD_DAT1__GPIO_2_21, + MX6SL_PAD_LCD_DAT2__GPIO_2_22, + MX6SL_PAD_LCD_DAT3__GPIO_2_23, + MX6SL_PAD_LCD_DAT4__GPIO_2_24, + MX6SL_PAD_LCD_DAT5__GPIO_2_25, + MX6SL_PAD_LCD_DAT10__GPIO_2_30, + MX6SL_PAD_LCD_DAT11__GPIO_2_31, + MX6SL_PAD_LCD_DAT12__GPIO_3_0, + MX6SL_PAD_LCD_DAT13__GPIO_3_1, + MX6SL_PAD_LCD_DAT14__GPIO_3_2, + MX6SL_PAD_LCD_DAT15__GPIO_3_3, + MX6SL_PAD_LCD_DAT16__GPIO_3_4, + MX6SL_PAD_LCD_DAT17__GPIO_3_5, + MX6SL_PAD_LCD_DAT18__GPIO_3_6, + MX6SL_PAD_LCD_DAT19__GPIO_3_7, + MX6SL_PAD_LCD_DAT20__GPIO_3_8, + MX6SL_PAD_LCD_DAT21__GPIO_3_9, + MX6SL_PAD_LCD_DAT22__GPIO_3_10, + MX6SL_PAD_LCD_DAT23__GPIO_3_11, + /* PWM pads */ + MX6SL_PAD_PWM1__GPIO_3_23, + /* SD pads. */ + MX6SL_PAD_SD1_CLK__GPIO_5_15, + MX6SL_PAD_SD1_CMD__GPIO_5_14, + MX6SL_PAD_SD1_DAT0__GPIO_5_11, + MX6SL_PAD_SD1_DAT1__GPIO_5_8, + MX6SL_PAD_SD1_DAT2__GPIO_5_13, + MX6SL_PAD_SD1_DAT3__GPIO_5_6, + MX6SL_PAD_SD1_DAT4__GPIO_5_12, + MX6SL_PAD_SD1_DAT5__GPIO_5_9, + MX6SL_PAD_SD1_DAT6__GPIO_5_7, + MX6SL_PAD_SD1_DAT7__GPIO_5_10, + + MX6SL_PAD_SD2_CLK__GPIO_5_5, + MX6SL_PAD_SD2_CMD__GPIO_5_4, + MX6SL_PAD_SD2_DAT0__GPIO_5_1, + MX6SL_PAD_SD2_DAT1__GPIO_4_30, + MX6SL_PAD_SD2_DAT2__GPIO_5_3, + MX6SL_PAD_SD2_DAT3__GPIO_4_28, + MX6SL_PAD_SD2_DAT4__GPIO_5_2, + MX6SL_PAD_SD2_DAT5__GPIO_4_31, + + MX6SL_PAD_SD3_CLK__GPIO_5_18, + MX6SL_PAD_SD3_CMD__GPIO_5_21, + MX6SL_PAD_SD3_DAT0__GPIO_5_19, + MX6SL_PAD_SD3_DAT1__GPIO_5_20, + MX6SL_PAD_SD3_DAT2__GPIO_5_16, + MX6SL_PAD_SD3_DAT3__GPIO_5_17, + + /* USBOTG ID pin */ +#ifndef CONFIG_USB_ID_WAKEUP_ENABLE + MX6SL_PAD_EPDC_PWRCOM__GPIO_2_11, +#endif + MX6SL_PAD_HSIC_STROBE__GPIO_3_20, + MX6SL_PAD_HSIC_DAT__GPIO_3_19, + + /* Key row/column */ + MX6SL_PAD_KEY_COL0__GPIO_3_24, + MX6SL_PAD_KEY_COL1__GPIO_3_26, + MX6SL_PAD_KEY_COL2__GPIO_3_28, + MX6SL_PAD_KEY_COL3__GPIO_3_30, + MX6SL_PAD_KEY_COL6__GPIO_4_4, + MX6SL_PAD_KEY_COL7__GPIO_4_6, + MX6SL_PAD_KEY_ROW0__GPIO_3_25, + MX6SL_PAD_KEY_ROW1__GPIO_3_27, + MX6SL_PAD_KEY_ROW2__GPIO_3_29, + MX6SL_PAD_KEY_ROW3__GPIO_3_31, + MX6SL_PAD_KEY_ROW4__GPIO_4_1, + MX6SL_PAD_KEY_ROW5__GPIO_4_3, + MX6SL_PAD_KEY_ROW6__GPIO_4_5, +}; + +static iomux_v3_cfg_t suspend_exit_pads[ARRAY_SIZE(suspend_enter_pads)]; + +#define MX6SL_USDHC_8BIT_PAD_SETTING(id, speed) \ +mx6sl_sd##id##_##speed##mhz[] = { \ + MX6SL_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6SL_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT4__USDHC##id##_DAT4_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT5__USDHC##id##_DAT5_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT6__USDHC##id##_DAT6_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT7__USDHC##id##_DAT7_##speed##MHZ, \ +} +#define MX6SL_USDHC_4BIT_PAD_SETTING(id, speed) \ +mx6sl_sd##id##_##speed##mhz[] = { \ + MX6SL_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6SL_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6SL_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ +} + + +static iomux_v3_cfg_t MX6SL_USDHC_8BIT_PAD_SETTING(1, 50); +static iomux_v3_cfg_t MX6SL_USDHC_8BIT_PAD_SETTING(1, 100); +static iomux_v3_cfg_t MX6SL_USDHC_8BIT_PAD_SETTING(1, 200); +static iomux_v3_cfg_t MX6SL_USDHC_4BIT_PAD_SETTING(2, 50); +static iomux_v3_cfg_t MX6SL_USDHC_4BIT_PAD_SETTING(2, 100); +static iomux_v3_cfg_t MX6SL_USDHC_4BIT_PAD_SETTING(2, 200); +static iomux_v3_cfg_t MX6SL_USDHC_4BIT_PAD_SETTING(3, 50); +static iomux_v3_cfg_t MX6SL_USDHC_4BIT_PAD_SETTING(3, 100); +static iomux_v3_cfg_t MX6SL_USDHC_4BIT_PAD_SETTING(3, 200); + +#endif diff --git a/arch/arm/mach-mx6/board-mx6sl_evk.c b/arch/arm/mach-mx6/board-mx6sl_evk.c new file mode 100644 index 00000000..4d09153d --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6sl_evk.c @@ -0,0 +1,1672 @@ +/* + * 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/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/smsc911x.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> +#include <sound/wm8962.h> +#include <sound/pcm.h> +#include <linux/power/sabresd_battery.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6sl.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.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 "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6sl_common.h" + + +static int spdc_sel; +static int max17135_regulator_init(struct max17135 *max17135); +struct clk *extern_audio_root; + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; +extern int __init mx6sl_evk_init_pfuze100(u32 int_gpio); + +static int csi_enabled; + +static iomux_v3_cfg_t mx6sl_brd_csi_enable_pads[] = { + MX6SL_PAD_EPDC_GDRL__CSI_MCLK, + MX6SL_PAD_EPDC_SDCE3__I2C3_SDA, + MX6SL_PAD_EPDC_SDCE2__I2C3_SCL, + MX6SL_PAD_EPDC_GDCLK__CSI_PIXCLK, + MX6SL_PAD_EPDC_GDSP__CSI_VSYNC, + MX6SL_PAD_EPDC_GDOE__CSI_HSYNC, + MX6SL_PAD_EPDC_SDLE__CSI_D_9, + MX6SL_PAD_EPDC_SDCLK__CSI_D_8, + MX6SL_PAD_EPDC_D7__CSI_D_7, + MX6SL_PAD_EPDC_D6__CSI_D_6, + MX6SL_PAD_EPDC_D5__CSI_D_5, + MX6SL_PAD_EPDC_D4__CSI_D_4, + MX6SL_PAD_EPDC_D3__CSI_D_3, + MX6SL_PAD_EPDC_D2__CSI_D_2, + MX6SL_PAD_EPDC_D1__CSI_D_1, + MX6SL_PAD_EPDC_D0__CSI_D_0, + + MX6SL_PAD_EPDC_SDSHR__GPIO_1_26, /* CMOS_RESET_B GPIO */ + MX6SL_PAD_EPDC_SDOE__GPIO_1_25, /* CMOS_PWDN GPIO */ +}; + +/* uart2 pins */ +static iomux_v3_cfg_t mx6sl_uart2_pads[] = { + MX6SL_PAD_SD2_DAT5__UART2_TXD, + MX6SL_PAD_SD2_DAT4__UART2_RXD, + MX6SL_PAD_SD2_DAT6__UART2_RTS, + MX6SL_PAD_SD2_DAT7__UART2_CTS, +}; + +enum sd_pad_mode { + SD_PAD_MODE_LOW_SPEED, + SD_PAD_MODE_MED_SPEED, + SD_PAD_MODE_HIGH_SPEED, +}; + +static int __init csi_setup(char *__unused) +{ + csi_enabled = 1; + return 1; +} +__setup("csi", csi_setup); + +static int plt_sd_pad_change(unsigned int index, int clock) +{ + /* LOW speed is the default state of SD pads */ + static enum sd_pad_mode pad_mode = SD_PAD_MODE_LOW_SPEED; + + iomux_v3_cfg_t *sd_pads_200mhz = NULL; + iomux_v3_cfg_t *sd_pads_100mhz = NULL; + iomux_v3_cfg_t *sd_pads_50mhz = NULL; + + u32 sd_pads_200mhz_cnt; + u32 sd_pads_100mhz_cnt; + u32 sd_pads_50mhz_cnt; + + switch (index) { + case 0: + sd_pads_200mhz = mx6sl_sd1_200mhz; + sd_pads_100mhz = mx6sl_sd1_100mhz; + sd_pads_50mhz = mx6sl_sd1_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd1_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd1_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd1_50mhz); + break; + case 1: + sd_pads_200mhz = mx6sl_sd2_200mhz; + sd_pads_100mhz = mx6sl_sd2_100mhz; + sd_pads_50mhz = mx6sl_sd2_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd2_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd2_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd2_50mhz); + break; + case 2: + sd_pads_200mhz = mx6sl_sd3_200mhz; + sd_pads_100mhz = mx6sl_sd3_100mhz; + sd_pads_50mhz = mx6sl_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd3_50mhz); + break; + default: + printk(KERN_ERR "no such SD host controller index %d\n", index); + return -EINVAL; + } + + if (clock > 100000000) { + if (pad_mode == SD_PAD_MODE_HIGH_SPEED) + return 0; + BUG_ON(!sd_pads_200mhz); + pad_mode = SD_PAD_MODE_HIGH_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_200mhz, + sd_pads_200mhz_cnt); + } else if (clock > 52000000) { + if (pad_mode == SD_PAD_MODE_MED_SPEED) + return 0; + BUG_ON(!sd_pads_100mhz); + pad_mode = SD_PAD_MODE_MED_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_100mhz, + sd_pads_100mhz_cnt); + } else { + if (pad_mode == SD_PAD_MODE_LOW_SPEED) + return 0; + BUG_ON(!sd_pads_50mhz); + pad_mode = SD_PAD_MODE_LOW_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_50mhz, + sd_pads_50mhz_cnt); + } +} + +static const struct esdhc_platform_data mx6_evk_sd1_data __initconst = { + .cd_gpio = MX6_BRD_SD1_CD, + .wp_gpio = MX6_BRD_SD1_WP, + .support_8bit = 1, + .support_18v = 1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct esdhc_platform_data mx6_evk_sd2_data __initconst = { + .cd_gpio = MX6_BRD_SD2_CD, + .wp_gpio = MX6_BRD_SD2_WP, + .keep_power_at_suspend = 1, + .delay_line = 0, + .support_18v = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +static const struct esdhc_platform_data mx6_evk_sd3_data __initconst = { + .cd_gpio = MX6_BRD_SD3_CD, + .wp_gpio = -1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .support_18v = 1, + .platform_pad_change = plt_sd_pad_change, +}; + +#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 evk_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), +}; + +static struct regulator_init_data evk_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(evk_vmmc_consumers), + .consumer_supplies = evk_vmmc_consumers, +}; + +static struct fixed_voltage_config evk_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &evk_vmmc_init, +}; + +static struct platform_device evk_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &evk_vmmc_reg_config, + }, +}; + +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 const struct anatop_thermal_platform_data + mx6sl_anatop_thermal_data __initconst = { + .name = "anatop_thermal", + }; + +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 = MX6SL_BRD_EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = MX6SL_BRD_EPDC_VCOM, + .gpio_pmic_wakeup = MX6SL_BRD_EPDC_PMIC_WAKE, + .gpio_pmic_v3p3 = MX6SL_BRD_EPDC_PWRCTRL0, + .gpio_pmic_intr = MX6SL_BRD_EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int __init 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; + } + } + + /* + * TODO: We cannot enable full constraints for now, since + * it results in the PFUZE regulators being disabled + * at the end of boot, which disables critical regulators. + */ + /*regulator_has_full_constraints();*/ + + return 0; +} + +static int mx6_evk_spi_cs[] = { + MX6_BRD_ECSPI1_CS0, +}; + +static const struct spi_imx_master mx6_evk_spi_data __initconst = { + .chipselect = mx6_evk_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6_evk_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition m25p32_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00100000, + }, { + .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", +}; + +static struct spi_board_info m25p32_spi0_board_info[] __initdata = { + { + /* The modalias must be the same as spi device driver name */ + .modalias = "m25p80", + .max_speed_hz = 20000000, + .bus_num = 0, + .chip_select = 0, + .platform_data = &m25p32_spi_flash_data, + }, +}; +#endif + +static void spi_device_init(void) +{ +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + spi_register_board_info(m25p32_spi0_board_info, + ARRAY_SIZE(m25p32_spi0_board_info)); +#endif +} + +static struct imx_ssi_platform_data mx6_sabresd_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static struct mxc_audio_platform_data wm8962_data; + +static struct platform_device mx6_sabresd_audio_wm8962_device = { + .name = "imx-wm8962", +}; + +static struct wm8962_pdata wm8962_config_data = { + +}; + +static int wm8962_clk_enable(int enable) +{ + if (enable) + clk_enable(extern_audio_root); + else + clk_disable(extern_audio_root); + + return 0; +} + +static int mxc_wm8962_init(void) +{ + struct clk *pll4; + int rate; + + extern_audio_root = clk_get(NULL, "extern_audio_clk"); + if (IS_ERR(extern_audio_root)) { + pr_err("can't get extern_audio_root clock.\n"); + return PTR_ERR(extern_audio_root); + } + + pll4 = clk_get(NULL, "pll4"); + if (IS_ERR(pll4)) { + pr_err("can't get pll4 clock.\n"); + return PTR_ERR(pll4); + } + + clk_set_parent(extern_audio_root, pll4); + + rate = 24000000; + clk_set_rate(extern_audio_root, 24000000); + + wm8962_data.sysclk = rate; + /* set AUDMUX pads to 1.8v */ + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_MCLK, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_RXD, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_TXC, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_TXD, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_TXFS, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + + return 0; +} + +static struct mxc_audio_platform_data wm8962_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_gpio = MX6_BRD_HEADPHONE_DET, + .hp_active_low = 1, + .mic_gpio = -1, + .mic_active_low = 1, + .init = mxc_wm8962_init, + .clock_enable = wm8962_clk_enable, +}; + +static struct regulator_consumer_supply sabresd_vwm8962_consumers[] = { + REGULATOR_SUPPLY("SPKVDD1", "1-001a"), + REGULATOR_SUPPLY("SPKVDD2", "1-001a"), +}; + +static struct regulator_init_data sabresd_vwm8962_init = { + .constraints = { + .name = "SPKVDD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sabresd_vwm8962_consumers), + .consumer_supplies = sabresd_vwm8962_consumers, +}; + +static struct fixed_voltage_config sabresd_vwm8962_reg_config = { + .supply_name = "SPKVDD", + .microvolts = 4325000, + .gpio = -1, + .enabled_at_boot = 1, + .init_data = &sabresd_vwm8962_init, +}; + +static struct platform_device sabresd_vwm8962_reg_devices = { + .name = "reg-fixed-voltage", + .id = 4, + .dev = { + .platform_data = &sabresd_vwm8962_reg_config, + }, +}; + +static int __init imx6q_init_audio(void) +{ + platform_device_register(&sabresd_vwm8962_reg_devices); + mxc_register_device(&mx6_sabresd_audio_wm8962_device, + &wm8962_data); + imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata); + + return 0; +} + +static int spdif_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long rate_actual; + rate_actual = clk_round_rate(clk, rate); + clk_set_rate(clk, rate_actual); + return 0; +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 1, + .spdif_clk_48000 = -1, + .spdif_div_44100 = 23, + .spdif_clk_set_rate = spdif_clk_set_rate, + .spdif_clk = NULL, +}; + + +enum DISPLAY_PANEL_MODE { + PANEL_MODE_LCD, + PANEL_MODE_HDMI, + PANEL_MODE_EINK, +}; + +static int display_panel_mode = PANEL_MODE_EINK; + +static iomux_v3_cfg_t mx6sl_sii902x_hdmi_pads_enabled[] = { + MX6SL_PAD_LCD_RESET__GPIO_2_19, + MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, +}; + +static int sii902x_get_pins(void) +{ + /* Sii902x HDMI controller */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_sii902x_hdmi_pads_enabled, \ + ARRAY_SIZE(mx6sl_sii902x_hdmi_pads_enabled)); + + /* Reset Pin */ + gpio_request(MX6_BRD_LCD_RESET, "disp0-reset"); + gpio_direction_output(MX6_BRD_LCD_RESET, 1); + + /* Interrupter pin GPIO */ + gpio_request(MX6SL_BRD_EPDC_PWRCTRL3, "disp0-detect"); + gpio_direction_input(MX6SL_BRD_EPDC_PWRCTRL3); + return 1; +} + +static void sii902x_put_pins(void) +{ + gpio_free(MX6_BRD_LCD_RESET); + gpio_free(MX6SL_BRD_EPDC_PWRCTRL3); +} + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(MX6_BRD_LCD_RESET, 0); + msleep(10); + gpio_set_value(MX6_BRD_LCD_RESET, 1); + msleep(10); +} + +static struct fsl_mxc_lcd_platform_data sii902x_hdmi_data = { + .ipu_id = 0, + .disp_id = 0, + .reset = sii902x_hdmi_reset, + .get_pins = sii902x_get_pins, + .put_pins = sii902x_put_pins, +}; + +static void mx6sl_csi_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_csi_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_csi_enable_pads)); + + /* Camera reset */ + gpio_request(MX6SL_BRD_CSI_RST, "cam-reset"); + gpio_direction_output(MX6SL_BRD_CSI_RST, 1); + + /* Camera power down */ + gpio_request(MX6SL_BRD_CSI_PWDN, "cam-pwdn"); + gpio_direction_output(MX6SL_BRD_CSI_PWDN, 1); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_PWDN, 0); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_RST, 0); + msleep(1); + gpio_set_value(MX6SL_BRD_CSI_RST, 1); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_PWDN, 1); +} + +static void mx6sl_csi_cam_powerdown(int powerdown) +{ + if (powerdown) + gpio_set_value(MX6SL_BRD_CSI_PWDN, 1); + else + gpio_set_value(MX6SL_BRD_CSI_PWDN, 0); + + msleep(2); +} + +static struct fsl_mxc_camera_platform_data camera_data = { + .mclk = 24000000, + .io_init = mx6sl_csi_io_init, + .pwdn = mx6sl_csi_cam_powerdown, + .core_regulator = "VGEN2_1V5", + .analog_regulator = "VGEN6_2V8", +}; + +static struct imxi2c_platform_data mx6_evk_i2c0_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_evk_i2c1_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_evk_i2c2_data = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxc_i2c0_board_info[] __initdata = { + { + I2C_BOARD_INFO("max17135", 0), /*0x48*/ + .platform_data = &max17135_pdata, + }, { + I2C_BOARD_INFO("elan-touch", 0), /*0x10*/ + .irq = gpio_to_irq(MX6SL_BRD_ELAN_INT), + }, { + I2C_BOARD_INFO("mma8450", 0x1c), + }, +}; + +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { + { + I2C_BOARD_INFO("wm8962", 0x1a), + .platform_data = &wm8962_config_data, + }, + { + I2C_BOARD_INFO("sii902x", 0), /*0x39*/ + .platform_data = &sii902x_hdmi_data, + .irq = gpio_to_irq(MX6SL_BRD_EPDC_PWRCTRL3) + }, +}; + +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { + { + I2C_BOARD_INFO("ov5640", 0x3c), + .platform_data = (void *)&camera_data, + }, +}; + +static struct mxc_dvfs_platform_data mx6sl_evk_dvfscore_data = { +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + .reg_id = "VDDCORE", + .soc_id = "VDDSOC", +#else + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", +#endif + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_32M, +}; + +void __init early_console_setup(unsigned long base, struct clk *clk); + +static const struct imxuart_platform_data mx6sl_evk_uart1_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS | IMXUART_SDMA, + .dma_req_rx = MX6Q_DMA_REQ_UART2_RX, + .dma_req_tx = MX6Q_DMA_REQ_UART2_TX, +}; + +static inline void mx6_evk_init_uart(void) +{ + imx6q_add_imx_uart(0, NULL); /* DEBUG UART1 */ +} + +static int mx6sl_evk_fec_phy_init(struct phy_device *phydev) +{ + int val; + + /* power on FEC phy and reset phy */ + gpio_request(MX6_BRD_FEC_PWR_EN, "fec-pwr"); + gpio_direction_output(MX6_BRD_FEC_PWR_EN, 0); + /* wait RC ms for hw reset */ + msleep(1); + gpio_direction_output(MX6_BRD_FEC_PWR_EN, 1); + + /* check phy power */ + val = phy_read(phydev, 0x0); + if (val & BMCR_PDOWN) + phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); + + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6sl_evk_fec_phy_init, + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static int epdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for EPDC pins - used during power up/down */ + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_0, "epdc_d0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_1, "epdc_d1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_2, "epdc_d2"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_3, "epdc_d3"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_4, "epdc_d4"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_5, "epdc_d5"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_6, "epdc_d6"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_7, "epdc_d7"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDCLK, "epdc_gdclk"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDSP, "epdc_gdsp"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDOE, "epdc_gdoe"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDRL, "epdc_gdrl"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCLK, "epdc_sdclk"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDOE, "epdc_sdoe"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDLE, "epdc_sdle"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDSHR, "epdc_sdshr"); + ret |= gpio_request(MX6SL_BRD_EPDC_BDR0, "epdc_bdr0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE0, "epdc_sdce0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE1, "epdc_sdce1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE2, "epdc_sdce2"); + + return ret; +} + +static void epdc_put_pins(void) +{ + gpio_free(MX6SL_BRD_EPDC_SDDO_0); + gpio_free(MX6SL_BRD_EPDC_SDDO_1); + gpio_free(MX6SL_BRD_EPDC_SDDO_2); + gpio_free(MX6SL_BRD_EPDC_SDDO_3); + gpio_free(MX6SL_BRD_EPDC_SDDO_4); + gpio_free(MX6SL_BRD_EPDC_SDDO_5); + gpio_free(MX6SL_BRD_EPDC_SDDO_6); + gpio_free(MX6SL_BRD_EPDC_SDDO_7); + gpio_free(MX6SL_BRD_EPDC_GDCLK); + gpio_free(MX6SL_BRD_EPDC_GDSP); + gpio_free(MX6SL_BRD_EPDC_GDOE); + gpio_free(MX6SL_BRD_EPDC_GDRL); + gpio_free(MX6SL_BRD_EPDC_SDCLK); + gpio_free(MX6SL_BRD_EPDC_SDOE); + gpio_free(MX6SL_BRD_EPDC_SDLE); + gpio_free(MX6SL_BRD_EPDC_SDSHR); + gpio_free(MX6SL_BRD_EPDC_BDR0); + gpio_free(MX6SL_BRD_EPDC_SDCE0); + gpio_free(MX6SL_BRD_EPDC_SDCE1); + gpio_free(MX6SL_BRD_EPDC_SDCE2); +} + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_epdc_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_epdc_enable_pads)); + + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_0); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_1); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_2); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_3); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_4); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_5); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_6); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_7); + gpio_direction_input(MX6SL_BRD_EPDC_GDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_GDSP); + gpio_direction_input(MX6SL_BRD_EPDC_GDOE); + gpio_direction_input(MX6SL_BRD_EPDC_GDRL); + gpio_direction_input(MX6SL_BRD_EPDC_SDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDOE); + gpio_direction_input(MX6SL_BRD_EPDC_SDLE); + gpio_direction_input(MX6SL_BRD_EPDC_SDSHR); + gpio_direction_input(MX6SL_BRD_EPDC_BDR0); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE0); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE1); + gpio_direction_input(MX6SL_BRD_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(mx6sl_brd_epdc_disable_pads, \ + ARRAY_SIZE(mx6sl_brd_epdc_disable_pads)); + + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_2, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_3, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_4, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_5, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_6, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_7, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDSP, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDRL, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDLE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDSHR, 0); + gpio_direction_output(MX6SL_BRD_EPDC_BDR0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE1, 0); + gpio_direction_output(MX6SL_BRD_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, + .refresh = 85, + .xres = 800, + .yres = 600, +}; +static struct fb_videomode e060scm_mode = { + .name = "E060SCM", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 26666667, + .left_margin = 8, + .right_margin = 100, + .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 */ + }, + { + &e060scm_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 419, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 5, /* 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 int spdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for SPDC pins - used during power up/down */ + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_0, "SPDC_D0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_1, "SPDC_D1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_2, "SPDC_D2"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_3, "SPDC_D3"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_4, "SPDC_D4"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_5, "SPDC_D5"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_6, "SPDC_D6"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_7, "SPDC_D7"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDOE, "SIPIX_YOE"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_9, "SIPIX_PWR_RDY"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDSP, "SIPIX_YDIO"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDCLK, "SIPIX_YCLK"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDSHR, "SIPIX_XDIO"); + + ret |= gpio_request(MX6SL_BRD_EPDC_SDLE, "SIPIX_LD"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE1, "SIPIX_SOE"); + + ret |= gpio_request(MX6SL_BRD_EPDC_SDCLK, "SIPIX_XCLK"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_10, "SIPIX_SHD_N"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE0, "SIPIX2_CE"); + + return ret; +} + +static void spdc_put_pins(void) +{ + gpio_free(MX6SL_BRD_EPDC_SDDO_0); + gpio_free(MX6SL_BRD_EPDC_SDDO_1); + gpio_free(MX6SL_BRD_EPDC_SDDO_2); + gpio_free(MX6SL_BRD_EPDC_SDDO_3); + gpio_free(MX6SL_BRD_EPDC_SDDO_4); + gpio_free(MX6SL_BRD_EPDC_SDDO_5); + gpio_free(MX6SL_BRD_EPDC_SDDO_6); + gpio_free(MX6SL_BRD_EPDC_SDDO_7); + + gpio_free(MX6SL_BRD_EPDC_GDOE); + gpio_free(MX6SL_BRD_EPDC_SDDO_9); + gpio_free(MX6SL_BRD_EPDC_GDSP); + gpio_free(MX6SL_BRD_EPDC_GDCLK); + gpio_free(MX6SL_BRD_EPDC_SDSHR); + gpio_free(MX6SL_BRD_EPDC_SDLE); + gpio_free(MX6SL_BRD_EPDC_SDCE1); + gpio_free(MX6SL_BRD_EPDC_SDCLK); + gpio_free(MX6SL_BRD_EPDC_SDDO_10); + gpio_free(MX6SL_BRD_EPDC_SDCE0); +} + +static void spdc_enable_pins(void) +{ + /* Configure MUX settings to enable SPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_spdc_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_spdc_enable_pads)); + + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_0); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_1); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_2); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_3); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_4); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_5); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_6); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_7); + gpio_direction_input(MX6SL_BRD_EPDC_GDOE); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_9); + gpio_direction_input(MX6SL_BRD_EPDC_GDSP); + gpio_direction_input(MX6SL_BRD_EPDC_GDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDSHR); + gpio_direction_input(MX6SL_BRD_EPDC_SDLE); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE1); + gpio_direction_input(MX6SL_BRD_EPDC_SDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_10); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE0); +} + +static void spdc_disable_pins(void) +{ + /* Configure MUX settings for SPDC pins to + * GPIO and drive to 0. */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_spdc_disable_pads, \ + ARRAY_SIZE(mx6sl_brd_spdc_disable_pads)); + + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_2, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_3, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_4, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_5, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_6, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_7, 0); + + gpio_direction_output(MX6SL_BRD_EPDC_GDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_9, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDSP, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDSHR, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDLE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_10, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE0, 0); +} + +static struct imx_spdc_panel_init_set spdc_init_set = { + .yoe_pol = false, + .dual_gate = false, + .resolution = 0, + .ud = false, + .rl = false, + .data_filter_n = true, + .power_ready = true, + .rgbw_mode_enable = false, + .hburst_len_en = true, +}; + +static struct fb_videomode erk_1_4_a01 = { + .name = "ERK_1_4_A01", + .refresh = 50, + .xres = 800, + .yres = 600, + .pixclock = 40000000, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct imx_spdc_fb_mode spdc_panel_modes[] = { + { + &erk_1_4_a01, + &spdc_init_set, + .wave_timing = "pvi" + }, +}; + +static struct imx_spdc_fb_platform_data spdc_data = { + .spdc_mode = spdc_panel_modes, + .num_modes = ARRAY_SIZE(spdc_panel_modes), + .get_pins = spdc_get_pins, + .put_pins = spdc_put_pins, + .enable_pins = spdc_enable_pins, + .disable_pins = spdc_disable_pins, +}; + +static int __init early_use_spdc_sel(char *p) +{ + spdc_sel = 1; + return 0; +} +early_param("spdc", early_use_spdc_sel); + +static void setup_spdc(void) +{ + /* GPR0[8]: 0:EPDC, 1:SPDC */ + if (spdc_sel) + mxc_iomux_set_gpr_register(0, 8, 1, 1); +} + +static void imx6_evk_usbotg_vbus(bool on) +{ + if (on) + gpio_set_value(MX6_BRD_USBOTG1_PWR, 1); + else + gpio_set_value(MX6_BRD_USBOTG1_PWR, 0); +} + +static void __init mx6_evk_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + + /* disable external charger detect, + * or it will affect signal quality at dp. + */ + + ret = gpio_request(MX6_BRD_USBOTG1_PWR, "usbotg-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_BRD_USBOTG1_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_BRD_USBOTG1_PWR, 0); + + ret = gpio_request(MX6_BRD_USBOTG2_PWR, "usbh1-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_BRD_USBOTG2_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_BRD_USBOTG2_PWR, 1); + + mx6_set_otghost_vbus_func(imx6_evk_usbotg_vbus); +#ifdef CONFIG_USB_EHCI_ARC_HSIC + mx6_usb_h2_init(); +#endif +} + +static struct platform_pwm_backlight_data mx6_evk_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; +static struct fb_videomode wvga_video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 32MHz */ + "SEIKO-WVGA", 60, 800, 480, 29850, 89, 164, 23, 10, 10, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data wvga_fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB24, + .mode_str = "SEIKO-WVGA", + .mode = wvga_video_modes, + .num_modes = ARRAY_SIZE(wvga_video_modes), + .panel_type = "lcd", + }, +}; + +static struct platform_device lcd_wvga_device = { + .name = "lcd_seiko", +}; + +static struct fb_videomode hdmi_video_modes[] = { + { + /* 1920x1080 @ 60 Hz , pixel clk @ 148MHz */ + "sii9022x_1080p60", 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data hdmi_fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB24, + .mode_str = "1920x1080M@60", + .mode = hdmi_video_modes, + .num_modes = ARRAY_SIZE(hdmi_video_modes), + .panel_type = "hdmi", + }, +}; + +static int mx6sl_evk_keymap[] = { + KEY(0, 0, KEY_SELECT), /* EVK:SW6 DC2:SELECT */ + KEY(0, 1, KEY_BACK), /* EVK:SW7 DC2:BACK */ + KEY(0, 2, KEY_F1), /* EVK:SW8 DC2:F1 */ + KEY(0, 3, KEY_F2), /* EVK DC2:F2 */ + + KEY(1, 0, KEY_F3), /* EVK:SW9 DC2:F3 */ + KEY(1, 1, KEY_VOLUMEDOWN), /* EVK:SW10 DC2:F4 */ + KEY(1, 2, KEY_VOLUMEUP), /* EVK:SW11 DC2:F5 */ + KEY(1, 3, KEY_MENU), /* EVK DC2:MENU */ + + KEY(2, 0, KEY_PREVIOUS), /* EVK:SW12 DC2:PREV */ + KEY(2, 1, KEY_NEXT), /* EVK:SW13 DC2:NEX1 */ + KEY(2, 2, KEY_HOME), /* EVK DC2:HOME */ + KEY(2, 3, KEY_NEXT), /* EVK DC2:NEX2 */ + + KEY(3, 0, KEY_UP), /* EVK DC2:UP */ + KEY(3, 1, KEY_LEFT), /* EVK DC2:LEFT */ + KEY(3, 2, KEY_RIGHT), /* EVK DC2:RIGHT */ + KEY(3, 3, KEY_DOWN), /* EVK DC2:DOWN */ +}; + +static const struct matrix_keymap_data mx6sl_evk_map_data __initconst = { + .keymap = mx6sl_evk_keymap, + .keymap_size = ARRAY_SIZE(mx6sl_evk_keymap), +}; +static void __init elan_ts_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_elan_pads, + ARRAY_SIZE(mx6sl_brd_elan_pads)); + + /* ELAN Touchscreen */ + gpio_request(MX6SL_BRD_ELAN_INT, "elan-interrupt"); + gpio_direction_input(MX6SL_BRD_ELAN_INT); + + gpio_request(MX6SL_BRD_ELAN_CE, "elan-cs"); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 0); + + gpio_request(MX6SL_BRD_ELAN_RST, "elan-rst"); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 1); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 0); + mdelay(1); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 1); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); +} + +/* + *Usually UOK and DOK should have separate + *line to differentiate its behaviour (with different + * GPIO irq),because connect max8903 pin UOK to + *pin DOK from hardware design,cause software cannot + *process and distinguish two interrupt, so default + *enable dc_valid for ac charger + */ +static struct max8903_pdata charger1_data = { + .dok = MX6_BRD_CHG_DOK, + .uok = MX6_BRD_CHG_UOK, + .chg = MX6_BRD_CHG_STATUS, + .flt = MX6_BRD_CHG_FLT, + .dcm_always_high = true, + .dc_valid = true, + .usb_valid = false, + .feature_flag = 1, +}; + +static struct platform_device evk_max8903_charger_1 = { + .name = "max8903-charger", + .dev = { + .platform_data = &charger1_data, + }, +}; + +/*! Device Definition for csi v4l2 device */ +static struct platform_device csi_v4l2_devices = { + .name = "csi_v4l2", + .id = 0, +}; + +#define SNVS_LPCR 0x38 +static void mx6_snvs_poweroff(void) +{ + u32 value; + void __iomem *mx6_snvs_base = MX6_IO_ADDRESS(MX6Q_SNVS_BASE_ADDR); + + value = readl(mx6_snvs_base + SNVS_LPCR); + /* set TOP and DP_EN bit */ + writel(value | 0x60, mx6_snvs_base + SNVS_LPCR); +} + +static int uart2_enabled; +static int __init uart2_setup(char * __unused) +{ + uart2_enabled = 1; + return 1; +} +__setup("bluetooth", uart2_setup); + +static void __init uart2_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_uart2_pads, + ARRAY_SIZE(mx6sl_uart2_pads)); + imx6sl_add_imx_uart(1, &mx6sl_evk_uart1_data); +} + + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) + +#define MX6SL_EVK_POWER_OFF IMX_GPIO_NR(3, 18) + +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ + .debounce_interval = debounce, \ +} + +static struct gpio_keys_button imx6sl_buttons[] = { + GPIO_BUTTON(MX6SL_EVK_POWER_OFF, KEY_POWER, 1, "power", 1, 1), +}; + +static struct gpio_keys_platform_data imx6sl_button_data = { + .buttons = imx6sl_buttons, + .nbuttons = ARRAY_SIZE(imx6sl_buttons), + .rep = 0, +}; + +static struct platform_device imx6sl_button_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &imx6sl_button_data, + } +}; + +static void __init imx6sl_add_device_buttons(void) +{ + platform_device_register(&imx6sl_button_device); +} +#else +static void __init imx6sl_add_device_buttons(void) {} +#endif + + + +/*! + * Board specific initialization. + */ +static void __init mx6_evk_init(void) +{ + u32 i; + + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_pads, + ARRAY_SIZE(mx6sl_brd_pads)); + +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + gp_reg_id = mx6sl_evk_dvfscore_data.reg_id; + soc_reg_id = mx6sl_evk_dvfscore_data.soc_id; +#else + gp_reg_id = mx6sl_evk_dvfscore_data.reg_id; + soc_reg_id = mx6sl_evk_dvfscore_data.soc_id; + pu_reg_id = mx6sl_evk_dvfscore_data.pu_id; + mx6_cpu_regulator_init(); +#endif + + imx6q_add_imx_snvs_rtc(); + + imx6q_add_imx_i2c(0, &mx6_evk_i2c0_data); + imx6q_add_imx_i2c(1, &mx6_evk_i2c1_data); + + /* setting sii902x address when hdmi enabled */ + switch (display_panel_mode) { + case PANEL_MODE_EINK: + for (i = 0; i < ARRAY_SIZE(mxc_i2c0_board_info); i++) + if (!strcmp(mxc_i2c0_board_info[i].type, "max17135")) + mxc_i2c0_board_info[i].addr = 0x48; + for (i = 0; i < ARRAY_SIZE(mxc_i2c0_board_info); i++) + if (!strcmp(mxc_i2c0_board_info[i].type, "elan-touch")) + mxc_i2c0_board_info[i].addr = 0x10; + elan_ts_init(); + mxc_register_device(&max17135_sensor_device, NULL); + setup_spdc(); + if (!spdc_sel) + imx6dl_add_imx_epdc(&epdc_data); + else + imx6sl_add_imx_spdc(&spdc_data); + break; + case PANEL_MODE_HDMI: + for (i = 0; i < ARRAY_SIZE(mxc_i2c1_board_info); i++) + if (!strcmp(mxc_i2c1_board_info[i].type, "sii902x")) + mxc_i2c1_board_info[i].addr = 0x39; +#ifdef CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF//[ + imx6dl_add_imx_elcdif(&hdmi_fb_data[0]); +#endif //]CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF + mxc_spdif_data.spdif_core_clk = clk_get_sys("mxc_spdif.0", + NULL); + clk_put(mxc_spdif_data.spdif_core_clk); + imx6q_add_spdif(&mxc_spdif_data); + imx6q_add_spdif_dai(); + imx6q_add_spdif_audio_device(); + break; + case PANEL_MODE_LCD: +#ifdef CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF//[ + imx6dl_add_imx_elcdif(&wvga_fb_data[0]); +#endif //]CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF + gpio_request(MX6_BRD_LCD_PWR_EN, "elcdif-power-on"); + gpio_direction_output(MX6_BRD_LCD_PWR_EN, 1); + mxc_register_device(&lcd_wvga_device, NULL); + break; + default: + pr_err("Error display_panel_mode\n"); + } + + 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)); + + /* only camera on I2C2, that's why we can do so */ + if (csi_enabled == 1) { + mxc_register_device(&csi_v4l2_devices, NULL); + imx6q_add_imx_i2c(2, &mx6_evk_i2c2_data); + i2c_register_board_info(2, mxc_i2c2_board_info, + ARRAY_SIZE(mxc_i2c2_board_info)); + } + + /* SPI */ + imx6q_add_ecspi(0, &mx6_evk_spi_data); + spi_device_init(); + + mx6sl_evk_init_pfuze100(0); + + imx6q_add_anatop_thermal_imx(1, &mx6sl_anatop_thermal_data); + + mx6_evk_init_uart(); + /* get enet tx reference clk from FEC_REF_CLK pad. + * GPR1[14] = 0, GPR1[18:17] = 00 + */ + mxc_iomux_set_gpr_register(1, 14, 1, 0); + mxc_iomux_set_gpr_register(1, 17, 2, 0); + + imx6_init_fec(fec_data); + + platform_device_register(&evk_vmmc_reg_devices); + imx6q_add_sdhci_usdhc_imx(1, &mx6_evk_sd2_data); + imx6q_add_sdhci_usdhc_imx(0, &mx6_evk_sd1_data); + imx6q_add_sdhci_usdhc_imx(2, &mx6_evk_sd3_data); + + mx6_evk_init_usb(); + imx6q_add_otp(); + imx6q_add_mxc_pwm(0); + imx6q_add_mxc_pwm_backlight(0, &mx6_evk_pwm_backlight_data); +#ifdef CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF//[ + imx6dl_add_imx_elcdif(&wvga_fb_data[0]); +#endif //] CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF + + gpio_request(MX6_BRD_LCD_PWR_EN, "elcdif-power-on"); + gpio_direction_output(MX6_BRD_LCD_PWR_EN, 1); + mxc_register_device(&lcd_wvga_device, NULL); + + imx6dl_add_imx_pxp(); + imx6dl_add_imx_pxp_client(); + + if (csi_enabled) { + imx6sl_add_fsl_csi(); + } + imx6q_add_dvfs_core(&mx6sl_evk_dvfscore_data); + + imx6q_init_audio(); + + /* uart2 for bluetooth */ + if (uart2_enabled) + uart2_init(); + + //mxc_register_device(&mxc_bt_rfkill, &mxc_bt_rfkill_data); + + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + imx6sl_add_device_buttons(); + imx6sl_add_imx_keypad(&mx6sl_evk_map_data); + imx6q_add_busfreq(); + imx6sl_add_dcp(); + imx6sl_add_rngb(); + imx6sl_add_imx_pxp_v4l2(); + + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); + /* Register charger chips */ + platform_device_register(&evk_max8903_charger_1); + pm_power_off = mx6_snvs_poweroff; +} + +extern void __iomem *twd_base; +static void __init mx6_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6sl_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART1_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx6_timer_init, +}; + +static void __init mx6_evk_reserve(void) +{ +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + phys_addr_t phys; + + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, MEMBLOCK_ALLOC_ACCESSIBLE); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif +} + +static int __init display_panel_setup(char *options) +{ + if (!options || !*options) { + pr_err("Error panel options\n"); + return 0; + } + + if (!strcmp(options, "lcd")) + display_panel_mode = PANEL_MODE_LCD; + else if (!strcmp(options, "hdmi")) + display_panel_mode = PANEL_MODE_HDMI; + else if (!strcmp(options, "eink")) + display_panel_mode = PANEL_MODE_EINK; + else + pr_warn("WARN: invalid display panel mode setting"); + + return 1; +} + +__setup("panel=", display_panel_setup); + +MACHINE_START(MX6SL_EVK, "Freescale i.MX 6SoloLite EVK Board") + .boot_params = MX6SL_PHYS_OFFSET + 0x100, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_evk_init, + .timer = &mxc_timer, + .reserve = mx6_evk_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6sl_ntx.c b/arch/arm/mach-mx6/board-mx6sl_ntx.c new file mode 100755 index 00000000..26c3c900 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6sl_ntx.c @@ -0,0 +1,3886 @@ +/* + * 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/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/nodemask.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/smsc911x.h> +#include <linux/spi/spi.h> +#include <linux/spi/flash.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/ata.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/pmic_external.h> +#include <linux/pmic_status.h> +#include <linux/mxcfb.h> +#include <linux/pwm_backlight.h> +#include <linux/fec.h> +#include <linux/memblock.h> +#include <linux/gpio.h> +#include <linux/etherdevice.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/mfd/max17135.h> +#include <sound/wm8962.h> +#include <sound/pcm.h> +#include <linux/power/sabresd_battery.h> +#include <../drivers/misc/ntx-misc.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include <mach/memory.h> +#include <mach/iomux-mx6sl.h> +#include <mach/imx-uart.h> +#include <mach/viv_gpu.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 <linux/usbplugevent.h> +#include <linux/mmc/sdhci.h> + + +#include "usb.h" +#include "devices-imx6q.h" +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "board-mx6sl_common.h" +#include "board-mx6sl_ntx.h" + +#include "ntx_hwconfig.h" + +#include <linux/mfd/ricoh619.h> +#include <linux/rtc/rtc-ricoh619.h> +#include <linux/power/ricoh619_battery.h> +#include <linux/regulator/ricoh619-regulator.h> + +#include "../../../drivers/input/keyboard/gpiofn.h" +#define TOUCH_HOME_LED 1 +#include "../../../drivers/misc/ntx-misc.h" + + +#define GDEBUG 0 +#include <linux/gallen_dbg.h> + + +#define EPD_TIMING_ED068OG1_NUMCE3 1 +#define EPD_TIMING_ED068TG1 1 + + + +extern int gSleep_Mode_Suspend; + + +volatile unsigned gMX6SL_NTX_ACIN_PG = IMX_GPIO_NR(4, 20); /* FEC_MDIO */ +volatile unsigned gMX6SL_NTX_CHG = IMX_GPIO_NR(4, 21); /* FEC_TX_CLK */ +volatile unsigned gMX6SL_MSP_INT = IMX_GPIO_NR(4, 19); /* FEC_RX_ER */ +volatile unsigned gMX6SL_PWR_SW = IMX_GPIO_NR(4, 25); /* FEC_CRS_DV */ +volatile unsigned gMX6SL_IR_TOUCH_INT = IMX_GPIO_NR(4, 24); /* FEC_TXD0 */ +volatile unsigned gMX6SL_IR_TOUCH_RST = IMX_GPIO_NR(4, 17); /* FEC_RXD0 */ +volatile unsigned gMX6SL_HALL_EN = IMX_GPIO_NR(4, 23); /* FEC_MDC */ +volatile unsigned gMX6SL_ON_LED = IMX_GPIO_NR(4, 22); /* FEC_TX_EN */ +volatile unsigned gMX6SL_CHG_LED = IMX_GPIO_NR(4, 16); /* FEC_TXD1 */ +volatile unsigned gMX6SL_ACT_LED = IMX_GPIO_NR(4, 26); /* FEC_REF_CLK */ +volatile unsigned gMX6SL_WIFI_3V3 = IMX_GPIO_NR(5, 0); /* SD2_DAT7 */ +volatile unsigned gMX6SL_WIFI_RST = IMX_GPIO_NR(4, 27); /* SD2_RST */ +volatile unsigned gMX6SL_WIFI_INT = IMX_GPIO_NR(4, 29); /* SD2_DAT6 */ +volatile unsigned gMX6SL_HOME_LED = IMX_GPIO_NR(5, 10); /* SD2_DAT6 */ + +volatile int giISD_3V3_ON_Ctrl = -1; + +static int spdc_sel; +static int max17135_regulator_init(struct max17135 *max17135); + +extern char *gp_reg_id; +extern char *soc_reg_id; +extern char *pu_reg_id; +extern int __init mx6sl_ntx_init_pfuze100(u32 int_gpio); +extern void tle4913_init(void); + +static int csi_enabled; + +#define _MYINIT_DATA +#define _MYINIT_TEXT +volatile static unsigned char _MYINIT_DATA *gpbHWCFG_paddr; +//volatile unsigned char *gpbHWCFG_vaddr; +volatile unsigned long _MYINIT_DATA gdwHWCFG_size; +volatile int _MYINIT_DATA giBootPort; + +volatile NTX_HWCONFIG *gptHWCFG; + +static void * _MemoryRequest(void *addr, u32 len, const char * name) +{ + void * mem = NULL; + do { + printk(KERN_DEBUG "***%s:%d: request memory region! addr=%p, len=%hd***\n", + __FUNCTION__, __LINE__, addr, len); + if (!request_mem_region((u32)addr, len, name)) { + printk(KERN_CRIT "%s(): request memory region failed! addr=%p, len %hd\n",__FUNCTION__, addr, len); + break; + } + mem = (void *) ioremap_nocache((u32)addr, len); + if (!mem) { + printk(KERN_CRIT "***%s:%d: could not ioremap %s***\n", __FUNCTION__, __LINE__, name); + release_mem_region((u32)addr, len); + break; + } + } while (0); + return mem; +} + +int gIsCustomerUi; +static int _MYINIT_TEXT hwcfg_p_setup(char *str) +{ + gpbHWCFG_paddr = (unsigned char *)simple_strtoul(str,NULL,0); + if(NULL==gptHWCFG) { + gptHWCFG = (NTX_HWCONFIG *)_MemoryRequest((void *)gpbHWCFG_paddr, gdwHWCFG_size, "hwcfg_p"); + if(!gptHWCFG) { + return 0; + } + } + printk("%s() hwcfg_p=%p,vaddr=%p,size=%d,pcb=0x%x\n",__FUNCTION__, + gpbHWCFG_paddr,gptHWCFG,(int)gdwHWCFG_size,gptHWCFG->m_val.bPCB); + gIsCustomerUi = (int)gptHWCFG->m_val.bUIStyle; + + return 1; +} + +static int _MYINIT_TEXT hwcfg_size_setup(char *str) +{ + gdwHWCFG_size = (unsigned long)simple_strtoul(str,NULL,0); + printk("%s() hwcfg_szie=%d\n",__FUNCTION__,(int)gdwHWCFG_size); + return 1; +} + +static int _MYINIT_TEXT boot_port_setup(char *str) +{ + giBootPort = (int)simple_strtoul(str,NULL,0); + printk("%s() boot_port=%d\n",__FUNCTION__,giBootPort); + return 1; +} + +static void _parse_cmdline(void) +{ + static int iParseCnt = 0; + char *pcPatternStart,*pcPatternVal,*pcPatternValEnd,cTempStore; + unsigned long ulPatternLen; + + char *szParsePatternA[]={"hwcfg_sz=","hwcfg_p=","boot_port="}; + int ((*pfnDispatchA[])(char *str))={hwcfg_size_setup,hwcfg_p_setup,boot_port_setup }; + + int i; + char *pszCmdLineBuf; + + + if(iParseCnt++>0) { + printk("%s : cmdline parse already done .\n",__FUNCTION__); + return ; + } + //printk("%s():cmdline(%d)=%s\n",__FUNCTION__,strlen(saved_command_line),saved_command_line); + + pszCmdLineBuf = kmalloc(strlen(saved_command_line)+1,GFP_KERNEL); + //ASSERT(pszCmdLineBuf); + strcpy(pszCmdLineBuf,saved_command_line); + printk("%s():cp cmdline=%s\n",__FUNCTION__,pszCmdLineBuf); + + for(i=0;i<sizeof(szParsePatternA)/sizeof(szParsePatternA[0]);i++) { + ulPatternLen = strlen(szParsePatternA[i]); + pcPatternStart = strstr(pszCmdLineBuf,szParsePatternA[i]); + if(pcPatternStart) { + pcPatternVal=pcPatternStart + ulPatternLen ; + pcPatternValEnd = strchr(pcPatternVal,' '); + cTempStore='\0'; + if(pcPatternValEnd) { + cTempStore = *pcPatternValEnd; + *pcPatternValEnd = '\0'; + } + //printk("%s():pattern \"%s\" ,val=\"%s\"\n",__FUNCTION__,szParsePatternA[i],pcPatternVal); + pfnDispatchA[i](pcPatternVal); + if(pcPatternValEnd) { + *pcPatternValEnd = cTempStore; + } + } + else + printk ("[%s-%d] %s not found !!!\n",__func__,__LINE__,szParsePatternA[i]); + } + if (NULL == gptHWCFG) { + printk ("[%s-%d] personal initial hw config.\n",__func__,__LINE__); + gptHWCFG = (NTX_HWCONFIG *)kmalloc(sizeof(NTX_HWCONFIG), GFP_KERNEL); + gptHWCFG->m_val.bTouchCtrl = 8; + } +} + + + +/* uart2 pins */ +#if 0 // gallen disabled . +static iomux_v3_cfg_t mx6sl_uart2_pads[] = { + MX6SL_PAD_SD2_DAT5__UART2_TXD, + MX6SL_PAD_SD2_DAT4__UART2_RXD, + MX6SL_PAD_SD2_DAT6__UART2_RTS, + MX6SL_PAD_SD2_DAT7__UART2_CTS, +}; +#endif + +enum sd_pad_mode { + SD_PAD_MODE_LOW_SPEED, + SD_PAD_MODE_MED_SPEED, + SD_PAD_MODE_HIGH_SPEED, +}; + +static int plt_sd_pad_change(unsigned int index, int clock) +{ + /* LOW speed is the default state of SD pads */ + static enum sd_pad_mode pad_mode = SD_PAD_MODE_LOW_SPEED; + + iomux_v3_cfg_t *sd_pads_200mhz = NULL; + iomux_v3_cfg_t *sd_pads_100mhz = NULL; + iomux_v3_cfg_t *sd_pads_50mhz = NULL; + + u32 sd_pads_200mhz_cnt; + u32 sd_pads_100mhz_cnt; + u32 sd_pads_50mhz_cnt; + + switch (index) { + case 0: + sd_pads_200mhz = mx6sl_sd1_200mhz; + sd_pads_100mhz = mx6sl_sd1_100mhz; + sd_pads_50mhz = mx6sl_sd1_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd1_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd1_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd1_50mhz); + break; + case 1: + sd_pads_200mhz = mx6sl_sd2_200mhz; + sd_pads_100mhz = mx6sl_sd2_100mhz; + sd_pads_50mhz = mx6sl_sd2_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd2_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd2_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd2_50mhz); + break; + case 2: + sd_pads_200mhz = mx6sl_sd3_200mhz; + sd_pads_100mhz = mx6sl_sd3_100mhz; + sd_pads_50mhz = mx6sl_sd3_50mhz; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_sd3_200mhz); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_sd3_100mhz); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_sd3_50mhz); + break; + case 3: + sd_pads_200mhz = mx6sl_brd_ntx_sd4_pads; + sd_pads_100mhz = mx6sl_brd_ntx_sd4_pads; + sd_pads_50mhz = mx6sl_brd_ntx_sd4_pads; + + sd_pads_200mhz_cnt = ARRAY_SIZE(mx6sl_brd_ntx_sd4_pads); + sd_pads_100mhz_cnt = ARRAY_SIZE(mx6sl_brd_ntx_sd4_pads); + sd_pads_50mhz_cnt = ARRAY_SIZE(mx6sl_brd_ntx_sd4_pads); + break; + + default: + printk(KERN_ERR "no such SD host controller index %d\n", index); + return -EINVAL; + } + + if (clock > 100000000) { + if (pad_mode == SD_PAD_MODE_HIGH_SPEED) + return 0; + BUG_ON(!sd_pads_200mhz); + pad_mode = SD_PAD_MODE_HIGH_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_200mhz, + sd_pads_200mhz_cnt); + } else if (clock > 52000000) { + if (pad_mode == SD_PAD_MODE_MED_SPEED) + return 0; + BUG_ON(!sd_pads_100mhz); + pad_mode = SD_PAD_MODE_MED_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_100mhz, + sd_pads_100mhz_cnt); + } else { + if (pad_mode == SD_PAD_MODE_LOW_SPEED) + return 0; + BUG_ON(!sd_pads_50mhz); + pad_mode = SD_PAD_MODE_LOW_SPEED; + return mxc_iomux_v3_setup_multiple_pads(sd_pads_50mhz, + sd_pads_50mhz_cnt); + } +} + + +static const struct esdhc_platform_data mx6_ntx_isd_data __initconst = { + .always_present = 1, + .delay_line = 0, + .platform_pad_change = plt_sd_pad_change, + .cd_type = ESDHC_CD_PERMANENT, +}; +static const struct esdhc_platform_data mx6_ntx_isd8bits_data __initconst = { + .always_present = 1, + .delay_line = 0, + .support_8bit = 1, + .platform_pad_change = plt_sd_pad_change, + .cd_type = ESDHC_CD_PERMANENT, +}; + +static const struct esdhc_platform_data mx6_ntx_sd_wifi_data __initconst = { + .cd_gpio = MX6SL_WIFI_3V3, + .wp_gpio = -1, + .keep_power_at_suspend = 1, + .delay_line = 0, +// .platform_pad_change = plt_sd_pad_change, + .cd_type = ESDHC_CD_WIFI_PWR, +}; + +static const struct esdhc_platform_data mx6_ntx_q22_sd_wifi_data __initconst = { + .cd_gpio = IMX_GPIO_NR(4, 29), + .wp_gpio = -1, + .keep_power_at_suspend = 1, + .delay_line = 0, +// .platform_pad_change = plt_sd_pad_change, + .cd_type = ESDHC_CD_WIFI_PWR, +}; + +static const struct esdhc_platform_data mx6_ntx_esd_data __initconst = { + .cd_gpio = MX6SL_EXT_SD_CD, + .wp_gpio = -1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .platform_pad_change = plt_sd_pad_change, + .cd_type = ESDHC_CD_GPIO, +}; +static const struct esdhc_platform_data mx6_ntx_esd_nocd_data __initconst = { + .always_present = 1, + .cd_gpio = 0, + .wp_gpio = -1, + .keep_power_at_suspend = 1, + .delay_line = 0, + .platform_pad_change = 0, + .cd_type = ESDHC_CD_PERMANENT, +}; + +#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) + +#if 0 +static struct regulator_consumer_supply ntx_vmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.0"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.1"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.2"), + REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; + +static struct regulator_init_data ntx_vmmc_init = { + .num_consumer_supplies = ARRAY_SIZE(ntx_vmmc_consumers), + .consumer_supplies = ntx_vmmc_consumers, +}; + +static struct fixed_voltage_config ntx_vmmc_reg_config = { + .supply_name = "vmmc", + .microvolts = 3300000, + .gpio = -1, + .init_data = &ntx_vmmc_init, +}; + +static struct platform_device ntx_vmmc_reg_devices = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &ntx_vmmc_reg_config, + }, +}; +#endif + +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[] = { +#if 0 + { + .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, + }, +#endif +}; + +static const struct anatop_thermal_platform_data + mx6sl_anatop_thermal_data __initconst = { + .name = "anatop_thermal", + }; + +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 = MX6SL_BRD_EPDC_PWRSTAT, + .gpio_pmic_vcom_ctrl = MX6SL_BRD_EPDC_VCOM, + .gpio_pmic_wakeup = MX6SL_BRD_EPDC_PMIC_WAKE, + .gpio_pmic_v3p3 = MX6SL_BRD_EPDC_PWRCTRL0, + .gpio_pmic_intr = MX6SL_BRD_EPDC_PMIC_INT, + .regulator_init = max17135_init_data, + .init = max17135_regulator_init, +}; + +static int __init max17135_regulator_init(struct max17135 *max17135) +{ +#if 0 + 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; + } + } + + /* + * TODO: We cannot enable full constraints for now, since + * it results in the PFUZE regulators being disabled + * at the end of boot, which disables critical regulators. + */ + /*regulator_has_full_constraints();*/ +#endif + return 0; +} + +static int mx6_ntx_spi_cs[] = { + MX6_BRD_ECSPI1_CS0, +}; + +static const struct spi_imx_master mx6_ntx_spi_data __initconst = { + .chipselect = mx6_ntx_spi_cs, + .num_chipselect = ARRAY_SIZE(mx6_ntx_spi_cs), +}; + +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) +static struct mtd_partition m25p32_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x00100000, + }, { + .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", +}; + +static struct spi_board_info m25p32_spi0_board_info[] __initdata = { + { + /* The modalias must be the same as spi device driver name */ + .modalias = "m25p80", + .max_speed_hz = 20000000, + .bus_num = 0, + .chip_select = 0, + .platform_data = &m25p32_spi_flash_data, + }, +}; +#endif + +static void spi_device_init(void) +{ +#if defined(CONFIG_MTD_M25P80) || defined(CONFIG_MTD_M25P80_MODULE) + spi_register_board_info(m25p32_spi0_board_info, + ARRAY_SIZE(m25p32_spi0_board_info)); +#endif +} + +static struct imx_ssi_platform_data mx6_sabresd_ssi_pdata = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +#if 0 +static struct mxc_audio_platform_data wm8962_data; + +static struct platform_device mx6_sabresd_audio_wm8962_device = { + .name = "imx-wm8962", +}; + +static struct wm8962_pdata wm8962_config_data = { + +}; + +static int wm8962_clk_enable(int enable) +{ + if (enable) + clk_enable(ntx_extern_audio_root); + else + clk_disable(ntx_extern_audio_root); + + return 0; +} + +static int mxc_wm8962_init(void) +{ + struct clk *pll4; + int rate; + + ntx_extern_audio_root = clk_get(NULL, "extern_audio_clk"); + if (IS_ERR(ntx_extern_audio_root)) { + pr_err("can't get ntx_extern_audio_root clock.\n"); + return PTR_ERR(ntx_extern_audio_root); + } + + pll4 = clk_get(NULL, "pll4"); + if (IS_ERR(pll4)) { + pr_err("can't get pll4 clock.\n"); + return PTR_ERR(pll4); + } + + clk_set_parent(ntx_extern_audio_root, pll4); + + rate = clk_round_rate(ntx_extern_audio_root, 26000000); + clk_set_rate(ntx_extern_audio_root, rate); + + wm8962_data.sysclk = rate; + /* set AUDMUX pads to 1.8v */ + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_MCLK, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_RXD, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_TXC, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_TXD, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + mxc_iomux_set_specialbits_register(MX6SL_PAD_AUD_TXFS, + PAD_CTL_LVE, PAD_CTL_LVE_MASK); + + return 0; +} + +static struct mxc_audio_platform_data wm8962_data = { + .ssi_num = 1, + .src_port = 2, + .ext_port = 3, + .hp_gpio = MX6_BRD_HEADPHONE_DET, + .hp_active_low = 1, + .mic_gpio = -1, + .mic_active_low = 1, + .init = mxc_wm8962_init, + .clock_enable = wm8962_clk_enable, +}; + +static struct regulator_consumer_supply sabresd_vwm8962_consumers[] = { + REGULATOR_SUPPLY("SPKVDD1", "1-001a"), + REGULATOR_SUPPLY("SPKVDD2", "1-001a"), +}; + +static struct regulator_init_data sabresd_vwm8962_init = { + .constraints = { + .name = "SPKVDD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sabresd_vwm8962_consumers), + .consumer_supplies = sabresd_vwm8962_consumers, +}; + +static struct fixed_voltage_config sabresd_vwm8962_reg_config = { + .supply_name = "SPKVDD", + .microvolts = 4325000, + .gpio = -1, + .enabled_at_boot = 1, + .init_data = &sabresd_vwm8962_init, +}; + +static struct platform_device sabresd_vwm8962_reg_devices = { + .name = "reg-fixed-voltage", + .id = 4, + .dev = { + .platform_data = &sabresd_vwm8962_reg_config, + }, +}; + +static int __init imx6q_init_audio(void) +{ + platform_device_register(&sabresd_vwm8962_reg_devices); + mxc_register_device(&mx6_sabresd_audio_wm8962_device, + &wm8962_data); + imx6q_add_imx_ssi(1, &mx6_sabresd_ssi_pdata); + + return 0; +} + +static int spdif_clk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long rate_actual; + rate_actual = clk_round_rate(clk, rate); + clk_set_rate(clk, rate_actual); + return 0; +} + +static struct mxc_spdif_platform_data mxc_spdif_data = { + .spdif_tx = 1, + .spdif_rx = 0, + .spdif_clk_44100 = 1, + .spdif_clk_48000 = -1, + .spdif_div_44100 = 23, + .spdif_clk_set_rate = spdif_clk_set_rate, + .spdif_clk = NULL, +}; +#endif + + +enum DISPLAY_PANEL_MODE { + PANEL_MODE_LCD, + PANEL_MODE_HDMI, + PANEL_MODE_EINK, +}; + +static int display_panel_mode = PANEL_MODE_EINK; + +#if 0 +static iomux_v3_cfg_t mx6sl_sii902x_hdmi_pads_enabled[] = { + MX6SL_PAD_LCD_RESET__GPIO_2_19, + MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, +}; + +static int sii902x_get_pins(void) +{ + /* Sii902x HDMI controller */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_sii902x_hdmi_pads_enabled, \ + ARRAY_SIZE(mx6sl_sii902x_hdmi_pads_enabled)); + + /* Reset Pin */ + gpio_request(MX6_BRD_LCD_RESET, "disp0-reset"); + gpio_direction_output(MX6_BRD_LCD_RESET, 1); + + /* Interrupter pin GPIO */ + gpio_request(MX6SL_BRD_EPDC_PWRCTRL3, "disp0-detect"); + gpio_direction_input(MX6SL_BRD_EPDC_PWRCTRL3); + return 1; +} + +static void sii902x_put_pins(void) +{ + gpio_free(MX6_BRD_LCD_RESET); + gpio_free(MX6SL_BRD_EPDC_PWRCTRL3); +} + +static void sii902x_hdmi_reset(void) +{ + gpio_set_value(MX6_BRD_LCD_RESET, 0); + msleep(10); + gpio_set_value(MX6_BRD_LCD_RESET, 1); + msleep(10); +} + +static struct fsl_mxc_lcd_platform_data sii902x_hdmi_data = { + .ipu_id = 0, + .disp_id = 0, + .reset = sii902x_hdmi_reset, + .get_pins = sii902x_get_pins, + .put_pins = sii902x_put_pins, +}; + +static void mx6sl_csi_io_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_csi_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_csi_enable_pads)); + + /* Camera reset */ + gpio_request(MX6SL_BRD_CSI_RST, "cam-reset"); + gpio_direction_output(MX6SL_BRD_CSI_RST, 1); + + /* Camera power down */ + gpio_request(MX6SL_BRD_CSI_PWDN, "cam-pwdn"); + gpio_direction_output(MX6SL_BRD_CSI_PWDN, 1); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_PWDN, 0); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_RST, 0); + msleep(1); + gpio_set_value(MX6SL_BRD_CSI_RST, 1); + msleep(5); + gpio_set_value(MX6SL_BRD_CSI_PWDN, 1); +} + +static void mx6sl_csi_cam_powerdown(int powerdown) +{ + if (powerdown) + gpio_set_value(MX6SL_BRD_CSI_PWDN, 1); + else + gpio_set_value(MX6SL_BRD_CSI_PWDN, 0); + + msleep(2); +} + +static struct fsl_mxc_camera_platform_data camera_data = { + .mclk = 24000000, + .io_init = mx6sl_csi_io_init, + .pwdn = mx6sl_csi_cam_powerdown, + .core_regulator = "VGEN2_1V5", + .analog_regulator = "VGEN6_2V8", +}; +#endif + +static struct imxi2c_platform_data mx6_ntx_i2c0_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_ntx_i2c1_data = { + .bitrate = 100000, +}; + +static struct imxi2c_platform_data mx6_ntx_i2c2_data = { + .bitrate = 100000, +}; + +static struct i2c_board_info i2c_zforce_ir_touch_binfo = { + .type = "zforce-ir-touch", + .addr = 0x50, + //.platform_data = MX6SL_IR_TOUCH_INT, + //.irq = gpio_to_irq(MX6SL_IR_TOUCH_INT), +}; + +static struct i2c_board_info i2c_elan_touch_binfo = { + .type = "elan-touch", + .addr = 0x15, +}; + +int ricoh619_init_port(int irq_num) +{ + printk("[%s-%d] ...\n",__func__,__LINE__); + return 0; +} + +static struct ricoh619_rtc_platform_data ricoh_rtc_data = { + .time = { + .tm_year = 1970, + .tm_mon = 0, + .tm_mday = 1, + .tm_hour = 0, + .tm_min = 0, + .tm_sec = 0, + }, +}; + +static struct ricoh619_battery_platform_data ricoh_battery_data = { +// .irq = RICOH619_IRQ_BASE, + .alarm_vol_mv = 3400, + // .adc_channel = RICOH619_ADC_CHANNEL_VBAT, + .multiple = 100, //100% + .monitor_time = 60, + /* some parameter is depend of battery type */ + .type[0] = { + .ch_vfchg = 0xFF, /* VFCHG = 0 - 4 (4.05v, 4.10v, 4.15v, 4.20v, 4.35v) */ + .ch_vrchg = 0xFF, /* VRCHG = 0 - 4 (3.85v, 3.90v, 3.95v, 4.00v, 4.10v) */ + .ch_vbatovset = 0xFF, /* VBATOVSET = 0 or 1 (0 : 4.38v(up)/3.95v(down) 1: 4.53v(up)/4.10v(down)) */ + .ch_ichg = 0xFF, /* ICHG = 0 - 0x1D (100mA - 3000mA) */ + .ch_ilim_adp = 0xFF, /* ILIM_ADP = 0 - 0x1D (100mA - 3000mA) */ + .ch_ilim_usb = 0xFF, /* ILIM_USB = 0 - 0x1D (100mA - 3000mA) */ + .ch_icchg = 0, /* ICCHG = 0 - 3 (50mA 100mA 150mA 200mA) */ + .fg_target_vsys = 0, /* This value is the target one to DSOC=0% */ + .fg_target_ibat = 0, /* This value is the target one to DSOC=0% */ + .fg_poff_vbat = 3520, /* setting value of 0 per Vbat */ + .jt_en = 0, /* JEITA Enable = 0 or 1 (1:enable, 0:disable) */ + .jt_hw_sw = 1, /* JEITA HW or SW = 0 or 1 (1:HardWare, 0:SoftWare) */ + .jt_temp_h = 50, /* degree C */ + .jt_temp_l = 12, /* degree C */ + .jt_vfchg_h = 0x03, /* VFCHG High = 0 - 4 (4.05v, 4.10v, 4.15v, 4.20v, 4.35v) */ + .jt_vfchg_l = 0, /* VFCHG High = 0 - 4 (4.05v, 4.10v, 4.15v, 4.20v, 4.35v) */ + .jt_ichg_h = 0x0D, /* VFCHG Low = 0 - 4 (4.05v, 4.10v, 4.15v, 4.20v, 4.35v) */ + .jt_ichg_l = 0x09, /* ICHG Low = 0 - 0x1D (100mA - 3000mA) */ + }, + /* + .type[1] = { + .ch_vfchg = 0x0, + .ch_vrchg = 0x0, + .ch_vbatovset = 0x0, + .ch_ichg = 0x0, + .ch_ilim_adp = 0x0, + .ch_ilim_usb = 0x0, + .ch_icchg = 0x00, + .fg_target_vsys = 3300,//3000, + .fg_target_ibat = 1000,//1000, + .jt_en = 0, + .jt_hw_sw = 1, + .jt_temp_h = 40, + .jt_temp_l = 10, + .jt_vfchg_h = 0x0, + .jt_vfchg_l = 0, + .jt_ichg_h = 0x01, + .jt_ichg_l = 0x01, + }, + */ + +/* JEITA Parameter +* +* VCHG +* | +* jt_vfchg_h~+~~~~~~~~~~~~~~~~~~~+ +* | | +* jt_vfchg_l-| - - - - - - - - - +~~~~~~~~~~+ +* | Charge area + | +* -------0--+-------------------+----------+--- Temp +* ! + +* ICHG +* | + +* jt_ichg_h-+ - -+~~~~~~~~~~~~~~+~~~~~~~~~~+ +* + | + | +* jt_ichg_l-+~~~~+ Charge area | +* | + + | +* 0--+----+--------------+----------+--- Temp +* 0 jt_temp_l jt_temp_h 55 +*/ +}; + +#define RICOH_REG(_id, _name, _sname) \ +{ \ + .id = RICOH619_ID_##_id, \ + .name = "ricoh61x-regulator", \ + .platform_data = &pdata_##_name##_##_sname, \ +} + +static struct regulator_consumer_supply ricoh619_dc1_supply_0[] = { + REGULATOR_SUPPLY("vdd_core2_1v3_soc", NULL), +}; +static struct regulator_consumer_supply ricoh619_dc2_supply_0[] = { + REGULATOR_SUPPLY("vdd_core1_3v3", NULL), +}; +static struct regulator_consumer_supply ricoh619_dc3_supply_0[] = { + REGULATOR_SUPPLY("vdd_core2_1v3_arm", NULL), +}; +static struct regulator_consumer_supply ricoh619_dc4_supply_0[] = { + REGULATOR_SUPPLY("vdd_core4_1v2", NULL), +}; +static struct regulator_consumer_supply ricoh619_dc5_supply_0[] = { + REGULATOR_SUPPLY("vdd_core4_1v8", NULL), +}; +static struct regulator_consumer_supply ricoh619_ldo1_supply_0[] = { + REGULATOR_SUPPLY("vdd_ir_3v3", NULL), +}; +static struct regulator_consumer_supply ricoh619_ldo2_supply_0[] = { +}; +static struct regulator_consumer_supply ricoh619_ldo3_supply_0[] = { + REGULATOR_SUPPLY("vdd_core5_1v2", NULL), +}; +static struct regulator_consumer_supply ricoh619_ldo4_supply_0[] = { +}; +static struct regulator_consumer_supply ricoh619_ldo5_supply_0[] = { + REGULATOR_SUPPLY("vdd_spd_3v3", NULL), +// REGULATOR_SUPPLY("vmmc", "sdhci-esdhc-imx.3"), +}; +static struct regulator_consumer_supply ricoh619_ldo6_supply_0[] = { + REGULATOR_SUPPLY("vdd_ddr_0v6", NULL), +}; +static struct regulator_consumer_supply ricoh619_ldo7_supply_0[] = { + REGULATOR_SUPPLY("vdd_pwm", "0-0007"), + REGULATOR_SUPPLY("vdd_fl_0_pwm", "0-0043"), + REGULATOR_SUPPLY("vdd_fl_pwm", "2-0043"), +}; +static struct regulator_consumer_supply ricoh619_ldo8_supply_0[] = { + REGULATOR_SUPPLY("ldo_1v8", NULL), +}; +static struct regulator_consumer_supply ricoh619_ldo9_supply_0[] = { +}; +static struct regulator_consumer_supply ricoh619_ldo10_supply_0[] = { +}; +static struct regulator_consumer_supply ricoh619_ldortc1_supply_0[] = { + REGULATOR_SUPPLY("vdd_rtc_3v3", NULL), +}; +static struct regulator_consumer_supply ricoh619_ldortc2_supply_0[] = { +}; + +#define RICOH_PDATA_INIT(_name, _sname, _minmv, _maxmv, _supply_reg, _always_on, \ + _boot_on, _apply_uv, _init_uV, _init_enable, _init_apply, _flags, \ + _ext_contol, _sleep_mV) \ + static struct ricoh619_regulator_platform_data pdata_##_name##_##_sname = \ + { \ + .regulator = { \ + .constraints = { \ + .min_uV = (_minmv)*1000, \ + .max_uV = (_maxmv)*1000, \ + .valid_modes_mask = (REGULATOR_MODE_NORMAL | \ + REGULATOR_MODE_STANDBY), \ + .valid_ops_mask = (REGULATOR_CHANGE_MODE | \ + REGULATOR_CHANGE_STATUS | \ + REGULATOR_CHANGE_VOLTAGE), \ + .always_on = _always_on, \ + .boot_on = _boot_on, \ + .apply_uV = _apply_uv, \ + }, \ + .num_consumer_supplies = \ + ARRAY_SIZE(ricoh619_##_name##_supply_##_sname), \ + .consumer_supplies = ricoh619_##_name##_supply_##_sname, \ + .supply_regulator = _supply_reg, \ + }, \ + .init_uV = _init_uV * 1000, \ + .init_enable = _init_enable, \ + .init_apply = _init_apply, \ + .sleep_uV = (_sleep_mV)*1000, \ + .flags = _flags, \ + .ext_pwr_req = _ext_contol, \ + } + +RICOH_PDATA_INIT(dc1, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 950); // Core2_1V3 +RICOH_PDATA_INIT(dc2, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // Core3_3V3 +RICOH_PDATA_INIT(dc3, 0, 950, 1425, 0, 1, 1, 0, 1425, 1, 1, 0, 0, 950); // Core2_1V3_ARM +RICOH_PDATA_INIT(dc4, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // Core4_1V2 +RICOH_PDATA_INIT(dc5, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // Core4_1V8 + +RICOH_PDATA_INIT(ldo1, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // IR_3V3 +RICOH_PDATA_INIT(ldo2, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // Core1_3V3* +RICOH_PDATA_INIT(ldo3, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // Core5_1V2 +RICOH_PDATA_INIT(ldo4, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0); // Reserved +RICOH_PDATA_INIT(ldo5, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // SPD_3V3 +RICOH_PDATA_INIT(ldo6, 0, 0, 0, 0, 1, 1, 0, -1, 1, 1, 0, 0, 0); // DDR_0V6 +RICOH_PDATA_INIT(ldo7, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0); // VDD_PWM +RICOH_PDATA_INIT(ldo8, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0); // ldo_1v8 +//RICOH_PDATA_INIT(ldo8, 0, 3300, 3300, 0, 1, 1, 0, 3300, 1, 1, 0, 0, 3300); // ldo_1v8 output 3V3 +RICOH_PDATA_INIT(ldo9, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0); // Reserved +RICOH_PDATA_INIT(ldo10, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 0); // Reserved +RICOH_PDATA_INIT(ldortc1, 0,0, 0, 0, 1, 1, 0, -1, 1, 1, -1, -1, -1); +RICOH_PDATA_INIT(ldortc2, 0,0, 0, 0, 0, 0, 0, -1, 0, 1, -1, -1, -1); + +#define RICOH619_DEV_REG \ + RICOH_REG(DC1, dc1, 0), \ + RICOH_REG(DC2, dc2, 0), \ + RICOH_REG(DC3, dc3, 0), \ + RICOH_REG(DC4, dc4, 0), \ + RICOH_REG(DC5, dc5, 0), \ + RICOH_REG(LDO1, ldo1, 0), \ + RICOH_REG(LDO2, ldo2, 0), \ + RICOH_REG(LDO3, ldo3, 0), \ + RICOH_REG(LDO4, ldo4, 0), \ + RICOH_REG(LDO5, ldo5, 0), \ + RICOH_REG(LDO6, ldo6, 0), \ + RICOH_REG(LDO7, ldo7, 0), \ + RICOH_REG(LDO8, ldo8, 0), \ + RICOH_REG(LDO9, ldo9, 0), \ + RICOH_REG(LDO10, ldo10, 0), \ + RICOH_REG(LDORTC1, ldortc1, 0), \ + RICOH_REG(LDORTC2, ldortc2, 0) + +struct ricoh619_subdev_info ricoh619_sub_data[] = { + RICOH619_DEV_REG, + { + .name = "ricoh619-battery", + .id = -1, + .platform_data = &ricoh_battery_data, + }, + { + .name = "rtc_ricoh619", + .id = 0, + .platform_data = &ricoh_rtc_data, + }, +}; + + +#define RICOH_GPIO_INIT(_init_apply, _output_mode, _output_val, _led_mode, _led_func) \ + { \ + .output_mode_en = _output_mode, \ + .output_val = _output_val, \ + .init_apply = _init_apply, \ + .led_mode = _led_mode, \ + .led_func = _led_func, \ + } +struct ricoh619_gpio_init_data ricoh_gpio_data[] = { + RICOH_GPIO_INIT(false, false, 0, 0, 0), + RICOH_GPIO_INIT(false, false, 0, 0, 0), + RICOH_GPIO_INIT(false, false, 0, 0, 0), + RICOH_GPIO_INIT(false, false, 0, 0, 0), +}; + +static struct ricoh619_platform_data ntx_ricoh_data = { + .num_subdevs = ARRAY_SIZE(ricoh619_sub_data), + .subdevs = ricoh619_sub_data, + .gpio_base = 7*32, + .gpio_init_data = ricoh_gpio_data, + .num_gpioinit_data = ARRAY_SIZE(ricoh_gpio_data), + .enable_shutdown_pin = true, +}; + +static struct i2c_board_info i2c_sysmp_ricoh619_binfo = { + .type = "ricoh619", + .addr = 0x32, + .platform_data = &ntx_ricoh_data, +}; + +static struct i2c_board_info i2c_sysmp_msp430_binfo = { + .type = "msp430", + .addr = 0x43, + //.irq = gpio_to_irq(MX6SL_MSP_INT), +}; + +static struct i2c_board_info i2c_ht68f20_binfo = { + .type = "ht68f20", + .addr = 0x07, +}; + +static struct i2c_board_info i2c_kl25_binfo = { + .type = "kl25", + .addr = 0x5A, + .irq = gpio_to_irq(MX6SL_KL25_INT2), +}; + +static struct i2c_board_info i2c_mma8652_binfo = { + .type = "mma8652", + .addr = 0x1D, + .irq = gpio_to_irq(MX6SL_KL25_INT2), +}; + +static struct i2c_board_info i2c_wacom_binfo = { + .type = "wacom_i2c", + .addr = 0x09, + .irq = gpio_to_irq(MX6SL_WACOM_INT), +}; + +static struct i2c_board_info __initdata i2c_waltop_binfo = { + .type = "waltop_i2c", + .addr = 0x37, + .platform_data = MX6SL_WALTOP_RST, + .irq = gpio_to_irq(MX6SL_WALTOP_INT), +}; +#if 0 +static struct i2c_board_info mxc_i2c1_board_info[] __initdata = { +}; +static struct i2c_board_info mxc_i2c2_board_info[] __initdata = { +#if 0 + { + I2C_BOARD_INFO("ov5640", 0x3c), + .platform_data = (void *)&camera_data, + }, +#endif + { + .type = "msp430", + .addr = 0x43, + .irq = gpio_to_irq(MX6SL_MSP_INT), + }, +}; +#endif + +static struct ntx_misc_platform_data ntx_misc_info; + +static struct platform_device ntx_charger = { + .name = "pmic_battery", + .id = 1, + .dev = { + .platform_data = &ntx_misc_info, + } +}; + +static struct platform_device ntx_light_ldm = { + .name = "pmic_light", + .id = 1, +}; + +static struct mxc_dvfs_platform_data mx6sl_ntx_dvfscore_data = { +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + .reg_id = "VDDCORE", + .soc_id = "VDDSOC", +#else + .reg_id = "cpu_vddgp", + .soc_id = "cpu_vddsoc", + .pu_id = "cpu_vddvpu", +#endif + .clk1_id = "cpu_clk", + .clk2_id = "gpc_dvfs_clk", + .gpc_cntr_offset = MXC_GPC_CNTR_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 viv_gpu_platform_data imx6q_gpu_pdata __initdata = { + .reserved_mem_size = SZ_32M, +}; + +void __init early_console_setup(unsigned long base, struct clk *clk); + +static const struct imxuart_platform_data mx6sl_ntx_uart1_data __initconst = { + .flags = IMXUART_HAVE_RTSCTS | IMXUART_SDMA, + .dma_req_rx = MX6Q_DMA_REQ_UART2_RX, + .dma_req_tx = MX6Q_DMA_REQ_UART2_TX, +}; + +static inline void mx6_ntx_init_uart(void) +{ + imx6q_add_imx_uart(0, NULL); /* DEBUG UART1 */ +} + +#if 0 +static int mx6sl_ntx_fec_phy_init(struct phy_device *phydev) +{ + int val; + + /* power on FEC phy and reset phy */ + gpio_request(MX6_BRD_FEC_PWR_EN, "fec-pwr"); + gpio_direction_output(MX6_BRD_FEC_PWR_EN, 0); + /* wait RC ms for hw reset */ + msleep(1); + gpio_direction_output(MX6_BRD_FEC_PWR_EN, 1); + + /* check phy power */ + val = phy_read(phydev, 0x0); + if (val & BMCR_PDOWN) + phy_write(phydev, 0x0, (val & ~BMCR_PDOWN)); + + return 0; +} + +static struct fec_platform_data fec_data __initdata = { + .init = mx6sl_ntx_fec_phy_init, + .phy = PHY_INTERFACE_MODE_RMII, +}; +#endif + +static int epdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for EPDC pins - used during power up/down */ + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_0, "epdc_d0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_1, "epdc_d1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_2, "epdc_d2"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_3, "epdc_d3"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_4, "epdc_d4"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_5, "epdc_d5"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_6, "epdc_d6"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_7, "epdc_d7"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_8 , "epdc_d8"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_9 , "epdc_d9"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_10, "epdc_d10"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_11, "epdc_d11"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_12, "epdc_d12"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_13, "epdc_d13"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_14, "epdc_d14"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_15, "epdc_d15"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDCLK, "epdc_gdclk"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDSP, "epdc_gdsp"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDOE, "epdc_gdoe"); + ret |= gpio_request(MX6SL_BRD_EPDC_GDRL, "epdc_gdrl"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCLK, "epdc_sdclk"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDOE, "epdc_sdoe"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDLE, "epdc_sdle"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDSHR, "epdc_sdshr"); + ret |= gpio_request(MX6SL_BRD_EPDC_BDR0, "epdc_bdr0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE0, "epdc_sdce0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE1, "epdc_sdce1"); +// ret |= gpio_request(MX6SL_BRD_EPDC_SDCE2, "epdc_sdce2"); + + return ret; +} + +static void epdc_put_pins(void) +{ + gpio_free(MX6SL_BRD_EPDC_SDDO_0); + gpio_free(MX6SL_BRD_EPDC_SDDO_1); + gpio_free(MX6SL_BRD_EPDC_SDDO_2); + gpio_free(MX6SL_BRD_EPDC_SDDO_3); + gpio_free(MX6SL_BRD_EPDC_SDDO_4); + gpio_free(MX6SL_BRD_EPDC_SDDO_5); + gpio_free(MX6SL_BRD_EPDC_SDDO_6); + gpio_free(MX6SL_BRD_EPDC_SDDO_7); + gpio_free(MX6SL_BRD_EPDC_SDDO_8); + gpio_free(MX6SL_BRD_EPDC_SDDO_9); + gpio_free(MX6SL_BRD_EPDC_SDDO_10); + gpio_free(MX6SL_BRD_EPDC_SDDO_11); + gpio_free(MX6SL_BRD_EPDC_SDDO_12); + gpio_free(MX6SL_BRD_EPDC_SDDO_13); + gpio_free(MX6SL_BRD_EPDC_SDDO_14); + gpio_free(MX6SL_BRD_EPDC_SDDO_15); + gpio_free(MX6SL_BRD_EPDC_GDCLK); + gpio_free(MX6SL_BRD_EPDC_GDSP); + gpio_free(MX6SL_BRD_EPDC_GDOE); + gpio_free(MX6SL_BRD_EPDC_GDRL); + gpio_free(MX6SL_BRD_EPDC_SDCLK); + gpio_free(MX6SL_BRD_EPDC_SDOE); + gpio_free(MX6SL_BRD_EPDC_SDLE); + gpio_free(MX6SL_BRD_EPDC_SDSHR); + gpio_free(MX6SL_BRD_EPDC_BDR0); + gpio_free(MX6SL_BRD_EPDC_SDCE0); + gpio_free(MX6SL_BRD_EPDC_SDCE1); +// gpio_free(MX6SL_BRD_EPDC_SDCE2); +} + +static void mxc_pads_lve_setup(iomux_v3_cfg_t *pad_list, unsigned count,int iIsLVE) +{ + iomux_v3_cfg_t tPadctrlOld; + iomux_v3_cfg_t tPadctrl; + iomux_v3_cfg_t *p = pad_list; + + int i; + + for(i=0;i<count;i++) { + tPadctrlOld = tPadctrl = *p ; + +#if 0 + if(tPadctrl&NO_PAD_CTRL) { + mxc_iomux_v3_get_pad(&tPadctrlOld); + tPadctrl = tPadctrlOld; + //tPadctrl &= ~((iomux_v3_cfg_t)NO_PAD_CTRL<<MUX_PAD_CTRL_SHIFT); + } +#endif + + if(iIsLVE) { + tPadctrl |= ((iomux_v3_cfg_t)PAD_CTL_LVE<<MUX_PAD_CTRL_SHIFT); + } + else { + tPadctrl &= ~((iomux_v3_cfg_t)PAD_CTL_LVE<<MUX_PAD_CTRL_SHIFT); + } + + #if 0 + printk("PAD LVE 0x%llx:0x%llx->0x%llx \n", + pad_list[i],tPadctrlOld,tPadctrl); + #endif + + mxc_iomux_v3_setup_pad(tPadctrl); + p++; + } +} + + + + + +static void epdc_enable_pins(void) +{ + /* Configure MUX settings to enable EPDC use */ + + if(NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bPCB_Flags,4)) { + // Panel is designed for low voltage . + mxc_pads_lve_setup(mx6sl_brd_epdc_enable_pads,\ + ARRAY_SIZE(mx6sl_brd_epdc_enable_pads),1); + } + else { +#if 0 + mxc_pads_lve_setup(mx6sl_brd_epdc_enable_pads,\ + ARRAY_SIZE(mx6sl_brd_epdc_enable_pads),0); +#else + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_epdc_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_epdc_enable_pads)); +#endif + + } + + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_0); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_1); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_2); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_3); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_4); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_5); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_6); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_7); + //if( 1==gptHWCFG->m_val.bDisplayBusWidth || + // 3==gptHWCFG->m_val.bDisplayBusWidth) + { + // 16 bits . + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_8); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_9); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_10); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_11); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_12); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_13); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_14); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_15); + } + gpio_direction_input(MX6SL_BRD_EPDC_GDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_GDSP); + gpio_direction_input(MX6SL_BRD_EPDC_GDOE); + gpio_direction_input(MX6SL_BRD_EPDC_GDRL); + gpio_direction_input(MX6SL_BRD_EPDC_SDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDOE); + gpio_direction_input(MX6SL_BRD_EPDC_SDLE); + gpio_direction_input(MX6SL_BRD_EPDC_SDSHR); + gpio_direction_input(MX6SL_BRD_EPDC_BDR0); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE0); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE1); +// gpio_direction_input(MX6SL_BRD_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(mx6sl_brd_epdc_disable_pads, \ + ARRAY_SIZE(mx6sl_brd_epdc_disable_pads)); + + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_2, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_3, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_4, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_5, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_6, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_7, 0); + //if( 1==gptHWCFG->m_val.bDisplayBusWidth || + // 3==gptHWCFG->m_val.bDisplayBusWidth) + { + // 16 bits . + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_8, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_9, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_10, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_11, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_12, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_13, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_14, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_15, 0); + } + gpio_direction_output(MX6SL_BRD_EPDC_GDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDSP, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDRL, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDLE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDSHR, 0); + gpio_direction_output(MX6SL_BRD_EPDC_BDR0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE1, 0); +// gpio_direction_output(MX6SL_BRD_EPDC_SDCE2, 0); +} + +#if 1 //[ +static struct fb_videomode ed060scq_mode = { +.name = "E60SCQ", +.refresh = 85, +.xres = 800, +.yres = 600, +.pixclock = 25000000, +.left_margin = 8, +.right_margin = 60, +.upper_margin = 4, +.lower_margin = 10, +.hsync_len = 8, +.vsync_len = 4, +.sync = 0, +.vmode = FB_VMODE_NONINTERLACED, +.flag = 0, +}; + +static struct fb_videomode ed060sc8_mode = { +.name = "E60SC8", +.refresh = 85, +.xres = 800, +.yres = 600, +.pixclock = 30000000, +.left_margin = 8, +.right_margin = 164, +.upper_margin = 4, +.lower_margin = 18, +.hsync_len = 4, +.vsync_len = 1, +.sync = 0, +.vmode = FB_VMODE_NONINTERLACED, +.flag = 0, +}; + +// for ED060XC5 release by Freescale Grace 20120726 . + +static struct fb_videomode ed060xc1_mode = { +.name = "E60XC1", +.refresh = 85, +.xres = 1024, +.yres = 768, +.pixclock = 40000000, +.left_margin = 12, +.right_margin = 72, +.upper_margin = 4, +.lower_margin = 5, +.hsync_len = 8, +.vsync_len = 2, +.sync = 0, +.vmode = FB_VMODE_NONINTERLACED, +.flag = 0, +}; + +static struct fb_videomode ed060xc5_mode = { +.name = "E60XC5", +.refresh = 85, +.xres = 1024, +.yres = 758, +.pixclock = 40000000, +.left_margin = 12, +.right_margin = 76, +.upper_margin = 4, +.lower_margin = 5, +.hsync_len = 12, +.vsync_len = 2, +.sync = 0, +.vmode = FB_VMODE_NONINTERLACED, +.flag = 0, +}; + +static struct fb_videomode e60_v110_mode = { +.name = "E60_V110", +.refresh = 50, +.xres = 800, +.yres = 600, +.pixclock = 18604700, +.left_margin = 8, +.right_margin = 176, +.upper_margin = 4, +.lower_margin = 2, +.hsync_len = 4, +.vsync_len = 1, +.sync = 0, +.vmode = FB_VMODE_NONINTERLACED, +.flag = 0, +}; + +static struct fb_videomode ed050xxx_mode = { + .name="ED050XXXX", + .refresh=85, + .xres=800, + .yres=600, + .pixclock=26666667, + .left_margin=4, + .right_margin=98, + .upper_margin=4, + .lower_margin=9, + .hsync_len=8, + .vsync_len=2, + .sync=0, + .vmode=FB_VMODE_NONINTERLACED, + .flag=0, +}; + + +#ifdef EPD_TIMING_ED068TG1 //[ +static struct fb_videomode ed068tg1_mode = { +.name = "ED068TG1", +.refresh=85, +.xres=1440, +.yres=1080, +.pixclock=96000000, +.left_margin=24, +.right_margin=267, +.upper_margin=4, +.lower_margin=5, +.hsync_len=24, +.vsync_len=2, +.sync=0, +.vmode=FB_VMODE_NONINTERLACED, +.flag=0, +}; +#elif defined(EPD_TIMING_ED068OG1_NUMCE3) //][ +/* i.MX508 waveform data timing data structures for ed068og1_numce3 */ +/* Created on - Monday, October 15, 2012 10:36:24 + Warning: this pixel clock is derived from 480 MHz parent! */ + +static struct fb_videomode ed068og1_numce3_mode = { +.name="ED068OG1_NUMCE3", +.refresh=85, +.xres=1440, +.yres=1080, +.pixclock=96000000, +.left_margin=24, +.right_margin=267, +.upper_margin=4, +.lower_margin=5, +.hsync_len=24, +.vsync_len=2, +.sync=0, +.vmode=FB_VMODE_NONINTERLACED, +.flag=0, +}; +#else +static struct fb_videomode ed068og1_mode = { +.name = "E68OG1", +.refresh=85, +.xres=1440, +.yres=1080, +.pixclock=120000000, +.left_margin=32, +.right_margin=508, +.upper_margin=4, +.lower_margin=5, +.hsync_len=32, +.vsync_len=2, +.sync=0, +.vmode=FB_VMODE_NONINTERLACED, +.flag=0, +}; +#endif//]EPD_TIMING_ED068OG1_NUMCE3 + +static struct fb_videomode peng060d_mode = { +.name = "PENG060D", +.refresh=85, +.xres=1448, +.yres=1072, +.pixclock=80000000, +.left_margin=16, +.right_margin=102, +.upper_margin=4, +.lower_margin=4, +.hsync_len=28, +.vsync_len=2, +.sync=0, +.vmode=FB_VMODE_NONINTERLACED, +.flag=0, +}; + +static struct fb_videomode ef133ut1sce_mode = { +.name="EF133UT1SCE", +.refresh=65, +.xres=1600, +.yres=1200, +.pixclock=72222223, +.left_margin=8, +.right_margin=97, +.upper_margin=4, +.lower_margin=7, +.hsync_len=12, +.vsync_len=1, +.sync=0, +.vmode=FB_VMODE_NONINTERLACED, +.flag=0, +}; + + + +static struct imx_epdc_fb_mode panel_modes[] = { +//////////////////// +{ +& ed060sc8_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +465, /* gdclk_hp_offs */ +250, /* gdsp_offs changed delay to 8.3 uS */ +0, /* gdoe_offs */ +8, /* gdclk_offs changed delay to 4.5 SDCLK */ +1, /* num_ce */ +}, + +//////////////////// +{ +& e60_v110_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +465, /* gdclk_hp_offs */ +250, /* gdsp_offs changed delay to 8.3 uS */ +0, /* gdoe_offs */ +8, /* gdclk_offs changed delay to 4.5 SDCLK */ +1, /* num_ce */ +}, + +//////////////////// +{ +& ed060xc5_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +524, /* gdclk_hp_offs */ +25, /* gdsp_offs changed delay to 8.3 uS */ +0, /* gdoe_offs */ +19, /* gdclk_offs changed delay to 4.5 SDCLK */ +1, /* num_ce */ +}, + +//////////////////// +{ +& ed060xc1_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +492, /* gdclk_hp_offs */ +29, /* gdsp_offs changed delay to 8.3 uS */ +0, /* gdoe_offs */ +23, /* gdclk_offs changed delay to 4.5 SDCLK */ +1, /* num_ce */ +}, + +//////////////////// +{ + &ed050xxx_mode, /* struct fb_videomode *mode */ + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 420, /* GDCLK_HP */ + 20, /* GDSP_OFF */ + 0, /* GDOE_OFF */ + 11, /* gdclk_offs */ + 3, /* num_ce */ +}, + +#ifdef EPD_TIMING_ED068TG1 //[ +{ +& ed068tg1_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +665, /* GDCLK_HP */ +718, /* GDSP_OFF */ +0, /* GDOE_OFF */ +199, /* gdclk_offs */ +1, /* num_ce */ +}, +#elif defined(EPD_TIMING_ED068OG1_NUMCE3)//][ +{ +& ed068og1_numce3_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +665, /* GDCLK_HP */ +210, /* GDSP_OFF */ +0, /* GDOE_OFF */ +199, /* gdclk_offs */ +3, /* num_ce */ +}, +#else//][ !EPD_TIMING_ED068OG1_NUMCE3 +{ +& ed068og1_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +831, /* GDCLK_HP */ +285, /* GDSP_OFF */ +0, /* GDOE_OFF */ +271, /* gdclk_offs */ +1, /* num_ce */ +}, +#endif//] EPD_TIMING_ED068OG1_NUMCE3 + +{ +&peng060d_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +562, /* GDCLK_HP */ +664, /* GDSP_OFF */ +0, /* GDOE_OFF */ +227, /* gdclk_offs */ +3, /* num_ce */ +}, +{ +&ef133ut1sce_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +743, /* GDCLK_HP */ +475, /* GDSP_OFF */ +0, /* GDOE_OFF */ +15, /* gdclk_offs */ +1, /* num_ce */ +}, +{ +&ed060scq_mode, +4, /* vscan_holdoff */ +10, /* sdoed_width */ +20, /* sdoed_delay */ +10, /* sdoez_width */ +20, /* sdoez_delay */ +438, /* GDCLK_HP */ +263, /* GDSP_OFF */ +0, /* GDOE_OFF */ +23, /* gdclk_offs */ +3, /* num_ce */ +}, +}; + + +#else //][! +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, + .refresh = 85, + .xres = 800, + .yres = 600, +}; +static struct fb_videomode e060scm_mode = { + .name = "E060SCM", + .refresh = 85, + .xres = 800, + .yres = 600, + .pixclock = 26666667, + .left_margin = 8, + .right_margin = 100, + .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 */ + }, + { + &e060scm_mode, + 4, /* vscan_holdoff */ + 10, /* sdoed_width */ + 20, /* sdoed_delay */ + 10, /* sdoez_width */ + 20, /* sdoez_delay */ + 419, /* gdclk_hp_offs */ + 20, /* gdsp_offs */ + 0, /* gdoe_offs */ + 5, /* 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 */ + } +}; +#endif //] + +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, +}; + +typedef void (*usb_insert_handler) (char inserted); +usb_insert_handler mxc_misc_report_usb; + +static void mxc_register_usb_plug(void* pk_cb) +{ + pmic_event_callback_t usb_plug_event; + +// usb_plug_event.param = (void *)1; +// usb_plug_event.func = (void *)pk_cb; +// pmic_event_subscribe(EVENT_VBUSVI, usb_plug_event); + if (gIsCustomerUi) + mxc_misc_report_usb = pk_cb; + DBG_MSG("%s(),pk_cb=%p\n",__FUNCTION__,pk_cb); + +} + + +extern int mxc_usb_plug_getstatus (void); + + +#define SW_USBPLUG 0x0C +static struct usbplug_event_platform_data usbplug_data = { + .usbevent.type = EV_SW, + .usbevent.code = SW_USBPLUG, + .register_usbplugevent = mxc_register_usb_plug, + .get_key_status = mxc_usb_plug_getstatus, +}; + +struct platform_device mxc_usb_plug_device = { + .name = "usb_plug", + .id = 0, + }; + + + +static int spdc_get_pins(void) +{ + int ret = 0; + + /* Claim GPIOs for SPDC pins - used during power up/down */ + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_0, "SPDC_D0"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_1, "SPDC_D1"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_2, "SPDC_D2"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_3, "SPDC_D3"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_4, "SPDC_D4"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_5, "SPDC_D5"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_6, "SPDC_D6"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_7, "SPDC_D7"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDOE, "SIPIX_YOE"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_9, "SIPIX_PWR_RDY"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDSP, "SIPIX_YDIO"); + + ret |= gpio_request(MX6SL_BRD_EPDC_GDCLK, "SIPIX_YCLK"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDSHR, "SIPIX_XDIO"); + + ret |= gpio_request(MX6SL_BRD_EPDC_SDLE, "SIPIX_LD"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE1, "SIPIX_SOE"); + + ret |= gpio_request(MX6SL_BRD_EPDC_SDCLK, "SIPIX_XCLK"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDDO_10, "SIPIX_SHD_N"); + ret |= gpio_request(MX6SL_BRD_EPDC_SDCE0, "SIPIX2_CE"); + + return ret; +} + +static void spdc_put_pins(void) +{ + gpio_free(MX6SL_BRD_EPDC_SDDO_0); + gpio_free(MX6SL_BRD_EPDC_SDDO_1); + gpio_free(MX6SL_BRD_EPDC_SDDO_2); + gpio_free(MX6SL_BRD_EPDC_SDDO_3); + gpio_free(MX6SL_BRD_EPDC_SDDO_4); + gpio_free(MX6SL_BRD_EPDC_SDDO_5); + gpio_free(MX6SL_BRD_EPDC_SDDO_6); + gpio_free(MX6SL_BRD_EPDC_SDDO_7); + + gpio_free(MX6SL_BRD_EPDC_GDOE); + gpio_free(MX6SL_BRD_EPDC_SDDO_9); + gpio_free(MX6SL_BRD_EPDC_GDSP); + gpio_free(MX6SL_BRD_EPDC_GDCLK); + gpio_free(MX6SL_BRD_EPDC_SDSHR); + gpio_free(MX6SL_BRD_EPDC_SDLE); + gpio_free(MX6SL_BRD_EPDC_SDCE1); + gpio_free(MX6SL_BRD_EPDC_SDCLK); + gpio_free(MX6SL_BRD_EPDC_SDDO_10); + gpio_free(MX6SL_BRD_EPDC_SDCE0); +} + +static void spdc_enable_pins(void) +{ + /* Configure MUX settings to enable SPDC use */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_spdc_enable_pads, \ + ARRAY_SIZE(mx6sl_brd_spdc_enable_pads)); + + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_0); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_1); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_2); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_3); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_4); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_5); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_6); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_7); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_8); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_9); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_10); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_11); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_12); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_13); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_14); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_15); + gpio_direction_input(MX6SL_BRD_EPDC_GDOE); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_9); + gpio_direction_input(MX6SL_BRD_EPDC_GDSP); + gpio_direction_input(MX6SL_BRD_EPDC_GDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDSHR); + gpio_direction_input(MX6SL_BRD_EPDC_SDLE); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE1); + gpio_direction_input(MX6SL_BRD_EPDC_SDCLK); + gpio_direction_input(MX6SL_BRD_EPDC_SDDO_10); + gpio_direction_input(MX6SL_BRD_EPDC_SDCE0); +} + +static void spdc_disable_pins(void) +{ + /* Configure MUX settings for SPDC pins to + * GPIO and drive to 0. */ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_spdc_disable_pads, \ + ARRAY_SIZE(mx6sl_brd_spdc_disable_pads)); + + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_0, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_2, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_3, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_4, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_5, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_6, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_7, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_8 , 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_9 , 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_10, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_11, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_12, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_13, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_14, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_15, 0); + + gpio_direction_output(MX6SL_BRD_EPDC_GDOE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_9, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDSP, 0); + gpio_direction_output(MX6SL_BRD_EPDC_GDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDSHR, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDLE, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE1, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCLK, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDDO_10, 0); + gpio_direction_output(MX6SL_BRD_EPDC_SDCE0, 0); +} + +static struct imx_spdc_panel_init_set spdc_init_set = { + .yoe_pol = false, + .dual_gate = false, + .resolution = 0, + .ud = false, + .rl = false, + .data_filter_n = true, + .power_ready = true, + .rgbw_mode_enable = false, + .hburst_len_en = true, +}; + +static struct fb_videomode erk_1_4_a01 = { + .name = "ERK_1_4_A01", + .refresh = 50, + .xres = 800, + .yres = 600, + .pixclock = 40000000, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct imx_spdc_fb_mode spdc_panel_modes[] = { + { + &erk_1_4_a01, + &spdc_init_set, + .wave_timing = "pvi" + }, +}; + +static struct imx_spdc_fb_platform_data spdc_data = { + .spdc_mode = spdc_panel_modes, + .num_modes = ARRAY_SIZE(spdc_panel_modes), + .get_pins = spdc_get_pins, + .put_pins = spdc_put_pins, + .enable_pins = spdc_enable_pins, + .disable_pins = spdc_disable_pins, +}; + +static int __init early_use_spdc_sel(char *p) +{ + spdc_sel = 1; + return 0; +} +early_param("spdc", early_use_spdc_sel); + +static void setup_spdc(void) +{ + /* GPR0[8]: 0:EPDC, 1:SPDC */ + if (spdc_sel) + mxc_iomux_set_gpr_register(0, 8, 1, 1); +} + +static void imx6_ntx_usbotg_vbus(bool on) +{ +#if 0 + if (on) + gpio_set_value(MX6_BRD_USBOTG1_PWR, 1); + else + gpio_set_value(MX6_BRD_USBOTG1_PWR, 0); +#endif +} + +static void __init mx6_ntx_init_usb(void) +{ + int ret = 0; + + imx_otg_base = MX6_IO_ADDRESS(MX6Q_USB_OTG_BASE_ADDR); + +#if 0 + /* disable external charger detect, + * or it will affect signal quality at dp. + */ + + ret = gpio_request(MX6_BRD_USBOTG1_PWR, "usbotg-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_BRD_USBOTG1_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_BRD_USBOTG1_PWR, 0); + + ret = gpio_request(MX6_BRD_USBOTG2_PWR, "usbh1-pwr"); + if (ret) { + pr_err("failed to get GPIO MX6_BRD_USBOTG2_PWR:%d\n", ret); + return; + } + gpio_direction_output(MX6_BRD_USBOTG2_PWR, 1); +#endif + + mx6_set_otghost_vbus_func(imx6_ntx_usbotg_vbus); +#ifdef CONFIG_USB_EHCI_ARC_HSIC + mx6_usb_h2_init(); +#endif +} + +static struct platform_device mxcbl_device = { + .name = "mxc_msp430_fl", +}; + +static struct platform_pwm_backlight_data mx6_ntx_pwm_backlight_data = { + .pwm_id = 0, + .max_brightness = 255, + .dft_brightness = 128, + .pwm_period_ns = 50000, +}; +static struct fb_videomode wvga_video_modes[] = { + { + /* 800x480 @ 57 Hz , pixel clk @ 32MHz */ + "SEIKO-WVGA", 60, 800, 480, 29850, 99, 164, 33, 10, 10, 10, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data wvga_fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB24, + .mode_str = "SEIKO-WVGA", + .mode = wvga_video_modes, + .num_modes = ARRAY_SIZE(wvga_video_modes), + .panel_type = "lcd", + }, +}; + +static struct platform_device lcd_wvga_device = { + .name = "lcd_seiko", +}; + +#if 0 +static struct fb_videomode hdmi_video_modes[] = { + { + /* 1920x1080 @ 60 Hz , pixel clk @ 148MHz */ + "sii9022x_1080p60", 60, 1920, 1080, 6734, 148, 88, 36, 4, 44, 5, + FB_SYNC_CLK_LAT_FALL, + FB_VMODE_NONINTERLACED, + 0,}, +}; + +static struct mxc_fb_platform_data hdmi_fb_data[] = { + { + .interface_pix_fmt = V4L2_PIX_FMT_RGB24, + .mode_str = "1920x1080M@60", + .mode = hdmi_video_modes, + .num_modes = ARRAY_SIZE(hdmi_video_modes), + .panel_type = "hdmi", + }, +}; +#endif + +static int mx6sl_ntx_keymap[] = { + KEY(0, 0, 90), +}; + +static struct platform_device ntx_device_rtc = { + .name = "ntx_misc_rtc", + .id = 0, + .dev = { + .platform_data = -1, + } +}; + +static const struct matrix_keymap_data mx6sl_ntx_map_data __initconst = { + .keymap = mx6sl_ntx_keymap, + .keymap_size = ARRAY_SIZE(mx6sl_ntx_keymap), +}; +#if 0 +static void __init elan_ts_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_elan_pads, + ARRAY_SIZE(mx6sl_brd_elan_pads)); + + /* ELAN Touchscreen */ + gpio_request(MX6SL_BRD_ELAN_INT, "elan-interrupt"); + gpio_direction_input(MX6SL_BRD_ELAN_INT); + + gpio_request(MX6SL_BRD_ELAN_CE, "elan-cs"); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 0); + + gpio_request(MX6SL_BRD_ELAN_RST, "elan-rst"); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 1); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 0); + mdelay(1); + gpio_direction_output(MX6SL_BRD_ELAN_RST, 1); + gpio_direction_output(MX6SL_BRD_ELAN_CE, 1); +} +#endif + +/* + *Usually UOK and DOK should have separate + *line to differentiate its behaviour (with different + * GPIO irq),because connect max8903 pin UOK to + *pin DOK from hardware design,cause software cannot + *process and distinguish two interrupt, so default + *enable dc_valid for ac charger + */ +static struct max8903_pdata charger1_data = { + .dok = MX6_BRD_CHG_DOK, + .uok = MX6_BRD_CHG_UOK, + .chg = MX6_BRD_CHG_STATUS, + .flt = MX6_BRD_CHG_FLT, + .dcm_always_high = true, + .dc_valid = true, + .usb_valid = false, + .feature_flag = 1, +}; + +static struct platform_device ntx_max8903_charger_1 = { + .name = "max8903-charger", + .dev = { + .platform_data = &charger1_data, + }, +}; + +/*! Device Definition for csi v4l2 device */ +static struct platform_device csi_v4l2_devices = { + .name = "csi_v4l2", + .id = 0, +}; + +#define SNVS_LPCR 0x38 +static void mx6_snvs_poweroff(void) +{ + u32 value; + void __iomem *mx6_snvs_base = MX6_IO_ADDRESS(MX6Q_SNVS_BASE_ADDR); + + value = readl(mx6_snvs_base + SNVS_LPCR); + /* set TOP and DP_EN bit */ + writel(value | 0x60, mx6_snvs_base + SNVS_LPCR); +} + +#if 0 +static int uart2_enabled; +static int __init uart2_setup(char * __unused) +{ + uart2_enabled = 1; + return 1; +} +__setup("bluetooth", uart2_setup); + +static void __init uart2_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_uart2_pads, + ARRAY_SIZE(mx6sl_uart2_pads)); + imx6sl_add_imx_uart(1, &mx6sl_ntx_uart1_data); +} +#endif + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) + +#define GPIO_BUTTON(gpio_num, ev_code, act_low, descr, wake, debounce) \ +{ \ + .gpio = gpio_num, \ + .type = EV_KEY, \ + .code = ev_code, \ + .active_low = act_low, \ + .desc = "btn " descr, \ + .wakeup = wake, \ + .debounce_interval = debounce, \ +} + +static struct gpio_keys_button gpio_key_matrix_FL[] = { + GPIO_BUTTON(GPIO_KB_ROW0, 90, 1, "front_light", 1,1), // Front light +//#ifdef CONFIG_ANDROID //[ + GPIO_BUTTON(IMX_GPIO_NR(4, 25), KEY_POWER, 1, "power", 1, 1), +//#endif //]CONFIG_ANDROID +}; + +static struct gpio_keys_button gpio_key_HOME_FL[] = { + GPIO_BUTTON(GPIO_KB_COL1, 90, 1, "front_light", 1,1), // Front light + GPIO_BUTTON(GPIO_KB_COL0, KEY_HOME, 1, "home", 1,1), // home +//#ifdef CONFIG_ANDROID //[ + GPIO_BUTTON(IMX_GPIO_NR(5, 8), KEY_POWER, 1, "power", 1, 1), +//#endif //]CONFIG_ANDROID +}; +static struct gpio_keys_button gpio_key_RETURN_HOME_MENU[] = { + GPIO_BUTTON(GPIO_KB_ROW0, KEY_HOME, 1, "home", 1,1), // home + GPIO_BUTTON(GPIO_KB_ROW1, KEY_MENU, 1, "menu", 1,1), // menu + GPIO_BUTTON(GPIO_KB_ROW2, KEY_ESC, 1, "return", 1,1), // return +//#ifdef CONFIG_ANDROID //[ + GPIO_BUTTON(IMX_GPIO_NR(5, 8), KEY_POWER, 1, "power", 1, 1), +//#endif //]CONFIG_ANDROID +}; + +static struct gpio_keys_button gpio_key_HOME[] = { + GPIO_BUTTON(GPIO_KB_COL0, 61, 1, "home", 1, 50), // home +//#ifdef CONFIG_ANDROID //[ + GPIO_BUTTON(IMX_GPIO_NR(5, 8), KEY_POWER, 1, "power", 1, 1), +//#endif //]CONFIG_ANDROID +}; + +static struct gpio_keys_button gpio_key_FL[] = { + GPIO_BUTTON(GPIO_KB_COL1, 90, 1, "front_light", 1, 10), // Front light +//#ifdef CONFIG_ANDROID //[ + GPIO_BUTTON(IMX_GPIO_NR(5, 8), KEY_POWER, 1, "power", 1, 1), +//#endif //]CONFIG_ANDROID +}; + +static struct gpio_keys_button gpio_key_None[] = { +//#ifdef CONFIG_ANDROID //[ + GPIO_BUTTON(IMX_GPIO_NR(5, 8), KEY_POWER, 1, "power", 1, 1), +//#endif //]CONFIG_ANDROID +}; + +static struct gpio_keys_button *gptGPIO_HOME_KEY; + +static struct gpio_keys_platform_data ntx_gpio_key_data = { + .buttons = gpio_key_matrix_FL, + .nbuttons = ARRAY_SIZE(gpio_key_matrix_FL), +}; + +static struct platform_device ntx_gpio_key_device = { + .name = "gpio-keys", + .id = -1, + .num_resources = 0, + .dev = { + .platform_data = &ntx_gpio_key_data, + } +}; + +#ifdef TOUCH_HOME_LED//[ + +extern int ntx_get_homepad_enabled_status(void); + +static int giHomeLED_Delay_Ticks=100; +static volatile int giCurHomeLED_state; +static struct delayed_work homeled_pwrdwn_work,homepad_check_work; +/* + * giHomePad_enable : + * 0 = disabled . + * 1 = enabled home pad/led action . + * 2 = enabled home pad/led action and send event to application layer . + */ +static int giHomePad_enable=2; + + +static void _homeled_onoff_force(int iIsON) +{ + //int iOldHomeLED_state=giCurHomeLED_state; + int iIsHOMELED_gpio=1; + + if( 0==gptHWCFG->m_val.bHOME_LED_PWM && \ + ( 36!=gptHWCFG->m_val.bPCB && 40!=gptHWCFG->m_val.bPCB) ) + { + // HOME_LED_PWM==NO && !=E60Q3X&&E60Q5X + return ; + } + + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + printk("MSP430 "); + iIsHOMELED_gpio=0; + } + else { + printk("GPIO "); + } + + if(iIsON) { + giCurHomeLED_state=1; + printk("HOME LED [ON]\n"); + if(iIsHOMELED_gpio) { + gpio_direction_output (gMX6SL_HOME_LED, 0); + } + else { + } + } + else { + giCurHomeLED_state=0; + printk("HOME LED [OFF]\n"); + if(iIsHOMELED_gpio) { + gpio_direction_output (gMX6SL_HOME_LED, 1); + } + else { + } + } +} + + +static ssize_t homepad_enable_write(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + int iParam; + extern void gpiokeys_enable_button(struct gpio_keys_button *button,int iIsEnable); + + iParam = simple_strtol(buf,NULL,0); + + if(iParam!=giHomePad_enable) { + switch (iParam) { + case 0: + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + //msp430_homeled_enable(0); + } + //gpiokeys_enable_button(gptGPIO_HOME_KEY,0); + _homeled_onoff_force(0); + msp430_homepad_enable(0); + giHomePad_enable = iParam; + break; + case 1: + case 2: + //gpiokeys_enable_button(gptGPIO_HOME_KEY,1); + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + //msp430_homeled_enable(1); + } + msp430_homepad_enable(2); + giHomePad_enable = iParam; + break; + default : + printk(KERN_ERR"invalid parameter !\n"); + return -1; + } + } + else { + + } + + return strlen(buf); +} +static ssize_t homepad_enable_read(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + ssize_t szChk=0; + sprintf(buf,"%d\n",giHomePad_enable); + szChk = strlen(buf); + return szChk; +} +static DEVICE_ATTR(homepad_enable,0666, + homepad_enable_read, + homepad_enable_write); + +static ssize_t homeled_delayms_show(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + ssize_t szChk=0; + sprintf(buf,"%d\n",giHomeLED_Delay_Ticks*(1000/HZ)); + szChk = strlen(buf); + return szChk; +} +static ssize_t homeled_delayms_store(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + int iDelayms; + ssize_t szChk; + iDelayms = simple_strtol(buf,NULL,0); + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + int iChk = msp430_set_homeled_delayms(iDelayms); + if(iChk>=0) { + giHomeLED_Delay_Ticks = msecs_to_jiffies(iChk); + szChk = strlen(buf); + } + else { + szChk = -1; + } + } + else if (36==gptHWCFG->m_val.bPCB || 2==gptHWCFG->m_val.bHOME_LED_PWM) + { + // HOME LED is controlled by SOC . + giHomeLED_Delay_Ticks = msecs_to_jiffies(iDelayms); + szChk = strlen(buf); + } + return szChk; +} +static DEVICE_ATTR(homeled_delayms,0666, + homeled_delayms_show, + homeled_delayms_store); + +static ssize_t homeled_delaylevel_show(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + ssize_t szChk=0; + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + if(MSP430_HOMELED_TYPE_PWM==msp430_homeled_type_get(0)) { + sprintf(buf,"%d\n",msp430_get_homeled_pwm_delaylevel()); + } + else { + sprintf(buf,"%d\n",msp430_get_homeled_gpio_delaylevel()); + } + szChk = strlen(buf); + } + else { + } + return szChk; +} +static ssize_t homeled_delaylevel_store(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + int iDelayLevel; + + iDelayLevel = simple_strtol(buf,NULL,0); + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + if(MSP430_HOMELED_TYPE_PWM==msp430_homeled_type_get(0)) { + msp430_set_homeled_pwm_delaylevel(iDelayLevel); + } + else { + msp430_set_homeled_gpio_delaylevel(iDelayLevel); + } + return strlen(buf); + } + else { + return (ssize_t)(-1); + } +} +static DEVICE_ATTR(homeled_delaylevel,0666, + homeled_delaylevel_show, + homeled_delaylevel_store); + + +static ssize_t homeled_type_show(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + char *pszHomeLedType; + + msp430_homeled_type_get(&pszHomeLedType); + sprintf(buf,"%s\n",pszHomeLedType); + + return strlen(buf); + } + else { + return 0; + } +} + +static ssize_t homeled_type_store(struct device *dev, + struct device_attribute *attr,const char *buf,size_t count) +{ + ssize_t szChk = -1; + + if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED is controlled by MSP430 . + if( msp430_homeled_type_set_by_name(buf) >=0 ) { + szChk = strlen(buf); + } + } + else { + printk(KERN_WARNING"Home led control type cannot changed on this hardware \n"); + } + + return szChk; +} + +static DEVICE_ATTR(homeled_type,0666, + homeled_type_show, + homeled_type_store); + + +static const struct attribute *sysfs_homepad_attrs[] = { + &dev_attr_homepad_enable.attr, + NULL +}; +static const struct attribute *sysfs_homeled_msp430_attrs[] = { + &dev_attr_homeled_type.attr, + &dev_attr_homeled_delayms.attr, + &dev_attr_homeled_delaylevel.attr, + NULL +}; +static const struct attribute *sysfs_homeled_socgpio_attrs[] = { + &dev_attr_homeled_delayms.attr, + NULL +}; + + + +static void _homeled_onoff(int iIsON) +{ + if(2==gptHWCFG->m_val.bUIStyle) { + if(gSleep_Mode_Suspend) { + // skip home led control when system want to enter fake hibernation . + _homeled_onoff_force(0); + return ; + } + } + _homeled_onoff_force(iIsON); +} + +static void _homepad_work_func(struct work_struct *work) +{ + int iIsHomePressing,iHomeGPIOVal; + + iHomeGPIOVal=gpio_get_value(gptGPIO_HOME_KEY->gpio); + iIsHomePressing = (iHomeGPIOVal?1:0)^gptGPIO_HOME_KEY->active_low; + //printk("%s(),\"%s\" gpio=%d,down=%d\n",__FUNCTION__, + // gptGPIO_HOME_KEY->desc,iHomeGPIOVal,iIsHomePressing); + if(iIsHomePressing) { + msp430_homepad_enable(2); + } +} +static void _homeled_work_func(struct work_struct *work) +{ + + _homeled_onoff(0); + +} + +static int ntx_touch_home_key_hook(struct gpio_keys_button *I_gpio_btn_data,int state) +{ + int iRet = 0; + //printk("%s(%p,%d)\n",__FUNCTION__,I_gpio_btn_data,state); + /*if(0x03==gptHWCFG->m_val.bUIConfig) { + // RD/MP mode . + if(!state) { + printk("%s():current home led=%d\n",__FUNCTION__,giCurHomeLED_state); + _homeled_onoff(!giCurHomeLED_state); + } + } + else*/ + { + if(state) { + + if( 36==gptHWCFG->m_val.bPCB || 2==gptHWCFG->m_val.bHOME_LED_PWM ) { + // E60Q3X or HOME LED is GPIO controlled by SOC . + cancel_delayed_work_sync(&homeled_pwrdwn_work); + cancel_delayed_work_sync(&homepad_check_work); + schedule_delayed_work(&homepad_check_work, giHomeLED_Delay_Ticks+400); + _homeled_onoff(1); + } + } + else { + + if( 36==gptHWCFG->m_val.bPCB || 2==gptHWCFG->m_val.bHOME_LED_PWM ) { + // E60Q3X or HOME LED is GPIO controlled by SOC . + cancel_delayed_work_sync(&homeled_pwrdwn_work); + schedule_delayed_work(&homeled_pwrdwn_work, giHomeLED_Delay_Ticks); + } + } + + if(giHomePad_enable<=1) { + iRet = -1; + } + } + return iRet; +} + +void homeled_onoff(int iIsON) { + _homeled_onoff_force(iIsON); +} + +int ntx_get_homepad_enabled_status(void) +{ + return giHomePad_enable; +} + +int ntx_get_homeled_delay_ms(void) +{ + return jiffies_to_msecs(giHomeLED_Delay_Ticks); +} + +void ntx_create_homepad_sys_attrs(struct kobject *kobj) +{ + int iChk; + if(36==gptHWCFG->m_val.bPCB || 40==gptHWCFG->m_val.bPCB || 0!=gptHWCFG->m_val.bHOME_LED_PWM) { + iChk = sysfs_create_files(kobj,sysfs_homepad_attrs); + if(iChk) { + pr_err("Can't create homepad attr sysfs !\n"); + } + if(36==gptHWCFG->m_val.bPCB||2==gptHWCFG->m_val.bHOME_LED_PWM) { + // E60Q3X or HOME LED PWM controlled by SOC . + iChk = sysfs_create_files(kobj,sysfs_homeled_socgpio_attrs); + if(iChk) { + pr_err("Can't create homepad soc gpio attr sysfs !\n"); + } + } + else if(1==gptHWCFG->m_val.bHOME_LED_PWM) { + // HOME LED PWM is controlled by MSP430 . + iChk = sysfs_create_files(kobj,sysfs_homeled_msp430_attrs); + if(iChk) { + pr_err("Can't create homepad msp430 pwm attr sysfs !\n"); + } + } + } +} +#else //][!TOUCH_HOME_LED +static void _homeled_onoff(int iIsON) {} +void homeled_onoff(int iIsON) {} +#endif //]TOUCH_HOME_LED + +#endif + + + +void *g_wifi_sd_host; +irq_handler_t g_cd_irq; + +void ntx_register_wifi_cd (irq_handler_t handler, void *data) +{ + printk ("[%s-%d] register g_cd_irq \n",__func__,__LINE__); + g_wifi_sd_host = data; + g_cd_irq = handler; +} + + +static DEFINE_MUTEX(ntx_wifi_power_mutex); +static int gi_wifi_power_status = -1; + +int _ntx_get_wifi_power_status(void) +{ + int iWifiPowerStatus; + + mutex_lock(&ntx_wifi_power_mutex); + iWifiPowerStatus = gi_wifi_power_status; + mutex_unlock(&ntx_wifi_power_mutex); + + return iWifiPowerStatus; +} + +int _ntx_wifi_power_ctrl (int isWifiEnable) +{ + int iHWID; + int iOldStatus; + + mutex_lock(&ntx_wifi_power_mutex); + iOldStatus = gi_wifi_power_status; + printk("Wifi / BT power control %d\n", isWifiEnable); + if(isWifiEnable == 0){ + gpio_direction_output (gMX6SL_WIFI_RST, 0); + gpio_direction_input (gMX6SL_WIFI_3V3); // turn off Wifi_3V3_on + + msleep(10); +// DO NOT switch pin functions to GPIO +/* + // sdio port disable ... + if(33==gptHWCFG->m_val.bPCB) { + //E60Q2X . + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_sd3_gpio_pads, ARRAY_SIZE(mx6sl_ntx_sd3_gpio_pads)); + gpio_request (MX6SL_SD3_CLK , "MX6SL_SD3_CLK" ); + gpio_request (MX6SL_SD3_CMD , "MX6SL_SD3_CMD" ); + gpio_request (MX6SL_SD3_DAT0, "MX6SL_SD3_DAT0"); + gpio_request (MX6SL_SD3_DAT1, "MX6SL_SD3_DAT1"); + gpio_request (MX6SL_SD3_DAT2, "MX6SL_SD3_DAT2"); + gpio_request (MX6SL_SD3_DAT3, "MX6SL_SD3_DAT3"); + gpio_direction_output (MX6SL_SD3_CLK , 0); + gpio_direction_output (MX6SL_SD3_CMD , 0); + gpio_direction_output (MX6SL_SD3_DAT0, 0); + gpio_direction_output (MX6SL_SD3_DAT1, 0); + gpio_direction_output (MX6SL_SD3_DAT2, 0); + gpio_direction_output (MX6SL_SD3_DAT3, 0); + } + else { + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_sd2_gpio_pads, ARRAY_SIZE(mx6sl_ntx_sd2_gpio_pads)); + gpio_request (MX6SL_SD2_CLK , "MX6SL_SD2_CLK" ); + gpio_request (MX6SL_SD2_CMD , "MX6SL_SD2_CMD" ); + gpio_request (MX6SL_SD2_DAT0, "MX6SL_SD2_DAT0"); + gpio_request (MX6SL_SD2_DAT1, "MX6SL_SD2_DAT1"); + gpio_request (MX6SL_SD2_DAT2, "MX6SL_SD2_DAT2"); + gpio_request (MX6SL_SD2_DAT3, "MX6SL_SD2_DAT3"); + gpio_direction_input (MX6SL_SD2_CLK ); + gpio_direction_input (MX6SL_SD2_CMD ); + gpio_direction_input (MX6SL_SD2_DAT0); + gpio_direction_input (MX6SL_SD2_DAT1); + gpio_direction_input (MX6SL_SD2_DAT2); + gpio_direction_input (MX6SL_SD2_DAT3); + } +*/ + +#ifdef _WIFI_ALWAYS_ON_ + disable_irq_wake(gpio_to_irq(gMX6SL_WIFI_INT)); +#endif + gi_wifi_power_status=0; + } + else { + + + // sdio port process ... + if(31==gptHWCFG->m_val.bPCB||32==gptHWCFG->m_val.bPCB) { + // E60Q0X/E60Q1X + gpio_free (MX6SL_SD2_CLK ); + gpio_free (MX6SL_SD2_CMD ); + gpio_free (MX6SL_SD2_DAT0); + gpio_free (MX6SL_SD2_DAT1); + gpio_free (MX6SL_SD2_DAT2); + gpio_free (MX6SL_SD2_DAT3); + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_sd2_wifi_pads, ARRAY_SIZE(mx6sl_ntx_sd2_wifi_pads)); + } + else { + gpio_free (MX6SL_SD3_CLK ); + gpio_free (MX6SL_SD3_CMD ); + gpio_free (MX6SL_SD3_DAT0); + gpio_free (MX6SL_SD3_DAT1); + gpio_free (MX6SL_SD3_DAT2); + gpio_free (MX6SL_SD3_DAT3); + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_sd3_wifi_pads, ARRAY_SIZE(mx6sl_ntx_sd3_wifi_pads)); + } + //msleep(10); + + gpio_direction_output (gMX6SL_WIFI_3V3, 0); // turn on Wifi_3V3_on + //schedule_timeout(HZ/50); + msleep(10); + + gpio_direction_input (gMX6SL_WIFI_INT); + //msleep(10); + gpio_direction_output (gMX6SL_WIFI_RST, 1); // turn on wifi_RST + //schedule_timeout(HZ/10); + msleep(30); +#ifdef _WIFI_ALWAYS_ON_ + enable_irq_wake(gpio_to_irq(gMX6SL_WIFI_INT)); +#endif + gi_wifi_power_status=1; + } + + if (g_cd_irq) { + struct sdhci_host *host; + + host = (struct sdhci_host *) g_wifi_sd_host; + //g_cd_irq (0, g_wifi_sd_host); + //schedule_timeout (100); + //msleep(1000); + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + //msleep(600); + schedule_timeout(500); + } + else { + printk ("[%s-%d] not registered.\n",__func__,__LINE__); + } + + if(isWifiEnable == 0){ // switch PIN function to GPIO + // sdio port disable ... + if(31==gptHWCFG->m_val.bPCB||32==gptHWCFG->m_val.bPCB) { + // E60Q0X/E60Q1X. + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_sd2_gpio_pads, ARRAY_SIZE(mx6sl_ntx_sd2_gpio_pads)); + gpio_request (MX6SL_SD2_CLK , "MX6SL_SD2_CLK" ); + gpio_request (MX6SL_SD2_CMD , "MX6SL_SD2_CMD" ); + gpio_request (MX6SL_SD2_DAT0, "MX6SL_SD2_DAT0"); + gpio_request (MX6SL_SD2_DAT1, "MX6SL_SD2_DAT1"); + gpio_request (MX6SL_SD2_DAT2, "MX6SL_SD2_DAT2"); + gpio_request (MX6SL_SD2_DAT3, "MX6SL_SD2_DAT3"); + gpio_direction_input (MX6SL_SD2_CLK ); + gpio_direction_input (MX6SL_SD2_CMD ); + gpio_direction_input (MX6SL_SD2_DAT0); + gpio_direction_input (MX6SL_SD2_DAT1); + gpio_direction_input (MX6SL_SD2_DAT2); + gpio_direction_input (MX6SL_SD2_DAT3); + } + else { + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_sd3_gpio_pads, ARRAY_SIZE(mx6sl_ntx_sd3_gpio_pads)); + gpio_request (MX6SL_SD3_CLK , "MX6SL_SD3_CLK" ); + gpio_request (MX6SL_SD3_CMD , "MX6SL_SD3_CMD" ); + gpio_request (MX6SL_SD3_DAT0, "MX6SL_SD3_DAT0"); + gpio_request (MX6SL_SD3_DAT1, "MX6SL_SD3_DAT1"); + gpio_request (MX6SL_SD3_DAT2, "MX6SL_SD3_DAT2"); + gpio_request (MX6SL_SD3_DAT3, "MX6SL_SD3_DAT3"); + gpio_direction_output (MX6SL_SD3_CLK , 0); + gpio_direction_output (MX6SL_SD3_CMD , 0); + gpio_direction_output (MX6SL_SD3_DAT0, 0); + gpio_direction_output (MX6SL_SD3_DAT1, 0); + gpio_direction_output (MX6SL_SD3_DAT2, 0); + gpio_direction_output (MX6SL_SD3_DAT3, 0); + } + } + printk("%s() end.\n",__FUNCTION__); + mutex_unlock(&ntx_wifi_power_mutex); + return iOldStatus; +} + +void ntx_wifi_power_ctrl(int iIsWifiEnable) +{ + _ntx_wifi_power_ctrl(iIsWifiEnable); +} + +EXPORT_SYMBOL(ntx_wifi_power_ctrl); + +static iomux_v3_cfg_t mx6sl_ntx_suspend_pads[] = { + MX6SL_PAD_I2C2_SCL__GPIO_3_14, + MX6SL_PAD_I2C2_SDA__GPIO_3_15, +}; + +static iomux_v3_cfg_t mx6sl_ntx_resume_pads[] = { + MX6SL_PAD_I2C2_SCL__I2C2_SCL, + MX6SL_PAD_I2C2_SDA__I2C2_SDA, +}; + +extern void ntx_gpio_suspend (void); +extern void ntx_gpio_resume (void); + +static void ntx_suspend_enter(void) +{ +// mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_suspend_pads, ARRAY_SIZE(mx6sl_ntx_suspend_pads)); +// gpio_request(MX6SL_I2C2_SCL, "MX6SL_I2C2_SCL"); +// gpio_request(MX6SL_I2C2_SDA, "MX6SL_I2C2_SDA"); +// gpio_direction_output (MX6SL_I2C2_SCL, 0); +// gpio_direction_output (MX6SL_I2C2_SDA, 0); + +#if 0 + gpio_direction_output (MX6SL_EP_PWRALL, 1); + gpio_direction_output (MX6SL_EP_WAKEUP, 0); + gpio_direction_output (MX6SL_EP_PWRUP, 0); + gpio_direction_output (MX6SL_EP_VCOM, 0); + gpio_direction_input (MX6SL_EP_INT); + gpio_direction_input (MX6SL_EP_PWRSTAT); +#endif + + _homeled_onoff_force(0); + + ntx_gpio_suspend (); + +#if 0 + { + unsigned int *pIomux = IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR)+0x4C; + unsigned int value; + + printk ("Addr , value\n"); + while (IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR)+0x5A8 >= pIomux) { + value = *pIomux; + printk ("0x%08X, 0x%08X, %s%s%s\n",pIomux, value,((value&0x2000)?"PUE - ":""),\ + ((value&0x2000)?((value&0xC000)?"Pull Up - ":"Pull Down - "):""),((value&0x1000)?"PKE":"")); + ++pIomux; + } + } +#endif +#if 0 +{ + void __iomem *base = IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR); + unsigned int offset = 0x4C; + unsigned int addr = 0x20E0000; + unsigned int value; + + for(offset=0x4C; offset <=0x884; offset+=4) { + value = __raw_readl( base + offset); + printk(KERN_DEBUG "addr %08x = %08x\n", addr+offset, value); + } + + base = IO_ADDRESS(GPIO1_BASE_ADDR); + addr = 0x209C000; + for(offset=0; offset<=0x1C; offset+=4) { + value = __raw_readl( base + offset); + printk(KERN_DEBUG "addr %08x = %08x\n", addr+offset, value); + } + + base = IO_ADDRESS(GPIO2_BASE_ADDR); + addr = 0x20A0000; + for(offset=0; offset<=0x1C; offset+=4) { + value = __raw_readl( base + offset); + printk(KERN_DEBUG "addr %08x = %08x\n", addr+offset, value); + } + + base = IO_ADDRESS(GPIO3_BASE_ADDR); + addr = 0x20A4000; + for(offset=0; offset<=0x1C; offset+=4) { + value = __raw_readl( base + offset); + printk(KERN_DEBUG "addr %08x = %08x\n", addr+offset, value); + } + + base = IO_ADDRESS(GPIO4_BASE_ADDR); + addr = 0x20A8000; + for(offset=0; offset<=0x1C; offset+=4) { + value = __raw_readl( base + offset); + printk(KERN_DEBUG "addr %08x = %08x\n", addr+offset, value); + } + + base = IO_ADDRESS(GPIO5_BASE_ADDR); + addr = 0x20AC000; + for(offset=0; offset<=0x1C; offset+=4) { + value = __raw_readl( base + offset); + printk(KERN_DEBUG "addr %08x = %08x\n", addr+offset, value); + } +} +#endif +} + +static void ntx_suspend_exit(void) +{ +#if 0 + gpio_direction_output (MX6SL_EP_WAKEUP, 1); +#endif + +// gpio_free(MX6SL_I2C2_SCL); +// gpio_free(MX6SL_I2C2_SDA); +// mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_resume_pads, ARRAY_SIZE(mx6sl_ntx_resume_pads)); + ntx_gpio_resume (); + +} + +static const struct pm_platform_data mx6sl_ntx_pm_data __initconst = { + .name = "imx_pm", + .suspend_enter = ntx_suspend_enter, + .suspend_exit = ntx_suspend_exit, +}; + +void ntx_wacom_reset(bool on) { + gpio_direction_output (MX6SL_WACOM_RST, on); +} +static void ntx_gpio_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_pads, + ARRAY_SIZE(mx6sl_brd_ntx_pads)); + + + + if(31==gptHWCFG->m_val.bPCB||32==gptHWCFG->m_val.bPCB) { + // E60Q0X|E60Q1X. + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_sd4_gpio_pads, + ARRAY_SIZE(mx6sl_brd_ntx_sd4_gpio_pads)); + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_sd1_pads, + ARRAY_SIZE(mx6sl_brd_ntx_sd1_pads)); +#if 1 + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_q12_wifictrl_pads, + ARRAY_SIZE(mx6sl_ntx_q12_wifictrl_pads)); +#endif + giISD_3V3_ON_Ctrl=-1; + } + else { + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_sd4_pads, + ARRAY_SIZE(mx6sl_brd_ntx_sd4_pads)); + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_sd1_gpio_pads, + ARRAY_SIZE(mx6sl_brd_ntx_sd1_gpio_pads)); + +#if 1 + mxc_iomux_v3_setup_multiple_pads(mx6sl_ntx_q22_wifictrl_pads, + ARRAY_SIZE(mx6sl_ntx_q22_wifictrl_pads)); +#endif + if(1==gptHWCFG->m_val.bLed) { + // RGB/G type LED . + // ON_LED# + mxc_iomux_v3_setup_pad(MX6SL_PAD_SD1_DAT2__GPIO_5_13_PULLHIGH); + } + + gMX6SL_NTX_ACIN_PG = IMX_GPIO_NR(5, 14); + gMX6SL_NTX_CHG = IMX_GPIO_NR(5, 15); + gMX6SL_MSP_INT = IMX_GPIO_NR(5, 11); + gMX6SL_PWR_SW = IMX_GPIO_NR(5, 8); + gMX6SL_IR_TOUCH_INT = IMX_GPIO_NR(5, 6); + gMX6SL_IR_TOUCH_RST = IMX_GPIO_NR(5, 9); + if(49==gptHWCFG->m_val.bPCB) { + // E60QDX + gMX6SL_IR_TOUCH_RST = IMX_GPIO_NR(5, 13); + } + + gMX6SL_HALL_EN = IMX_GPIO_NR(5, 12); + + // LED assign ... + gMX6SL_CHG_LED = IMX_GPIO_NR(5, 10); + if(37==gptHWCFG->m_val.bPCB) { + // E60QB0 . + gMX6SL_ACT_LED = IMX_GPIO_NR(5, 13); + gMX6SL_ON_LED = IMX_GPIO_NR(5, 7); + } + else if(46==gptHWCFG->m_val.bPCB||48==gptHWCFG->m_val.bPCB) { + // E60Q9X/E60QAX . + + // ON_LED# pull high . + mxc_iomux_v3_setup_pad(MX6SL_PAD_SD1_DAT2__GPIO_5_13_PULLHIGH); + + gMX6SL_ACT_LED = IMX_GPIO_NR(5, 7); + gMX6SL_ON_LED = IMX_GPIO_NR(5, 13); + } + else if(42==gptHWCFG->m_val.bPCB){ + // E60Q6X + gMX6SL_ACT_LED = IMX_GPIO_NR(5, 13); + gMX6SL_ON_LED = IMX_GPIO_NR(5, 13); + } + else { + gMX6SL_ACT_LED = IMX_GPIO_NR(5, 7); + gMX6SL_ON_LED = IMX_GPIO_NR(5, 7); + } + + gMX6SL_WIFI_3V3 = IMX_GPIO_NR(4, 29); + gMX6SL_WIFI_RST = IMX_GPIO_NR(5, 0); + gMX6SL_WIFI_INT = IMX_GPIO_NR(4, 31); + + if(37==gptHWCFG->m_val.bPCB) { + // E60QBX. + gpio_request (GPIO_ESD_3V3_ON, "ESD_3V3_ON"); + gpio_direction_input (GPIO_ESD_3V3_ON); + gpio_free (GPIO_ESD_3V3_ON); + giISD_3V3_ON_Ctrl = -1; + } + else { + if(36==gptHWCFG->m_val.bPCB || 40==gptHWCFG->m_val.bPCB) { + // E60Q3X/E60Q5X + gMX6SL_CHG_LED = IMX_GPIO_NR(5, 7); + gMX6SL_IR_TOUCH_RST = IMX_GPIO_NR(5, 13); + gpio_request (MX6SL_KL25_INT2, "MX6SL_KL25_INT2"); + gpio_direction_input (MX6SL_KL25_INT2); + } + else { + if(0==gptHWCFG->m_val.bPMIC) { + //若有RICOH PMIC則ESD_3V3_ON都會交由PMIC控制. + gpio_request (GPIO_ESD_3V3_ON, "ESD_3V3_ON"); + gpio_direction_output (GPIO_ESD_3V3_ON, 1); + } + } + + if(0==gptHWCFG->m_val.bPMIC) { + gpio_request (GPIO_ISD_3V3_ON, "ISD_3V3_ON"); + if(33==gptHWCFG->m_val.bPCB) { + // E60Q2X . + giISD_3V3_ON_Ctrl = 0; + } + else { + giISD_3V3_ON_Ctrl = 1; + } + } + } + + + gpio_request (GPIO_IR_3V3_ON, "IR_3V3_ON"); + gpio_direction_output (GPIO_IR_3V3_ON, 1); + //gpio_request (GPIO_EP_3V3_ON, "EP_3V3_ON"); + //gpio_direction_output (GPIO_EP_3V3_ON, 1); + + if(2==gptHWCFG->m_val.bTouch2Ctrl) { + // Wacom Digitizer + gpio_request (MX6SL_WACOM_PDCT, "MX6SL_WACOM_PDCT"); + gpio_direction_input (MX6SL_WACOM_PDCT); + gpio_request (MX6SL_WACOM_FWE, "MX6SL_WACOM_FWE"); + gpio_direction_output (MX6SL_WACOM_FWE, 0); + gpio_request (MX6SL_WACOM_RST, "MX6SL_WACOM_RST"); + ntx_wacom_reset(0); + + if(42==gptHWCFG->m_val.bPCB) { + // Wacom GPIOs + gpio_request (MX6SL_WACOM_INT, "MX6SL_WACOM_INT"); + gpio_direction_input (MX6SL_WACOM_INT); + i2c_register_board_info(1,&i2c_wacom_binfo,1); + } + else { + gpio_request (MX6SL_WACOM_INT_4_1, "MX6SL_WACOM_INT"); + gpio_direction_input (MX6SL_WACOM_INT_4_1); + i2c_register_board_info(0,&i2c_wacom_binfo,1); + } + } + else if(3==gptHWCFG->m_val.bTouch2Ctrl) { + if(42==gptHWCFG->m_val.bPCB) { + gpio_request (MX6SL_WALTOP_INT_4_0, "MX6SL_WALTOP_INT_4_0"); + gpio_direction_input (MX6SL_WALTOP_INT_4_0); + gpio_request (MX6SL_WALTOP_RST_3_30, "MX6SL_WALTOP_RST_3_30"); + gpio_direction_output (MX6SL_WALTOP_RST_3_30, 1); + + i2c_waltop_binfo.platform_data = MX6SL_WALTOP_RST_3_30; + i2c_waltop_binfo.irq = gpio_to_irq(MX6SL_WALTOP_INT_4_0); + i2c_register_board_info(1,&i2c_waltop_binfo,1); + } else { + gpio_request (MX6SL_WALTOP_INT, "MX6SL_WALTOP_INT"); + gpio_direction_input (MX6SL_WALTOP_INT); + gpio_request (MX6SL_WALTOP_RST, "MX6SL_WALTOP_RST"); + gpio_direction_output (MX6SL_WALTOP_RST, 1); + i2c_register_board_info(0,&i2c_waltop_binfo,1); + } + } + } + + if(-1!=giISD_3V3_ON_Ctrl) { + gpio_direction_output (GPIO_ISD_3V3_ON, giISD_3V3_ON_Ctrl?1:0); + } + + i2c_zforce_ir_touch_binfo.platform_data = gMX6SL_IR_TOUCH_INT; + i2c_zforce_ir_touch_binfo.irq = gpio_to_irq(gMX6SL_IR_TOUCH_INT); + + i2c_elan_touch_binfo.platform_data = gMX6SL_IR_TOUCH_INT; + i2c_elan_touch_binfo.irq = gpio_to_irq(gMX6SL_IR_TOUCH_INT); + if(47==gptHWCFG->m_val.bPCB) { //ED0Q02 + i2c_elan_touch_binfo.addr = 0x10; + } + + i2c_sysmp_msp430_binfo.irq = gpio_to_irq(gMX6SL_MSP_INT); + i2c_sysmp_ricoh619_binfo.irq = gpio_to_irq(gMX6SL_MSP_INT); + + ntx_misc_info.acin_gpio = gMX6SL_NTX_ACIN_PG; + ntx_misc_info.chg_gpio = gMX6SL_NTX_CHG; + + if(37!=gptHWCFG->m_val.bPCB) { + gpio_request (MX6SL_HW_ID0, "MX6SL_HW_ID0"); + gpio_request (MX6SL_HW_ID1, "MX6SL_HW_ID1"); + gpio_request (MX6SL_HW_ID2, "MX6SL_HW_ID2"); + gpio_request (MX6SL_HW_ID3, "MX6SL_HW_ID3"); + gpio_request (MX6SL_HW_ID4, "MX6SL_HW_ID4"); + gpio_direction_input (MX6SL_HW_ID0); + gpio_direction_input (MX6SL_HW_ID1); + gpio_direction_input (MX6SL_HW_ID2); + gpio_direction_input (MX6SL_HW_ID3); + gpio_direction_input (MX6SL_HW_ID4); + } + + gpio_request (gMX6SL_ON_LED, "MX6SL_ON_LED"); + gpio_request (gMX6SL_ACT_LED, "MX6SL_ACT_LED"); + gpio_direction_input (gMX6SL_ACT_LED); + gpio_direction_output (gMX6SL_ON_LED, 0); + + if(36==gptHWCFG->m_val.bPCB || 40==gptHWCFG->m_val.bPCB) { + // E60Q3X/E60Q5X + gpio_request (gMX6SL_HOME_LED, "MX6SL_HOME_LED"); + } + else { + gpio_request (gMX6SL_CHG_LED, "MX6SL_CHG_LED"); + gpio_direction_input (gMX6SL_CHG_LED); + } + + gpio_request (gMX6SL_NTX_ACIN_PG, "MX6SL_NTX_ACIN_PG"); + gpio_direction_input (gMX6SL_NTX_ACIN_PG); + + gpio_request (gMX6SL_NTX_CHG, "MX6SL_NTX_CHG"); + gpio_direction_input (gMX6SL_NTX_CHG); + + gpio_request (gMX6SL_MSP_INT, "MX6SL_MSP_INT"); + gpio_direction_input (gMX6SL_MSP_INT); + //#ifndef CONFIG_ANDROID //[ + if(0==gptHWCFG->m_val.bUIStyle) { + gpio_request (gMX6SL_PWR_SW, "MX6SL_PWR_SW"); + gpio_direction_input (gMX6SL_PWR_SW); + } + //#endif //]CONFIG_ANDROID + + gpio_request (gMX6SL_IR_TOUCH_INT, "MX6SL_IR_TOUCH_INT"); + gpio_direction_input (gMX6SL_IR_TOUCH_INT); + + gpio_request (gMX6SL_IR_TOUCH_RST, "MX6SL_IR_TOUCH_RST"); + gpio_direction_output (gMX6SL_IR_TOUCH_RST, 0); + mdelay (10); + gpio_direction_input (gMX6SL_IR_TOUCH_RST); + if(0==gptHWCFG->m_val.bHallSensor) { + gpio_request (gMX6SL_HALL_EN, "MX6SL_HALL_EN"); + gpio_direction_input (gMX6SL_HALL_EN); + } + + gpio_request (gMX6SL_WIFI_RST, "MX6SL_WIFI_RST"); + gpio_request (gMX6SL_WIFI_3V3, "MX6SL_WIFI_3V3"); + gpio_request (gMX6SL_WIFI_INT, "MX6SL_WIFI_INT"); + gpio_direction_input (gMX6SL_WIFI_INT); + ntx_wifi_power_ctrl (0); + + gpio_request (MX6SL_FL_EN, "MX6SL_FL_EN"); + gpio_direction_input (MX6SL_FL_EN); + gpio_request (MX6SL_FL_R_EN, "MX6SL_FL_R_EN"); + gpio_direction_input (MX6SL_FL_R_EN); + +#if 0 //[ + gpio_request (MX6SL_EP_PWRALL, "MX6SL_EP_PWRALL" ); + gpio_request (MX6SL_EP_WAKEUP , "MX6SL_EP_WAKEUP" ); + gpio_request (MX6SL_EP_PWRUP , "MX6SL_EP_PWRUP" ); + gpio_request (MX6SL_EP_INT , "MX6SL_EP_INT" ); + gpio_request (MX6SL_EP_PWRSTAT , "MX6SL_EP_PWRSTAT" ); + gpio_request (MX6SL_EP_VCOM , "MX6SL_EP_VCOM" ); + gpio_direction_output (MX6SL_EP_PWRALL, 1); + gpio_direction_output (MX6SL_EP_WAKEUP, 0); + gpio_direction_output (MX6SL_EP_PWRUP, 0); + gpio_direction_output (MX6SL_EP_VCOM, 0); + gpio_direction_input (MX6SL_EP_INT); + gpio_direction_input (MX6SL_EP_PWRSTAT); +#endif //] + +} + +/*! + * Board specific initialization. + */ +static void __init mx6_ntx_init(void) +{ + u32 i; + int iMSP430_I2C_Chn; + struct esdhc_platform_data *pt_esdhc_ntx_isd_data; + + _parse_cmdline(); + + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_pads, + ARRAY_SIZE(mx6sl_brd_pads)); + + ntx_gpio_init (); + + gpiofn_init(); + +#ifdef CONFIG_MX6_INTER_LDO_BYPASS + gp_reg_id = mx6sl_ntx_dvfscore_data.reg_id; + soc_reg_id = mx6sl_ntx_dvfscore_data.soc_id; +#else + gp_reg_id = mx6sl_ntx_dvfscore_data.reg_id; + soc_reg_id = mx6sl_ntx_dvfscore_data.soc_id; + pu_reg_id = mx6sl_ntx_dvfscore_data.pu_id; + mx6_cpu_regulator_init(); +#endif + + if( (46==gptHWCFG->m_val.bPCB && gptHWCFG->m_val.bPCB_REV>=0x10) || + 48==gptHWCFG->m_val.bPCB) + { + // E60Q9X rev >=A10 ... + // E60QAX ... + // MSP430 @ I2C1 + iMSP430_I2C_Chn = 0;//I2C1 + } + else { + iMSP430_I2C_Chn = 2;//I2C3 in curcuit . + if(0==gptHWCFG->m_val.bPMIC) { + // 當MSP430å–代為PMIC工作時,它éžå¸¸å¿™éŒ„ï¼Œé«˜é€Ÿçš„é »çŽ‡æœ‰å¯èƒ½æœƒä½¿å®ƒå‡ºéŒ¯ã€‚ + mx6_ntx_i2c2_data.bitrate = 100000; + } + } +// imx6q_add_imx_snvs_rtc(); + + + imx6q_add_imx_i2c(0, &mx6_ntx_i2c0_data); + imx6q_add_imx_i2c(1, &mx6_ntx_i2c1_data); + imx6q_add_imx_i2c(2, &mx6_ntx_i2c2_data); + + if (4==gptHWCFG->m_val.bTouchType) { + // IR touch type + if ( 31==gptHWCFG->m_val.bPCB||32==gptHWCFG->m_val.bPCB|| + 33==gptHWCFG->m_val.bPCB||36==gptHWCFG->m_val.bPCB|| + 40==gptHWCFG->m_val.bPCB|| + (46==gptHWCFG->m_val.bPCB&&gptHWCFG->m_val.bPCB_REV<0x10) ) + { + // E60Q2X/E60Q3X/E60Q1X/E60Q2X/E60Q5X/<E60Q9XA10 + i2c_register_board_info(0,&i2c_zforce_ir_touch_binfo,1); + } + else { + // + i2c_register_board_info(1,&i2c_zforce_ir_touch_binfo,1); + } + } + else if (3==gptHWCFG->m_val.bTouchType) { + // C touch type . + i2c_register_board_info(0,&i2c_elan_touch_binfo,1); + } + else { + printk("TouchType %d do not support yet ! no touch driver will be loaded \n",(int) gptHWCFG->m_val.bTouchType); + } + + if(1==gptHWCFG->m_val.bPMIC){ + // RC5T619 . + if(!NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bPCB_Flags,4)) { + // Panel is designed for low voltage . + printk("ldo8_1v8 ouput 3v3\n"); + pdata_ldo8_0.regulator.constraints.min_uV = 3300*1000; + pdata_ldo8_0.regulator.constraints.max_uV = 3300*1000; + //pdata_ldo8_0.regulator.constraints.always_on = 1; + //pdata_ldo8_0.regulator.constraints.boot_on = 1; + pdata_ldo8_0.init_uV = 3300*1000; + //pdata_ldo8_0.init_enable = 1; + pdata_ldo8_0.sleep_uV = 3300*1000; + } + + // PCB is designed for low voltage . + ntx_ricoh_data.irq_base = irq_alloc_descs (-1, 0, RICOH61x_NR_IRQS, "RICOH61x"); + if (0 < ntx_ricoh_data.irq_base) { + ricoh_battery_data.irq = ntx_ricoh_data.irq_base; + ricoh_rtc_data.irq = ntx_ricoh_data.irq_base; + printk ("[%s-%d] irq_alloc_descs return %d for %d RICOH61x\n",__func__, __LINE__, ntx_ricoh_data.irq_base, RICOH61x_NR_IRQS); + } + else { + printk ("[%s-%d] RICOH61x irq_alloc_descs failed with %d\n",__func__, __LINE__, ntx_ricoh_data.irq_base, RICOH61x_NR_IRQS); + } + i2c_register_board_info(2,&i2c_sysmp_ricoh619_binfo,1); + // platform_device_register(&ricoh_device_rtc); + pm_power_off = ricoh619_power_off; + } + + + if(38!=gptHWCFG->m_val.bPCB&&37!=gptHWCFG->m_val.bPCB) + { + i2c_register_board_info(iMSP430_I2C_Chn,&i2c_sysmp_msp430_binfo,1); + } + + if(0==gptHWCFG->m_val.bRTC) { + // RTC use MSP430 + platform_device_register(&ntx_device_rtc); + } + + if(1==gptHWCFG->m_val.bFL_PWM){ + // Front light PWM source is ht68f20 + i2c_register_board_info(0,&i2c_ht68f20_binfo,1); + } + + if(3==gptHWCFG->m_val.bRSensor) { + // g-sensor with microP KL25 + i2c_register_board_info(0,&i2c_kl25_binfo,1); + } + + + if(4==gptHWCFG->m_val.bRSensor) { + // g-sensor : MMA8652 + //if(36!=gptHWCFG->m_val.bPCB) + { + /* 20140220 temporarily remove MMA8652 from E60Q32 to save power + since not currently used but installed (MMA8652 default mode: Standby) */ + i2c_register_board_info(0,&i2c_mma8652_binfo,1); + } + } + + //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)); + + /* only camera on I2C2, that's why we can do so */ +// if (csi_enabled == 1) { +// mxc_register_device(&csi_v4l2_devices, NULL); +// imx6q_add_imx_i2c(2, &mx6_ntx_i2c2_data); +// } +// imx6q_add_imx_snvs_rtc(); + + /* SPI */ +// imx6q_add_ecspi(0, &mx6_ntx_spi_data); +// spi_device_init(); + +// mx6sl_ntx_init_pfuze100(0); + imx6q_add_anatop_thermal_imx(1, &mx6sl_anatop_thermal_data); + imx6q_add_pm_imx(0, &mx6sl_ntx_pm_data); + + mx6_ntx_init_uart(); + /* get enet tx reference clk from FEC_REF_CLK pad. + * GPR1[14] = 0, GPR1[18:17] = 00 + */ +// mxc_iomux_set_gpr_register(1, 14, 1, 0); +// mxc_iomux_set_gpr_register(1, 17, 2, 0); + +// imx6_init_fec(fec_data); + + //platform_device_register(&ntx_vmmc_reg_devices); + + if(2==gptHWCFG->m_val.bIFlash) { + // eMMC . + pt_esdhc_ntx_isd_data = &mx6_ntx_isd8bits_data; + } + else { + pt_esdhc_ntx_isd_data = &mx6_ntx_isd_data; + } + + switch(gptHWCFG->m_val.bPCB) { + case 31: //E60Q0X . + case 32: //E60Q1X . + // SD1 = ISD + // SD2 = ESD + // SD3 = SDIO WIFI + // SD4 = GPIO + imx6q_add_sdhci_usdhc_imx(giBootPort, pt_esdhc_ntx_isd_data); + imx6q_add_sdhci_usdhc_imx(2, &mx6_ntx_esd_data); // mmcblk1 + imx6q_add_sdhci_usdhc_imx(1, &mx6_ntx_sd_wifi_data); + break; + + default: + // \C5\FD\B7s\AA\BA\B3]\ADp\BA\FB\AB\F9\A6b\B3o\ADӰ϶\F4\A1A\A5H\BAÉ¥i\AF\E0\B9F\A8줣\ADק\EFCODE\B4N\AF\E0\A5Ψ\EC\B7s\BE\F7\BAؤW\A1C + // SD1 = GPIO + // SD2 = ESD + // SD3 = SDIO WIFI + // SD4 = EMMC + if(1==giBootPort) { + // ESD is boot device . + printk("add usdhc %d as mmcblk0\n",giBootPort+1); + if(46==gptHWCFG->m_val.bPCB|| + 48==gptHWCFG->m_val.bPCB) + { + // + imx6q_add_sdhci_usdhc_imx(giBootPort, &mx6_ntx_esd_nocd_data); + } + else { + imx6q_add_sdhci_usdhc_imx(giBootPort, &mx6_ntx_esd_data); + } + printk("add usdhc 4 as mmcblk1\n"); + imx6q_add_sdhci_usdhc_imx(3, pt_esdhc_ntx_isd_data); // mmcblk1 + printk("add usdhc 3 as sdio for wifi\n"); + imx6q_add_sdhci_usdhc_imx(2, &mx6_ntx_q22_sd_wifi_data); + } + else { + // EMMC is boot device . + imx6q_add_sdhci_usdhc_imx(giBootPort, pt_esdhc_ntx_isd_data); + imx6q_add_sdhci_usdhc_imx(1, &mx6_ntx_esd_data); // mmcblk1 + imx6q_add_sdhci_usdhc_imx(2, &mx6_ntx_q22_sd_wifi_data); + } + break; + } + + mx6_ntx_init_usb(); + imx6q_add_otp(); +// imx6q_add_mxc_pwm(0); +// imx6q_add_mxc_pwm_backlight(0, &mx6_ntx_pwm_backlight_data); + + +// gpio_request(MX6_BRD_LCD_PWR_EN, "elcdif-power-on"); +// gpio_direction_output(MX6_BRD_LCD_PWR_EN, 1); + //mxc_register_device(&lcd_wvga_device, NULL); + + imx6dl_add_imx_pxp(); + imx6dl_add_imx_pxp_client(); + + imx6dl_add_imx_epdc(&epdc_data); +#ifdef CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF //[ + imx6dl_add_imx_elcdif(&wvga_fb_data[0]); +#endif //]CONFIG_IMX_HAVE_PLATFORM_IMX_ELCDIF + //imx6q_add_dvfs_core(&mx6sl_ntx_dvfscore_data); + + imx6q_add_viim(); + imx6q_add_imx2_wdt(0, NULL); + + +#ifdef CONFIG_MXC_GPU_VIV//[ + if(2==gptHWCFG->m_val.bUIStyle) + { + // only android models needs GPU . + imx_add_viv_gpu(&imx6_gpu_data, &imx6q_gpu_pdata); + } +#endif//] CONFIG_MXC_GPU_VIV + + //imx6sl_add_device_buttons(); + if(!NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bPCB_Flags,0)) { + // key matrix : ON + + //mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_kb_pads,ARRAY_SIZE(mx6sl_brd_ntx_kb_pads)); + //mdelay(1); + + imx6sl_add_imx_keypad(&mx6sl_ntx_map_data); + } + //else + { + // gpio keys + mxc_iomux_v3_setup_multiple_pads(mx6sl_brd_ntx_kb_gpio_pads, + ARRAY_SIZE(mx6sl_brd_ntx_kb_gpio_pads)); + udelay(1); + + switch(gptHWCFG->m_val.bPCB) { + case 32://E60Q1X + case 31://E60Q0X + // use gpio instead of keymatrix ... + gpio_request (GPIO_KB_COL0, "KB_COL0"); + gpio_direction_output (GPIO_KB_COL0, 0); + gpio_request (GPIO_KB_COL1, "KB_COL1"); + gpio_direction_output (GPIO_KB_COL1, 0); + + ntx_gpio_key_data.buttons = gpio_key_matrix_FL; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_matrix_FL); + break; + case 33://E60Q2X + ntx_gpio_key_data.buttons = gpio_key_HOME; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_HOME); + break; + /*case 36://E60Q3X + ntx_gpio_key_data.buttons = gpio_key_HOME_FL; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_HOME_FL); + break;*/ + default: + switch(gptHWCFG->m_val.bKeyPad) { //key pad define through bKeyPad in hwconfig + case 12: // NO_Key + ntx_gpio_key_data.buttons = gpio_key_None; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_None); + break; + case 11: // FL_Key + ntx_gpio_key_data.buttons = gpio_key_FL; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_FL); + break; + case 16: // FL+HOME PAD + case 13: // FL+HOME KEY + ntx_gpio_key_data.buttons = gpio_key_HOME_FL; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_HOME_FL); + break; + case 14: // HOME + case 18: // HOMEPAD + ntx_gpio_key_data.buttons = gpio_key_HOME; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_HOME); + break; + case 17: // RETURN+HOME+MENU + ntx_gpio_key_data.buttons = gpio_key_RETURN_HOME_MENU; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_RETURN_HOME_MENU); + break; + default: // FL+HOME + ntx_gpio_key_data.buttons = gpio_key_HOME_FL; + ntx_gpio_key_data.nbuttons = ARRAY_SIZE(gpio_key_HOME_FL); + break; + } + break; + } + + for(i=0;i<ntx_gpio_key_data.nbuttons;i++) { + if(0==strcmp(ntx_gpio_key_data.buttons[i].desc,"btn home")) { + +#ifdef TOUCH_HOME_LED//[ + if(36==gptHWCFG->m_val.bPCB || 40==gptHWCFG->m_val.bPCB || + 0!=gptHWCFG->m_val.bHOME_LED_PWM) + { + // E60Q32/E60Q5X/ + /* + * prepare hook functions of keys . + */ + gptGPIO_HOME_KEY = &ntx_gpio_key_data.buttons[i]; + + if( 36==gptHWCFG->m_val.bPCB || 2==gptHWCFG->m_val.bHOME_LED_PWM ) + { + // E60Q3X or HOME LED is GPIO controlled by SOC . + mxc_iomux_v3_setup_pad(MX6SL_PAD_SD1_DAT7__GPIO_5_10_OUPUT); + INIT_DELAYED_WORK(&homeled_pwrdwn_work,_homeled_work_func); + INIT_DELAYED_WORK(&homepad_check_work,_homepad_work_func); + } + + ntx_gpio_key_data.buttons[i].hook = ntx_touch_home_key_hook; + ntx_gpio_key_data.buttons[i].debounce_interval = 50; + + } + + +#endif //]TOUCH_HOME_LED + + if(2==gptHWCFG->m_val.bUIStyle) { + ntx_gpio_key_data.buttons[i].code = KEY_HOME; + } + } + else { + if(0==gptHWCFG->m_val.bUIStyle) { + if(0==strcmp(ntx_gpio_key_data.buttons[i].desc,"btn power")) { + printk("%s(),Ebrmain remote power key in gpio keys \n",__FUNCTION__); + ntx_gpio_key_data.nbuttons-=1; + } + } + } + } + + if( 1==gptHWCFG->m_val.bHOME_LED_PWM ) { + // HOME LED is controled by MSP430 . + if(MSP430_HOMELED_TYPE_PWM==msp430_homeled_type_get(0)) { + giHomeLED_Delay_Ticks = 200; + } + else { + giHomeLED_Delay_Ticks = 100; + } + } + + + platform_device_register(&ntx_gpio_key_device); + } + + imx6q_add_busfreq(); + imx6sl_add_dcp(); + imx6sl_add_rngb(); + imx6sl_add_imx_pxp_v4l2(); + + imx6q_add_perfmon(0); + imx6q_add_perfmon(1); + imx6q_add_perfmon(2); + mxc_register_device(&mxcbl_device, NULL); + + + platform_device_register(&ntx_light_ldm); +#ifndef CONFIG_ANDROID //[ + mxc_register_device(&mxc_usb_plug_device, &usbplug_data); +#endif//]CONFIG_ANDROID + if (1==gptHWCFG->m_val.bPMIC) { + // RC5T619 . + } + else { + /* Register charger chips */ + platform_device_register(&ntx_charger); + + } + + if(gptHWCFG) { + + if(1==gptHWCFG->m_val.bHallSensor) { + // hall sensor enabled . + tle4913_init(); + } + + + } + else { + printk(KERN_ERR "missing ntx hwconfig !!\n"); + } + +} + +extern void __iomem *twd_base; +static void __init mx6_timer_init(void) +{ + struct clk *uart_clk; +#ifdef CONFIG_LOCAL_TIMERS + twd_base = ioremap(LOCAL_TWD_ADDR, SZ_256); + BUG_ON(!twd_base); +#endif + mx6sl_clocks_init(32768, 24000000, 0, 0); + + uart_clk = clk_get_sys("imx-uart.0", NULL); + early_console_setup(UART1_BASE_ADDR, uart_clk); +} + +static struct sys_timer mxc_timer = { + .init = mx6_timer_init, +}; + +static void __init mx6_ntx_reserve(void) +{ +#if defined(CONFIG_MXC_GPU_VIV) || defined(CONFIG_MXC_GPU_VIV_MODULE) + phys_addr_t phys; + + if (imx6q_gpu_pdata.reserved_mem_size) { + phys = memblock_alloc_base(imx6q_gpu_pdata.reserved_mem_size, + SZ_4K, MEMBLOCK_ALLOC_ACCESSIBLE); + memblock_remove(phys, imx6q_gpu_pdata.reserved_mem_size); + imx6q_gpu_pdata.reserved_mem_base = phys; + } +#endif +} + +static int __init display_panel_setup(char *options) +{ + if (!options || !*options) { + pr_err("Error panel options\n"); + return 0; + } + + if (!strcmp(options, "lcd")) + display_panel_mode = PANEL_MODE_LCD; + else if (!strcmp(options, "hdmi")) + display_panel_mode = PANEL_MODE_HDMI; + else if (!strcmp(options, "eink")) + display_panel_mode = PANEL_MODE_EINK; + else + pr_warn("WARN: invalid display panel mode setting"); + + return 1; +} + +__setup("panel=", display_panel_setup); + +MACHINE_START(MX6SL_NTX, "Freescale i.MX 6SoloLite NTX Board") + .boot_params = MX6SL_PHYS_OFFSET + 0x100, + .map_io = mx6_map_io, + .init_irq = mx6_init_irq, + .init_machine = mx6_ntx_init, + .timer = &mxc_timer, + .reserve = mx6_ntx_reserve, +MACHINE_END diff --git a/arch/arm/mach-mx6/board-mx6sl_ntx.h b/arch/arm/mach-mx6/board-mx6sl_ntx.h new file mode 100755 index 00000000..15e6534d --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6sl_ntx.h @@ -0,0 +1,306 @@ +#ifndef _BOARD_MX6SL_NTX_H +#define _BOARD_MX6SL_NTX_H +#include <mach/iomux-mx6sl.h> + + +#define MX6SL_NTX_ACIN_PG gMX6SL_NTX_ACIN_PG +#define MX6SL_NTX_CHG gMX6SL_NTX_CHG +#define MX6SL_MSP_INT gMX6SL_MSP_INT +#define MX6SL_PWR_SW gMX6SL_PWR_SW +#define MX6SL_IR_TOUCH_INT gMX6SL_IR_TOUCH_INT +#define MX6SL_IR_TOUCH_RST gMX6SL_IR_TOUCH_RST +#define MX6SL_HALL_EN gMX6SL_HALL_EN +#define MX6SL_ON_LED gMX6SL_ON_LED +#define MX6SL_CHG_LED gMX6SL_CHG_LED +#define MX6SL_ACT_LED gMX6SL_ACT_LED + +#define MX6SL_EXT_SD_CD IMX_GPIO_NR(5, 2) /* SD2_DAT4 */ +#define MX6SL_WIFI_3V3 IMX_GPIO_NR(5, 0) /* SD2_DAT7 */ +#define MX6SL_WIFI_RST IMX_GPIO_NR(4, 27) /* SD2_RST */ +#define MX6SL_WIFI_INT IMX_GPIO_NR(4, 29) /* SD2_DAT6 */ +#define MX6SL_HW_ID0 IMX_GPIO_NR(4, 2) /* KEY_COL5 */ +#define MX6SL_HW_ID1 IMX_GPIO_NR(4, 4) /* KEY_COL6 */ +#define MX6SL_HW_ID2 IMX_GPIO_NR(4, 6) /* KEY_COL7 */ +#define MX6SL_HW_ID3 IMX_GPIO_NR(4, 5) /* KEY_ROW6 */ +#define MX6SL_HW_ID4 IMX_GPIO_NR(4, 7) /* KEY_ROW7 */ +#define MX6SL_FL_EN IMX_GPIO_NR(2, 10) /* EPDC_PWRCTRL3 */ +#define MX6SL_FL_R_EN IMX_GPIO_NR(1, 29) /* EPDC_SDCE2 */ +#define MX6SL_EP_PWRALL IMX_GPIO_NR(2, 14) /* EPDC_PWRWAKEUP */ +#define MX6SL_EP_WAKEUP IMX_GPIO_NR(2, 7) /* EPDC_PWRCTRL0 */ +#define MX6SL_EP_PWRUP IMX_GPIO_NR(2, 8) /* EPDC_PWRCTRL1 */ +#define MX6SL_EP_INT IMX_GPIO_NR(2, 9) /* EPDC_PWRCTRL2 */ +#define MX6SL_EP_PWRSTAT IMX_GPIO_NR(2, 13) /* EPDC_PWRSTAT */ +#define MX6SL_EP_VCOM IMX_GPIO_NR(2, 3) /* EPDC_VCOM0 */ + +#define MX6SL_SD2_CLK IMX_GPIO_NR(5, 5) /* SD2_CLK */ +#define MX6SL_SD2_CMD IMX_GPIO_NR(5, 4) /* SD2_CMD */ +#define MX6SL_SD2_DAT0 IMX_GPIO_NR(5, 1) /* SD2_DAT0 */ +#define MX6SL_SD2_DAT1 IMX_GPIO_NR(4, 30) /* SD2_DAT1 */ +#define MX6SL_SD2_DAT2 IMX_GPIO_NR(5, 3) /* SD2_DAT2 */ +#define MX6SL_SD2_DAT3 IMX_GPIO_NR(4, 28) /* SD2_DAT3 */ + +#define MX6SL_SD3_CLK IMX_GPIO_NR(5, 18) /* SD3_CLK */ +#define MX6SL_SD3_CMD IMX_GPIO_NR(5, 21) /* SD3_CMD */ +#define MX6SL_SD3_DAT0 IMX_GPIO_NR(5, 19) /* SD3_DAT0 */ +#define MX6SL_SD3_DAT1 IMX_GPIO_NR(5, 20) /* SD3_DAT1 */ +#define MX6SL_SD3_DAT2 IMX_GPIO_NR(5, 16) /* SD3_DAT2 */ +#define MX6SL_SD3_DAT3 IMX_GPIO_NR(5, 17) /* SD3_DAT3 */ + +#define MX6SL_I2C2_SCL IMX_GPIO_NR(3, 14) /* I2C2_SCL */ +#define MX6SL_I2C2_SDA IMX_GPIO_NR(3, 15) /* I2C2_SDA */ +#define MX6SL_I2C3_SCL IMX_GPIO_NR(3, 21) /* I2C3_SCL */ +#define MX6SL_I2C3_SDA IMX_GPIO_NR(3, 22) /* I2C3_SDA */ + +#define GPIO_ESD_3V3_ON IMX_GPIO_NR(3, 29) /* ROW2 */ +#define GPIO_ISD_3V3_ON IMX_GPIO_NR(3, 31) /* ROW3 */ +#define GPIO_IR_3V3_ON IMX_GPIO_NR(4, 1) /* ROW4 */ +//#define GPIO_EP_3V3_ON IMX_GPIO_NR(4, 3) /* ROW5 */ + +#define GPIO_KB_COL0 IMX_GPIO_NR(3, 24) /* COL0 */ +#define GPIO_KB_COL1 IMX_GPIO_NR(3, 26) /* COL1 */ + +#define GPIO_KB_ROW0 IMX_GPIO_NR(3, 25) /* ROW0 */ +#define GPIO_KB_ROW1 IMX_GPIO_NR(3, 27) /* ROW1 */ +#define GPIO_KB_ROW2 IMX_GPIO_NR(3, 29) /* ROW2 */ + +#define MX6SL_KL25_INT2 IMX_GPIO_NR(3, 29) /* ROW2 */ +#if 1 +#define MX6SL_WACOM_INT IMX_GPIO_NR(4, 0) /* COL4 */ +#define MX6SL_WACOM_PDCT IMX_GPIO_NR(4, 2) /* COL5 */ +#else +#define MX6SL_WACOM_INT IMX_GPIO_NR(4, 2) /* COL5 */ +#define MX6SL_WACOM_PDCT IMX_GPIO_NR(4, 0) /* COL4 */ +#endif +#define MX6SL_WACOM_INT_4_1 IMX_GPIO_NR(4, 1) /* ROW4 */ +#define MX6SL_WACOM_FWE IMX_GPIO_NR(3, 24) /* COL0 */ +#define MX6SL_WACOM_RST IMX_GPIO_NR(3, 30) /* COL3 */ + +#define MX6SL_WALTOP_RST IMX_GPIO_NR(3, 31) /* ROW3 */ +#define MX6SL_WALTOP_RST_3_30 IMX_GPIO_NR(3, 30) /* ROW3 */ +#define MX6SL_WALTOP_INT IMX_GPIO_NR(4, 1) /* ROW4 */ +#define MX6SL_WALTOP_INT_4_0 IMX_GPIO_NR(4, 0) /* ROW4 */ + + +extern volatile unsigned gMX6SL_NTX_ACIN_PG; +extern volatile unsigned gMX6SL_NTX_CHG; +extern volatile unsigned gMX6SL_MSP_INT; +extern volatile unsigned gMX6SL_PWR_SW; +extern volatile unsigned gMX6SL_IR_TOUCH_INT; +extern volatile unsigned gMX6SL_IR_TOUCH_RST; +extern volatile unsigned gMX6SL_HALL_EN; +extern volatile unsigned gMX6SL_ON_LED; +extern volatile unsigned gMX6SL_CHG_LED; +extern volatile unsigned gMX6SL_ACT_LED; +extern volatile unsigned gMX6SL_WIFI_3V3; +extern volatile unsigned gMX6SL_WIFI_RST; +extern volatile unsigned gMX6SL_WIFI_INT; + +static iomux_v3_cfg_t mx6sl_brd_ntx_kb_pads[] = { + MX6SL_PAD_KEY_COL0__KPP_COL_0, + MX6SL_PAD_KEY_COL1__KPP_COL_1, + MX6SL_PAD_KEY_ROW0__KPP_ROW_0, + MX6SL_PAD_KEY_ROW1__KPP_ROW_1, +}; +static iomux_v3_cfg_t mx6sl_brd_ntx_kb_gpio_pads[] = { + MX6SL_PAD_KEY_COL0__GPIO_3_24, + MX6SL_PAD_KEY_COL1__GPIO_3_26, + MX6SL_PAD_KEY_ROW0__GPIO_3_25, + MX6SL_PAD_KEY_ROW1__GPIO_3_27, + MX6SL_PAD_KEY_ROW2__GPIO_3_29, +}; + +static iomux_v3_cfg_t mx6sl_brd_ntx_sd4_pads[] = { + MX6SL_PAD_FEC_MDIO__USDHC4_CLK, + MX6SL_PAD_FEC_TX_CLK__USDHC4_CMD, + MX6SL_PAD_FEC_RX_ER__USDHC4_DAT0, + MX6SL_PAD_FEC_CRS_DV__USDHC4_DAT1, + MX6SL_PAD_FEC_RXD1__USDHC4_DAT2, + MX6SL_PAD_FEC_TXD0__USDHC4_DAT3, + MX6SL_PAD_FEC_MDC__USDHC4_DAT4, + MX6SL_PAD_FEC_RXD0__USDHC4_DAT5, + MX6SL_PAD_FEC_TX_EN__USDHC4_DAT6, + MX6SL_PAD_FEC_TXD1__USDHC4_DAT7, + MX6SL_PAD_FEC_REF_CLK__GPIO_4_26_PULLHIGH, +}; + +static iomux_v3_cfg_t mx6sl_brd_ntx_sd4_gpio_pads[] = { + MX6SL_PAD_FEC_MDIO__GPIO_4_20, // PWR_GOOD + MX6SL_PAD_FEC_TX_CLK__GPIO_4_21, // CHG# + MX6SL_PAD_FEC_RX_ER__GPIO_4_19, // MSP_INT# + MX6SL_PAD_FEC_CRS_DV__GPIO_4_25, // PWR_SW + MX6SL_PAD_FEC_RXD1__GPIO_4_18, // GS_INT + MX6SL_PAD_FEC_TXD0__GPIO_4_24, // IR_TOUCH_INT# + MX6SL_PAD_FEC_MDC__GPIO_4_23, // HALL_EN + MX6SL_PAD_FEC_RXD0__GPIO_4_17, // IR_RST + MX6SL_PAD_FEC_TX_EN__GPIO_4_22, // ACT_LED + MX6SL_PAD_FEC_TXD1__GPIO_4_16, // CHG_LED + MX6SL_PAD_FEC_REF_CLK__GPIO_4_26, // ON_LED +}; + + +static iomux_v3_cfg_t mx6sl_brd_ntx_sd1_pads[] = { + MX6SL_PAD_SD1_CLK__USDHC1_CLK_50MHZ, + MX6SL_PAD_SD1_CMD__USDHC1_CMD_50MHZ, + MX6SL_PAD_SD1_DAT0__USDHC1_DAT0_50MHZ, + MX6SL_PAD_SD1_DAT1__USDHC1_DAT1_50MHZ, + MX6SL_PAD_SD1_DAT2__USDHC1_DAT2_50MHZ, + MX6SL_PAD_SD1_DAT3__USDHC1_DAT3_50MHZ, + MX6SL_PAD_SD1_DAT4__USDHC1_DAT4_50MHZ, + MX6SL_PAD_SD1_DAT5__USDHC1_DAT5_50MHZ, + MX6SL_PAD_SD1_DAT6__USDHC1_DAT6_50MHZ, + MX6SL_PAD_SD1_DAT7__USDHC1_DAT7_50MHZ, +}; + +static iomux_v3_cfg_t mx6sl_brd_ntx_sd1_gpio_pads[] = { + MX6SL_PAD_SD1_CLK__GPIO_5_15, // CHG# + MX6SL_PAD_SD1_CMD__GPIO_5_14, // ACIN_PG# + MX6SL_PAD_SD1_DAT0__GPIO_5_11, // MSP_INT# + MX6SL_PAD_SD1_DAT1__GPIO_5_8, // PWR_SW# + MX6SL_PAD_SD1_DAT2__GPIO_5_13, // TP85 + MX6SL_PAD_SD1_DAT3__GPIO_5_6, // IR_DataReady + MX6SL_PAD_SD1_DAT4__GPIO_5_12, // TP86/Hall_EN# + MX6SL_PAD_SD1_DAT5__GPIO_5_9, // V325_RST# + MX6SL_PAD_SD1_DAT6__GPIO_5_7, // ACTION_LED_RH# + MX6SL_PAD_SD1_DAT7__GPIO_5_10, // TP82/Charge_LED_RH# +}; + + + +static iomux_v3_cfg_t mx6sl_brd_ntx_pads[] = { + MX6SL_PAD_REF_CLK_24M__I2C3_SCL, + MX6SL_PAD_REF_CLK_32K__I2C3_SDA, + + /* USBOTG ID pin */ + MX6SL_PAD_EPDC_PWRCOM__ANATOP_USBOTG1_ID, + + MX6SL_PAD_SD2_DAT4__GPIO_5_2, // EXT_SD_CD + MX6SL_PAD_SD2_DAT7__GPIO_5_0, // WIFI_3V3_ON + MX6SL_PAD_SD2_RST__GPIO_4_27, // WIFI_RST + //MX6SL_PAD_SD2_DAT6__GPIO_4_29_OUTPUT, // WIFI_INT + + MX6SL_PAD_KEY_COL5__GPIO_4_2, // HW_ID0 + MX6SL_PAD_KEY_COL6__GPIO_4_4, // HW_ID1 + MX6SL_PAD_KEY_COL7__GPIO_4_6, // HW_ID2 + MX6SL_PAD_KEY_ROW6__GPIO_4_5, // HW_ID3 + MX6SL_PAD_KEY_ROW7__GPIO_4_7, // HW_ID4 + + MX6SL_PAD_KEY_ROW2__GPIO_3_29, // ESD_3V3_ON(Q22)/BS_INT(Q12)/NA + MX6SL_PAD_KEY_ROW3__GPIO_3_31, // ISD_3V3_ON(Q22)/BS_3V3(Q12/NA + MX6SL_PAD_KEY_ROW4__GPIO_4_1, // IR_3V3_ON(Q22)/BS_UP(Q12)/NA + //MX6SL_PAD_KEY_ROW5__GPIO_4_3, // EP_3V3_ON(Q22)/BS_DN(Q12)/NA + + MX6SL_PAD_KEY_COL2__GPIO_3_28, // BS_Left (Q12)/NA + MX6SL_PAD_KEY_COL3__GPIO_3_30, // BS_Right (Q12)/NA + MX6SL_PAD_KEY_COL4__GPIO_4_0, // BS_Click (Q12)/NA + +#if 0 + MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7, // EP_PWRCTRL0 (WAKEUP#) + MX6SL_PAD_EPDC_PWRCTRL1__GPIO_2_8, // EP_PWRCTRL1 (PWRUP) + MX6SL_PAD_EPDC_PWRCTRL2__GPIO_2_9, // EP_INT + MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14,// PWRALL + MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13, // EP_PWRSTAT (PWR_GOOD) + MX6SL_PAD_EPDC_VCOM0__GPIO_2_3, // VCOM_CTRL +#endif + + MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, // FL_EN + MX6SL_PAD_EPDC_SDCE2__GPIO_1_29, // FL_R_EN + + MX6SL_PAD_LCD_DAT0__GPIO_2_20, + MX6SL_PAD_LCD_DAT1__GPIO_2_21, + MX6SL_PAD_LCD_DAT2__GPIO_2_22, + MX6SL_PAD_LCD_DAT3__GPIO_2_23, + MX6SL_PAD_LCD_DAT4__GPIO_2_24, + MX6SL_PAD_LCD_DAT5__GPIO_2_25, + MX6SL_PAD_LCD_DAT6__GPIO_2_26, + MX6SL_PAD_LCD_DAT7__GPIO_2_27, + MX6SL_PAD_LCD_DAT8__GPIO_2_28, + MX6SL_PAD_LCD_DAT9__GPIO_2_29, + MX6SL_PAD_LCD_DAT10__GPIO_2_30, + MX6SL_PAD_LCD_DAT11__GPIO_2_31, + MX6SL_PAD_LCD_DAT12__GPIO_3_0, + MX6SL_PAD_LCD_DAT13__GPIO_3_1, + MX6SL_PAD_LCD_DAT14__GPIO_3_2, + MX6SL_PAD_LCD_DAT15__GPIO_3_3, + MX6SL_PAD_LCD_DAT16__GPIO_3_4, + MX6SL_PAD_LCD_DAT17__GPIO_3_5, + MX6SL_PAD_LCD_DAT18__GPIO_3_6, + MX6SL_PAD_LCD_DAT19__GPIO_3_7, + MX6SL_PAD_LCD_DAT20__GPIO_3_8, + MX6SL_PAD_LCD_DAT21__GPIO_3_9, + MX6SL_PAD_LCD_DAT22__GPIO_3_10, + MX6SL_PAD_LCD_DAT23__GPIO_3_11, + + MX6SL_PAD_LCD_CLK__GPIO_2_15, + MX6SL_PAD_LCD_ENABLE__GPIO_2_16, + MX6SL_PAD_LCD_HSYNC__GPIO_2_17, + MX6SL_PAD_LCD_VSYNC__GPIO_2_18, + MX6SL_PAD_LCD_RESET__GPIO_2_19, + + MX6SL_PAD_ECSPI1_SCLK__GPIO_4_8, + MX6SL_PAD_ECSPI1_MOSI__GPIO_4_9, + MX6SL_PAD_ECSPI1_MISO__GPIO_4_10, + MX6SL_PAD_ECSPI1_SS0__GPIO_4_11, + MX6SL_PAD_ECSPI2_SCLK__GPIO_4_12, + MX6SL_PAD_ECSPI2_MOSI__GPIO_4_13, + MX6SL_PAD_ECSPI2_MISO__GPIO_4_14, + MX6SL_PAD_ECSPI2_SS0__GPIO_4_15, + MX6SL_PAD_AUD_RXFS__GPIO_1_0, + MX6SL_PAD_AUD_RXC__GPIO_1_1, + MX6SL_PAD_AUD_RXD__GPIO_1_2, + MX6SL_PAD_AUD_TXC__GPIO_1_3, + MX6SL_PAD_AUD_TXFS__GPIO_1_4, + MX6SL_PAD_AUD_TXD__GPIO_1_5, + MX6SL_PAD_AUD_MCLK__GPIO_1_6, + MX6SL_PAD_HSIC_DAT__GPIO_3_19, + MX6SL_PAD_HSIC_STROBE__GPIO_3_20, + MX6SL_PAD_WDOG_B__GPIO_3_18, +}; + +static iomux_v3_cfg_t mx6sl_ntx_sd2_gpio_pads[] = { + MX6SL_PAD_SD2_CLK__GPIO_5_5, + MX6SL_PAD_SD2_CMD__GPIO_5_4, + MX6SL_PAD_SD2_DAT0__GPIO_5_1, + MX6SL_PAD_SD2_DAT1__GPIO_4_30, + MX6SL_PAD_SD2_DAT2__GPIO_5_3, + MX6SL_PAD_SD2_DAT3__GPIO_4_28, +}; + +static iomux_v3_cfg_t mx6sl_ntx_sd2_wifi_pads[] = { + MX6SL_PAD_SD2_CLK__USDHC2_CLK_50MHZ, + MX6SL_PAD_SD2_CMD__USDHC2_CMD_50MHZ, + MX6SL_PAD_SD2_DAT0__USDHC2_DAT0_50MHZ, + MX6SL_PAD_SD2_DAT1__USDHC2_DAT1_50MHZ, + MX6SL_PAD_SD2_DAT2__USDHC2_DAT2_50MHZ, + MX6SL_PAD_SD2_DAT3__USDHC2_DAT3_50MHZ, +}; + +static iomux_v3_cfg_t mx6sl_ntx_sd3_gpio_pads[] = { + MX6SL_PAD_SD3_CLK__GPIO_5_18, + MX6SL_PAD_SD3_CMD__GPIO_5_21, + MX6SL_PAD_SD3_DAT0__GPIO_5_19, + MX6SL_PAD_SD3_DAT1__GPIO_5_20, + MX6SL_PAD_SD3_DAT2__GPIO_5_16, + MX6SL_PAD_SD3_DAT3__GPIO_5_17, +}; + +static iomux_v3_cfg_t mx6sl_ntx_sd3_wifi_pads[] = { + MX6SL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6SL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6SL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6SL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6SL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6SL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, +}; + + +static iomux_v3_cfg_t mx6sl_ntx_q22_wifictrl_pads[] = { + MX6SL_PAD_SD2_DAT6__GPIO_4_29_OUTPUT, // WiFi_3V3_ON# + MX6SL_PAD_SD2_DAT5__GPIO_4_31_INPUT, // WiFi_INT# +}; + +static iomux_v3_cfg_t mx6sl_ntx_q12_wifictrl_pads[] = { + MX6SL_PAD_SD2_DAT6__GPIO_4_29, // WiFi_INT# + MX6SL_PAD_SD2_DAT5__GPIO_4_31, //NC +}; + +#endif diff --git a/arch/arm/mach-mx6/board-mx6solo_sabreauto.h b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h new file mode 100644 index 00000000..b0edb5e5 --- /dev/null +++ b/arch/arm/mach-mx6/board-mx6solo_sabreauto.h @@ -0,0 +1,377 @@ + +/* + * Copyright (C) 2012-2013 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/iomux-mx6dl.h> + +static iomux_v3_cfg_t mx6dl_sabreauto_pads[] = { + + /* UART4 for debug */ + MX6DL_PAD_KEY_COL0__UART4_TXD, + MX6DL_PAD_KEY_ROW0__UART4_RXD, + /* USB HSIC ports use the same pin with ENET */ +#ifdef CONFIG_USB_EHCI_ARC_HSIC + /* USB H2 strobe/data pin */ + MX6DL_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE, + MX6DL_PAD_RGMII_TXC__USBOH3_H2_DATA, + + /* USB H3 strobe/data pin */ + MX6DL_PAD_RGMII_RXC__USBOH3_H3_STROBE, + MX6DL_PAD_RGMII_RX_CTL__USBOH3_H3_DATA, + /* ENET */ +#else + MX6DL_PAD_KEY_COL1__ENET_MDIO, + MX6DL_PAD_KEY_COL2__ENET_MDC, + MX6DL_PAD_RGMII_TXC__ENET_RGMII_TXC, + MX6DL_PAD_RGMII_TD0__ENET_RGMII_TD0, + MX6DL_PAD_RGMII_TD1__ENET_RGMII_TD1, + MX6DL_PAD_RGMII_TD2__ENET_RGMII_TD2, + MX6DL_PAD_RGMII_TD3__ENET_RGMII_TD3, + MX6DL_PAD_RGMII_TX_CTL__ENET_RGMII_TX_CTL, + MX6DL_PAD_ENET_REF_CLK__ENET_TX_CLK, + MX6DL_PAD_RGMII_RXC__ENET_RGMII_RXC, + MX6DL_PAD_RGMII_RD0__ENET_RGMII_RD0, + MX6DL_PAD_RGMII_RD1__ENET_RGMII_RD1, + MX6DL_PAD_RGMII_RD2__ENET_RGMII_RD2, + MX6DL_PAD_RGMII_RD3__ENET_RGMII_RD3, + MX6DL_PAD_RGMII_RX_CTL__ENET_RGMII_RX_CTL, + /*RGMII Phy Interrupt */ + MX6DL_PAD_GPIO_19__GPIO_4_5, +#endif + /* MCLK for csi0 */ + MX6DL_PAD_GPIO_0__CCM_CLKO, + /*MX6DL_PAD_GPIO_3__CCM_CLKO2,i*/ + + /* Android GPIO keys */ + MX6DL_PAD_SD2_CMD__GPIO_1_11, /* home */ + MX6DL_PAD_SD2_DAT3__GPIO_1_12, /* back */ + MX6DL_PAD_SD4_DAT4__GPIO_2_12, /* prog */ + MX6DL_PAD_SD4_DAT7__GPIO_2_15, /* vol up */ + MX6DL_PAD_DISP0_DAT20__GPIO_5_14, /* vol down */ + + /* SD1 */ + MX6DL_PAD_SD1_CLK__USDHC1_CLK_50MHZ_40OHM, + MX6DL_PAD_SD1_CMD__USDHC1_CMD_50MHZ_40OHM, + MX6DL_PAD_SD1_DAT0__USDHC1_DAT0_50MHZ_40OHM, + MX6DL_PAD_SD1_DAT1__USDHC1_DAT1_50MHZ_40OHM, + MX6DL_PAD_SD1_DAT2__USDHC1_DAT2_50MHZ_40OHM, + MX6DL_PAD_SD1_DAT3__USDHC1_DAT3_50MHZ_40OHM, + + /* SD1_CD and SD1_WP */ + MX6DL_PAD_GPIO_1__GPIO_1_1, + MX6DL_PAD_CSI0_DATA_EN__GPIO_5_20, + + /* SD3 */ + MX6DL_PAD_SD3_CLK__USDHC3_CLK_50MHZ, + MX6DL_PAD_SD3_CMD__USDHC3_CMD_50MHZ, + MX6DL_PAD_SD3_DAT0__USDHC3_DAT0_50MHZ, + MX6DL_PAD_SD3_DAT1__USDHC3_DAT1_50MHZ, + MX6DL_PAD_SD3_DAT2__USDHC3_DAT2_50MHZ, + MX6DL_PAD_SD3_DAT3__USDHC3_DAT3_50MHZ, + MX6DL_PAD_SD3_DAT4__USDHC3_DAT4_50MHZ, + MX6DL_PAD_SD3_DAT5__USDHC3_DAT5_50MHZ, + MX6DL_PAD_SD3_DAT6__USDHC3_DAT6_50MHZ, + MX6DL_PAD_SD3_DAT7__USDHC3_DAT7_50MHZ, + + /* SD3 VSelect */ + MX6DL_PAD_GPIO_18__USDHC3_VSELECT, + /* SD3_CD and SD3_WP */ + MX6DL_PAD_NANDF_CS2__GPIO_6_15, + MX6DL_PAD_SD2_DAT2__GPIO_1_13, + + /* ESAI */ + MX6DL_PAD_ENET_CRS_DV__ESAI1_SCKT, + MX6DL_PAD_ENET_RXD1__ESAI1_FST, + MX6DL_PAD_ENET_TX_EN__ESAI1_TX3_RX2, + MX6DL_PAD_GPIO_5__ESAI1_TX2_RX3, + MX6DL_PAD_ENET_TXD0__ESAI1_TX4_RX1, + MX6DL_PAD_ENET_MDC__ESAI1_TX5_RX0, + MX6DL_PAD_GPIO_17__ESAI1_TX0, + MX6DL_PAD_NANDF_CS3__ESAI1_TX1, + MX6DL_PAD_ENET_MDIO__ESAI1_SCKR, + MX6DL_PAD_GPIO_9__ESAI1_FSR, + /* esai interrupt */ + MX6DL_PAD_SD2_CLK__GPIO_1_10, + + /* I2C2 */ + MX6DL_PAD_EIM_EB2__I2C2_SCL, + MX6DL_PAD_KEY_ROW3__I2C2_SDA, + MX6DL_PAD_SD2_DAT0__GPIO_1_15, + + /* DISPLAY */ + MX6DL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK, + MX6DL_PAD_DI0_PIN15__IPU1_DI0_PIN15, + MX6DL_PAD_DI0_PIN2__IPU1_DI0_PIN2, + MX6DL_PAD_DI0_PIN3__IPU1_DI0_PIN3, + MX6DL_PAD_DISP0_DAT0__IPU1_DISP0_DAT_0, + MX6DL_PAD_DISP0_DAT1__IPU1_DISP0_DAT_1, + MX6DL_PAD_DISP0_DAT2__IPU1_DISP0_DAT_2, + MX6DL_PAD_DISP0_DAT3__IPU1_DISP0_DAT_3, + MX6DL_PAD_DISP0_DAT4__IPU1_DISP0_DAT_4, + MX6DL_PAD_DISP0_DAT5__IPU1_DISP0_DAT_5, + MX6DL_PAD_DISP0_DAT6__IPU1_DISP0_DAT_6, + MX6DL_PAD_DISP0_DAT7__IPU1_DISP0_DAT_7, + MX6DL_PAD_DISP0_DAT8__IPU1_DISP0_DAT_8, + MX6DL_PAD_DISP0_DAT9__IPU1_DISP0_DAT_9, + MX6DL_PAD_DISP0_DAT10__IPU1_DISP0_DAT_10, + MX6DL_PAD_DISP0_DAT11__IPU1_DISP0_DAT_11, + MX6DL_PAD_DISP0_DAT12__IPU1_DISP0_DAT_12, + MX6DL_PAD_DISP0_DAT13__IPU1_DISP0_DAT_13, + MX6DL_PAD_DISP0_DAT14__IPU1_DISP0_DAT_14, + MX6DL_PAD_DISP0_DAT15__IPU1_DISP0_DAT_15, + MX6DL_PAD_DISP0_DAT16__IPU1_DISP0_DAT_16, + MX6DL_PAD_DISP0_DAT17__IPU1_DISP0_DAT_17, + MX6DL_PAD_DISP0_DAT18__IPU1_DISP0_DAT_18, + MX6DL_PAD_DISP0_DAT19__IPU1_DISP0_DAT_19, + MX6DL_PAD_DISP0_DAT21__IPU1_DISP0_DAT_21, + /* LITE_SENS_INT_B */ + MX6DL_PAD_DISP0_DAT23__GPIO_5_17, + /*PMIC INT*/ + MX6DL_PAD_DISP0_DAT22__GPIO_5_16, + + /* ipu1 csi0 */ + MX6DL_PAD_CSI0_DAT4__IPU1_CSI0_D_4, + MX6DL_PAD_CSI0_DAT5__IPU1_CSI0_D_5, + MX6DL_PAD_CSI0_DAT6__IPU1_CSI0_D_6, + MX6DL_PAD_CSI0_DAT7__IPU1_CSI0_D_7, + MX6DL_PAD_CSI0_DAT8__IPU1_CSI0_D_8, + MX6DL_PAD_CSI0_DAT9__IPU1_CSI0_D_9, + MX6DL_PAD_CSI0_DAT10__IPU1_CSI0_D_10, + MX6DL_PAD_CSI0_DAT11__IPU1_CSI0_D_11, + MX6DL_PAD_CSI0_DAT12__IPU1_CSI0_D_12, + MX6DL_PAD_CSI0_DAT13__IPU1_CSI0_D_13, + MX6DL_PAD_CSI0_DAT14__IPU1_CSI0_D_14, + MX6DL_PAD_CSI0_DAT15__IPU1_CSI0_D_15, + MX6DL_PAD_CSI0_DAT16__IPU1_CSI0_D_16, + MX6DL_PAD_CSI0_DAT17__IPU1_CSI0_D_17, + MX6DL_PAD_CSI0_DAT18__IPU1_CSI0_D_18, + MX6DL_PAD_CSI0_DAT19__IPU1_CSI0_D_19, + MX6DL_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC, + MX6DL_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC, + MX6DL_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK, + + /* PWM3 and PMW4 */ + MX6DL_PAD_SD4_DAT1__PWM3_PWMO, + MX6DL_PAD_SD4_DAT2__PWM4_PWMO, + + /* DISP0 RESET */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, + + /* SPDIF */ + MX6DL_PAD_KEY_COL3__SPDIF_IN1, + + /* Touchscreen interrupt */ + MX6DL_PAD_EIM_EB0__GPIO_2_28, + + /* USBOTG ID pin */ + MX6DL_PAD_ENET_RX_ER__ANATOP_USBOTG_ID, + + /* VIDEO adv7180 INTRQ */ + MX6DL_PAD_ENET_RXD0__GPIO_1_27, + /* UART 2 */ + MX6DL_PAD_GPIO_7__UART2_TXD, + MX6DL_PAD_GPIO_8__UART2_RXD, + MX6DL_PAD_SD4_DAT6__UART2_CTS, + MX6DL_PAD_SD4_DAT5__UART2_RTS, + + /*USBs OC pin */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, /*HOST1_OC*/ + MX6DL_PAD_SD4_DAT0__GPIO_2_8, /*OTG_OC*/ + + /* DISP0 I2C ENABLE*/ + MX6DL_PAD_EIM_D28__GPIO_3_28, + + /* DISP0 DET */ + MX6DL_PAD_EIM_D31__GPIO_3_31, + + /* DISP0 RESET */ + MX6DL_PAD_EIM_WAIT__GPIO_5_0, + + /* HDMI */ + MX6DL_PAD_EIM_A25__HDMI_TX_CEC_LINE, + +#ifdef CONFIG_MX6_ENET_IRQ_TO_GPIO + MX6DL_PAD_GPIO_6__OBSERVE_MUX_OBSRV_INT_OUT1, +#else + /* MLB150 */ + MX6DL_PAD_ENET_TXD1__MLB_MLBCLK, + MX6DL_PAD_GPIO_6__MLB_MLBSIG, + MX6DL_PAD_GPIO_2__MLB_MLBDAT, +#endif +}; + +static iomux_v3_cfg_t mx6dl_sabreauto_can0_pads[] = { + /* CAN1 */ + MX6DL_PAD_KEY_COL2__CAN1_TXCAN, + MX6DL_PAD_KEY_ROW2__CAN1_RXCAN, +}; + + +static iomux_v3_cfg_t mx6dl_sabreauto_can1_pads[] = { + /* CAN2 */ + MX6DL_PAD_KEY_COL4__CAN2_TXCAN, + MX6DL_PAD_KEY_ROW4__CAN2_RXCAN, +}; + +static iomux_v3_cfg_t mx6dl_sabreauto_mipi_sensor_pads[] = { + MX6DL_PAD_CSI0_MCLK__CCM_CLKO, +}; + +#define MX6DL_USDHC_PAD_SETTING(id, speed) \ +mx6dl_sd##id##_##speed##mhz[] = { \ + MX6DL_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \ + MX6DL_PAD_SD##id##_CMD__USDHC##id##_CMD_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT0__USDHC##id##_DAT0_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT1__USDHC##id##_DAT1_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT2__USDHC##id##_DAT2_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT3__USDHC##id##_DAT3_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT4__USDHC##id##_DAT4_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT5__USDHC##id##_DAT5_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT6__USDHC##id##_DAT6_##speed##MHZ, \ + MX6DL_PAD_SD##id##_DAT7__USDHC##id##_DAT7_##speed##MHZ, \ +} + +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(3, 50); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(3, 100); +static iomux_v3_cfg_t MX6DL_USDHC_PAD_SETTING(3, 200); + +/* The GPMI is conflicted with SD3, so init this in the driver. */ +static iomux_v3_cfg_t mx6dl_gpmi_nand[] __initdata = { + MX6DL_PAD_NANDF_CLE__RAWNAND_CLE, + MX6DL_PAD_NANDF_ALE__RAWNAND_ALE, + MX6DL_PAD_NANDF_CS0__RAWNAND_CE0N, + MX6DL_PAD_NANDF_CS1__RAWNAND_CE1N, + MX6DL_PAD_NANDF_RB0__RAWNAND_READY0, + MX6DL_PAD_SD4_DAT0__RAWNAND_DQS, + MX6DL_PAD_NANDF_D0__RAWNAND_D0, + MX6DL_PAD_NANDF_D1__RAWNAND_D1, + MX6DL_PAD_NANDF_D2__RAWNAND_D2, + MX6DL_PAD_NANDF_D3__RAWNAND_D3, + MX6DL_PAD_NANDF_D4__RAWNAND_D4, + MX6DL_PAD_NANDF_D5__RAWNAND_D5, + MX6DL_PAD_NANDF_D6__RAWNAND_D6, + MX6DL_PAD_NANDF_D7__RAWNAND_D7, + MX6DL_PAD_SD4_CMD__RAWNAND_RDN, + MX6DL_PAD_SD4_CLK__RAWNAND_WRN, + MX6DL_PAD_NANDF_WP_B__RAWNAND_RESETN, +}; + +static iomux_v3_cfg_t mx6dl_i2c3_pads_rev_a[] __initdata = { + MX6DL_PAD_GPIO_3__I2C3_SCL, + MX6DL_PAD_GPIO_16__I2C3_SDA, +}; + +static iomux_v3_cfg_t mx6dl_i2c3_pads_rev_b[] __initdata = { + MX6DL_PAD_GPIO_3__I2C3_SCL, + MX6DL_PAD_EIM_D18__I2C3_SDA, +}; +static iomux_v3_cfg_t mx6dl_tuner_pads[] __initdata = { + MX6DL_PAD_DISP0_DAT16__AUDMUX_AUD5_TXC, + MX6DL_PAD_DISP0_DAT18__AUDMUX_AUD5_TXFS, + MX6DL_PAD_DISP0_DAT19__AUDMUX_AUD5_RXD, +}; +static iomux_v3_cfg_t mx6dl_extra_pads_rev_b[] __initdata = { + MX6DL_PAD_EIM_A24__GPIO_5_4, + MX6DL_PAD_GPIO_16__ENET_ANATOP_ETHERNET_REF_OUT, +}; +static iomux_v3_cfg_t mx6dl_spinor_pads[] __initdata = { + /* eCSPI1 */ + MX6DL_PAD_EIM_D16__ECSPI1_SCLK, + MX6DL_PAD_EIM_D17__ECSPI1_MISO, + MX6DL_PAD_EIM_D18__ECSPI1_MOSI, + MX6DL_PAD_EIM_D19__ECSPI1_SS1, + + MX6DL_PAD_EIM_D19__GPIO_3_19, +}; + +/*Bluetooth is conflicted with GMPI and NOR chips*/ +static iomux_v3_cfg_t mx6dl_bluetooth_pads[] __initdata = { + /* UART 3 */ + MX6DL_PAD_SD4_CLK__UART3_RXD, + MX6DL_PAD_SD4_CMD__UART3_TXD, + MX6DL_PAD_EIM_D30__UART3_CTS, + MX6DL_PAD_EIM_EB3__UART3_RTS, +}; + +static iomux_v3_cfg_t mx6dl_weimnor_pads[] __initdata = { + /* Parallel NOR */ + MX6DL_PAD_EIM_OE__WEIM_WEIM_OE, + MX6DL_PAD_EIM_RW__WEIM_WEIM_RW, + MX6DL_PAD_EIM_WAIT__WEIM_WEIM_WAIT, + MX6DL_PAD_EIM_CS0__WEIM_WEIM_CS_0, + /*Control NOR reset using gpio mode*/ + MX6DL_PAD_DISP0_DAT8__GPIO_4_29, + + MX6DL_PAD_EIM_LBA__WEIM_WEIM_LBA, + MX6DL_PAD_EIM_BCLK__WEIM_WEIM_BCLK, + /* Parallel Nor Data Bus */ + MX6DL_PAD_EIM_D16__WEIM_WEIM_D_16, + MX6DL_PAD_EIM_D17__WEIM_WEIM_D_17, + MX6DL_PAD_EIM_D18__WEIM_WEIM_D_18, + MX6DL_PAD_EIM_D19__WEIM_WEIM_D_19, + MX6DL_PAD_EIM_D20__WEIM_WEIM_D_20, + MX6DL_PAD_EIM_D21__WEIM_WEIM_D_21, + MX6DL_PAD_EIM_D22__WEIM_WEIM_D_22, + MX6DL_PAD_EIM_D23__WEIM_WEIM_D_23, + MX6DL_PAD_EIM_D24__WEIM_WEIM_D_24, + MX6DL_PAD_EIM_D25__WEIM_WEIM_D_25, + MX6DL_PAD_EIM_D26__WEIM_WEIM_D_26, + MX6DL_PAD_EIM_D27__WEIM_WEIM_D_27, + MX6DL_PAD_EIM_D28__WEIM_WEIM_D_28, + MX6DL_PAD_EIM_D29__WEIM_WEIM_D_29, + MX6DL_PAD_EIM_D30__WEIM_WEIM_D_30, + MX6DL_PAD_EIM_D31__WEIM_WEIM_D_31, + + /* Parallel Nor 25 bit Address Bus */ + MX6DL_PAD_EIM_A24__GPIO_5_4, + MX6DL_PAD_EIM_A23__WEIM_WEIM_A_23, + MX6DL_PAD_EIM_A22__WEIM_WEIM_A_22, + MX6DL_PAD_EIM_A21__WEIM_WEIM_A_21, + MX6DL_PAD_EIM_A20__WEIM_WEIM_A_20, + MX6DL_PAD_EIM_A19__WEIM_WEIM_A_19, + MX6DL_PAD_EIM_A18__WEIM_WEIM_A_18, + MX6DL_PAD_EIM_A17__WEIM_WEIM_A_17, + MX6DL_PAD_EIM_A16__WEIM_WEIM_A_16, + + MX6DL_PAD_EIM_DA15__WEIM_WEIM_DA_A_15, + MX6DL_PAD_EIM_DA14__WEIM_WEIM_DA_A_14, + MX6DL_PAD_EIM_DA13__WEIM_WEIM_DA_A_13, + MX6DL_PAD_EIM_DA12__WEIM_WEIM_DA_A_12, + MX6DL_PAD_EIM_DA11__WEIM_WEIM_DA_A_11, + MX6DL_PAD_EIM_DA10__WEIM_WEIM_DA_A_10, + MX6DL_PAD_EIM_DA9__WEIM_WEIM_DA_A_9, + MX6DL_PAD_EIM_DA8__WEIM_WEIM_DA_A_8, + MX6DL_PAD_EIM_DA7__WEIM_WEIM_DA_A_7, + MX6DL_PAD_EIM_DA6__WEIM_WEIM_DA_A_6, + MX6DL_PAD_EIM_DA5__WEIM_WEIM_DA_A_5, + MX6DL_PAD_EIM_DA4__WEIM_WEIM_DA_A_4, + MX6DL_PAD_EIM_DA3__WEIM_WEIM_DA_A_3, + MX6DL_PAD_EIM_DA2__WEIM_WEIM_DA_A_2, + MX6DL_PAD_EIM_DA1__WEIM_WEIM_DA_A_1, + MX6DL_PAD_EIM_DA0__WEIM_WEIM_DA_A_0, +}; + +static iomux_v3_cfg_t mx6dl_sabreauto_hdmi_ddc_pads[] = { + MX6DL_PAD_EIM_EB2__HDMI_TX_DDC_SCL, /* HDMI DDC SCL */ + MX6DL_PAD_KEY_ROW3__HDMI_TX_DDC_SDA, /* HDMI DDC SDA */ +}; + +static iomux_v3_cfg_t mx6dl_sabreauto_i2c2_pads[] = { + MX6DL_PAD_EIM_EB2__I2C2_SCL, /* I2C2 SCL */ + MX6DL_PAD_KEY_ROW3__I2C2_SDA, /* I2C2 SDA */ +}; diff --git a/arch/arm/mach-mx6/bus_freq.c b/arch/arm/mach-mx6/bus_freq.c new file mode 100644 index 00000000..2d408b8b --- /dev/null +++ b/arch/arm/mach-mx6/bus_freq.c @@ -0,0 +1,842 @@ +/* + * Copyright (C) 2011-2013 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 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" +#include <linux/suspend.h> + +#define LPAPM_CLK 24000000 +#define DDR_AUDIO_CLK 100000000 +#define DDR_MED_CLK 400000000 +#define DDR3_NORMAL_CLK 528000000 +#define GPC_PGC_GPU_PGCR_OFFSET 0x260 +#define GPC_CNTR_OFFSET 0x0 + +static DEFINE_SPINLOCK(freq_lock); + +int low_bus_freq_mode; +int audio_bus_freq_mode; +int high_bus_freq_mode; +int med_bus_freq_mode; + +int bus_freq_scaling_initialized; +static struct device *busfreq_dev; +static int busfreq_suspended; + +/* True if bus_frequency is scaled not using DVFS-PER */ +int bus_freq_scaling_is_active; + +int lp_high_freq; +int lp_med_freq; +int lp_audio_freq; +int high_cpu_freq; +unsigned int ddr_low_rate; +unsigned int ddr_med_rate; +unsigned int ddr_normal_rate; + +int low_freq_bus_used(void); +void set_ddr_freq(int ddr_freq); +void *mx6sl_wfi_iram_base; +unsigned long mx6sl_wfi_iram_phys_addr; + +void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr,\ + int audio_mode) = NULL; +extern void mx6sl_wait (int arm_podf, unsigned long wfi_iram_addr); + +void *mx6sl_ddr_freq_base; +unsigned long mx6sl_ddr_freq_phys_addr; +void (*mx6sl_ddr_freq_change_iram)(int ddr_freq, int low_bus_freq_mode) = NULL; +extern void mx6sl_ddr_iram(int ddr_freq); + +extern int init_mmdc_settings(void); +extern struct cpu_op *(*get_cpu_op)(int *op); +extern int update_ddr_freq(int ddr_rate); +extern unsigned long save_ttbr1(void); +extern void restore_ttbr1(u32 ttbr1); +extern int chip_rev; + +DEFINE_MUTEX(bus_freq_mutex); + +struct timeval start_time; +struct timeval end_time; + +static int cpu_op_nr; +static u32 org_arm_podf; +static struct cpu_op *cpu_op_tbl; +static struct clk *pll2_400; +static struct clk *axi_clk; +static struct clk *ahb_clk; +static struct clk *periph_clk; +static struct clk *osc_clk; +static struct clk *cpu_clk; +static struct clk *pll3; +static struct clk *pll2; +static struct clk *pll1; +static struct clk *pll1_sw_clk; +static struct clk *pll3_sw_clk; +static struct clk *pll2_200; +struct clk *mmdc_ch0_axi; +static struct clk *pll3_540; + +static struct delayed_work low_bus_freq_handler; + +void reduce_bus_freq(void) +{ + if (!cpu_is_mx6sl()) { + if (cpu_is_mx6dl() && + (clk_get_parent(axi_clk) != periph_clk)) + /* Set the axi_clk to be sourced from the periph_clk. + * So that its frequency can be lowered down to 50MHz + * or 24MHz as the case may be. + */ + clk_set_parent(axi_clk, periph_clk); + + clk_enable(pll3); + if (lp_audio_freq) { + /* Need to ensure that PLL2_PFD_400M is kept ON. */ + clk_enable(pll2_400); + update_ddr_freq(DDR_AUDIO_CLK); + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk, pll2_200); + audio_bus_freq_mode = 1; + low_bus_freq_mode = 0; + } else { + update_ddr_freq(LPAPM_CLK); + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk, osc_clk); + if (audio_bus_freq_mode) + clk_disable(pll2_400); + low_bus_freq_mode = 1; + audio_bus_freq_mode = 0; + } + + if (med_bus_freq_mode) + clk_disable(pll2_400); + + clk_disable(pll3); + med_bus_freq_mode = 0; + } else { + u32 reg; + u32 div; + unsigned long flags; + + if (high_bus_freq_mode) { + /* Set periph_clk to be sourced from OSC_CLK */ + /* Set AXI to 24MHz. */ + clk_set_parent(periph_clk, osc_clk); + clk_set_rate(axi_clk, + clk_round_rate(axi_clk, LPAPM_CLK)); + /* Set AHB to 24MHz. */ + clk_set_rate(ahb_clk, + clk_round_rate(ahb_clk, LPAPM_CLK)); + } + if (lp_audio_freq) { + u32 ttbr1; + /* PLL2 is on in this mode, as DDR is at 100MHz. */ + /* Now change DDR freq while running from IRAM. */ + + /* Set AHB to 24MHz. */ + clk_set_rate(ahb_clk, + clk_round_rate(ahb_clk, LPAPM_CLK / 3)); + + spin_lock_irqsave(&freq_lock, flags); + /* sync the outer cache. */ + outer_sync(); + + /* Save TTBR1 */ + ttbr1 = save_ttbr1(); + + mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK, + low_bus_freq_mode); + restore_ttbr1(ttbr1); + + spin_unlock_irqrestore(&freq_lock, flags); + + if (low_bus_freq_mode) { + /* Swtich ARM to run off PLL2_PFD2_400MHz + * since DDR is anyway at 100MHz. + */ + clk_set_parent(pll1_sw_clk, pll2_400); + + /* Ensure that the clock will be + * at original speed. + */ + reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR); + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + /* We have enabled PLL1 in the code below when + * ARM is from PLL1, so disable it here. + */ + clk_disable(pll1); + } + low_bus_freq_mode = 0; + audio_bus_freq_mode = 1; + } else { + u32 ttbr1; + /* Set MMDC clk to 24MHz. */ + /* Since we are going to set PLL2 in bypass mode, + * move the CPU clock off PLL2. + */ + /* Ensure that the clock will be at + * lowest possible freq. + */ + org_arm_podf = __raw_readl(MXC_CCM_CACRR); + /* Need to enable PLL1 before setting its rate. */ + clk_enable(pll1); + clk_set_rate(pll1, + cpu_op_tbl[cpu_op_nr - 1].pll_lpm_rate); + div = clk_get_rate(pll1) / + cpu_op_tbl[cpu_op_nr - 1].cpu_rate; + + reg = __raw_writel(div - 1, MXC_CCM_CACRR); + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + clk_set_parent(pll1_sw_clk, pll1); + + spin_lock_irqsave(&freq_lock, flags); + /* sync the outer cache. */ + outer_sync(); + + ttbr1 = save_ttbr1(); + /* Now change DDR freq while running from IRAM. */ + mx6sl_ddr_freq_change_iram(LPAPM_CLK, + low_bus_freq_mode); + restore_ttbr1(ttbr1); + + spin_unlock_irqrestore(&freq_lock, flags); + + low_bus_freq_mode = 1; + audio_bus_freq_mode = 0; + } + } + high_bus_freq_mode = 0; + +} + +static void reduce_bus_freq_handler(struct work_struct *work) +{ + mutex_lock(&bus_freq_mutex); + + if (!low_freq_bus_used()) { + mutex_unlock(&bus_freq_mutex); + return; + } + /* If we are already in audio bus freq mode, + * just return if lp_audio_freq is true. + */ + if (audio_bus_freq_mode && lp_audio_freq) { + mutex_unlock(&bus_freq_mutex); + return; + } + + /* If we dont want to transition from low bus to + * audio bus mode and are already in + *low bus mode, then return. + */ + if (!lp_audio_freq && low_bus_freq_mode) { + mutex_unlock(&bus_freq_mutex); + return; + } + reduce_bus_freq(); + + mutex_unlock(&bus_freq_mutex); +} + +/* Set the DDR, AHB to 24MHz. + * This mode will be activated only when none of the modules that + * need a higher DDR or AHB frequency are active. + */ +int set_low_bus_freq(void) +{ + if (busfreq_suspended) + return 0; + + if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) + return 0; + + /* Check to see if we need to get from + * low bus freq mode to audio bus freq mode. + * If so, the change needs to be done immediately. + */ + if (lp_audio_freq && low_bus_freq_mode) + reduce_bus_freq(); + else + /* Don't lower the frequency immediately. Instead + * scheduled a delayed work and drop the freq if + * the conditions still remain the same. + */ + schedule_delayed_work(&low_bus_freq_handler, + usecs_to_jiffies(500000)); + return 0; +} + +/* Set the DDR to either 528MHz or 400MHz for MX6q + * or 400MHz for MX6DL. + */ +int set_high_bus_freq(int high_bus_freq) +{ + if (bus_freq_scaling_initialized && bus_freq_scaling_is_active) + cancel_delayed_work_sync(&low_bus_freq_handler); + + if (busfreq_suspended) + return 0; + + + if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) + return 0; + + if (cpu_is_mx6sl()) + high_bus_freq = 1; + + if (high_bus_freq_mode && high_bus_freq) + return 0; + + + /* medium bus freq is only supported for MX6DQ */ + if (cpu_is_mx6q() && med_bus_freq_mode && !high_bus_freq) + return 0; + + if (cpu_is_mx6dl() && high_bus_freq) + high_bus_freq = 0; + + if (cpu_is_mx6dl() && med_bus_freq_mode) + return 0; + + if ((high_bus_freq_mode && (high_bus_freq || lp_high_freq)) || + (med_bus_freq_mode && !high_bus_freq && lp_med_freq && + !lp_high_freq)) + return 0; + + if (cpu_is_mx6sl()) { + u32 reg; + unsigned long flags; + u32 ttbr1; + + spin_lock_irqsave(&freq_lock, flags); + /* sync the outer cache. */ + outer_sync(); + + ttbr1 = save_ttbr1(); + + /* Change DDR freq in IRAM. */ + mx6sl_ddr_freq_change_iram(ddr_normal_rate, low_bus_freq_mode); + + restore_ttbr1(ttbr1); + + spin_unlock_irqrestore(&freq_lock, flags); + + /* Set periph_clk to be sourced from pll2_pfd2_400M */ + /* First need to set the divider before changing the */ + /* parent if parent clock is larger than previous one */ + clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, + LPAPM_CLK / 3)); + clk_set_rate(axi_clk, + clk_round_rate(axi_clk, LPAPM_CLK / 2)); + clk_set_parent(periph_clk, pll2_400); + + if (low_bus_freq_mode) { + /* Now move ARM to be sourced from PLL2_400 too. */ + clk_set_parent(pll1_sw_clk, pll2_400); + + /* Ensure that the clock will be at original speed. */ + reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR); + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + clk_disable(pll1); + } + high_bus_freq_mode = 1; + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + } else { + clk_enable(pll3); + if (high_bus_freq) { + update_ddr_freq(ddr_normal_rate); + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk, pll2); + if (med_bus_freq_mode) + clk_disable(pll2_400); + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + } else { + clk_enable(pll2_400); + update_ddr_freq(ddr_med_rate); + /* Make sure periph clk's parent also got updated */ + clk_set_parent(periph_clk, pll2_400); + high_bus_freq_mode = 0; + med_bus_freq_mode = 1; + } + if (audio_bus_freq_mode) + clk_disable(pll2_400); + + /* AXI_CLK is sourced from PLL3_PFD_540 on MX6DL */ + if (cpu_is_mx6dl() && + clk_get_parent(axi_clk) != pll3_540) + clk_set_parent(axi_clk, pll3_540); + + low_bus_freq_mode = 0; + audio_bus_freq_mode = 0; + + clk_disable(pll3); + } + return 0; +} + +int low_freq_bus_used(void) +{ + if (!bus_freq_scaling_initialized) + return 0; + + /* We only go the lowest setpoint if ARM is also + * at the lowest setpoint. + */ + if (high_cpu_freq) + return 0; + + if ((lp_high_freq == 0) + && (lp_med_freq == 0)) + return 1; + else + return 0; +} + +void bus_freq_update(struct clk *clk, bool flag) +{ + mutex_lock(&bus_freq_mutex); + + if (flag) { + if (clk == cpu_clk) { + /* The CPU freq is being increased. + * check if we need to increase the bus freq + */ + high_cpu_freq = 1; + if (low_bus_freq_mode || audio_bus_freq_mode) + set_high_bus_freq(0); + } else { + /* Update count */ + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq++; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq++; + else if (clk->flags & AHB_AUDIO_SET_POINT) + lp_audio_freq++; + /* Update bus freq */ + if ((clk->flags & CPU_FREQ_TRIG_UPDATE) + && (clk_get_usecount(clk) == 0)) { + if (!(clk->flags & + (AHB_HIGH_SET_POINT | AHB_MED_SET_POINT))) { + if (low_freq_bus_used()) + set_low_bus_freq(); + } else { + if ((clk->flags & AHB_MED_SET_POINT) + && !med_bus_freq_mode) { + /* Set to Medium setpoint */ + set_high_bus_freq(0); + } else if ((clk->flags & AHB_HIGH_SET_POINT) + && !high_bus_freq_mode) { + /* Currently at low or medium + * set point, need to set to + * high setpoint + */ + set_high_bus_freq(1); + } + } + } + } + } else { + if (clk == cpu_clk) { + /* CPU freq is dropped, check if we can + * lower the bus freq. + */ + high_cpu_freq = 0; + + if (low_freq_bus_used() && + !(low_bus_freq_mode || audio_bus_freq_mode)) + set_low_bus_freq(); + } else { + /* Update count */ + if (clk->flags & AHB_HIGH_SET_POINT) + lp_high_freq--; + else if (clk->flags & AHB_MED_SET_POINT) + lp_med_freq--; + else if (clk->flags & AHB_AUDIO_SET_POINT) + lp_audio_freq--; + /* Update bus freq */ + if ((clk->flags & CPU_FREQ_TRIG_UPDATE) + && (clk_get_usecount(clk) == 0)) { + if (low_freq_bus_used()) + set_low_bus_freq(); + else { + /* Set to either high or + * medium setpoint. + */ + set_high_bus_freq(0); + } + } + } + } + mutex_unlock(&bus_freq_mutex); + return; +} +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) +{ + if (strncmp(buf, "1", 1) == 0) { +#ifdef CONFIG_MX6_VPU_352M + if (cpu_is_mx6q()) + /*do not enable bus freq*/ + bus_freq_scaling_is_active = 0; + printk(KERN_WARNING "Bus frequency can't be enabled if using VPU 352M!\n"); + return size; +#else + bus_freq_scaling_is_active = 1; +#endif + set_high_bus_freq(0); + /* Make sure system can enter low bus mode if it should be in + low bus mode */ + if (low_freq_bus_used() && !low_bus_freq_mode) + set_low_bus_freq(); + } 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) +{ + return 0; +} + +static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event, + void *dummy) +{ + mutex_lock(&bus_freq_mutex); + + if (event == PM_SUSPEND_PREPARE) { + set_high_bus_freq(1); + busfreq_suspended = 1; + } else if (event == PM_POST_SUSPEND) { + busfreq_suspended = 0; + } + + mutex_unlock(&bus_freq_mutex); + + return NOTIFY_OK; +} +static int busfreq_resume(struct platform_device *pdev) +{ + return 0; +} +static struct notifier_block imx_bus_freq_pm_notifier = { + .notifier_call = bus_freq_pm_notify, +}; + +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) +{ + u32 err; + + busfreq_dev = &pdev->dev; + + pll2_400 = clk_get(NULL, "pll2_pfd_400M"); + if (IS_ERR(pll2_400)) { + printk(KERN_DEBUG "%s: failed to get pll2_pfd_400M\n", + __func__); + return PTR_ERR(pll2_400); + } + + pll2_200 = clk_get(NULL, "pll2_200M"); + if (IS_ERR(pll2_200)) { + printk(KERN_DEBUG "%s: failed to get pll2_200M\n", + __func__); + return PTR_ERR(pll2_200); + } + + pll2 = clk_get(NULL, "pll2"); + if (IS_ERR(pll2)) { + printk(KERN_DEBUG "%s: failed to get pll2\n", + __func__); + return PTR_ERR(pll2); + } + + 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); + } + + 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); + } + + + if (IS_ERR(pll2)) { + printk(KERN_DEBUG "%s: failed to get pll2\n", + __func__); + return PTR_ERR(pll2); + } + + + 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); + } + + pll3 = clk_get(NULL, "pll3_main_clk"); + if (IS_ERR(pll3)) { + printk(KERN_DEBUG "%s: failed to get pll3\n", + __func__); + return PTR_ERR(pll3); + } + + pll3_540 = clk_get(NULL, "pll3_pfd_540M"); + if (IS_ERR(pll3_540)) { + printk(KERN_DEBUG "%s: failed to get periph_clk\n", + __func__); + return PTR_ERR(pll3_540); + } + + pll3_sw_clk = clk_get(NULL, "pll3_sw_clk"); + if (IS_ERR(pll3_sw_clk)) { + printk(KERN_DEBUG "%s: failed to get pll3_sw_clk\n", + __func__); + return PTR_ERR(pll3_sw_clk); + } + + axi_clk = clk_get(NULL, "axi_clk"); + if (IS_ERR(axi_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_clk\n", + __func__); + return PTR_ERR(axi_clk); + } + + ahb_clk = clk_get(NULL, "ahb"); + if (IS_ERR(ahb_clk)) { + printk(KERN_DEBUG "%s: failed to get ahb_clk\n", + __func__); + return PTR_ERR(ahb_clk); + } + + periph_clk = clk_get(NULL, "periph_clk"); + if (IS_ERR(periph_clk)) { + printk(KERN_DEBUG "%s: failed to get periph_clk\n", + __func__); + return PTR_ERR(periph_clk); + } + + osc_clk = clk_get(NULL, "osc"); + if (IS_ERR(osc_clk)) { + printk(KERN_DEBUG "%s: failed to get osc_clk\n", + __func__); + return PTR_ERR(osc_clk); + } + + mmdc_ch0_axi = clk_get(NULL, "mmdc_ch0_axi"); + if (IS_ERR(mmdc_ch0_axi)) { + printk(KERN_DEBUG "%s: failed to get mmdc_ch0_axi\n", + __func__); + return PTR_ERR(mmdc_ch0_axi); + } + + 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; + } + + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + low_bus_freq_mode = 0; + if (cpu_is_mx6dl()) { + high_bus_freq_mode = 0; + med_bus_freq_mode = 1; + /* To make pll2_400 use count right, as when + system enter 24M, it will disable pll2_400 */ + clk_enable(pll2_400); + } else if (cpu_is_mx6sl()) { + /* Set med_bus_freq_mode to 1 since med_bus_freq_mode + is not supported as yet for MX6SL */ + high_bus_freq_mode = 1; + med_bus_freq_mode = 1; + } else { + high_bus_freq_mode = 1; + med_bus_freq_mode = 0; + } + bus_freq_scaling_is_active = 0; + bus_freq_scaling_initialized = 1; + + if (cpu_is_mx6q()) { + ddr_low_rate = LPAPM_CLK; + ddr_med_rate = DDR_MED_CLK; + ddr_normal_rate = DDR3_NORMAL_CLK; + } + if (cpu_is_mx6dl() || cpu_is_mx6sl()) { + ddr_low_rate = LPAPM_CLK; + ddr_normal_rate = ddr_med_rate = DDR_MED_CLK; + } + + INIT_DELAYED_WORK(&low_bus_freq_handler, reduce_bus_freq_handler); + register_pm_notifier(&imx_bus_freq_pm_notifier); + + if (!cpu_is_mx6sl()) + init_mmdc_settings(); + else { + /* Use preallocated memory */ + mx6sl_wfi_iram_phys_addr = MX6SL_WFI_IRAM_CODE; + + /* + * Don't ioremap the address, we have fixed the IRAM address + * at IRAM_BASE_ADDR_VIRT + */ + mx6sl_wfi_iram_base = (void *)IRAM_BASE_ADDR_VIRT + + (mx6sl_wfi_iram_phys_addr - IRAM_BASE_ADDR); + + memcpy(mx6sl_wfi_iram_base, mx6sl_wait, MX6SL_WFI_IRAM_CODE_SIZE); + mx6sl_wfi_iram = (void *)mx6sl_wfi_iram_base; + + /* Use preallocated memory */ + mx6sl_ddr_freq_phys_addr = MX6_DDR_FREQ_IRAM_CODE; + + /* + * Don't ioremap the address, we have fixed the IRAM address + * at IRAM_BASE_ADDR_VIRT + */ + mx6sl_ddr_freq_base = (void *)IRAM_BASE_ADDR_VIRT + + (mx6sl_ddr_freq_phys_addr - IRAM_BASE_ADDR); + + memcpy(mx6sl_ddr_freq_base, mx6sl_ddr_iram, MX6SL_DDR_FREQ_CODE_SIZE); + mx6sl_ddr_freq_change_iram = (void *)mx6sl_ddr_freq_base; + } + + 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"); + +#ifdef CONFIG_MX6_VPU_352M + if (cpu_is_mx6q()) + bus_freq_scaling_is_active = 0;/*disable bus_freq*/ + +#else + /* Enable busfreq by default. */ + bus_freq_scaling_is_active = 1; +#endif + if (cpu_is_mx6q()) + set_high_bus_freq(1); + else if (cpu_is_mx6dl()) + set_high_bus_freq(0); + + printk(KERN_INFO "Bus freq driver Enabled\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; +} + +late_initcall(busfreq_init); +module_exit(busfreq_cleanup); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("BusFreq driver"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c new file mode 100644 index 00000000..9d3dbfa2 --- /dev/null +++ b/arch/arm/mach-mx6/clock.c @@ -0,0 +1,5736 @@ + +/* + * Copyright (C) 2012-2014 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 <linux/regulator/consumer.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include <mach/ahci_sata.h> +#include <mach/mxc_hdmi.h> +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "regs-anadig.h" + +#ifdef CONFIG_CLK_DEBUG +#define __INIT_CLK_DEBUG(n) .name = #n, +#else +#define __INIT_CLK_DEBUG(n) +#endif + +extern u32 arm_max_freq; +extern int mxc_jtag_enabled; +extern struct regulator *cpu_regulator; +extern struct cpu_op *(*get_cpu_op)(int *op); +extern int lp_high_freq; +extern int lp_med_freq; +extern int wait_mode_arm_podf; +extern int lp_audio_freq; +extern int cur_arm_podf; +extern bool enet_is_active; + +void __iomem *apll_base; + +static void __iomem *timer_base; +static struct clk ipu1_clk; +static struct clk ipu2_clk; +static struct clk axi_clk; +static struct clk pll1_sys_main_clk; +static struct clk pll2_528_bus_main_clk; +static struct clk pll2_pfd_400M; +static struct clk pll2_pfd_352M; +static struct clk pll3_pfd_540M; +static struct clk pll2_pfd_594M; +static struct clk pll3_usb_otg_main_clk; +static struct clk pll4_audio_main_clk; +static struct clk pll5_video_main_clk; +static struct clk pll6_mlb150_main_clk; +static struct clk pll7_usb_host_main_clk; +static struct clk pll8_enet_main_clk; +static struct clk apbh_dma_clk; +static struct clk openvg_axi_clk; +static struct clk enfc_clk; +static struct clk usdhc3_clk; +static struct clk ipg_clk; +static struct clk gpt_clk[]; +static struct clk clko2_clk; + +static struct cpu_op *cpu_op_tbl; +static int cpu_op_nr; +static bool pll1_enabled; +static bool arm_needs_pll2_400; + +#define SPIN_DELAY 1200000 /* in nanoseconds */ + +#define AUDIO_VIDEO_MIN_CLK_FREQ 650000000 +#define AUDIO_VIDEO_MAX_CLK_FREQ 1300000000 +DEFINE_SPINLOCK(clk_lock); +#define V2_TCN 0x24 +#define V2_TSTAT 0x08 +#define V2_TSTAT_ROV (1 << 5) +#define V2_TCTL_CLK_OSC_DIV8 (5 << 6) +#define MXC_TCTL 0x00 +#define MXC_TPRER 0x04 +#define V2_TPRER_PRE24M_OFFSET 12 +#define V2_TPRER_PRE24M_MASK 0xF + +/* We need to check the exp status again after timer expiration, + * as there might be interrupt coming between the first time exp + * and the time reading, then the time reading may be several ms + * after the exp checking due to the irq handle, so we need to + * check it to make sure the exp return the right value after + * timer expiration. */ +#define WAIT(exp, timeout) \ +({ \ + u32 gpt_rate; \ + u32 gpt_ticks; \ + u32 gpt_cnt; \ + u32 reg; \ + int result = 1; \ + gpt_rate = clk_get_rate(&gpt_clk[0]); \ + gpt_ticks = timeout / (1000000000 / gpt_rate); \ + reg = __raw_readl(timer_base + V2_TSTAT);\ + /* Clear the GPT roll over interrupt. */ \ + if (reg & V2_TSTAT_ROV) { \ + __raw_writel(V2_TSTAT_ROV, timer_base + V2_TSTAT);\ + } \ + gpt_cnt = __raw_readl(timer_base + V2_TCN); \ + while (!(exp)) { \ + if ((__raw_readl(timer_base + V2_TCN) - gpt_cnt) > gpt_ticks) { \ + if (!exp) \ + result = 0; \ + break; \ + } else { \ + reg = __raw_readl(timer_base + V2_TSTAT);\ + if (reg & V2_TSTAT_ROV) { \ + u32 old_cnt = gpt_cnt; \ + /* Timer has rolled over. \ + * Calculate the new tick count. \ + */ \ + gpt_cnt = __raw_readl(timer_base + V2_TCN); \ + gpt_ticks -= (0xFFFFFFFF - old_cnt + gpt_cnt); \ + /* Clear the roll over interrupt. */ \ + __raw_writel(V2_TSTAT_ROV, \ + timer_base + V2_TSTAT); \ + } \ + } \ + } \ + result; \ +}) + +/* 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 unsigned long anaclk_1_reference, anaclk_2_reference; + +/* For MX 6DL/S, Video PLL may be used by synchronous display devices, + * such as HDMI or LVDS, and also by the EPDC. If EPDC is in use, + * it must use the Video PLL to achieve the clock frequencies it needs. + * So if EPDC is in use, the "epdc" string should be added to kernel + * parameters, in order to set the EPDC parent clock to the Video PLL. + * This will have an impact on the behavior of HDMI and LVDS. + */ +int epdc_enabled; +static int __init epdc_setup(char *__unused) +{ + epdc_enabled = 1; + return 1; +} +__setup("epdc", epdc_setup); + +static void __calc_pre_post_dividers(u32 max_podf, u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + /* Some of the podfs are 3 bits while others are 6 bits. + * Handle both cases here. + */ + if (div >= 512 && (max_podf == 64)) { + /* For pre = 3bits and podf = 6 bits, max divider is 512. */ + *pre = 8; + *post = 64; + } else if (div >= 64 && (max_podf == 8)) { + /* For pre = 3bits and podf = 3 bits, max divider is 64. */ + *pre = 8; + *post = 8; + } else if (div >= 8) { + /* Find the minimum pre-divider for a max podf */ + if (max_podf == 64) + min_pre = (div - 1) / (1 << 6) + 1; + else + min_pre = (div - 1) / (1 << 3) + 1; + old_err = 8; + /* Now loop through to find the max pre-divider. */ + 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 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; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_sys_main_clk) + return PLL1_SYS_BASE_ADDR; + else if (pll == &pll2_528_bus_main_clk) + return PLL2_528_BASE_ADDR; + else if (pll == &pll3_usb_otg_main_clk) + return PLL3_480_USB1_BASE_ADDR; + else if (pll == &pll4_audio_main_clk) + return PLL4_AUDIO_BASE_ADDR; + else if (pll == &pll5_video_main_clk) + return PLL5_VIDEO_BASE_ADDR; + else if (pll == &pll6_mlb150_main_clk) + return PLL6_MLB_BASE_ADDR; + else if (pll == &pll7_usb_host_main_clk) + return PLL7_480_USB2_BASE_ADDR; + else if (pll == &pll8_enet_main_clk) + return PLL8_ENET_BASE_ADDR; + else + BUG(); + return NULL; +} + + +/* + * For the 6-to-1 muxed input clock + */ +static inline u32 _get_mux6(struct clk *parent, struct clk *m0, struct clk *m1, + struct clk *m2, struct clk *m3, struct clk *m4, + struct clk *m5) +{ + 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 + BUG(); + + 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_anaclk_1_get_rate(struct clk *clk) +{ + return anaclk_1_reference; +} + +static int _clk_anaclk_1_set_rate(struct clk *clk, unsigned long rate) +{ + anaclk_1_reference = rate; + return 0; +} + +static unsigned long _clk_anaclk_2_get_rate(struct clk *clk) +{ + return anaclk_2_reference; +} + +static int _clk_anaclk_2_set_rate(struct clk *clk, unsigned long rate) +{ + anaclk_2_reference = rate; + return 0; +} + +/* 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 struct clk anaclk_1 = { + __INIT_CLK_DEBUG(anaclk_1) + .get_rate = _clk_anaclk_1_get_rate, + .set_rate = _clk_anaclk_1_set_rate, +}; + +static struct clk anaclk_2 = { + __INIT_CLK_DEBUG(anaclk_2) + .get_rate = _clk_anaclk_2_get_rate, + .set_rate = _clk_anaclk_2_set_rate, +}; + +static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + + tmp = (u64)clk_get_rate(clk->parent) * 18; + tmp += rate/2; + do_div(tmp, rate); + frac = tmp; + frac = frac < 12 ? 12 : frac; + frac = frac > 35 ? 35 : frac; + tmp = (u64)clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + return tmp; +} + +static unsigned long pfd_get_rate(struct clk *clk) +{ + 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); + + frac = (__raw_readl(clk->enable_reg) >> clk->enable_shift) & + ANADIG_PFD_FRAC_MASK; + + 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); + + /* Round up the divider so that we don't set a rate + * higher than what is requested. */ + tmp += rate/2; + do_div(tmp, rate); + frac = tmp; + frac = frac < 12 ? 12 : frac; + frac = frac > 35 ? 35 : frac; + /* clear clk frac bits */ + __raw_writel(ANADIG_PFD_FRAC_MASK << clk->enable_shift, + (int)clk->enable_reg + 8); + /* set clk frac bits */ + __raw_writel(frac << clk->enable_shift, + (int)clk->enable_reg + 4); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + return 0; +} + +static int _clk_pfd_enable(struct clk *clk) +{ + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + /* clear clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + (int)clk->enable_reg + 8); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); + + return 0; +} + +static void _clk_pfd_disable(struct clk *clk) +{ + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.enable(&apbh_dma_clk); + + /* set clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + (int)clk->enable_reg + 4); + + if (apbh_dma_clk.usecount == 0) + apbh_dma_clk.disable(&apbh_dma_clk); +} + +static int _clk_pll_enable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + reg &= ~ANADIG_PLL_POWER_DOWN; + + /* The 480MHz PLLs have the opposite definition for power bit. */ + if (clk == &pll3_usb_otg_main_clk || clk == &pll7_usb_host_main_clk) + reg |= ANADIG_PLL_POWER_DOWN; + + __raw_writel(reg, pllbase); + + /* It will power on pll3 */ + if (clk == &pll3_usb_otg_main_clk) + __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_CLR); + + /* Wait for PLL to lock */ + if (!WAIT((__raw_readl(pllbase) & ANADIG_PLL_LOCK), + SPIN_DELAY)) + panic("pll enable failed\n"); + + /* Enable the PLL output now*/ + reg = __raw_readl(pllbase); + reg &= ~ANADIG_PLL_BYPASS; + reg |= ANADIG_PLL_ENABLE; + __raw_writel(reg, pllbase); + + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + if ((arm_needs_pll2_400) && (clk == &pll2_528_bus_main_clk)) + return; + /* + * To support USB remote wake up, need always keep power and enable bit + * BM_ANADIG_ANA_MISC2_CONTROL0 will power off PLL3's power + * Please see TKT064178 for detail. + */ + if (clk == &pll3_usb_otg_main_clk) { + __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_SET); + return; + } + + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + reg |= ANADIG_PLL_BYPASS; + reg &= ~ANADIG_PLL_ENABLE; + + __raw_writel(reg, pllbase); + +} + +static unsigned long _clk_pll1_main_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + /* If PLL1 is bypassed, its rate will be from OSC directly */ + if (__raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_SYS_BYPASS_MASK) + return clk_get_rate(clk->parent); + + div = __raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_SYS_DIV_SELECT_MASK; + val = (clk_get_rate(clk->parent) * div) / 2; + return val; +} + +static int _clk_pll1_main_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate < AUDIO_VIDEO_MIN_CLK_FREQ || rate > AUDIO_VIDEO_MAX_CLK_FREQ) + return -EINVAL; + + div = (rate * 2) / clk_get_rate(clk->parent); + + /* Update div */ + reg = __raw_readl(PLL1_SYS_BASE_ADDR) & ~ANADIG_PLL_SYS_DIV_SELECT_MASK; + reg |= div; + __raw_writel(reg, PLL1_SYS_BASE_ADDR); + + /* Wait for PLL1 to lock */ + if (!WAIT((__raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_LOCK), + SPIN_DELAY)) + panic("pll1 enable failed\n"); + + return 0; +} + +static void _clk_pll1_disable(struct clk *clk) +{ + void __iomem *pllbase; + u32 reg; + + pll1_enabled = false; + + /* Set PLL1 in bypass mode only. */ + /* We need to be able to set the ARM-PODF bit + * when the system enters WAIT mode. And setting + * this bit requires PLL1_main to be enabled. + */ + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + reg |= ANADIG_PLL_BYPASS; + __raw_writel(reg, pllbase); +} + +static int _clk_pll1_enable(struct clk *clk) +{ + _clk_pll_enable(clk); + pll1_enabled = true; + return 0; +} + +static struct clk pll1_sys_main_clk = { + __INIT_CLK_DEBUG(pll1_sys_main_clk) + .parent = &osc_clk, + .get_rate = _clk_pll1_main_get_rate, + .set_rate = _clk_pll1_main_set_rate, + .enable = _clk_pll1_enable, + .disable = _clk_pll1_disable, +}; + +static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll1_sys_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. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL); + } else { + /* Set STEP_CLK to be the parent*/ + if (parent == &osc_clk) { + /* Set STEP_CLK to be sourced from LPAPM. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL); + __raw_writel(reg, MXC_CCM_CCSR); + } else { + /* Set STEP_CLK to be sourced from PLL2-PDF (400MHz). */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_STEP_SEL; + __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) +{ + return clk_get_rate(clk->parent); +} + +static struct clk pll1_sw_clk = { + __INIT_CLK_DEBUG(pll1_sw_clk) + .parent = &pll1_sys_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = _clk_pll1_sw_get_rate, +}; + +static unsigned long _clk_pll2_main_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL2_528_BASE_ADDR) & ANADIG_PLL_528_DIV_SELECT; + + if (div == 1) + val = clk_get_rate(clk->parent) * 22; + + else + val = clk_get_rate(clk->parent) * 20; + + return val; +} + +static int _clk_pll2_main_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate == 528000000) + div = 1; + else if (rate == 480000000) + div = 0; + else + return -EINVAL; + + reg = __raw_readl(PLL2_528_BASE_ADDR); + reg &= ~ANADIG_PLL_528_DIV_SELECT; + reg |= div; + __raw_writel(reg, PLL2_528_BASE_ADDR); + + return 0; +} + +static struct clk pll2_528_bus_main_clk = { + __INIT_CLK_DEBUG(pll2_528_bus_main_clk) + .parent = &osc_clk, + .get_rate = _clk_pll2_main_get_rate, + .set_rate = _clk_pll2_main_set_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +static void _clk_pll2_pfd_400M_disable(struct clk *clk) +{ + if (!arm_needs_pll2_400) + _clk_pfd_disable(clk); +} + +static struct clk pll2_pfd_400M = { + __INIT_CLK_DEBUG(pll2_pfd_400M) + .parent = &pll2_528_bus_main_clk, + .enable_reg = (void *)PFD_528_BASE_ADDR, + .enable_shift = ANADIG_PFD2_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pll2_pfd_400M_disable, + .get_rate = pfd_get_rate, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll2_pfd_352M = { + __INIT_CLK_DEBUG(pll2_pfd_352M) + .parent = &pll2_528_bus_main_clk, + .enable_reg = (void *)PFD_528_BASE_ADDR, + .enable_shift = ANADIG_PFD0_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll2_pfd_594M = { + __INIT_CLK_DEBUG(pll2_pfd_594M) + .parent = &pll2_528_bus_main_clk, + .enable_reg = (void *)PFD_528_BASE_ADDR, + .enable_shift = ANADIG_PFD1_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static unsigned long _clk_pll2_200M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk pll2_200M = { + __INIT_CLK_DEBUG(pll2_200M) + .parent = &pll2_pfd_400M, + .get_rate = _clk_pll2_200M_get_rate, +}; + +static unsigned long _clk_pll3_usb_otg_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL3_480_USB1_BASE_ADDR) + & ANADIG_PLL_480_DIV_SELECT_MASK; + + if (div == 1) + val = clk_get_rate(clk->parent) * 22; + else + val = clk_get_rate(clk->parent) * 20; + return val; +} + +static int _clk_pll3_usb_otg_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate == 528000000) + div = 1; + else if (rate == 480000000) + div = 0; + else + return -EINVAL; + + reg = __raw_readl(PLL3_480_USB1_BASE_ADDR); + reg &= ~ANADIG_PLL_480_DIV_SELECT_MASK; + reg |= div; + __raw_writel(reg, PLL3_480_USB1_BASE_ADDR); + + return 0; +} + + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_usb_otg_main_clk = { + __INIT_CLK_DEBUG(pll3_usb_otg_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +/* for USB OTG */ +static struct clk usb_phy1_clk = { + __INIT_CLK_DEBUG(usb_phy1_clk) + .parent = &pll3_usb_otg_main_clk, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +/* For HSIC port 1 */ +static struct clk usb_phy3_clk = { + __INIT_CLK_DEBUG(usb_phy3_clk) + .parent = &pll3_usb_otg_main_clk, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +/* For HSIC port 2 */ +static struct clk usb_phy4_clk = { + __INIT_CLK_DEBUG(usb_phy4_clk) + .parent = &pll3_usb_otg_main_clk, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +static struct clk pll3_pfd_508M = { + __INIT_CLK_DEBUG(pll3_pfd_508M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD2_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll3_pfd_454M = { + __INIT_CLK_DEBUG(pll3_pfd_454M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD3_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll3_pfd_720M = { + __INIT_CLK_DEBUG(pll3_pfd_720M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD0_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static int pfd_540M_set_rate(struct clk *clk, unsigned long rate) +{ + if ((clk_get_parent(&ipu1_clk) == clk) || + (clk_get_parent(&ipu2_clk) == clk) || + (clk_get_parent(&axi_clk) == clk)) + WARN(1, "CHANGING rate of 540M PFD when IPU and \ + AXI is sourced from it \n"); + + return pfd_set_rate(clk, rate); +} + +static struct clk pll3_pfd_540M = { + __INIT_CLK_DEBUG(pll3_pfd_540M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD1_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_540M_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, + .get_rate = pfd_get_rate, +}; + +static unsigned long _clk_pll3_sw_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->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 = &pll3_usb_otg_main_clk, + .get_rate = _clk_pll3_sw_get_rate, +}; + +static unsigned long _clk_pll3_120M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 4; +} + +static struct clk pll3_120M = { + __INIT_CLK_DEBUG(pll3_120M) + .parent = &pll3_sw_clk, + .get_rate = _clk_pll3_120M_get_rate, +}; + +static unsigned long _clk_pll3_80M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 6; +} + +static struct clk pll3_80M = { + __INIT_CLK_DEBUG(pll3_80M) + .parent = &pll3_sw_clk, + .get_rate = _clk_pll3_80M_get_rate, +}; + +static unsigned long _clk_pll3_60M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 8; +} + +static struct clk pll3_60M = { + __INIT_CLK_DEBUG(pll3_60M) + .parent = &pll3_sw_clk, + .get_rate = _clk_pll3_60M_get_rate, +}; + +static unsigned long _clk_audio_video_get_rate(struct clk *clk) +{ + unsigned int div, mfn, mfd; + unsigned long rate; + unsigned int parent_rate = clk_get_rate(clk->parent); + void __iomem *pllbase; + int rev = mx6q_revision(); + unsigned int test_div_sel, control3, post_div = 1; + + if (clk == &pll4_audio_main_clk) + pllbase = PLL4_AUDIO_BASE_ADDR; + else + pllbase = PLL5_VIDEO_BASE_ADDR; + + if ((rev >= IMX_CHIP_REVISION_1_1) || cpu_is_mx6dl()) { + test_div_sel = (__raw_readl(pllbase) + & ANADIG_PLL_AV_TEST_DIV_SEL_MASK) + >> ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET; + if (test_div_sel == 0) + post_div = 4; + else if (test_div_sel == 1) + post_div = 2; + + if (clk == &pll5_video_main_clk) { + control3 = (__raw_readl(ANA_MISC2_BASE_ADDR) + & ANADIG_ANA_MISC2_CONTROL3_MASK) + >> ANADIG_ANA_MISC2_CONTROL3_OFFSET; + if (control3 == 1) + post_div *= 2; + else if (control3 == 3) + post_div *= 4; + } + } + + div = __raw_readl(pllbase) & ANADIG_PLL_SYS_DIV_SELECT_MASK; + mfn = __raw_readl(pllbase + PLL_NUM_DIV_OFFSET); + mfd = __raw_readl(pllbase + PLL_DENOM_DIV_OFFSET); + + rate = (parent_rate * div) + ((parent_rate / mfd) * mfn); + rate = rate / post_div; + + return rate; +} + +static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + unsigned int mfn, mfd = 1000000; + s64 temp64; + unsigned int parent_rate = clk_get_rate(clk->parent); + void __iomem *pllbase; + unsigned long min_clk_rate, pre_div_rate; + int rev = mx6q_revision(); + u32 test_div_sel = 2; + u32 control3 = 0; + + if ((rev < IMX_CHIP_REVISION_1_1) && !cpu_is_mx6dl()) + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ; + else if (clk == &pll4_audio_main_clk) + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4; + else + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 16; + + if ((rate < min_clk_rate) || (rate > AUDIO_VIDEO_MAX_CLK_FREQ)) + return -EINVAL; + + if (clk == &pll4_audio_main_clk) + pllbase = PLL4_AUDIO_BASE_ADDR; + else + pllbase = PLL5_VIDEO_BASE_ADDR; + + pre_div_rate = rate; + if ((rev >= IMX_CHIP_REVISION_1_1) || cpu_is_mx6dl()) { + while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) { + pre_div_rate *= 2; + /* + * test_div_sel field values: + * 2 -> Divide by 1 + * 1 -> Divide by 2 + * 0 -> Divide by 4 + * + * control3 field values: + * 0 -> Divide by 1 + * 1 -> Divide by 2 + * 3 -> Divide by 4 + */ + if (test_div_sel != 0) + test_div_sel--; + else { + control3++; + if (control3 == 2) + control3++; + } + } + } + + div = pre_div_rate / parent_rate; + temp64 = (u64) (pre_div_rate - (div * parent_rate)); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + reg = __raw_readl(pllbase) + & ~ANADIG_PLL_SYS_DIV_SELECT_MASK + & ~ANADIG_PLL_AV_TEST_DIV_SEL_MASK; + reg |= div | + (test_div_sel << ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET); + __raw_writel(reg, pllbase); + __raw_writel(mfn, pllbase + PLL_NUM_DIV_OFFSET); + __raw_writel(mfd, pllbase + PLL_DENOM_DIV_OFFSET); + + if ((rev >= IMX_CHIP_REVISION_1_1) && + (pllbase == PLL5_VIDEO_BASE_ADDR)) { + reg = __raw_readl(ANA_MISC2_BASE_ADDR) + & ~ANADIG_ANA_MISC2_CONTROL3_MASK; + reg |= control3 << ANADIG_ANA_MISC2_CONTROL3_OFFSET; + __raw_writel(reg, ANA_MISC2_BASE_ADDR); + } + + return 0; +} + +static unsigned long _clk_audio_video_round_rate(struct clk *clk, + unsigned long rate) +{ + unsigned long min_clk_rate; + unsigned int div, post_div = 1; + unsigned int mfn, mfd = 1000000; + s64 temp64; + unsigned int parent_rate = clk_get_rate(clk->parent); + unsigned long pre_div_rate; + u32 test_div_sel = 2; + u32 control3 = 0; + unsigned long final_rate; + int rev = mx6q_revision(); + + if ((rev < IMX_CHIP_REVISION_1_1) && !cpu_is_mx6dl()) + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ; + else if (clk == &pll4_audio_main_clk) + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4; + else + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 16; + + if (rate < min_clk_rate) + return min_clk_rate; + + if (rate > AUDIO_VIDEO_MAX_CLK_FREQ) + return AUDIO_VIDEO_MAX_CLK_FREQ; + + pre_div_rate = rate; + if ((rev >= IMX_CHIP_REVISION_1_1) || cpu_is_mx6dl()) { + while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) { + pre_div_rate *= 2; + post_div *= 2; + if (test_div_sel != 0) + test_div_sel--; + else { + control3++; + if (control3 == 2) + control3++; + } + } + } + + div = pre_div_rate / parent_rate; + temp64 = (u64) (pre_div_rate - (div * parent_rate)); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + final_rate = (parent_rate * div) + ((parent_rate / mfd) * mfn); + final_rate = final_rate / post_div; + + return final_rate; +} + +static int _clk_audio_video_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + int mux; + void __iomem *pllbase; + + if (clk == &pll4_audio_main_clk) + pllbase = PLL4_AUDIO_BASE_ADDR; + else + pllbase = PLL5_VIDEO_BASE_ADDR; + + reg = __raw_readl(pllbase) & ~ANADIG_PLL_BYPASS_CLK_SRC_MASK; + mux = _get_mux6(parent, &osc_clk, &anaclk_1, &anaclk_2, + NULL, NULL, NULL); + reg |= mux << ANADIG_PLL_BYPASS_CLK_SRC_OFFSET; + __raw_writel(reg, pllbase); + + /* Set anaclk_x as input */ + if (parent == &anaclk_1) { + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= (ANATOP_LVDS_CLK1_IBEN_MASK & + ~ANATOP_LVDS_CLK1_OBEN_MASK); + __raw_writel(reg, ANADIG_MISC1_REG); + } else if (parent == &anaclk_2) { + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= (ANATOP_LVDS_CLK2_IBEN_MASK & + ~ANATOP_LVDS_CLK2_OBEN_MASK); + __raw_writel(reg, ANADIG_MISC1_REG); + } + + return 0; +} + +static struct clk pll4_audio_main_clk = { + __INIT_CLK_DEBUG(pll4_audio_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_audio_video_set_rate, + .get_rate = _clk_audio_video_get_rate, + .round_rate = _clk_audio_video_round_rate, + .set_parent = _clk_audio_video_set_parent, +}; + +static struct clk pll5_video_main_clk = { + __INIT_CLK_DEBUG(pll5_video_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_audio_video_set_rate, + .get_rate = _clk_audio_video_get_rate, + .round_rate = _clk_audio_video_round_rate, + .set_parent = _clk_audio_video_set_parent, +}; + +static int _clk_pll_mlb_main_enable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + reg &= ~ANADIG_PLL_BYPASS; + + reg = (0x3 << ANADIG_PLL_MLB_FLT_RES_CFG_OFFSET) | + (0x3 << ANADIG_PLL_MLB_RX_CLK_DELAY_CFG_OFFSET) | + (0x2 << ANADIG_PLL_MLB_VDDD_DELAY_CFG_OFFSET) | + (0x1 << ANADIG_PLL_MLB_VDDA_DELAY_CFG_OFFSET) | + (ANADIG_PLL_HOLD_RING_OFF); + __raw_writel(reg, pllbase); + + return 0; +} + +static void _clk_pll_mlb_main_disable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + + reg |= ANADIG_PLL_BYPASS; + + __raw_writel(reg, pllbase); +} + +static struct clk pll6_mlb150_main_clk = { + __INIT_CLK_DEBUG(pll6_mlb150_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_mlb_main_enable, + .disable = _clk_pll_mlb_main_disable, +}; + +static unsigned long _clk_pll7_usb_otg_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL7_480_USB2_BASE_ADDR) + & ANADIG_PLL_480_DIV_SELECT_MASK; + + if (div == 1) + val = clk_get_rate(clk->parent) * 22; + else + val = clk_get_rate(clk->parent) * 20; + return val; +} + +static int _clk_pll7_usb_otg_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate == 528000000) + div = 1; + else if (rate == 480000000) + div = 0; + else + return -EINVAL; + + reg = __raw_readl(PLL7_480_USB2_BASE_ADDR); + reg &= ~ANADIG_PLL_480_DIV_SELECT_MASK; + reg |= div; + __raw_writel(reg, PLL7_480_USB2_BASE_ADDR); + + return 0; +} + +static struct clk pll7_usb_host_main_clk = { + __INIT_CLK_DEBUG(pll7_usb_host_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll7_usb_otg_set_rate, + .get_rate = _clk_pll7_usb_otg_get_rate, + +}; + +static struct clk pll8_enet_main_clk = { + __INIT_CLK_DEBUG(pll8_enet_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +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_arm_set_rate(struct clk *clk, unsigned long rate) +{ + int i; + u32 div; + unsigned long parent_rate; + unsigned long flags; + unsigned long ipg_clk_rate, max_arm_wait_clk; + + for (i = 0; i < cpu_op_nr; i++) { + if (rate == cpu_op_tbl[i].cpu_rate) + break; + } + if (i >= cpu_op_nr) + return -EINVAL; + + spin_lock_irqsave(&clk_lock, flags); + + if (rate <= clk_get_rate(&pll2_pfd_400M)) { + /* Source pll1_sw_clk from step_clk which is sourced from + * PLL2_PFD_400M. + */ + if (pll1_sw_clk.parent != &pll2_pfd_400M) { + if (pll2_pfd_400M.usecount == 0) { + /* Check if PLL2 needs to be enabled also. */ + if (pll2_528_bus_main_clk.usecount == 0) + pll2_528_bus_main_clk.enable(&pll2_528_bus_main_clk); + /* Ensure parent usecount is + * also incremented. + */ + pll2_528_bus_main_clk.usecount++; + pll2_pfd_400M.enable(&pll2_pfd_400M); + } + pll2_pfd_400M.usecount++; + arm_needs_pll2_400 = true; + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd_400M); + pll1_sw_clk.parent = &pll2_pfd_400M; + } + } else { + /* Make sure PLL1 is enabled */ + if (!pll1_enabled) { + pll1_sys_main_clk.enable(&pll1_sys_main_clk); + pll1_sys_main_clk.usecount = 1; + } + /* Make sure PLL1 rate is what we want */ + if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) { + /* If pll1_sw_clk is from pll1_sys_main_clk, switch it */ + if (pll1_sw_clk.parent == &pll1_sys_main_clk) { + /* Change the PLL1 rate. */ + if (pll2_pfd_400M.usecount != 0) + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd_400M); + else + pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk); + } + pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate); + } + /* Make sure pll1_sw_clk is from pll1_sys_main_clk */ + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk); + pll1_sw_clk.parent = &pll1_sys_main_clk; + if (arm_needs_pll2_400) { + pll2_pfd_400M.usecount--; + if (pll2_pfd_400M.usecount == 0) { + pll2_pfd_400M.disable(&pll2_pfd_400M); + /* Ensure parent usecount is + * also decremented. + */ + pll2_528_bus_main_clk.usecount--; + if (pll2_528_bus_main_clk.usecount == 0) + pll2_528_bus_main_clk.disable(&pll2_528_bus_main_clk); + } + } + arm_needs_pll2_400 = false; + } + parent_rate = clk_get_rate(clk->parent); + div = parent_rate / rate; + /* Calculate the ARM_PODF to be applied when the system + * enters WAIT state. The max ARM clk is decided by the + * ipg_clk and has to follow the ratio of ARM_CLK:IPG_CLK of 12:5. + * For ex, when IPG is at 66MHz, ARM_CLK cannot be greater + * than 158MHz. + * Pre-calculate the optimal divider now. + */ + ipg_clk_rate = clk_get_rate(&ipg_clk); + max_arm_wait_clk = (12 * ipg_clk_rate) / 5; + wait_mode_arm_podf = parent_rate / max_arm_wait_clk; + + if (div == 0) + div = 1; + + if ((parent_rate / div) > rate) + div++; + + if (div > 8) { + spin_unlock_irqrestore(&clk_lock, flags); + return -1; + } + + cur_arm_podf = div; + + __raw_writel(div - 1, MXC_CCM_CACRR); + + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + + if (pll1_sys_main_clk.usecount == 1 && arm_needs_pll2_400) { + pll1_sys_main_clk.disable(&pll1_sys_main_clk); + pll1_sys_main_clk.usecount = 0; + } + + spin_unlock_irqrestore(&clk_lock, flags); + + return 0; +} + +static struct clk cpu_clk = { + __INIT_CLK_DEBUG(cpu_clk) + .parent = &pll1_sw_clk, + .set_rate = _clk_arm_set_rate, + .get_rate = _clk_arm_get_rate, +}; + +static unsigned long _clk_twd_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk twd_clk = { + __INIT_CLK_DEBUG(twd_clk) + .parent = &cpu_clk, + .get_rate = _clk_twd_get_rate, +}; + +static int _clk_periph_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + int mux; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, &pll2_pfd_400M, + &pll2_pfd_352M, &pll2_200M, &pll3_sw_clk, &osc_clk); + + if (mux <= 3) { + /* Set the pre_periph_clk multiplexer */ + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + /* Set the periph_clk_sel multiplexer. */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } else { + reg = __raw_readl(MXC_CCM_CBCDR); + /* Set the periph_clk2_podf divider to divide by 1. */ + reg &= ~MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK; + __raw_writel(reg, MXC_CCM_CBCDR); + + /* Set the periph_clk2_sel mux. */ + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK; + reg |= ((mux - 4) << MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + + reg = __raw_readl(MXC_CCM_CBCDR); + /* Set periph_clk_sel to select periph_clk2. */ + reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY), SPIN_DELAY)) + panic("_clk_periph_set_parent failed\n"); + + return 0; +} + +static unsigned long _clk_periph_get_rate(struct clk *clk) +{ + u32 div = 1; + u32 reg; + unsigned long val; + + if ((clk->parent == &pll3_sw_clk) || (clk->parent == &osc_clk)) { + reg = __raw_readl(MXC_CCM_CBCDR) + & MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK; + div = (reg >> MXC_CCM_CBCDR_PERIPH_CLK2_PODF_OFFSET) + 1; + } + val = clk_get_rate(clk->parent) / div; + return val; +} + +static struct clk periph_clk = { + __INIT_CLK_DEBUG(periph_clk) + .parent = &pll2_528_bus_main_clk, + .set_parent = _clk_periph_set_parent, + .get_rate = _clk_periph_get_rate, +}; + +static unsigned long _clk_axi_get_rate(struct clk *clk) +{ + u32 div, reg; + unsigned long val; + + reg = __raw_readl(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_AXI_PODF_MASK; + div = (reg >> MXC_CCM_CBCDR_AXI_PODF_OFFSET); + + val = clk_get_rate(clk->parent) / (div + 1); + return val; +} + +static int _clk_axi_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_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_AXI_PODF_BUSY), SPIN_DELAY)) + panic("pll _clk_axi_a_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_axi_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 int _clk_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + int mux; + + mux = _get_mux6(parent, &periph_clk, &pll2_pfd_400M, + &pll3_pfd_540M, NULL, NULL, NULL); + + if (mux == 0) { + /* Set the AXI_SEL mux */ + reg = __raw_readl(MXC_CCM_CBCDR) & ~MXC_CCM_CBCDR_AXI_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } else { + /* Set the AXI_ALT_SEL mux. */ + reg = __raw_readl(MXC_CCM_CBCDR) + & ~MXC_CCM_CBCDR_AXI_ALT_SEL_MASK; + reg |= ((mux - 1) << MXC_CCM_CBCDR_AXI_ALT_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + /* Set the AXI_SEL mux */ + reg = __raw_readl(MXC_CCM_CBCDR) & ~MXC_CCM_CBCDR_AXI_SEL; + reg |= MXC_CCM_CBCDR_AXI_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } + return 0; +} + +static struct clk axi_clk = { + __INIT_CLK_DEBUG(axi_clk) + .parent = &periph_clk, + .set_parent = _clk_axi_set_parent, + .set_rate = _clk_axi_set_rate, + .get_rate = _clk_axi_get_rate, + .round_rate = _clk_axi_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; + 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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk ahb_clk = { + __INIT_CLK_DEBUG(ahb_clk) + .parent = &periph_clk, + .get_rate = _clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, +}; + +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 struct clk tzasc1_clk = { + __INIT_CLK_DEBUG(tzasc1_clk) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk tzasc2_clk = { + __INIT_CLK_DEBUG(tzasc2_clk) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk mx6fast1_clk = { + __INIT_CLK_DEBUG(mx6fast1_clk) + .id = 0, + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk mx6per1_clk = { + __INIT_CLK_DEBUG(mx6per1_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &mx6fast1_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk mx6per2_clk = { + __INIT_CLK_DEBUG(mx6per2_clk) + .id = 0, + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static unsigned long _clk_mmdc_ch0_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >> + MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_mmdc_ch0_axi_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_MMDC_CH0_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_MMDC_CH0_PODF_BUSY), + SPIN_DELAY)) + panic("_clk_mmdc_ch0_axi_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_mmdc_ch0_axi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk mmdc_ch0_axi_clk[] = { + { + __INIT_CLK_DEBUG(mmdc_ch0_axi_clk) + .id = 0, + .parent = &periph_clk, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .secondary = &mmdc_ch0_axi_clk[1], + .get_rate = _clk_mmdc_ch0_axi_get_rate, + .set_rate = _clk_mmdc_ch0_axi_set_rate, + .round_rate = _clk_mmdc_ch0_axi_round_rate, + }, + { + __INIT_CLK_DEBUG(mmdc_ch0_ipg_clk) + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .secondary = &tzasc1_clk, + }, +}; + +static unsigned long _clk_mmdc_ch1_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK) >> + MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_mmdc_ch1_axi_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_MMDC_CH1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_MMDC_CH1_PODF_BUSY), SPIN_DELAY)) + panic("_clk_mmdc_ch1_axi_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_mmdc_ch1_axi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk mmdc_ch1_axi_clk[] = { + { + __INIT_CLK_DEBUG(mmdc_ch1_axi_clk) + .id = 0, + .parent = &pll2_pfd_400M, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .secondary = &mmdc_ch1_axi_clk[1], + .get_rate = _clk_mmdc_ch1_axi_get_rate, + .set_rate = _clk_mmdc_ch1_axi_set_rate, + .round_rate = _clk_mmdc_ch1_axi_round_rate, + }, + { + .id = 1, + __INIT_CLK_DEBUG(mmdc_ch1_ipg_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .secondary = &tzasc2_clk, + }, +}; + +static struct clk ocram_clk = { + __INIT_CLK_DEBUG(ocram_clk) + .id = 0, + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static unsigned long _clk_ipg_perclk_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + div = ((reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK) >> + MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipg_perclk_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 > 64)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_PERCLK_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET; + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + + +static unsigned long _clk_ipg_perclk_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 (div > 64) + div = 64; + + return parent_rate / div; +} + +static struct clk ipg_perclk = { + __INIT_CLK_DEBUG(ipg_perclk) + .parent = &ipg_clk, + .get_rate = _clk_ipg_perclk_get_rate, + .set_rate = _clk_ipg_perclk_set_rate, + .round_rate = _clk_ipg_perclk_round_rate, +}; + +static struct clk spba_clk = { + __INIT_CLK_DEBUG(spba_clk) + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk sdma_clk[] = { + { + __INIT_CLK_DEBUG(sdma_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &sdma_clk[1], + }, + { + .parent = &mx6per1_clk, +#ifdef CONFIG_SDMA_IRAM + .secondary = &ocram_clk, +#else + .secondary = &mmdc_ch0_axi_clk[0], +#endif + }, +}; + +static int _clk_gpu2d_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_GPU2D_AXI_CLK_SEL; + + if (parent == &ahb_clk) + reg |= MXC_CCM_CBCMR_GPU2D_AXI_CLK_SEL; + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu2d_axi_clk = { + __INIT_CLK_DEBUG(gpu2d_axi_clk) + .parent = &axi_clk, + .set_parent = _clk_gpu2d_axi_set_parent, +}; + +static int _clk_gpu3d_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_GPU3D_AXI_CLK_SEL; + + if (parent == &ahb_clk) + reg |= MXC_CCM_CBCMR_GPU3D_AXI_CLK_SEL; + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu3d_axi_clk = { + __INIT_CLK_DEBUG(gpu3d_axi_clk) + .parent = &axi_clk, + .secondary = &mmdc_ch0_axi_clk[0], + .set_parent = _clk_gpu3d_axi_set_parent, +}; + +static int _clk_pcie_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL; + + if (parent == &ahb_clk) + reg |= MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL; + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk pcie_axi_clk = { + __INIT_CLK_DEBUG(pcie_axi_clk) + .parent = &axi_clk, + .set_parent = _clk_pcie_axi_set_parent, +}; + +static int _clk_vdo_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CBCMR) & ~MXC_CCM_CBCMR_VDOAXI_CLK_SEL; + + if (parent == &ahb_clk) + reg |= MXC_CCM_CBCMR_VDOAXI_CLK_SEL; + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk vdo_axi_clk = { + __INIT_CLK_DEBUG(vdo_axi_clk) + .parent = &axi_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_vdo_axi_set_parent, +}; + +static struct clk vdoa_clk[] = { + { + __INIT_CLK_DEBUG(vdoa_clk) + .id = 0, + .parent = &vdo_axi_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &vdoa_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &vdoa_clk[2], + }, + { + .parent = &mx6fast1_clk, + .secondary = &ocram_clk, + }, +}; + +static unsigned long mx6_timer_rate(void) +{ + u32 parent_rate = clk_get_rate(&osc_clk); + + u32 reg = __raw_readl(timer_base + MXC_TCTL); + u32 div; + + if ((reg & V2_TCTL_CLK_OSC_DIV8) == V2_TCTL_CLK_OSC_DIV8) { + if (cpu_is_mx6q()) + /* For MX6Q, only options are 24MHz or 24MHz/8*/ + return parent_rate / 8; + else { + /* For MX6DLS and MX6Solo, the rate is based on the + * divider value set in prescalar register. */ + div = __raw_readl(timer_base + MXC_TPRER); + div = (div >> V2_TPRER_PRE24M_OFFSET) & + V2_TPRER_PRE24M_MASK; + return parent_rate / (div + 1); + } + } + return 0; +} + +static unsigned long _clk_gpt_get_rate(struct clk *clk) +{ + unsigned long rate; + + if (mx6q_revision() == IMX_CHIP_REVISION_1_0) + return clk_get_rate(clk->parent); + + rate = mx6_timer_rate(); + if (!rate) + return clk_get_rate(clk->parent); + + return rate; +} + +static struct clk gpt_clk[] = { + { + __INIT_CLK_DEBUG(gpt_clk) + .parent = &osc_clk, + .id = 0, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .get_rate = _clk_gpt_get_rate, + .secondary = &gpt_clk[1], + }, + { + __INIT_CLK_DEBUG(gpt_serial_clk) + .id = 0, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_iim_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent); +} + +static struct clk iim_clk = { + __INIT_CLK_DEBUG(iim_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + .get_rate = _clk_iim_get_rate, +}; + +static struct clk i2c_clk[] = { + { + __INIT_CLK_DEBUG(i2c_clk_0) + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_1) + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_2) + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static int _clk_vpu_axi_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CBCMR) + & ~MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK; + + mux = _get_mux6(parent, &axi_clk, &pll2_pfd_400M, + &pll2_pfd_352M, NULL, NULL, NULL); + + reg |= (mux << MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static unsigned long _clk_vpu_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_VPU_AXI_PODF_MASK) >> + MXC_CCM_CSCDR1_VPU_AXI_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_vpu_axi_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_VPU_AXI_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_VPU_AXI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static unsigned long _clk_vpu_axi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk vpu_clk[] = { + { + __INIT_CLK_DEBUG(vpu_clk) + .parent = &axi_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_vpu_axi_set_parent, + .round_rate = _clk_vpu_axi_round_rate, + .set_rate = _clk_vpu_axi_set_rate, + .get_rate = _clk_vpu_axi_get_rate, + .secondary = &vpu_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &vpu_clk[2], + }, + { + .parent = &mx6fast1_clk, + .secondary = &ocram_clk, + }, +}; + +static int _clk_ipu1_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCDR3) + & ~MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll2_pfd_400M, &pll3_120M, &pll3_pfd_540M, NULL, NULL); + + reg |= (mux << MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static unsigned long _clk_ipu1_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR3); + div = ((reg & MXC_CCM_CSCDR3_IPU1_HSP_PODF_MASK) >> + MXC_CCM_CSCDR3_IPU1_HSP_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu1_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_CSCDR3); + reg &= ~MXC_CCM_CSCDR3_IPU1_HSP_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR3_IPU1_HSP_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static unsigned long _clk_ipu_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk ipu1_clk = { + __INIT_CLK_DEBUG(ipu1_clk) + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mmdc_ch0_axi_clk[0], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu1_set_parent, + .round_rate = _clk_ipu_round_rate, + .set_rate = _clk_ipu1_set_rate, + .get_rate = _clk_ipu1_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_ipu2_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCDR3) + & ~MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll2_pfd_400M, &pll3_120M, &pll3_pfd_540M, NULL, NULL); + + reg |= (mux << MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static unsigned long _clk_ipu2_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR3); + div = ((reg & MXC_CCM_CSCDR3_IPU2_HSP_PODF_MASK) >> + MXC_CCM_CSCDR3_IPU2_HSP_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu2_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_CSCDR3); + reg &= ~MXC_CCM_CSCDR3_IPU2_HSP_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR3_IPU2_HSP_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static struct clk ipu2_clk = { + __INIT_CLK_DEBUG(ipu2_clk) + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mmdc_ch0_axi_clk[0], + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu2_set_parent, + .round_rate = _clk_ipu_round_rate, + .set_rate = _clk_ipu2_set_rate, + .get_rate = _clk_ipu2_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk usdhc_dep_clk = { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6per1_clk, + }; + +static unsigned long _clk_usdhc_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_usdhc1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC1_CLK_SEL; + + if (parent == &pll2_pfd_352M) + reg |= (MXC_CCM_CSCMR1_USDHC1_CLK_SEL); + + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc1_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc1_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk usdhc1_clk = { + __INIT_CLK_DEBUG(usdhc1_clk) + .id = 0, + .parent = &pll2_pfd_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc1_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc1_set_rate, + .get_rate = _clk_usdhc1_get_rate, +}; + +static int _clk_usdhc2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC2_CLK_SEL; + + if (parent == &pll2_pfd_352M) + reg |= (MXC_CCM_CSCMR1_USDHC2_CLK_SEL); + + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc2_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc2_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC2_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk usdhc2_clk = { + __INIT_CLK_DEBUG(usdhc2_clk) + .id = 1, + .parent = &pll2_pfd_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc2_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc2_set_rate, + .get_rate = _clk_usdhc2_get_rate, +}; + +static int _clk_usdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC3_CLK_SEL; + + if (parent == &pll2_pfd_352M) + reg |= (MXC_CCM_CSCMR1_USDHC3_CLK_SEL); + + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc3_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc3_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC3_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + + +static struct clk usdhc3_clk = { + __INIT_CLK_DEBUG(usdhc3_clk) + .id = 2, + .parent = &pll2_pfd_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc3_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc3_set_rate, + .get_rate = _clk_usdhc3_get_rate, +}; + +static int _clk_usdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC4_CLK_SEL; + + if (parent == &pll2_pfd_352M) + reg |= (MXC_CCM_CSCMR1_USDHC4_CLK_SEL); + + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc4_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc4_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC4_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + + +static struct clk usdhc4_clk = { + __INIT_CLK_DEBUG(usdhc4_clk) + .id = 3, + .parent = &pll2_pfd_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc4_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc4_set_rate, + .get_rate = _clk_usdhc4_get_rate, +}; + +static unsigned long _clk_ssi_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(1 << 6, div, &pre, &post); + + return parent_rate / (pre * post); +} + +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; + 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_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK | + MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + + +static int _clk_ssi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1) + & ~MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd_508M, &pll3_pfd_454M, + &pll4_audio_main_clk, NULL, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi1_clk = { + __INIT_CLK_DEBUG(ssi1_clk) + .parent = &pll3_pfd_508M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ssi1_set_parent, + .set_rate = _clk_ssi1_set_rate, + .round_rate = _clk_ssi_round_rate, + .get_rate = _clk_ssi1_get_rate, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &ocram_clk, +#else + .secondary = &mmdc_ch0_axi_clk[0], +#endif + .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +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; + 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_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~(MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK | + MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS2CDR); + + return 0; +} + + +static int _clk_ssi2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1) + & ~MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd_508M, &pll3_pfd_454M, + &pll4_audio_main_clk, NULL, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi2_clk = { + __INIT_CLK_DEBUG(ssi2_clk) + .parent = &pll3_pfd_508M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ssi2_set_parent, + .set_rate = _clk_ssi2_set_rate, + .round_rate = _clk_ssi_round_rate, + .get_rate = _clk_ssi2_get_rate, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &ocram_clk, +#else + .secondary = &mmdc_ch0_axi_clk[0], +#endif + .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_ssi3_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; + 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_ssi3_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI3_CLK_PODF_MASK| + MXC_CCM_CS1CDR_SSI3_CLK_PRED_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI3_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI3_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + + +static int _clk_ssi3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI3_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd_508M, &pll3_pfd_454M, + &pll4_audio_main_clk, NULL, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_SSI3_CLK_SEL_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi3_clk = { + __INIT_CLK_DEBUG(ssi3_clk) + .parent = &pll3_pfd_508M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ssi3_set_parent, + .set_rate = _clk_ssi3_set_rate, + .round_rate = _clk_ssi_round_rate, + .get_rate = _clk_ssi3_get_rate, +#ifdef CONFIG_SND_MXC_SOC_IRAM + .secondary = &ocram_clk, +#else + .secondary = &mmdc_ch0_axi_clk[0], +#endif + .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +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 unsigned long _clk_ldb_di0_get_rate(struct clk *clk) +{ + u32 div; + + div = __raw_readl(MXC_CCM_CSCMR2) & + MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV; + + if (div) + return clk_get_rate(clk->parent) / 7; + + return (2 * clk_get_rate(clk->parent)) / 7; +} + +static int _clk_ldb_di0_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 |= MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV; + else + reg &= ~MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV; + + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static int _clk_ldb_di0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + int rev = mx6q_revision(); + + reg = __raw_readl(MXC_CCM_CS2CDR) + & ~MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll5_video_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, + (rev == IMX_CHIP_REVISION_1_0) ? + &pll3_pfd_540M : /* MX6Q TO1.0 */ + &mmdc_ch1_axi_clk[0], /* MX6Q TO1.1 and MX6DL */ + &pll3_usb_otg_main_clk, NULL); + reg |= (mux << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CS2CDR); + + return 0; +} + +static struct clk ldb_di0_clk = { + __INIT_CLK_DEBUG(ldb_di0_clk) + .id = 0, + .parent = &pll2_pfd_352M, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ldb_di0_set_parent, + .set_rate = _clk_ldb_di0_set_rate, + .round_rate = _clk_ldb_di_round_rate, + .get_rate = _clk_ldb_di0_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_ldb_di1_get_rate(struct clk *clk) +{ + u32 div; + + 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 int _clk_ldb_di1_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 |= MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV; + else + reg &= ~MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV; + + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static int _clk_ldb_di1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + int rev = mx6q_revision(); + + reg = __raw_readl(MXC_CCM_CS2CDR) + & ~MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll5_video_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, + (rev == IMX_CHIP_REVISION_1_0) ? + &pll3_pfd_540M : /* MX6Q TO1.0 */ + &mmdc_ch1_axi_clk[0], /* MX6Q TO1.1 and MX6DL */ + &pll3_usb_otg_main_clk, NULL); + reg |= (mux << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CS2CDR); + + return 0; +} + +static struct clk ldb_di1_clk = { + __INIT_CLK_DEBUG(ldb_di1_clk) + .id = 0, + .parent = &pll2_pfd_352M, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ldb_di1_set_parent, + .set_rate = _clk_ldb_di1_set_rate, + .round_rate = _clk_ldb_di_round_rate, + .get_rate = _clk_ldb_di1_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + + +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_di0_clk) || + (clk->parent == &ldb_di1_clk)) + return parent_rate; + + div = parent_rate / rate; + /* Round to closest divisor */ + if ((parent_rate % rate) > (rate / 2)) + div++; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + +static unsigned long _clk_ipu1_di0_get_rate(struct clk *clk) +{ + u32 reg, div; + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) + return clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CHSCCDR); + + div = ((reg & MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK) >> + MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu1_di0_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) { + if (parent_rate == rate) + return 0; + else + return -EINVAL; + } + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CHSCCDR); + reg &= ~MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CHSCCDR); + + return 0; +} + + +static int _clk_ipu1_di0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (parent == &ldb_di0_clk) + mux = 0x3; + else if (parent == &ldb_di1_clk) + mux = 0x4; + else { + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, &pll3_pfd_540M); + reg |= (mux << MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CHSCCDR); + + /* Derive clock from divided pre-muxed ipu1_di0 clock.*/ + mux = 0; + } + + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET), + MXC_CCM_CHSCCDR); + + return 0; +} + +static unsigned long _clk_ipu1_di1_get_rate(struct clk *clk) +{ + u32 reg, div; + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) + return clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CHSCCDR); + + div = ((reg & MXC_CCM_CHSCCDR_IPU1_DI1_PODF_MASK) + >> MXC_CCM_CHSCCDR_IPU1_DI1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu1_di1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) { + if (parent_rate == rate) + return 0; + else + return -EINVAL; + } + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CHSCCDR); + reg &= ~MXC_CCM_CHSCCDR_IPU1_DI1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CHSCCDR_IPU1_DI1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CHSCCDR); + + return 0; +} + + +static int _clk_ipu1_di1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (parent == &ldb_di0_clk) + mux = 0x3; + else if (parent == &ldb_di1_clk) + mux = 0x4; + else { + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, &pll3_pfd_540M); + reg |= (mux << MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CHSCCDR); + + /* Derive clock from divided pre-muxed ipu1_di0 clock.*/ + mux = 0; + } + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_OFFSET), + MXC_CCM_CHSCCDR); + + return 0; +} + +static struct clk ipu1_di_clk[] = { + { + __INIT_CLK_DEBUG(ipu1_di_clk_0) + .id = 0, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu1_di0_set_parent, + .set_rate = _clk_ipu1_di0_set_rate, + .round_rate = _clk_ipu_di_round_rate, + .get_rate = _clk_ipu1_di0_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(ipu1_di_clk_1) + .id = 1, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu1_di1_set_parent, + .set_rate = _clk_ipu1_di1_set_rate, + .round_rate = _clk_ipu_di_round_rate, + .get_rate = _clk_ipu1_di1_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, +}; + +static unsigned long _clk_ipu2_di0_get_rate(struct clk *clk) +{ + u32 reg, div; + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) + return clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCDR2); + + div = ((reg & MXC_CCM_CSCDR2_IPU2_DI0_PODF_MASK) >> + MXC_CCM_CSCDR2_IPU2_DI0_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu2_di0_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) { + if (parent_rate == rate) + return 0; + else + return -EINVAL; + } + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~MXC_CCM_CSCDR2_IPU2_DI0_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR2_IPU2_DI0_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static int _clk_ipu2_di0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (parent == &ldb_di0_clk) + mux = 0x3; + else if (parent == &ldb_di1_clk) + mux = 0x4; + else { + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, &pll3_pfd_540M); + reg |= (mux << MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR2); + + /* Derive clock from divided pre-muxed ipu2_di0 clock.*/ + mux = 0; + } + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_OFFSET), + MXC_CCM_CSCDR2); + + return 0; +} + +static unsigned long _clk_ipu2_di1_get_rate(struct clk *clk) +{ + u32 reg, div; + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) + return clk_get_rate(clk->parent); + + reg = __raw_readl(MXC_CCM_CSCDR2); + + div = ((reg & MXC_CCM_CSCDR2_IPU2_DI1_PODF_MASK) + >> MXC_CCM_CSCDR2_IPU2_DI1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu2_di1_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div; + u32 parent_rate = clk_get_rate(clk->parent); + + if ((clk->parent == &ldb_di0_clk) || + (clk->parent == &ldb_di1_clk)) { + if (parent_rate == rate) + return 0; + else + return -EINVAL; + } + + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~MXC_CCM_CSCDR2_IPU2_DI1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR2_IPU2_DI1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static int _clk_ipu2_di1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + if (parent == &ldb_di0_clk) + mux = 0x3; + else if (parent == &ldb_di1_clk) + mux = 0x4; + else { + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, &pll3_pfd_540M); + reg |= (mux << MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR2); + + /* Derive clock from divided pre-muxed ipu1_di0 clock.*/ + mux = 0; + } + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI1_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CSCDR2_IPU2_DI1_CLK_SEL_OFFSET), + MXC_CCM_CSCDR2); + + return 0; +} + +static struct clk ipu2_di_clk[] = { + { + __INIT_CLK_DEBUG(ipu2_di_clk_0) + .id = 0, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu2_di0_set_parent, + .set_rate = _clk_ipu2_di0_set_rate, + .round_rate = _clk_ipu_di_round_rate, + .get_rate = _clk_ipu2_di0_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(ipu2_di_clk_1) + .id = 1, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu2_di1_set_parent, + .set_rate = _clk_ipu2_di1_set_rate, + .round_rate = _clk_ipu_di_round_rate, + .get_rate = _clk_ipu2_di1_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, +}; + +static unsigned long _clk_can_root_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 (div > 64) + div = 64; + + return parent_rate / div; +} + +static int _clk_can_root_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 > 64)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCMR2) & MXC_CCM_CSCMR2_CAN_CLK_PODF_MASK; + reg |= ((div - 1) << MXC_CCM_CSCMR2_CAN_CLK_PODF_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_can_root_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long val; + + reg = __raw_readl(MXC_CCM_CSCMR2) & MXC_CCM_CSCMR2_CAN_CLK_PODF_MASK; + div = (reg >> MXC_CCM_CSCMR2_CAN_CLK_PODF_OFFSET) + 1; + val = clk_get_rate(clk->parent) / div; + + return val; +} + +static struct clk can_clk_root = { + __INIT_CLK_DEBUG(can_clk_root) + .parent = &pll3_60M, + .set_rate = _clk_can_root_set_rate, + .get_rate = _clk_can_root_get_rate, + .round_rate = _clk_can_root_round_rate, +}; + +static struct clk can2_clk[] = { + { + __INIT_CLK_DEBUG(can2_module_clk) + .id = 0, + .parent = &can_clk_root, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &can2_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(can2_serial_clk) + .id = 1, + .parent = &can_clk_root, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + + +static struct clk can1_clk[] = { + { + __INIT_CLK_DEBUG(can1_module_clk) + .id = 0, + .parent = &can_clk_root, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &can1_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(can1_serial_clk) + .id = 1, + .parent = &can_clk_root, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_spdif_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(1 << 3, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_spdif0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CDCDR) + & ~MXC_CCM_CDCDR_SPDIF0_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll4_audio_main_clk, + &pll3_pfd_508M, &pll3_pfd_454M, + &pll3_sw_clk, NULL, NULL); + reg |= mux << MXC_CCM_CDCDR_SPDIF0_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static unsigned long _clk_spdif0_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + 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; + + return clk_get_rate(clk->parent) / (pred * podf); +} + +static int _clk_spdif0_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 > 64) + return -EINVAL; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~(MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK| + MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static struct clk spdif0_clk[] = { + { + __INIT_CLK_DEBUG(spdif0_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &spdif0_clk[1], + .set_rate = _clk_spdif0_set_rate, + .get_rate = _clk_spdif0_get_rate, + .set_parent = _clk_spdif0_set_parent, + .round_rate = _clk_spdif_round_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(spdif0_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &spba_clk, + }, +}; + +static unsigned long _clk_esai_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(1 << 3, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_esai_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_ESAI_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll4_audio_main_clk, &pll3_pfd_508M, + &pll3_pfd_454M, &pll3_sw_clk, NULL, NULL); + reg |= mux << MXC_CCM_CSCMR2_ESAI_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_esai_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + + 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); +} + +static int _clk_esai_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 > 64) + return -EINVAL; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK| + MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static struct clk esai_clk = { + __INIT_CLK_DEBUG(esai_clk) + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_rate = _clk_esai_set_rate, + .get_rate = _clk_esai_get_rate, + .set_parent = _clk_esai_set_parent, + .round_rate = _clk_esai_round_rate, +}; + +static int _clk_enet_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div = 1; + + switch (rate) { + case 25000000: + div = 0; + break; + case 50000000: + div = 1; + break; + case 100000000: + div = 2; + break; + case 125000000: + div = 3; + break; + default: + return -EINVAL; + } + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_ENET_DIV_SELECT_MASK; + reg |= (div << ANADIG_PLL_ENET_DIV_SELECT_OFFSET); + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + return 0; +} + +static unsigned long _clk_enet_get_rate(struct clk *clk) +{ + unsigned int div; + + div = (__raw_readl(PLL8_ENET_BASE_ADDR)) + & ANADIG_PLL_ENET_DIV_SELECT_MASK; + + switch (div) { + case 0: + div = 20; + break; + case 1: + div = 10; + break; + case 3: + div = 5; + break; + case 4: + div = 4; + break; + } + + return 500000000 / div; +} + +static int _clk_enet_enable(struct clk *clk) +{ +#ifndef CONFIG_MX6_ENET_IRQ_TO_GPIO + enet_is_active = true; +#endif + _clk_enable(clk); + return 0; +} + +static void _clk_enet_disable(struct clk *clk) +{ + _clk_disable(clk); +#ifndef CONFIG_MX6_ENET_IRQ_TO_GPIO + enet_is_active = false; +#endif +} + +static struct clk enet_clk[] = { + { + __INIT_CLK_DEBUG(enet_clk) + .id = 0, + .parent = &pll8_enet_main_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enet_enable, + .disable = _clk_enet_disable, + .set_rate = _clk_enet_set_rate, + .get_rate = _clk_enet_get_rate, + .secondary = &enet_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6per1_clk, + }, +}; + +static unsigned long _clk_enet_mdc_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent); +} + +static struct clk enet_mdc_clk = { + __INIT_CLK_DEBUG(enet_mdc_clk) + .parent = &ipg_clk, + .get_rate = _clk_enet_mdc_get_rate, +}; + +static struct clk ecspi_clk[] = { + { + __INIT_CLK_DEBUG(ecspi0_clk) + .id = 0, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ecspi1_clk) + .id = 1, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ecspi2_clk) + .id = 2, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ecspi3_clk) + .id = 3, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(ecspi4_clk) + .id = 4, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_emi_slow_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCMR1) + & ~MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK; + + mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk, + &pll2_pfd_400M, &pll2_pfd_352M, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_emi_slow_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + div = ((reg & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK) >> + MXC_CCM_CSCMR1_ACLK_EMI_SLOW_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; + 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_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET; + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk emi_slow_clk = { + __INIT_CLK_DEBUG(emi_slow_clk) + .id = 0, + .parent = &axi_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_rate = _clk_emi_slow_set_rate, + .get_rate = _clk_emi_slow_get_rate, + .round_rate = _clk_emi_slow_round_rate, + .set_parent = _clk_emi_slow_set_parent, +}; + +static unsigned long _clk_emi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_emi_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_ACLK_EMI_MASK; + + /*mux = _get_mux6(parent, &pll2_pfd_400M, &pll3_usb_otg_main_clk, + &axi_clk, &pll2_pfd_352M, NULL, NULL);*/ + mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk, + &pll2_pfd_400M, &pll2_pfd_352M, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_ACLK_EMI_OFFSET); + /* aclk_podf fixup */ + reg ^= 0x00600000; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_emi_get_rate(struct clk *clk) +{ + u32 reg, div; + + /* ACLK_EMI_PODF read value matches with real divider value */ + reg = __raw_readl(MXC_CCM_CSCMR1); + div = ((reg & MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK) >> + MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_emi_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; + + /* + * This is a software workaround for ACLK_EMI_PODF SoC + * implementation bug. The write/read/divider values + * have the relationship described by the following table: + * + * write value read value description + * 3b'000 3b'110 divided by 7 + * 3b'001 3b'111 divided by 8 + * 3b'010 3b'100 divided by 5 + * 3b'011 3b'101 divided by 6 + * 3b'100 3b'010 divided by 3 + * 3b'101 3b'011 divided by 4 + * 3b'110 3b'000 divided by 1 + * 3b'111 3b'001 divided by 2(default) + * + * That's why we do the xor operation below. + */ + reg = __raw_readl(MXC_CCM_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK; + reg |= ((div - 1)^0x6) << MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk emi_clk = { + __INIT_CLK_DEBUG(emi_clk) + .id = 0, + .parent = &axi_clk, + .set_rate = _clk_emi_set_rate, + .get_rate = _clk_emi_get_rate, + .round_rate = _clk_emi_round_rate, + .set_parent = _clk_emi_set_parent, +}; + +static unsigned long _clk_enfc_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(1 << 6, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_enfc_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CS2CDR) + & ~MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_pfd_352M, + &pll2_528_bus_main_clk, &pll3_usb_otg_main_clk, + &pll2_pfd_400M, NULL, NULL); + reg |= mux << MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CS2CDR); + + return 0; +} + +static unsigned long _clk_enfc_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CS2CDR); + + pred = ((reg & MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK) + >> MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET) + 1; + podf = ((reg & MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK) + >> MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (pred * podf); +} + +static int _clk_enfc_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~(MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK| + MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS2CDR); + + return 0; +} + +static struct clk enfc_clk = { + __INIT_CLK_DEBUG(enfc_clk) + .id = 0, + .parent = &pll2_pfd_352M, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_rate = _clk_enfc_set_rate, + .get_rate = _clk_enfc_get_rate, + .round_rate = _clk_enfc_round_rate, + .set_parent = _clk_enfc_set_parent, +}; + +static unsigned long _clk_uart_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 (div > 64) + div = 64; + + return parent_rate / div; +} + +static int _clk_uart_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 > 64)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCDR1) & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg |= ((div - 1) << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static unsigned long _clk_uart_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long val; + + reg = __raw_readl(MXC_CCM_CSCDR1) & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + div = (reg >> MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1; + val = clk_get_rate(clk->parent) / div; + + return val; +} + +static struct clk uart_clk[] = { + { + __INIT_CLK_DEBUG(uart_clk) + .id = 0, + .parent = &pll3_80M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &uart_clk[1], + .set_rate = _clk_uart_set_rate, + .get_rate = _clk_uart_get_rate, + .round_rate = _clk_uart_round_rate, + }, + { + __INIT_CLK_DEBUG(uart_serial_clk) + .id = 1, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static unsigned long _clk_hsi_tx_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_hsi_tx_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CDCDR) & ~MXC_CCM_CDCDR_HSI_TX_CLK_SEL; + + if (parent == &pll2_pfd_400M) + reg |= (MXC_CCM_CDCDR_HSI_TX_CLK_SEL); + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static unsigned long _clk_hsi_tx_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CDCDR); + div = ((reg & MXC_CCM_CDCDR_HSI_TX_PODF_MASK) >> + MXC_CCM_CDCDR_HSI_TX_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_hsi_tx_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_CDCDR); + reg &= ~MXC_CCM_CDCDR_HSI_TX_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CDCDR_HSI_TX_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static struct clk hsi_tx_clk[] = { + { + __INIT_CLK_DEBUG(hsi_tx_clk) + .id = 0, + .parent = &pll2_pfd_400M, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_hsi_tx_set_parent, + .round_rate = _clk_hsi_tx_round_rate, + .set_rate = _clk_hsi_tx_set_rate, + .get_rate = _clk_hsi_tx_get_rate, + .secondary = &hsi_tx_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mx6per1_clk, + .secondary = &mx6per2_clk, + }, +}; + +static struct clk mipi_pllref_clk = { + __INIT_CLK_DEBUG(mipi_pllref_clk) + .id = 0, + .parent = &pll3_pfd_540M, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk hdmi_clk[] = { + { + __INIT_CLK_DEBUG(hdmi_isfr_clk) + .id = 0, + .parent = &pll3_pfd_540M, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(hdmi_iahb_clk) + .id = 1, + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk caam_clk[] = { + { + __INIT_CLK_DEBUG(caam_mem_clk) + .id = 0, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &caam_clk[1], + }, + { + __INIT_CLK_DEBUG(caam_aclk_clk) + .id = 1, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &caam_clk[2], + }, + { + __INIT_CLK_DEBUG(caam_ipg_clk) + .id = 2, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6per1_clk, + }, +}; + +static int _clk_asrc_serial_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CDCDR) & ~MXC_CCM_CDCDR_SPDIF1_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll4_audio_main_clk, &pll3_pfd_508M, + &pll3_pfd_454M, &pll3_sw_clk, NULL, NULL); + reg |= mux << MXC_CCM_CDCDR_SPDIF1_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static unsigned long _clk_asrc_serial_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + 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; + + return clk_get_rate(clk->parent) / (pred * podf); +} + +static int _clk_asrc_serial_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 > 64) + return -EINVAL; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~(MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK| + MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static unsigned long _clk_asrc_serial_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(1 << 3, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static struct clk asrc_clk[] = { + { + __INIT_CLK_DEBUG(asrc_clk) + .id = 0, + .parent = &pll4_audio_main_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &spba_clk, + }, + { + /*In the MX6 spec, asrc_serial_clk is listed as SPDIF1 clk + * This clock can never be gated and does not have any + * CCGR bits associated with it. + */ + __INIT_CLK_DEBUG(asrc_serial_clk) + .id = 1, + .parent = &pll3_sw_clk, + .set_rate = _clk_asrc_serial_set_rate, + .get_rate = _clk_asrc_serial_get_rate, + .set_parent = _clk_asrc_serial_set_parent, + .round_rate = _clk_asrc_serial_round_rate, + }, +}; + +static struct clk apbh_dma_clk = { + __INIT_CLK_DEBUG(apbh_dma_clk) + .parent = &usdhc3_clk, + .secondary = &mx6per1_clk, + .enable = _clk_enable, + .disable = _clk_disable_inwait, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, +}; + +static struct clk aips_tz2_clk = { + __INIT_CLK_DEBUG(aips_tz2_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz1_clk = { + __INIT_CLK_DEBUG(aips_tz1_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + + +static struct clk openvg_axi_clk = { + __INIT_CLK_DEBUG(openvg_axi_clk) + .parent = &gpu2d_axi_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_gpu3d_core_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_gpu3d_core_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CBCMR) + & ~MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll3_usb_otg_main_clk, + &pll2_pfd_594M, &pll2_pfd_400M, NULL, NULL); + reg |= (mux << MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static unsigned long _clk_gpu3d_core_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCMR); + div = ((reg & MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK) >> + MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_gpu3d_core_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 (div > 8) + div = 8; + + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu3d_core_clk[] = { + { + __INIT_CLK_DEBUG(gpu3d_core_clk) + .parent = &pll2_pfd_594M, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .set_parent = _clk_gpu3d_core_set_parent, + .set_rate = _clk_gpu3d_core_set_rate, + .get_rate = _clk_gpu3d_core_get_rate, + .round_rate = _clk_gpu3d_core_round_rate, + .secondary = &gpu3d_core_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &gpu3d_axi_clk, + .secondary = &mx6fast1_clk, + }, +}; + +static unsigned long _clk_gpu2d_core_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_gpu2d_core_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CBCMR) & + ~MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK; + + /*on mx6dl, 2d core clock sources from 3d shader core clock*/ + if (!cpu_is_mx6dl()) { + mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk, + &pll2_pfd_352M, &pll2_pfd_400M, NULL, NULL); + reg |= (mux << MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + } + + return 0; +} + +static unsigned long _clk_gpu2d_core_get_rate(struct clk *clk) +{ + u32 reg, div = 1; + + reg = __raw_readl(MXC_CCM_CBCMR); + if (cpu_is_mx6q()) + div = ((reg & MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK) >> + MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET) + 1; + else if (cpu_is_mx6dl()) + /* on i.mx6dl, gpu2d_core_clk source from gpu3d_shader_clk */ + return clk_get_rate(clk->parent); + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_gpu2d_core_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_CBCMR); + reg &= ~MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} +static struct clk gpu2d_core_clk[] = { + { + __INIT_CLK_DEBUG(gpu2d_core_clk) + .parent = &pll2_pfd_352M, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + .set_parent = _clk_gpu2d_core_set_parent, + .set_rate = _clk_gpu2d_core_set_rate, + .get_rate = _clk_gpu2d_core_get_rate, + .round_rate = _clk_gpu2d_core_round_rate, + .secondary = &mx6fast1_clk, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, +}; + +static unsigned long _clk_gpu3d_shader_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_gpu3d_shader_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CBCMR) + & ~MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_MASK; + + mux = _get_mux6(parent, &mmdc_ch0_axi_clk[0], + &pll3_usb_otg_main_clk, + &pll2_pfd_594M, &pll3_pfd_720M, NULL, NULL); + reg |= (mux << MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static unsigned long _clk_gpu3d_shader_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCMR); + div = ((reg & MXC_CCM_CBCMR_GPU3D_SHADER_PODF_MASK) >> + MXC_CCM_CBCMR_GPU3D_SHADER_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_gpu3d_shader_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 (div > 8) + div = 8; + + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_GPU3D_SHADER_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCMR_GPU3D_SHADER_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + + +static struct clk gpu3d_shader_clk = { + __INIT_CLK_DEBUG(gpu3d_shader_clk) + .parent = &pll3_pfd_720M, + .secondary = &mmdc_ch0_axi_clk[0], + .set_parent = _clk_gpu3d_shader_set_parent, + .set_rate = _clk_gpu3d_shader_set_rate, + .get_rate = _clk_gpu3d_shader_get_rate, + .round_rate = _clk_gpu3d_shader_round_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +/* set the parent by the ipcg table */ +static struct clk gpmi_nand_clk[] = { + { /* gpmi_io_clk */ + __INIT_CLK_DEBUG(gpmi_io_clk) + .parent = &enfc_clk, + .secondary = &gpmi_nand_clk[1], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .disable = _clk_disable, + }, + { /* gpmi_apb_clk */ + __INIT_CLK_DEBUG(gpmi_apb_clk) + .parent = &usdhc3_clk, + .secondary = &gpmi_nand_clk[2], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG15_OFFSET, + .disable = _clk_disable, + }, + { /* bch_clk */ + __INIT_CLK_DEBUG(gpmi_bch_clk) + .parent = &usdhc4_clk, + .secondary = &gpmi_nand_clk[3], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + }, + { /* bch_apb_clk */ + __INIT_CLK_DEBUG(gpmi_bch_apb_clk) + .parent = &usdhc3_clk, + .secondary = &gpmi_nand_clk[4], + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .disable = _clk_disable, + }, + { /* bch relative clk */ + __INIT_CLK_DEBUG(pl301_mx6qperl_bch) + .parent = &mx6per1_clk, + .secondary = &mmdc_ch0_axi_clk[0], + }, +}; + +static struct clk pwm_clk[] = { + { + __INIT_CLK_DEBUG(pwm_clk_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm_clk_1) + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm_clk_2) + .parent = &ipg_perclk, + .id = 2, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm_clk_3) + .parent = &ipg_perclk, + .id = 3, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static int _clk_sata_enable(struct clk *clk) +{ + unsigned int reg; + + /* Enable SATA ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg |= ANADIG_PLL_ENET_EN_SATA; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + _clk_enable(clk); + + return 0; +} + +static void _clk_sata_disable(struct clk *clk) +{ + unsigned int reg; + + _clk_disable(clk); + + /* Disable SATA ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_ENET_EN_SATA; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); +} + +static struct clk sata_clk[] = { + { + __INIT_CLK_DEBUG(sata_clk) + .parent = &pll8_enet_main_clk, + .enable = _clk_sata_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_sata_disable, + .secondary = &sata_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &ipg_clk, + .secondary = &sata_clk[2], + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6per1_clk, + }, +}; + +static int _clk_pcie_enable(struct clk *clk) +{ + unsigned int reg; + +#ifndef CONFIG_IMX_PCIE_RC_MODE_IN_EP_RC_SYS + /* Activate LVDS CLK1 (the MiniPCIe slot clock input) */ + reg = __raw_readl(ANADIG_MISC1_REG); + reg &= ~ANATOP_LVDS_CLK1_IBEN_MASK; + __raw_writel(reg, ANADIG_MISC1_REG); + + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= ANATOP_LVDS_CLK1_SRC_SATA; + __raw_writel(reg, ANADIG_MISC1_REG); + + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= ANATOP_LVDS_CLK1_OBEN_MASK; + __raw_writel(reg, ANADIG_MISC1_REG); +#endif + + /* Enable PCIE ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg |= ANADIG_PLL_ENET_EN_PCIE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + _clk_enable(clk); + + return 0; +} + +static void _clk_pcie_disable(struct clk *clk) +{ + unsigned int reg; + + _clk_disable(clk); + +#ifndef CONFIG_IMX_PCIE_RC_MODE_IN_EP_RC_SYS + /* De-activate LVDS CLK1 (the MiniPCIe slot clock input) */ + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= ANATOP_LVDS_CLK1_IBEN_MASK; + __raw_writel(reg, ANADIG_MISC1_REG); + + reg = __raw_readl(ANADIG_MISC1_REG); + reg &= ~ANATOP_LVDS_CLK1_SRC_SATA; + __raw_writel(reg, ANADIG_MISC1_REG); + + reg = __raw_readl(ANADIG_MISC1_REG); + reg &= ~ANATOP_LVDS_CLK1_OBEN_MASK; + __raw_writel(reg, ANADIG_MISC1_REG); +#endif + + /* Disable PCIE ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_ENET_EN_PCIE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); +} + +static struct clk pcie_clk[] = { + { + __INIT_CLK_DEBUG(pcie_clk) + .parent = &pcie_axi_clk, + .enable = _clk_pcie_enable, + .disable = _clk_pcie_disable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .secondary = &pcie_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + /* + * Enable SATA ref clock. + * PCIe needs both sides to have the same source of refernce clock, + * The SATA reference clock is taken out to link partner. + */ + .parent = &sata_clk[0], + .secondary = &pcie_clk[2], + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6fast1_clk, + }, +}; + +static int _clk_pcie_ep_enable(struct clk *clk) +{ + unsigned int reg; + + /* Enable PCIE ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg |= ANADIG_PLL_ENET_EN_PCIE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + _clk_enable(clk); + + return 0; +} + +static void _clk_pcie_ep_disable(struct clk *clk) +{ + unsigned int reg; + + _clk_disable(clk); + + /* Disable PCIE ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_ENET_EN_PCIE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); +} + +static struct clk pcie_ep_clk[] = { + { + __INIT_CLK_DEBUG(pcie_ep_clk) + .parent = &pcie_axi_clk, + .enable = _clk_pcie_ep_enable, + .disable = _clk_pcie_ep_disable, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .secondary = &pcie_ep_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &pll8_enet_main_clk, + .secondary = &pcie_ep_clk[2], + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6fast1_clk, + }, +}; + +static struct clk usboh3_clk[] = { + { + __INIT_CLK_DEBUG(usboh3_clk) + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + .secondary = &usboh3_clk[1], + .flags = AHB_MED_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mmdc_ch0_axi_clk[0], + .secondary = &mx6per1_clk, + }, +}; + +static int _clk_mlb_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, cbcmr = __raw_readl(MXC_CCM_CBCMR); + + /* + * In Rigel validatioin, the MLB sys_clock isn't using the + * right frequency after boot. + * In arik, the register CBCMR controls gpu2d clock, not mlb clock, + * mlb is sourced from axi clock. + * But In rigel, the axi clock is lower than in mx6q, so mlb need to + * find a new clock root. + * The gpu2d clock is the root of mlb clock in rigel. + * Thus we need to add below code in mx6dl. + * */ + sel = _get_mux(parent, &axi_clk, &pll3_sw_clk, + &pll2_pfd_352M, &pll2_pfd_400M); + + cbcmr &= ~MXC_CCM_CBCMR_MLB_CLK_SEL_MASK; + cbcmr |= sel << MXC_CCM_CBCMR_MLB_CLK_SEL_OFFSET; + __raw_writel(cbcmr, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk mlb150_clk = { + __INIT_CLK_DEBUG(mlb150_clk) + .id = 0, + .secondary = &ocram_clk, + .set_parent = _clk_mlb_set_parent, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static int _clk_enable1(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_disable1(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg; + + if (parent == &pll3_usb_otg_main_clk) + sel = 0; + else if (parent == &pll2_528_bus_main_clk) + sel = 1; + else if (parent == &pll1_sys_main_clk) + sel = 2; + else if (parent == &pll5_video_main_clk) + sel = 3; + else if (parent == &axi_clk) + sel = 5; + else if (parent == &enfc_clk) + sel = 6; + else if (parent == &ipu1_di_clk[0]) + sel = 7; + else if (parent == &ipu1_di_clk[1]) + sel = 8; + else if (parent == &ipu2_di_clk[0]) + sel = 9; + else if (parent == &ipu2_di_clk[1]) + sel = 10; + 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 if (parent == &pll4_audio_main_clk) + sel = 15; + else if (parent == &clko2_clk) { + reg = __raw_readl(MXC_CCM_CCOSR); + reg |= MXC_CCM_CCOSR_CKOL_MIRROR_CKO2_MASK; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; + } else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~(MXC_CCM_CCOSR_CKOL_MIRROR_CKO2_MASK | + MXC_CCM_CCOSR_CKOL_SEL_MASK); + reg |= sel << MXC_CCM_CCOSR_CKOL_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long _clk_clko_get_rate(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCOSR); + u32 div = ((reg & MXC_CCM_CCOSR_CKOL_DIV_MASK) >> + MXC_CCM_CCOSR_CKOL_DIV_OFFSET) + 1; + + if (clk->parent == &clko2_clk) + /* clko may output clko2 without divider */ + return clk_get_rate(clk->parent); + else + return clk_get_rate(clk->parent) / div; +} + +static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + /* clko may output clko2 without divider */ + if (clk->parent == &clko2_clk) + return 0; + + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg |= (div - 1) << MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long _clk_clko_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + /* clko may output clko2 without divider */ + if (clk->parent == &clko2_clk) + return parent_rate; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + else if (parent_rate % rate) + div++; + + if (div > 8) + div = 8; + return parent_rate / div; +} + +static int _clk_clko2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg; + + if (parent == &mmdc_ch0_axi_clk[0]) + sel = 0; + else if (parent == &mmdc_ch1_axi_clk[0]) + sel = 1; + else if (parent == &usdhc4_clk) + sel = 2; + else if (parent == &usdhc1_clk) + sel = 3; + else if (parent == &gpu2d_axi_clk) + sel = 4; + else if (parent == &ecspi_clk[0]) + sel = 6; + else if (parent == &gpu3d_axi_clk) + sel = 7; + else if (parent == &usdhc3_clk) + sel = 8; + else if (parent == &pcie_clk[0]) + sel = 9; + else if (parent == &ipu1_clk) + sel = 11; + else if (parent == &ipu2_clk) + sel = 12; + else if (parent == &vdo_axi_clk) + sel = 13; + else if (parent == &osc_clk) + sel = 14; + else if (parent == &gpu2d_core_clk[0]) + sel = 15; + else if (parent == &gpu3d_core_clk[0]) + sel = 16; + else if (parent == &usdhc2_clk) + sel = 17; + else if (parent == &ssi1_clk) + sel = 18; + else if (parent == &ssi2_clk) + sel = 19; + else if (parent == &ssi3_clk) + sel = 20; + else if (parent == &gpu3d_shader_clk) + sel = 21; + else if (parent == &can_clk_root) + sel = 23; + else if (parent == &ldb_di0_clk) + sel = 24; + else if (parent == &ldb_di1_clk) + sel = 25; + else if (parent == &esai_clk) + sel = 26; + else if (parent == &uart_clk[0]) + sel = 28; + else if (parent == &spdif0_clk[0]) + sel = 29; + else if (parent == &hsi_tx_clk[0]) + sel = 31; + else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKO2_SEL_MASK; + reg |= sel << MXC_CCM_CCOSR_CKO2_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long _clk_clko2_get_rate(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCOSR); + u32 div = ((reg & MXC_CCM_CCOSR_CKO2_DIV_MASK) >> + MXC_CCM_CCOSR_CKO2_DIV_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_clko2_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKO2_DIV_MASK; + reg |= (div - 1) << MXC_CCM_CCOSR_CKO2_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static struct clk clko_clk = { + __INIT_CLK_DEBUG(clko_clk) + .parent = &pll2_528_bus_main_clk, + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCOSR, + .enable_shift = MXC_CCM_CCOSR_CKOL_EN_OFFSET, + .disable = _clk_disable1, + .set_parent = _clk_clko_set_parent, + .set_rate = _clk_clko_set_rate, + .get_rate = _clk_clko_get_rate, + .round_rate = _clk_clko_round_rate, +}; + +static struct clk clko2_clk = { + __INIT_CLK_DEBUG(clko2_clk) + .parent = &usdhc4_clk, + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCOSR, + .enable_shift = MXC_CCM_CCOSR_CKO2_EN_OFFSET, + .disable = _clk_disable1, + .set_parent = _clk_clko2_set_parent, + .set_rate = _clk_clko2_set_rate, + .get_rate = _clk_clko2_get_rate, + .round_rate = _clk_clko_round_rate, +}; + +static struct clk perfmon0_clk = { + __INIT_CLK_DEBUG(perfmon0_clk) + .parent = &mmdc_ch0_axi_clk[0], + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable1, +}; + +static struct clk perfmon1_clk = { + __INIT_CLK_DEBUG(perfmon1_clk) + .parent = &ipu1_clk, + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable1, +}; + +static struct clk perfmon2_clk = { + __INIT_CLK_DEBUG(perfmon2_clk) + .parent = &mmdc_ch0_axi_clk[0], + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable1, +}; + +static struct clk dummy_clk = { + .id = 0, +}; + +#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_sys_main_clk), + _REGISTER_CLOCK(NULL, "pll1_sw_clk", pll1_sw_clk), + _REGISTER_CLOCK(NULL, "pll2", pll2_528_bus_main_clk), + _REGISTER_CLOCK(NULL, "pll2_pfd_400M", pll2_pfd_400M), + _REGISTER_CLOCK(NULL, "pll2_pfd_352M", pll2_pfd_352M), + _REGISTER_CLOCK(NULL, "pll2_pfd_594M", pll2_pfd_594M), + _REGISTER_CLOCK(NULL, "pll2_200M", pll2_200M), + _REGISTER_CLOCK(NULL, "pll3_main_clk", pll3_usb_otg_main_clk), + _REGISTER_CLOCK(NULL, "pll3_pfd_508M", pll3_pfd_508M), + _REGISTER_CLOCK(NULL, "pll3_pfd_454M", pll3_pfd_454M), + _REGISTER_CLOCK(NULL, "pll3_pfd_720M", pll3_pfd_720M), + _REGISTER_CLOCK(NULL, "pll3_pfd_540M", pll3_pfd_540M), + _REGISTER_CLOCK(NULL, "pll3_sw_clk", pll3_sw_clk), + _REGISTER_CLOCK(NULL, "pll3_120M", pll3_120M), + _REGISTER_CLOCK(NULL, "pll3_120M", pll3_80M), + _REGISTER_CLOCK(NULL, "pll3_120M", pll3_60M), + _REGISTER_CLOCK(NULL, "pll4", pll4_audio_main_clk), + _REGISTER_CLOCK(NULL, "pll5", pll5_video_main_clk), + _REGISTER_CLOCK(NULL, "pll6", pll6_mlb150_main_clk), + _REGISTER_CLOCK(NULL, "pll3", pll7_usb_host_main_clk), + _REGISTER_CLOCK(NULL, "pll4", pll8_enet_main_clk), + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk), + _REGISTER_CLOCK("smp_twd", NULL, twd_clk), + _REGISTER_CLOCK(NULL, "periph_clk", periph_clk), + _REGISTER_CLOCK(NULL, "axi_clk", axi_clk), + _REGISTER_CLOCK(NULL, "mmdc_ch0_axi", mmdc_ch0_axi_clk[0]), + _REGISTER_CLOCK(NULL, "mmdc_ch1_axi", mmdc_ch1_axi_clk[0]), + _REGISTER_CLOCK(NULL, "ahb", ahb_clk), + _REGISTER_CLOCK(NULL, "ipg_clk", ipg_clk), + _REGISTER_CLOCK(NULL, "ipg_perclk", ipg_perclk), + _REGISTER_CLOCK(NULL, "spba", spba_clk), + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk[0]), + _REGISTER_CLOCK(NULL, "gpu2d_axi_clk", gpu2d_axi_clk), + _REGISTER_CLOCK(NULL, "gpu3d_axi_clk", gpu3d_axi_clk), + _REGISTER_CLOCK(NULL, "pcie_axi_clk", pcie_axi_clk), + _REGISTER_CLOCK(NULL, "vdo_axi_clk", vdo_axi_clk), + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), + _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(NULL, "vpu_clk", vpu_clk[0]), + _REGISTER_CLOCK(NULL, "ipu1_clk", ipu1_clk), + _REGISTER_CLOCK(NULL, "ipu2_clk", ipu2_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, usdhc1_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, usdhc2_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, usdhc3_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, usdhc4_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(NULL, "ipu1_di0_clk", ipu1_di_clk[0]), + _REGISTER_CLOCK(NULL, "ipu1_di1_clk", ipu1_di_clk[1]), + _REGISTER_CLOCK(NULL, "ipu2_di0_clk", ipu2_di_clk[0]), + _REGISTER_CLOCK(NULL, "ipu2_di1_clk", ipu2_di_clk[1]), + _REGISTER_CLOCK(NULL, "can_root_clk", can_clk_root), + _REGISTER_CLOCK("imx6q-flexcan.0", NULL, can1_clk[0]), + _REGISTER_CLOCK("imx6q-flexcan.1", NULL, can2_clk[0]), + _REGISTER_CLOCK(NULL, "ldb_di0_clk", ldb_di0_clk), + _REGISTER_CLOCK(NULL, "ldb_di1_clk", ldb_di1_clk), + _REGISTER_CLOCK("mxc_spdif.0", NULL, spdif0_clk[0]), + _REGISTER_CLOCK(NULL, "esai_clk", esai_clk), + _REGISTER_CLOCK("imx6q-ecspi.0", NULL, ecspi_clk[0]), + _REGISTER_CLOCK("imx6q-ecspi.1", NULL, ecspi_clk[1]), + _REGISTER_CLOCK("imx6q-ecspi.2", NULL, ecspi_clk[2]), + _REGISTER_CLOCK("imx6q-ecspi.3", NULL, ecspi_clk[3]), + _REGISTER_CLOCK("imx6q-ecspi.4", NULL, ecspi_clk[4]), + _REGISTER_CLOCK(NULL, "emi_slow_clk", emi_slow_clk), + _REGISTER_CLOCK(NULL, "emi_clk", emi_clk), + _REGISTER_CLOCK(NULL, "enfc_clk", enfc_clk), + _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.4", NULL, uart_clk[0]), + _REGISTER_CLOCK(NULL, "hsi_tx", hsi_tx_clk[0]), + _REGISTER_CLOCK(NULL, "caam_clk", caam_clk[0]), + _REGISTER_CLOCK(NULL, "asrc_clk", asrc_clk[0]), + _REGISTER_CLOCK(NULL, "asrc_serial_clk", asrc_clk[1]), + _REGISTER_CLOCK(NULL, "mxs-dma-apbh", apbh_dma_clk), + _REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk), + _REGISTER_CLOCK(NULL, "gpu3d_clk", gpu3d_core_clk[0]), + _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_core_clk[0]), + _REGISTER_CLOCK(NULL, "gpu3d_shader_clk", gpu3d_shader_clk), + _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]), + _REGISTER_CLOCK("imx6q-gpmi-nand.0", NULL, gpmi_nand_clk[0]), + _REGISTER_CLOCK(NULL, "gpmi-apb", gpmi_nand_clk[1]), + _REGISTER_CLOCK(NULL, "bch", gpmi_nand_clk[2]), + _REGISTER_CLOCK(NULL, "bch-apb", gpmi_nand_clk[3]), + _REGISTER_CLOCK(NULL, "pl301_mx6qperl-bch", gpmi_nand_clk[4]), + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk[0]), + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm_clk[1]), + _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm_clk[2]), + _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm_clk[3]), + _REGISTER_CLOCK(NULL, "pcie_clk", pcie_clk[0]), + _REGISTER_CLOCK(NULL, "pcie_ep_clk", pcie_ep_clk[0]), + _REGISTER_CLOCK(NULL, "fec_clk", enet_clk[0]), + _REGISTER_CLOCK(NULL, "fec_mdc_clk", enet_mdc_clk), + _REGISTER_CLOCK(NULL, "imx_sata_clk", sata_clk[0]), + _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk[0]), + _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy1_clk), + _REGISTER_CLOCK(NULL, "usb_phy3_clk", usb_phy3_clk), + _REGISTER_CLOCK(NULL, "usb_phy4_clk", usb_phy4_clk), + _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk), + _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk), + _REGISTER_CLOCK(NULL, "hdmi_isfr_clk", hdmi_clk[0]), + _REGISTER_CLOCK(NULL, "hdmi_iahb_clk", hdmi_clk[1]), + _REGISTER_CLOCK(NULL, "mipi_pllref_clk", mipi_pllref_clk), + _REGISTER_CLOCK(NULL, "vdoa", vdoa_clk[0]), + _REGISTER_CLOCK(NULL, NULL, aips_tz2_clk), + _REGISTER_CLOCK(NULL, NULL, aips_tz1_clk), + _REGISTER_CLOCK(NULL, "clko_clk", clko_clk), + _REGISTER_CLOCK(NULL, "clko2_clk", clko2_clk), + _REGISTER_CLOCK(NULL, "pxp_axi", ipu2_clk), + _REGISTER_CLOCK(NULL, "epdc_axi", ipu2_clk), + _REGISTER_CLOCK(NULL, "epdc_pix", ipu2_di_clk[1]), + _REGISTER_CLOCK("mxs-perfmon.0", "perfmon", perfmon0_clk), + _REGISTER_CLOCK("mxs-perfmon.1", "perfmon", perfmon1_clk), + _REGISTER_CLOCK("mxs-perfmon.2", "perfmon", perfmon2_clk), + _REGISTER_CLOCK(NULL, "mlb150_clk", mlb150_clk), + _REGISTER_CLOCK(NULL, "anaclk_1", anaclk_1), + _REGISTER_CLOCK(NULL, "anaclk_2", anaclk_2), + _REGISTER_CLOCK(NULL, "apb_pclk", dummy_clk), +}; + +static void clk_tree_init(void) + +{ + unsigned int reg; + + reg = __raw_readl(MMDC_MDMISC_OFFSET); + if ((reg & MMDC_MDMISC_DDR_TYPE_MASK) == + (0x1 << MMDC_MDMISC_DDR_TYPE_OFFSET) || + cpu_is_mx6dl()) { + clk_set_parent(&periph_clk, &pll2_pfd_400M); + printk(KERN_INFO "Set periph_clk's parent to pll2_pfd_400M!\n"); + } +} + + +int __init mx6_clocks_init(unsigned long ckil, unsigned long osc, + unsigned long ckih1, unsigned long ckih2) +{ + __iomem void *base; + int i, reg; + u32 parent_rate, rate; + unsigned long ipg_clk_rate, max_arm_wait_clk; + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + timer_base = ioremap(GPT_BASE_ADDR, SZ_4K); + + apll_base = ioremap(ANATOP_BASE_ADDR, SZ_4K); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + clk_debug_register(lookups[i].clk); + } + + /* Lower the ipg_perclk frequency to 22MHz. + * I2C needs a minimum of 12.8MHz as its source + * to acheive 400KHz speed. IPG_PERCLK sources + * I2C. 22MHz when divided by the I2C divider gives the + * freq closest to 400KHz. + */ + clk_set_rate(&ipg_perclk, 22000000); + + /* Timer needs to be initialized first as the + * the WAIT routines use GPT counter as + * a delay. + */ + if (mx6q_revision() == IMX_CHIP_REVISION_1_0) { + gpt_clk[0].parent = &ipg_perclk; + gpt_clk[0].get_rate = NULL; + } else { + /* Here we use OSC 24M as GPT's clock source, no need to + enable gpt serial clock*/ + gpt_clk[0].secondary = NULL; + } + + mxc_timer_init(&gpt_clk[0], timer_base, MXC_INT_GPT); + + clk_tree_init(); + + /* + * Lower the ipg_perclk frequency to 22MHz. + * I2C needs a minimum of 12.8MHz as its source + * to acheive 400KHz speed. IPG_PERCLK sources + * I2C. 22MHz when divided by the I2C divider gives the + * freq closest to 400KHz. + */ + //clk_set_rate(&ipg_perclk, 22000000); + +#ifdef CONFIG_MX6_VPU_352M + if (cpu_is_mx6q()) { + clk_set_rate(&pll2_pfd_400M, 352000000); + clk_set_parent(&vpu_clk[0], &pll2_pfd_400M); + } +#endif + /* keep correct count. */ + clk_enable(&cpu_clk); + clk_enable(&periph_clk); + /* Disable un-necessary PFDs & PLLs */ + if (pll2_pfd_400M.usecount == 0 && cpu_is_mx6q()) + pll2_pfd_400M.disable(&pll2_pfd_400M); + pll2_pfd_352M.disable(&pll2_pfd_352M); + pll2_pfd_594M.disable(&pll2_pfd_594M); + +#if !defined(CONFIG_FEC_1588) + pll3_pfd_454M.disable(&pll3_pfd_454M); + pll3_pfd_508M.disable(&pll3_pfd_508M); + pll3_pfd_540M.disable(&pll3_pfd_540M); + pll3_pfd_720M.disable(&pll3_pfd_720M); + + pll3_usb_otg_main_clk.disable(&pll3_usb_otg_main_clk); +#endif + pll4_audio_main_clk.disable(&pll4_audio_main_clk); + pll5_video_main_clk.disable(&pll5_video_main_clk); + pll6_mlb150_main_clk.disable(&pll6_mlb150_main_clk); + pll7_usb_host_main_clk.disable(&pll7_usb_host_main_clk); + pll8_enet_main_clk.disable(&pll8_enet_main_clk); + + sata_clk[0].disable(&sata_clk[0]); + pcie_clk[0].disable(&pcie_clk[0]); + + /* Initialize Audio and Video PLLs to valid frequency. */ + clk_set_rate(&pll4_audio_main_clk, 176000000); + clk_set_rate(&pll5_video_main_clk, 650000000); + + clk_set_parent(&ipu1_di_clk[0], &pll5_video_main_clk); + clk_set_parent(&ipu1_di_clk[1], &pll5_video_main_clk); + clk_set_parent(&ipu2_di_clk[0], &pll5_video_main_clk); + clk_set_parent(&ipu2_di_clk[1], &pll5_video_main_clk); + + clk_set_parent(&emi_clk, &pll2_pfd_400M); +#ifdef CONFIG_MX6_VPU_352M + clk_set_rate(&emi_clk, 176000000); +#else + clk_set_rate(&emi_clk, 198000000); +#endif + /* + * on mx6dl, 2d core clock sources from 3d shader core clock, + * but 3d shader clock multiplexer of mx6dl is different from + * mx6q. For instance the equivalent of pll2_pfd_594M on mc6q + * is pll2_pfd_528M on mx6dl. Make a note here. + */ + clk_set_parent(&gpu3d_shader_clk, &pll2_pfd_594M); + clk_set_rate(&gpu3d_shader_clk, 594000000); + if (cpu_is_mx6dl()) { + /*for mx6dl, change gpu3d core clk parant to 594_PFD */ + clk_set_parent(&gpu3d_core_clk[0], &pll2_pfd_594M); + clk_set_rate(&gpu3d_core_clk[0], 594000000); + + /*on mx6dl, 2d core clock sources from 3d shader core clock*/ + clk_set_parent(&gpu2d_core_clk[0], &gpu3d_shader_clk); + /* on mx6dl gpu3d_axi_clk source from mmdc0 directly */ + clk_set_parent(&gpu3d_axi_clk, &mmdc_ch0_axi_clk[0]); + /* on mx6dl gpu2d_axi_clk source from mmdc0 directly */ + clk_set_parent(&gpu2d_axi_clk, &mmdc_ch0_axi_clk[0]); + + clk_set_rate(&pll3_pfd_540M, 540000000); + + clk_set_parent(&ipu1_clk, &pll3_pfd_540M); + /* pxp & epdc */ + clk_set_parent(&ipu2_clk, &pll2_pfd_400M); + clk_set_rate(&ipu2_clk, 200000000); + clk_set_parent(&axi_clk, &pll3_pfd_540M); + } else if (cpu_is_mx6q()) { + clk_set_parent(&gpu3d_core_clk[0], &mmdc_ch0_axi_clk[0]); + clk_set_rate(&gpu3d_core_clk[0], 528000000); + clk_set_parent(&ipu2_clk, &mmdc_ch0_axi_clk[0]); + clk_set_parent(&ipu1_clk, &mmdc_ch0_axi_clk[0]); + clk_set_parent(&axi_clk, &periph_clk); + } + + /* Need to keep PLL3_PFD_540M enabled until AXI is sourced from it. */ + clk_enable(&axi_clk); + + if (cpu_is_mx6q()) + clk_set_parent(&gpu2d_core_clk[0], &pll3_usb_otg_main_clk); + + clk_set_parent(&ldb_di0_clk, &pll2_pfd_352M); + clk_set_parent(&ldb_di1_clk, &pll2_pfd_352M); + + /* PCLK camera - J5 */ + clk_set_parent(&clko2_clk, &osc_clk); + clk_set_rate(&clko2_clk, 2400000); + + clk_set_parent(&clko_clk, &pll4_audio_main_clk); + /* + * FIXME: asrc needs to use asrc_serial(spdif1) clock to do sample + * rate convertion and this clock frequency can not be too high, set + * it to the minimum value 7.5Mhz to make asrc work properly. + */ + clk_set_parent(&asrc_clk[1], &pll3_sw_clk); + clk_set_rate(&asrc_clk[1], 7500000); + + /* set the GPMI clock to default frequency : 20MHz */ + clk_set_parent(&enfc_clk, &pll2_pfd_400M); + clk_set_rate(&enfc_clk, enfc_clk.round_rate(&enfc_clk, 20000000)); + + mx6_cpu_op_init(); + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + + /* Gate off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(3 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 3 << MXC_CCM_CCGRx_CG0_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 3 << MXC_CCM_CCGRx_CG0_OFFSET, MXC_CCM_CCGR0); + } + if (mx6q_revision() == IMX_CHIP_REVISION_1_0) + /* If GPT use ipg_perclk, we need to enable gpt serial clock */ + __raw_writel(3 << MXC_CCM_CCGRx_CG10_OFFSET | 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR1); + else + __raw_writel(3 << MXC_CCM_CCGRx_CG10_OFFSET, MXC_CCM_CCGR1); + __raw_writel(1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG10_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR2); + __raw_writel(1 << MXC_CCM_CCGRx_CG14_OFFSET | + 1 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG10_OFFSET, MXC_CCM_CCGR3); + __raw_writel(3 << MXC_CCM_CCGRx_CG7_OFFSET | + 1 << MXC_CCM_CCGRx_CG6_OFFSET | + 1 << MXC_CCM_CCGRx_CG4_OFFSET, MXC_CCM_CCGR4); + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(0, MXC_CCM_CCGR6); + + /* S/PDIF */ + clk_set_parent(&spdif0_clk[0], &pll3_pfd_454M); + + /* MLB150 SYS Clock */ + /* + * In Rigel validatioin, the MLB sys_clock isn't using the + * right frequency after boot. + * In arik, the register CBCMR controls gpu2d clock, not mlb clock, + * mlb is sourced from axi clock. + * But In rigel, the axi clock is lower than in mx6q, so mlb need to + * find a new clock root. + * The gpu2d clock is the root of mlb clock in rigel. + * Thus we need to add below code in mx6dl. + * */ + if (cpu_is_mx6dl()) + clk_set_parent(&mlb150_clk, &pll3_sw_clk); + + + if (cpu_is_mx6dl()) { + /* pxp & epdc */ + clk_set_parent(&ipu2_clk, &pll2_pfd_400M); + clk_set_rate(&ipu2_clk, 200000000); + if (epdc_enabled) + clk_set_parent(&ipu2_di_clk[1], &pll5_video_main_clk); + else + clk_set_parent(&ipu2_di_clk[1], &pll3_pfd_540M); + } + + lp_high_freq = 0; + lp_med_freq = 0; + lp_audio_freq = 0; + + /* Get current ARM_PODF value */ + rate = clk_get_rate(&cpu_clk); + parent_rate = clk_get_rate(&pll1_sw_clk); + cur_arm_podf = parent_rate / rate; + + /* Calculate the ARM_PODF to be applied when the system + * enters WAIT state. + * The max ARM clk is decided by the ipg_clk and has to + * follow the ratio of ARM_CLK:IPG_CLK of 12:5. + */ + ipg_clk_rate = clk_get_rate(&ipg_clk); + max_arm_wait_clk = (12 * ipg_clk_rate) / 5; + wait_mode_arm_podf = parent_rate / max_arm_wait_clk; + + /* Turn OFF all unnecessary PHYs. */ + if (cpu_is_mx6q()) { + /* Turn off SATA PHY. */ + base = ioremap(MX6Q_SATA_BASE_ADDR, SZ_8K); + reg = __raw_readl(base + PORT_PHY_CTL); + __raw_writel(reg | PORT_PHY_CTL_PDDQ_LOC, base + PORT_PHY_CTL); + } + + /* Turn off HDMI PHY. */ + base = ioremap(MX6Q_HDMI_ARB_BASE_ADDR, SZ_128K); + reg = __raw_readb(base + HDMI_PHY_CONF0); + __raw_writeb(reg | HDMI_PHY_CONF0_GEN2_PDDQ_MASK, base + HDMI_PHY_CONF0); + + reg = __raw_readb(base + HDMI_MC_PHYRSTZ); + __raw_writeb(reg | HDMI_MC_PHYRSTZ_DEASSERT, base + HDMI_MC_PHYRSTZ); + + iounmap(base); + + base = ioremap(MX6Q_IOMUXC_BASE_ADDR, SZ_4K); + /* Close PLL inside SATA PHY. */ + reg = __raw_readl(base + 0x34); + __raw_writel(reg | (1 << 1), base + 0x34); + + /* Close PCIE PHY. */ + reg = __raw_readl(base + 0x04); + reg |= (1 << 18); + __raw_writel(reg, base + 0x04); + iounmap(base); + + return 0; + +} diff --git a/arch/arm/mach-mx6/clock_mx6sl.c b/arch/arm/mach-mx6/clock_mx6sl.c new file mode 100755 index 00000000..f70563d3 --- /dev/null +++ b/arch/arm/mach-mx6/clock_mx6sl.c @@ -0,0 +1,4182 @@ +/* + * Copyright (C) 2012-2014 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/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 <linux/regulator/consumer.h> +#include <asm/div64.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/clock.h> +#include <mach/mxc_dvfs.h> +#include "crm_regs.h" +#include "cpu_op-mx6.h" +#include "regs-anadig.h" + +#ifdef CONFIG_CLK_DEBUG +#define __INIT_CLK_DEBUG(n) .name = #n, +#else +#define __INIT_CLK_DEBUG(n) +#endif + +extern u32 arm_max_freq; +extern int mxc_jtag_enabled; +extern struct regulator *cpu_regulator; +extern struct cpu_op *(*get_cpu_op)(int *op); +extern int lp_high_freq; +extern int lp_med_freq; +extern int wait_mode_arm_podf; +extern int mx6q_revision(void); +extern int cur_arm_podf; + +static void __iomem *apll_base; +static void __iomem *timer_base; +static struct clk pll1_sys_main_clk; +static struct clk pll2_528_bus_main_clk; +static struct clk pll2_pfd2_400M; +static struct clk pll3_usb_otg_main_clk; +static struct clk pll4_audio_main_clk; +static struct clk pll5_video_main_clk; +static struct clk pll6_enet_main_clk; /* Essentially same as PLL8 on MX6Q/DL */ +static struct clk pll7_usb_host_main_clk; +static struct clk usdhc3_clk; +static struct clk ipg_clk; +static struct clk gpt_clk[]; +static struct clk ahb_clk; + +static struct cpu_op *cpu_op_tbl; +static int cpu_op_nr; +static bool pll1_enabled; +static bool arm_needs_pll2_400; +static bool audio_pll_bypass; + +DEFINE_SPINLOCK(mx6sl_clk_lock); +#define SPIN_DELAY 1200000 /* in nanoseconds */ + +#define AUDIO_VIDEO_MIN_CLK_FREQ 650000000 +#define AUDIO_VIDEO_MAX_CLK_FREQ 1300000000 +#define MAX_ARM_CLK_IN_WAIT 158000000 +#define V2_TCN 0x24 +#define V2_TSTAT 0x08 +#define V2_TSTAT_ROV (1 << 5) +#define V2_TCTL_CLK_OSC_DIV8 (5 << 6) +#define MXC_TCTL 0x00 +#define MXC_TPRER 0x04 +#define V2_TPRER_PRE24M_OFFSET 12 +#define V2_TPRER_PRE24M_MASK 0xF + +/* We need to check the exp status again after timer expiration, + * as there might be interrupt coming between the first time exp + * and the time reading, then the time reading may be several ms + * after the exp checking due to the irq handle, so we need to + * check it to make sure the exp return the right value after + * timer expiration. */ +#define WAIT(exp, timeout) \ +({ \ + u32 gpt_rate; \ + u32 gpt_ticks; \ + u32 gpt_cnt; \ + u32 reg; \ + int result = 1; \ + gpt_rate = clk_get_rate(&gpt_clk[0]); \ + gpt_ticks = timeout / (1000000000 / gpt_rate); \ + reg = __raw_readl(timer_base + V2_TSTAT);\ + /* Clear the GPT roll over interrupt. */ \ + if (reg & V2_TSTAT_ROV) { \ + __raw_writel(V2_TSTAT_ROV, timer_base + V2_TSTAT); \ + } \ + gpt_cnt = __raw_readl(timer_base + V2_TCN); \ + while (!(exp)) { \ + if ((__raw_readl(timer_base + V2_TCN) - gpt_cnt) > gpt_ticks) { \ + if (!exp) \ + result = 0; \ + break; \ + } else { \ + reg = __raw_readl(timer_base + V2_TSTAT);\ + if (reg & V2_TSTAT_ROV) { \ + u32 old_cnt = gpt_cnt; \ + /* Timer has rolled over. \ + * Calculate the new tick count. \ + */ \ + gpt_cnt = __raw_readl(timer_base + V2_TCN); \ + gpt_ticks -= (0xFFFFFFFF - old_cnt + gpt_cnt); \ + /* Clear the roll over interrupt. */ \ + __raw_writel(V2_TSTAT_ROV, \ + timer_base + V2_TSTAT); \ + } \ + } \ + } \ + result; \ +}) + +/* 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 unsigned long anaclk_1_reference, anaclk_2_reference; + +static void __calc_pre_post_dividers(u32 max_podf, u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + /* Some of the podfs are 3 bits while others are 6 bits. + * Handle both cases here. + */ + if (div >= 512 && (max_podf == 64)) { + /* For pre = 3bits and podf = 6 bits, max divider is 512. */ + *pre = 8; + *post = 64; + } else if (div >= 64 && (max_podf == 8)) { + /* For pre = 3bits and podf = 3 bits, max divider is 64. */ + *pre = 8; + *post = 8; + } else if (div >= 8) { + /* Find the minimum pre-divider for a max podf */ + if (max_podf == 64) + min_pre = (div - 1) / (1 << 6) + 1; + else + min_pre = (div - 1) / (1 << 3) + 1; + old_err = 8; + /* Now loop through to find the max pre-divider. */ + 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 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; +} + +static inline void __iomem *_get_pll_base(struct clk *pll) +{ + if (pll == &pll1_sys_main_clk) + return PLL1_SYS_BASE_ADDR; + else if (pll == &pll2_528_bus_main_clk) + return PLL2_528_BASE_ADDR; + else if (pll == &pll3_usb_otg_main_clk) + return PLL3_480_USB1_BASE_ADDR; + else if (pll == &pll4_audio_main_clk) + return PLL4_AUDIO_BASE_ADDR; + else if (pll == &pll5_video_main_clk) + return PLL5_VIDEO_BASE_ADDR; + else if (pll == &pll6_enet_main_clk) + /* Essentially same as PLL8 on MX6Q/DL */ + return PLL8_ENET_BASE_ADDR; + else if (pll == &pll7_usb_host_main_clk) + return PLL7_480_USB2_BASE_ADDR; + else + BUG(); + return NULL; +} + + +/* + * For the 6-to-1 muxed input clock + */ +static inline u32 _get_mux6(struct clk *parent, struct clk *m0, struct clk *m1, + struct clk *m2, struct clk *m3, struct clk *m4, + struct clk *m5) +{ + 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 + BUG(); + + 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_anaclk_1_get_rate(struct clk *clk) +{ + return anaclk_1_reference; +} + +static int _clk_anaclk_1_set_rate(struct clk *clk, unsigned long rate) +{ + anaclk_1_reference = rate; + return 0; +} + +static unsigned long _clk_anaclk_2_get_rate(struct clk *clk) +{ + return anaclk_2_reference; +} + +static int _clk_anaclk_2_set_rate(struct clk *clk, unsigned long rate) +{ + anaclk_2_reference = rate; + return 0; +} + +/* 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 struct clk anaclk_1 = { + __INIT_CLK_DEBUG(anaclk_1) + .get_rate = _clk_anaclk_1_get_rate, + .set_rate = _clk_anaclk_1_set_rate, +}; + +static struct clk anaclk_2 = { + __INIT_CLK_DEBUG(anaclk_2) + .get_rate = _clk_anaclk_2_get_rate, + .set_rate = _clk_anaclk_2_set_rate, +}; + +static unsigned long pfd_round_rate(struct clk *clk, unsigned long rate) +{ + u32 frac; + u64 tmp; + + tmp = (u64)clk_get_rate(clk->parent) * 18; + tmp += rate/2; + do_div(tmp, rate); + frac = tmp; + frac = frac < 12 ? 12 : frac; + frac = frac > 35 ? 35 : frac; + tmp = (u64)clk_get_rate(clk->parent) * 18; + do_div(tmp, frac); + return tmp; +} + +static unsigned long pfd_get_rate(struct clk *clk) +{ + u32 frac; + u64 tmp; + tmp = (u64)clk_get_rate(clk->parent) * 18; + + frac = (__raw_readl(clk->enable_reg) >> clk->enable_shift) & + ANADIG_PFD_FRAC_MASK; + + 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; + + /* Round up the divider so that we don't set a rate + * higher than what is requested. */ + tmp += rate/2; + do_div(tmp, rate); + frac = tmp; + frac = frac < 12 ? 12 : frac; + frac = frac > 35 ? 35 : frac; + /* clear clk frac bits */ + __raw_writel(ANADIG_PFD_FRAC_MASK << clk->enable_shift, + (int)clk->enable_reg + 8); + /* set clk frac bits */ + __raw_writel(frac << clk->enable_shift, + (int)clk->enable_reg + 4); + + return 0; +} + +static int _clk_pfd_enable(struct clk *clk) +{ + /* clear clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + (int)clk->enable_reg + 8); + + udelay(3); + return 0; +} + +static void _clk_pfd_disable(struct clk *clk) +{ + /* set clk gate bit */ + __raw_writel((1 << (clk->enable_shift + 7)), + (int)clk->enable_reg + 4); +} + +static int _clk_pll_enable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + if (clk != &pll4_audio_main_clk || !audio_pll_bypass) + reg &= ~ANADIG_PLL_POWER_DOWN; + + /* The 480MHz PLLs have the opposite definition for power bit. */ + if (clk == &pll3_usb_otg_main_clk || clk == &pll7_usb_host_main_clk) + reg |= ANADIG_PLL_POWER_DOWN; + + __raw_writel(reg, pllbase); + + /* It will power on pll3 */ + if (clk == &pll3_usb_otg_main_clk) + __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_CLR); + + /* Wait for PLL to lock */ + if (clk != &pll4_audio_main_clk || !audio_pll_bypass) { + if (!WAIT((__raw_readl(pllbase) & ANADIG_PLL_LOCK), + SPIN_DELAY)) + panic("pll enable failed\n"); + } + /* Enable the PLL output now*/ + reg = __raw_readl(pllbase); + + /* If audio PLL is set to 24MHz, leave it in bypass mode. */ + if (clk != &pll4_audio_main_clk || !audio_pll_bypass) + reg &= ~ANADIG_PLL_BYPASS; + + reg |= ANADIG_PLL_ENABLE; + + __raw_writel(reg, pllbase); + + return 0; +} + +static void _clk_pll_disable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + if ((arm_needs_pll2_400) && (clk == &pll2_528_bus_main_clk)) + return; + + + pllbase = _get_pll_base(clk); + + reg = __raw_readl(pllbase); + reg |= ANADIG_PLL_BYPASS; + reg |= ANADIG_PLL_POWER_DOWN; + + /* The 480MHz PLLs have the opposite definition for power bit. */ + if (clk == &pll3_usb_otg_main_clk || clk == &pll7_usb_host_main_clk) + reg &= ~ANADIG_PLL_POWER_DOWN; + + /* PLL1, PLL2, PLL3, PLL7 should not disable the ENABLE bit. + * The output of these PLLs maybe used even if they are bypassed. + */ + if (clk == &pll4_audio_main_clk || clk == &pll5_video_main_clk || + clk == &pll6_enet_main_clk) + reg &= ~ANADIG_PLL_ENABLE; + + __raw_writel(reg, pllbase); + + /* + * It will power off PLL3's power, it is the TO1.1 fix + * Please see TKT064178 for detail. + */ + if (clk == &pll3_usb_otg_main_clk) + __raw_writel(BM_ANADIG_ANA_MISC2_CONTROL0, apll_base + HW_ANADIG_ANA_MISC2_SET); +} + +static unsigned long _clk_pll1_main_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_SYS_DIV_SELECT_MASK; + val = (clk_get_rate(clk->parent) * div) / 2; + return val; +} + +static int _clk_pll1_main_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate < AUDIO_VIDEO_MIN_CLK_FREQ || rate > AUDIO_VIDEO_MAX_CLK_FREQ) + return -EINVAL; + + div = (rate * 2) / clk_get_rate(clk->parent); + + /* Update div */ + reg = __raw_readl(PLL1_SYS_BASE_ADDR) & ~ANADIG_PLL_SYS_DIV_SELECT_MASK; + reg |= div; + __raw_writel(reg, PLL1_SYS_BASE_ADDR); + + /* Wait for PLL1 to lock */ + if (!WAIT((__raw_readl(PLL1_SYS_BASE_ADDR) & ANADIG_PLL_LOCK), + SPIN_DELAY)) + panic("pll1 set rate failed\n"); + + return 0; +} + +static int _clk_pll1_main_enable(struct clk *clk) +{ + pll1_enabled = true; + _clk_pll_enable(clk); + return 0; +} + +static void _clk_pll1_main_disable(struct clk *clk) +{ + unsigned int reg; + void __iomem *pllbase; + + pll1_enabled = false; + pllbase = _get_pll_base(clk); + + /* Set the PLL is bypass mode only. + * We need to be able to set the ARM_PODF bit + * in WAIT mode. Setting the ARM_PODF bit + * requires PLL1 to be enabled. + */ + reg = __raw_readl(pllbase); + reg |= (ANADIG_PLL_BYPASS | ANADIG_PLL_POWER_DOWN); + __raw_writel(reg, pllbase); +} + +static struct clk pll1_sys_main_clk = { + __INIT_CLK_DEBUG(pll1_sys_main_clk) + .parent = &osc_clk, + .get_rate = _clk_pll1_main_get_rate, + .set_rate = _clk_pll1_main_set_rate, + .enable = _clk_pll1_main_enable, + .disable = _clk_pll1_main_disable, +}; + +static int _clk_pll1_sw_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCSR); + + if (parent == &pll1_sys_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. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL); + } else { + /* Set STEP_CLK to be the parent*/ + if (parent == &osc_clk) { + /* Set STEP_CLK to be sourced from LPAPM. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg = (reg & ~MXC_CCM_CCSR_STEP_SEL); + __raw_writel(reg, MXC_CCM_CCSR); + } else { + /* Set STEP_CLK to be sourced from PLL2-PDF (400MHz). */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_STEP_SEL; + __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) +{ + return clk_get_rate(clk->parent); +} + +static struct clk pll1_sw_clk = { + __INIT_CLK_DEBUG(pll1_sw_clk) + .parent = &pll1_sys_main_clk, + .set_parent = _clk_pll1_sw_set_parent, + .get_rate = _clk_pll1_sw_get_rate, +}; + +static unsigned long _clk_pll2_main_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL2_528_BASE_ADDR) & ANADIG_PLL_528_DIV_SELECT; + + if (div == 1) + val = clk_get_rate(clk->parent) * 22; + + else + val = clk_get_rate(clk->parent) * 20; + + return val; +} + +static int _clk_pll2_main_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate == 528000000) + div = 1; + else if (rate == 480000000) + div = 0; + else + return -EINVAL; + + reg = __raw_readl(PLL2_528_BASE_ADDR); + reg &= ~ANADIG_PLL_528_DIV_SELECT; + reg |= div; + __raw_writel(reg, PLL2_528_BASE_ADDR); + + return 0; +} + +static struct clk pll2_528_bus_main_clk = { + __INIT_CLK_DEBUG(pll2_528_bus_main_clk) + .parent = &osc_clk, + .get_rate = _clk_pll2_main_get_rate, + .set_rate = _clk_pll2_main_set_rate, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +static void _clk_pll2_pfd2_400M_disable(struct clk *clk) +{ + if (!arm_needs_pll2_400) + _clk_pfd_disable(clk); +} + +static struct clk pll2_pfd2_400M = { + __INIT_CLK_DEBUG(pll2_pfd2_400M) + .parent = &pll2_528_bus_main_clk, + .enable_reg = (void *)PFD_528_BASE_ADDR, + .enable_shift = ANADIG_PFD2_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pll2_pfd2_400M_disable, + .get_rate = pfd_get_rate, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll2_pfd0_352M = { + __INIT_CLK_DEBUG(pll2_pfd0_352M) + .parent = &pll2_528_bus_main_clk, + .enable_reg = (void *)PFD_528_BASE_ADDR, + .enable_shift = ANADIG_PFD0_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll2_pfd1_594M = { + __INIT_CLK_DEBUG(pll2_pfd1_594M) + .parent = &pll2_528_bus_main_clk, + .enable_reg = (void *)PFD_528_BASE_ADDR, + .enable_shift = ANADIG_PFD1_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static unsigned long _clk_pll2_200M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static struct clk pll2_200M = { + __INIT_CLK_DEBUG(pll2_200M) + .parent = &pll2_pfd2_400M, + .get_rate = _clk_pll2_200M_get_rate, +}; + +static unsigned long _clk_pll3_usb_otg_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL3_480_USB1_BASE_ADDR) + & ANADIG_PLL_480_DIV_SELECT_MASK; + + if (div == 1) + val = clk_get_rate(clk->parent) * 22; + else + val = clk_get_rate(clk->parent) * 20; + return val; +} + +static int _clk_pll3_usb_otg_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate == 528000000) + div = 1; + else if (rate == 480000000) + div = 0; + else + return -EINVAL; + + reg = __raw_readl(PLL3_480_USB1_BASE_ADDR); + reg &= ~ANADIG_PLL_480_DIV_SELECT_MASK; + reg |= div; + __raw_writel(reg, PLL3_480_USB1_BASE_ADDR); + + return 0; +} + + +/* same as pll3_main_clk. These two clocks should always be the same */ +static struct clk pll3_usb_otg_main_clk = { + __INIT_CLK_DEBUG(pll3_usb_otg_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +/* for USB OTG */ +static struct clk usb_phy1_clk = { + __INIT_CLK_DEBUG(usb_phy1_clk) + .parent = &pll3_usb_otg_main_clk, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +/* For HSIC port 1 */ +static struct clk usb_phy3_clk = { + __INIT_CLK_DEBUG(usb_phy3_clk) + .parent = &pll3_usb_otg_main_clk, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +/* For HSIC port 2 */ +static struct clk usb_phy4_clk = { + __INIT_CLK_DEBUG(usb_phy4_clk) + .parent = &pll3_usb_otg_main_clk, + .set_rate = _clk_pll3_usb_otg_set_rate, + .get_rate = _clk_pll3_usb_otg_get_rate, +}; + +static struct clk pll3_pfd2_508M = { + __INIT_CLK_DEBUG(pll3_pfd2_508M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD2_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll3_pfd3_454M = { + __INIT_CLK_DEBUG(pll3_pfd3_454M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD3_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll3_pfd0_720M = { + __INIT_CLK_DEBUG(pll3_pfd0_720M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD0_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, +}; + +static struct clk pll3_pfd1_540M = { + __INIT_CLK_DEBUG(pll3_pfd1_540M) + .parent = &pll3_usb_otg_main_clk, + .enable_reg = (void *)PFD_480_BASE_ADDR, + .enable_shift = ANADIG_PFD1_FRAC_OFFSET, + .enable = _clk_pfd_enable, + .disable = _clk_pfd_disable, + .set_rate = pfd_set_rate, + .get_rate = pfd_get_rate, + .round_rate = pfd_round_rate, + .get_rate = pfd_get_rate, +}; + +static unsigned long _clk_pll3_sw_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->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 = &pll3_usb_otg_main_clk, + .get_rate = _clk_pll3_sw_get_rate, +}; + +static unsigned long _clk_pll3_120M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 4; +} + +static struct clk pll3_120M = { + __INIT_CLK_DEBUG(pll3_120M) + .parent = &pll3_sw_clk, + .get_rate = _clk_pll3_120M_get_rate, +}; + +static unsigned long _clk_pll3_80M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 6; +} + +static struct clk pll3_80M = { + __INIT_CLK_DEBUG(pll3_80M) + .parent = &pll3_sw_clk, + .get_rate = _clk_pll3_80M_get_rate, +}; + +static unsigned long _clk_pll3_60M_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 8; +} + +static struct clk pll3_60M = { + __INIT_CLK_DEBUG(pll3_60M) + .parent = &pll3_sw_clk, + .get_rate = _clk_pll3_60M_get_rate, +}; + +static unsigned long _clk_audio_video_get_rate(struct clk *clk) +{ + unsigned int div, mfn, mfd; + unsigned long rate; + unsigned int parent_rate = clk_get_rate(clk->parent); + void __iomem *pllbase; + unsigned int test_div_sel, control3, post_div; + + pllbase = _get_pll_base(clk); + + if (__raw_readl(pllbase) & ANADIG_PLL_BYPASS) + return 24000000; + + test_div_sel = (__raw_readl(pllbase) + & ANADIG_PLL_AV_TEST_DIV_SEL_MASK) + >> ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET; + /* post_div = 4 - test_div_sel; */ + if (test_div_sel == 0) + post_div = 4; + else if (test_div_sel == 1) + post_div = 2; + else + post_div = 1; + + /* PMU_REG_MISC2 in RM */ + if (clk == &pll5_video_main_clk) { + control3 = (__raw_readl(ANA_MISC2_BASE_ADDR) + & ANADIG_ANA_MISC2_CONTROL3_MASK) + >> ANADIG_ANA_MISC2_CONTROL3_OFFSET; + if (control3 == 1) + post_div *= 2; + else if (control3 == 3) + post_div *= 4; + } + + div = __raw_readl(pllbase) & ANADIG_PLL_SYS_DIV_SELECT_MASK; + mfn = __raw_readl(pllbase + PLL_NUM_DIV_OFFSET); + mfd = __raw_readl(pllbase + PLL_DENOM_DIV_OFFSET); + + rate = (parent_rate * div) + ((parent_rate / mfd) * mfn); + rate = rate / post_div; + + return rate; +} + +static int _clk_audio_video_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + unsigned int mfn, mfd = 1000000; + s64 temp64; + unsigned int parent_rate = clk_get_rate(clk->parent); + void __iomem *pllbase; + unsigned long min_clk_rate, pre_div_rate; + u32 test_div_sel = 2; + u32 control3 = 0; + + pllbase = _get_pll_base(clk); + + if (clk == &pll4_audio_main_clk && audio_pll_bypass) { + reg = __raw_readl(pllbase) + & ~ANADIG_PLL_SYS_DIV_SELECT_MASK + & ~ANADIG_PLL_AV_TEST_DIV_SEL_MASK; + __raw_writel(reg, pllbase); + return 0; + } + + if (clk == &pll4_audio_main_clk) + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4; + else + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 16; + + if ((rate < min_clk_rate) || (rate > AUDIO_VIDEO_MAX_CLK_FREQ)) + return -EINVAL; + + pre_div_rate = rate; + while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) { + pre_div_rate *= 2; + /* + * test_div_sel field values: + * 2 -> Divide by 1 + * 1 -> Divide by 2 + * 0 -> Divide by 4 + * + * control3 field values: + * 0 -> Divide by 1 + * 1 -> Divide by 2 + * 3 -> Divide by 4 + */ + if (test_div_sel != 0) + test_div_sel--; + else { + control3++; + if (control3 == 2) + control3++; + } + } + + div = pre_div_rate / parent_rate; + temp64 = (u64) (pre_div_rate - (div * parent_rate)); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + reg = __raw_readl(pllbase) + & ~ANADIG_PLL_SYS_DIV_SELECT_MASK + & ~ANADIG_PLL_AV_TEST_DIV_SEL_MASK; + reg |= div | + (test_div_sel << ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET); + __raw_writel(reg, pllbase); + __raw_writel(mfn, pllbase + PLL_NUM_DIV_OFFSET); + __raw_writel(mfd, pllbase + PLL_DENOM_DIV_OFFSET); + + reg = __raw_readl(ANA_MISC2_BASE_ADDR) + & ~ANADIG_ANA_MISC2_CONTROL3_MASK; + reg |= control3 << ANADIG_ANA_MISC2_CONTROL3_OFFSET; + __raw_writel(reg, ANA_MISC2_BASE_ADDR); + + return 0; +} + +static unsigned long _clk_audio_video_round_rate(struct clk *clk, + unsigned long rate) +{ + unsigned long min_clk_rate; + unsigned int div, post_div = 1; + unsigned int mfn, mfd = 1000000; + s64 temp64; + unsigned int parent_rate = clk_get_rate(clk->parent); + unsigned long pre_div_rate; + u32 test_div_sel = 2; + u32 control3 = 0; + unsigned long final_rate; + + if (clk == &pll4_audio_main_clk && audio_pll_bypass) + return 24000000; + + if (clk == &pll4_audio_main_clk) + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 4; + else + min_clk_rate = AUDIO_VIDEO_MIN_CLK_FREQ / 16; + + if (rate < min_clk_rate) + return min_clk_rate; + + if (rate > AUDIO_VIDEO_MAX_CLK_FREQ) + return AUDIO_VIDEO_MAX_CLK_FREQ; + + pre_div_rate = rate; + while (pre_div_rate < AUDIO_VIDEO_MIN_CLK_FREQ) { + pre_div_rate *= 2; + post_div *= 2; + if (test_div_sel != 0) + test_div_sel--; + else { + control3++; + if (control3 == 2) + control3++; + } + } + + div = pre_div_rate / parent_rate; + temp64 = (u64) (pre_div_rate - (div * parent_rate)); + temp64 *= mfd; + do_div(temp64, parent_rate); + mfn = temp64; + + final_rate = (parent_rate * div) + ((parent_rate / mfd) * mfn); + final_rate = final_rate / post_div; + + return final_rate; +} + +static int _clk_audio_video_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + int mux; + void __iomem *pllbase; + + if (clk == &pll4_audio_main_clk) + pllbase = PLL4_AUDIO_BASE_ADDR; + else + pllbase = PLL5_VIDEO_BASE_ADDR; + + reg = __raw_readl(pllbase) & ~ANADIG_PLL_BYPASS_CLK_SRC_MASK; + mux = _get_mux6(parent, &osc_clk, &anaclk_1, &anaclk_2, + NULL, NULL, NULL); + reg |= mux << ANADIG_PLL_BYPASS_CLK_SRC_OFFSET; + __raw_writel(reg, pllbase); + + /* Set anaclk_x as input */ + if (parent == &anaclk_1) { + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= (ANATOP_LVDS_CLK1_IBEN_MASK & + ~ANATOP_LVDS_CLK1_OBEN_MASK); + __raw_writel(reg, ANADIG_MISC1_REG); + } else if (parent == &anaclk_2) { + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= (ANATOP_LVDS_CLK2_IBEN_MASK & + ~ANATOP_LVDS_CLK2_OBEN_MASK); + __raw_writel(reg, ANADIG_MISC1_REG); + } + + return 0; +} + +static struct clk pll4_audio_main_clk = { + __INIT_CLK_DEBUG(pll4_audio_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_audio_video_set_rate, + .get_rate = _clk_audio_video_get_rate, + .round_rate = _clk_audio_video_round_rate, + .set_parent = _clk_audio_video_set_parent, +}; + +static struct clk pll5_video_main_clk = { + __INIT_CLK_DEBUG(pll5_video_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_audio_video_set_rate, + .get_rate = _clk_audio_video_get_rate, + .round_rate = _clk_audio_video_round_rate, + .set_parent = _clk_audio_video_set_parent, +}; + +static struct clk pll6_enet_main_clk = { + __INIT_CLK_DEBUG(pll6_enet_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, +}; + +static unsigned long _clk_pll7_usb_otg_get_rate(struct clk *clk) +{ + unsigned int div; + unsigned long val; + + div = __raw_readl(PLL7_480_USB2_BASE_ADDR) + & ANADIG_PLL_480_DIV_SELECT_MASK; + + if (div == 1) + val = clk_get_rate(clk->parent) * 22; + else + val = clk_get_rate(clk->parent) * 20; + return val; +} + +static int _clk_pll7_usb_otg_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div; + + if (rate == 528000000) + div = 1; + else if (rate == 480000000) + div = 0; + else + return -EINVAL; + + reg = __raw_readl(PLL7_480_USB2_BASE_ADDR); + reg &= ~ANADIG_PLL_480_DIV_SELECT_MASK; + reg |= div; + __raw_writel(reg, PLL7_480_USB2_BASE_ADDR); + + return 0; +} + +static struct clk pll7_usb_host_main_clk = { + __INIT_CLK_DEBUG(pll7_usb_host_main_clk) + .parent = &osc_clk, + .enable = _clk_pll_enable, + .disable = _clk_pll_disable, + .set_rate = _clk_pll7_usb_otg_set_rate, + .get_rate = _clk_pll7_usb_otg_get_rate, + +}; + +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; +} + +extern int high_cpu_freq; + +static int _clk_arm_set_rate(struct clk *clk, unsigned long rate) +{ + int i; + u32 div; + u32 parent_rate; + unsigned long ipg_clk_rate, max_arm_wait_clk; + unsigned long flags; + + for (i = 0; i < cpu_op_nr; i++) { + if (rate == cpu_op_tbl[i].cpu_rate) + break; + } + if (i >= cpu_op_nr) + return -EINVAL; + + if (clk_get_rate(&ahb_clk) == 24000000) { + printk(KERN_INFO "we should not be here!!!!! AHB is at 24MHz....cpu_rate requested = %ld\n", rate); + dump_stack(); + BUG(); + } + spin_lock_irqsave(&mx6sl_clk_lock, flags); + + if (rate <= clk_get_rate(&pll2_pfd2_400M)) { + /* Source pll1_sw_clk from step_clk which is sourced from + * PLL2_PFD2_400M. + */ + if (pll1_sw_clk.parent != &pll2_pfd2_400M) { + if (pll2_pfd2_400M.usecount == 0) { + /* Check if PLL2 needs to be enabled also. */ + if (pll2_528_bus_main_clk.usecount == 0) { + pll2_528_bus_main_clk.enable(&pll2_528_bus_main_clk); + osc_clk.usecount++; + } + /* Ensure parent usecount is + * also incremented. + */ + pll2_528_bus_main_clk.usecount++; + pll2_pfd2_400M.enable(&pll2_pfd2_400M); + } + arm_needs_pll2_400 = true; + pll2_pfd2_400M.usecount++; + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M); + pll1_sw_clk.parent = &pll2_pfd2_400M; + } + } else { + /* Make sure PLL1 is enabled */ + if (!pll1_enabled) { + pll1_sys_main_clk.enable(&pll1_sys_main_clk); + pll1_sys_main_clk.usecount = 1; + osc_clk.usecount++; + } + if (cpu_op_tbl[i].pll_rate != clk_get_rate(&pll1_sys_main_clk)) { + if (pll1_sw_clk.parent == &pll1_sys_main_clk) { + /* Change the PLL1 rate. */ + if (pll2_pfd2_400M.usecount != 0) + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll2_pfd2_400M); + else + pll1_sw_clk.set_parent(&pll1_sw_clk, &osc_clk); + } + pll1_sys_main_clk.set_rate(&pll1_sys_main_clk, cpu_op_tbl[i].pll_rate); + } + pll1_sw_clk.set_parent(&pll1_sw_clk, &pll1_sys_main_clk); + pll1_sw_clk.parent = &pll1_sys_main_clk; + + if (arm_needs_pll2_400) { + pll2_pfd2_400M.usecount--; + if (pll2_pfd2_400M.usecount == 0) { + pll2_pfd2_400M.disable(&pll2_pfd2_400M); + /* Ensure parent usecount is + * also decremented. + */ + pll2_528_bus_main_clk.usecount--; + if (pll2_528_bus_main_clk.usecount == 0) { + pll2_528_bus_main_clk.disable(&pll2_528_bus_main_clk); + osc_clk.usecount--; + } + } + } + arm_needs_pll2_400 = false; + } + parent_rate = clk_get_rate(clk->parent); + div = parent_rate / rate; + /* Calculate the ARM_PODF to be applied when the system + * enters WAIT state. + * The max ARM clk is decided by the ipg_clk and has to + * follow the ratio of ARM_CLK:IPG_CLK of 12:5. + * For ex, when IPG is at 66MHz, ARM_CLK cannot be greater + * than 158MHz. Pre-calculate the optimal divider now. + */ + ipg_clk_rate = clk_get_rate(&ipg_clk); + max_arm_wait_clk = (12 * ipg_clk_rate) / 5; + wait_mode_arm_podf = parent_rate / max_arm_wait_clk; + + if (div == 0) + div = 1; + + if ((parent_rate / div) > rate) + div++; + + if (div > 8) { + spin_unlock_irqrestore(&mx6sl_clk_lock, flags); + return -1; + } + + cur_arm_podf = div; + + __raw_writel(div - 1, MXC_CCM_CACRR); + + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + + if (pll1_sys_main_clk.usecount == 1 && arm_needs_pll2_400) { + pll1_sys_main_clk.disable(&pll1_sys_main_clk); + pll1_sys_main_clk.usecount = 0; + osc_clk.usecount--; + } + + spin_unlock_irqrestore(&mx6sl_clk_lock, flags); + + return 0; +} + +static struct clk cpu_clk = { + __INIT_CLK_DEBUG(cpu_clk) + .parent = &pll1_sw_clk, + .set_rate = _clk_arm_set_rate, + .get_rate = _clk_arm_get_rate, +}; + +static unsigned long _clk_twd_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static int _clk_ipg_perclk_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1); + + if (parent == &osc_clk) + reg |= 0x1 << MXC_CCM_CSCMR1_PERCLK_CLK_SEL_OFFSET; + else + reg &= ~(0x1 << MXC_CCM_CSCMR1_PERCLK_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} +static struct clk twd_clk = { + __INIT_CLK_DEBUG(twd_clk) + .parent = &cpu_clk, + .get_rate = _clk_twd_get_rate, +}; + +static int _clk_periph_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + int mux; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, &pll2_pfd2_400M, + &pll2_pfd0_352M, &pll2_200M, &pll3_sw_clk, &osc_clk); + + if (mux <= 3) { + /* Set the pre_periph_clk multiplexer */ + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + udelay(5); + /* Set the periph_clk_sel multiplexer. */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERIPH_CLK_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } else { + reg = __raw_readl(MXC_CCM_CBCDR); + /* Set the periph_clk2_podf divider to divide by 1. */ + reg &= ~MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK; + __raw_writel(reg, MXC_CCM_CBCDR); + + /* Set the periph_clk2_sel mux. */ + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK; + reg |= ((mux - 4) << MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + + reg = __raw_readl(MXC_CCM_CBCDR); + /* Set periph_clk_sel to select periph_clk. */ + reg |= MXC_CCM_CBCDR_PERIPH_CLK_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY), SPIN_DELAY)) + panic("_clk_periph_set_parent failed\n"); + + return 0; +} + +static unsigned long _clk_periph_get_rate(struct clk *clk) +{ + u32 div = 1; + u32 reg; + unsigned long val; + + if ((clk->parent == &pll3_sw_clk) || (clk->parent == &osc_clk)) { + reg = __raw_readl(MXC_CCM_CBCDR) + & MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK; + div = (reg >> MXC_CCM_CBCDR_PERIPH_CLK2_PODF_OFFSET) + 1; + } + val = clk_get_rate(clk->parent) / div; + return val; +} + +static struct clk periph_clk = { + __INIT_CLK_DEBUG(periph_clk) + .parent = &pll2_528_bus_main_clk, + .set_parent = _clk_periph_set_parent, + .get_rate = _clk_periph_get_rate, +}; + +static unsigned long _clk_axi_get_rate(struct clk *clk) +{ + u32 div, reg; + unsigned long val; + + reg = __raw_readl(MXC_CCM_CBCDR) & MXC_CCM_CBCDR_AXI_PODF_MASK; + div = (reg >> MXC_CCM_CBCDR_AXI_PODF_OFFSET); + + val = clk_get_rate(clk->parent) / (div + 1); + return val; +} + +static int _clk_axi_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_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_AXI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_AXI_PODF_BUSY), SPIN_DELAY)) + panic("pll _clk_axi_a_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_axi_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 int _clk_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + int mux; + + mux = _get_mux6(parent, &periph_clk, &pll2_pfd2_400M, + &pll3_pfd1_540M, NULL, NULL, NULL); + + if (mux == 0) { + /* Set the AXI_SEL mux */ + reg = __raw_readl(MXC_CCM_CBCDR) & ~MXC_CCM_CBCDR_AXI_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } else { + /* Set the AXI_ALT_SEL mux. */ + reg = __raw_readl(MXC_CCM_CBCDR) + & ~MXC_CCM_CBCDR_AXI_ALT_SEL_MASK; + reg |= ((mux - 1) << MXC_CCM_CBCDR_AXI_ALT_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCDR); + + /* Set the AXI_SEL mux */ + reg = __raw_readl(MXC_CCM_CBCDR) & ~MXC_CCM_CBCDR_AXI_SEL; + reg |= MXC_CCM_CBCDR_AXI_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } + return 0; +} + +static struct clk axi_clk = { + __INIT_CLK_DEBUG(axi_clk) + .parent = &periph_clk, + .set_parent = _clk_axi_set_parent, + .set_rate = _clk_axi_set_rate, + .get_rate = _clk_axi_get_rate, + .round_rate = _clk_axi_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; + 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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk ahb_clk = { + __INIT_CLK_DEBUG(ahb_clk) + .parent = &periph_clk, + .get_rate = _clk_ahb_get_rate, + .set_rate = _clk_ahb_set_rate, + .round_rate = _clk_ahb_round_rate, +}; + +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 struct clk tzasc2_clk = { + __INIT_CLK_DEBUG(tzasc2_clk) + .id = 0, + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk mx6fast1_clk = { + __INIT_CLK_DEBUG(mx6fast1_clk) + .id = 0, + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk mx6per1_clk = { + __INIT_CLK_DEBUG(mx6per1_clk) + .id = 0, + .parent = &ahb_clk, + .secondary = &mx6fast1_clk, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static int _clk_mmdc_ch1_axi_set_parent(struct clk *clk, + struct clk *parent) +{ + u32 reg; + int mux; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, &pll2_pfd2_400M, + &pll2_pfd0_352M, &pll2_200M, &pll3_sw_clk, NULL); + + if (mux <= 3) { + /* Set the pre_periph2_clk_sel multiplexer */ + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK; + reg |= mux << MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + /* Set the periph2_clk_sel multiplexer. */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERIPH2_CLK_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } else { + /* Select PLL3_SW_CLK from the periph2_clk2 + multiplexer */ + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_PERIPH2_CLK2_SEL; + __raw_writel(reg, MXC_CCM_CBCMR); + + /* Set the periph2_clk_sel multiplexer. */ + reg = __raw_readl(MXC_CCM_CBCDR); + reg &= ~MXC_CCM_CBCDR_PERIPH2_CLK_SEL; + reg |= MXC_CCM_CBCDR_PERIPH2_CLK_SEL; + __raw_writel(reg, MXC_CCM_CBCDR); + } + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_PERIPH2_CLK_SEL_BUSY), SPIN_DELAY)) + panic("_clk_mmdc_ch1_axi_set_parent failed\n"); + + return 0; +} + +static unsigned long _clk_mmdc_ch1_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCDR); + div = ((reg & MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK) >> + MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_mmdc_ch1_axi_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_MMDC_CH1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCDR); + + if (!WAIT(!(__raw_readl(MXC_CCM_CDHIPR) + & MXC_CCM_CDHIPR_MMDC_CH1_PODF_BUSY), SPIN_DELAY)) + panic("_clk_mmdc_ch1_axi_set_rate failed\n"); + + return 0; +} + +static unsigned long _clk_mmdc_ch1_axi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk mmdc_ch1_axi_clk[] = { + { + __INIT_CLK_DEBUG(mmdc_ch1_axi_clk) + .id = 0, + .parent = &pll2_pfd2_400M, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .secondary = &mmdc_ch1_axi_clk[1], + .set_parent = _clk_mmdc_ch1_axi_set_parent, + .get_rate = _clk_mmdc_ch1_axi_get_rate, + .set_rate = _clk_mmdc_ch1_axi_set_rate, + .round_rate = _clk_mmdc_ch1_axi_round_rate, + }, + { + .id = 1, + __INIT_CLK_DEBUG(mmdc_ch1_ipg_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .disable = _clk_disable, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .secondary = &tzasc2_clk, + }, +}; + +#if defined(CONFIG_SDMA_IRAM) || defined(CONFIG_SND_MXC_SOC_IRAM) +static struct clk ocram_clk = { + __INIT_CLK_DEBUG(ocram_clk) + .id = 0, + .parent = &axi_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; +#endif + +static unsigned long _clk_ipg_perclk_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + div = ((reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK) >> + MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipg_perclk_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 > 64)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_PERCLK_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + + +static unsigned long _clk_ipg_perclk_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 (div > 64) + div = 64; + + return parent_rate / div; +} + +static struct clk ipg_perclk = { + __INIT_CLK_DEBUG(ipg_perclk) + .parent = &osc_clk, + .set_parent = _clk_ipg_perclk_set_parent, + .get_rate = _clk_ipg_perclk_get_rate, + .set_rate = _clk_ipg_perclk_set_rate, + .round_rate = _clk_ipg_perclk_round_rate, +}; + +static struct clk spba_clk = { + __INIT_CLK_DEBUG(spba_clk) + .parent = &ipg_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, +}; + +static struct clk sdma_clk[] = { + { + __INIT_CLK_DEBUG(sdma_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &sdma_clk[1], + }, + { + .parent = &mx6per1_clk, +#ifdef CONFIG_SDMA_IRAM + .secondary = &ocram_clk, +#else + .secondary = &mmdc_ch1_axi_clk[0], +#endif + }, +}; + +static unsigned long mx6_timer_rate(void) +{ + u32 parent_rate = clk_get_rate(&osc_clk); + + u32 reg = __raw_readl(timer_base + MXC_TCTL); + u32 div; + + if ((reg & V2_TCTL_CLK_OSC_DIV8) == V2_TCTL_CLK_OSC_DIV8) { + if (cpu_is_mx6q()) + /* For MX6Q, only options are 24MHz or 24MHz/8*/ + return parent_rate / 8; + else { + /* For MX6DLS and MX6Solo, the rate is based on the + * divider value set in prescalar register. */ + div = __raw_readl(timer_base + MXC_TPRER); + div = (div >> V2_TPRER_PRE24M_OFFSET) & + V2_TPRER_PRE24M_MASK; + return parent_rate / (div + 1); + } + } + return 0; +} + +static unsigned long _clk_gpt_get_rate(struct clk *clk) +{ + unsigned long rate; + + if (mx6q_revision() == IMX_CHIP_REVISION_1_0) + return clk_get_rate(clk->parent); + + rate = mx6_timer_rate(); + if (!rate) + return clk_get_rate(clk->parent); + + return rate; +} + +static struct clk gpt_clk[] = { + { + __INIT_CLK_DEBUG(gpt_clk) + .parent = &osc_clk, + .id = 0, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .get_rate = _clk_gpt_get_rate, + }, +}; + +static unsigned long _clk_iim_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent); +} + +static struct clk iim_clk = { + __INIT_CLK_DEBUG(iim_clk) + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG6_OFFSET, + .disable = _clk_disable, + .get_rate = _clk_iim_get_rate, +}; + +static struct clk i2c_clk[] = { + { + __INIT_CLK_DEBUG(i2c_clk_0) + .id = 0, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_1) + .id = 1, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(i2c_clk_2) + .id = 2, + .parent = &ipg_perclk, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static int _clk_ipu1_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCDR3) + & ~MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_MASK; + + mux = _get_mux6(parent, &osc_clk, + &pll2_pfd2_400M, &pll3_120M, &pll3_pfd1_540M, NULL, NULL); + + reg |= (mux << MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static unsigned long _clk_ipu1_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR3); + div = ((reg & MXC_CCM_CSCDR3_IPU1_HSP_PODF_MASK) >> + MXC_CCM_CSCDR3_IPU1_HSP_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu1_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_CSCDR3); + reg &= ~MXC_CCM_CSCDR3_IPU1_HSP_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR3_IPU1_HSP_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static unsigned long _clk_ipu_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static struct clk ipu1_clk = { + __INIT_CLK_DEBUG(csi_clk) + .parent = &osc_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu1_set_parent, + .round_rate = _clk_ipu_round_rate, + .set_rate = _clk_ipu1_set_rate, + .get_rate = _clk_ipu1_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_ipu2_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCDR3) + & ~MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, + &pll2_pfd2_400M, &pll3_sw_clk, &pll3_pfd1_540M, NULL, NULL); + + reg |= (mux << MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static unsigned long _clk_ipu2_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR3); + div = ((reg & MXC_CCM_CSCDR3_IPU2_HSP_PODF_MASK) >> + MXC_CCM_CSCDR3_IPU2_HSP_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_ipu2_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_CSCDR3); + reg &= ~MXC_CCM_CSCDR3_IPU2_HSP_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR3_IPU2_HSP_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR3); + + return 0; +} + +static struct clk ipu2_clk = { + __INIT_CLK_DEBUG(elcdif_axi_clk) + .parent = &pll2_pfd2_400M, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ipu2_set_parent, + .round_rate = _clk_ipu_round_rate, + .set_rate = _clk_ipu2_set_rate, + .get_rate = _clk_ipu2_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk usdhc_dep_clk = { + .parent = &mmdc_ch1_axi_clk[0], + .secondary = &mx6per1_clk, + }; + +static unsigned long _clk_usdhc_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_usdhc1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC1_CLK_SEL; + + if (parent == &pll2_pfd0_352M) + reg |= (MXC_CCM_CSCMR1_USDHC1_CLK_SEL); + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc1_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc1_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk usdhc1_clk = { + __INIT_CLK_DEBUG(usdhc1_clk) + .id = 0, + .parent = &pll2_pfd2_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc1_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc1_set_rate, + .get_rate = _clk_usdhc1_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_usdhc2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC2_CLK_SEL; + + if (parent == &pll2_pfd0_352M) + reg |= (MXC_CCM_CSCMR1_USDHC2_CLK_SEL); + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc2_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc2_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC2_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk usdhc2_clk = { + __INIT_CLK_DEBUG(usdhc2_clk) + .id = 1, + .parent = &pll2_pfd2_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc2_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc2_set_rate, + .get_rate = _clk_usdhc2_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_usdhc3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC3_CLK_SEL; + + if (parent == &pll2_pfd0_352M) + reg |= (MXC_CCM_CSCMR1_USDHC3_CLK_SEL); + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc3_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc3_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC3_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + + +static struct clk usdhc3_clk = { + __INIT_CLK_DEBUG(usdhc3_clk) + .id = 2, + .parent = &pll2_pfd2_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc3_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc3_set_rate, + .get_rate = _clk_usdhc3_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static int _clk_usdhc4_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USDHC4_CLK_SEL; + + if (parent == &pll2_pfd0_352M) + reg |= (MXC_CCM_CSCMR1_USDHC4_CLK_SEL); + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_usdhc4_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCDR1); + div = ((reg & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >> + MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_usdhc4_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_CSCDR1); + reg &= ~MXC_CCM_CSCDR1_USDHC4_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + + +static struct clk usdhc4_clk = { + __INIT_CLK_DEBUG(usdhc4_clk) + .id = 3, + .parent = &pll2_pfd2_400M, + .secondary = &usdhc_dep_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_usdhc4_set_parent, + .round_rate = _clk_usdhc_round_rate, + .set_rate = _clk_usdhc4_set_rate, + .get_rate = _clk_usdhc4_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_ssi_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(1 << 6, div, &pre, &post); + + return parent_rate / (pre * post); +} + +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; + 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_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK | + MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static unsigned long _clk_extern_audio_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(1 << 3, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_extern_audio_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR2) & ~MXC_CCM_CSCMR2_ESAI_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll4_audio_main_clk, &pll3_pfd2_508M, + &pll3_pfd3_454M, &pll3_sw_clk, NULL, NULL); + reg |= mux << MXC_CCM_CSCMR2_ESAI_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCMR2); + + return 0; +} + +static unsigned long _clk_extern_audio_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + reg = __raw_readl(MXC_CCM_CS1CDR); + + 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); +} + +static int _clk_extern_audio_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + + if (rate == 24000000 && clk->parent == &pll4_audio_main_clk) { + /* If the requested rate is 24MHz, + * set the PLL4 to bypass mode. + */ + audio_pll_bypass = 1; + pre = post = 1; + } else { + div = parent_rate / rate; + if (div == 0) + div++; + if (((parent_rate / div) != rate) || div > 64) + return -EINVAL; + + audio_pll_bypass = 0; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + } + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK| + MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + +static struct clk extern_audio_clk = { + __INIT_CLK_DEBUG(extern_audio_clk) + .id = 0, + .parent = &pll3_sw_clk, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_rate = _clk_extern_audio_set_rate, + .get_rate = _clk_extern_audio_get_rate, + .set_parent = _clk_extern_audio_set_parent, + .round_rate = _clk_extern_audio_round_rate, +}; + + +static int _clk_ssi1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1) + & ~MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd2_508M, &pll3_pfd3_454M, + &pll4_audio_main_clk, NULL, NULL, NULL); + 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) + .parent = &pll3_pfd2_508M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ssi1_set_parent, + .set_rate = _clk_ssi1_set_rate, + .round_rate = _clk_ssi_round_rate, + .get_rate = _clk_ssi1_get_rate, + .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#ifndef CONFIG_SND_MXC_SOC_IRAM + .secondary = &mmdc_ch1_axi_clk[0], +#else + .secondary = &ocram_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; + 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_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS2CDR); + reg &= ~(MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK | + MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS2CDR); + + return 0; +} + + +static int _clk_ssi2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1) + & ~MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd2_508M, &pll3_pfd3_454M, + &pll4_audio_main_clk, NULL, NULL, NULL); + 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) + .parent = &pll3_pfd2_508M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ssi2_set_parent, + .set_rate = _clk_ssi2_set_rate, + .round_rate = _clk_ssi_round_rate, + .get_rate = _clk_ssi2_get_rate, + .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#ifndef CONFIG_SND_MXC_SOC_IRAM + .secondary = &mmdc_ch1_axi_clk[0], +#else + .secondary = &ocram_clk, +#endif + }, +}; + +static unsigned long _clk_ssi3_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; + 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_ssi3_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(1 << 6, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CS1CDR); + reg &= ~(MXC_CCM_CS1CDR_SSI3_CLK_PODF_MASK| + MXC_CCM_CS1CDR_SSI3_CLK_PRED_MASK); + reg |= (post - 1) << MXC_CCM_CS1CDR_SSI3_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CS1CDR_SSI3_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CS1CDR); + + return 0; +} + + +static int _clk_ssi3_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_SSI3_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd2_508M, &pll3_pfd3_454M, + &pll4_audio_main_clk, NULL, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_SSI3_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk ssi3_clk[] = { + { + __INIT_CLK_DEBUG(ssi3_clk) + .parent = &pll3_pfd2_508M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ssi3_set_parent, + .set_rate = _clk_ssi3_set_rate, + .round_rate = _clk_ssi_round_rate, + .get_rate = _clk_ssi3_get_rate, + .flags = AHB_AUDIO_SET_POINT | CPU_FREQ_TRIG_UPDATE, +#ifndef CONFIG_SND_MXC_SOC_IRAM + .secondary = &mmdc_ch1_axi_clk[0], +#else + .secondary = &ocram_clk, +#endif + }, +}; + +static unsigned long _clk_epdc_lcdif_pix_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 pre, post; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + /* Round to closest divisor */ + if ((parent_rate % rate) > (rate / 2)) + div++; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + + if (div > 64) + div = 64; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static unsigned long _clk_pxp_epdc_axi_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 div; + u32 parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + /* Round to closest divisor */ + if ((parent_rate % rate) > (rate / 2)) + div++; + + /* Make sure rate is not greater than the maximum value for the clock. + * Also prevent a div of 0. + */ + if (div == 0) + div++; + + if (div > 8) + div = 8; + + return parent_rate / div; +} + +static unsigned long _clk_pxp_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CHSCCDR); + + div = ((reg & MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK) >> + MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_pxp_axi_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_CHSCCDR); + reg &= ~MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CHSCCDR); + + return 0; +} + +static int _clk_pxp_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd0_352M, &pll2_pfd2_400M, &pll3_pfd1_540M); + reg |= (mux << MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CHSCCDR); + + /* Derive clock from divided pre-muxed pxp_axi clock.*/ + mux = 0; + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET), + MXC_CCM_CHSCCDR); + + return 0; +} + +static unsigned long _clk_epdc_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CHSCCDR); + + div = ((reg & MXC_CCM_CHSCCDR_IPU1_DI1_PODF_MASK) + >> MXC_CCM_CHSCCDR_IPU1_DI1_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_epdc_axi_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_CHSCCDR); + reg &= ~MXC_CCM_CHSCCDR_IPU1_DI1_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CHSCCDR_IPU1_DI1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CHSCCDR); + + return 0; +} + +static int _clk_epdc_axi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd0_352M, &pll2_pfd2_400M, &pll3_pfd1_540M); + reg |= (mux << MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CHSCCDR); + + /* Derive clock from divided pre-muxed ipu1_di0 clock.*/ + mux = 0; + reg = __raw_readl(MXC_CCM_CHSCCDR) + & ~MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_OFFSET), + MXC_CCM_CHSCCDR); + + return 0; +} + +static struct clk pxp_axi_clk = { + __INIT_CLK_DEBUG(pxp_axi_clk) + .id = 0, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_pxp_axi_set_parent, + .set_rate = _clk_pxp_axi_set_rate, + .round_rate = _clk_pxp_epdc_axi_round_rate, + .get_rate = _clk_pxp_axi_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk epdc_axi_clk = { + __INIT_CLK_DEBUG(epdc_axi_clk) + .id = 0, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_epdc_axi_set_parent, + .set_rate = _clk_epdc_axi_set_rate, + .round_rate = _clk_pxp_epdc_axi_round_rate, + .get_rate = _clk_epdc_axi_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_lcdif_pix_get_rate(struct clk *clk) +{ + u32 reg, pre, post; + + reg = __raw_readl(MXC_CCM_CSCDR2); + + pre = ((reg & MXC_CCM_CSCDR2_IPU2_DI0_PODF_MASK) >> + MXC_CCM_CSCDR2_IPU2_DI0_PODF_OFFSET) + 1; + + reg = __raw_readl(MXC_CCM_CSCMR1); + post = ((reg & MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK) >> + MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / (pre * post); +} + +static int _clk_lcdif_pix_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 > 64)) + return -EINVAL; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~MXC_CCM_CSCDR2_IPU2_DI0_PODF_MASK; + reg |= (pre - 1) << MXC_CCM_CSCDR2_IPU2_DI0_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + /* + * fixup: + * Bits 22 and 21 of the divide value are inverted before + * going into the divider port. + */ + post = (post - 1) ^ 0x6; + + reg = __raw_readl(MXC_CCM_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK; + reg |= post << MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static int _clk_lcdif_pix_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd0_352M, &pll3_pfd0_720M, &pll3_pfd1_540M); + reg |= (mux << MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR2); + + /* Derive clock from divided pre-muxed lcdif_pix clock.*/ + mux = 0; + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_MASK; + __raw_writel(reg | (mux << MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_OFFSET), + MXC_CCM_CSCDR2); + + return 0; +} + +static unsigned long _clk_epdc_pix_get_rate(struct clk *clk) +{ + u32 reg, pre, post; + + reg = __raw_readl(MXC_CCM_CSCDR2); + + pre = ((reg & MXC_CCM_CSCDR2_IPU2_DI1_PODF_MASK) >> + MXC_CCM_CSCDR2_IPU2_DI1_PODF_OFFSET) + 1; + + reg = __raw_readl(MXC_CCM_CBCMR); + post = ((reg & MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK) >> + MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET) + 1; + + + return clk_get_rate(clk->parent) / (pre * post); +} + +static int _clk_epdc_pix_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 > 64)) + return -EINVAL; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CSCDR2); + reg &= ~MXC_CCM_CSCDR2_IPU2_DI1_PODF_MASK; + reg |= (pre - 1) << MXC_CCM_CSCDR2_IPU2_DI1_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCDR2); + + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK; + reg |= (post - 1) << MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static int _clk_epdc_pix_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCDR2) + & ~MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_528_bus_main_clk, + &pll3_usb_otg_main_clk, &pll5_video_main_clk, + &pll2_pfd0_352M, &pll2_pfd1_594M, &pll3_pfd1_540M); + reg |= (mux << MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static struct clk lcdif_pix_clk = { + __INIT_CLK_DEBUG(lcdif_pix_clk) + .id = 0, + .parent = &pll5_video_main_clk, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_lcdif_pix_set_parent, + .set_rate = _clk_lcdif_pix_set_rate, + .round_rate = _clk_epdc_lcdif_pix_round_rate, + .get_rate = _clk_lcdif_pix_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static struct clk epdc_pix_clk = { + __INIT_CLK_DEBUG(epdc_pix_clk) + .id = 0, + .parent = &pll3_pfd1_540M, + .enable_reg = MXC_CCM_CCGR3, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_epdc_pix_set_parent, + .set_rate = _clk_epdc_pix_set_rate, + .round_rate = _clk_epdc_lcdif_pix_round_rate, + .get_rate = _clk_epdc_pix_get_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; +static unsigned long _clk_spdif_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(1 << 3, div, &pre, &post); + + return parent_rate / (pre * post); +} + +static int _clk_spdif0_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CDCDR) + & ~MXC_CCM_CDCDR_SPDIF0_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll4_audio_main_clk, + &pll3_pfd2_508M, &pll3_pfd3_454M, + &pll3_sw_clk, NULL, NULL); + reg |= mux << MXC_CCM_CDCDR_SPDIF0_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static unsigned long _clk_spdif0_get_rate(struct clk *clk) +{ + u32 reg, pred, podf; + + 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; + + return clk_get_rate(clk->parent) / (pred * podf); +} + +static int _clk_spdif0_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 > 64) + return -EINVAL; + + __calc_pre_post_dividers(1 << 3, div, &pre, &post); + + reg = __raw_readl(MXC_CCM_CDCDR); + reg &= ~(MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK| + MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK); + reg |= (post - 1) << MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET; + + __raw_writel(reg, MXC_CCM_CDCDR); + + return 0; +} + +static struct clk spdif0_clk[] = { + { + __INIT_CLK_DEBUG(spdif0_clk_0) + .id = 0, + .parent = &pll3_sw_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG7_OFFSET, + .disable = _clk_disable, + .secondary = &spdif0_clk[1], + .set_rate = _clk_spdif0_set_rate, + .get_rate = _clk_spdif0_get_rate, + .set_parent = _clk_spdif0_set_parent, + .round_rate = _clk_spdif_round_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + __INIT_CLK_DEBUG(spdif0_clk_1) + .id = 1, + .parent = &ipg_clk, + .secondary = &spba_clk, + }, +}; + +static int _clk_ecspi_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCDR2) & ~MXC_CCM_CSCDR2_ECSPI_CLK_SEL_MASK; + + if (parent == &pll3_60M) + mux = 0; + else + mux = 1; /* osc */ + + reg |= mux << MXC_CCM_CSCDR2_ECSPI_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCDR2); + + return 0; +} + +static int _clk_fec_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int reg, div = 1; + + switch (rate) { + case 25000000: + div = 0; + break; + case 50000000: + div = 1; + break; + case 100000000: + div = 2; + break; + case 125000000: + div = 3; + break; + default: + return -EINVAL; + } + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_ENET_DIV_SELECT_MASK; + reg |= (div << ANADIG_PLL_ENET_DIV_SELECT_OFFSET); + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + return 0; +} + +static unsigned long _clk_fec_get_rate(struct clk *clk) +{ + unsigned int div; + + div = (__raw_readl(PLL8_ENET_BASE_ADDR)) + & ANADIG_PLL_ENET_DIV_SELECT_MASK; + + switch (div) { + case 0: + div = 20; + break; + case 1: + div = 10; + break; + case 3: + div = 5; + break; + case 4: + div = 4; + break; + } + + return 500000000 / div; +} + +static int _clk_fec_enable(struct clk *clk) +{ + unsigned int reg; + + /* Enable ENET ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg &= ~ANADIG_PLL_BYPASS; + reg |= ANADIG_PLL_ENABLE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); + + _clk_enable(clk); + return 0; +} + +static void _clk_fec_disable(struct clk *clk) +{ + unsigned int reg; + + _clk_disable(clk); + + /* Enable ENET ref clock */ + reg = __raw_readl(PLL8_ENET_BASE_ADDR); + reg |= ANADIG_PLL_BYPASS; + reg &= ~ANADIG_PLL_ENABLE; + __raw_writel(reg, PLL8_ENET_BASE_ADDR); +} + +static struct clk fec_clk[] = { + { + __INIT_CLK_DEBUG(fec_clk) + .id = 0, + .parent = &pll6_enet_main_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_fec_enable, + .disable = _clk_fec_disable, + .set_rate = _clk_fec_set_rate, + .get_rate = _clk_fec_get_rate, + .secondary = &fec_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mmdc_ch1_axi_clk[0], + .secondary = &mx6per1_clk, + }, +}; + +static unsigned long _clk_fec_mdc_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent); +} + +static struct clk fec_mdc_clk = { + __INIT_CLK_DEBUG(fec_mdc_clk) + .parent = &ipg_clk, + .get_rate = _clk_fec_mdc_get_rate, +}; + +static struct clk ecspi_clk[] = { + { + __INIT_CLK_DEBUG(ecspi0_clk) + .id = 0, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ecspi_set_parent, + }, + { + __INIT_CLK_DEBUG(ecspi1_clk) + .id = 1, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ecspi_set_parent, + }, + { + __INIT_CLK_DEBUG(ecspi2_clk) + .id = 2, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ecspi_set_parent, + }, + { + __INIT_CLK_DEBUG(ecspi3_clk) + .id = 3, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ecspi_set_parent, + }, + { + __INIT_CLK_DEBUG(ecspi4_clk) + .id = 4, + .parent = &pll3_60M, + .secondary = &spba_clk, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG4_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_parent = _clk_ecspi_set_parent, + }, +}; + +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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_emi_slow_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CSCMR1) + & ~MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK; + + mux = _get_mux6(parent, &axi_clk, &pll3_usb_otg_main_clk, + &pll2_pfd2_400M, &pll3_pfd0_720M, NULL, NULL); + reg |= (mux << MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET); + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static unsigned long _clk_emi_slow_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CSCMR1); + div = ((reg & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK) >> + MXC_CCM_CSCMR1_ACLK_EMI_SLOW_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; + 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_CSCMR1); + reg &= ~MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk emi_slow_clk = { + __INIT_CLK_DEBUG(emi_slow_clk) + .id = 0, + .parent = &axi_clk, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG5_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .set_rate = _clk_emi_slow_set_rate, + .get_rate = _clk_emi_slow_get_rate, + .round_rate = _clk_emi_slow_round_rate, + .set_parent = _clk_emi_slow_set_parent, +}; + +static unsigned long _clk_uart_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 (div > 64) + div = 64; + + return parent_rate / div; +} + +static int _clk_uart_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 > 64)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CSCDR1) & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + reg |= ((div - 1) << MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET); + + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static unsigned long _clk_uart_get_rate(struct clk *clk) +{ + u32 reg, div; + unsigned long val; + + reg = __raw_readl(MXC_CCM_CSCDR1) & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; + div = (reg >> MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET) + 1; + val = clk_get_rate(clk->parent) / div; + + /* If the parent is OSC, there is an in-built divide by 6. */ + if (clk->parent == &osc_clk) + val = val / 6; + + return val; +} + +static int _clk_uart_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg, mux; + + reg = __raw_readl(MXC_CCM_CSCDR1) & ~MXC_CCM_CSCDR1_UART_CLK_SEL_MASK; + + if (parent == &osc_clk) + mux = 1; + else + mux = 0; /* osc */ + + reg |= mux << MXC_CCM_CSCDR1_UART_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCDR1); + + return 0; +} + +static struct clk uart_clk[] = { + { + __INIT_CLK_DEBUG(uart_clk) + .id = 0, + .parent = &pll3_80M, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG12_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + .secondary = &uart_clk[1], + .set_rate = _clk_uart_set_rate, + .get_rate = _clk_uart_get_rate, + .round_rate = _clk_uart_round_rate, + .set_parent = _clk_uart_set_parent, + }, + { + __INIT_CLK_DEBUG(uart_serial_clk) + .id = 1, + .enable_reg = MXC_CCM_CCGR5, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk aips_tz2_clk = { + __INIT_CLK_DEBUG(aips_tz2_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +static struct clk aips_tz1_clk = { + __INIT_CLK_DEBUG(aips_tz1_clk) + .parent = &ahb_clk, + .enable_reg = MXC_CCM_CCGR0, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable_inwait, +}; + +/* Raster 2D and OpenVG GPU core share the same clock gate bits, + * so we abstract gpu2d_core_clk to handle clock gate enabling + * and disabling for both 2D core. These two 2D core have + * different multiplexer, so gpu2d_axi_clk and openvg_axi_clk + * are provided for them to control the multiplexer individually. +*/ +static struct clk gpu2d_core_clk = { + __INIT_CLK_DEBUG(gpu2d_core_clk) + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR1, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, + .disable = _clk_disable, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_openvg_axi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_openvg_axi_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CBCMR) + & ~MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll3_pfd1_540M, + &pll3_usb_otg_main_clk, + &pll2_528_bus_main_clk, &pll2_pfd2_400M, NULL, NULL); + reg |= (mux << MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static unsigned long _clk_openvg_axi_get_rate(struct clk *clk) +{ + u32 reg, div; + + reg = __raw_readl(MXC_CCM_CBCMR); + div = ((reg & MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK) >> + MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_openvg_axi_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 (div > 8) + div = 8; + + reg = __raw_readl(MXC_CCM_CBCMR); + reg &= ~MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk openvg_axi_clk = { + __INIT_CLK_DEBUG(openvg_axi_clk) + .parent = &pll2_528_bus_main_clk, + .set_parent = _clk_openvg_axi_set_parent, + .set_rate = _clk_openvg_axi_set_rate, + .get_rate = _clk_openvg_axi_get_rate, + .round_rate = _clk_openvg_axi_round_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +static unsigned long _clk_gpu2d_axi_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 (div > 8) + div = 8; + + return parent_rate / div; +} + +static int _clk_gpu2d_axi_set_parent(struct clk *clk, struct clk *parent) +{ + int mux; + u32 reg = __raw_readl(MXC_CCM_CBCMR) & + ~MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_MASK; + + mux = _get_mux6(parent, &pll2_pfd2_400M, &pll3_usb_otg_main_clk, + &pll3_pfd1_540M, &pll2_528_bus_main_clk, NULL, NULL); + reg |= (mux << MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_OFFSET); + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static unsigned long _clk_gpu2d_axi_get_rate(struct clk *clk) +{ + u32 reg, div = 1; + + reg = __raw_readl(MXC_CCM_CBCMR); + div = ((reg & MXC_CCM_CBCMR_GPU3D_SHADER_PODF_MASK) >> + MXC_CCM_CBCMR_GPU3D_SHADER_PODF_OFFSET) + 1; + + return clk_get_rate(clk->parent) / div; +} + +static int _clk_gpu2d_axi_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_CBCMR); + reg &= ~MXC_CCM_CBCMR_GPU3D_SHADER_PODF_MASK; + reg |= (div - 1) << MXC_CCM_CBCMR_GPU3D_SHADER_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_CBCMR); + + return 0; +} + +static struct clk gpu2d_axi_clk = { + __INIT_CLK_DEBUG(gpu2d_axi_clk) + .parent = &pll2_528_bus_main_clk, + .set_parent = _clk_gpu2d_axi_set_parent, + .set_rate = _clk_gpu2d_axi_set_rate, + .get_rate = _clk_gpu2d_axi_get_rate, + .round_rate = _clk_gpu2d_axi_round_rate, + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, +}; + +/* set the parent by the ipcg table */ + +static struct clk pwm_clk[] = { + { + __INIT_CLK_DEBUG(pwm_clk_0) + .parent = &ipg_perclk, + .id = 0, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG8_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm_clk_1) + .parent = &ipg_perclk, + .id = 1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG9_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm_clk_2) + .parent = &ipg_perclk, + .id = 2, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG10_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, + { + __INIT_CLK_DEBUG(pwm_clk_3) + .parent = &ipg_perclk, + .id = 3, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG11_OFFSET, + .enable = _clk_enable, + .disable = _clk_disable, + }, +}; + +static struct clk usboh3_clk[] = { + { + __INIT_CLK_DEBUG(usboh3_clk) + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CCGR6, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_disable, + .secondary = &usboh3_clk[1], + .flags = AHB_HIGH_SET_POINT | CPU_FREQ_TRIG_UPDATE, + }, + { + .parent = &mmdc_ch1_axi_clk[0], + .secondary = &mx6per1_clk, + }, +}; + +static int _clk_enable1(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_disable1(struct clk *clk) +{ + u32 reg; + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg; + + if (parent == &pll3_usb_otg_main_clk) + sel = 0; + else if (parent == &pll2_528_bus_main_clk) + sel = 1; + else if (parent == &pll1_sys_main_clk) + sel = 2; + else if (parent == &pll5_video_main_clk) + sel = 3; + else if (parent == &axi_clk) + sel = 5; + else if (parent == &pxp_axi_clk) + sel = 7; + else if (parent == &epdc_axi_clk) + sel = 8; + else if (parent == &lcdif_pix_clk) + sel = 9; + else if (parent == &epdc_pix_clk) + sel = 10; + 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 if (parent == &pll4_audio_main_clk) + sel = 15; + 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 unsigned long _clk_clko_get_rate(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCOSR); + u32 div = ((reg & MXC_CCM_CCOSR_CKOL_DIV_MASK) >> + MXC_CCM_CCOSR_CKOL_DIV_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKOL_DIV_MASK; + reg |= (div - 1) << MXC_CCM_CCOSR_CKOL_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long _clk_clko_round_rate(struct clk *clk, + unsigned long rate) +{ + u32 parent_rate = clk_get_rate(clk->parent); + u32 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 (div > 8) + div = 8; + return parent_rate / div; +} + +static int _clk_clko2_set_parent(struct clk *clk, struct clk *parent) +{ + u32 sel, reg; + + if (parent == &mmdc_ch1_axi_clk[0]) + sel = 0; + else if (parent == &usdhc4_clk) + sel = 2; + else if (parent == &usdhc1_clk) + sel = 3; + else if (parent == &ecspi_clk[0]) + sel = 6; + else if (parent == &usdhc3_clk) + sel = 8; + else if (parent == &ipu1_clk) + sel = 11; + else if (parent == &ipu2_clk) + sel = 12; + + else if (parent == &osc_clk) + sel = 14; + else if (parent == &usdhc2_clk) + sel = 17; + else if (parent == &ssi1_clk[0]) + sel = 18; + else if (parent == &ssi2_clk[0]) + sel = 19; + else if (parent == &ssi3_clk[0]) + sel = 20; + else if (parent == &uart_clk[0]) + sel = 28; + else if (parent == &spdif0_clk[0]) + sel = 29; + else if (parent == &spdif0_clk[1]) + sel = 30; + else + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKO2_SEL_MASK; + reg |= sel << MXC_CCM_CCOSR_CKO2_SEL_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static unsigned long _clk_clko2_get_rate(struct clk *clk) +{ + u32 reg = __raw_readl(MXC_CCM_CCOSR); + u32 div = ((reg & MXC_CCM_CCOSR_CKO2_DIV_MASK) >> + MXC_CCM_CCOSR_CKO2_DIV_OFFSET) + 1; + return clk_get_rate(clk->parent) / div; +} + +static int _clk_clko2_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 parent_rate = clk_get_rate(clk->parent); + u32 div = parent_rate / rate; + + if (div == 0) + div++; + if (((parent_rate / div) != rate) || (div > 8)) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCOSR); + reg &= ~MXC_CCM_CCOSR_CKO2_DIV_MASK; + reg |= (div - 1) << MXC_CCM_CCOSR_CKO2_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCOSR); + return 0; +} + +static struct clk clko_clk = { + __INIT_CLK_DEBUG(clko_clk) + .parent = &pll2_528_bus_main_clk, + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCOSR, + .enable_shift = MXC_CCM_CCOSR_CKOL_EN_OFFSET, + .disable = _clk_disable1, + .set_parent = _clk_clko_set_parent, + .set_rate = _clk_clko_set_rate, + .get_rate = _clk_clko_get_rate, + .round_rate = _clk_clko_round_rate, +}; + +static struct clk clko2_clk = { + __INIT_CLK_DEBUG(clko2_clk) + .parent = &usdhc4_clk, + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCOSR, + .enable_shift = MXC_CCM_CCOSR_CKO2_EN_OFFSET, + .disable = _clk_disable1, + .set_parent = _clk_clko2_set_parent, + .set_rate = _clk_clko2_set_rate, + .get_rate = _clk_clko2_get_rate, + .round_rate = _clk_clko_round_rate, +}; + +static struct clk perfmon0_clk = { + __INIT_CLK_DEBUG(perfmon0_clk) + .parent = &mmdc_ch1_axi_clk[0], + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG1_OFFSET, + .disable = _clk_disable1, +}; + +static struct clk perfmon1_clk = { + __INIT_CLK_DEBUG(perfmon1_clk) + .parent = &ipu1_clk, + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG2_OFFSET, + .disable = _clk_disable1, +}; + +static struct clk perfmon2_clk = { + __INIT_CLK_DEBUG(perfmon2_clk) + .parent = &mmdc_ch1_axi_clk[0], + .enable = _clk_enable1, + .enable_reg = MXC_CCM_CCGR4, + .enable_shift = MXC_CCM_CCGRx_CG3_OFFSET, + .disable = _clk_disable1, +}; + +static struct clk dummy_clk = { + .id = 0, +}; + +#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_sys_main_clk), + _REGISTER_CLOCK(NULL, "pll1_sw_clk", pll1_sw_clk), + _REGISTER_CLOCK(NULL, "pll2", pll2_528_bus_main_clk), + _REGISTER_CLOCK(NULL, "pll2_pfd_400M", pll2_pfd2_400M), + _REGISTER_CLOCK(NULL, "pll2_pfd0_352M", pll2_pfd0_352M), + _REGISTER_CLOCK(NULL, "pll2_pfd1_594M", pll2_pfd1_594M), + _REGISTER_CLOCK(NULL, "pll2_200M", pll2_200M), + _REGISTER_CLOCK(NULL, "pll3_main_clk", pll3_usb_otg_main_clk), + _REGISTER_CLOCK(NULL, "pll3_pfd2_508M", pll3_pfd2_508M), + _REGISTER_CLOCK(NULL, "pll3_pfd3_454M", pll3_pfd3_454M), + _REGISTER_CLOCK(NULL, "pll3_pfd0_720M", pll3_pfd0_720M), + _REGISTER_CLOCK(NULL, "pll3_pfd_540M", pll3_pfd1_540M), + _REGISTER_CLOCK(NULL, "pll3_sw_clk", pll3_sw_clk), + _REGISTER_CLOCK(NULL, "pll3_120M", pll3_120M), + _REGISTER_CLOCK(NULL, "pll3_80M", pll3_80M), + _REGISTER_CLOCK(NULL, "pll3_60M", pll3_60M), + _REGISTER_CLOCK(NULL, "pll4", pll4_audio_main_clk), + _REGISTER_CLOCK(NULL, "pll5", pll5_video_main_clk), + _REGISTER_CLOCK(NULL, "pll6", pll6_enet_main_clk), + _REGISTER_CLOCK(NULL, "extern_audio_clk", extern_audio_clk), + _REGISTER_CLOCK(NULL, "cpu_clk", cpu_clk), + _REGISTER_CLOCK("smp_twd", NULL, twd_clk), + _REGISTER_CLOCK(NULL, "periph_clk", periph_clk), + _REGISTER_CLOCK(NULL, "axi_clk", axi_clk), + _REGISTER_CLOCK(NULL, "mmdc_ch0_axi", mmdc_ch1_axi_clk[0]), + _REGISTER_CLOCK(NULL, "ahb", ahb_clk), + _REGISTER_CLOCK(NULL, "ipg_clk", ipg_clk), + _REGISTER_CLOCK(NULL, "ipg_perclk", ipg_perclk), + _REGISTER_CLOCK(NULL, "spba", spba_clk), + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk[0]), + _REGISTER_CLOCK(NULL, "iim_clk", iim_clk), + _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(NULL, "csi_clk", ipu1_clk), + _REGISTER_CLOCK(NULL, "elcdif_axi", ipu2_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, usdhc1_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, usdhc2_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, usdhc3_clk), + _REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, usdhc4_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, "pxp_axi", pxp_axi_clk), + _REGISTER_CLOCK(NULL, "epdc_axi", epdc_axi_clk), + _REGISTER_CLOCK(NULL, "epdc_pix", epdc_pix_clk), + _REGISTER_CLOCK(NULL, "elcdif_pix", lcdif_pix_clk), + _REGISTER_CLOCK("mxc_spdif.0", NULL, spdif0_clk[0]), + _REGISTER_CLOCK("imx6q-ecspi.0", NULL, ecspi_clk[0]), + _REGISTER_CLOCK("imx6q-ecspi.1", NULL, ecspi_clk[1]), + _REGISTER_CLOCK("imx6q-ecspi.2", NULL, ecspi_clk[2]), + _REGISTER_CLOCK("imx6q-ecspi.3", NULL, ecspi_clk[3]), + _REGISTER_CLOCK("imx6q-ecspi.4", NULL, ecspi_clk[4]), + _REGISTER_CLOCK(NULL, "emi_slow_clk", emi_slow_clk), + _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[0]), + _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[0]), + _REGISTER_CLOCK(NULL, "gpt", gpt_clk[0]), + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk[0]), + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm_clk[1]), + _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm_clk[2]), + _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm_clk[3]), + _REGISTER_CLOCK(NULL, "fec_clk", fec_clk[0]), + _REGISTER_CLOCK(NULL, "fec_mdc_clk", fec_mdc_clk), + _REGISTER_CLOCK(NULL, "usboh3_clk", usboh3_clk[0]), + _REGISTER_CLOCK(NULL, "usb_phy1_clk", usb_phy1_clk), + _REGISTER_CLOCK(NULL, "usb_phy3_clk", usb_phy3_clk), + _REGISTER_CLOCK(NULL, "usb_phy4_clk", usb_phy4_clk), + _REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk), + _REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk), + _REGISTER_CLOCK(NULL, "kpp", dummy_clk), + _REGISTER_CLOCK(NULL, NULL, aips_tz2_clk), + _REGISTER_CLOCK(NULL, NULL, aips_tz1_clk), + _REGISTER_CLOCK(NULL, "clko_clk", clko_clk), + _REGISTER_CLOCK(NULL, "clko2_clk", clko2_clk), + _REGISTER_CLOCK("mxs-perfmon.0", "perfmon", perfmon0_clk), + _REGISTER_CLOCK("mxs-perfmon.1", "perfmon", perfmon1_clk), + _REGISTER_CLOCK("mxs-perfmon.2", "perfmon", perfmon2_clk), + _REGISTER_CLOCK(NULL, "anaclk_1", anaclk_1), + _REGISTER_CLOCK(NULL, "anaclk_2", anaclk_2), + _REGISTER_CLOCK(NULL, "gpu2d_clk", gpu2d_core_clk), + _REGISTER_CLOCK(NULL, "gpu2d_axi_clk", gpu2d_axi_clk), + _REGISTER_CLOCK(NULL, "openvg_axi_clk", openvg_axi_clk), + _REGISTER_CLOCK(NULL, "rng_clk", dummy_clk), + _REGISTER_CLOCK(NULL, "dcp_clk", dummy_clk), +}; + +static void clk_tree_init(void) + +{ + unsigned int reg; + + reg = __raw_readl(MMDC_MDMISC_OFFSET); + /* + * For lpddr2 board, current freq only support up to 400MHz, + * in this case, periph clk will set to 400MHz in uboot, + * so in clock init, we need to check whether the ddr clock + * is set to 400MHz, if yes, then we should set periph clk + * parent to pll2_pfd2_400M. + */ + if ((reg & MMDC_MDMISC_DDR_TYPE_MASK) == + (0x1 << MMDC_MDMISC_DDR_TYPE_OFFSET)) { + clk_set_parent(&periph_clk, &pll2_pfd2_400M); + } +} + + +int __init mx6sl_clocks_init(unsigned long ckil, unsigned long osc, + unsigned long ckih1, unsigned long ckih2) +{ + int i; + u32 parent_rate, rate; + unsigned long ipg_clk_rate, max_arm_wait_clk; + + external_low_reference = ckil; + external_high_reference = ckih1; + ckih2_reference = ckih2; + oscillator_reference = osc; + + timer_base = ioremap(GPT_BASE_ADDR, SZ_4K); + apll_base = ioremap(ANATOP_BASE_ADDR, SZ_4K); + + for (i = 0; i < ARRAY_SIZE(lookups); i++) { + clkdev_add(&lookups[i]); + clk_debug_register(lookups[i].clk); + } + + /* GPT will source from perclk, hence ipg_perclk + * should be from OSC24M */ + clk_set_parent(&ipg_perclk, &osc_clk); + + + /*IPG_PERCLK sources I2C. + * I2C needs a minimum of 12.8MHz as its source + * to acheive 400KHz speed. + * Hence set ipg_perclk to 24MHz. + */ + + clk_set_rate(&ipg_perclk, 24000000); + + gpt_clk[0].parent = &ipg_perclk; + gpt_clk[0].get_rate = NULL; + + mxc_timer_init(&gpt_clk[0], timer_base, MXC_INT_GPT); + + /* keep correct count. */ + clk_enable(&cpu_clk); + clk_enable(&periph_clk); + clk_enable(&mmdc_ch1_axi_clk[0]); + + clk_tree_init(); + + /* Set AHB to 132MHz. */ + clk_set_rate(&ahb_clk, clk_round_rate(&ahb_clk, 132000000)); + + /* Disable un-necessary PFDs & PLLs */ + pll2_pfd0_352M.disable(&pll2_pfd0_352M); + pll2_pfd1_594M.disable(&pll2_pfd1_594M); + + pll3_pfd3_454M.disable(&pll3_pfd3_454M); + pll3_pfd2_508M.disable(&pll3_pfd2_508M); + pll3_pfd1_540M.disable(&pll3_pfd1_540M); + pll3_pfd0_720M.disable(&pll3_pfd0_720M); + + pll3_usb_otg_main_clk.disable(&pll3_usb_otg_main_clk); + pll4_audio_main_clk.disable(&pll4_audio_main_clk); + pll5_video_main_clk.disable(&pll5_video_main_clk); + pll6_enet_main_clk.disable(&pll6_enet_main_clk); + + /* Initialize Audio and Video PLLs to valid frequency (650MHz). */ + clk_set_rate(&pll4_audio_main_clk, 650000000); + clk_set_rate(&pll5_video_main_clk, 650000000); + + clk_set_parent(&clko_clk, &ipg_clk); + + mx6_cpu_op_init(); + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + + /* Gate off all possible clocks */ + if (mxc_jtag_enabled) { + __raw_writel(3 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG2_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 3 << MXC_CCM_CCGRx_CG0_OFFSET, MXC_CCM_CCGR0); + } else { + __raw_writel(1 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG1_OFFSET | + 3 << MXC_CCM_CCGRx_CG0_OFFSET, MXC_CCM_CCGR0); + } + __raw_writel(3 << MXC_CCM_CCGRx_CG10_OFFSET | + 3 << MXC_CCM_CCGRx_CG11_OFFSET, MXC_CCM_CCGR1); + __raw_writel(1 << MXC_CCM_CCGRx_CG12_OFFSET | + 1 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG10_OFFSET | + 3 << MXC_CCM_CCGRx_CG9_OFFSET | + 3 << MXC_CCM_CCGRx_CG8_OFFSET, MXC_CCM_CCGR2); + __raw_writel(1 << MXC_CCM_CCGRx_CG14_OFFSET | + 3 << MXC_CCM_CCGRx_CG13_OFFSET | + 3 << MXC_CCM_CCGRx_CG12_OFFSET | + 3 << MXC_CCM_CCGRx_CG11_OFFSET | + 3 << MXC_CCM_CCGRx_CG10_OFFSET, MXC_CCM_CCGR3); + __raw_writel(3 << MXC_CCM_CCGRx_CG7_OFFSET | + 1 << MXC_CCM_CCGRx_CG6_OFFSET | + 1 << MXC_CCM_CCGRx_CG4_OFFSET, MXC_CCM_CCGR4); + __raw_writel(1 << MXC_CCM_CCGRx_CG0_OFFSET, MXC_CCM_CCGR5); + + __raw_writel(0, MXC_CCM_CCGR6); + + /* Bypass MMDC_CH0 handshake */ + __raw_writel(0x20000, MXC_CCM_CCDR); + + /* S/PDIF */ + clk_set_parent(&spdif0_clk[0], &pll3_pfd3_454M); + + /* pxp & epdc axi */ + clk_set_parent(&pxp_axi_clk, &pll2_pfd2_400M); + clk_set_rate(&pxp_axi_clk, 198000000); + clk_set_parent(&epdc_axi_clk, &pll2_pfd2_400M); + clk_set_rate(&epdc_axi_clk, 198000000); + + /* epdc pix - PLL5 as parent */ + clk_set_parent(&epdc_pix_clk, &pll5_video_main_clk); + /* lcdif pix - PLL5 as parent */ + clk_set_parent(&lcdif_pix_clk, &pll5_video_main_clk); + + clk_set_parent(&ssi2_clk[0], &pll4_audio_main_clk); + + lp_high_freq = 0; + lp_med_freq = 0; + + /* Get current ARM_PODF value */ + rate = clk_get_rate(&cpu_clk); + parent_rate = clk_get_rate(&pll1_sw_clk); + cur_arm_podf = parent_rate / rate; + + /* Calculate the ARM_PODF to be applied when the system + * enters WAIT state. + * The max ARM clk is decided by the ipg_clk and has to + * follow the ratio of ARM_CLK:IPG_CLK of 12:5. + */ + ipg_clk_rate = clk_get_rate(&ipg_clk); + max_arm_wait_clk = (12 * ipg_clk_rate) / 5; + wait_mode_arm_podf = parent_rate / max_arm_wait_clk; + +#if 1 + _clk_disable(&gpu2d_core_clk); +#endif + return 0; + +} diff --git a/arch/arm/mach-mx6/cpu.c b/arch/arm/mach-mx6/cpu.c new file mode 100644 index 00000000..86df0826 --- /dev/null +++ b/arch/arm/mach-mx6/cpu.c @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2011-2013 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 <linux/init.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/iram_alloc.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <mach/system.h> +#include <asm/io.h> +#include <asm/mach/map.h> + +#include "crm_regs.h" +#include "cpu_op-mx6.h" + +struct cpu_op *(*get_cpu_op)(int *op); +bool enable_wait_mode = true; +u32 enable_ldo_mode = LDO_MODE_DEFAULT; +u32 arm_max_freq = CPU_AT_1_2GHz; +bool mem_clk_on_in_wait; +int chip_rev; +unsigned long iram_tlb_base_addr; +unsigned long iram_tlb_phys_addr; + +void __iomem *gpc_base; +void __iomem *ccm_base; + +extern unsigned int num_cpu_idle_lock; + +static int cpu_silicon_rev = -1; +#define MX6_USB_ANALOG_DIGPROG 0x260 +#define MX6SL_USB_ANALOG_DIGPROG 0x280 + +unsigned long save_ttbr1(void) +{ + unsigned long lttbr1; + asm volatile( + ".align 4\n" + "mrc p15, 0, %0, c2, c0, 1\n" + : "=r" (lttbr1) + ); + return lttbr1; +} + +void restore_ttbr1(u32 ttbr1) +{ + asm volatile( + ".align 4\n" + "mcr p15, 0, %0, c2, c0, 1\n" + : : "r" (ttbr1) + ); +} + +static int mx6_get_srev(void) +{ + void __iomem *anatop = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + u32 rev; + if (cpu_is_mx6sl()) + rev = __raw_readl(anatop + MX6SL_USB_ANALOG_DIGPROG); + else + rev = __raw_readl(anatop + MX6_USB_ANALOG_DIGPROG); + + rev &= 0xff; + + if (rev == 0) + return IMX_CHIP_REVISION_1_0; + else if (rev == 1) + return IMX_CHIP_REVISION_1_1; + else if (rev == 2) + return IMX_CHIP_REVISION_1_2; + + return IMX_CHIP_REVISION_UNKNOWN; +} + +/* + * Returns: + * the silicon revision of the cpu + */ +int mx6q_revision(void) +{ + if (!cpu_is_mx6q()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + cpu_silicon_rev = mx6_get_srev(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx6q_revision); + +/* + * Returns: + * the silicon revision of the cpu + */ +int mx6dl_revision(void) +{ + if (!cpu_is_mx6dl()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + cpu_silicon_rev = mx6_get_srev(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx6dl_revision); + +/* + * Returns: + * the silicon revision of the cpu + */ +int mx6sl_revision(void) +{ + if (!cpu_is_mx6sl()) + return -EINVAL; + + if (cpu_silicon_rev == -1) + cpu_silicon_rev = mx6_get_srev(); + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx6sl_revision); + +static int __init post_cpu_init(void) +{ + unsigned int reg; + void __iomem *base; + u32 iram_size; + + if (cpu_is_mx6q()) + iram_size = MX6Q_IRAM_SIZE; + else + iram_size = MX6DL_MX6SL_IRAM_SIZE; + + iram_init(MX6Q_IRAM_BASE_ADDR, iram_size); + + base = ioremap(AIPS1_ON_BASE_ADDR, PAGE_SIZE); + __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); + iounmap(base); + + base = ioremap(AIPS2_ON_BASE_ADDR, PAGE_SIZE); + __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); + iounmap(base); + + /* Force IOMUXC irq to be pending for CCM LPM */ + base = IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR); + reg = __raw_readl(base + 0x4); + reg |= 0x1000; + __raw_writel(reg, base + 0x4); + + /* Allow SCU_CLK to be disabled when all cores are in WFI*/ + base = IO_ADDRESS(SCU_BASE_ADDR); + reg = __raw_readl(base); + reg |= 0x20; + __raw_writel(reg, base); + + /* Disable SRC warm reset to work aound system reboot issue */ + base = IO_ADDRESS(SRC_BASE_ADDR); + reg = __raw_readl(base); + reg &= ~0x1; + __raw_writel(reg, base); + + gpc_base = MX6_IO_ADDRESS(GPC_BASE_ADDR); + ccm_base = MX6_IO_ADDRESS(CCM_BASE_ADDR); + + /* enable AXI cache for VDOA/VPU/IPU + * set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 + * clear OCRAM_CTL bits to disable pipeline control + */ + reg = __raw_readl(IOMUXC_GPR3); + reg &= ~IOMUXC_GPR3_OCRAM_CTL_EN; + __raw_writel(reg, IOMUXC_GPR3); + reg = __raw_readl(IOMUXC_GPR4); + reg |= IOMUXC_GPR4_VDOA_CACHE_EN | IOMUXC_GPR4_VPU_CACHE_EN | + IOMUXC_GPR4_IPU_CACHE_EN; + __raw_writel(reg, IOMUXC_GPR4); + __raw_writel(IOMUXC_GPR6_IPU1_QOS, IOMUXC_GPR6); + __raw_writel(IOMUXC_GPR7_IPU2_QOS, IOMUXC_GPR7); + + num_cpu_idle_lock = 0x0; + if (cpu_is_mx6dl()) + num_cpu_idle_lock = 0xffff0000; + +#ifdef CONFIG_SMP + switch (setup_max_cpus) { + case 3: + num_cpu_idle_lock = 0xff000000; + break; + case 2: + num_cpu_idle_lock = 0xffff0000; + break; + case 1: + case 0: + num_cpu_idle_lock = 0xffffff00; + break; + } +#endif + /* + * The option to keep ARM memory clocks enabled during WAIT + * is only available on MX6SL, MX6DQ TO1.2 (or later) and + * MX6DL TO1.1 (or later) + * So if the user specifies "mem_clk_on" on any other chip, + * ensure that it is disabled. + */ + if (!cpu_is_mx6sl() && (mx6q_revision() < IMX_CHIP_REVISION_1_2) && + (mx6dl_revision() < IMX_CHIP_REVISION_1_1)) + mem_clk_on_in_wait = false; + + if (cpu_is_mx6q()) + chip_rev = mx6q_revision(); + else if (cpu_is_mx6dl()) + chip_rev = mx6dl_revision(); + else + chip_rev = mx6sl_revision(); + + /* mx6sl doesn't have pcie. save power, disable PCIe PHY */ + if (!cpu_is_mx6sl()) { + reg = __raw_readl(IOMUXC_GPR1); + reg = reg & (~IOMUXC_GPR1_PCIE_REF_CLK_EN); + reg |= IOMUXC_GPR1_TEST_POWERDOWN; + __raw_writel(reg, IOMUXC_GPR1); + } + if (cpu_is_mx6sl()) { + int i; + /* + * Allocate the bottom 16K of IRAM page tables that + * will be used when DDR is in self-refresh. + */ + iram_tlb_phys_addr = MX6_IRAM_TLB_BASE_ADDR; + iram_tlb_base_addr = (unsigned long)__arm_ioremap(iram_tlb_phys_addr, + MX6_IRAM_TLB_SIZE, MT_MEMORY_NONCACHED); + + /* Set all entries to 0. */ + memset((void *)iram_tlb_base_addr, 0, MX6_IRAM_TLB_SIZE); + + /* Make sure the IRAM virtual address has a mapping in the IRAM page table. */ + i = ((IRAM_BASE_ADDR_VIRT >> 20) << 2 ) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (IRAM_BASE_ADDR & 0xFFF0000) | TT_ATTRIB_NON_CACHEABLE_1M; + /* Make sure the AIPS1 virtual address has a mapping in the IRAM page table. */ + i = ((AIPS1_BASE_ADDR_VIRT >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (AIPS1_ARB_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; + /* Make sure the AIPS2 virtual address has a mapping in the IRAM page table. */ + i = ((AIPS2_BASE_ADDR_VIRT >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (AIPS2_ARB_BASE_ADDR & 0xFFF00000) | TT_ATTRIB_NON_CACHEABLE_1M; + /* Make sure the AIPS2 virtual address has a mapping in the IRAM page table. */ + i = ((L2_BASE_ADDR_VIRT >> 20) << 2) / 4; + *((unsigned long *)iram_tlb_base_addr + i) = + (L2_BASE_ADDR & 0xFFF0000) | TT_ATTRIB_NON_CACHEABLE_1M; + + } + return 0; +} +postcore_initcall(post_cpu_init); + +static int __init enable_wait(char *p) +{ + if (memcmp(p, "on", 2) == 0) { + enable_wait_mode = true; + p += 2; + } else if (memcmp(p, "off", 3) == 0) { + enable_wait_mode = false; + p += 3; + } + return 0; +} +early_param("enable_wait_mode", enable_wait); + +static int __init arm_core_max(char *p) +{ + if (memcmp(p, "1200", 4) == 0) { + arm_max_freq = CPU_AT_1_2GHz; + p += 4; + } else if (memcmp(p, "1000", 4) == 0) { + arm_max_freq = CPU_AT_1GHz; + p += 4; + } else if (memcmp(p, "800", 3) == 0) { + arm_max_freq = CPU_AT_800MHz; + p += 3; + } + return 0; +} + +early_param("arm_freq", arm_core_max); + +static int __init enable_ldo(char *p) +{ + if (memcmp(p, "on", 2) == 0) { + enable_ldo_mode = LDO_MODE_ENABLED; + p += 2; + } else if (memcmp(p, "off", 3) == 0) { + enable_ldo_mode = LDO_MODE_BYPASSED; + p += 3; + } + return 0; +} +early_param("ldo_active", enable_ldo); + +static int __init enable_mem_clk_in_wait(char *p) +{ + mem_clk_on_in_wait = true; + + return 0; +} + +early_param("mem_clk_on", enable_mem_clk_in_wait); + + + diff --git a/arch/arm/mach-mx6/cpu_op-mx6.c b/arch/arm/mach-mx6/cpu_op-mx6.c new file mode 100644 index 00000000..24dcc712 --- /dev/null +++ b/arch/arm/mach-mx6/cpu_op-mx6.c @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2010-2013 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 <asm/io.h> +#include <mach/hardware.h> +#include <mach/mxc_dvfs.h> +#include "cpu_op-mx6.h" + +#define OCOTP_SPEED_BIT_OFFSET (16) +extern struct cpu_op *(*get_cpu_op)(int *op); +extern struct dvfs_op *(*get_dvfs_core_op)(int *wp); +extern void (*set_num_cpu_op)(int num); +extern u32 arm_max_freq; +static int num_cpu_op; + +/* working point(wp): 0 - 1.2GHz; 1 - 792MHz, 2 - 498MHz 3 - 396MHz */ +static struct cpu_op mx6q_cpu_op_1_2G[] = { + { + .pll_rate = 1200000000, + .cpu_rate = 1200000000, + .cpu_podf = 0, + .pu_voltage = 1275000, + .soc_voltage = 1275000, + .cpu_voltage = 1275000,}, + { + .pll_rate = 996000000, + .cpu_rate = 996000000, + .cpu_podf = 0, + .pu_voltage = 1250000, + .soc_voltage = 1250000, + .cpu_voltage = 1250000,}, + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, +#ifdef CONFIG_MX6_VPU_352M + /*VPU 352Mhz need voltage 1.25V*/ + .pu_voltage = 1250000, + .soc_voltage = 1250000, +#else + .pu_voltage = 1175000, + .soc_voltage = 1175000, +#endif + .cpu_voltage = 1150000,}, +#ifdef CONFIG_MX6_VPU_352M + /*pll2_pfd_400M will be fix on 352M,to avoid modify other code + which assume ARM clock sourcing from pll2_pfd_400M, change cpu + freq from 396M to 352M.*/ + { + .pll_rate = 352000000, + .cpu_rate = 352000000, + .cpu_podf = 0, + .pu_voltage = 1250000, + .soc_voltage = 1250000, + .cpu_voltage = 950000,}, +#else + { + .pll_rate = 396000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 950000,}, +#endif +}; + +/* working point(wp): 0 - 1GHz; 1 - 792MHz, 2 - 498MHz 3 - 396MHz */ +static struct cpu_op mx6q_cpu_op_1G[] = { + { + .pll_rate = 996000000, + .cpu_rate = 996000000, + .cpu_podf = 0, + .pu_voltage = 1250000, + .soc_voltage = 1250000, + .cpu_voltage = 1250000,}, + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, +#ifdef CONFIG_MX6_VPU_352M + /*VPU 352Mhz need voltage 1.25V*/ + .pu_voltage = 1250000, + .soc_voltage = 1250000, +#else + .pu_voltage = 1175000, + .soc_voltage = 1175000, +#endif + .cpu_voltage = 1150000,}, +#ifdef CONFIG_MX6_VPU_352M + /*pll2_pfd_400M will be fix on 352M,to avoid modify other code + which assume ARM clock sourcing from pll2_pfd_400M, change cpu + freq from 396M to 352M.*/ + { + .pll_rate = 352000000, + .cpu_rate = 352000000, + .cpu_podf = 0, + .pu_voltage = 1250000, + .soc_voltage = 1250000, + .cpu_voltage = 950000,}, +#else + { + .pll_rate = 396000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 950000,}, +#endif +}; + +static struct cpu_op mx6q_cpu_op[] = { + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, +#ifdef CONFIG_MX6_VPU_352M + /*VPU 352Mhz need voltage 1.25V*/ + .pu_voltage = 1250000, + .soc_voltage = 1250000, +#else + .pu_voltage = 1175000, + .soc_voltage = 1175000, +#endif + .cpu_voltage = 1150000,}, +#ifdef CONFIG_MX6_VPU_352M + /*pll2_pfd_400M will be fix on 352M,to avoid modify other code + which assume ARM clock sourcing from pll2_pfd_400M, change cpu + freq from 396M to 352M.*/ + { + .pll_rate = 352000000, + .cpu_rate = 352000000, + .cpu_podf = 0, + .pu_voltage = 1250000, + .soc_voltage = 1250000, + .cpu_voltage = 950000,}, +#else + { + .pll_rate = 396000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 950000,}, +#endif +}; + +/* working point(wp): 0 - 1.2GHz; 1 - 800MHz, 2 - 400MHz, 3 - 200MHz */ +static struct cpu_op mx6dl_cpu_op_1_2G[] = { + { + .pll_rate = 1200000000, + .cpu_rate = 1200000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1275000,}, + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1175000,}, + { + .pll_rate = 396000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1075000,}, +}; +/* working point(wp): 0 - 1GHz; 1 - 800MHz, 2 - 400MHz, 3 - 200MHz */ +static struct cpu_op mx6dl_cpu_op_1G[] = { + { + .pll_rate = 996000000, + .cpu_rate = 996000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1250000,}, + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1175000,}, + { + .pll_rate = 396000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1075000,}, +}; +static struct cpu_op mx6dl_cpu_op[] = { + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1175000,}, + { + .pll_rate = 396000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1175000, + .soc_voltage = 1175000, + .cpu_voltage = 1075000,}, +}; + +static struct cpu_op mx6sl_cpu_op_1G[] = { + { + .pll_rate = 996000000, + .cpu_rate = 996000000, + .cpu_podf = 0, + .pu_voltage = 1200000, + .soc_voltage = 1200000, + .cpu_voltage = 1250000,}, +/* { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, + .pu_voltage = 1150000, + .soc_voltage = 1150000, + .cpu_voltage = 1150000,},*/ + { + .pll_rate = 396000000, + .pll_lpm_rate = 792000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1150000, + .soc_voltage = 1150000, + .cpu_voltage = 950000,}, +}; + +static struct cpu_op mx6sl_cpu_op[] = { + { + .pll_rate = 792000000, + .cpu_rate = 792000000, + .cpu_podf = 0, + .pu_voltage = 1150000, + .soc_voltage = 1150000, + .cpu_voltage = 1150000,}, + { + .pll_rate = 396000000, + .pll_lpm_rate = 792000000, + .cpu_rate = 396000000, + .cpu_podf = 0, + .pu_voltage = 1150000, + .soc_voltage = 1150000, + .cpu_voltage = 950000,}, +}; + +static struct dvfs_op dvfs_core_setpoint_1_2G[] = { + {33, 14, 33, 10, 128, 0x10}, /* 1.2GHz*/ + {30, 12, 33, 100, 200, 0x10}, /* 800MHz */ + {28, 12, 33, 100, 200, 0x10}, /* 672MHz */ + {26, 8, 33, 100, 200, 0x10}, /* 400MHz */ + {20, 0, 33, 20, 10, 0x10} }; /* 200MHz*/ + +static struct dvfs_op dvfs_core_setpoint_1G[] = { + {33, 14, 33, 10, 128, 0x10}, /* 1GHz*/ + {30, 12, 33, 100, 200, 0x10}, /* 800MHz */ + {28, 12, 33, 100, 200, 0x10}, /* 672MHz */ + {26, 8, 33, 100, 200, 0x10}, /* 400MHz */ + {20, 0, 33, 20, 10, 0x10} }; /* 200MHz*/ + +static struct dvfs_op dvfs_core_setpoint[] = { + {33, 14, 33, 10, 128, 0x08}, /* 800MHz */ + {26, 8, 33, 100, 200, 0x08}, /* 400MHz */ + {20, 0, 33, 100, 10, 0x08} }; /* 200MHz*/ + +static struct dvfs_op *mx6_get_dvfs_core_table(int *wp) +{ + if (arm_max_freq == CPU_AT_1_2GHz) { + *wp = ARRAY_SIZE(dvfs_core_setpoint_1_2G); + return dvfs_core_setpoint_1_2G; + } else if (arm_max_freq == CPU_AT_1GHz) { + *wp = ARRAY_SIZE(dvfs_core_setpoint_1G); + return dvfs_core_setpoint_1G; + } else { + *wp = ARRAY_SIZE(dvfs_core_setpoint); + return dvfs_core_setpoint; + } +} + +struct cpu_op *mx6_get_cpu_op(int *op) +{ + if (cpu_is_mx6dl()) { + if (arm_max_freq == CPU_AT_1_2GHz) { + *op = num_cpu_op = ARRAY_SIZE(mx6dl_cpu_op_1_2G); + return mx6dl_cpu_op_1_2G; + } else if (arm_max_freq == CPU_AT_1GHz) { + *op = num_cpu_op = ARRAY_SIZE(mx6dl_cpu_op_1G); + return mx6dl_cpu_op_1G; + } else { + *op = num_cpu_op = ARRAY_SIZE(mx6dl_cpu_op); + return mx6dl_cpu_op; + } + } else if (cpu_is_mx6q()) { + if (arm_max_freq == CPU_AT_1_2GHz) { + *op = num_cpu_op = ARRAY_SIZE(mx6q_cpu_op_1_2G); + return mx6q_cpu_op_1_2G; + } else if (arm_max_freq == CPU_AT_1GHz) { + *op = num_cpu_op = ARRAY_SIZE(mx6q_cpu_op_1G); + return mx6q_cpu_op_1G; + } else { + *op = num_cpu_op = ARRAY_SIZE(mx6q_cpu_op); + return mx6q_cpu_op; + } + } else { + if (arm_max_freq == CPU_AT_1GHz) { + *op = num_cpu_op = ARRAY_SIZE(mx6sl_cpu_op_1G); + return mx6sl_cpu_op_1G; + } else { + *op = num_cpu_op = ARRAY_SIZE(mx6sl_cpu_op); + return mx6sl_cpu_op; + } + } +} + +void mx6_set_num_cpu_op(int num) +{ + num_cpu_op = num; + return; +} + +void mx6_cpu_op_init(void) +{ + unsigned int reg; + void __iomem *base; + if (!cpu_is_mx6sl()) { + /*read fuse bit to know the max cpu freq : offset 0x440 + * bit[17:16]:SPEED_GRADING[1:0],for mx6dq/dl*/ + base = IO_ADDRESS(OCOTP_BASE_ADDR); + reg = __raw_readl(base + 0x440); + reg &= (0x3 << OCOTP_SPEED_BIT_OFFSET); + reg >>= OCOTP_SPEED_BIT_OFFSET; + /*choose the little value to run lower max cpufreq*/ + arm_max_freq = (reg > arm_max_freq) ? arm_max_freq : reg; + } else { + /* + * There is no SPEED_GRADING fuse bit on mx6sl,then do: + * If arm_max_freq set by default on CPU_AT_1_2GHz which mean + * there is no 'arm_freq' setting in cmdline from bootloader, + * force arm_max_freq to 1G. Else use 'arm_freq' setting. + */ + if (arm_max_freq == CPU_AT_1_2GHz) + arm_max_freq = CPU_AT_1GHz;/*mx6sl max freq is 1Ghz*/ + } + printk(KERN_INFO "arm_max_freq=%s\n", (arm_max_freq == CPU_AT_1_2GHz) ? + "1.2GHz" : ((arm_max_freq == CPU_AT_1GHz) ? "1GHz" : "800MHz")); + get_cpu_op = mx6_get_cpu_op; + set_num_cpu_op = mx6_set_num_cpu_op; + + get_dvfs_core_op = mx6_get_dvfs_core_table; +} + diff --git a/arch/arm/mach-mx6/cpu_op-mx6.h b/arch/arm/mach-mx6/cpu_op-mx6.h new file mode 100644 index 00000000..310cbb37 --- /dev/null +++ b/arch/arm/mach-mx6/cpu_op-mx6.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2010-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 + */ +/*The below value aligned with SPEED_GRADING bits in 0x440 fuse offset */ +#define CPU_AT_800MHz 0 +#define CPU_AT_1GHz 2 +#define CPU_AT_1_2GHz 3 + +void mx6_cpu_op_init(void); diff --git a/arch/arm/mach-mx6/cpu_regulator-mx6.c b/arch/arm/mach-mx6/cpu_regulator-mx6.c new file mode 100644 index 00000000..1a67e9d5 --- /dev/null +++ b/arch/arm/mach-mx6/cpu_regulator-mx6.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2012-2013 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 <linux/err.h> +#include <linux/jiffies.h> +#include <linux/regulator/consumer.h> +#include <linux/clk.h> +#if defined(CONFIG_CPU_FREQ) +#include <linux/cpufreq.h> +#endif +#include <linux/io.h> +#include <asm/cpu.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include <mach/system.h> +#include "regs-anadig.h" +#include "crm_regs.h" +struct regulator *cpu_regulator; +struct regulator *soc_regulator; +struct regulator *pu_regulator; +char *gp_reg_id; +char *soc_reg_id; +char *pu_reg_id; +static struct clk *cpu_clk; +static int cpu_op_nr; +static struct cpu_op *cpu_op_tbl; +extern struct cpu_op *(*get_cpu_op)(int *op); + +extern unsigned long loops_per_jiffy; +extern u32 enable_ldo_mode; +int external_pureg; + +static inline unsigned long mx6_cpu_jiffies(unsigned long old, u_int div, + u_int mult) +{ +#if BITS_PER_LONG == 32 + + u64 result = ((u64) old) * ((u64) mult); + do_div(result, div); + return (unsigned long) result; + +#elif BITS_PER_LONG == 64 + + unsigned long result = old * ((u64) mult); + result /= div; + return result; + +#endif +} + +void mx6_cpu_regulator_init(void) +{ + int cpu; + u32 curr_cpu = 0; + unsigned int reg; +#ifndef CONFIG_SMP + unsigned long old_loops_per_jiffy; +#endif + void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); + external_pureg = 0; + /*If internal ldo actived, use internal cpu_* regulator to replace the + *regulator ids from board file. If internal ldo bypassed, use the + *regulator ids which defined in board file and source from extern pmic + *power rails. + *If you want to use ldo bypass,you should do: + *1.set enable_ldo_mode=LDO_MODE_BYPASSED in your board file by default + * or set in commandline from u-boot + *2.set your extern pmic regulator name in your board file. + */ + if (enable_ldo_mode != LDO_MODE_BYPASSED) { + gp_reg_id = "cpu_vddgp"; + soc_reg_id = "cpu_vddsoc"; + pu_reg_id = "cpu_vddgpu"; + } + printk(KERN_INFO "cpu regulator mode:%s\n", (enable_ldo_mode == + LDO_MODE_BYPASSED) ? "ldo_bypass" : "ldo_enable"); + cpu_regulator = regulator_get(NULL, gp_reg_id); +#if 0 + if (IS_ERR(cpu_regulator)) + printk(KERN_ERR "%s: failed to get cpu regulator\n", __func__); + else +#endif + { + cpu_clk = clk_get(NULL, "cpu_clk"); + if (IS_ERR(cpu_clk)) { + printk(KERN_ERR "%s: failed to get cpu clock\n", + __func__); + } else { + curr_cpu = clk_get_rate(cpu_clk); + cpu_op_tbl = get_cpu_op(&cpu_op_nr); + + soc_regulator = regulator_get(NULL, soc_reg_id); + if (IS_ERR(soc_regulator)) + printk(KERN_ERR "%s: failed to get soc regulator\n", + __func__); + else + /* set soc to highest setpoint voltage. */ + regulator_set_voltage(soc_regulator, + cpu_op_tbl[0].soc_voltage, + cpu_op_tbl[0].soc_voltage); + + pu_regulator = regulator_get(NULL, pu_reg_id); + if (IS_ERR(pu_regulator)) + printk(KERN_ERR "%s: failed to get pu regulator\n", + __func__); + else + /* set pu to higheset setpoint voltage. */ + regulator_set_voltage(pu_regulator, + cpu_op_tbl[0].pu_voltage, + cpu_op_tbl[0].pu_voltage); + if (!IS_ERR(cpu_regulator)) { + /* set the core to higheset setpoint voltage. */ + regulator_set_voltage(cpu_regulator, + cpu_op_tbl[0].cpu_voltage, + cpu_op_tbl[0].cpu_voltage); + } + if (enable_ldo_mode == LDO_MODE_BYPASSED) { + /* digital bypass VDDPU/VDDSOC/VDDARM */ + reg = __raw_readl(ANADIG_REG_CORE); + reg &= ~BM_ANADIG_REG_CORE_REG0_TRG; + reg |= BF_ANADIG_REG_CORE_REG0_TRG(0x1f); + reg &= ~BM_ANADIG_REG_CORE_REG1_TRG; + reg |= BF_ANADIG_REG_CORE_REG1_TRG(0x1f); + reg &= ~BM_ANADIG_REG_CORE_REG2_TRG; + reg |= BF_ANADIG_REG_CORE_REG2_TRG(0x1f); + __raw_writel(reg, ANADIG_REG_CORE); + /* mask the ANATOP brown out irq in the GPC. */ + reg = __raw_readl(gpc_base + 0x14); + reg |= 0x80000000; + __raw_writel(reg, gpc_base + 0x14); + } + + clk_set_rate(cpu_clk, cpu_op_tbl[0].cpu_rate); + + /* fix loops-per-jiffy */ +#ifdef CONFIG_SMP + for_each_online_cpu(cpu) + per_cpu(cpu_data, cpu).loops_per_jiffy = + mx6_cpu_jiffies( + per_cpu(cpu_data, cpu).loops_per_jiffy, + curr_cpu / 1000, + clk_get_rate(cpu_clk) / 1000); +#else + old_loops_per_jiffy = loops_per_jiffy; + + loops_per_jiffy = + mx6_cpu_jiffies(old_loops_per_jiffy, + curr_cpu/1000, + clk_get_rate(cpu_clk) / 1000); +#endif +#if defined(CONFIG_CPU_FREQ) + /* Fix CPU frequency for CPUFREQ. */ + for (cpu = 0; cpu < num_online_cpus(); cpu++) + cpufreq_get(cpu); +#endif + } + } + /* + * if use ldo bypass and VDDPU_IN is single supplied + * by external pmic, it means VDDPU_IN can be turned off + * if GPU/VPU driver not running.In this case we should set + * external_pureg which can be used in pu_enable/pu_disable of + * arch/arm/mach-mx6/mx6_anatop_regulator.c to + * enable or disable external VDDPU regulator from pmic. But for FSL + * reference boards, VDDSOC_IN connect with VDDPU_IN, so we didn't set + * pu_reg_id to the external pmic regulator supply name in the board + * file. In this case external_pureg should be 0 and can't turn off + * extern pmic regulator, but can turn off VDDPU by internal anatop + * power gate. + * + * if enable internal ldo , external_pureg will be 0, and + * VDDPU can be turned off by internal anatop anatop power gate. + * + */ + if (!IS_ERR(pu_regulator) && strcmp(pu_reg_id, "cpu_vddgpu")) + external_pureg = 1; +} + diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h new file mode 100644 index 00000000..0ae8e41e --- /dev/null +++ b/arch/arm/mach-mx6/crm_regs.h @@ -0,0 +1,569 @@ +/* + * Copyright 2008-2013 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_MX6_CRM_REGS_H__ +#define __ARCH_ARM_MACH_MX6_CRM_REGS_H__ + +/* IOMUXC */ +#define MXC_IOMUXC_BASE MX6_IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR) +#define IOMUXC_GPR0 (MXC_IOMUXC_BASE + 0x00) +#define IOMUXC_GPR1 (MXC_IOMUXC_BASE + 0x04) +#define IOMUXC_GPR2 (MXC_IOMUXC_BASE + 0x08) +#define IOMUXC_GPR3 (MXC_IOMUXC_BASE + 0x0C) +#define IOMUXC_GPR4 (MXC_IOMUXC_BASE + 0x10) +#define IOMUXC_GPR5 (MXC_IOMUXC_BASE + 0x14) +#define IOMUXC_GPR6 (MXC_IOMUXC_BASE + 0x18) +#define IOMUXC_GPR7 (MXC_IOMUXC_BASE + 0x1C) +#define IOMUXC_GPR8 (MXC_IOMUXC_BASE + 0x20) +#define IOMUXC_GPR9 (MXC_IOMUXC_BASE + 0x24) +#define IOMUXC_GPR10 (MXC_IOMUXC_BASE + 0x28) +#define IOMUXC_GPR11 (MXC_IOMUXC_BASE + 0x2C) +#define IOMUXC_GPR12 (MXC_IOMUXC_BASE + 0x30) +#define IOMUXC_GPR13 (MXC_IOMUXC_BASE + 0x34) + +/* GPR1: IOMUXC_GPR1_PCIE_REF_CLK_EN(IOMUXC_GPR1[16]) */ +#define IOMUXC_GPR1_PCIE_REF_CLK_EN (1 << 16) +/* GPR1: IOMUXC_GPR1_TEST_POWERDOWN(IOMUXC_GPR1[18]) */ +#define IOMUXC_GPR1_TEST_POWERDOWN (1 << 18) + +/* GPR8: IOMUXC_GPR8_TX_DEEMPH_GEN1(IOMUXC_GPR8[5:0]) */ +#define IOMUXC_GPR8_TX_DEEMPH_GEN1 (0x3F << 0) +/* GPR8: IOMUXC_GPR8_TX_DEEMPH_GEN2_3P5DB(IOMUXC_GPR8[11:6]) */ +#define IOMUXC_GPR8_TX_DEEMPH_GEN2_3P5DB (0x3F << 6) +/* GPR8: IOMUXC_GPR8_TX_DEEMPH_GEN2_6DB(IOMUXC_GPR8[17:12]) */ +#define IOMUXC_GPR8_TX_DEEMPH_GEN2_6DB (0x3F << 12) +/* GPR8: IOMUXC_GPR8_TX_SWING_FULL(IOMUXC_GPR8[24:18]) */ +#define IOMUXC_GPR8_TX_SWING_FULL (0x7F << 18) +/* GPR8: IOMUXC_GPR8_TX_SWING_LOW(IOMUXC_GPR8[31:25]) */ +#define IOMUXC_GPR8_TX_SWING_LOW (0x7F << 25) + +/* GPR12: IOMUXC_GPR12_LOS_LEVEL(IOMUXC_GPR12[8:4]) */ +#define IOMUXC_GPR12_LOS_LEVEL (0x1F << 4) +/* GPR12: IOMUXC_GPR12_APP_LTSSM_ENABLE(IOMUXC_GPR12[10]) */ +#define IOMUXC_GPR12_APP_LTSSM_ENABLE (1 << 10) +/* GPR12: IOMUXC_GPR12_DEVICE_TYPE(IOMUXC_GPR12[15:12]) */ +#define IOMUXC_GPR12_DEVICE_TYPE (0xF << 12) + +#define IOMUXC_GPR3_OCRAM_CTL_EN (0xf << 21) +#define IOMUXC_GPR4_VDOA_CACHE_EN (0xf << 28) +#define IOMUXC_GPR4_VPU_CACHE_EN (0xcc) +#define IOMUXC_GPR4_IPU_CACHE_EN (0x3) +#define IOMUXC_GPR6_IPU1_QOS (0x007f007f) +#define IOMUXC_GPR7_IPU2_QOS (0x007f007f) + +/* MMDC */ +#define MXC_MMDC_P0_BASE MX6_IO_ADDRESS(MMDC_P0_BASE_ADDR) +#define MMDC_MDMISC_OFFSET (MXC_MMDC_P0_BASE + 0x18) +#define MMDC_MDMISC_DDR_TYPE_MASK (0x3 << 3) +#define MMDC_MDMISC_DDR_TYPE_OFFSET (3) + +/* PLLs */ +#define MXC_PLL_BASE MX6_IO_ADDRESS(ANATOP_BASE_ADDR) +#define PLL1_SYS_BASE_ADDR (MXC_PLL_BASE + 0x0) +#define PLL2_528_BASE_ADDR (MXC_PLL_BASE + 0x30) +#define PLL3_480_USB1_BASE_ADDR (MXC_PLL_BASE + 0x10) +#define PLL4_AUDIO_BASE_ADDR (MXC_PLL_BASE + 0x70) +#define PLL5_VIDEO_BASE_ADDR (MXC_PLL_BASE + 0xA0) +#define PLL6_MLB_BASE_ADDR (MXC_PLL_BASE + 0xD0) +#define PLL7_480_USB2_BASE_ADDR (MXC_PLL_BASE + 0x20) +#define PLL8_ENET_BASE_ADDR (MXC_PLL_BASE + 0xE0) +#define PFD_480_BASE_ADDR (MXC_PLL_BASE + 0xF0) +#define PFD_528_BASE_ADDR (MXC_PLL_BASE + 0x100) +#define ANADIG_REG_CORE (MXC_PLL_BASE + 0x140) +#define ANADIG_MISC1_REG (MXC_PLL_BASE + 0x160) +#define ANADIG_MISC2_REG (MXC_PLL_BASE + 0x170) +#define ANATOP_LVDS_CLK1_SRC_SATA 0xB +#define ANATOP_LVDS_CLK1_OBEN_MASK 0x400 +#define ANATOP_LVDS_CLK1_IBEN_MASK 0x1000 +#define ANATOP_LVDS_CLK2_OBEN_MASK 0x800 +#define ANATOP_LVDS_CLK2_IBEN_MASK 0x2000 +#define ANA_MISC2_BASE_ADDR (MXC_PLL_BASE + 0x170) + +#define PLL_SETREG_OFFSET 0x4 +#define PLL_CLRREG_OFFSET 0x8 +#define PLL_TOGGLE_OFFSET 0x0C +#define PLL_NUM_DIV_OFFSET 0x10 +#define PLL_DENOM_DIV_OFFSET 0x20 +#define PLL_528_SS_OFFSET 0x10 +#define PLL_528_NUM_DIV_OFFSET 0x20 +#define PLL_528_DENOM_DIV_OFFSET 0x30 + +/* Common PLL register bit defines. */ +#define ANADIG_PLL_LOCK (1 << 31) +#define ANADIG_PLL_BYPASS (1 << 16) +#define ANADIG_PLL_BYPASS_CLK_SRC_MASK (0x3 << 14) +#define ANADIG_PLL_BYPASS_CLK_SRC_OFFSET (14) +#define ANADIG_PLL_ENABLE (1 << 13) +#define ANADIG_PLL_POWER_DOWN (1 << 12) +#define ANADIG_PLL_HOLD_RING_OFF (1 << 11) + +/* PLL1_SYS defines */ +#define ANADIG_PLL_SYS_DIV_SELECT_MASK (0x7F) +#define ANADIG_PLL_SYS_DIV_SELECT_OFFSET (0) +#define ANADIG_PLL_SYS_BYPASS_MASK (0x10000) +#define ANADIG_PLL_SYS_BYPASS_OFFSET (16) + +/* PLL2_528 defines */ +#define ANADIG_PLL_528_DIV_SELECT (1) + +/* PLL3_480 defines. */ +#define ANADIG_PLL_480_EN_USB_CLKS (1 << 6) +#define ANADIG_PLL_480_DIV_SELECT_MASK (0x3) +#define ANADIG_PLL_480_DIV_SELECT_OFFSET (0) + +/* PLL4_AUDIO PLL5_VIDEO defines. */ +#define ANADIG_PLL_AV_DIV_SELECT_MASK (0x7F) +#define ANADIG_PLL_AV_DIV_SELECT_OFFSET (0) +#define ANADIG_PLL_AV_TEST_DIV_SEL_MASK (0x180000) +#define ANADIG_PLL_AV_TEST_DIV_SEL_OFFSET (19) + +/* PLL6_MLB defines. */ +#define ANADIG_PLL_MLB_LOCK (1 << 31) +#define ANADIG_PLL_MLB_FLT_RES_CFG_MASK (0x7 << 26) +#define ANADIG_PLL_MLB_FLT_RES_CFG_OFFSET (26) +#define ANADIG_PLL_MLB_RX_CLK_DELAY_CFG_MASK (0x7 << 23) +#define ANADIG_PLL_MLB_RX_CLK_DELAY_CFG_OFFSET (23) +#define ANADIG_PLL_MLB_VDDD_DELAY_CFG_MASK (0x7 << 20) +#define ANADIG_PLL_MLB_VDDD_DELAY_CFG_OFFSET (20) +#define ANADIG_PLL_MLB_VDDA_DELAY_CFG_MASK (0x7 << 17) +#define ANADIG_PLL_MLB_VDDA_DELAY_CFG_OFFSET (17) +#define ANADIG_PLL_MLB_BYPASS (1 << 16) + +/* PLL8_ENET defines. */ +#define ANADIG_PLL_ENET_LOCK (1 << 31) +#define ANADIG_PLL_ENET_EN_SATA (1 << 20) +#define ANADIG_PLL_ENET_EN_PCIE (1 << 19) +#define ANADIG_PLL_ENET_BYPASS (1 << 16) +#define ANADIG_PLL_ENET_EN (1 << 13) +#define ANADIG_PLL_ENET_POWER_DOWN (1 << 12) +#define ANADIG_PLL_ENET_DIV_SELECT_MASK (0x3) +#define ANADIG_PLL_ENET_DIV_SELECT_OFFSET (0) +#define ANATOP_BYPASS_SRC_LVDS1 0x00004000 + +/* PFD register defines. */ +#define ANADIG_PFD_FRAC_MASK 0x3F +#define ANADIG_PFD3_CLKGATE (1 << 31) +#define ANADIG_PFD3_STABLE (1 << 30) +#define ANADIG_PFD3_FRAC_OFFSET 24 +#define ANADIG_PFD2_CLKGATE (1 << 23) +#define ANADIG_PFD2_STABLE (1 << 22) +#define ANADIG_PFD2_FRAC_OFFSET 16 +#define ANADIG_PFD1_CLKGATE (1 << 15) +#define ANADIG_PFD1_STABLE (1 << 14) +#define ANADIG_PFD1_FRAC_OFFSET 8 +#define ANADIG_PFD0_CLKGATE (1 << 7) +#define ANADIG_PFD0_STABLE (1 << 6) +#define ANADIG_PFD0_FRAC_OFFSET 0 + +/* ANATOP Regulator/LDO defines */ +#define ANADIG_REG_RAMP_RATE_MASK 0x03 +#define ANADIG_REG_RAMP_RATE_OFFSET (0x3 << 27) +#define ANADIG_REG_ADJUST_MASK 0xF +#define ANADIG_REG_TARGET_MASK 0x1F +#define ANADIG_REG2_SOC_ADJUST_OFFSET 23 +#define ANADIG_REG2_SOC_TARGET_OFFSET 18 +#define ANADIG_REG1_PU_ADJUST_OFFSET 14 +#define ANADIG_REG1_PU_TARGET_OFFSET 9 +#define ANADIG_REG0_CORE_ADJUST_OFFSET 5 +#define ANADIG_REG0_CORE_TARGET_OFFSET 0 + +/* ANA MISC2 register defines */ +#define ANADIG_ANA_MISC2_REG1_BO_EN (1 << 13) +#define ANADIG_ANA_MISC2_CONTROL3_MASK 0xC0000000 +#define ANADIG_ANA_MISC2_CONTROL3_OFFSET 30 +#define ANADIG_ANA_MISC2_REG0_STEP_TIME_MASK 0x03000000 +#define ANADIG_ANA_MISC2_REG1_STEP_TIME_MASK 0x0C000000 +#define ANADIG_ANA_MISC2_REG2_STEP_TIME_MASK 0x30000000 + +#define MXC_CCM_BASE MX6_IO_ADDRESS(CCM_BASE_ADDR) +/* CCM Register Offsets. */ +#define MXC_CCM_CDCR_OFFSET 0x4C +#define MXC_CCM_CACRR_OFFSET 0x10 +#define MXC_CCM_CDHIPR_OFFSET 0x48 + +/* 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_CHSCCDR (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 the bits in register CCR */ +#define MXC_CCM_CCR_RBC_EN (1 << 27) +#define MXC_CCM_CCR_REG_BYPASS_CNT_MASK (0x3F << 21) +#define MXC_CCM_CCR_REG_BYPASS_CNT_OFFSET (21) +#define MXC_CCM_CCR_WB_COUNT_MASK (0x7 << 16) +#define MXC_CCM_CCR_WB_COUNT_OFFSET (16) +#define MXC_CCM_CCR_COSC_EN (1 << 12) +#define MXC_CCM_CCR_OSCNT_MASK (0xFF) +#define MXC_CCM_CCR_OSCNT_OFFSET (0) + +/* Define the bits in register CCDR */ +#define MXC_CCM_CCDR_MMDC_CH1_HS_MASK (1 << 16) +#define MXC_CCM_CCDR_MMDC_CH0_HS_MASK (1 << 17) + +/* Define the bits in register CSR */ +#define MXC_CCM_CSR_COSC_READY (1 << 5) +#define MXC_CCM_CSR_REF_EN_B (1 << 0) + +/* Define the bits in register CCSR */ +#define MXC_CCM_CCSR_PDF_540M_AUTO_DIS (1 << 15) +#define MXC_CCM_CCSR_PDF_720M_AUTO_DIS (1 << 14) +#define MXC_CCM_CCSR_PDF_454M_AUTO_DIS (1 << 13) +#define MXC_CCM_CCSR_PDF_508M_AUTO_DIS (1 << 12) +#define MXC_CCM_CCSR_PDF_594M_AUTO_DIS (1 << 11) +#define MXC_CCM_CCSR_PDF_352M_AUTO_DIS (1 << 10) +#define MXC_CCM_CCSR_PDF_400M_AUTO_DIS (1 << 9) +#define MXC_CCM_CCSR_STEP_SEL (1 << 8) +#define MXC_CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2) +#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 MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK (0x7 << 27) +#define MXC_CCM_CBCDR_PERIPH_CLK2_PODF_OFFSET (27) +#define MXC_CCM_CBCDR_PERIPH2_CLK_SEL (1 << 26) +#define MXC_CCM_CBCDR_PERIPH_CLK_SEL (1 << 25) +#define MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK (0x7 << 19) +#define MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET (19) +#define MXC_CCM_CBCDR_AXI_PODF_MASK (0x7 << 16) +#define MXC_CCM_CBCDR_AXI_PODF_OFFSET (16) +#define MXC_CCM_CBCDR_AHB_PODF_MASK (0x7 << 10) +#define MXC_CCM_CBCDR_AHB_PODF_OFFSET (10) +#define MXC_CCM_CBCDR_IPG_PODF_MASK (0x3 << 8) +#define MXC_CCM_CBCDR_IPG_PODF_OFFSET (8) +#define MXC_CCM_CBCDR_AXI_ALT_SEL_MASK (1 << 7) +#define MXC_CCM_CBCDR_AXI_ALT_SEL_OFFSET (7) +#define MXC_CCM_CBCDR_AXI_SEL (1 << 6) +#define MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK (0x7 << 3) +#define MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET (3) +#define MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_MASK (0x7 << 0) +#define MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_OFFSET (0) + +/* Define the bits in register CBCMR */ +#define MXC_CCM_CBCMR_GPU3D_SHADER_PODF_MASK (0x7 << 29) +#define MXC_CCM_CBCMR_GPU3D_SHADER_PODF_OFFSET (29) +#define MXC_CCM_CBCMR_GPU3D_CORE_PODF_MASK (0x7 << 26) +#define MXC_CCM_CBCMR_GPU3D_CORE_PODF_OFFSET (26) +#define MXC_CCM_CBCMR_GPU2D_CORE_PODF_MASK (0x7 << 23) +#define MXC_CCM_CBCMR_GPU2D_CORE_PODF_OFFSET (23) +#define MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK (0x3 << 21) +#define MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET (21) +#define MXC_CCM_CBCMR_PERIPH2_CLK2_SEL (1 << 20) +#define MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK (0x3 << 18) +#define MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET (18) +#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CBCMR_GPU2D_CLK_SEL_OFFSET (16) +#define MXC_CCM_CBCMR_MLB_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CBCMR_MLB_CLK_SEL_OFFSET (16) +#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CBCMR_VPU_AXI_CLK_SEL_OFFSET (14) +#define MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK (0x3 << 12) +#define MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET (12) +#define MXC_CCM_CBCMR_VDOAXI_CLK_SEL (1 << 11) +#define MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL (1 << 10) +#define MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_MASK (0x3 << 8) +#define MXC_CCM_CBCMR_GPU3D_SHADER_CLK_SEL_OFFSET (8) +#define MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_MASK (0x3 << 4) +#define MXC_CCM_CBCMR_GPU3D_CORE_CLK_SEL_OFFSET (4) +#define MXC_CCM_CBCMR_GPU3D_AXI_CLK_SEL (1 << 1) +#define MXC_CCM_CBCMR_GPU2D_AXI_CLK_SEL (1 << 0) + +/* Define the bits in register CSCMR1 */ +#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK (0x3 << 29) +#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET (29) +#define MXC_CCM_CSCMR1_ACLK_EMI_MASK (0x3 << 27) +#define MXC_CCM_CSCMR1_ACLK_EMI_OFFSET (27) +#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK (0x7 << 23) +#define MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET (23) +#define MXC_CCM_CSCMR1_ACLK_EMI_PODF_MASK (0x7 << 20) +#define MXC_CCM_CSCMR1_ACLK_EMI_PODF_OFFSET (20) +#define MXC_CCM_CSCMR1_USDHC4_CLK_SEL (1 << 19) +#define MXC_CCM_CSCMR1_USDHC3_CLK_SEL (1 << 18) +#define MXC_CCM_CSCMR1_USDHC2_CLK_SEL (1 << 17) +#define MXC_CCM_CSCMR1_USDHC1_CLK_SEL (1 << 16) +#define MXC_CCM_CSCMR1_SSI3_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CSCMR1_SSI3_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_MASK (0x3 << 12) +#define MXC_CCM_CSCMR1_SSI2_CLK_SEL_OFFSET (12) +#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_MASK (0x3 << 10) +#define MXC_CCM_CSCMR1_SSI1_CLK_SEL_OFFSET (10) +#define MXC_CCM_CSCMR1_PERCLK_CLK_SEL_MASK (0x1 << 6) +#define MXC_CCM_CSCMR1_PERCLK_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCMR1_PERCLK_PODF_MASK (0x3F) +#define MXC_CCM_CSCMR1_PERCLK_PODF_OFFSET (0) + +/* Define the bits in register CSCMR2 */ +#define MXC_CCM_CSCMR2_ESAI_CLK_SEL_MASK (0x3 << 19) +#define MXC_CCM_CSCMR2_ESAI_CLK_SEL_OFFSET (19) +#define MXC_CCM_CSCMR2_LDB_DI1_IPU_DIV (1 << 11) +#define MXC_CCM_CSCMR2_LDB_DI0_IPU_DIV (1 << 10) +#define MXC_CCM_CSCMR2_CAN_CLK_PODF_MASK (0x3F << 2) +#define MXC_CCM_CSCMR2_CAN_CLK_PODF_OFFSET (2) + +/* Define the bits in register CSCDR1 */ +#define MXC_CCM_CSCDR1_VPU_AXI_PODF_MASK (0x7 << 25) +#define MXC_CCM_CSCDR1_VPU_AXI_PODF_OFFSET (25) +#define MXC_CCM_CSCDR1_USDHC4_PODF_MASK (0x7 << 22) +#define MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET (22) +#define MXC_CCM_CSCDR1_USDHC3_PODF_MASK (0x7 << 19) +#define MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET (19) +#define MXC_CCM_CSCDR1_USDHC2_PODF_MASK (0x7 << 16) +#define MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET (16) +#define MXC_CCM_CSCDR1_USDHC1_PODF_MASK (0x7 << 11) +#define MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET (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_UART_CLK_SEL_MASK (0x1 << 6) +#define MXC_CCM_CSCDR1_UART_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK (0x3 << 6) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_MASK (0x3F) +#define MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET (0) + +/* Define the bits in register CS1CDR */ +#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_MASK (0x7 << 25) +#define MXC_CCM_CS1CDR_ESAI_CLK_PODF_OFFSET (25) +#define MXC_CCM_CS1CDR_SSI3_CLK_PRED_MASK (0x7 << 22) +#define MXC_CCM_CS1CDR_SSI3_CLK_PRED_OFFSET (22) +#define MXC_CCM_CS1CDR_SSI3_CLK_PODF_MASK (0x3F << 16) +#define MXC_CCM_CS1CDR_SSI3_CLK_PODF_OFFSET (16) +#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_MASK (0x7 << 9) +#define MXC_CCM_CS1CDR_ESAI_CLK_PRED_OFFSET (9) +#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CS1CDR_SSI1_CLK_PRED_OFFSET (6) +#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_MASK (0x3F) +#define MXC_CCM_CS1CDR_SSI1_CLK_PODF_OFFSET (0) + +/* Define the bits in register CS2CDR */ +#define MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK (0x3F << 21) +#define MXC_CCM_CS2CDR_ENFC_CLK_PODF_OFFSET (21) +#define MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK (0x7 << 18) +#define MXC_CCM_CS2CDR_ENFC_CLK_PRED_OFFSET (18) +#define MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK (0x3 << 16) +#define MXC_CCM_CS2CDR_ENFC_CLK_SEL_OFFSET (16) +#define MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK (0x7 << 12) +#define MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET (12) +#define MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK (0x7 << 9) +#define MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET (9) +#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK (0x7 << 6) +#define MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET (6) +#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK (0x3F) +#define MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET (0) + +/* Define the bits in register CDCDR */ +#define MXC_CCM_CDCDR_HSI_TX_PODF_MASK (0x7 << 29) +#define MXC_CCM_CDCDR_HSI_TX_PODF_OFFSET (29) +#define MXC_CCM_CDCDR_HSI_TX_CLK_SEL (1 << 28) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_MASK (0x7 << 25) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PRED_OFFSET (25) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_MASK (0x7 << 22) +#define MXC_CCM_CDCDR_SPDIF0_CLK_PODF_OFFSET (22) +#define MXC_CCM_CDCDR_SPDIF0_CLK_SEL_MASK (0x3 << 20) +#define MXC_CCM_CDCDR_SPDIF0_CLK_SEL_OFFSET (20) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_MASK (0x7 << 12) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PRED_OFFSET (12) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_MASK (0x7 << 9) +#define MXC_CCM_CDCDR_SPDIF1_CLK_PODF_OFFSET (9) +#define MXC_CCM_CDCDR_SPDIF1_CLK_SEL_MASK (0x3 << 7) +#define MXC_CCM_CDCDR_SPDIF1_CLK_SEL_OFFSET (7) + +/* Define the bits in register CHSCCDR */ +#define MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_MASK (0x7 << 15) +#define MXC_CCM_CHSCCDR_IPU1_DI1_PRE_CLK_SEL_OFFSET (15) +#define MXC_CCM_CHSCCDR_IPU1_DI1_PODF_MASK (0x7 << 12) +#define MXC_CCM_CHSCCDR_IPU1_DI1_PODF_OFFSET (12) +#define MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_MASK (0x7 << 9) +#define MXC_CCM_CHSCCDR_IPU1_DI1_CLK_SEL_OFFSET (9) +#define MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK (0x7 << 6) +#define MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET (6) +#define MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK (0x7 << 3) +#define MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET (3) +#define MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK (0x7) +#define MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_OFFSET (0) + +/* Define the bits in register CSCDR2 */ +#define MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK (0x3F << 19) +#define MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET (19) +#define MXC_CCM_CSCDR2_ECSPI_CLK_SEL_MASK (0x1 << 18) +#define MXC_CCM_CSCDR2_ECSPI_CLK_SEL_OFFSET (18) +#define MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_MASK (0x7 << 15) +#define MXC_CCM_CSCDR2_IPU2_DI1_PRE_CLK_SEL_OFFSET (15) +#define MXC_CCM_CSCDR2_IPU2_DI1_PODF_MASK (0x7 << 12) +#define MXC_CCM_CSCDR2_IPU2_DI1_PODF_OFFSET (12) +#define MXC_CCM_CSCDR2_IPU2_DI1_CLK_SEL_MASK (0x7 << 9) +#define MXC_CCM_CSCDR2_IPU2_DI1_CLK_SEL_OFFSET (9) +#define MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_MASK (0x7 << 6) +#define MXC_CCM_CSCDR2_IPU2_DI0_PRE_CLK_SEL_OFFSET (6) +#define MXC_CCM_CSCDR2_IPU2_DI0_PODF_MASK (0x7 << 3) +#define MXC_CCM_CSCDR2_IPU2_DI0_PODF_OFFSET (3) +#define MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_MASK (0x7) +#define MXC_CCM_CSCDR2_IPU2_DI0_CLK_SEL_OFFSET (0) + +/* Define the bits in register CSCDR3 */ +#define MXC_CCM_CSCDR3_IPU2_HSP_PODF_MASK (0x7 << 16) +#define MXC_CCM_CSCDR3_IPU2_HSP_PODF_OFFSET (16) +#define MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_MASK (0x3 << 14) +#define MXC_CCM_CSCDR3_IPU2_HSP_CLK_SEL_OFFSET (14) +#define MXC_CCM_CSCDR3_IPU1_HSP_PODF_MASK (0x7 << 11) +#define MXC_CCM_CSCDR3_IPU1_HSP_PODF_OFFSET (11) +#define MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_MASK (0x3 << 9) +#define MXC_CCM_CSCDR3_IPU1_HSP_CLK_SEL_OFFSET (9) + +/* Define the bits in register CDHIPR */ +#define MXC_CCM_CDHIPR_ARM_PODF_BUSY (1 << 16) +#define MXC_CCM_CDHIPR_PERIPH_CLK_SEL_BUSY (1 << 5) +#define MXC_CCM_CDHIPR_MMDC_CH0_PODF_BUSY (1 << 4) +#define MXC_CCM_CDHIPR_PERIPH2_CLK_SEL_BUSY (1 << 3) +#define MXC_CCM_CDHIPR_MMDC_CH1_PODF_BUSY (1 << 2) +#define MXC_CCM_CDHIPR_AHB_PODF_BUSY (1 << 1) +#define MXC_CCM_CDHIPR_AXI_PODF_BUSY (1) + +/* Define the bits in register CLPCR */ +#define MXC_CCM_CLPCR_MASK_L2CC_IDLE (1 << 27) +#define MXC_CCM_CLPCR_MASK_SCU_IDLE (1 << 26) +#define MXC_CCM_CLPCR_MASK_CORE3_WFI (1 << 25) +#define MXC_CCM_CLPCR_MASK_CORE2_WFI (1 << 24) +#define MXC_CCM_CLPCR_MASK_CORE1_WFI (1 << 23) +#define MXC_CCM_CLPCR_MASK_CORE0_WFI (1 << 22) +#define MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS (1 << 21) +#define MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS (1 << 19) +#define MXC_CCM_CLPCR_WB_CORE_AT_LPM (1 << 17) +#define MXC_CCM_CLPCR_WB_PER_AT_LPM (1 << 16) +#define MXC_CCM_CLPCR_COSC_PWRDOWN (1 << 11) +#define MXC_CCM_CLPCR_STBY_COUNT_MASK (0x3 << 9) +#define MXC_CCM_CLPCR_STBY_COUNT_OFFSET (9) +#define MXC_CCM_CLPCR_VSTBY (1 << 8) +#define MXC_CCM_CLPCR_DIS_REF_OSC (1 << 7) +#define MXC_CCM_CLPCR_SBYOS (1 << 6) +#define MXC_CCM_CLPCR_ARM_CLK_DIS_ON_LPM (1 << 5) +#define MXC_CCM_CLPCR_LPSR_CLK_SEL_MASK (0x3 << 3) +#define MXC_CCM_CLPCR_LPSR_CLK_SEL_OFFSET (3) +#define MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY (1 << 2) +#define MXC_CCM_CLPCR_LPM_MASK (0x3) +#define MXC_CCM_CLPCR_LPM_OFFSET (0) + +/* Define the bits in register CISR */ +#define MXC_CCM_CISR_ARM_PODF_LOADED (1 << 26) +#define MXC_CCM_CISR_MMDC_CH0_PODF_LOADED (1 << 23) +#define MXC_CCM_CISR_PERIPH_CLK_SEL_LOADED (1 << 22) +#define MXC_CCM_CISR_MMDC_CH1_PODF_LOADED (1 << 21) +#define MXC_CCM_CISR_AHB_PODF_LOADED (1 << 20) +#define MXC_CCM_CISR_PERIPH2_CLK_SEL_LOADED (1 << 19) +#define MXC_CCM_CISR_AXI_PODF_LOADED (1 << 17) +#define MXC_CCM_CISR_COSC_READY (1 << 6) +#define MXC_CCM_CISR_LRF_PLL (1) + +/* Define the bits in register CIMR */ +#define MXC_CCM_CIMR_MASK_ARM_PODF_LOADED (1 << 26) +#define MXC_CCM_CIMR_MASK_MMDC_CH0_PODF_LOADED (1 << 23) +#define MXC_CCM_CIMR_MASK_PERIPH_CLK_SEL_LOADED (1 << 22) +#define MXC_CCM_CIMR_MASK_MMDC_CH1_PODF_LOADED (1 << 21) +#define MXC_CCM_CIMR_MASK_AHB_PODF_LOADED (1 << 20) +#define MXC_CCM_CIMR_MASK_PERIPH2_CLK_SEL_LOADED (1 << 22) +#define MXC_CCM_CIMR_MASK_AXI_PODF_LOADED (1 << 17) +#define MXC_CCM_CIMR_MASK_COSC_READY (1 << 6) +#define MXC_CCM_CIMR_MASK_LRF_PLL (1) + +/* Define the bits in register CCOSR */ +#define MXC_CCM_CCOSR_CKO2_EN_OFFSET (24) +#define MXC_CCM_CCOSR_CKO2_DIV_MASK (0x7 << 21) +#define MXC_CCM_CCOSR_CKO2_DIV_OFFSET (21) +#define MXC_CCM_CCOSR_CKO2_SEL_OFFSET (16) +#define MXC_CCM_CCOSR_CKO2_SEL_MASK (0x1F << 16) +#define MXC_CCM_CCOSR_CKOL_MIRROR_CKO2_MASK (1 << 8) +#define MXC_CCM_CCOSR_CKOL_EN_OFFSET 7 +#define MXC_CCM_CCOSR_CKOL_EN (0x1 << 7) +#define MXC_CCM_CCOSR_CKOL_DIV_MASK (0x7 << 4) +#define MXC_CCM_CCOSR_CKOL_DIV_OFFSET (4) +#define MXC_CCM_CCOSR_CKOL_SEL_MASK (0xF) +#define MXC_CCM_CCOSR_CKOL_SEL_OFFSET (0) + +/* Define the bits in registers CGPR */ +#define MXC_CCM_CGPR_EFUSE_PROG_SUPPLY_GATE (1 << 4) +#define MXC_CCM_CGPR_MMDC_EXT_CLK_DIS (1 << 2) +#define MXC_CCM_CGPR_PMIC_DELAY_SCALER (1) +#define MXC_CCM_CGPR_MEM_IPG_STOP_MASK (1 << 1) +#define MXC_CCM_CGPR_WAIT_MODE_FIX (1 << 17) + +/* 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_CG7_MASK (0x3 << 14) +#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 + +#endif /* __ARCH_ARM_MACH_MX6_CRM_REGS_H__ */ diff --git a/arch/arm/mach-mx6/devices-imx6q.h b/arch/arm/mach-mx6/devices-imx6q.h new file mode 100644 index 00000000..4525e29a --- /dev/null +++ b/arch/arm/mach-mx6/devices-imx6q.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2011-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/mx6.h> +#include <mach/devices-common.h> + +extern const struct imx_imx_uart_1irq_data imx6q_imx_uart_data[] __initconst; +#define imx6q_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx6q_imx_uart_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx6sl_imx_uart_data[] __initconst; +#define imx6sl_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx6sl_imx_uart_data[id], pdata) + +extern const struct imx_snvs_rtc_data imx6q_imx_snvs_rtc_data __initconst; +#define imx6q_add_imx_snvs_rtc() \ + imx_add_snvs_rtc(&imx6q_imx_snvs_rtc_data) + +extern const struct imx_caam_data imx6q_imx_caam_data __initconst; +#define imx6q_add_imx_caam() \ + imx_add_caam(&imx6q_imx_caam_data) + +extern const struct imx_anatop_thermal_imx_data +imx6q_anatop_thermal_imx_data __initconst; +#define imx6q_add_anatop_thermal_imx(id, pdata) \ + imx_add_anatop_thermal_imx(&imx6q_anatop_thermal_imx_data, pdata) + +extern const struct imx_dma_res_data imx6q_dma_res_data __initconst; +#define imx6q_add_dma() imx_add_dma(&imx6q_dma_res_data); + +#define imx6q_add_gpmi(platform_data) imx_add_gpmi(platform_data); + +extern const struct imx_fec_data imx6q_fec_data __initconst; +#define imx6q_add_fec(pdata) \ + imx_add_fec(&imx6q_fec_data, pdata) +extern const struct imx_fec_data imx6sl_fec_data __initconst; +#define imx6sl_add_fec(pdata) \ + imx_add_fec(&imx6sl_fec_data, pdata) + +extern const struct imx_sdhci_esdhc_imx_data +imx6q_sdhci_usdhc_imx_data[] __initconst; +#define imx6q_add_sdhci_usdhc_imx(id, pdata) \ + imx_add_sdhci_esdhc_imx(&imx6q_sdhci_usdhc_imx_data[id], pdata) + +extern const struct imx_spi_imx_data imx6q_ecspi_data[] __initconst; +#define imx6q_add_ecspi(id, pdata) \ + imx_add_spi_imx(&imx6q_ecspi_data[id], pdata) + +extern const struct imx_imx_i2c_data imx6q_imx_i2c_data[] __initconst; +#define imx6q_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx6q_imx_i2c_data[id], pdata) + +extern const struct imx_fsl_usb2_udc_data imx6q_fsl_usb2_udc_data __initconst; +#define imx6q_add_fsl_usb2_udc(pdata) \ + imx_add_fsl_usb2_udc(&imx6q_fsl_usb2_udc_data, pdata) + +extern const struct imx_mxc_ehci_data imx6q_mxc_ehci_otg_data __initconst; +#define imx6q_add_fsl_ehci_otg(pdata) \ + imx_add_fsl_ehci(&imx6q_mxc_ehci_otg_data, pdata) + +extern const struct imx_mxc_ehci_data imx6q_mxc_ehci_hs_data[] __initconst; +#define imx6q_add_fsl_ehci_hs(id, pdata) \ + imx_add_fsl_ehci(&imx6q_mxc_ehci_hs_data[id - 1], pdata) + +extern const struct imx_mxc_ehci_data imx6sl_mxc_ehci_hs_data[] __initconst; +#define imx6sl_add_fsl_ehci_hs(id, pdata) \ + imx_add_fsl_ehci(&imx6sl_mxc_ehci_hs_data[id - 1], pdata) + +extern const struct imx_fsl_usb2_otg_data imx6q_fsl_usb2_otg_data __initconst; +#define imx6q_add_fsl_usb2_otg(pdata) \ + imx_add_fsl_usb2_otg(&imx6q_fsl_usb2_otg_data, pdata) + +extern const struct imx_fsl_usb2_wakeup_data imx6q_fsl_otg_wakeup_data __initconst; +#define imx6q_add_fsl_usb2_otg_wakeup(pdata) \ + imx_add_fsl_usb2_wakeup(&imx6q_fsl_otg_wakeup_data, pdata) + +extern const struct imx_fsl_usb2_wakeup_data imx6q_fsl_hs_wakeup_data[] __initconst; +#define imx6q_add_fsl_usb2_hs_wakeup(id, pdata) \ + imx_add_fsl_usb2_wakeup(&imx6q_fsl_hs_wakeup_data[id - 1], pdata) + +extern const struct imx_fsl_usb2_wakeup_data imx6sl_fsl_hs_wakeup_data[] __initconst; +#define imx6sl_add_fsl_usb2_hs_wakeup(id, pdata) \ + imx_add_fsl_usb2_wakeup(&imx6sl_fsl_hs_wakeup_data[id - 1], pdata) + +extern const struct imx_imx_esai_data imx6q_imx_esai_data[] __initconst; +#define imx6q_add_imx_esai(id, pdata) \ + imx_add_imx_esai(&imx6q_imx_esai_data[id], pdata) + +extern const struct imx_viv_gpu_data imx6_gpu_data __initconst; + +extern const struct imx_ahci_data imx6q_ahci_data __initconst; +#define imx6q_add_ahci(id, pdata) \ + imx_add_ahci(&imx6q_ahci_data, pdata) + +extern const struct imx_imx_ssi_data imx6_imx_ssi_data[] __initconst; +#define imx6q_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx6_imx_ssi_data[id], pdata) + +extern const struct imx_ipuv3_data imx6q_ipuv3_data[] __initconst; +#define imx6q_add_ipuv3(id, pdata) imx_add_ipuv3(id, &imx6q_ipuv3_data[id], pdata) +#define imx6q_add_ipuv3fb(id, pdata) imx_add_ipuv3_fb(id, pdata) + +#define imx6q_add_lcdif(pdata) \ + platform_device_register_resndata(NULL, "mxc_lcdif",\ + 0, NULL, 0, pdata, sizeof(*pdata)); + +extern const struct imx_ldb_data imx6q_ldb_data __initconst; +#define imx6q_add_ldb(pdata) \ + imx_add_ldb(&imx6q_ldb_data, pdata); + +#define imx6q_add_v4l2_output(id) \ + platform_device_register_resndata(NULL, "mxc_v4l2_output",\ + id, NULL, 0, NULL, 0); + +#define imx6q_add_v4l2_capture(id, pdata) \ + platform_device_register_resndata(NULL, "mxc_v4l2_capture",\ + id, NULL, 0, pdata, sizeof(*pdata)); + +extern const struct imx_mxc_hdmi_data imx6q_mxc_hdmi_data __initconst; +#define imx6q_add_mxc_hdmi(pdata) \ + imx_add_mxc_hdmi(&imx6q_mxc_hdmi_data, pdata) + +extern const struct imx_mxc_hdmi_core_data imx6q_mxc_hdmi_core_data __initconst; +#define imx6q_add_mxc_hdmi_core(pdata) \ + imx_add_mxc_hdmi_core(&imx6q_mxc_hdmi_core_data, pdata) + +extern const struct imx_vpu_data imx6q_vpu_data __initconst; +#define imx6q_add_vpu() imx_add_vpu(&imx6q_vpu_data) + +extern const struct imx_otp_data imx6q_otp_data __initconst; +#define imx6q_add_otp() \ + imx_add_otp(&imx6q_otp_data) + +extern const struct imx_viim_data imx6q_viim_data __initconst; +#define imx6q_add_viim() \ + imx_add_viim(&imx6q_viim_data) + +extern const struct imx_imx2_wdt_data imx6q_imx2_wdt_data[] __initconst; +#define imx6q_add_imx2_wdt(id, pdata) \ + imx_add_imx2_wdt(&imx6q_imx2_wdt_data[id]) + +extern const struct imx_pm_imx_data imx6q_pm_imx_data __initconst; +#define imx6q_add_pm_imx(id, pdata) \ + imx_add_pm_imx(&imx6q_pm_imx_data, pdata) + +extern const struct imx_imx_asrc_data imx6q_imx_asrc_data[] __initconst; +#define imx6q_add_asrc(pdata) \ + imx_add_imx_asrc(imx6q_imx_asrc_data, pdata) + +extern const struct imx_dvfs_core_data imx6q_dvfs_core_data __initconst; +#define imx6q_add_dvfs_core(pdata) \ + imx_add_dvfs_core(&imx6q_dvfs_core_data, pdata) + +extern const struct imx_viv_gpu_data imx6_gc2000_data __initconst; +extern const struct imx_viv_gpu_data imx6_gc320_data __initconst; +extern const struct imx_viv_gpu_data imx6_gc355_data __initconst; + +extern const struct imx_mxc_pwm_data imx6q_mxc_pwm_data[] __initconst; +#define imx6q_add_mxc_pwm(id) \ + imx_add_mxc_pwm(&imx6q_mxc_pwm_data[id]) + +#define imx6q_add_mxc_pwm_backlight(id, pdata) \ + platform_device_register_resndata(NULL, "pwm-backlight",\ + id, NULL, 0, pdata, sizeof(*pdata)); + +extern const struct imx_spdif_data imx6q_imx_spdif_data __initconst; +#define imx6q_add_spdif(pdata) imx_add_spdif(&imx6q_imx_spdif_data, pdata) + +extern const struct imx_spdif_dai_data imx6q_spdif_dai_data __initconst; +#define imx6q_add_spdif_dai() imx_add_spdif_dai(&imx6q_spdif_dai_data) + +#define imx6q_add_spdif_audio_device(pdata) imx_add_spdif_audio_device() + +#define imx6q_add_hdmi_soc() imx_add_hdmi_soc() +extern const struct imx_hdmi_soc_data imx6q_imx_hdmi_soc_dai_data __initconst; +#define imx6q_add_hdmi_soc_dai() \ + imx_add_hdmi_soc_dai(&imx6q_imx_hdmi_soc_dai_data) + +extern const struct imx_mipi_dsi_data imx6q_mipi_dsi_data __initconst; +#define imx6q_add_mipi_dsi(pdata) \ + imx_add_mipi_dsi(&imx6q_mipi_dsi_data, pdata) + +extern const struct imx_flexcan_data imx6q_flexcan_data[] __initconst; +#define imx6q_add_flexcan(id, pdata) \ + imx_add_flexcan(&imx6q_flexcan_data[id], pdata) +#define imx6q_add_flexcan0(pdata) imx6q_add_flexcan(0, pdata) +#define imx6q_add_flexcan1(pdata) imx6q_add_flexcan(1, pdata) + +extern const struct imx_mipi_csi2_data imx6q_mipi_csi2_data __initconst; +#define imx6q_add_mipi_csi2(pdata) \ + imx_add_mipi_csi2(&imx6q_mipi_csi2_data, pdata) + +extern const struct imx_perfmon_data imx6q_perfmon_data[] __initconst; +#define imx6q_add_perfmon(id) \ + imx_add_perfmon(&imx6q_perfmon_data[id]) + +extern const struct imx_mxc_mlb_data imx6q_mxc_mlb150_data __initconst; +#define imx6q_add_mlb150(pdata) \ + imx_add_mlb(pdata) + +extern const struct imx_pxp_data imx6dl_pxp_data __initconst; +#define imx6dl_add_imx_pxp() \ + imx_add_imx_pxp(&imx6dl_pxp_data) + +#define imx6dl_add_imx_pxp_client() \ + imx_add_imx_pxp_client() + +#define imx6sl_add_imx_pxp_v4l2() \ + imx_add_imx_pxp_v4l2() + +extern const struct imx_fsl_csi_data imx6sl_csi_data __initconst; +#define imx6sl_add_fsl_csi() \ + imx_add_fsl_csi(&imx6sl_csi_data) + +extern const struct imx_epdc_data imx6dl_epdc_data __initconst; +#define imx6dl_add_imx_epdc(pdata) \ + imx_add_imx_epdc(&imx6dl_epdc_data, pdata) + +extern const struct imx_epdc_data imx6sl_spdc_data __initconst; +#define imx6sl_add_imx_spdc(pdata) \ + imx_add_imx_spdc(&imx6sl_spdc_data, pdata) + +extern const struct imx_elcdif_data imx6dl_elcdif_data __initconst; +#define imx6dl_add_imx_elcdif(pdata) \ + imx_add_imx_elcdif(&imx6dl_elcdif_data, pdata) +extern const struct imx_vdoa_data imx6q_vdoa_data __initconst; +#define imx6q_add_vdoa() imx_add_vdoa(&imx6q_vdoa_data) + +extern const struct imx_pcie_data imx6q_pcie_data __initconst; +#define imx6q_add_pcie(pdata) imx_add_pcie(&imx6q_pcie_data, pdata) + +#define imx6q_add_busfreq(pdata) imx_add_busfreq(pdata) + +#define imx6q_add_ion(id, pdata, size) \ + platform_device_register_resndata(NULL, "ion-mxc",\ + id, NULL, 0, pdata, size); + +extern const struct imx_imx_keypad_data imx6sl_imx_keypad_data; +#define imx6sl_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx6sl_imx_keypad_data, pdata) + +extern const struct imx_dcp_data imx6sl_dcp_data __initconst; +#define imx6sl_add_dcp() \ + imx_add_dcp(&imx6sl_dcp_data); + +extern const struct imx_rngb_data imx6sl_rngb_data __initconst; +#define imx6sl_add_rngb() \ + imx_add_rngb(&imx6sl_rngb_data); + +#define imx6_add_armpmu() imx_add_imx_armpmu() diff --git a/arch/arm/mach-mx6/devices.c b/arch/arm/mach-mx6/devices.c new file mode 100644 index 00000000..29becab0 --- /dev/null +++ b/arch/arm/mach-mx6/devices.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2011-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/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/ipu.h> +#include <linux/fb.h> +#include <linux/delay.h> +#include <linux/uio_driver.h> +#include <linux/iram_alloc.h> +#include <linux/fsl_devices.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/gpio.h> + +static struct mxc_gpio_port mxc_gpio_ports[] = { + { + .chip.label = "gpio-0", + .base = IO_ADDRESS(GPIO1_BASE_ADDR), + .irq = MXC_INT_GPIO1_INT15_0_NUM, + .irq_high = MXC_INT_GPIO1_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + }, + { + .chip.label = "gpio-1", + .base = IO_ADDRESS(GPIO2_BASE_ADDR), + .irq = MXC_INT_GPIO2_INT15_0_NUM, + .irq_high = MXC_INT_GPIO2_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 1 + }, + { + .chip.label = "gpio-2", + .base = IO_ADDRESS(GPIO3_BASE_ADDR), + .irq = MXC_INT_GPIO3_INT15_0_NUM, + .irq_high = MXC_INT_GPIO3_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2 + }, + { + .chip.label = "gpio-3", + .base = IO_ADDRESS(GPIO4_BASE_ADDR), + .irq = MXC_INT_GPIO4_INT15_0_NUM, + .irq_high = MXC_INT_GPIO4_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 3 + }, + { + .chip.label = "gpio-4", + .base = IO_ADDRESS(GPIO5_BASE_ADDR), + .irq = MXC_INT_GPIO5_INT15_0_NUM, + .irq_high = MXC_INT_GPIO5_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 4 + }, + { + .chip.label = "gpio-5", + .base = IO_ADDRESS(GPIO6_BASE_ADDR), + .irq = MXC_INT_GPIO6_INT15_0_NUM, + .irq_high = MXC_INT_GPIO6_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 5 + }, + { + .chip.label = "gpio-6", + .base = IO_ADDRESS(GPIO7_BASE_ADDR), + .irq = MXC_INT_GPIO7_INT15_0_NUM, + .irq_high = MXC_INT_GPIO7_INT31_16_NUM, + .virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 6 + }, +}; + +int mx6q_register_gpios(void) +{ + /* 7 ports for Mx6 */ + return mxc_gpio_init(mxc_gpio_ports, 7); +} diff --git a/arch/arm/mach-mx6/dummy_gpio.c b/arch/arm/mach-mx6/dummy_gpio.c new file mode 100644 index 00000000..006397bc --- /dev/null +++ b/arch/arm/mach-mx6/dummy_gpio.c @@ -0,0 +1,124 @@ +/* + * 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/errno.h> +#include <linux/module.h> + +void gpio_uart_active(int port, int no_irda) {} +EXPORT_SYMBOL(gpio_uart_active); + +void gpio_uart_inactive(int port, int no_irda) {} +EXPORT_SYMBOL(gpio_uart_inactive); + +void gpio_gps_active(void) {} +EXPORT_SYMBOL(gpio_gps_active); + +void gpio_gps_inactive(void) {} +EXPORT_SYMBOL(gpio_gps_inactive); + +void config_uartdma_event(int port) {} +EXPORT_SYMBOL(config_uartdma_event); + +void gpio_spi_active(int cspi_mod) {} +EXPORT_SYMBOL(gpio_spi_active); + +void gpio_spi_inactive(int cspi_mod) {} +EXPORT_SYMBOL(gpio_spi_inactive); + +void gpio_owire_active(void) {} +EXPORT_SYMBOL(gpio_owire_active); + +void gpio_owire_inactive(void) {} +EXPORT_SYMBOL(gpio_owire_inactive); + +void gpio_i2c_active(int i2c_num) {} +EXPORT_SYMBOL(gpio_i2c_active); + +void gpio_i2c_inactive(int i2c_num) {} +EXPORT_SYMBOL(gpio_i2c_inactive); + +void gpio_i2c_hs_active(void) {} +EXPORT_SYMBOL(gpio_i2c_hs_active); + +void gpio_i2c_hs_inactive(void) {} +EXPORT_SYMBOL(gpio_i2c_hs_inactive); + +void gpio_pmic_active(void) {} +EXPORT_SYMBOL(gpio_pmic_active); + +void gpio_activate_audio_ports(void) {} +EXPORT_SYMBOL(gpio_activate_audio_ports); + +void gpio_sdhc_active(int module) {} +EXPORT_SYMBOL(gpio_sdhc_active); + +void gpio_sdhc_inactive(int module) {} +EXPORT_SYMBOL(gpio_sdhc_inactive); + +void gpio_sensor_select(int sensor) {} + +void gpio_sensor_active(unsigned int csi) {} +EXPORT_SYMBOL(gpio_sensor_active); + +void gpio_sensor_inactive(unsigned int csi) {} +EXPORT_SYMBOL(gpio_sensor_inactive); + +void gpio_ata_active(void) {} +EXPORT_SYMBOL(gpio_ata_active); + +void gpio_ata_inactive(void) {} +EXPORT_SYMBOL(gpio_ata_inactive); + +void gpio_nand_active(void) {} +EXPORT_SYMBOL(gpio_nand_active); + +void gpio_nand_inactive(void) {} +EXPORT_SYMBOL(gpio_nand_inactive); + +void gpio_keypad_active(void) {} +EXPORT_SYMBOL(gpio_keypad_active); + +void gpio_keypad_inactive(void) {} +EXPORT_SYMBOL(gpio_keypad_inactive); + +int gpio_usbotg_hs_active(void) +{ + return 0; +} +EXPORT_SYMBOL(gpio_usbotg_hs_active); + +void gpio_usbotg_hs_inactive(void) {} +EXPORT_SYMBOL(gpio_usbotg_hs_inactive); + +void gpio_fec_active(void) {} +EXPORT_SYMBOL(gpio_fec_active); + +void gpio_fec_inactive(void) {} +EXPORT_SYMBOL(gpio_fec_inactive); + +void gpio_spdif_active(void) {} +EXPORT_SYMBOL(gpio_spdif_active); + +void gpio_spdif_inactive(void) {} +EXPORT_SYMBOL(gpio_spdif_inactive); + +void gpio_mlb_active(void) {} +EXPORT_SYMBOL(gpio_mlb_active); + +void gpio_mlb_inactive(void) {} +EXPORT_SYMBOL(gpio_mlb_inactive); diff --git a/arch/arm/mach-mx6/etm.c b/arch/arm/mach-mx6/etm.c new file mode 100644 index 00000000..8f328608 --- /dev/null +++ b/arch/arm/mach-mx6/etm.c @@ -0,0 +1,110 @@ +/* + * 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/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/delay.h> +#include <linux/amba/bus.h> + +#include <mach/hardware.h> +#include <asm/io.h> +#include <asm/mach/map.h> +#include <asm/hardware/coresight.h> + +static struct __init amba_device mx6_etb_device = { + .dev = { + .init_name = "etb", + }, + .res = { + .start = MX6Q_ETB_BASE_ADDR, + .end = MX6Q_ETB_BASE_ADDR + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + .periphid = 0x3bb907, +}; + +static struct __init amba_device mx6_etm_device[] = { + { + .dev = { + .init_name = "etm.0", + }, + .res = { + .start = MX6Q_PTM0_BASE_ADDR, + .end = MX6Q_PTM0_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, + { + .dev = { + .init_name = "etm.1", + }, + .res = { + .start = MX6Q_PTM1_BASE_ADDR, + .end = MX6Q_PTM1_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, + { + .dev = { + .init_name = "etm.2", + }, + .res = { + .start = MX6Q_PTM2_BASE_ADDR, + .end = MX6Q_PTM2_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, + { + .dev = { + .init_name = "etm.3", + }, + .res = { + .start = MX6Q_PTM3_BASE_ADDR, + .end = MX6Q_PTM3_BASE_ADDR + SZ_4K - 1, + }, + .periphid = 0x1bb950, + }, +}; + +#define FUNNEL_CTL 0 +static int __init etm_init(void) +{ + int i; + __iomem void *base; + base = ioremap(0x02144000, SZ_4K); + /*Unlock Funnel*/ + __raw_writel(UNLOCK_MAGIC, base + CSMR_LOCKACCESS); + /*Enable all funnel port*/ + __raw_writel(__raw_readl(base + FUNNEL_CTL) | 0xFF, + base + FUNNEL_CTL); + /*Lock Funnel*/ + __raw_writel(0, base + CSMR_LOCKACCESS); + iounmap(base); + + amba_device_register(&mx6_etb_device, &iomem_resource); + for (i = 0; i < num_possible_cpus(); i++) + amba_device_register(mx6_etm_device + i, &iomem_resource); + + return 0; +} + +subsys_initcall(etm_init); diff --git a/arch/arm/mach-mx6/headsmp.S b/arch/arm/mach-mx6/headsmp.S new file mode 100644 index 00000000..9492d8dc --- /dev/null +++ b/arch/arm/mach-mx6/headsmp.S @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2011-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/linkage.h> +#include <linux/init.h> + +ENTRY(v7_invalidate_l1) + mov r0, #0 + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: subs r3, r3, #1 @ Temp-- + mov r5, r3, lsl r1 + mov r6, r2, lsl r0 + orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift) + mcr p15, 0, r5, c7, c6, 2 + bgt 2b + cmp r2, #0 + bgt 1b + dsb + isb + mov pc, lr +ENDPROC(v7_invalidate_l1) + + __CPUINIT +ENTRY(mx6_secondary_startup) + + /* Invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 @ Invalidate I-Cache + /* Invalidate L1 D-cache */ + bl v7_invalidate_l1 + /* Set ARM working mode */ + msr cpsr_fsxc, #0xd3 + + mrc p15, 0, r0, c0, c0, 5 + and r0, r0, #15 + ldr r1, = 0x020d8020 + add r1, r0, LSL#3 + + /*Clear SRC_GPR register */ + mov r0, #0 + str r0, [r1] + str r0, [r1, #0x4] + + /* Jump to secondary_startup */ + b secondary_startup + +ENDPROC(mx6_secondary_startup) diff --git a/arch/arm/mach-mx6/irq.c b/arch/arm/mach-mx6/irq.c new file mode 100644 index 00000000..d298d50b --- /dev/null +++ b/arch/arm/mach-mx6/irq.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011-2013 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/io.h> +#include <linux/platform_device.h> +#include <linux/irq.h> +#include <asm/hardware/gic.h> +#include <mach/hardware.h> +#ifdef CONFIG_CPU_FREQ_GOV_INTERACTIVE +#include <linux/cpufreq.h> +#endif +#ifdef CONFIG_PCI_MSI +#include "msi.h" +#endif + +int mx6q_register_gpios(void); +unsigned int gpc_wake_irq[4]; +extern bool enable_wait_mode; +#ifdef CONFIG_CPU_FREQ_GOV_INTERACTIVE +extern int cpufreq_gov_irq_tuner_register(struct irq_tuner dbs_irq_tuner); +#endif + +static int mx6_gic_irq_set_wake(struct irq_data *d, unsigned int enable) +{ + if ((d->irq < MXC_INT_START) || (d->irq > MXC_INT_END)) { + printk(KERN_ERR "Invalid irq number!\n"); + return -EINVAL; + } + + if (enable) { + gpc_wake_irq[d->irq / 32 - 1] |= 1 << (d->irq % 32); + printk(KERN_INFO "add wake up source irq %d\n", d->irq); + } else { + printk(KERN_INFO "remove wake up source irq %d\n", d->irq); + gpc_wake_irq[d->irq / 32 - 1] &= ~(1 << (d->irq % 32)); + } + return 0; +} +#ifdef CONFIG_CPU_FREQ_GOV_INTERACTIVE +static struct irq_tuner mxc_irq_tuner[] = { + { + .irq_number = 41, /* GPU 3D */ + .up_threshold = 0, + .enable = 0,}, + { + .irq_number = 42, /* GPU 2D */ + .up_threshold = 40, + .enable = 0,}, + { + .irq_number = 43, /* GPU VG */ + .up_threshold = 0, + .enable = 0,}, + { + .irq_number = 42, /* GPU 2D */ + .up_threshold = 40, + .enable = 1,}, + { + .irq_number = 43, /* GPU VG */ + .up_threshold = 0, + .enable = 1,}, + { + .irq_number = 54, /* uSDHC1 */ + .up_threshold = 4, + .enable = 1,}, + { + .irq_number = 55, /* uSDHC2 */ + .up_threshold = 4, + .enable = 1,}, + { + .irq_number = 56, /* uSDHC3 */ + .up_threshold = 4, + .enable = 1,}, + { + .irq_number = 57, /* uSDHC4 */ + .up_threshold = 4, + .enable = 1,}, + { + .irq_number = 71, /* SATA */ + .up_threshold = 4, + .enable = 1,}, + { + .irq_number = 75, /* OTG */ + .up_threshold = 10, + .enable = 1,}, + { + .irq_number = 150, /* ENET */ + .up_threshold = 4, + .enable = 1,}, + { + .irq_number = 0, /* END */ + .up_threshold = 0, + .enable = 0,}, +}; +#endif +void mx6_init_irq(void) +{ + void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); + struct irq_desc *desc; + unsigned int i; + + /* start offset if private timer irq id, which is 29. + * ID table: + * Global timer, PPI -> ID27 + * A legacy nFIQ, PPI -> ID28 + * Private timer, PPI -> ID29 + * Watchdog timers, PPI -> ID30 + * A legacy nIRQ, PPI -> ID31 + */ + gic_init(0, 29, IO_ADDRESS(IC_DISTRIBUTOR_BASE_ADDR), + IO_ADDRESS(IC_INTERFACES_BASE_ADDR)); + + if (enable_wait_mode) { + /* Mask the always pending interrupts - HW bug. */ + __raw_writel(0x00400000, gpc_base + 0x0c); + __raw_writel(0x20000000, gpc_base + 0x10); + } + + + for (i = MXC_INT_START; i <= MXC_INT_END; i++) { + desc = irq_to_desc(i); + desc->irq_data.chip->irq_set_wake = mx6_gic_irq_set_wake; + } + mx6q_register_gpios(); +#ifdef CONFIG_CPU_FREQ_GOV_INTERACTIVE + for (i = 0; i < ARRAY_SIZE(mxc_irq_tuner); i++) + cpufreq_gov_irq_tuner_register(mxc_irq_tuner[i]); +#endif +#ifdef CONFIG_PCI_MSI + imx_msi_init(); +#endif +} diff --git a/arch/arm/mach-mx6/localtimer.c b/arch/arm/mach-mx6/localtimer.c new file mode 100644 index 00000000..2fac9fb2 --- /dev/null +++ b/arch/arm/mach-mx6/localtimer.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011-2013 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/smp.h> +#include <linux/clockchips.h> +#include <asm/smp_twd.h> +#include <asm/localtimer.h> +#include <mach/irqs.h> +#include <mach/hardware.h> + +/* + * Setup the local clock events for a CPU. + */ +int __cpuinit local_timer_setup(struct clock_event_device *evt) +{ + evt->irq = IRQ_LOCALTIMER; + twd_timer_setup(evt); + return 0; +} diff --git a/arch/arm/mach-mx6/mm.c b/arch/arm/mach-mx6/mm.c new file mode 100644 index 00000000..78e5712b --- /dev/null +++ b/arch/arm/mach-mx6/mm.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2011-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. + */ + +/* + * Create static mapping between physical to virtual memory. + */ + +#include <linux/mm.h> +#include <linux/init.h> + +#include <asm/mach/map.h> +#include <mach/iomux-v3.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-v3.h> +#include <asm/hardware/cache-l2x0.h> +#include "crm_regs.h" + +/*! + * This structure defines the MX6 memory map. + */ +static struct map_desc mx6_io_desc[] __initdata = { + { + .virtual = BOOT_ROM_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(BOOT_ROM_BASE_ADDR), + .length = ROMCP_SIZE, + .type = MT_DEVICE}, + { + .virtual = AIPS1_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS1_ARB_BASE_ADDR), + .length = AIPS1_SIZE, + .type = MT_DEVICE}, + { + .virtual = AIPS2_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(AIPS2_ARB_BASE_ADDR), + .length = AIPS2_SIZE, + .type = MT_DEVICE}, + { + .virtual = ARM_PERIPHBASE_VIRT, + .pfn = __phys_to_pfn(ARM_PERIPHBASE), + .length = ARM_PERIPHBASE_SIZE, + .type = MT_DEVICE}, + { + .virtual = IRAM_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(IRAM_BASE_ADDR), + .length = IRAM_VIRT_SIZE, + .type = MT_MEMORY_NONCACHED}, +}; + +static void mx6_set_cpu_type(void) +{ + u32 cpu_type = readl(IO_ADDRESS(ANATOP_BASE_ADDR + 0x280)); + + cpu_type >>= 16; + if (cpu_type == 0x60) { + mxc_set_cpu_type(MXC_CPU_MX6SL); + imx_print_silicon_rev("i.MX6SoloLite", mx6sl_revision()); + return; + } + + cpu_type = readl(IO_ADDRESS(ANATOP_BASE_ADDR + 0x260)); + cpu_type >>= 16; + if (cpu_type == 0x63) { + mxc_set_cpu_type(MXC_CPU_MX6Q); + imx_print_silicon_rev("i.MX6Q", mx6q_revision()); + } else if (cpu_type == 0x61) { + mxc_set_cpu_type(MXC_CPU_MX6DL); + imx_print_silicon_rev("i.MX6DL/SOLO", mx6dl_revision()); + } else + pr_err("Unknown CPU type: %x\n", cpu_type); +} + +/*! + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory map for + * the IO modules. + */ +void __init mx6_map_io(void) +{ + iotable_init(mx6_io_desc, ARRAY_SIZE(mx6_io_desc)); + mxc_iomux_v3_init(IO_ADDRESS(MX6Q_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(IO_ADDRESS(MX6Q_WDOG1_BASE_ADDR)); + mx6_set_cpu_type(); + mxc_cpu_lp_set(WAIT_CLOCKED); +} +#ifdef CONFIG_CACHE_L2X0 +int mxc_init_l2x0(void) +{ + unsigned int val; + + #define IOMUXC_GPR11_L2CACHE_AS_OCRAM 0x00000002 + + val = readl(IOMUXC_GPR11); + if (cpu_is_mx6sl() && (val & IOMUXC_GPR11_L2CACHE_AS_OCRAM)) { + /* L2 cache configured as OCRAM, reset it */ + val &= ~IOMUXC_GPR11_L2CACHE_AS_OCRAM; + writel(val, IOMUXC_GPR11); + } + + writel(0x132, IO_ADDRESS(L2_BASE_ADDR + L2X0_TAG_LATENCY_CTRL)); + writel(0x132, IO_ADDRESS(L2_BASE_ADDR + L2X0_DATA_LATENCY_CTRL)); + + /* + * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0 + * The L2 cache controller(PL310) version on the i.MX6DL/SOLO/SL is r3p2 + * But according to ARM PL310 errata: 752271 + * ID: 752271: Double linefill feature can cause data corruption + * Fault Status: Present in: r3p0, r3p1, r3p1-50rel0. Fixed in r3p2 + * Workaround: The only workaround to this erratum is to disable the + * double linefill feature. This is the default behavior. + */ + if (!cpu_is_mx6q()) { + val = readl(IO_ADDRESS(L2_BASE_ADDR + L2X0_PREFETCH_CTRL)); + val |= 0x40800000; + writel(val, IO_ADDRESS(L2_BASE_ADDR + L2X0_PREFETCH_CTRL)); + } + + val = readl(IO_ADDRESS(L2_BASE_ADDR + L2X0_POWER_CTRL)); + val |= L2X0_DYNAMIC_CLK_GATING_EN; + val |= L2X0_STNDBY_MODE_EN; + writel(val, IO_ADDRESS(L2_BASE_ADDR + L2X0_POWER_CTRL)); + + l2x0_init(IO_ADDRESS(L2_BASE_ADDR), 0x0, ~0x00000000); + return 0; +} + + +arch_initcall(mxc_init_l2x0); +#endif diff --git a/arch/arm/mach-mx6/msi.c b/arch/arm/mach-mx6/msi.c new file mode 100644 index 00000000..096d1c24 --- /dev/null +++ b/arch/arm/mach-mx6/msi.c @@ -0,0 +1,151 @@ +/* + * arch/arm/mach-mx6/msi.c + * + * PCI MSI support for the imx processor + * + * Copyright (c) 2013 Boundary Devices. + * Copyright (C) 2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + */ +#include <linux/pci.h> +#include <linux/msi.h> +#include <asm/bitops.h> +#include <asm/mach/irq.h> +#include <asm/irq.h> +#include "msi.h" + + +#define IMX_NUM_MSI_IRQS 128 +static DECLARE_BITMAP(msi_irq_in_use, IMX_NUM_MSI_IRQS); + +static void imx_msi_handler(unsigned int irq, struct irq_desc *desc) +{ + int i, j; + unsigned int status; + struct irq_chip *chip = irq_get_chip(irq); + unsigned int base_irq = IRQ_IMX_MSI_0; + + chained_irq_enter(chip, desc); + for (i = 0; i < 8; i++) { + status = imx_pcie_msi_pending(i); + while (status) { + j = __fls(status); + generic_handle_irq(base_irq + j); + status &= ~(1 << j); + } + base_irq += 32; + } + chained_irq_exit(chip, desc); +} + +/* +* Dynamic irq allocate and deallocation +*/ +int create_irq(void) +{ + int irq, pos; + + do { + pos = find_first_zero_bit(msi_irq_in_use, IMX_NUM_MSI_IRQS); + if ((unsigned int)pos >= IMX_NUM_MSI_IRQS) + return -ENOSPC; + /* test_and_set_bit operates on 32-bits at a time */ + } while (test_and_set_bit(pos, msi_irq_in_use)); + + irq = IRQ_IMX_MSI_0 + pos; + dynamic_irq_init(irq); + return irq; +} + +void destroy_irq(unsigned int irq) +{ + int pos = irq - IRQ_IMX_MSI_0; + + dynamic_irq_cleanup(irq); + clear_bit(pos, msi_irq_in_use); +} + +void arch_teardown_msi_irq(unsigned int irq) +{ + destroy_irq(irq); +} + +static void imx_msi_irq_ack(struct irq_data *d) +{ + return; +} + +static void imx_msi_irq_enable(struct irq_data *d) +{ + imx_pcie_enable_irq(d->irq - IRQ_IMX_MSI_0, 1); + return unmask_msi_irq(d); +} + +static void imx_msi_irq_disable(struct irq_data *d) +{ + imx_pcie_enable_irq(d->irq - IRQ_IMX_MSI_0, 0); + return mask_msi_irq(d); +} + +static void imx_msi_irq_mask(struct irq_data *d) +{ + imx_pcie_mask_irq(d->irq - IRQ_IMX_MSI_0, 1); + return mask_msi_irq(d); +} + +static void imx_msi_irq_unmask(struct irq_data *d) +{ + imx_pcie_mask_irq(d->irq - IRQ_IMX_MSI_0, 0); + return unmask_msi_irq(d); +} + +static struct irq_chip imx_msi_chip = { + .name = "PCIe-MSI", + .irq_ack = imx_msi_irq_ack, + .irq_enable = imx_msi_irq_enable, + .irq_disable = imx_msi_irq_disable, + .irq_mask = imx_msi_irq_mask, + .irq_unmask = imx_msi_irq_unmask, +}; + +int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) +{ + int irq = create_irq(); + struct msi_msg msg; + + if (irq < 0) + return irq; + + irq_set_msi_desc(irq, desc); + + msg.address_hi = 0x0; + msg.address_lo = MSI_MATCH_ADDR; + /* 16bits msg.data: set cpu type to the upper 8bits*/ + msg.data = (mxc_cpu_type << 8) | ((irq - IRQ_IMX_MSI_0) & 0xFF); + + write_msi_msg(irq, &msg); + irq_set_chip_and_handler(irq, &imx_msi_chip, handle_simple_irq); + set_irq_flags(irq, IRQF_VALID); + pr_info("IMX-PCIe: MSI 0x%04x @%#x:%#x, irq = %d\n", + msg.data, msg.address_hi, + msg.address_lo, irq); + return 0; +} + +void imx_msi_init(void) +{ + irq_set_chained_handler(MXC_INT_PCIE_0, imx_msi_handler); +} diff --git a/arch/arm/mach-mx6/msi.h b/arch/arm/mach-mx6/msi.h new file mode 100644 index 00000000..ce0e4673 --- /dev/null +++ b/arch/arm/mach-mx6/msi.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 Boundary Devices, Inc. All Rights Reserved. + * Copyright (C) 2013 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. + */ + +extern void imx_pcie_enable_irq(unsigned pos, int set); +void imx_pcie_mask_irq(unsigned pos, int set); +unsigned imx_pcie_msi_pending(unsigned index); + +#define MSI_MATCH_ADDR 0x01FF8000 + +void imx_msi_init(void); diff --git a/arch/arm/mach-mx6/mx6_anatop_regulator.c b/arch/arm/mach-mx6/mx6_anatop_regulator.c new file mode 100644 index 00000000..b26f86bf --- /dev/null +++ b/arch/arm/mach-mx6/mx6_anatop_regulator.c @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2011-2013 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. + */ + +/* + * mx6_anatop_regulator.c -- i.MX6 Driver for Anatop regulators + */ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/regulator/consumer.h> +#include <linux/regulator/machine.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/clk.h> + +#include <mach/clock.h> +#include <mach/system.h> + +#include "crm_regs.h" +#include "regs-anadig.h" + +#define GPC_PGC_GPU_PGCR_OFFSET 0x260 +#define GPC_CNTR_OFFSET 0x0 + +#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ +#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* time base on 24M OSC */ + +extern struct platform_device sgtl5000_vdda_reg_devices; +extern struct platform_device sgtl5000_vddio_reg_devices; +extern struct platform_device sgtl5000_vddd_reg_devices; +extern void __iomem *gpc_base; +/* we use the below flag to keep PU regulator state, because enable/disable +of PU regulator share with the same register as voltage set of PU regulator. +PU voltage set by cpufreq driver if the flag is set, and enable/disable by +GPU/VPU driver*/ +static unsigned int pu_is_enabled; +static unsigned int get_clk; +static struct clk *gpu3d_clk, *gpu3d_shade_clk, *gpu2d_clk, *gpu2d_axi_clk; +static struct clk *openvg_axi_clk, *vpu_clk; +extern int external_pureg; +extern struct regulator *pu_regulator; +extern u32 enable_ldo_mode; + + +static int get_voltage(struct anatop_regulator *sreg) +{ + int uv; + struct anatop_regulator_data *rdata = sreg->rdata; + + if (sreg->rdata->control_reg) { + u32 val = (__raw_readl(rdata->control_reg) >> + rdata->vol_bit_shift) & rdata->vol_bit_mask; + uv = rdata->min_voltage + (val - rdata->min_bit_val) * 25000; + pr_debug("vddio = %d, val=%u\n", uv, val); + return uv; + } else { + pr_debug("Regulator not supported.\n"); + return -ENOTSUPP; + } +} + +static int set_voltage(struct anatop_regulator *sreg, int uv) +{ + u32 val, reg; + u32 delay, steps, old_val; + + pr_debug("%s: uv %d, min %d, max %d\n", __func__, + uv, sreg->rdata->min_voltage, sreg->rdata->max_voltage); + + if (uv < sreg->rdata->min_voltage || uv > sreg->rdata->max_voltage) + return -EINVAL; + + if (sreg->rdata->control_reg) { + val = sreg->rdata->min_bit_val + + (uv - sreg->rdata->min_voltage) / 25000; + + reg = (__raw_readl(sreg->rdata->control_reg) & + ~(sreg->rdata->vol_bit_mask << + sreg->rdata->vol_bit_shift)); + pr_debug("%s: calculated val %d\n", __func__, val); + + old_val = (__raw_readl(sreg->rdata->control_reg) >> + sreg->rdata->vol_bit_shift) & sreg->rdata->vol_bit_mask; + + __raw_writel((val << sreg->rdata->vol_bit_shift) | reg, + sreg->rdata->control_reg); + + if (sreg->rdata->control_reg == (unsigned int)(MXC_PLL_BASE + + HW_ANADIG_REG_CORE)) { + /* calculate how many steps to ramp up */ + steps = (val > old_val) ? val - old_val : 0; + if (steps) { + switch (sreg->rdata->vol_bit_shift) { + case BP_ANADIG_REG_CORE_REG0_TRG: + reg = (__raw_readl(MXC_PLL_BASE + + HW_ANADIG_ANA_MISC2) & + BM_ANADIG_ANA_MISC2_REG0_STEP_TIME) >> + BP_ANADIG_ANA_MISC2_REG0_STEP_TIME; + break; + case BP_ANADIG_REG_CORE_REG1_TRG: + reg = (__raw_readl(MXC_PLL_BASE + + HW_ANADIG_ANA_MISC2) & + BM_ANADIG_ANA_MISC2_REG1_STEP_TIME) >> + BP_ANADIG_ANA_MISC2_REG1_STEP_TIME; + break; + case BP_ANADIG_REG_CORE_REG2_TRG: + reg = (__raw_readl(MXC_PLL_BASE + + HW_ANADIG_ANA_MISC2) & + BM_ANADIG_ANA_MISC2_REG2_STEP_TIME) >> + BP_ANADIG_ANA_MISC2_REG2_STEP_TIME; + break; + default: + break; + } + + /* + * the delay time for LDO ramp up time is + * based on the register setting, we need + * to calculate how many steps LDO need to + * ramp up, and how much delay needs. (us) + */ + delay = steps * ((LDO_RAMP_UP_UNIT_IN_CYCLES << + reg) / LDO_RAMP_UP_FREQ_IN_MHZ + 1); + udelay(delay); + pr_debug("%s: %s: delay %d, steps %d, uv %d\n", + __func__, sreg->rdata->name, delay, + steps, uv); + } + } + + return 0; + } else { + pr_debug("Regulator not supported.\n"); + return -ENOTSUPP; + } +} + +static int pu_enable(struct anatop_regulator *sreg) +{ + unsigned int reg, vddsoc; + int ret = 0; + /*get PU related clk to finish PU regulator power up*/ + if (!get_clk) { + if (!cpu_is_mx6sl()) { + gpu3d_clk = clk_get(NULL, "gpu3d_clk"); + if (IS_ERR(gpu3d_clk)) + printk(KERN_ERR "%s: failed to get gpu3d_clk!\n" + , __func__); + gpu3d_shade_clk = clk_get(NULL, "gpu3d_shader_clk"); + if (IS_ERR(gpu3d_shade_clk)) + printk(KERN_ERR "%s: failed to get shade_clk!\n" + , __func__); + if (IS_ERR(vpu_clk)) + printk(KERN_ERR "%s: failed to get vpu_clk!\n", + __func__); + } + gpu2d_clk = clk_get(NULL, "gpu2d_clk"); + if (IS_ERR(gpu2d_clk)) + printk(KERN_ERR "%s: failed to get gpu2d_clk!\n", + __func__); + gpu2d_axi_clk = clk_get(NULL, "gpu2d_axi_clk"); + if (IS_ERR(gpu2d_axi_clk)) + printk(KERN_ERR "%s: failed to get gpu2d_axi_clk!\n", + __func__); + openvg_axi_clk = clk_get(NULL, "openvg_axi_clk"); + if (IS_ERR(openvg_axi_clk)) + printk(KERN_ERR "%s: failed to get openvg_axi_clk!\n", + __func__); + get_clk = 1; + + } + if (external_pureg) { + /*enable extern PU regulator*/ + ret = regulator_enable(pu_regulator); + if (ret < 0) + printk(KERN_ERR "%s: enable pu error!\n", __func__); + } else { + /*Track the voltage of VDDPU with VDDSOC if use internal PU + *regulator. + */ + reg = __raw_readl(ANADIG_REG_CORE); + vddsoc = reg & (ANADIG_REG_TARGET_MASK << + ANADIG_REG2_SOC_TARGET_OFFSET); + reg &= ~(ANADIG_REG_TARGET_MASK << + ANADIG_REG1_PU_TARGET_OFFSET); + reg |= vddsoc >> (ANADIG_REG2_SOC_TARGET_OFFSET + -ANADIG_REG1_PU_TARGET_OFFSET); + __raw_writel(reg, ANADIG_REG_CORE); + } + + /* Need to wait for the regulator to come back up */ + /* + * Delay time is based on the number of 24MHz clock cycles + * programmed in the ANA_MISC2_BASE_ADDR for each + * 25mV step. + */ + udelay(150); + /*enable gpu clock to powerup GPU right.*/ + if (get_clk) { + if (!cpu_is_mx6sl()) { + clk_enable(gpu3d_clk); + clk_enable(gpu3d_shade_clk); + clk_enable(vpu_clk); + } + clk_enable(gpu2d_clk); + clk_enable(gpu2d_axi_clk); + clk_enable(openvg_axi_clk); + } + /* enable power up request */ + reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + /* power up request */ + reg = __raw_readl(gpc_base + GPC_CNTR_OFFSET); + __raw_writel(reg | 0x2, gpc_base + GPC_CNTR_OFFSET); + /* Wait for the power up bit to clear */ + while (__raw_readl(gpc_base + GPC_CNTR_OFFSET) & 0x2) + ; + /* Enable the Brown Out detection. */ + reg = __raw_readl(ANA_MISC2_BASE_ADDR); + reg |= ANADIG_ANA_MISC2_REG1_BO_EN; + __raw_writel(reg, ANA_MISC2_BASE_ADDR); + if (enable_ldo_mode != LDO_MODE_BYPASSED) { + /* Unmask the ANATOP brown out interrupt in the GPC. */ + reg = __raw_readl(gpc_base + 0x14); + reg &= ~0x80000000; + __raw_writel(reg, gpc_base + 0x14); + } + pu_is_enabled = 1; + if (get_clk) { + if (!cpu_is_mx6sl()) { + clk_disable(gpu3d_clk); + clk_disable(gpu3d_shade_clk); + clk_disable(vpu_clk); + } + clk_disable(gpu2d_clk); + clk_disable(gpu2d_axi_clk); + clk_disable(openvg_axi_clk); + } + return 0; +} + +int pu_disable(struct anatop_regulator *sreg) +{ + unsigned int reg; + int ret = 0; + + /* Disable the brown out detection since we are going to be + * disabling the LDO. + */ + reg = __raw_readl(ANA_MISC2_BASE_ADDR); + reg &= ~ANADIG_ANA_MISC2_REG1_BO_EN; + __raw_writel(reg, ANA_MISC2_BASE_ADDR); + + /* Power gate the PU LDO. */ + /* Power gate the PU domain first. */ + /* enable power down request */ + reg = __raw_readl(gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + __raw_writel(reg | 0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET); + /* power down request */ + reg = __raw_readl(gpc_base + GPC_CNTR_OFFSET); + __raw_writel(reg | 0x1, gpc_base + GPC_CNTR_OFFSET); + /* Wait for power down to complete. */ + while (__raw_readl(gpc_base + GPC_CNTR_OFFSET) & 0x1) + ; + if (enable_ldo_mode != LDO_MODE_BYPASSED) { + /* Mask the ANATOP brown out interrupt in the GPC. */ + reg = __raw_readl(gpc_base + 0x14); + reg |= 0x80000000; + __raw_writel(reg, gpc_base + 0x14); + } + + if (external_pureg) { + /*disable extern PU regulator*/ + ret = regulator_disable(pu_regulator); + if (ret < 0) + printk(KERN_ERR "%s: disable pu error!\n", __func__); + } else { + /* PU power gating. */ + reg = __raw_readl(ANADIG_REG_CORE); + reg &= ~(ANADIG_REG_TARGET_MASK << + ANADIG_REG1_PU_TARGET_OFFSET); + __raw_writel(reg, ANADIG_REG_CORE); + } + pu_is_enabled = 0; + /* Clear the BO interrupt in the ANATOP. */ + reg = __raw_readl(ANADIG_MISC1_REG); + reg |= 0x80000000; + __raw_writel(reg, ANADIG_MISC1_REG); + return 0; +} +EXPORT_SYMBOL(pu_disable); +static int is_pu_enabled(struct anatop_regulator *sreg) +{ + return pu_is_enabled; +} +static int enable(struct anatop_regulator *sreg) +{ + return 0; +} + +static int disable(struct anatop_regulator *sreg) +{ + return 0; +} + +static int is_enabled(struct anatop_regulator *sreg) +{ + return 1; +} +static int vdd3p0_enable(struct anatop_regulator *sreg) +{ + __raw_writel(BM_ANADIG_REG_3P0_ENABLE_LINREG, + sreg->rdata->control_reg+4); + return 0; +} + +static int vdd3p0_disable(struct anatop_regulator *sreg) +{ + __raw_writel(BM_ANADIG_REG_3P0_ENABLE_LINREG, + sreg->rdata->control_reg+8); + return 0; +} + +static int vdd3p0_is_enabled(struct anatop_regulator *sreg) +{ + return !!(__raw_readl(sreg->rdata->control_reg) & BM_ANADIG_REG_3P0_ENABLE_LINREG); +} + +static struct anatop_regulator_data vddpu_data = { + .name = "vddpu", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = pu_enable, + .disable = pu_disable, + .is_enabled = is_pu_enabled, + .control_reg = (u32)(MXC_PLL_BASE + HW_ANADIG_REG_CORE), + .vol_bit_shift = 9, + .vol_bit_mask = 0x1F, + .min_bit_val = 1, + .min_voltage = 725000, + .max_voltage = 1300000, +}; + +static struct anatop_regulator_data vddcore_data = { + .name = "vddcore", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .control_reg = (u32)(MXC_PLL_BASE + HW_ANADIG_REG_CORE), + .vol_bit_shift = 0, + .vol_bit_mask = 0x1F, + .min_bit_val = 1, + .min_voltage = 725000, + .max_voltage = 1300000, +}; + +static struct anatop_regulator_data vddsoc_data = { + .name = "vddsoc", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .control_reg = (u32)(MXC_PLL_BASE + HW_ANADIG_REG_CORE), + .vol_bit_shift = 18, + .vol_bit_mask = 0x1F, + .min_bit_val = 1, + .min_voltage = 725000, + .max_voltage = 1300000, +}; + +static struct anatop_regulator_data vdd2p5_data = { + .name = "vdd2p5", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .control_reg = (u32)(MXC_PLL_BASE + HW_ANADIG_REG_2P5), + .vol_bit_shift = 8, + .vol_bit_mask = 0x1F, + .min_bit_val = 0, + .min_voltage = 2000000, + .max_voltage = 2775000, +}; + +static struct anatop_regulator_data vdd1p1_data = { + .name = "vdd1p1", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = enable, + .disable = disable, + .is_enabled = is_enabled, + .control_reg = (u32)(MXC_PLL_BASE + HW_ANADIG_REG_1P1), + .vol_bit_shift = 8, + .vol_bit_mask = 0x1F, + .min_bit_val = 4, + .min_voltage = 800000, + .max_voltage = 1400000, +}; + +static struct anatop_regulator_data vdd3p0_data = { + .name = "vdd3p0", + .set_voltage = set_voltage, + .get_voltage = get_voltage, + .enable = vdd3p0_enable, + .disable = vdd3p0_disable, + .is_enabled = vdd3p0_is_enabled, + .control_reg = (u32)(MXC_PLL_BASE + HW_ANADIG_REG_3P0), + .vol_bit_shift = 8, + .vol_bit_mask = 0x1F, + .min_bit_val = 0, + .min_voltage = 2625000, + .max_voltage = 3400000, +}; + +/* CPU */ +static struct regulator_consumer_supply vddcore_consumers[] = { + { + .supply = "cpu_vddgp", + } +}; +/* PU */ +static struct regulator_consumer_supply vddpu_consumers[] = { + { + .supply = "cpu_vddvpu", + }, + { + .supply = "cpu_vddgpu", + } +}; +/* SOC */ +static struct regulator_consumer_supply vddsoc_consumers[] = { + { + .supply = "cpu_vddsoc", + }, +}; + +/* USB phy 3P0 */ +static struct regulator_consumer_supply vdd3p0_consumers[] = { + { + .supply = "cpu_vdd3p0", + }, +}; + +static struct regulator_init_data vddpu_init = { + .constraints = { + .name = "vddpu", + .min_uV = 725000, + .max_uV = 1300000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS | + REGULATOR_CHANGE_MODE, + }, + .num_consumer_supplies = ARRAY_SIZE(vddpu_consumers), + .consumer_supplies = vddpu_consumers, +}; + +static struct regulator_init_data vddcore_init = { + .constraints = { + .name = "vddcore", + .min_uV = 725000, + .max_uV = 1300000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vddcore_consumers), + .consumer_supplies = &vddcore_consumers[0], +}; + +static struct regulator_init_data vddsoc_init = { + .constraints = { + .name = "vddsoc", + .min_uV = 725000, + .max_uV = 1300000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vddsoc_consumers), + .consumer_supplies = &vddsoc_consumers[0], +}; + +static struct regulator_init_data vdd2p5_init = { + .constraints = { + .name = "vdd2p5", + .min_uV = 2000000, + .max_uV = 2775000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .always_on = 1, + }, + .num_consumer_supplies = 0, + .consumer_supplies = NULL, +}; + + +static struct regulator_init_data vdd1p1_init = { + .constraints = { + .name = "vdd1p1", + .min_uV = 800000, + .max_uV = 1400000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .input_uV = 5000000, + .always_on = 1, + }, + .num_consumer_supplies = 0, + .consumer_supplies = NULL, +}; + + +static struct regulator_init_data vdd3p0_init = { + .constraints = { + .name = "vdd3p0", + .min_uV = 2625000, + .max_uV = 3400000, + .valid_modes_mask = REGULATOR_MODE_FAST | + REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | + REGULATOR_CHANGE_STATUS, + .always_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vdd3p0_consumers), + .consumer_supplies = &vdd3p0_consumers[0], +}; + +static struct anatop_regulator vddpu_reg = { + .rdata = &vddpu_data, +}; + +static struct anatop_regulator vddcore_reg = { + .rdata = &vddcore_data, +}; + +static struct anatop_regulator vddsoc_reg = { + .rdata = &vddsoc_data, +}; + +static struct anatop_regulator vdd2p5_reg = { + .rdata = &vdd2p5_data, +}; + +static struct anatop_regulator vdd1p1_reg = { + .rdata = &vdd1p1_data, +}; + +static struct anatop_regulator vdd3p0_reg = { + .rdata = &vdd3p0_data, +}; + +static int __init regulators_init(void) +{ + unsigned int reg; + + anatop_register_regulator(&vddpu_reg, ANATOP_VDDPU, &vddpu_init); + anatop_register_regulator(&vddcore_reg, ANATOP_VDDCORE, &vddcore_init); + anatop_register_regulator(&vddsoc_reg, ANATOP_VDDSOC, &vddsoc_init); + anatop_register_regulator(&vdd2p5_reg, ANATOP_VDD2P5, &vdd2p5_init); + anatop_register_regulator(&vdd1p1_reg, ANATOP_VDD1P1, &vdd1p1_init); + anatop_register_regulator(&vdd3p0_reg, ANATOP_VDD3P0, &vdd3p0_init); + + /* Set the REGx step time back to reset value, + * as ROM may modify it according to fuse setting, + * so we need to set it back, otherwise, the delay + * time in cpu freq change will be impacted, the reset + * value is 0'b00, 64 cycles of 24M clock. + */ + reg = __raw_readl(ANADIG_MISC2_REG); + reg &= ~ANADIG_ANA_MISC2_REG0_STEP_TIME_MASK; + reg &= ~ANADIG_ANA_MISC2_REG1_STEP_TIME_MASK; + reg &= ~ANADIG_ANA_MISC2_REG2_STEP_TIME_MASK; + __raw_writel(reg, ANADIG_MISC2_REG); + + /* clear flag in boot */ + pu_is_enabled = 0; + get_clk = 0; + pu_disable(NULL); + return 0; +} +postcore_initcall(regulators_init); diff --git a/arch/arm/mach-mx6/mx6_ddr_freq.S b/arch/arm/mach-mx6/mx6_ddr_freq.S new file mode 100644 index 00000000..de20f0c3 --- /dev/null +++ b/arch/arm/mach-mx6/mx6_ddr_freq.S @@ -0,0 +1,1010 @@ +/* + * Copyright (C) 2011-2013 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> +#include <mach/hardware.h> + + .macro switch_to_528MHz + + /* DDR freq change to 528MHz */ + + /* check if periph_clk_sel is already set */ + ldr r0, [r6, #0x14] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + beq set_ahb_podf_before_switch + + /* Step 1: Change periph_clk to be sourced from pll3_clk. */ + /* Ensure PLL3 is the source and set the divider to 1. */ + ldr r0, [r6, #0x18] + bic r0, r0, #0x3000 + str r0, [r6, #0x18] + + ldr r0, [r6, #0x14] + bic r0, r0, #0x38000000 + str r0, [r6, #0x14] + + /* Set the AHB dividers before the switch. */ + /* Don't change AXI clock divider. */ + /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4 (need to maintain GPT divider). */ + ldr r0, [r6, #0x14] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0xd00 + orr r0, r0, #0x10000 + str r0, [r6, #0x14] + +wait_div_update528: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne wait_div_update528 + + /* Now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #0x14] + orr r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch3: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch3 + + b switch_pre_periph_clk_528 + +set_ahb_podf_before_switch: + /* Set the AHB dividers before the switch. */ + /* Especially if the AHB is at 24MHz, divider + * would be at divide by 1 and clock + * would be too fast when switching to PLL3. + */ + /* Don't change AXI clock divider. */ + /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4 (need to maintain GPT divider). */ + ldr r0, [r6, #0x14] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0xd00 + orr r0, r0, #0x10000 + str r0, [r6, #0x14] + +wait_div_update528_1: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne wait_div_update528_1 + +switch_pre_periph_clk_528: + + /* Now switch pre_periph_clk to PLL2_528MHz. */ + ldr r0, [r6, #0x18] + bic r0, r0, #0xC0000 + str r0, [r6, #0x18] + + /* Now switch periph_clk back. */ + ldr r0, [r6, #0x14] + bic r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch4: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch4 + + ldr r0, =ANATOP_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + ldr r1, [r0, #0x260] + mov r2, r1 + /*Is mx6q?*/ + and r1, r1, #0xff0000 + cmp r1, #0x630000 + bne skip_gpt_workaround1 + /*Is mx6q TO1.0?*/ + and r2, r2, #0xff + cmp r2, #0x0 + bne skip_gpt_workaround1 + /* Change the GPT divider so that its at 6MHz. */ + ldr r0, [r6, #0x1C] + bic r0, r0, #0x3F + orr r0, r0, #0xA + str r0, [r6, #0x1C] +skip_gpt_workaround1: + .endm + + .macro switch_to_400MHz + + /* check if periph_clk_sel is already set */ + ldr r0, [r6, #0x14] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + beq set_ahb_podf_before_switch1 + + /* Step 1: Change periph_clk to be sourced from pll3_clk. */ + /* Ensure PLL3 is the source and set the divider to 1. */ + ldr r0, [r6, #0x18] + bic r0, r0, #0x3000 + str r0, [r6, #0x18] + + ldr r0, [r6, #0x14] + bic r0, r0, #0x38000000 + str r0, [r6, #0x14] + + /* Now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #0x14] + orr r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch5: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch5 + + b switch_pre_periph_clk_400 + +set_ahb_podf_before_switch1: + /* Set the AHB dividers before the switch. */ + /* Especially if the AHB is at 24MHz, divider + * would be at divide by 1 and clock + * would be too fast when switching to PLL3. + */ + /* Don't change AXI clock divider. */ + /* Set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4 (need to maintain GPT divider). */ + ldr r0, [r6, #0x14] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0x900 + orr r0, r0, #0x10000 + str r0, [r6, #0x14] + +wait_div_update400_1: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne wait_div_update400_1 + +switch_pre_periph_clk_400: + + /* Now switch pre_periph_clk to PFD_400MHz. */ + ldr r0, [r6, #0x18] + bic r0, r0, #0xC0000 + orr r0, r0, #0x40000 + str r0, [r6, #0x18] + + /* Now switch periph_clk back. */ + ldr r0, [r6, #0x14] + bic r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch6: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch6 + + /* Change AHB divider so that we are at 400/3=133MHz. */ + /* Don't change AXI clock divider. */ + /* Set the MMDC_DIV=1, AXI_DIV=2, AHB_DIV=3 (need to maintain GPT divider). */ + ldr r0, [r6, #0x14] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0x900 + orr r0, r0, #0x10000 + str r0, [r6, #0x14] + +wait_div_update400_2: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne wait_div_update400_2 + + ldr r0, =ANATOP_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + ldr r1, [r0, #0x260] + mov r2, r1 + /*Is mx6q?*/ + and r1, r1, #0xff0000 + cmp r1, #0x630000 + bne skip_gpt_workaround2 + /*Is mx6q TO1.0?*/ + and r2, r2, #0xff + cmp r2, #0x0 + bne skip_gpt_workaround2 + /* Change the GPT divider so that its at 6MHz. */ + ldr r0, [r6, #0x1C] + bic r0, r0, #0x3F + orr r0, r0, #0xA + str r0, [r6, #0x1C] +skip_gpt_workaround2: + .endm + + .macro switch_to_50MHz + + /* Set DDR to 50MHz. */ + /* check if periph_clk_sel is already set */ + ldr r0, [r6, #0x14] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + beq switch_pre_periph_clk_50 + + /* Set the periph_clk to be sourced from PLL2_PFD_200M */ + /* Step 1: Change periph_clk to be sourced from pll3_clk. */ + /* Ensure PLL3 is the source and set the divider to 1. */ + ldr r0, [r6, #0x18] + bic r0, r0, #0x3000 + str r0, [r6, #0x18] + + ldr r0, [r6, #0x14] + bic r0, r0, #0x38000000 + str r0, [r6, #0x14] + + /* Now switch periph_clk to pll3_main_clk. */ + ldr r0, [r6, #0x14] + orr r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch_50: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch_50 + +switch_pre_periph_clk_50: + + /* Now switch pre_periph_clk to PFD_200MHz. */ + ldr r0, [r6, #0x18] + orr r0, r0, #0xC0000 + str r0, [r6, #0x18] + + /* Set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8 (need to maintain GPT divider). */ + ldr r0, [r6, #0x14] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + + orr r0, r0, #0x180000 + orr r0, r0, #0x30000 + + /* If changing AHB divider remember to change the IPGPER divider too below. */ + orr r0, r0, #0x1d00 + str r0, [r6, #0x14] + +wait_div_update_50: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne wait_div_update_50 + + /* Now switch periph_clk back. */ + ldr r0, [r6, #0x14] + bic r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch2: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch2 + + ldr r0, =ANATOP_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + ldr r1, [r0, #0x260] + mov r2, r1 + /*Is mx6q?*/ + and r1, r1, #0xff0000 + cmp r1, #0x630000 + bne skip_gpt_workaround3 + /*Is mx6q TO1.0?*/ + and r2, r2, #0xff + cmp r2, #0x0 + bne skip_gpt_workaround3 + /* Change the GPT divider so that its at 6MHz. */ + ldr r0, [r6, #0x1C] + bic r0, r0, #0x3F + orr r0, r0, #0x1 + str r0, [r6, #0x1C] +skip_gpt_workaround3: + + .endm + + .macro switch_to_24MHz + /* Change the freq now */ + /* Try setting DDR to 24MHz. */ + /* Source it from the periph_clk2 */ + /* Ensure the periph_clk2 is sourced from 24MHz + and the divider is 1. */ + ldr r0, [r6, #0x18] + bic r0, r0, #0x3000 + orr r0, r0, #0x1000 + str r0, [r6, #0x18] + + ldr r0, [r6, #0x14] + bic r0, r0, #0x38000000 + str r0, [r6, #0x14] + + /* Now switch periph_clk to 24MHz. */ + ldr r0, [r6, #0x14] + orr r0, r0, #0x2000000 + str r0, [r6, #0x14] + +periph_clk_switch1: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne periph_clk_switch1 + + /* Change all the dividers to 1. */ + ldr r0, [r6, #0x14] + ldr r2, =0x3f1f00 + bic r0, r0, r2 + orr r0, r0, #0x100 + str r0, [r6, #0x14] + + /* Wait for the divider to change. */ +wait_div_update: + ldr r0, [r6, #0x48] + cmp r0, #0 + bne wait_div_update + + ldr r0, =ANATOP_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + ldr r1, [r0, #0x260] + mov r2, r1 + /*Is mx6q?*/ + and r1, r1, #0xff0000 + cmp r1, #0x630000 + bne skip_gpt_workaround4 + /*Is mx6q TO1.0?*/ + and r2, r2, #0xff + cmp r2, #0x0 + bne skip_gpt_workaround4 + /* Change the GPT divider so that its at 6MHz. */ + ldr r0, [r6, #0x1C] + bic r0, r0, #0x3F + orr r0, r0, #0x1 + str r0, [r6, #0x1C] +skip_gpt_workaround4: + + .endm + +/* + * mx6_ddr_freq_change + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx6_ddr_freq_change) + + stmfd sp!, {r4,r5,r6, r7, r8, r9, r10, r11} @ Save registers + + ldr r6, =CCM_BASE_ADDR + add r6, r6, #PERIPBASE_VIRT + ldr r5, =MMDC_P0_BASE_ADDR + add r5, r5, #PERIPBASE_VIRT + ldr r7, =MX6Q_IOMUXC_BASE_ADDR + add r7, r7, #PERIPBASE_VIRT + + mov r4, r0 @save new freq requested + mov r8, r1 @save the ddr settings for the new rate + mov r9, r2 @save the mode DDR is currently in (DLL ON/OFF) + mov r11, r3 @save iomux offsets + +ddr_freq_change: + /* 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 r10, ddr_freq_change @Address in this function. + + ldr r2, [r6] @ TLB will miss, + @CCM address will be loaded + ldr r2, [r5] @ TLB will miss, + @MMDC address will be loaded + ldr r2, [r7] @ TLB will miss, + @IOMUX will be loaded + + ldr r2, [r8] @ Get the DDR settings. + ldr r2, [r10] @ TLB will miss + ldr r2, [r11] @Get the IOMUX settings + + /* Make sure all the L1 & L2 buffers are drained, as + * we don't want any writes to the DDR when it is + * in self-refresh. + */ + /* Make sure the L1 buffers are drained. */ + dsb + +#ifdef CONFIG_CACHE_L2X0 + /* Make sure the L2 buffers are drained. + * Sync operation on L2 drains the buffers. + */ + ldr r0, =L2_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + mov r1, #0x0 + str r1, [r0, #0x730] +#endif + + /* The second dsb might be needed to keep cache sync (device write) + * ordering with the memory accesses before it. + */ + dsb + isb + + /* Disable automatic power saving. */ + ldr r0, [r5, #0x404] + orr r0, r0, #0x01 + str r0, [r5, #0x404] + + /* Disable MMDC power down timer. */ + /*MMDC0_MDPDC disable power down timer */ + ldr r0, [r5, #0x4] + bic r0, r0, #0xff00 + str r0, [r5, #0x4] + +/* Delay for a while */ + ldr r1, =4 +delay1: + ldr r2, =0 +cont1: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont1 + sub r1, r1, #1 + cmp r1, #0 + bgt delay1 + + /* set CON_REG */ + ldr r0, =0x8000 + str r0, [r5, #0x1C] +poll_conreq_set_1: + ldr r0, [r5, #0x1C] + and r0, r0, #0x4000 + cmp r0, #0x4000 + bne poll_conreq_set_1 + + /*setmem /32 0x021b001c = 0x00008010 //Precharge all on cs0 */ + /*setmem /32 0x021b001c = 0x00008018 //Precharge all on cs1 */ + ldr r0, =0x00008010 + str r0, [r5, #0x1C] + ldr r0, =0x00008018 + str r0, [r5, #0x1C] + + /* if requested frequency is greater than 300MHz go to DLL on mode */ + ldr r1, =300000000 + cmp r4, r1 + bge dll_on_mode + +dll_off_mode: + + /* if DLL is currently on, turn it off + cmp r9, #1 + beq continue_dll_off_1 + + /* setmem /32 0x021b001c = 0x00018031 //Rtt_NOM off + set dll off, cs 0 */ + /* setmem /32 0x021b001c = 0x00018039 //Rtt_NOM off + set dll off, cs 1 */ + ldr r0, =0x00018031 + str r0, [r5, #0x1C] + + ldr r0, =0x00018039 + str r0, [r5, #0x1C] + + ldr r1, =10 +delay1a: + ldr r2, =0 +cont1a: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont1a + sub r1, r1, #1 + cmp r1, #0 + bgt delay1a + +continue_dll_off_1: + + /* set DVFS - enter self refresh mode */ + ldr r0, [r5, #0x404] + orr r0, r0, #0x200000 + str r0, [r5, #0x404] + + /* de-assert con_req */ + mov r0, #0x0 + str r0, [r5, #0x1C] + +poll_dvfs_set_1: + ldr r0, [r5, #0x404] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + bne poll_dvfs_set_1 + + ldr r1, =24000000 + cmp r4, r1 + beq switch_freq_24 + + switch_to_50MHz + b continue_dll_off_2 + +switch_freq_24: + switch_to_24MHz + +continue_dll_off_2: + + /* set SBS - block ddr accesses */ + ldr r0, [r5, #0x410] + orr r0, r0, #0x100 + str r0, [r5, #0x410] + + /* clear DVFS - exit from self refresh mode */ + ldr r0, [r5, #0x404] + bic r0, r0, #0x200000 + str r0, [r5, #0x404] + +poll_dvfs_clear_1: + ldr r0, [r5, #0x404] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + beq poll_dvfs_clear_1 + + /* if DLL was previously on, continue DLL off routine + cmp r9, #1 + beq continue_dll_off_3 + + /* setmem /32 0x021b001c = 0x00018031 //Rtt_NOM off + set dll off, cs 0 */ + /* setmem /32 0x021b001c = 0x00018039 //Rtt_NOM off + set dll off, cs 1 */ + ldr r0, =0x00018031 + str r0, [r5, #0x1C] + + ldr r0, =0x00018039 + str r0, [r5, #0x1C] + + /* setmem /32 0x021b001c = 0x04208030 //write mode reg MR0: CL=6, wr=6 ,cs 0 */ + /* setmem /32 0x021b001c = 0x04208038 //write mode reg MR0: CL=6, wr=6 ,cs 1 */ + ldr r0, =0x08208030 + str r0, [r5, #0x1C] + + ldr r0, =0x08208038 + str r0, [r5, #0x1C] + + /* setmem /32 0x021b001c = 0x02088032 //write mode reg MR2 , CWL=6 ,cs0 */ + /* setmem /32 0x021b001c = 0x0208803A //write mode reg MR2 , CWL=6 ,cs1 */ + ldr r0, =0x00088032 + str r0, [r5, #0x1C] + + ldr r0, =0x0008803A + str r0, [r5, #0x1C] + + /* double refresh ???? + ldr r0, =0x00001800 + str r0, [r5, #0x20]*/ + + /* delay for a while. */ + ldr r1, =4 +delay_1: + ldr r2, =0 +cont_1: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont_1 + sub r1, r1, #1 + cmp r1, #0 + bgt delay_1 + + /* MMDC0_MDCFG0 see spread sheet for timings, CAS=6 */ + ldr r0, [r5, #0x0C] + bic r0, r0, #0xf + orr r0, r0, #0x3 + str r0, [r5, #0x0C] + + /* MMDC0_MDCFG1 see spread sheet for timings, tCWL=6 */ + ldr r0, [r5, #0x10] + bic r0, r0, #0x7 + orr r0, r0, #0x4 + str r0, [r5, #0x10] + + /* Enable bank interleaving, Address mirror on, WALAT = 0x1, RALAT = 0x2, DDR2_EN = 0 */ + /*setmem /32 0x021b0018 = 0x00091680 */ + ldr r0, =0x00091680 + str r0, [r5, #0x18] + + /* enable dqs pull down in the IOMUX. */ + /* + setmem /32 0x020e05a8 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 - DSE=110 + setmem /32 0x020e05b0 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 - DSE=110 + setmem /32 0x020e0524 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 - DSE=110 + setmem /32 0x020e051c = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 - DSE=110 + setmem /32 0x020e0518 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS4 - DSE=110 + setmem /32 0x020e050c = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS5 - DSE=110 + setmem /32 0x020e05b8 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS6 - DSE=110 + setmem /32 0x020e05c0 = 0x00003030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS7 - DSE=110 + */ + ldr r1, [r11] @size of array + add r11, r11, #8 @skip first eight bytes in array + ldr r2, =0x3028 +update_iomux: + ldr r0, [r11, #0x0] @ offset + ldr r3, [r7, r0] + bic r3, r3, r2 @ Clear the DSE, PUE and PKE bits + orr r3, r3, #0x3000 @ Enable the Pull downs and lower the drive strength. + orr r3, r3, #0x28 + str r3, [r7, r0] + add r11, r11, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_iomux + + /* ODT disabled */ + /* setmem /32 0x021b0818 = 0x0 // DDR_PHY_P0_MPODTCTRL */ + /* setmem /32 0x021b4818 = 0x0 // DDR_PHY_P1_MPODTCTRL */ + ldr r0, =0x0 + ldr r2, =0x818 + str r0, [r5, r2] + ldr r2, =0x4818 + str r0, [r5, r2] + + /* DQS gating disabled */ + /* setmem /32 0x021b083c = 0x233f033f */ + ldr r2, =0x83c + ldr r0, [r5, r2] + orr r0, r0, #0x20000000 + str r0, [r5, r2] + + ldr r2, =0x483c + ldr r0, [r5, r2] + orr r0, r0, #0x20000000 + str r0, [r5, r2] + + /* MMDC0_MAPSR adopt power down enable */ + /* setmem /32 0x021b0404 = 0x00011006 */ + ldr r0, [r5, #0x404] + bic r0, r0, #0x01 + str r0, [r5, #0x404] + + /* frc_msr + mu bypass*/ + ldr r0, =0x00000060 + str r0, [r5, #0x8b8] + ldr r2, =0x48b8 + str r0, [r5, r2] + ldr r0, =0x00000460 + str r0, [r5, #0x8b8] + ldr r2, =0x48b8 + str r0, [r5, r2] + ldr r0, =0x00000c60 + str r0, [r5, #0x8b8] + ldr r2, =0x48b8 + str r0, [r5, r2] + +continue_dll_off_3: + + /* clear SBS - unblock accesses to DDR */ + ldr r0, [r5, #0x410] + bic r0, r0, #0x100 + str r0, [r5, #0x410] + + mov r0, #0x0 + str r0, [r5, #0x1C] +poll_conreq_clear_1: + ldr r0, [r5, #0x1C] + and r0, r0, #0x4000 + cmp r0, #0x4000 + beq poll_conreq_clear_1 + + b done + +dll_on_mode: + /* assert DVFS - enter self refresh mode */ + ldr r0, [r5, #0x404] + orr r0, r0, #0x200000 + str r0, [r5, #0x404] + + /* de-assert CON_REQ */ + mov r0, #0x0 + str r0, [r5, #0x1C] + + /* poll DVFS ack */ +poll_dvfs_set_2: + ldr r0, [r5, #0x404] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + bne poll_dvfs_set_2 + + ldr r1, =528000000 + cmp r4, r1 + beq switch_freq_528 + + switch_to_400MHz + + b continue_dll_on + +switch_freq_528: + switch_to_528MHz + +continue_dll_on: + + /* set SBS step-by-step mode */ + ldr r0, [r5, #0x410] + orr r0, r0, #0x100 + str r0, [r5, #0x410] + + /* clear DVFS - exit self refresh mode */ + ldr r0, [r5, #0x404] + bic r0, r0, #0x200000 + str r0, [r5, #0x404] + +poll_dvfs_clear_2: + ldr r0, [r5, #0x404] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + beq poll_dvfs_clear_2 + + /* if DLL is currently off, turn it back on */ + cmp r9, #0 + beq update_calibration_only + + ldr r0, =0xa5390003 + str r0, [r5, #0x800] + ldr r2, =0x4800 + str r0, [r5, r2] + + /* enable DQS gating */ + ldr r2, =0x83c + ldr r0, [r5, r2] + bic r0, r0, #0x20000000 + str r0, [r5, r2] + + ldr r2, =0x483c + ldr r0, [r5, r2] + bic r0, r0, #0x20000000 + str r0, [r5, r2] + + /* force measure */ + ldr r0, =0x00000800 + str r0, [r5, #0x8b8] + ldr r2, =0x48b8 + str r0, [r5, r2] + + /* delay for while */ + ldr r1, =4 +delay5: + ldr r2, =0 +cont5: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont5 + sub r1, r1, #1 + cmp r1, #0 + bgt delay5 + /* Disable dqs pull down in the IOMUX. */ + /* + setmem /32 0x020e05a8 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 - DSE=110 + setmem /32 0x020e05b0 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 - DSE=110 + setmem /32 0x020e0524 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS2 - DSE=110 + setmem /32 0x020e051c = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS3 - DSE=110 + setmem /32 0x020e0518 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS4 - DSE=110 + setmem /32 0x020e050c = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS5 - DSE=110 + setmem /32 0x020e05b8 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS6 - DSE=110 + setmem /32 0x020e05c0 = 0x00000030 // IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS7 - DSE=110 + */ + ldr r1, [r11] @size of array + add r11, r11, #8 @skip first eight bytes in array +update_iomux1: + ldr r0, [r11, #0x0] @ offset + ldr r3, [r11, #0x4] + str r3, [r7, r0] @Store the original IOMUX value read during boot + add r11, r11, #8 + sub r1, r1, #1 + cmp r1, #0 + bgt update_iomux1 + + /* config ESDCTL timings to 528MHz: + @// setmem /32 0x021b000c = 0x555A7975 @// MMDC0_MDCFG0 see spread sheet for timings + @//setmem /32 0x021b0010 = 0xFF538E64 @// MMDC0_MDCFG1 see spread sheet for timings + @//setmem /32 0x021b0014 = 0x01ff00db @// MMDC0_MDCFG2 - tRRD - 4ck; tWTR - 4ck; tRTP - 4ck; tDLLK - 512ck + @//setmem /32 0x021b0018 = 0x00081740 @// MMDC0_MDMISC, RALAT=0x5 (original value) + */ + ldr r9, [r8] @size of array + add r8, r8, #8 @skip first eight bytes in array + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + /* update MISC register: WALAT, RALAT */ + ldr r0, =0x00081740 + str r0, [r5, #0x18] + + /*configure ddr devices to dll on, odt + @//setmem /32 0x021b001c = 0x00428031 + @//setmem /32 0x021b001c = 0x00428039 + */ + ldr r0, =0x00028031 + str r0, [r5, #0x1C] + + ldr r0, =0x00028039 + str r0, [r5, #0x1C] + + /* delay for while */ + ldr r1, =4 +delay7: + ldr r2, =0 +cont7: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont7 + sub r1, r1, #1 + cmp r1, #0 + bgt delay7 + + /* reset dll + @// setmem /32 0x021b001c = 0x09208030 + @// setmem /32 0x021b001c = 0x09208038 + */ + ldr r0, =0x09208030 + str r0, [r5, #0x1C] + + ldr r0, =0x09208038 + str r0, [r5, #0x1C] + + /* delay for while */ + ldr r1, =100 +delay8: + ldr r2, =0 +cont8: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont8 + sub r1, r1, #1 + cmp r1, #0 + bgt delay8 + + /* tcwl=6: + @//setmem /32 0x021b001c = 0x04088032 + @//setmem /32 0x021b001c = 0x0408803a + */ + /* MR2 - CS0 */ + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + /*MR2 - CS1 */ + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + ldr r0, =0x00428031 + str r0, [r5, #0x1C] + + ldr r0, =0x00428039 + str r0, [r5, #0x1C] + + /* tcl=8 + @// setmem /32 0x021b001c = 0x08408030 + @// setmem /32 0x021b001c = 0x08408038 + */ + /* MR1 - CS0 */ + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + /*MR1 - CS1 */ + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + /* issue a zq command + @// setmem /32 0x021b001c = 0x04000040 + @// setmem /32 0x021b001c = 0x04000048 + */ + ldr r0, =0x04008040 + str r0, [r5, #0x1C] + + ldr r0, =0x04008048 + str r0, [r5, #0x1C] + + /* ESDCTL ODT enable + @//setmem /32 0x021b0818 = 0x00022225 @// DDR_PHY_P0_MPODTCTRL + @//setmem /32 0x021b4818 = 0x00022225 @// DDR_PHY_P1_MPODTCTRL + */ + ldr r0, [r8, #0x0] @ offset + ldr r3, [r8, #0x4] @ value + str r3, [r5, r0] + add r8, r8, #8 + + ldr r2, =0x4818 + str r0, [r5, r2] + + /* delay for while */ + ldr r1, =40 +delay15: + ldr r2, =0 +cont15: + ldr r0, [r5, r2] + add r2, r2, #4 + cmp r2, #16 + bne cont15 + sub r1, r1, #1 + cmp r1, #0 + bgt delay15 + + /* MMDC0_MAPSR adopt power down enable */ + /* setmem /32 0x021b0404 = 0x00011006 */ + ldr r0, [r5, #0x404] + bic r0, r0, #0x01 + str r0, [r5, #0x404] + + /* Enable MMDC power down timer. */ + ldr r0, [r5, #0x4] + orr r0, r0, #0x5500 + str r0, [r5, #0x4] + + b update_calibration + +update_calibration_only: + ldr r1, [r8] @ size of array + sub r1, r1, #7 @ first 7 entries are not related to calibration + add r8, r8, #64 @ Skip the first 7 entries that are needed only when DLL was OFF + count entry. + b update_calib + +update_calibration: + /* Write the new calibration values. */ + mov r1, r9 @ size of array + sub r1, r1, #7 @ first 7 entries are not related to calibration + +update_calib: + 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_calib + + /* Perform a force measurement. */ + ldr r0, =0x800 + str r0, [r5, #0x8B8] + ldr r2, =0x48B8 + str r0, [r5, r2] + + /* clear SBS - unblock DDR accesses */ + ldr r0, [r5, #0x410] + bic r0, r0, #0x100 + str r0, [r5, #0x410] + + mov r0, #0x0 + str r0, [r5, #0x1C] +poll_conreq_clear_2: + ldr r0, [r5, #0x1C] + and r0, r0, #0x4000 + cmp r0, #0x4000 + beq poll_conreq_clear_2 + +done: + + /* Restore registers */ + + ldmfd sp!, {r4,r5,r6, r7, r8, r9, r10, r11} + + mov pc, lr + + .type mx6_do_ddr_freq_change, #object +ENTRY(mx6_do_ddr_freq_change) + .word mx6_ddr_freq_change + .size mx6_ddr_freq_change, . - mx6_ddr_freq_change diff --git a/arch/arm/mach-mx6/mx6_fec.c b/arch/arm/mach-mx6/mx6_fec.c new file mode 100644 index 00000000..935ba264 --- /dev/null +++ b/arch/arm/mach-mx6/mx6_fec.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011-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/fec.h> +#include <linux/etherdevice.h> + +#include <mach/common.h> +#include <mach/hardware.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include "devices-imx6q.h" + +#define HW_OCOTP_MACn(n) (0x00000620 + (n) * 0x10) + +static int fec_get_mac_addr(unsigned char *mac) +{ + unsigned int value; + + value = readl(MX6_IO_ADDRESS(OCOTP_BASE_ADDR) + HW_OCOTP_MACn(0)); + mac[5] = value & 0xff; + mac[4] = (value >> 8) & 0xff; + mac[3] = (value >> 16) & 0xff; + mac[2] = (value >> 24) & 0xff; + value = readl(MX6_IO_ADDRESS(OCOTP_BASE_ADDR) + HW_OCOTP_MACn(1)); + mac[1] = value & 0xff; + mac[0] = (value >> 8) & 0xff; + + return 0; +} + +void __init imx6_init_fec(struct fec_platform_data fec_data) +{ + fec_get_mac_addr(fec_data.mac); + if (!is_valid_ether_addr(fec_data.mac)) + random_ether_addr(fec_data.mac); + + if (cpu_is_mx6sl()) + imx6sl_add_fec(&fec_data); + else + imx6q_add_fec(&fec_data); +} diff --git a/arch/arm/mach-mx6/mx6_mmdc.c b/arch/arm/mach-mx6/mx6_mmdc.c new file mode 100644 index 00000000..eca8d83c --- /dev/null +++ b/arch/arm/mach-mx6/mx6_mmdc.c @@ -0,0 +1,367 @@ +/* + * Copyright (C) 2011-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 + */ + +/*! + * @file mx6_mmdc.c + * + * @brief MX6 MMDC specific file. + * + * @ingroup PM + */ +#include <asm/io.h> +#include <linux/sched.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/iram_alloc.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/cpumask.h> +#include <linux/kernel.h> +#include <linux/smp.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> +#include <asm/hardware/gic.h> +#include "crm_regs.h" + + +/* DDR settings */ +unsigned long (*iram_ddr_settings)[2]; +unsigned long (*normal_mmdc_settings)[2]; +unsigned long (*iram_iomux_settings)[2]; +void __iomem *mmdc_base; +void __iomem *iomux_base; +void __iomem *gic_dist_base; +void __iomem *gic_cpu_base; + +void (*mx6_change_ddr_freq)(u32 freq, void *ddr_settings, bool dll_mode, void* iomux_offsets) = NULL; + +extern unsigned int ddr_low_rate; +extern unsigned int ddr_med_rate; +extern unsigned int ddr_normal_rate; +extern int low_bus_freq_mode; +extern int audio_bus_freq_mode; +extern int mmdc_med_rate; +extern void __iomem *ccm_base; +extern void mx6_ddr_freq_change(u32 freq, void *ddr_settings, bool dll_mode, void *iomux_offsets); + +static void *ddr_freq_change_iram_base; +static int ddr_settings_size; +static int iomux_settings_size; +static volatile unsigned int cpus_in_wfe; +static volatile bool wait_for_ddr_freq_update; +static int curr_ddr_rate; + +#define MIN_DLL_ON_FREQ 333000000 +#define MAX_DLL_OFF_FREQ 125000000 + +unsigned long ddr3_dll_mx6q[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04088032}, + {0x1C, 0x0408803a}, + {0x1C, 0x08408030}, + {0x1C, 0x08408038}, + {0x818, 0x0}, +}; + +unsigned long ddr3_calibration[][2] = { + {0x83c, 0x0}, + {0x840, 0x0}, + {0x483c, 0x0}, + {0x4840, 0x0}, + {0x848, 0x0}, + {0x4848, 0x0}, + {0x850, 0x0}, + {0x4850, 0x0}, +}; + +unsigned long ddr3_dll_mx6dl[][2] = { + {0x0c, 0x0}, + {0x10, 0x0}, + {0x1C, 0x04008032}, + {0x1C, 0x0400803a}, + {0x1C, 0x07208030}, + {0x1C, 0x07208038}, + {0x818, 0x0}, +}; + +unsigned long iomux_offsets_mx6q[][2] = { + {0x5A8, 0x0}, + {0x5B0, 0x0}, + {0x524, 0x0}, + {0x51C, 0x0}, + {0x518, 0x0}, + {0x50C, 0x0}, + {0x5B8, 0x0}, + {0x5C0, 0x0}, +}; + +unsigned long iomux_offsets_mx6dl[][2] = { + {0x4BC, 0x0}, + {0x4C0, 0x0}, + {0x4C4, 0x0}, + {0x4C8, 0x0}, + {0x4CC, 0x0}, + {0x4D0, 0x0}, + {0x4D4, 0x0}, + {0x4D8, 0x0}, +}; + +unsigned long ddr3_400[][2] = { + {0x83c, 0x42490249}, + {0x840, 0x02470247}, + {0x483c, 0x42570257}, + {0x4840, 0x02400240}, + {0x848, 0x4039363C}, + {0x4848, 0x3A39333F}, + {0x850, 0x38414441}, + {0x4850, 0x472D4833} +}; + +unsigned long *irq_used; + +unsigned long irqs_used_mx6q[] = { + MXC_INT_INTERRUPT_139_NUM, + MX6Q_INT_PERFMON1, + MX6Q_INT_PERFMON2, + MX6Q_INT_PERFMON3, +}; + +unsigned long irqs_used_mx6dl[] = { + MXC_INT_INTERRUPT_139_NUM, + MX6Q_INT_PERFMON1, +}; + +int can_change_ddr_freq(void) +{ + return 1; +} + + +/* Each active core apart from the one changing the DDR frequency will execute + * this function. The rest of the cores have to remain in WFE state until the frequency + * is changed. + */ +irqreturn_t wait_in_wfe_irq(int irq, void *dev_id) +{ + u32 me = smp_processor_id(); + + *((char *)(&cpus_in_wfe) + (u8)me) = 0xff; + + while (wait_for_ddr_freq_update) + wfe(); + + *((char *)(&cpus_in_wfe) + (u8)me) = 0; + + return IRQ_HANDLED; +} + +/* Change the DDR frequency. */ +int update_ddr_freq(int ddr_rate) +{ + int i, j; + unsigned int reg; + bool dll_off = false; + unsigned int online_cpus = 0; + int cpu = 0; + int me; + + if (!can_change_ddr_freq()) + return -1; + + if (ddr_rate == curr_ddr_rate) + return 0; + + printk(KERN_DEBUG"%s(%d) %s(%d)\n",__FILE__,__LINE__,__FUNCTION__,ddr_rate); + + if (low_bus_freq_mode || audio_bus_freq_mode) + dll_off = true; + + iram_ddr_settings[0][0] = ddr_settings_size; + iram_iomux_settings[0][0] = iomux_settings_size; + if (ddr_rate == ddr_med_rate && cpu_is_mx6q()) { + for (i = 0; i < ARRAY_SIZE(ddr3_dll_mx6q); i++) { + iram_ddr_settings[i + 1][0] = + normal_mmdc_settings[i][0]; + iram_ddr_settings[i + 1][1] = + normal_mmdc_settings[i][1]; + } + for (j = 0, i = ARRAY_SIZE(ddr3_dll_mx6q); i < iram_ddr_settings[0][0]; j++, i++) { + iram_ddr_settings[i + 1][0] = + ddr3_400[j][0]; + iram_ddr_settings[i + 1][1] = + ddr3_400[j][1]; + } + } else if (ddr_rate == ddr_normal_rate) { + for (i = 0; i < iram_ddr_settings[0][0]; i++) { + iram_ddr_settings[i + 1][0] = + normal_mmdc_settings[i][0]; + iram_ddr_settings[i + 1][1] = + normal_mmdc_settings[i][1]; + } + } + + /* Ensure that all Cores are in WFE. */ + local_irq_disable(); + + me = smp_processor_id(); + + *((char *)(&cpus_in_wfe) + (u8)me) = 0xff; + wait_for_ddr_freq_update = true; + for_each_online_cpu(cpu) { + *((char *)(&online_cpus) + (u8)cpu) = 0xff; + if (cpu != me) { + /* Set the interrupt to be pending in the GIC. */ + reg = 1 << (irq_used[cpu] % 32); + writel_relaxed(reg, gic_dist_base + GIC_DIST_PENDING_SET + (irq_used[cpu] / 32) * 4); + } + } + while (cpus_in_wfe != online_cpus) + udelay(5); + + /* Now we can change the DDR frequency. */ + mx6_change_ddr_freq(ddr_rate, iram_ddr_settings, dll_off, iram_iomux_settings); + + curr_ddr_rate = ddr_rate; + + /* DDR frequency change is done . */ + wait_for_ddr_freq_update = false; + + /* Wake up all the cores. */ + sev(); + + *((char *)(&cpus_in_wfe) + (u8)me) = 0; + + local_irq_enable(); + + return 0; +} + +int init_mmdc_settings(void) +{ + unsigned long iram_paddr; + int i, err, cpu; + + mmdc_base = ioremap(MMDC_P0_BASE_ADDR, SZ_32K); + iomux_base = ioremap(MX6Q_IOMUXC_BASE_ADDR, SZ_16K); + gic_dist_base = ioremap(IC_DISTRIBUTOR_BASE_ADDR, SZ_16K); + gic_cpu_base = ioremap(IC_INTERFACES_BASE_ADDR, SZ_16K); + + if (cpu_is_mx6q()) + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6q) + ARRAY_SIZE(ddr3_calibration); + if (cpu_is_mx6dl()) + ddr_settings_size = ARRAY_SIZE(ddr3_dll_mx6dl) + ARRAY_SIZE(ddr3_calibration); + + normal_mmdc_settings = kmalloc((ddr_settings_size * 8), GFP_KERNEL); + if (cpu_is_mx6q()) { + memcpy(normal_mmdc_settings, ddr3_dll_mx6q, sizeof(ddr3_dll_mx6q)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6q)), ddr3_calibration, sizeof(ddr3_calibration)); + } + if (cpu_is_mx6dl()) { + memcpy(normal_mmdc_settings, ddr3_dll_mx6dl, sizeof(ddr3_dll_mx6dl)); + memcpy(((char *)normal_mmdc_settings + sizeof(ddr3_dll_mx6dl)), ddr3_calibration, sizeof(ddr3_calibration)); + } + + /* Store the original DDR settings at boot. */ + for (i = 0; i < ddr_settings_size; i++) { + /*Writes via command mode register cannot be read back. + * Hence hardcode them in the initial static array. + * This may require modification on a per customer basis. + */ + if (normal_mmdc_settings[i][0] != 0x1C) + normal_mmdc_settings[i][1] = + __raw_readl(mmdc_base + + normal_mmdc_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) + 8, &iram_paddr); + if (iram_ddr_settings == NULL) { + printk(KERN_DEBUG + "%s: failed to allocate iRAM memory for ddr settings\n", + __func__); + return ENOMEM; + } + + iomux_settings_size = ARRAY_SIZE(iomux_offsets_mx6q); + /* Store the size of the iomux settings in iRAM also, + * increase the size by 8 bytes. + */ + iram_iomux_settings = iram_alloc((iomux_settings_size * 8) + 8, &iram_paddr); + if (iram_iomux_settings == NULL) { + printk(KERN_DEBUG + "%s: failed to allocate iRAM memory for iomuxr settings\n", + __func__); + return ENOMEM; + } + + /* Store the IOMUX settings at boot. */ + if (cpu_is_mx6q()) { + for (i = 0; i < iomux_settings_size; i++) { + iomux_offsets_mx6q[i][1] = + __raw_readl(iomux_base + + iomux_offsets_mx6q[i][0]); + iram_iomux_settings[i+1][0] = iomux_offsets_mx6q[i][0]; + iram_iomux_settings[i+1][1] = iomux_offsets_mx6q[i][1]; + } + irq_used = irqs_used_mx6q; + } + + if (cpu_is_mx6dl()) { + for (i = 0; i < iomux_settings_size; i++) { + iomux_offsets_mx6dl[i][1] = + __raw_readl(iomux_base + + iomux_offsets_mx6dl[i][0]); + iram_iomux_settings[i+1][0] = iomux_offsets_mx6dl[i][0]; + iram_iomux_settings[i+1][1] = iomux_offsets_mx6dl[i][1]; + } + irq_used = irqs_used_mx6dl; + } + + /* 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_NONCACHED); + memcpy(ddr_freq_change_iram_base, mx6_ddr_freq_change, SZ_8K); + mx6_change_ddr_freq = (void *)ddr_freq_change_iram_base; + + curr_ddr_rate = ddr_normal_rate; + + for_each_online_cpu(cpu) { + /* Set up a reserved interrupt to get all the active cores into a WFE state + * before changing the DDR frequency. + */ + err = request_irq(irq_used[cpu], wait_in_wfe_irq, IRQF_PERCPU, "mmdc_1", + NULL); + if (err) { + printk(KERN_ERR "MMDC: Unable to attach to %ld,err = %d\n", irq_used[cpu], err); + return err; + } + err = irq_set_affinity(irq_used[cpu], cpumask_of(cpu)); + if (err) { + printk(KERN_ERR "MMDC: unable to set irq affinity irq=%ld,\n", irq_used[cpu]); + return err; + } + } + return 0; +} diff --git a/arch/arm/mach-mx6/mx6_suspend.S b/arch/arm/mach-mx6/mx6_suspend.S new file mode 100644 index 00000000..30388ead --- /dev/null +++ b/arch/arm/mach-mx6/mx6_suspend.S @@ -0,0 +1,1713 @@ +/* + * 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 <linux/linkage.h> +#include <mach/hardware.h> +#include <asm/memory.h> +#include <asm/hardware/cache-l2x0.h> +#include "src-reg.h" + +#define ARM_CTRL_DCACHE (1 << 2) +#define ARM_CTRL_ICACHE (1 << 12) +#define ARM_AUXCR_L2EN (1 << 1) +#define TTRBIT_MASK 0xffffc000 +#define TABLE_INDEX_MASK 0xfff00000 +#define TABLE_ENTRY 0x00000c02 +#define CACHE_DISABLE_MASK 0xfffffffb +#define MMDC_MAPSR_OFFSET 0x404 +#define MMDC_MAPSR_PSS (1 << 4) +#define MMDC_MAPSR_PSD (1 << 0) +/* + * The code size is limited to 5K, as we may need to store + * this code * along with the low power WFI and DDR freq + * change code within 8K of IRAM. + */ +#define IRAM_SUSPEND_SIZE MX6_SUSPEND_CODE_SIZE + +.extern iram_tlb_phys_addr +.extern suspend_iram_base +.extern suspend_iram_phys_addr + +/************************************************************* +mx6_suspend: + +Suspend the processor (eg, wait for interrupt). +Set the DDR into Self Refresh +IRQs are already disabled. + +The following code contain both standby and +dormant mode for MX6, decided by the parameter +passed in r0: +see define in include/linux/suspend.h +1 -> cpu enter stop mode; +3 -> cpu enter dormant mode. +r1: iram_paddr +r2: suspend_iram_base +*************************************************************/ + .macro mx6sl_standy_saving_set + + /* Move periph_clk to OSC_CLK. */ + ldr r1, =CCM_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Ensure the periph_clk2_sel to OSC clk. */ + ldr r0, [r1, #0x18] + bic r0, r0, #0x3000 + orr r0, r0, #0x1000 + str r0, [r1, #0x18] + + ldr r0, [r1, #0x14] + orr r0, r0, #0x2000000 + str r0, [r1, #0x14] + +periph_clk_switch: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne periph_clk_switch + + /* Set the divider to divider by 8 */ + ldr r0, [r1, #0x14] + orr r0, r0, #0x70000 + orr r0, r0, #0x1c00 + str r0, [r1, #0x14] + +ahb_podf: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne ahb_podf + + /* Move DDR clk to PLL3 clock. + */ + /* First set the divider to 2. */ + ldr r0, [r1, #0x14] + orr r0, r0, #0x1 + str r0, [r1, #0x14] + + ldr r0, [r1, #0x18] + bic r0, r0, #0x100000 + str r0, [r1, #0x18] + + ldr r0, [r1, #0x14] + orr r0, r0, #0x4000000 + str r0, [r1, #0x14] + +ddr_switch: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne ddr_switch + + /* Set DDR clock to divide by 8. */ + ldr r0, [r1, #0x14] + orr r0, r0, #0x38 + str r0, [r1, #0x14] + +mmdc_div: + ldr r0, [r1, #0x48] + cmp r0, #0 + bne mmdc_div + + /* Now Switch ARM to run from + * step_clk sourced from OSC. + */ + ldr r0, [r1, #0xc] + bic r0, r1, #0x100 + str r0, [r1, #0x0c] + + /* Now switch PLL1_SW_CLK to step_clk. */ + ldr r0, [r1, #0x0c] + orr r0, r0, #0x4 + str r0, [r1, #0x0c] + + ldr r1, =ANATOP_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Need to clock gate the 528 PFDs before + * powering down PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC/AHB + */ + ldr r0, [r1, #0x100] + orr r0, r0, #0x800000 + str r0, [r1, #0x100] + + /* Now bypass PLL1 and PLL2. */ + ldr r0, =0x10000 + str r0, [r1, #0x4] + str r0, [r1, #0x34] + + /* Now do all the analog savings. */ + + /* Disable 1p1 brown out. */ + ldr r0, [r1, #0x110] + bic r0, r0, #0x2 + str r0, [r1, #0x110] + + /* Enable the weak 2P5 */ + ldr r0, [r1, #0x130] + orr r0, r0, #0x40000 + str r0, [r1, #0x130] + + /*Disable main 2p5. */ + ldr r0, [r1, #0x130] + bic r0, r0, #0x1 + str r0, [r1, #0x130] + + + /* Set the OSC bias current to -37.5% + * to drop the power on VDDHIGH. + */ + ldr r0, [r1, #0x150] + orr r0, r0, #0xC000 + str r0, [r1, #0x150] + .endm + + .macro mx6sl_standby_savings_restore + + /* Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r1, #0x150] + bic r6, r6, #0xC000 + str r6, [r1, #0x150] + + /*Enable main 2p5. */ + ldr r6, [r1, #0x130] + orr r6, r6, #0x1 + str r6, [r1, #0x130] + + /* Ensure the 2P5 is up. */ +loop_2p5: + ldr r6, [r1, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne loop_2p5 + + /* Disable the weak 2P5 */ + ldr r6, [r1, #0x130] + bic r6, r6, #0x40000 + str r6, [r1, #0x130] + + /* Enable 1p1 brown out. */ + ldr r6, [r1, #0x110] + orr r6, r6, #0x2 + str r6, [r1, #0x110] + + /* Unbypass PLLs and + * wait for relock. + */ + ldr r6, =(1 << 16) + str r6, [r1, #0x08] + str r6, [r1, #0x38] + +wait_for_pll_lock: + ldr r6, [r1, #0x0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock + +wait_for_pll2_lock: + ldr r6, [r1, #0x30] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll2_lock + + /* Set PLL1_sw_clk back to PLL1. */ + ldr r6, [r3, #0x0c] + bic r6, r6, #0x4 + str r6, [r3, #0xc] + + /* Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r1, #0x100] + bic r6, r6, #0x800000 + str r6, [r1, #0x100] + + /* Move periph_clk back + * to PLL2_PFD2_400. + */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x2000000 + str r6, [r3, #0x14] + +periph_clk_switch1: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne periph_clk_switch1 + + /* Set the dividers to default value. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x70000 + bic r6, r6, #0x1c00 + orr r6, r6, #0x10800 + str r6, [r3, #0x14] + +ahb_podf1: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne ahb_podf1 + + /* Move MMDC back to PLL2_PFD2_400 */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x4000000 + str r6, [r3, #0x14] + +mmdc_loop2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_loop2 + + /* Set DDR clock to divide by 1. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x38 + str r6, [r3, #0x14] + +mmdc_div1: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_div1 + + .endm + + .macro mx6sl_standby_pg_savings_restore + + /* Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r1, #0x150] + bic r6, r6, #0xC000 + str r6, [r1, #0x150] + + /*Enable main 2p5. */ + ldr r6, [r1, #0x130] + orr r6, r6, #0x1 + str r6, [r1, #0x130] + + /* Ensure the 2P5 is up. */ +loop_2p5_1: + ldr r6, [r1, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne loop_2p5_1 + + /* Disable the weak 2P5 */ + ldr r6, [r1, #0x130] + bic r6, r6, #0x40000 + str r6, [r1, #0x130] + + /* Enable 1p1 brown out. */ + ldr r6, [r1, #0x110] + orr r6, r6, #0x2 + str r6, [r1, #0x110] + + /* Unbypass PLLs and + * wait for relock. + */ + ldr r6, =(1 << 16) + str r6, [r1, #0x08] + str r6, [r1, #0x38] + +wait_for_pll_lock1: + ldr r6, [r1, #0x0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock1 + + /* Set PLL1_sw_clk back to PLL1. */ + ldr r6, [r3, #0x0c] + bic r6, r6, #0x4 + str r6, [r3, #0xc] + + /* Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r1, #0x100] + bic r6, r6, #0x800000 + str r6, [r1, #0x100] + + /* Move DDR clock back to PLL2_PFD2_400 */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x4000000 + str r6, [r3, #0x14] + +mmdc_loop3: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_loop3 + + /* Set DDR clock to divide by 1. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x38 + str r6, [r3, #0x14] + +mmdc_div2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne mmdc_div2 + + /* Move periph_clk back + * to PLL2_PFD2_400. + */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x2000000 + str r6, [r3, #0x14] + +periph_clk_switch2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne periph_clk_switch2 + + /* Set the dividers to default value. */ + ldr r6, [r3, #0x14] + bic r6, r6, #0x70000 + bic r6, r6, #0x1c00 + orr r6, r6, #0x10800 + str r6, [r3, #0x14] + +ahb_podf2: + ldr r6, [r3, #0x48] + cmp r6, #0 + bne ahb_podf2 + + .endm + + .macro sl_ddr_io_save + + ldr r4, [r1, #0x30c] /* DRAM_DQM0 */ + ldr r5, [r1, #0x310] /* DRAM_DQM1 */ + ldr r6, [r1, #0x314] /* DRAM_DQM2 */ + ldr r7, [r1, #0x318] /* DRAM_DQM3 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x5c4] /* GPR_B0DS */ + ldr r5, [r1, #0x5cc] /* GPR_B1DS */ + ldr r6, [r1, #0x5d4] /* GPR_B2DS */ + ldr r7, [r1, #0x5d8] /* GPR_B3DS */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x300] /* DRAM_CAS */ + ldr r5, [r1, #0x31c] /* DRAM_RAS */ + ldr r6, [r1, #0x338] /* DRAM_SDCLK_0 */ + ldr r7, [r1, #0x5ac] /* GPR_ADDS*/ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x5b0] /* DDRMODE_CTL */ + ldr r5, [r1, #0x5c0] /* DDRMODE */ + ldr r6, [r1, #0x33c] /* DRAM_SODT0*/ + ldr r7, [r1, #0x340] /* DRAM_SODT1*/ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x330] /* DRAM_SDCKE0 */ + ldr r5, [r1, #0x334] /* DRAM_SDCKE1 */ + ldr r6, [r1, #0x320] /* DRAM_RESET */ + stmfd r0!, {r4-r6} + + .endm + + .macro sl_ddr_io_restore + + ldmea r0!, {r4-r7} + str r4, [r1, #0x30c] /* DRAM_DQM0 */ + str r5, [r1, #0x310] /* DRAM_DQM1 */ + str r6, [r1, #0x314] /* DRAM_DQM2 */ + str r7, [r1, #0x318] /* DRAM_DQM3 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x5c4] /* GPR_B0DS */ + str r5, [r1, #0x5cc] /* GPR_B1DS */ + str r6, [r1, #0x5d4] /* GPR_B2DS */ + str r7, [r1, #0x5d8] /* GPR_B3DS */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x300] /* DRAM_CAS */ + str r5, [r1, #0x31c] /* DRAM_RAS */ + str r6, [r1, #0x338] /* DRAM_SDCLK_0 */ + str r7, [r1, #0x5ac] /* GPR_ADDS*/ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x5b0] /* DDRMODE_CTL */ + str r5, [r1, #0x5c0] /* DDRMODE */ + str r6, [r1, #0x33c] /* DRAM_SODT0*/ + str r7, [r1, #0x340] /* DRAM_SODT1*/ + + ldmea r0!, {r4-r6} + str r4, [r1, #0x330] /* DRAM_SDCKE0 */ + str r5, [r1, #0x334] /* DRAM_SDCKE1 */ + str r6, [r1, #0x320] /* DRAM_RESET */ + + .endm + + .macro sl_ddr_io_set_lpm + + mov r0, #0 + str r0, [r1, #0x30c] /* DRAM_DQM0 */ + str r0, [r1, #0x310] /* DRAM_DQM1 */ + str r0, [r1, #0x314] /* DRAM_DQM2 */ + str r0, [r1, #0x318] /* DRAM_DQM3 */ + + str r0, [r1, #0x5c4] /* GPR_B0DS */ + str r0, [r1, #0x5cc] /* GPR_B1DS */ + str r0, [r1, #0x5d4] /* GPR_B2DS */ + str r0, [r1, #0x5d8] /* GPR_B3DS */ + + str r0, [r1, #0x300] /* DRAM_CAS */ + str r0, [r1, #0x31c] /* DRAM_RAS */ + str r0, [r1, #0x338] /* DRAM_SDCLK_0 */ + str r0, [r1, #0x5ac] /* GPR_ADDS*/ + + str r0, [r1, #0x5b0] /* DDRMODE_CTL */ + str r0, [r1, #0x5c0] /* DDRMODE */ + str r0, [r1, #0x33c] /* DRAM_SODT0*/ + str r0, [r1, #0x340] /* DRAM_SODT1*/ + + mov r0, #0x80000 + str r0, [r1, #0x320] /* DRAM_RESET */ + mov r0, #0x1000 + str r0, [r1, #0x330] /* DRAM_SDCKE0 */ + str r0, [r1, #0x334] /* DRAM_SDCKE1 */ + + .endm + + .macro dl_ddr_io_save + + ldr r4, [r1, #0x470] /* DRAM_DQM0 */ + ldr r5, [r1, #0x474] /* DRAM_DQM1 */ + ldr r6, [r1, #0x478] /* DRAM_DQM2 */ + ldr r7, [r1, #0x47c] /* DRAM_DQM3 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x480] /* DRAM_DQM4 */ + ldr r5, [r1, #0x484] /* DRAM_DQM5 */ + ldr r6, [r1, #0x488] /* DRAM_DQM6 */ + ldr r7, [r1, #0x48c] /* DRAM_DQM7 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x464] /* DRAM_CAS */ + ldr r5, [r1, #0x490] /* DRAM_RAS */ + ldr r6, [r1, #0x4ac] /* DRAM_SDCLK_0 */ + ldr r7, [r1, #0x4b0] /* DRAM_SDCLK_1 */ + stmfd r0!, {r4-r7} + + ldr r5, [r1, #0x750] /* DDRMODE_CTL */ + ldr r6, [r1, #0x760] /* DDRMODE */ + stmfd r0!, {r5-r6} + + ldr r4, [r1, #0x4bc] /* DRAM_SDQS0 */ + ldr r5, [r1, #0x4c0] /* DRAM_SDQS1 */ + ldr r6, [r1, #0x4c4] /* DRAM_SDQS2 */ + ldr r7, [r1, #0x4c8] /* DRAM_SDQS3 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x4cc] /* DRAM_SDQS4 */ + ldr r5, [r1, #0x4d0] /* DRAM_SDQS5 */ + ldr r6, [r1, #0x4d4] /* DRAM_SDQS6 */ + ldr r7, [r1, #0x4d8] /* DRAM_SDQS7 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x764] /* GPR_B0DS */ + ldr r5, [r1, #0x770] /* GPR_B1DS */ + ldr r6, [r1, #0x778] /* GPR_B2DS */ + ldr r7, [r1, #0x77c] /* GPR_B3DS */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x780] /* GPR_B4DS */ + ldr r5, [r1, #0x784] /* GPR_B5DS */ + ldr r6, [r1, #0x78c] /* GPR_B6DS */ + ldr r7, [r1, #0x748] /* GPR_B7DS */ + stmfd r0!, {r4-r7} + + ldr r5, [r1, #0x74c] /* GPR_ADDS*/ + ldr r6, [r1, #0x4b4] /* DRAM_SODT0*/ + ldr r7, [r1, #0x4b8] /* DRAM_SODT1*/ + stmfd r0!, {r5-r7} + + .endm + + .macro dl_ddr_io_restore + + ldmea r0!, {r4-r7} + str r4, [r1, #0x470] /* DRAM_DQM0 */ + str r5, [r1, #0x474] /* DRAM_DQM1 */ + str r6, [r1, #0x478] /* DRAM_DQM2 */ + str r7, [r1, #0x47c] /* DRAM_DQM3 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x480] /* DRAM_DQM4 */ + str r5, [r1, #0x484] /* DRAM_DQM5 */ + str r6, [r1, #0x488] /* DRAM_DQM6 */ + str r7, [r1, #0x48c] /* DRAM_DQM7 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x464] /* DRAM_CAS */ + str r5, [r1, #0x490] /* DRAM_RAS */ + str r6, [r1, #0x4ac] /* DRAM_SDCLK_0 */ + str r7, [r1, #0x4b0] /* DRAM_SDCLK_1 */ + + ldmea r0!, {r5-r6} + str r5, [r1, #0x750] /* DDRMODE_CTL */ + str r6, [r1, #0x760] /* DDRMODE */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x4bc] /* DRAM_SDQS0 */ + str r5, [r1, #0x4c0] /* DRAM_SDQS1 */ + str r6, [r1, #0x4c4] /* DRAM_SDQS2 */ + str r7, [r1, #0x4c8] /* DRAM_SDQS3 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x4cc] /* DRAM_SDQS4 */ + str r5, [r1, #0x4d0] /* DRAM_SDQS5 */ + str r6, [r1, #0x4d4] /* DRAM_SDQS6 */ + str r7, [r1, #0x4d8] /* DRAM_SDQS7 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x764] /* GPR_B0DS */ + str r5, [r1, #0x770] /* GPR_B1DS */ + str r6, [r1, #0x778] /* GPR_B2DS */ + str r7, [r1, #0x77c] /* GPR_B3DS */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x780] /* GPR_B4DS */ + str r5, [r1, #0x784] /* GPR_B5DS */ + str r6, [r1, #0x78c] /* GPR_B6DS */ + str r7, [r1, #0x748] /* GPR_B7DS */ + + ldmea r0!, {r5-r7} + str r5, [r1, #0x74c] /* GPR_ADDS*/ + str r6, [r1, #0x4b4] /* DRAM_SODT0*/ + str r7, [r1, #0x4b8] /* DRAM_SODT1*/ + + .endm + + .macro dl_ddr_io_set_lpm + + mov r0, #0 + str r0, [r1, #0x470] /* DRAM_DQM0 */ + str r0, [r1, #0x474] /* DRAM_DQM1 */ + str r0, [r1, #0x478] /* DRAM_DQM2 */ + str r0, [r1, #0x47c] /* DRAM_DQM3 */ + + str r0, [r1, #0x480] /* DRAM_DQM4 */ + str r0, [r1, #0x484] /* DRAM_DQM5 */ + str r0, [r1, #0x488] /* DRAM_DQM6 */ + str r0, [r1, #0x48c] /* DRAM_DQM7 */ + + str r0, [r1, #0x464] /* DRAM_CAS */ + str r0, [r1, #0x490] /* DRAM_RAS */ + str r0, [r1, #0x4ac] /* DRAM_SDCLK_0 */ + str r0, [r1, #0x4b0] /* DRAM_SDCLK_1 */ + + str r0, [r1, #0x750] /* DDRMODE_CTL */ + str r0, [r1, #0x760] /* DDRMODE */ + + str r0, [r1, #0x4bc] /* DRAM_SDQS0 */ + str r0, [r1, #0x4c0] /* DRAM_SDQS1 */ + str r0, [r1, #0x4c4] /* DRAM_SDQS2 */ + str r0, [r1, #0x4c8] /* DRAM_SDQS3 */ + + str r0, [r1, #0x4cc] /* DRAM_SDQS4 */ + str r0, [r1, #0x4d0] /* DRAM_SDQS5 */ + str r0, [r1, #0x4d4] /* DRAM_SDQS6 */ + str r0, [r1, #0x4d8] /* DRAM_SDQS7 */ + + str r0, [r1, #0x764] /* GPR_B0DS */ + str r0, [r1, #0x770] /* GPR_B1DS */ + str r0, [r1, #0x778] /* GPR_B2DS */ + str r0, [r1, #0x77c] /* GPR_B3DS */ + + str r0, [r1, #0x780] /* GPR_B4DS */ + str r0, [r1, #0x784] /* GPR_B5DS */ + str r0, [r1, #0x78c] /* GPR_B6DS */ + str r0, [r1, #0x748] /* GPR_B7DS */ + + str r0, [r1, #0x74c] /* GPR_ADDS*/ + str r0, [r1, #0x4b4] /* DRAM_SODT0*/ + str r0, [r1, #0x4b8] /* DRAM_SODT1*/ + + .endm + + .macro dq_ddr_io_save + + ldr r4, [r1, #0x5ac] /* DRAM_DQM0 */ + ldr r5, [r1, #0x5b4] /* DRAM_DQM1 */ + ldr r6, [r1, #0x528] /* DRAM_DQM2 */ + ldr r7, [r1, #0x520] /* DRAM_DQM3 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x514] /* DRAM_DQM4 */ + ldr r5, [r1, #0x510] /* DRAM_DQM5 */ + ldr r6, [r1, #0x5bc] /* DRAM_DQM6 */ + ldr r7, [r1, #0x5c4] /* DRAM_DQM7 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x56c] /* DRAM_CAS */ + ldr r5, [r1, #0x578] /* DRAM_RAS */ + ldr r6, [r1, #0x588] /* DRAM_SDCLK_0 */ + ldr r7, [r1, #0x594] /* DRAM_SDCLK_1 */ + stmfd r0!, {r4-r7} + + ldr r5, [r1, #0x750] /* DDRMODE_CTL */ + ldr r6, [r1, #0x774] /* DDRMODE */ + stmfd r0!, {r5-r6} + + ldr r4, [r1, #0x5a8] /* DRAM_SDQS0 */ + ldr r5, [r1, #0x5b0] /* DRAM_SDQS1 */ + ldr r6, [r1, #0x524] /* DRAM_SDQS2 */ + ldr r7, [r1, #0x51c] /* DRAM_SDQS3 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x518] /* DRAM_SDQS4 */ + ldr r5, [r1, #0x50c] /* DRAM_SDQS5 */ + ldr r6, [r1, #0x5b8] /* DRAM_SDQS6 */ + ldr r7, [r1, #0x5c0] /* DRAM_SDQS7 */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x784] /* GPR_B0DS */ + ldr r5, [r1, #0x788] /* GPR_B1DS */ + ldr r6, [r1, #0x794] /* GPR_B2DS */ + ldr r7, [r1, #0x79c] /* GPR_B3DS */ + stmfd r0!, {r4-r7} + + ldr r4, [r1, #0x7a0] /* GPR_B4DS */ + ldr r5, [r1, #0x7a4] /* GPR_B5DS */ + ldr r6, [r1, #0x7a8] /* GPR_B6DS */ + ldr r7, [r1, #0x748] /* GPR_B7DS */ + stmfd r0!, {r4-r7} + + ldr r5, [r1, #0x74c] /* GPR_ADDS*/ + ldr r6, [r1, #0x59c] /* DRAM_SODT0*/ + ldr r7, [r1, #0x5a0] /* DRAM_SODT1*/ + stmfd r0!, {r5-r7} + + .endm + + .macro dq_ddr_io_restore + + ldmea r0!, {r4-r7} + str r4, [r1, #0x5ac] /* DRAM_DQM0 */ + str r5, [r1, #0x5b4] /* DRAM_DQM1 */ + str r6, [r1, #0x528] /* DRAM_DQM2 */ + str r7, [r1, #0x520] /* DRAM_DQM3 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x514] /* DRAM_DQM4 */ + str r5, [r1, #0x510] /* DRAM_DQM5 */ + str r6, [r1, #0x5bc] /* DRAM_DQM6 */ + str r7, [r1, #0x5c4] /* DRAM_DQM7 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x56c] /* DRAM_CAS */ + str r5, [r1, #0x578] /* DRAM_RAS */ + str r6, [r1, #0x588] /* DRAM_SDCLK_0 */ + str r7, [r1, #0x594] /* DRAM_SDCLK_1 */ + + ldmea r0!, {r5-r6} + str r5, [r1, #0x750] /* DDRMODE_CTL */ + str r6, [r1, #0x774] /* DDRMODE */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x5a8] /* DRAM_SDQS0 */ + str r5, [r1, #0x5b0] /* DRAM_SDQS1 */ + str r6, [r1, #0x524] /* DRAM_SDQS2 */ + str r7, [r1, #0x51c] /* DRAM_SDQS3 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x518] /* DRAM_SDQS4 */ + str r5, [r1, #0x50c] /* DRAM_SDQS5 */ + str r6, [r1, #0x5b8] /* DRAM_SDQS6 */ + str r7, [r1, #0x5c0] /* DRAM_SDQS7 */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x784] /* GPR_B0DS */ + str r5, [r1, #0x788] /* GPR_B1DS */ + str r6, [r1, #0x794] /* GPR_B2DS */ + str r7, [r1, #0x79c] /* GPR_B3DS */ + + ldmea r0!, {r4-r7} + str r4, [r1, #0x7a0] /* GPR_B4DS */ + str r5, [r1, #0x7a4] /* GPR_B5DS */ + str r6, [r1, #0x7a8] /* GPR_B6DS */ + str r7, [r1, #0x748] /* GPR_B7DS */ + + ldmea r0!, {r5-r7} + str r5, [r1, #0x74c] /* GPR_ADDS*/ + str r6, [r1, #0x59c] /* DRAM_SODT0*/ + str r7, [r1, #0x5a0] /* DRAM_SODT1*/ + + .endm + + .macro dq_ddr_io_set_lpm + + mov r0, #0 + str r0, [r1, #0x5ac] /* DRAM_DQM0 */ + str r0, [r1, #0x5b4] /* DRAM_DQM1 */ + str r0, [r1, #0x528] /* DRAM_DQM2 */ + str r0, [r1, #0x520] /* DRAM_DQM3 */ + + str r0, [r1, #0x514] /* DRAM_DQM4 */ + str r0, [r1, #0x510] /* DRAM_DQM5 */ + str r0, [r1, #0x5bc] /* DRAM_DQM6 */ + str r0, [r1, #0x5c4] /* DRAM_DQM7 */ + + str r0, [r1, #0x56c] /* DRAM_CAS */ + str r0, [r1, #0x578] /* DRAM_RAS */ + str r0, [r1, #0x588] /* DRAM_SDCLK_0 */ + str r0, [r1, #0x594] /* DRAM_SDCLK_1 */ + + str r0, [r1, #0x750] /* DDRMODE_CTL */ + str r0, [r1, #0x774] /* DDRMODE */ + + str r0, [r1, #0x5a8] /* DRAM_SDQS0 */ + str r0, [r1, #0x5b0] /* DRAM_SDQS1 */ + str r0, [r1, #0x524] /* DRAM_SDQS2 */ + str r0, [r1, #0x51c] /* DRAM_SDQS3 */ + + str r0, [r1, #0x518] /* DRAM_SDQS4 */ + str r0, [r1, #0x50c] /* DRAM_SDQS5 */ + str r0, [r1, #0x5b8] /* DRAM_SDQS6 */ + str r0, [r1, #0x5c0] /* DRAM_SDQS7 */ + + str r0, [r1, #0x784] /* GPR_B0DS */ + str r0, [r1, #0x788] /* GPR_B1DS */ + str r0, [r1, #0x794] /* GPR_B2DS */ + str r0, [r1, #0x79c] /* GPR_B3DS */ + + str r0, [r1, #0x7a0] /* GPR_B4DS */ + str r0, [r1, #0x7a4] /* GPR_B5DS */ + str r0, [r1, #0x7a8] /* GPR_B6DS */ + str r0, [r1, #0x748] /* GPR_B7DS */ + + str r0, [r1, #0x74c] /* GPR_ADDS*/ + str r0, [r1, #0x59c] /* DRAM_SODT0*/ + str r0, [r1, #0x5a0] /* DRAM_SODT1*/ + + .endm + +/****************************************************************** +Invalidate l1 dcache, r0-r4, r6, r7 used +******************************************************************/ + .macro invalidate_l1_dcache + + mov r0, #0 + mcr p15, 2, r0, c0, c0, 0 + mrc p15, 1, r0, c0, c0, 0 + + ldr r1, =0x7fff + and r2, r1, r0, lsr #13 + + ldr r1, =0x3ff + + and r3, r1, r0, lsr #3 @ NumWays - 1 + add r2, r2, #1 @ NumSets + + and r0, r0, #0x7 + add r0, r0, #4 @ SetShift + + clz r1, r3 @ WayShift + add r4, r3, #1 @ NumWays +1: + sub r2, r2, #1 @ NumSets-- + mov r3, r4 @ Temp = NumWays +2: + subs r3, r3, #1 @ Temp-- + mov r7, r3, lsl r1 + mov r6, r2, lsl r0 + orr r7, r7, r6 + mcr p15, 0, r7, c7, c6, 2 + bgt 2b + cmp r2, #0 + bgt 1b + dsb + isb + + .endm + +/****************************************************************** +Flush and disable L1 dcache +******************************************************************/ + .macro flush_disable_l1_dcache + + /* + * Flush all data from the L1 data cache before disabling + * SCTLR.C bit. + */ + push {r0-r12, lr} + ldr r0, =v7_flush_dcache_all + mov lr, pc + mov pc, r0 + pop {r0-r12, lr} + + /* + * Clear the SCTLR.C bit to prevent further data cache + * allocation. Clearing SCTLR.C would make all the data accesses + * strongly ordered and would not hit the cache. + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #(1 << 2) @ Disable the C bit + mcr p15, 0, r0, c1, c0, 0 + isb + + /* + * Invalidate L1 data cache. Even though only invalidate is + * necessary exported flush API is used here. Doing clean + * on already clean cache would be almost NOP. + */ + push {r0-r12, lr} + ldr r0, =v7_flush_dcache_all + mov lr, pc + mov pc, r0 + pop {r0-r12, lr} + + /* + * Execute an ISB instruction to ensure that all of the + * CP15 register changes have been committed. + */ + isb + + /* + * Execute a barrier instruction to ensure that all cache, + * TLB and branch predictor maintenance operations issued + * by any CPU in the cluster have completed. + */ + dsb + dmb + + .endm + +/****************************************************************** +Clean L2 cache +******************************************************************/ + .macro clean_l2_cache + /* Clean L2 cache to write the dirty data into DRAM to make + sure the data alignment between DRAM and L2 cache. + */ +#ifdef CONFIG_CACHE_L2X0 + /* Clean L2 cache here */ + ldr r1, =L2_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + /* Make way to 0xFFFF 16 ways */ + mov r0, #0x10000 + sub r0, r0, #0x1 + /* 0x7BC is L2X0_CLEAN_WAY */ + mov r4, #0x700 + orr r4, #0xBC + str r0, [r1, r4] +3: + ldr r5, [r1, r4] + ands r5, r5, r0 + bne 3b +4: + mov r5, #0x0 + /* 0x730 is L2X0_CACHE_SYNC */ + mov r4, #0x700 + orr r4, #0x30 + str r5, [r1, r4] +5: + ldr r5, [r1, r4] + ands r5, r5, #0x1 + bne 5b +#endif + .endm + + .align 3 +ENTRY(mx6_suspend) + stmfd sp!, {r0-r12} @ Save registers +/************************************************************* +suspend mode entry +*************************************************************/ + mov r12, r3 /* Save CPU type to r12*/ + mov r11, r0 /* Save the state in r11 */ + + cmp r12, #MXC_CPU_MX6SL + beq dormant + + cmp r0, #0x1 + bne dormant /* dormant mode */ + + /* Need to flush and disable L1 dcache*/ + flush_disable_l1_dcache + + /* Need to clean L2 dcache*/ + clean_l2_cache + + /* Disable L2 cache */ +#ifdef CONFIG_CACHE_L2X0 + ldr r2, =L2_BASE_ADDR + add r2, r2, #PERIPBASE_VIRT + mov r4, #0x0 + str r4, [r2, #L2X0_CTRL] +#endif + + wfi + + nop + nop + nop + nop + + /* Invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 @ Invalidate I-Cache + + /* Need to invalidate L1 dcache, as the power is dropped */ + invalidate_l1_dcache + + /* Enable L1 dcache first */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #(1 << 2) @ Disable the C bit + mcr p15, 0, r0, c1, c0, 0 + + /* Enable L2 cache here */ +#ifdef CONFIG_CACHE_L2X0 + ldr r2, =L2_BASE_ADDR + add r2, r2, #PERIPBASE_VIRT + mov r4, #0x1 + str r4, [r2, #L2X0_CTRL] +#endif + +/*********************************************************** +never run to here +************************************************************/ + b out /* exit standby */ + /* Place the literal pool here so that + * literals are within 4KB range + */ + .ltorg +/************************************************************ +dormant entry, data save in stack, save sp in the src_gpr2 +************************************************************/ +dormant: + mov r3, r1 + mov r0, r1 + add r0, r0, #IRAM_SUSPEND_SIZE /* 8K */ + ldr r4, =SRC_BASE_ADDR + add r4, r4, #PERIPBASE_VIRT + str r0, [r4, #SRC_GPR2_OFFSET] /* set src_gpr2 */ +/************************************************************ +saved register and context as below: + ddr_iomux set + sp + spsr + lr + CPACR + TTBR0 + TTBR1 + TTBCR + DACR + PRRR + NMRR + ACTLR + Context ID + User r/w thread ID + Secure or NS VBAR + CPSR + SCTLR +************************************************************/ + /* save mmdc iomux setting, stack is from the tail of + iram_suspend base */ + + mov r0, r2 /* get suspend_iram_base */ + add r0, r0, #IRAM_SUSPEND_SIZE /* 5K */ + + mov r4, r12 @ Store cpu type + stmfd r0!, {r4} + mov r4, r11 @ Store state entered + stmfd r0!, {r4} + + ldr r1, =MX6Q_IOMUXC_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + cmp r12, #MXC_CPU_MX6Q + bne dl_io_save + dq_ddr_io_save + b ddr_io_save_done +dl_io_save: + cmp r12, #MXC_CPU_MX6DL + bne sl_io_save + dl_ddr_io_save + b ddr_io_save_done +sl_io_save: + sl_ddr_io_save + +ddr_io_save_done: +#ifdef CONFIG_CACHE_L2X0 + ldr r1, =L2_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + ldr r4, [r1, #L2X0_CTRL] + ldr r5, [r1, #L2X0_AUX_CTRL] + ldr r6, [r1, #L2X0_TAG_LATENCY_CTRL] + ldr r7, [r1, #L2X0_DATA_LATENCY_CTRL] + stmfd r0!, {r4-r7} + + ldr r4, [r1, #L2X0_PREFETCH_CTRL] + ldr r5, [r1, #L2X0_POWER_CTRL] + stmfd r0!, {r4-r5} +#endif + + mov r4, sp @ Store sp + mrs r5, spsr @ Store spsr + mov r6, lr @ Store lr + stmfd r0!, {r4-r6} + + /* c1 and c2 registers */ + mrc p15, 0, r4, c1, c0, 2 @ CPACR + mrc p15, 0, r5, c2, c0, 0 @ TTBR0 + mrc p15, 0, r6, c2, c0, 1 @ TTBR1 + mrc p15, 0, r7, c2, c0, 2 @ TTBCR + stmfd r0!, {r4-r7} + + /* c3 and c10 registers */ + mrc p15, 0, r4, c3, c0, 0 @ DACR + mrc p15, 0, r5, c10, c2, 0 @ PRRR + mrc p15, 0, r6, c10, c2, 1 @ NMRR + mrc p15, 0, r7, c1, c0, 1 @ ACTLR + stmfd r0!,{r4-r7} + + /* c12, c13 and CPSR registers */ + mrc p15, 0, r4, c13, c0, 1 @ Context ID + mrc p15, 0, r5, c13, c0, 2 @ User r/w thread ID + mrc p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR + mrs r7, cpsr @ Store CPSR + stmfd r0!, {r4-r7} + + /* c1 control register */ + mrc p15, 0, r4, c1, c0, 0 @ SCTLR + stmfd r0!, {r4} + + /* Need to flush and disable L1 dcache*/ + flush_disable_l1_dcache + + /* Need to clean L2 dcache*/ + clean_l2_cache + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + ldr r6, =iram_tlb_phys_addr + ldr r6, [r6] + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r6, c2, c0, 1 + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + +/**************************************************************** +set ddr iomux to low power mode +****************************************************************/ + ldr r1, =MMDC_P0_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Put DDR explicitly into self-refresh. */ + /* Disable Automatic power savings. */ + ldr r0, [r1, #0x404] + orr r0, r0, #0x01 + str r0, [r1, #0x404] + + /* Make the DDR explicitly enter self-refresh. */ + ldr r0, [r1, #0x404] + orr r0, r0, #0x200000 + str r0, [r1, #0x404] + +poll_dvfs_set_1: + ldr r0, [r1, #0x404] + and r0, r0, #0x2000000 + cmp r0, #0x2000000 + bne poll_dvfs_set_1 + + /* set mmdc iomux to low power mode */ + ldr r1, =MX6Q_IOMUXC_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + cmp r12, #MXC_CPU_MX6Q + bne dl_io_set_lpm + dq_ddr_io_set_lpm + b ddr_io_set_lpm_done +dl_io_set_lpm: + cmp r12, #MXC_CPU_MX6DL + bne sl_io_set_lpm + dl_ddr_io_set_lpm + b ddr_io_set_lpm_done +sl_io_set_lpm: + sl_ddr_io_set_lpm + +ddr_io_set_lpm_done: + /* Do Analog Power Optimizations + * for MX6SL in standby mode. + */ + cmp r12, #MXC_CPU_MX6SL + bne no_analog_savings + cmp r11, #1 + bne no_analog_savings + + /* We are here because on + * MX6SL, we want to lower + * the power in Standby mode. + */ + mx6sl_standy_saving_set + +no_analog_savings: + +/**************************************************************** +save resume pointer into SRC_GPR1 +****************************************************************/ + ldr r0, =mx6_suspend + ldr r1, =resume + sub r1, r1, r0 + add r3, r3, r1 + ldr r1, =SRC_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + str r3, [r1, #SRC_GPR1_OFFSET] + + /* Mask all GPC interrupts before + * enabling the RBC counters to + * avoid the counter starting too + * early if an interupt is already + * pending. + */ + ldr r3, =GPC_BASE_ADDR + add r3, r3, #PERIPBASE_VIRT + ldr r4, [r3, #0x08] + ldr r5, [r3, #0x0c] + ldr r6, [r3, #0x10] + ldr r7, [r3, #0x14] + + ldr r8, =0xffffffff + str r8, [r3, #0x08] + str r8, [r3, #0x0c] + str r8, [r3, #0x10] + str r8, [r3, #0x14] + + /* Enable the RBC bypass counter here + * to hold off the interrupts. + * RBC counter = 32 (1ms) + * Minimum RBC delay should be + * 400us for the analog LDOs to + * power down. + */ + ldr r1, =CCM_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r8, [r1, #0x0] + ldr r0, =0x7E00000 + bic r8, r8, r0 + ldr r0, =0x4000000 + orr r8, r8, r0 + str r8, [r1, #0x0] + + /* Enable the counter. */ + ldr r8, [r1, #0x0] + orr r8, r8, #0x8000000 + str r8, [r1, #0x0] + + /* Unmask all the GPC interrupts. */ + str r4, [r3, #0x08] + str r5, [r3, #0x0c] + str r6, [r3, #0x10] + str r7, [r3, #0x14] + + + /* Now delay for a short while (3usec) + * ARM is at 1GHz at this point + * so a short loop should be enough. + * This delay is required to ensure that + * the RBC counter can start counting in case an + * interrupt is already pending or in case an interrupt + * arrives just as ARM is about to assert DSM_request. + */ + ldr r4, =2000 +rbc_loop: + sub r4, r4, #0x1 + cmp r4, #0x0 + bne rbc_loop + + /*if internal ldo(VDDARM) bypassed,analog bypass it for DSM(0x1e) and + *restore it when resume(0x1f). + */ + ldr r1, =ANATOP_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r4, [r1, #0x140] + and r4, r4, #0x1f + cmp r4, #0x1f + bne ldo_check_done1 +ldo_analog_bypass: + ldr r4, [r1, #0x140] + bic r4, r4, #0x1f + orr r4, r4, #0x1e + str r4, [r1, #0x140] +ldo_check_done1: +/**************************************************************** +execute a wfi instruction to let SOC go into stop mode. +****************************************************************/ + wfi + + nop + nop + nop + nop + +/**************************************************************** +if go here, means there is a wakeup irq pending, we should resume +system immediately. +****************************************************************/ + /*restore it with 0x1f if use ldo bypass mode.*/ + ldr r1, =ANATOP_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r3, [r1, #0x140] + and r3, r3, #0x1f + cmp r3, #0x1e + bne ldo_check_done2 +ldo_bypass_restore: + ldr r3, [r1, #0x140] + orr r3, r3, #0x1f + str r3, [r1, #0x140] +ldo_check_done2: + /* + * Get the address of IRAM stack + */ + ldr r0, =SRC_BASE_ADDR + add r0, r0, #PERIPBASE_VIRT + ldr r0, [r0, #SRC_GPR2_OFFSET] + + add r0, r0, #PERIPBASE_VIRT + ldmea r0!, {r12} @ get cpu type to make ddr io + @ offset right + + ldmea r0!, {r11} @ standby or mem + + cmp r12, #MXC_CPU_MX6SL + bne no_analog_restore + + cmp r11, #0x1 + bne no_analog_restore + + ldr r3, =CCM_BASE_ADDR + add r3, r3, #PERIPBASE_VIRT + + /* Restore the analog settings. */ + mx6sl_standby_savings_restore + +no_analog_restore: + ldr r1, =MX6Q_IOMUXC_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + cmp r12, #MXC_CPU_MX6Q + bne dl_io_restore + dq_ddr_io_restore + b ddr_io_restore_done +dl_io_restore: + cmp r12, #MXC_CPU_MX6DL + bne sl_io_restore + dl_ddr_io_restore + b ddr_io_restore_done +sl_io_restore: + sl_ddr_io_restore + ldr r1, =MMDC_P0_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =0x83c + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +fifo_reset1_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne fifo_reset1_wait + + /* reset FIFO a second time */ + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +fifo_reset2_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne fifo_reset2_wait + +ddr_io_restore_done: + ldr r1, =MMDC_P0_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Ensure DDR exits self-refresh. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x200000 + str r6, [r1, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r1, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x01 + str r6, [r1, #0x404] + + /* Add enough nops so that the + * prefetcher will not get instructions + * from DDR before its IO pads + * are restored. + */ + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #(1 << 2) @ Enable the C bit + mcr p15, 0, r1, c1, c0, 0 + + /* Restore TTBCR */ + dsb + isb + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + b out /* exit standby */ + .ltorg + +/**************************************************************** +when SOC exit stop mode, arm core restart from here, currently +are running with MMU off. +****************************************************************/ +resume: + /*restore it with 0x1f if use ldo bypass mode.*/ + ldr r1, =ANATOP_BASE_ADDR + ldr r3, [r1, #0x140] + and r3, r3, #0x1f + cmp r3, #0x1e + bne ldo_check_done3 + ldr r3, [r1, #0x140] + orr r3, r3, #0x1f + str r3, [r1, #0x140] +ldo_check_done3: + /* Invalidate L1 I-cache first */ + mov r1, #0x0 + mcr p15, 0, r1, c7, c5, 0 @ Invalidate I-Cache + mcr p15, 0, r1, c7, c5, 0 @ invalidate Icache to PoU + mcr p15, 0, r1, c7, c5, 6 @ invalidate branch predictor + mov r1, #0x1800 + mcr p15, 0, r1, c1, c0, 0 @ enable the Icache and branch prediction + isb @ as soon as possible + + /* Need to invalidate L1 dcache */ + invalidate_l1_dcache + + ldr r0, =SRC_BASE_ADDR + str r1, [r0, #SRC_GPR1_OFFSET] /* clear SRC_GPR1 */ + ldr r0, [r0, #SRC_GPR2_OFFSET] + + ldmea r0!, {r12} @ get cpu type + + ldmea r0!, {r11} @ standby or mem + + cmp r12, #MXC_CPU_MX6SL + bne no_analog_restore1 + + cmp r11, #0x1 + bne no_analog_restore1 + + ldr r1, =ANATOP_BASE_ADDR + ldr r3, =CCM_BASE_ADDR + + /* Restore the analog settings. */ + mx6sl_standby_pg_savings_restore + +no_analog_restore1: + /* Restore DDR IO */ + ldr r1, =MX6Q_IOMUXC_BASE_ADDR + + cmp r12, #MXC_CPU_MX6Q + bne dl_io_dsm_restore + dq_ddr_io_restore + b ddr_io_restore_dsm_done +dl_io_dsm_restore: + cmp r12, #MXC_CPU_MX6DL + bne sl_io_dsm_restore + dl_ddr_io_restore + b ddr_io_restore_dsm_done +sl_io_dsm_restore: + sl_ddr_io_restore + ldr r1, =MMDC_P0_BASE_ADDR + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =0x83c + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +dsm_fifo_reset1_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne dsm_fifo_reset1_wait + + /* reset FIFO a second time */ + ldr r6, [r1, r7] + orr r6, r6, #0x80000000 + str r6, [r1, r7] +dsm_fifo_reset2_wait: + ldr r6, [r1, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne dsm_fifo_reset2_wait + +ddr_io_restore_dsm_done: + ldr r1, =MMDC_P0_BASE_ADDR + + /* Ensure DDR exits self-refresh. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x200000 + str r6, [r1, #0x404] + +poll_dvfs_clear_2: + ldr r6, [r1, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_2 + + /* Enable Automatic power savings. */ + ldr r6, [r1, #0x404] + bic r6, r6, #0x01 + str r6, [r1, #0x404] + +#ifdef CONFIG_CACHE_L2X0 + ldr r2, =L2_BASE_ADDR + ldmea r0!, {r4-r7} + /* L2 will be enabled after L1 is enabled */ + mov r4, #0x0 + str r4, [r2, #L2X0_CTRL] + str r5, [r2, #L2X0_AUX_CTRL] + str r6, [r2, #L2X0_TAG_LATENCY_CTRL] + str r7, [r2, #L2X0_DATA_LATENCY_CTRL] + + ldmea r0!, {r4-r5} + str r4, [r2, #L2X0_PREFETCH_CTRL] + str r5, [r2, #L2X0_POWER_CTRL] +#endif + + /* Restore cp15 registers and cpu type */ + ldmea r0!, {r4-r6} + mov sp, r4 @ Restore sp + msr spsr_cxsf, r5 @ Restore spsr + mov lr, r6 @ Restore lr + + /* c1 and c2 registers */ + ldmea r0!, {r4-r7} + mcr p15, 0, r4, c1, c0, 2 @ CPACR + mcr p15, 0, r5, c2, c0, 0 @ TTBR0 + mcr p15, 0, r6, c2, c0, 1 @ TTBR1 + mcr p15, 0, r7, c2, c0, 2 @ TTBCR + + /* c3 and c10 registers */ + ldmea r0!,{r4-r7} + mcr p15, 0, r4, c3, c0, 0 @ DACR + mcr p15, 0, r5, c10, c2, 0 @ PRRR + mcr p15, 0, r6, c10, c2, 1 @ NMRR + mcr p15, 0, r7, c1, c0, 1 @ ACTLR + + /* c12, c13 and CPSR registers */ + ldmea r0!,{r4-r7} + mcr p15, 0, r4, c13, c0, 1 @ Context ID + mcr p15, 0, r5, c13, c0, 2 @ User r/w thread ID + mrc p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR + msr cpsr, r7 @ store cpsr + + /* + * Enabling MMU here. Page entry needs to be altered + * to create temporary 1:1 map and then resore the entry + * ones MMU is enabled + */ + mrc p15, 0, r7, c2, c0, 2 @ Read TTBRControl + and r7, #0x7 @ Extract N (0:2) to decide + cmp r7, #0x0 @ TTBR0/TTBR1 + beq use_ttbr0 +ttbr_error: + b ttbr_error @ Only N = 0 supported +use_ttbr0: + mrc p15, 0, r2, c2, c0, 0 @ Read TTBR0 + ldr r5, =TTRBIT_MASK + and r2, r5 + mov r4, pc + ldr r5, =TABLE_INDEX_MASK + and r4, r5 @ r4 = 31 to 20 bits of pc + ldr r1, =TABLE_ENTRY + add r1, r1, r4 @ r1 has value of table entry + lsr r4, #18 @ Address of table entry + add r2, r4 @ r2 - location to be modified + + /* Storing previous entry of location being modified */ + ldr r4, [r2] + mov r9, r4 + str r1, [r2] + + /* + * Storing address of entry being modified + * It will be restored after enabling MMU + */ + mov r10, r2 + + mov r1, #0 + mcr p15, 0, r1, c7, c5, 4 @ Flush prefetch buffer + mcr p15, 0, r1, c8, c5, 0 @ Invalidate ITLB + mcr p15, 0, r1, c8, c6, 0 @ Invalidate DTLB + + /* + * Restore control register but don't enable Data caches here. + * Caches will be enabled after restoring MMU table entry. + */ + ldmea r0!, {r4} + mov r11, r4 + ldr r2, =CACHE_DISABLE_MASK + and r4, r4, r2 + mcr p15, 0, r4, c1, c0, 0 + isb + dsb + ldr r1, =mmu_on_label + bx r1 +mmu_on_label: + +/************************************************************ +restore control register to enable cache +************************************************************/ + mov r0, r11 + mcr p15, 0, r0, c1, c0, 0 @ with caches enabled. + dsb + isb + +#ifdef CONFIG_CACHE_L2X0 + /* Enable L2 cache here */ + ldr r2, =L2_BASE_ADDR + add r2, r2, #PERIPBASE_VIRT + mov r4, #0x1 + str r4, [r2, #L2X0_CTRL] +#endif + + mov r8, lr + push {r0-r3, r12} + + /* Set up the per-CPU stacks */ + bl cpu_init + pop {r0-r3, r12} + + /* + * Restore the MMU table entry that was modified for + * enabling MMU. + */ + ldr r4, =PAGE_OFFSET + + cmp r12, #MXC_CPU_MX6SL + bne dq_dl_phy_offset + ldr r5, =MX6SL_PHYS_OFFSET + b get_phy_offset_done +dq_dl_phy_offset: + ldr r5, =MX6_PHYS_OFFSET +get_phy_offset_done: + + sub r4, r4, r5 + add r4, r4, r10 + str r9, [r4] + + mov r0, #0 + mcr p15, 0, r0, c7, c1, 6 @ flush TLB and issue barriers + mcr p15, 0, r0, c7, c5, 4 @ Flush prefetch buffer + mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB + mcr p15, 0, r0, c8, c5, 0 @ Invalidate ITLB + mcr p15, 0, r0, c8, c6, 0 @ Invalidate DTLB + dsb + isb + +/*********************************************************** +return back to mx6_suspend_enter for dormant +***********************************************************/ + mov lr, r8 + ldmfd sp!, {r0-r12} + mov pc, lr +/************************************************ +return back to mx6_suspend_enter for suspend +*************************************************/ +out: + ldmfd sp!, {r0-r12} + mov pc, lr + + .type mx6_do_suspend, #object +ENTRY(mx6_do_suspend) + .word mx6_suspend + .size mx6_suspend, . - mx6_suspend diff --git a/arch/arm/mach-mx6/mx6_wfi.S b/arch/arm/mach-mx6/mx6_wfi.S new file mode 100644 index 00000000..afe7b9a3 --- /dev/null +++ b/arch/arm/mach-mx6/mx6_wfi.S @@ -0,0 +1,156 @@ +/* + * 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 <linux/linkage.h> +#include <mach/hardware.h> + +/* + * mx6_wait + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + */ +ENTRY(mx6_wait) + + push {r4, r5, r6, r7, r8, r9} + + mov r7, r2 /* Store the arm_podf to be used. */ + mov r6, r3 + + ldr r2, =ANATOP_BASE_ADDR + add r2, r2, #PERIPBASE_VIRT + + ldr r8, =CCM_BASE_ADDR + add r8, r8, #PERIPBASE_VIRT + + + /* get the flags variables into the cache */ + ldr r3, [r0] + + /* get CPU ID */ + mrc p15,0,r5,c0,c0,5 + and r5, r5, #0x3 + + mov r4,#0xff + strb r4,[r0,r5] + + dsb + + mvn r4, #0x0 + ldr r3, [r0] + cmp r3, r4 + bne DO_WFI + + mov r4, #0x1 + ldrex r3, [r1] + cmp r3, #0x0 + strexeq r3, r4, [r1] + cmpeq r3, #0x0 + bne DO_WFI + + mov r3, #0xff + + /* Check to see if we need to switch to 24MHz */ + cmp r7, #0 + bne use_podf + /* Switch ARM to PLL1 output. */ + /* PLL1 should already be in bypass state. */ + ldr r6, [r8, #0x0C] + bic r6, r6, #0x04 + str r6, [r8, #0x0C] + b cont + +use_podf: + /* Change ARM_PODF to the max possible podf + * so that ARM_CLK to IPG_CLK is in 12:5 ratio. + */ + str r7, [r8, #0x10] + /* Loop till podf is accepted. */ +podf_loop: + ldr r4, [r8, #0x48] + cmp r4, #0x0 + bne podf_loop + + /* dmb */ + +cont: + str r3, [r1] + + dsb + + mvn r4, #0x0 + ldr r3, [r0] + cmp r3, r4 + beq DO_WFI + + mov r3, #0x0 + /* Switch to 24MHz or use ARM_PODF. */ + cmp r7, #0x0 + bne use_podf1 + /* Set pll1_sw_clk to run from STEP_CLK. */ + orr r6, r6, #0x04 + str r6, [r8, #0x0C] + b DO_WFI +use_podf1: + str r6, [r8, #0x10] + + str r3, [r1] + +DO_WFI: + dsb + + wfi + + mov r4, #0x0 + strb r4, [r0, r5] + + dsb + + ldr r3, [r1] + cmp r3, #0xff + bne DONE + + mov r4, #0x0 + cmp r7, #0x0 + bne use_podf2 + /* Set pll1_sw_clk to run from STEP_CLK. */ + ldr r6, [r8, #0x0C] + orr r6, r6, #0x04 + str r6, [r8, #0x0C] + + b cont1 + +use_podf2: + str r6, [r8, #0x10] + +cont1: + mov r3, #0x0 + str r3, [r1] + +DONE: + + pop {r4,r5, r6, r7, r8, r9} + + /* Restore registers */ + mov pc, lr + + .type mx6_do_wait, #object +ENTRY(mx6_do_wait) + .word mx6_wait + .size mx6_wait, . - mx6_wait diff --git a/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c new file mode 100644 index 00000000..671233f3 --- /dev/null +++ b/arch/arm/mach-mx6/mx6q_sabreauto_pmic_pfuze100.c @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2011-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., 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/err.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/pfuze.h> +#include <linux/io.h> +#include <mach/irqs.h> +#include <mach/system.h> +#include "crm_regs.h" +#include "regs-anadig.h" +#include "cpu_op-mx6.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 PFUZE100_I2C_DEVICE_NAME "pfuze100" +/* 7-bit I2C bus slave address */ +#define PFUZE100_I2C_ADDR (0x08) +#define PFUZE100_DEVICEID (0x0) +#define PFUZE100_REVID (0x3) +#define PFUZE100_SW1AMODE (0x23) +#define PFUZE100_SW1AVOL 32 +#define PFUZE100_SW1AVOL_VSEL_M (0x3f<<0) +#define PFUZE100_SW1CVOL 46 +#define PFUZE100_SW1CVOL_VSEL_M (0x3f<<0) +#define PFUZE100_SW1ACON 36 +#define PFUZE100_SW1ACON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1ACON_SPEED_M (0x3<<6) +#define PFUZE100_SW1CCON 49 +#define PFUZE100_SW1CCON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1CCON_SPEED_M (0x3<<6) + +extern u32 arm_max_freq; +extern u32 enable_ldo_mode; + +static struct regulator_consumer_supply sw1a_consumers[] = { + { + .supply = "VDDCORE", + } +}; + +static struct regulator_consumer_supply sw1c_consumers[] = { + { + .supply = "VDDSOC", + } +}; + +static struct regulator_consumer_supply sw2_consumers[] = { + { + .supply = "P3V0_VDDHIGH_SW2", + } +}; + +static struct regulator_consumer_supply sw3_consumers[] = { + { + .supply = "P1V5_DDR_SW3", + } +}; + +static struct regulator_consumer_supply sw4_consumers[] = { + { + .supply = "P1V8_SW4", + } +}; + +static struct regulator_consumer_supply swbst_consumers[] = { + { + .supply = "P5V0_SWBST", + } +}; + +static struct regulator_consumer_supply vsnvs_consumers[] = { + { + .supply = "P3V0_STBY", + } +}; + +static struct regulator_consumer_supply vgen1_consumers[] = { + { + .supply = "P1V2_VGEN1", + } +}; + +static struct regulator_consumer_supply vgen2_consumers[] = { + { + .supply = "P1V5_VGEN2", + } +}; + +static struct regulator_consumer_supply vgen3_consumers[] = { + { + .supply = "P1V8_VGEN3", + } +}; + +static struct regulator_consumer_supply vgen4_consumers[] = { + { + .supply = "P1V8_VGEN4", + } +}; + +static struct regulator_consumer_supply vgen5_consumers[] = { + { + .supply = "P2V5_VGEN5", + } +}; + +static struct regulator_consumer_supply vgen6_consumers[] = { + { + .supply = "P2V8_VGEN6", + } +}; + +static struct regulator_init_data sw1a_init = { + .constraints = { + .name = "SW1A", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 650000, + .max_uV = 1437500, +#else + .min_uV = 300000, + .max_uV = 1875000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .boot_on = 1, + .always_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1a_consumers), + .consumer_supplies = sw1a_consumers, +}; + +static struct regulator_init_data sw1b_init = { + .constraints = { + .name = "SW1B", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw1c_init = { + .constraints = { + .name = "SW1C", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1c_consumers), + .consumer_supplies = sw1c_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "SW2", +#if PFUZE100_SW2_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw2_consumers), + .consumer_supplies = sw2_consumers, +}; + +static struct regulator_init_data sw3a_init = { + .constraints = { + .name = "SW3A", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw3_consumers), + .consumer_supplies = sw3_consumers, +}; + +static struct regulator_init_data sw3b_init = { + .constraints = { + .name = "SW3B", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "SW4", +#if PFUZE100_SW4_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "SWBST", + .min_uV = 5000000, + .max_uV = 5150000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(swbst_consumers), + .consumer_supplies = swbst_consumers, +}; + +static struct regulator_init_data vsnvs_init = { + .constraints = { + .name = "VSNVS", + .min_uV = 1200000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vsnvs_consumers), + .consumer_supplies = vsnvs_consumers, +}; + +static struct regulator_init_data vrefddr_init = { + .constraints = { + .name = "VREFDDR", + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "VGEN1", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "VGEN2", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen2_consumers), + .consumer_supplies = vgen2_consumers, + +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "VGEN3", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen3_consumers), + .consumer_supplies = vgen3_consumers, +}; + +static struct regulator_init_data vgen4_init = { + .constraints = { + .name = "VGEN4", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen4_consumers), + .consumer_supplies = vgen4_consumers, +}; + +static struct regulator_init_data vgen5_init = { + .constraints = { + .name = "VGEN5", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen5_consumers), + .consumer_supplies = vgen5_consumers, +}; + +static struct regulator_init_data vgen6_init = { + .constraints = { + .name = "VGEN6", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen6_consumers), + .consumer_supplies = vgen6_consumers, +}; + +static int pfuze100_init(struct mc_pfuze *pfuze) +{ + int ret, i; + unsigned char value; + + /*use default mode(ldo bypass) if no param from cmdline*/ + if (enable_ldo_mode == LDO_MODE_DEFAULT) + enable_ldo_mode = LDO_MODE_ENABLED; + + /*read Device ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_DEVICEID, &value); + if (ret) + goto err; + if (value != 0x10) { + printk(KERN_ERR "wrong device id:%x!\n", value); + goto err; + } + + /*read Revision ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_REVID, &value); + if (ret) + goto err; + if (value == 0x10) { + printk(KERN_WARNING "PF100 1.0 chip found!\n"); + /* workaround ER1 of pfuze1.0: set all buck regulators in PWM mode + * except SW1C(APS) in normal and PFM mode in standby. + */ + for (i = 0; i < 7; i++) { + if (i == 2)/*SW1C*/ + value = 0xc;/*normal:APS mode;standby:PFM mode*/ + else + value = 0xd;/*normal:PWM mode;standby:PFM mode*/ + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } else { + /*set all switches APS in normal and PFM mode in standby*/ + for (i = 0; i < 7; i++) { + value = 0xc; + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } + /*use ldo active mode if use 1.2GHz,otherwise use ldo bypass mode*/ + if (arm_max_freq == CPU_AT_1_2GHz) { + /*VDDARM_IN 1.425*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2d); + if (ret) + goto err; + /*VDDSOC_IN 1.425V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2d); + if (ret) + goto err; + enable_ldo_mode = LDO_MODE_ENABLED; + } else if (enable_ldo_mode == LDO_MODE_BYPASSED) { + /*decrease VDDARM_IN/VDDSOC_IN,since we will use ldo bypass mode*/ + /*VDDARM_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*VDDSOC_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*set SW1AB/1C DVSPEED as 25mV step each 4us,quick than 16us before.*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1ACON, + PFUZE100_SW1ACON_SPEED_M, + PFUZE100_SW1ACON_SPEED_VAL); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CCON, + PFUZE100_SW1CCON_SPEED_M, + PFUZE100_SW1CCON_SPEED_VAL); + if (ret) + goto err; + } else if (enable_ldo_mode != LDO_MODE_BYPASSED) { + /*Increase VDDARM_IN/VDDSOC_IN to 1.375V in ldo active mode*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + } + return 0; +err: + printk(KERN_ERR "pfuze100 init error!\n"); + return -1; +} + +static struct pfuze_regulator_init_data mx6q_sabreauto_pfuze100_regulators[] = { + {.id = PFUZE100_SW1A, .init_data = &sw1a_init}, + {.id = PFUZE100_SW1B, .init_data = &sw1b_init}, + {.id = PFUZE100_SW1C, .init_data = &sw1c_init}, + {.id = PFUZE100_SW2, .init_data = &sw2_init}, + {.id = PFUZE100_SW3A, .init_data = &sw3a_init}, + {.id = PFUZE100_SW3B, .init_data = &sw3b_init}, + {.id = PFUZE100_SW4, .init_data = &sw4_init}, + {.id = PFUZE100_SWBST, .init_data = &swbst_init}, + {.id = PFUZE100_VSNVS, .init_data = &vsnvs_init}, + {.id = PFUZE100_VREFDDR, .init_data = &vrefddr_init}, + {.id = PFUZE100_VGEN1, .init_data = &vgen1_init}, + {.id = PFUZE100_VGEN2, .init_data = &vgen2_init}, + {.id = PFUZE100_VGEN3, .init_data = &vgen3_init}, + {.id = PFUZE100_VGEN4, .init_data = &vgen4_init}, + {.id = PFUZE100_VGEN5, .init_data = &vgen5_init}, + {.id = PFUZE100_VGEN6, .init_data = &vgen6_init}, +}; + +static struct pfuze_platform_data pfuze100_plat = { + .flags = PFUZE_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx6q_sabreauto_pfuze100_regulators), + .regulators = mx6q_sabreauto_pfuze100_regulators, + .pfuze_init = pfuze100_init, + +}; + +static struct i2c_board_info __initdata pfuze100_i2c_device = { + I2C_BOARD_INFO(PFUZE100_I2C_DEVICE_NAME, PFUZE100_I2C_ADDR), + .platform_data = &pfuze100_plat, +}; + +int __init mx6q_sabreauto_init_pfuze100(u32 int_gpio) +{ + pfuze100_i2c_device.irq = gpio_to_irq(int_gpio); /*update INT gpio */ + return i2c_register_board_info(1, &pfuze100_i2c_device, 1); +} diff --git a/arch/arm/mach-mx6/mx6q_sabresd_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6q_sabresd_pmic_pfuze100.c new file mode 100644 index 00000000..c18a0143 --- /dev/null +++ b/arch/arm/mach-mx6/mx6q_sabresd_pmic_pfuze100.c @@ -0,0 +1,529 @@ +/* + * 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., 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/err.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/pfuze.h> +#include <linux/io.h> +#include <mach/irqs.h> +#include <mach/system.h> +#include "crm_regs.h" +#include "regs-anadig.h" +#include "cpu_op-mx6.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 PFUZE100_I2C_DEVICE_NAME "pfuze100" +/* 7-bit I2C bus slave address */ +#define PFUZE100_I2C_ADDR (0x08) +#define PFUZE100_DEVICEID (0x0) +#define PFUZE100_REVID (0x3) +#define PFUZE100_SW1AMODE (0x23) +#define PFUZE100_SW1AVOL 32 +#define PFUZE100_SW1AVOL_VSEL_M (0x3f<<0) +#define PFUZE100_SW1CVOL 46 +#define PFUZE100_SW1CVOL_VSEL_M (0x3f<<0) +#define PFUZE100_SW1ACON 36 +#define PFUZE100_SW1ACON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1ACON_SPEED_M (0x3<<6) +#define PFUZE100_SW1CCON 49 +#define PFUZE100_SW1CCON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1CCON_SPEED_M (0x3<<6) + +extern u32 arm_max_freq; +extern u32 enable_ldo_mode; + +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "VDDCORE", + } +}; +static struct regulator_consumer_supply sw1c_consumers[] = { + { + .supply = "VDDSOC", + }, +}; + +static struct regulator_consumer_supply sw2_consumers[] = { + { + .supply = "MICVDD", + .dev_name = "0-001a", + } +}; +static struct regulator_consumer_supply sw4_consumers[] = { + { + .supply = "AUD_1V8", + } +}; +static struct regulator_consumer_supply swbst_consumers[] = { + { + .supply = "SWBST_5V", + } +}; +static struct regulator_consumer_supply vgen1_consumers[] = { + { + .supply = "VGEN1_1V5", + } +}; +static struct regulator_consumer_supply vgen2_consumers[] = { + { + .supply = "VGEN2_1V5", + } +}; +static struct regulator_consumer_supply vgen4_consumers[] = { + { + .supply = "DBVDD", + .dev_name = "0-001a", + }, + { + .supply = "AVDD", + .dev_name = "0-001a", + }, + { + .supply = "DCVDD", + .dev_name = "0-001a", + }, + { + .supply = "CPVDD", + .dev_name = "0-001a", + }, + { + .supply = "PLLVDD", + .dev_name = "0-001a", + } +}; +static struct regulator_consumer_supply vgen5_consumers[] = { + { + .supply = "VGEN5_2V8", + } +}; +static struct regulator_consumer_supply vgen6_consumers[] = { + { + .supply = "VGEN6_3V3", + } +}; + +static struct regulator_init_data sw1a_init = { + .constraints = { + .name = "PFUZE100_SW1A", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 650000, + .max_uV = 1437500, +#else + .min_uV = 300000, + .max_uV = 1875000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .boot_on = 1, + .always_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw1b_init = { + .constraints = { + .name = "PFUZE100_SW1B", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw1c_init = { + .constraints = { + .name = "PFUZE100_SW1C", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1c_consumers), + .consumer_supplies = sw1c_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "PFUZE100_SW2", +#if PFUZE100_SW2_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw2_consumers), + .consumer_supplies = sw2_consumers, +}; + +static struct regulator_init_data sw3a_init = { + .constraints = { + .name = "PFUZE100_SW3A", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw3b_init = { + .constraints = { + .name = "PFUZE100_SW3B", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "PFUZE100_SW4", +#if PFUZE100_SW4_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "PFUZE100_SWBST", + .min_uV = 5000000, + .max_uV = 5150000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(swbst_consumers), + .consumer_supplies = swbst_consumers, +}; + +static struct regulator_init_data vsnvs_init = { + .constraints = { + .name = "PFUZE100_VSNVS", + .min_uV = 1200000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vrefddr_init = { + .constraints = { + .name = "PFUZE100_VREFDDR", + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "PFUZE100_VGEN1", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "PFUZE100_VGEN2", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen2_consumers), + .consumer_supplies = vgen2_consumers, + +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "PFUZE100_VGEN3", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, +}; + +static struct regulator_init_data vgen4_init = { + .constraints = { + .name = "PFUZE100_VGEN4", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen4_consumers), + .consumer_supplies = vgen4_consumers, +}; + +static struct regulator_init_data vgen5_init = { + .constraints = { + .name = "PFUZE100_VGEN5", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen5_consumers), + .consumer_supplies = vgen5_consumers, +}; + +static struct regulator_init_data vgen6_init = { + .constraints = { + .name = "PFUZE100_VGEN6", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen6_consumers), + .consumer_supplies = vgen6_consumers, +}; + +static int pfuze100_init(struct mc_pfuze *pfuze) +{ + int ret, i; + unsigned char value; + /*use default mode(ldo bypass) if no param from cmdline*/ + if (enable_ldo_mode == LDO_MODE_DEFAULT) + enable_ldo_mode = LDO_MODE_BYPASSED; + /*read Device ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_DEVICEID, &value); + if (ret) + goto err; + if (value != 0x10) { + printk(KERN_ERR "wrong device id:%x!\n", value); + goto err; + } + + /*read Revision ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_REVID, &value); + if (ret) + goto err; + if (value == 0x10) { + printk(KERN_WARNING "PF100 1.0 chip found!\n"); + /* workaround ER1 of pfuze1.0: set all buck regulators in PWM mode + * except SW1C(APS) in normal and PFM mode in standby. + */ + for (i = 0; i < 7; i++) { + if (i == 2)/*SW1C*/ + value = 0xc;/*normal:APS mode;standby:PFM mode*/ + else + value = 0xd;/*normal:PWM mode;standby:PFM mode*/ + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } else { + /*set all switches APS in normal and PFM mode in standby*/ + for (i = 0; i < 7; i++) { + value = 0xc; + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } + /*use ldo active mode if use 1.2GHz,otherwise use ldo bypass mode*/ + if (arm_max_freq == CPU_AT_1_2GHz) { + /*VDDARM_IN 1.425*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2d); + if (ret) + goto err; + /*VDDSOC_IN 1.425V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2d); + if (ret) + goto err; + enable_ldo_mode = LDO_MODE_ENABLED; + } else if (enable_ldo_mode == LDO_MODE_BYPASSED) { + /*decrease VDDARM_IN/VDDSOC_IN,since we will use ldo bypass mode*/ + /*VDDARM_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*VDDSOC_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*set SW1AB/1C DVSPEED as 25mV step each 4us,quick than 16us before.*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1ACON, + PFUZE100_SW1ACON_SPEED_M, + PFUZE100_SW1ACON_SPEED_VAL); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CCON, + PFUZE100_SW1CCON_SPEED_M, + PFUZE100_SW1CCON_SPEED_VAL); + if (ret) + goto err; + } else if (enable_ldo_mode != LDO_MODE_BYPASSED) { + /*Increase VDDARM_IN/VDDSOC_IN to 1.375V in ldo active mode*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + } + return 0; +err: + printk(KERN_ERR "pfuze100 init error!\n"); + return -1; +} + +static struct pfuze_regulator_init_data mx6q_sabreauto_pfuze100_regulators[] = { + {.id = PFUZE100_SW1A, .init_data = &sw1a_init}, + {.id = PFUZE100_SW1B, .init_data = &sw1b_init}, + {.id = PFUZE100_SW1C, .init_data = &sw1c_init}, + {.id = PFUZE100_SW2, .init_data = &sw2_init}, + {.id = PFUZE100_SW3A, .init_data = &sw3a_init}, + {.id = PFUZE100_SW3B, .init_data = &sw3b_init}, + {.id = PFUZE100_SW4, .init_data = &sw4_init}, + {.id = PFUZE100_SWBST, .init_data = &swbst_init}, + {.id = PFUZE100_VSNVS, .init_data = &vsnvs_init}, + {.id = PFUZE100_VREFDDR, .init_data = &vrefddr_init}, + {.id = PFUZE100_VGEN1, .init_data = &vgen1_init}, + {.id = PFUZE100_VGEN2, .init_data = &vgen2_init}, + {.id = PFUZE100_VGEN3, .init_data = &vgen3_init}, + {.id = PFUZE100_VGEN4, .init_data = &vgen4_init}, + {.id = PFUZE100_VGEN5, .init_data = &vgen5_init}, + {.id = PFUZE100_VGEN6, .init_data = &vgen6_init}, +}; + +static struct pfuze_platform_data pfuze100_plat = { + .flags = PFUZE_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx6q_sabreauto_pfuze100_regulators), + .regulators = mx6q_sabreauto_pfuze100_regulators, + .pfuze_init = pfuze100_init, +}; + +static struct i2c_board_info __initdata pfuze100_i2c_device = { + I2C_BOARD_INFO(PFUZE100_I2C_DEVICE_NAME, PFUZE100_I2C_ADDR), + .platform_data = &pfuze100_plat, +}; + +int __init mx6q_sabresd_init_pfuze100(u32 int_gpio) +{ + pfuze100_i2c_device.irq = gpio_to_irq(int_gpio); /*update INT gpio */ + return i2c_register_board_info(1, &pfuze100_i2c_device, 1); +} diff --git a/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c new file mode 100644 index 00000000..7cebb8f2 --- /dev/null +++ b/arch/arm/mach-mx6/mx6sl_arm2_pmic_pfuze100.c @@ -0,0 +1,531 @@ +/* + * 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., 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/err.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/pfuze.h> +#include <mach/irqs.h> +#include <mach/system.h> +#include "cpu_op-mx6.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 PFUZE100_I2C_DEVICE_NAME "pfuze100" +/* 7-bit I2C bus slave address */ +#define PFUZE100_I2C_ADDR (0x08) +#define PFUZE100_DEVICEID (0x0) +#define PFUZE100_REVID (0x3) +#define PFUZE100_SW1AMODE (0x23) +#define PFUZE100_SW1ACON 36 +#define PFUZE100_SW1ACON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1ACON_SPEED_M (0x3<<6) +#define PFUZE100_SW1CCON 49 +#define PFUZE100_SW1CCON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1CCON_SPEED_M (0x3<<6) +#define PFUZE100_SW1AVOL 32 +#define PFUZE100_SW1AVOL_VSEL_M (0x3f<<0) +#define PFUZE100_SW1CVOL 46 +#define PFUZE100_SW1CVOL_VSEL_M (0x3f<<0) +extern u32 enable_ldo_mode; +extern u32 arm_max_freq; + + +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "VDDCORE", + } +}; +static struct regulator_consumer_supply sw1c_consumers[] = { + { + .supply = "VDDSOC", + }, +}; + +static struct regulator_consumer_supply sw2_consumers[] = { + { + .supply = "MICVDD", + .dev_name = "1-001a", + }, + { + .supply = "DBVDD", + .dev_name = "1-001a", + } + +}; +static struct regulator_consumer_supply sw4_consumers[] = { + { + .supply = "AUD_1V8", + } +}; +static struct regulator_consumer_supply swbst_consumers[] = { + { + .supply = "SWBST_5V", + } +}; +static struct regulator_consumer_supply vgen1_consumers[] = { + { + .supply = "VGEN1_1V5", + } +}; +static struct regulator_consumer_supply vgen2_consumers[] = { + { + .supply = "VGEN2_1V5", + } +}; +static struct regulator_consumer_supply vgen4_consumers[] = { + { + .supply = "AVDD", + .dev_name = "1-001a", + }, + { + .supply = "DCVDD", + .dev_name = "1-001a", + }, + { + .supply = "CPVDD", + .dev_name = "1-001a", + }, + { + .supply = "PLLVDD", + .dev_name = "1-001a", + } +}; +static struct regulator_consumer_supply vgen5_consumers[] = { + { + .supply = "VGEN5_2V8", + } +}; +static struct regulator_consumer_supply vgen6_consumers[] = { + { + .supply = "VGEN6_3V3", + } +}; + +static struct regulator_init_data sw1a_init = { + .constraints = { + .name = "PFUZE100_SW1A", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 650000, + .max_uV = 1437500, +#else + .min_uV = 300000, + .max_uV = 1875000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .boot_on = 1, + .always_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw1b_init = { + .constraints = { + .name = "PFUZE100_SW1B", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw1c_init = { + .constraints = { + .name = "PFUZE100_SW1C", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1c_consumers), + .consumer_supplies = sw1c_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "PFUZE100_SW2", +#if PFUZE100_SW2_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw2_consumers), + .consumer_supplies = sw2_consumers, +}; + +static struct regulator_init_data sw3a_init = { + .constraints = { + .name = "PFUZE100_SW3A", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw3b_init = { + .constraints = { + .name = "PFUZE100_SW3B", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "PFUZE100_SW4", +#if PFUZE100_SW4_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "PFUZE100_SWBST", + .min_uV = 5000000, + .max_uV = 5150000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(swbst_consumers), + .consumer_supplies = swbst_consumers, +}; + +static struct regulator_init_data vsnvs_init = { + .constraints = { + .name = "PFUZE100_VSNVS", + .min_uV = 1200000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vrefddr_init = { + .constraints = { + .name = "PFUZE100_VREFDDR", + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "PFUZE100_VGEN1", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "PFUZE100_VGEN2", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen2_consumers), + .consumer_supplies = vgen2_consumers, + +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "PFUZE100_VGEN3", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 0, + .boot_on = 0, + }, +}; + +static struct regulator_init_data vgen4_init = { + .constraints = { + .name = "PFUZE100_VGEN4", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen4_consumers), + .consumer_supplies = vgen4_consumers, +}; + +static struct regulator_init_data vgen5_init = { + .constraints = { + .name = "PFUZE100_VGEN5", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen5_consumers), + .consumer_supplies = vgen5_consumers, +}; + +static struct regulator_init_data vgen6_init = { + .constraints = { + .name = "PFUZE100_VGEN6", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen6_consumers), + .consumer_supplies = vgen6_consumers, +}; + +static int pfuze100_init(struct mc_pfuze *pfuze) +{ + int ret, i; + unsigned char value; + + /*use default mode(ldo bypass) if no param from cmdline*/ + if (enable_ldo_mode == LDO_MODE_DEFAULT) + enable_ldo_mode = LDO_MODE_BYPASSED; + /*read Device ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_DEVICEID, &value); + if (ret) + goto err; + if (value != 0x10) { + printk(KERN_ERR "wrong device id:%x!\n", value); + goto err; + } + + /*read Revision ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_REVID, &value); + if (ret) + goto err; + if (value == 0x10) { + printk(KERN_WARNING "PF100 1.0 chip found!\n"); + /* workaround ER1 of pfuze1.0: set all buck regulators in PWM mode + * except SW1C(APS) in normal and PFM mode in standby. + */ + for (i = 0; i < 7; i++) { + if (i == 2)/*SW1C*/ + value = 0xc;/*normal:APS mode;standby:PFM mode*/ + else + value = 0xd;/*normal:PWM mode;standby:PFM mode*/ + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } else { + /*set all switches APS in normal and PFM mode in standby*/ + for (i = 0; i < 7; i++) { + value = 0xc; + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } + /*use ldo active mode if use 1.2GHz,otherwise use ldo bypass mode*/ + if (arm_max_freq == CPU_AT_1_2GHz) { + /*VDDARM_IN 1.47*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2f); + if (ret) + goto err; + /*VDDSOC_IN 1.475V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2f); + if (ret) + goto err; + enable_ldo_mode = LDO_MODE_ENABLED; + } else if (enable_ldo_mode == LDO_MODE_BYPASSED) { + /*decrease VDDARM_IN/VDDSOC_IN,since we will use dynamic ldo bypass + *mode or ldo bypass mode here.*/ + /*VDDARM_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*VDDSOC_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*set SW1AB/SW1C DVSPEED as 25mV step each 4us,quick than 16us before.*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1ACON, + PFUZE100_SW1ACON_SPEED_M, + PFUZE100_SW1ACON_SPEED_VAL); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CCON, + PFUZE100_SW1CCON_SPEED_M, + PFUZE100_SW1CCON_SPEED_VAL); + if (ret) + goto err; + } else if (enable_ldo_mode != LDO_MODE_BYPASSED) { + /*Increase VDDARM_IN/VDDSOC_IN to 1.375V in ldo active mode*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + } + return 0; +err: + printk(KERN_ERR "pfuze100 init error!\n"); + return -1; +} + +static struct pfuze_regulator_init_data mx6q_sabreauto_pfuze100_regulators[] = { + {.id = PFUZE100_SW1A, .init_data = &sw1a_init}, + {.id = PFUZE100_SW1B, .init_data = &sw1b_init}, + {.id = PFUZE100_SW1C, .init_data = &sw1c_init}, + {.id = PFUZE100_SW2, .init_data = &sw2_init}, + {.id = PFUZE100_SW3A, .init_data = &sw3a_init}, + {.id = PFUZE100_SW3B, .init_data = &sw3b_init}, + {.id = PFUZE100_SW4, .init_data = &sw4_init}, + {.id = PFUZE100_SWBST, .init_data = &swbst_init}, + {.id = PFUZE100_VSNVS, .init_data = &vsnvs_init}, + {.id = PFUZE100_VREFDDR, .init_data = &vrefddr_init}, + {.id = PFUZE100_VGEN1, .init_data = &vgen1_init}, + {.id = PFUZE100_VGEN2, .init_data = &vgen2_init}, + {.id = PFUZE100_VGEN3, .init_data = &vgen3_init}, + {.id = PFUZE100_VGEN4, .init_data = &vgen4_init}, + {.id = PFUZE100_VGEN5, .init_data = &vgen5_init}, + {.id = PFUZE100_VGEN6, .init_data = &vgen6_init}, +}; + +static struct pfuze_platform_data pfuze100_plat = { + .flags = PFUZE_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx6q_sabreauto_pfuze100_regulators), + .regulators = mx6q_sabreauto_pfuze100_regulators, + .pfuze_init = pfuze100_init, +}; + +static struct i2c_board_info __initdata pfuze100_i2c_device = { + I2C_BOARD_INFO(PFUZE100_I2C_DEVICE_NAME, PFUZE100_I2C_ADDR), + .platform_data = &pfuze100_plat, +}; + +int __init mx6sl_arm2_init_pfuze100(u32 int_gpio) +{ + if (int_gpio) + pfuze100_i2c_device.irq = gpio_to_irq(int_gpio); /*update INT gpio */ + return i2c_register_board_info(0, &pfuze100_i2c_device, 1); +} diff --git a/arch/arm/mach-mx6/mx6sl_ddr.S b/arch/arm/mach-mx6/mx6sl_ddr.S new file mode 100644 index 00000000..bac1e7c2 --- /dev/null +++ b/arch/arm/mach-mx6/mx6sl_ddr.S @@ -0,0 +1,570 @@ +/* + * Copyright (C) 2012-2013 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> +#include <mach/hardware.h> +.extern iram_tlb_phys_addr +.extern mx6sl_ddr_freq_base +.extern mx6sl_ddr_freq_phys_addr + + .macro mx6sl_switch_to_24MHz + + /* Set MMDC clock to be sourced from PLL3. */ + /* Ensure first periph2_clk2 is sourced from PLL3. */ + /* Set the PERIPH2_CLK2_PODF to divide by 2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x7 + orr r6, r6, #0x1 + str r6, [r2, #0x14] + + /* Select PLL3 to source MMDC. */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* Swtich periph2_clk_sel to run from PLL3. */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch1: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch1 + + /* Need to clock gate the 528 PFDs before + * powering down PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC + */ + ldr r6, [r3, #0x100] + orr r6, r6, #0x800000 + str r6, [r3, #0x100] + + /* Set PLL2 to bypass state. We should be here + *only if MMDC is not sourced from PLL2.*/ + ldr r6, [r3, #0x30] + orr r6, r6, #0x10000 + str r6, [r3, #0x30] + + ldr r6, [r3, #0x30] + orr r6, r6, #0x1000 + str r6, [r3, #0x30] + + /* Ensure pre_periph2_clk_mux is set to pll2 */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x600000 + str r6, [r2, #0x18] + + /* Set MMDC clock to be sourced from the bypassed PLL2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch2: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch2 + + /* Now move MMDC back to periph2_clk2 source. + * after selecting PLL2 as the option. + */ + /* Select PLL2 as the source. */ + ldr r6, [r2, #0x18] + orr r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* set periph2_clk2_podf to divide by 1. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x7 + str r6, [r2, #0x14] + + /* Now move periph2_clk to periph2_clk2 source */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch3: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch3 + + /* Now set the MMDC PODF back to 1.*/ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + str r6, [r2, #0x14] + +mmdc_podf0: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf0 + + .endm + + .macro ddr_switch_400MHz + + /* Set MMDC divider first, in case PLL3 is at 480MHz. */ + ldr r6, [r3, #0x10] + and r6, r6, #0x10000 + cmp r6, #0x10000 + beq pll3_in_bypass + /* Set MMDC divder to divide by 2. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x8 + str r6, [r2, #0x14] + +mmdc_podf: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf + +pll3_in_bypass: + + /* Check if we are switching between + * 400Mhz <-> 100MHz.If so, we should + * try to source MMDC from PLL2_200M. + */ + cmp r1, #0 + beq not_low_bus_freq + + /* Ensure that MMDC is sourced from PLL2 mux first. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch4: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch4 + +not_low_bus_freq: + /* Now ensure periph2_clk2_sel mux is set to PLL3 */ + ldr r6, [r2, #0x18] + bic r6, r6, #0x100000 + str r6, [r2, #0x18] + + /* Now switch MMDC to PLL3. */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x4000000 + str r6, [r2, #0x14] + +periph2_clk_switch5: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne periph2_clk_switch5 + + /* Check if PLL2 is already unlocked. + * If so do nothing with PLL2. + */ + cmp r1, #0 + beq pll2_already_on + + /* Now power up PLL2 and unbypass it. */ + ldr r6, [r3, #0x30] + bic r6, r6, #0x1000 + str r6, [r3, #0x30] + + /* Make sure PLL2 has locked.*/ +wait_for_pll_lock: + ldr r6, [r3, #0x30] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock + + ldr r6, [r3, #0x30] + bic r6, r6, #0x10000 + str r6, [r3, #0x30] + + /* Need to enable the 528 PFDs after + * powering up PLL2. + * Only the PLL2_PFD2_400M should be ON + * as it feeds the MMDC. Rest should have + * been managed by clock code. + */ + ldr r6, [r3, #0x100] + bic r6, r6, #0x800000 + str r6, [r3, #0x100] + +pll2_already_on: + /* Now switch MMDC clk back to pll2_mux option. */ + /* Ensure pre_periph2_clk2 is set to pll2_pfd_400M */ + /* If switching to audio DDR freq, set the + * pre_periph2_clk2 to PLL2_PFD_200M + */ + ldr r6, =400000000 + cmp r6, r0 + bne use_pll2_pfd_200M + + ldr r6, [r2, #0x18] + bic r6, r6, #0x600000 + orr r6, r6, #0x200000 + str r6, [r2, #0x18] + ldr r6, =400000000 + b cont2 + +use_pll2_pfd_200M: + ldr r6, [r2, #0x18] + orr r6, r6, #0x600000 + str r6, [r2, #0x18] + ldr r6, =200000000 + +cont2: + ldr r4, [r2, #0x14] + bic r4, r4, #0x4000000 + str r4, [r2, #0x14] + +periph2_clk_switch6: + ldr r4, [r2, #0x48] + cmp r4, #0 + bne periph2_clk_switch6 + +change_divider_only: + /* Calculate the MMDC divider + * based on the requested freq. + */ + ldr r4, =0 +Loop2: + sub r6, r6, r0 + cmp r6, r0 + blt Div_Found + add r4, r4, #1 + bgt Loop2 + + /* Shift divider into correct offset. */ + lsl r4, r4, #3 +Div_Found: + /* Set the MMDC PODF. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, r4 + str r6, [r2, #0x14] + +mmdc_podf1: + ldr r6, [r2, #0x48] + cmp r6, #0 + bne mmdc_podf1 + + .endm + + .macro mmdc_clk_lower_100MHz + + /* Prior to reducing the DDR frequency (at 528/400 MHz), + read the Measure unit count bits (MU_UNIT_DEL_NUM) */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + /* Original MU unit count */ + mov r6, r6, LSR #16 + ldr r4, =0x3FF + and r6, r6, r4 + /* Original MU unit count * 2 */ + mov r7, r6, LSL #1 + /* Bypass the automatic measure unit when below 100 MHz + by setting the Measure unit bypass enable bit (MU_BYP_EN) */ + ldr r6, [r8, r5] + orr r6, r6, #0x400 + str r6, [r8, r5] + /* Double the measure count value read in step 1 and program it in the + * measurement bypass bits (MU_BYP_VAL) of the MMDC PHY Measure Unit + * Register for the reduced frequency operation below 100 MHz + */ + ldr r6, [r8, r5] + ldr r4, =0x3FF + bic r6, r6, r4 + orr r6, r6, r7 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure + + .endm + + .macro mmdc_clk_above_100MHz + + /* Make sure that the PHY measurement unit is NOT in bypass mode */ + ldr r5, =0x8B8 + ldr r6, [r8, r5] + bic r6, r6, #0x400 + str r6, [r8, r5] + /* Now perform a Force Measurement. */ + ldr r6, [r8, r5] + orr r6, r6, #0x800 + str r6, [r8, r5] + /* Wait for FRC_MSR to clear. */ +force_measure1: + ldr r6, [r8, r5] + and r6, r6, #0x800 + cmp r6, #0x0 + bne force_measure1 + .endm + + .align 3 +/* + * mx6sl_ddr_iram + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + * r0 : DDR freq. + * r1: low_bus_freq_mode flag + */ +ENTRY(mx6sl_ddr_iram) + + push {r4-r10} + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + +mx6sl_ddr_freq_change: + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* + * Sync L2 and then disable it. + */ + dsb + ldr r4, =L2_BASE_ADDR + add r4, r4, #PERIPBASE_VIRT + ldr r6, =0x0 + str r6, [r4, #0x730] + /* Disable L2. */ + str r6, [r4, #0x100] + + dsb + isb + + ldr r3, =ANATOP_BASE_ADDR + add r3, r3, #PERIPBASE_VIRT + ldr r2, =CCM_BASE_ADDR + add r2, r2, #PERIPBASE_VIRT + ldr r8, =MMDC_P0_BASE_ADDR + add r8, r8, #PERIPBASE_VIRT + + /* Disable Automatic power savings. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x01 + str r6, [r8, #0x404] + + /* Disable MMDC power down timer. */ + /*MMDC0_MDPDC disable power down timer */ + ldr r6, [r8, #0x4] + bic r6, r6, #0xff00 + str r6, [r8, #0x4] + + /* Delay for a while */ + ldr r10, =10 +delay1: + ldr r7, =0 +cont1: + ldr r6, [r8, r7] + add r7, r7, #4 + cmp r7, #16 + bne cont1 + sub r10, r10, #1 + cmp r10, #0 + bgt delay1 + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_set_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r8, #0x410] + orr r6, r6, #0x100 + str r6, [r8, #0x410] + + ldr r10, =100000000 + cmp r0, r10 + bgt set_ddr_mu_above_100 + mmdc_clk_lower_100MHz + +set_ddr_mu_above_100: + ldr r10, =24000000 + cmp r0, r10 + beq set_to_24MHz + + ddr_switch_400MHz + ldr r10, =100000000 + cmp r0, r10 + blt done + mmdc_clk_above_100MHz + b done + +set_to_24MHz: + mx6sl_switch_to_24MHz + +done: + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x01 + str r6, [r8, #0x404] + + ldr r10, =24000000 + cmp r0, r10 + beq skip_power_down + + /* Enable MMDC power down timer. */ + ldr r6, [r8, #0x4] + orr r6, r6, #0x5500 + str r6, [r8, #0x4] + +skip_power_down: + /* clear SBS - unblock DDR accesses */ + ldr r6, [r8, #0x410] + bic r6, r6, #0x100 + str r6, [r8, #0x410] + + /* Enable L2. */ + ldr r1, =L2_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r6, =0x1 + str r6, [r1, #0x100] + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + dsb + isb + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + pop {r4-r10} + + /* Restore registers */ + mov pc, lr diff --git a/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c new file mode 100644 index 00000000..14bd33ff --- /dev/null +++ b/arch/arm/mach-mx6/mx6sl_evk_pmic_pfuze100.c @@ -0,0 +1,536 @@ +/* + * 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., 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/err.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/pfuze.h> +#include <mach/irqs.h> +#include <mach/system.h> +#include "cpu_op-mx6.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 PFUZE100_I2C_DEVICE_NAME "pfuze100" +/* 7-bit I2C bus slave address */ +#define PFUZE100_I2C_ADDR (0x08) +#define PFUZE100_DEVICEID (0x0) +#define PFUZE100_REVID (0x3) +#define PFUZE100_SW1AMODE (0x23) +#define PFUZE100_SW1ACON 36 +#define PFUZE100_SW1ACON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1ACON_SPEED_M (0x3<<6) +#define PFUZE100_SW1CCON 49 +#define PFUZE100_SW1CCON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1CCON_SPEED_M (0x3<<6) +#define PFUZE100_SW1AVOL 32 +#define PFUZE100_SW1AVOL_VSEL_M (0x3f<<0) +#define PFUZE100_SW1CVOL 46 +#define PFUZE100_SW1CVOL_VSEL_M (0x3f<<0) + +extern u32 enable_ldo_mode; +extern u32 arm_max_freq; +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "VDDCORE", + } +}; +static struct regulator_consumer_supply sw1c_consumers[] = { + { + .supply = "VDDSOC", + }, +}; + +static struct regulator_consumer_supply sw2_consumers[] = { + { + .supply = "MICVDD", + .dev_name = "1-001a", + } +}; +static struct regulator_consumer_supply sw4_consumers[] = { + { + .supply = "AUD_1V8", + } +}; +static struct regulator_consumer_supply swbst_consumers[] = { + { + .supply = "SWBST_5V", + } +}; +static struct regulator_consumer_supply vgen1_consumers[] = { + { + .supply = "VGEN1_1V5", + } +}; +static struct regulator_consumer_supply vgen2_consumers[] = { + { + .supply = "VGEN2_1V5", + } +}; +static struct regulator_consumer_supply vgen3_consumers[] = { + { + .supply = "AVDD", + .dev_name = "1-001a", + }, + { + .supply = "DCVDD", + .dev_name = "1-001a", + }, + { + .supply = "CPVDD", + .dev_name = "1-001a", + }, + { + .supply = "PLLVDD", + .dev_name = "1-001a", + }, + { + .supply = "DBVDD", + .dev_name = "1-001a", + } +}; +static struct regulator_consumer_supply vgen4_consumers[] = { + { + .supply = "VGEN4_1V8", + } +}; +static struct regulator_consumer_supply vgen5_consumers[] = { + { + .supply = "VGEN5_2V8", + } +}; +static struct regulator_consumer_supply vgen6_consumers[] = { + { + .supply = "VGEN6_2V8", + } +}; + +static struct regulator_init_data sw1a_init = { + .constraints = { + .name = "PFUZE100_SW1A", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 650000, + .max_uV = 1437500, +#else + .min_uV = 300000, + .max_uV = 1875000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .boot_on = 1, + .always_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +}; + +static struct regulator_init_data sw1b_init = { + .constraints = { + .name = "PFUZE100_SW1B", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw1c_init = { + .constraints = { + .name = "PFUZE100_SW1C", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + .state_mem = { + .uV = 975000,/*0.9V+6%*/ + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1c_consumers), + .consumer_supplies = sw1c_consumers, +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "PFUZE100_SW2", +#if PFUZE100_SW2_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw2_consumers), + .consumer_supplies = sw2_consumers, +}; + +static struct regulator_init_data sw3a_init = { + .constraints = { + .name = "PFUZE100_SW3A", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw3b_init = { + .constraints = { + .name = "PFUZE100_SW3B", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "PFUZE100_SW4", +#if PFUZE100_SW4_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "PFUZE100_SWBST", + .min_uV = 5000000, + .max_uV = 5150000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(swbst_consumers), + .consumer_supplies = swbst_consumers, +}; + +static struct regulator_init_data vsnvs_init = { + .constraints = { + .name = "PFUZE100_VSNVS", + .min_uV = 1200000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vrefddr_init = { + .constraints = { + .name = "PFUZE100_VREFDDR", + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "PFUZE100_VGEN1", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "PFUZE100_VGEN2", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen2_consumers), + .consumer_supplies = vgen2_consumers, + +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "PFUZE100_VGEN3", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen3_consumers), + .consumer_supplies = vgen3_consumers, +}; + +static struct regulator_init_data vgen4_init = { + .constraints = { + .name = "PFUZE100_VGEN4", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen4_consumers), + .consumer_supplies = vgen4_consumers, +}; + +static struct regulator_init_data vgen5_init = { + .constraints = { + .name = "PFUZE100_VGEN5", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen5_consumers), + .consumer_supplies = vgen5_consumers, +}; + +static struct regulator_init_data vgen6_init = { + .constraints = { + .name = "PFUZE100_VGEN6", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen6_consumers), + .consumer_supplies = vgen6_consumers, +}; + +static int pfuze100_init(struct mc_pfuze *pfuze) +{ + int ret, i; + unsigned char value; + /*use default mode(ldo bypass) if no param from cmdline*/ + if (enable_ldo_mode == LDO_MODE_DEFAULT) + enable_ldo_mode = LDO_MODE_BYPASSED; + /*read Device ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_DEVICEID, &value); + if (ret) + goto err; + if (value != 0x10) { + printk(KERN_ERR "wrong device id:%x!\n", value); + goto err; + } + + /*read Revision ID*/ + ret = pfuze_reg_read(pfuze, PFUZE100_REVID, &value); + if (ret) + goto err; + if (value == 0x10) { + printk(KERN_WARNING "PF100 1.0 chip found!\n"); + /* workaround ER1 of pfuze1.0: set all buck regulators in PWM mode + * except SW1C(APS) in normal and PFM mode in standby. + */ + for (i = 0; i < 7; i++) { + if (i == 2)/*SW1C*/ + value = 0xc;/*normal:APS mode;standby:PFM mode*/ + else + value = 0xd;/*normal:PWM mode;standby:PFM mode*/ + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } else { + /*set all switches APS in normal and PFM mode in standby*/ + for (i = 0; i < 7; i++) { + value = 0xc; + ret = pfuze_reg_write(pfuze, + PFUZE100_SW1AMODE + (i * 7), + value); + if (ret) + goto err; + } + + } + /*use ldo active mode if use 1.2GHz,otherwise use ldo bypass mode*/ + if (arm_max_freq == CPU_AT_1_2GHz) { + /*VDDARM_IN 1.47*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2f); + if (ret) + goto err; + /*VDDSOC_IN 1.475V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2f); + if (ret) + goto err; + enable_ldo_mode = LDO_MODE_ENABLED; + } else if (enable_ldo_mode == LDO_MODE_BYPASSED) { + /*decrease VDDARM_IN/VDDSOC_IN,since we will use dynamic ldo bypass + *mode or ldo bypass mode here.*/ + /*VDDARM_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x28); + if (ret) + goto err; + /*VDDSOC_IN 1.3V*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x28); + if (ret) + goto err; + + /*set SW1AB/SW1CDVSPEED as 25mV step each 4us,quick than 16us before.*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1ACON, + PFUZE100_SW1ACON_SPEED_M, + PFUZE100_SW1ACON_SPEED_VAL); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CCON, + PFUZE100_SW1CCON_SPEED_M, + PFUZE100_SW1CCON_SPEED_VAL); + if (ret) + goto err; + } else if (enable_ldo_mode != LDO_MODE_BYPASSED) { + /*Increase VDDARM_IN/VDDSOC_IN to 1.375V in ldo active mode*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1AVOL, + PFUZE100_SW1AVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CVOL, + PFUZE100_SW1CVOL_VSEL_M, + 0x2b); + if (ret) + goto err; + } + return 0; +err: + printk(KERN_ERR "pfuze100 init error!\n"); + return -1; +} + +static struct pfuze_regulator_init_data mx6q_sabreauto_pfuze100_regulators[] = { + {.id = PFUZE100_SW1A, .init_data = &sw1a_init}, + {.id = PFUZE100_SW1B, .init_data = &sw1b_init}, + {.id = PFUZE100_SW1C, .init_data = &sw1c_init}, + {.id = PFUZE100_SW2, .init_data = &sw2_init}, + {.id = PFUZE100_SW3A, .init_data = &sw3a_init}, + {.id = PFUZE100_SW3B, .init_data = &sw3b_init}, + {.id = PFUZE100_SW4, .init_data = &sw4_init}, + {.id = PFUZE100_SWBST, .init_data = &swbst_init}, + {.id = PFUZE100_VSNVS, .init_data = &vsnvs_init}, + {.id = PFUZE100_VREFDDR, .init_data = &vrefddr_init}, + {.id = PFUZE100_VGEN1, .init_data = &vgen1_init}, + {.id = PFUZE100_VGEN2, .init_data = &vgen2_init}, + {.id = PFUZE100_VGEN3, .init_data = &vgen3_init}, + {.id = PFUZE100_VGEN4, .init_data = &vgen4_init}, + {.id = PFUZE100_VGEN5, .init_data = &vgen5_init}, + {.id = PFUZE100_VGEN6, .init_data = &vgen6_init}, +}; + +static struct pfuze_platform_data pfuze100_plat = { + .flags = PFUZE_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx6q_sabreauto_pfuze100_regulators), + .regulators = mx6q_sabreauto_pfuze100_regulators, + .pfuze_init = pfuze100_init, +}; + +static struct i2c_board_info __initdata pfuze100_i2c_device = { + I2C_BOARD_INFO(PFUZE100_I2C_DEVICE_NAME, PFUZE100_I2C_ADDR), + .platform_data = &pfuze100_plat, +}; + +int __init mx6sl_evk_init_pfuze100(u32 int_gpio) +{ + if (int_gpio) + pfuze100_i2c_device.irq = gpio_to_irq(int_gpio); /*update INT gpio */ + return i2c_register_board_info(0, &pfuze100_i2c_device, 1); +} diff --git a/arch/arm/mach-mx6/mx6sl_ntx_io.c b/arch/arm/mach-mx6/mx6sl_ntx_io.c new file mode 100755 index 00000000..403509d1 --- /dev/null +++ b/arch/arm/mach-mx6/mx6sl_ntx_io.c @@ -0,0 +1,2605 @@ +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/input.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/iomux-mx6sl.h> +#include <asm/uaccess.h> +#include <asm/system.h> + + +#include <generated/autoconf.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/wait.h> +#include <linux/miscdevice.h> +#include <linux/irq.h> +#include <linux/freezer.h> + +#include <mach/common.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> +#include <mach/iomux-v3.h> + + +#include <linux/mfd/ricoh619.h> +#include <linux/rtc/rtc-ricoh619.h> +#include <linux/power/ricoh619_battery.h> +#include <linux/regulator/ricoh619-regulator.h> + +#define GDEBUG 0 +#include <linux/gallen_dbg.h> + +//#define GPIOFN_PWRKEY 1 + +//#ifdef GPIOFN_PWRKEY//[ + #include "../../../drivers/input/keyboard/gpiofn.h" +//#endif //]GPIOFN_PWRKEY + +#include "../../../drivers/video/mxc/lk_tps65185.h" +#include "../../../drivers/video/mxc/lk_fp9928.h" + + +//#define _WIFI_ALWAYS_ON_ // wifi always on for startic + +#include "board-mx6sl_ntx.h" +#include "ntx_hwconfig.h" + +#define DEVICE_NAME "ntx_io" // "pvi_io" +#define DEVICE_MINJOR 190 + +#define CM_PLATFORM 164 +#define CM_HWCONFIG 165 +#define CM_SET_HWCONFIG 166 + +#define CM_SD_IN 117 +#define AC_IN 118 +#define CM_PWR_ON2 112 +#define CM_AUDIO_PWR 113 +#define CM_POWER_BTN 110 +#define CM_USB_Plug_IN 108 +#define CM_AC_CK 109 +#define CM_CHARGE_STATUS 204 +#define CM_nLED 101 +#define CM_nLED_CPU 102 +#define POWER_OFF_COMMAND 0xC0 // 192 +#define SYS_RESET_COMMAND 193 // Joseph 091223 +#define GET_LnBATT_CPU 0XC2 // 194 +#define GET_VBATT_TH 0XC3 // 195 +#define CM_SIGUSR1 104 +//kay 20081110 for detecting SD write protect +#define CM_SD_PROTECT 120 +#define SYS_AUTO_POWER_ON 0xC4 // 196 Joseph 120620 + +//20090216 for detecting controller +#define CM_CONTROLLER 121 + +//20090416 for detecting controller +#define CM_USB_AC_STATUS 122 +#define CM_RTC_WAKEUP_FLAG 123 +#define CM_SYSTEM_RESET 124 +#define CM_USB_HOST_PWR 125 +#define CM_BLUETOOTH_PWR 126 +#define CM_TELLPID 99 +#define CM_LED_BLINK 127 +#define CM_TOUCH_LOCK 128 +#define CM_DEVICE_MODULE 129 +#define CM_BLUETOOTH_RESET 130 +#define CM_DEVICE_INFO 131 + +//Joseph 091211 for 3G +#define CM_3G_POWER 150 +#define CM_3G_RF_OFF 151 +#define CM_3G_RESET 152 +#define CM_3G_GET_WAKE_STATUS 153 + +//Joseph 091209 +#define CM_ROTARY_STATUS 200 +#define CM_GET_KEY_STATUS 201 +#define CM_GET_WHEEL_KEY_STATUS 202 +#define CM_GET_KL25_STATUS 203 +#define CM_GET_KL25_ACTION 199 +#define POWER_KEEP_COMMAND 205 +#define CM_GET_BATTERY_STATUS 206 +#define CM_SET_ALARM_WAKEUP 207 +#define CM_WIFI_CTRL 208 +#define CM_ROTARY_ENABLE 209 + +#define CM_GET_UP_VERSION 215 + +// gallen 100621 +// Audio functions ... +#define CM_AUDIO_GET_VOLUME 230 +#define CM_AUDIO_SET_VOLUME 240 +#define CM_FRONT_LIGHT_SET 241 +#define CM_FRONT_LIGHT_AVAILABLE 242 +#define CM_FRONT_LIGHT_DUTY 243 +#define CM_FRONT_LIGHT_FREQUENCY 244 +#define CM_FRONT_LIGHT_R_EN 245 +#define CM_FRONT_LIGHT_HT68F20_SETDUTY 246 +#define CM_FRONT_LIGHT_GETDUTY 247 + +#define CM_GET_KEYS 107 + + +#ifdef GPIOFN_PWRKEY//[ +static void power_key_chk(unsigned long v); + +static int PWR_SW_func(int iGPIOVal) +{ + printk("[%s]\n",__FUNCTION__); + power_key_chk(0); +} + +static GPIODATA gtNTX_PWR_GPIO_data = { + .pfnGPIO = PWR_SW_func, + .uGPIO = gMX6SL_PWR_SW, + .szName = "PWR_SW", + .tPADCtrl = MX50_PAD_CSPI_MISO__GPIO_4_10, + .uiIRQType = IRQF_TRIGGER_RISING|IRQF_TRIGGER_FALLING, + .iWakeup = 1, +}; + +#endif //]GPIOFN_PWRKEY + + +unsigned short __EBRMAIN_PID__ = 0; + +unsigned char __USB_ADAPTOR__=0; +EXPORT_SYMBOL(__USB_ADAPTOR__); + +static int Driver_Count = -1; +unsigned char __TOUCH_LOCK__= 0; +int gSleep_Mode_Suspend; + +extern volatile NTX_HWCONFIG *gptHWCFG; + +extern volatile int giISD_3V3_ON_Ctrl ; + +typedef enum __DEV_MODULE_NAME{ + EB500=0, + EB600=1, + EB600E=2, + EB600EM=3, + COOKIE=4, +}__dev_module_name; + +typedef enum __DEV_MODULE_CPU{ + CPU_S3C2410=0, + CPU_S3C2440=1, + CPU_S3C2416=2, + CPU_CORETEX_A8=3, + CPU_COOKIE=4, +}__dev_module_cpu; + +typedef enum __DEV_MODULE_CONTROLLER{ + CONTROLLER_PVI=0, + CONTROLLER_EPSON=1, + CONTROLLER_SW=2, +}__dev_module_controller; + +typedef enum __DEV_MODULE_WIFI{ + WIFI_NONE=0, + WIFI_MARVELL=1, + WIFI_OTHER=2, +}__dev_module_wifi; + +typedef enum __DEV_MODULE_BLUETOOTH{ + BLUETOOTH_NONE=0, + BLUETOOTH_TI=1, + BLUETOOTH_CSR=2, +}__devi_module_bluetooth; + +struct ebook_device_info { + char device_name; + char cpu; + char controller; + char wifi; + char bluetooth; +}; + + +static volatile int giFL_ON=0; + +static unsigned short FL_table0[100]={ +0x0001,0x0006,0x0007,0x0009,0x000C,0x000D,0x000E,0x000F,0x0011,0x0012, +0x0014,0x0015,0x0017,0x0018,0x001A,0x001B,0x001C,0x001D,0x001F,0x0020, +0x0022,0x0023,0x0025,0x0027,0x0028,0x002A,0x002B,0x002D,0x002E,0x0030, +0x0031,0x0033,0x0035,0x0036,0x0038,0x0039,0x003B,0x003C,0x003E,0x0040, +0x0041,0x0043,0x0044,0x0046,0x0047,0x0049,0x004A,0x0051,0x0057,0x005D, +0x0063,0x006A,0x0070,0x0076,0x007C,0x0083,0x0089,0x008F,0x0095,0x009C, +0x00A2,0x00A8,0x00AE,0x00B5,0x00B9,0x00BB,0x00C1,0x00C7,0x00CE,0x00D4, +0x00DA,0x00E0,0x00E7,0x00ED,0x00F3,0x00F9,0x0100,0x0106,0x010C,0x0112, +0x0118,0x011F,0x0125,0x012B,0x0131,0x0138,0x013E,0x0144,0x014A,0x0151, +0x0157,0x015D,0x0163,0x016A,0x0170,0x0176,0x017C,0x0183,0x0189,0x018F +}; + +struct front_light_setting { + unsigned short fl_r_en; + unsigned short freq; + unsigned short duty; +}; + +static struct front_light_setting FL_table[][100]={ +{// TABLE1 +{0,20000,3}, {0,20000,5}, {0,20000,7}, {0,20000,9}, {0,20000,11}, +{0,20000,13}, {0,20000,15}, {0,20000,17}, {0,20000,19}, {0,20000,21}, +{0,20000,23}, {0,20000,25}, {0,20000,27}, {0,20000,30}, {0,20000,33}, +{0,20000,36}, {0,20000,39}, {0,20000,42}, {0,20000,46}, {0,20000,51}, +{0,20000,54}, {0,20000,59}, {0,20000,63}, {0,20000,68}, {0,20000,71}, +{0,20000,74}, {0,20000,87}, {0,20000,99}, {0,20000,112}, {0,20000,124}, +{0,20000,137}, {0,20000,149}, {0,20000,162}, {0,20000,174}, {0,20000,185}, +{0,20000,193}, {0,20000,206}, {0,20000,218}, {0,20000,231}, {0,20000,243}, +{0,20000,256}, {1,20000,45}, {1,20000,46}, {1,20000,47}, {1,20000,48}, +{1,20000,49}, {1,20000,50}, {1,20000,51}, {1,20000,53}, {1,20000,55}, +{1,20000,56}, {1,20000,58}, {1,20000,60}, {1,20000,63}, {1,20000,65}, +{1,20000,68}, {1,20000,70}, {1,20000,75}, {1,20000,78}, {1,20000,80}, +{1,20000,85}, {1,20000,88}, {1,20000,90}, {1,20000,95}, {1,20000,100}, +{1,20000,105}, {1,20000,110}, {1,20000,115}, {1,20000,120}, {1,20000,125}, +{1,20000,130}, {1,20000,135}, {1,20000,140}, {1,20000,145}, {1,20000,150}, +{1,20000,155}, {1,20000,160}, {1,20000,170}, {1,20000,180}, {1,20000,190}, +{1,20000,200}, {1,20000,210}, {1,20000,220}, {1,20000,230}, {1,20000,240}, +{1,20000,250}, {1,20000,260}, {1,20000,270}, {1,20000,280}, {1,20000,290}, +{1,20000,300}, {1,20000,310}, {1,20000,320}, {1,20000,330}, {1,20000,340}, +{1,20000,350}, {1,20000,360}, {1,20000,370}, {1,20000,380}, {1,20000,400} +}, +{// TABLE2 +{0,20000, 3 }, {0,20000, 4 }, {0,20000, 5 }, {0,20000, 6 }, {0,20000, 7 }, // 1% +{0,20000, 8 }, {0,20000, 8 }, {0,20000, 9 }, {0,20000, 9 }, {0,20000, 10 }, // +{0,20000, 12 }, {0,20000, 16 }, {0,20000, 19 }, {0,20000, 22 }, {0,20000, 25 }, // 11% +{0,20000, 30 }, {0,20000, 38 }, {0,20000, 45 }, {0,20000, 52 }, {0,20000, 60 }, // +{0,20000, 75 }, {0,20000,100 }, {0,20000,125 }, {0,20000,145 }, {0,20000,160 }, // 21% +{0,20000,160 }, {0,20000,160 }, {0,20000,160 }, {0,20000,160 }, {1,20000, 20 }, // +{1,20000, 22 }, {1,20000, 24 }, {1,20000, 26 }, {1,20000, 28 }, {1,20000, 30 }, // 31% +{1,20000, 32 }, {1,20000, 34 }, {1,20000, 36 }, {1,20000, 38 }, {1,20000, 40 }, // +{1,20000, 42 }, {1,20000, 44 }, {1,20000, 46 }, {1,20000, 48 }, {1,20000, 50 }, // 41% +{1,20000, 52 }, {1,20000, 54 }, {1,20000, 56 }, {1,20000, 58 }, {1,20000, 60 }, // +{1,20000, 62 }, {1,20000, 65 }, {1,20000, 69 }, {1,20000, 74 }, {1,20000, 80 }, // 51% +{1,20000, 84 }, {1,20000, 88 }, {1,20000, 92 }, {1,20000, 96 }, {1,20000,100 }, // +{1,20000,106 }, {1,20000,112 }, {1,20000,118 }, {1,20000,124 }, {1,20000,130 }, // 61% +{1,20000,136 }, {1,20000,142 }, {1,20000,148 }, {1,20000,154 }, {1,20000,160 }, // +{1,20000,168 }, {1,20000,176 }, {1,20000,184 }, {1,20000,192 }, {1,20000,200 }, // 71% +{1,20000,206 }, {1,20000,212 }, {1,20000,218 }, {1,20000,224 }, {1,20000,230 }, // +{1,20000,238 }, {1,20000,246 }, {1,20000,254 }, {1,20000,262 }, {1,20000,270 }, // 81% +{1,20000,278 }, {1,20000,286 }, {1,20000,294 }, {1,20000,302 }, {1,20000,310 }, // +{1,20000,318 }, {1,20000,326 }, {1,20000,334 }, {1,20000,342 }, {1,20000,350 }, // 91% +{1,20000,360 }, {1,20000,370 }, {1,20000,380 }, {1,20000,330 }, {1,20000,400 } +}, +{// TABLE3 +{0,10000,6},{0,10000,28},{0,10000,44},{0,10000,62},{0,10000,87}, +{0,10000,100},{0,10000,112},{0,10000,128},{0,10000,147},{0,10000,153}, +{0,10000,165},{0,10000,172},{0,10000,181},{0,10000,194},{0,10000,215}, +{0,10000,225},{0,10000,247},{0,10000,265},{0,10000,287},{0,10000,490}, +{0,10000,500},{0,10000,515},{0,10000,537},{0,10000,553},{0,10000,587}, +{0,10000,618},{0,10000,681},{0,10000,737},{0,10000,799},{1,10000,6}, +{1,10000,12},{1,10000,19},{1,10000,25},{1,10000,28},{1,10000,37}, +{1,10000,44},{1,10000,53},{1,10000,56},{1,10000,62},{1,10000,69}, +{1,10000,75},{1,10000,81},{1,10000,87},{1,10000,94},{1,10000,100}, +{1,10000,103},{1,10000,109},{1,10000,116},{1,10000,122},{1,10000,128}, +{1,10000,134},{1,10000,137},{1,10000,144},{1,10000,150},{1,10000,165}, +{1,10000,178},{1,10000,187},{1,10000,197},{1,10000,206},{1,10000,215}, +{1,10000,225},{1,10000,237},{1,10000,250},{1,10000,262},{1,10000,275}, +{1,10000,287},{1,10000,300},{1,10000,312},{1,10000,325},{1,10000,337}, +{1,10000,350},{1,10000,365},{1,10000,381},{1,10000,393},{1,10000,409}, +{1,10000,425},{1,10000,440},{1,10000,456},{1,10000,471},{1,10000,484}, +{1,10000,496},{1,10000,509},{1,10000,524},{1,10000,540},{1,10000,553}, +{1,10000,568},{1,10000,584},{1,10000,599},{1,10000,615},{1,10000,631}, +{1,10000,646},{1,10000,659},{1,10000,677},{1,10000,696},{1,10000,712}, +{1,10000,731},{1,10000,746},{1,10000,765},{1,10000,784},{1,10000,799} +}, +{// TABLE4 +{0,20000,2}, {0,20000,5}, {0,20000,8}, {0,20000,12}, {0,20000,16}, +{0,20000,22}, {0,20000,28}, {0,20000,36}, {0,20000,39}, {0,20000,45}, +{0,20000,52}, {0,20000,56}, {0,20000,61}, {0,20000,67}, {0,20000,75}, +{0,20000,81}, {0,20000,87}, {0,20000,94}, {0,20000,100}, {0,20000,106}, +{0,20000,112}, {0,20000,119}, {0,20000,131}, {0,20000,137}, {0,20000,144}, +{0,20000,156}, {0,20000,175}, {0,20000,188}, {0,20000,212}, {0,20000,231}, +{0,20000,237}, {0,20000,250}, {0,20000,256}, {0,20000,262}, {0,20000,268}, +{0,20000,275}, {0,20000,287}, {0,20000,293}, {0,20000,306}, {0,20000,331}, +{0,20000,337}, {0,20000,350}, {0,20000,368}, {1,20000,67}, {1,20000,69}, +{1,20000,72}, {1,20000,75}, {1,20000,81}, {1,20000,87}, {1,20000,94}, +{1,20000,100}, {1,20000,106}, {1,20000,112}, {1,20000,119}, {1,20000,125}, +{1,20000,131}, {1,20000,137}, {1,20000,144}, {1,20000,150}, {1,20000,156}, +{1,20000,162}, {1,20000,169}, {1,20000,175}, {1,20000,181}, {1,20000,185}, +{1,20000,188}, {1,20000,194}, {1,20000,200}, {1,20000,206}, {1,20000,212}, +{1,20000,219}, {1,20000,225}, {1,20000,231}, {1,20000,237}, {1,20000,244}, +{1,20000,250}, {1,20000,256}, {1,20000,262}, {1,20000,268}, {1,20000,275}, +{1,20000,281}, {1,20000,287}, {1,20000,293}, {1,20000,300}, {1,20000,306}, +{1,20000,312}, {1,20000,318}, {1,20000,325}, {1,20000,331}, {1,20000,337}, +{1,20000,343}, {1,20000,350}, {1,20000,356}, {1,20000,362}, {1,20000,368}, +{1,20000,375}, {1,20000,381}, {1,20000,387}, {1,20000,393}, {1,20000,400} +}, +{// TABLE5 +{0,20000,39},{0,20000,41},{0,20000,42},{0,20000,45},{0,20000,47}, +{0,20000,48},{0,20000,50},{0,20000,53},{0,20000,56},{0,20000,59}, +{0,20000,62},{0,20000,64},{0,20000,67},{0,20000,70},{0,20000,73}, +{0,20000,75},{0,20000,81},{0,20000,87},{0,20000,94},{0,20000,100}, +{0,20000,106},{0,20000,112},{0,20000,119},{0,20000,125},{0,20000,131}, +{0,20000,137},{0,20000,144},{0,20000,150},{0,20000,156},{0,20000,162}, +{0,20000,168},{0,20000,175},{0,20000,181},{0,20000,185},{0,20000,194}, +{0,20000,200},{0,20000,206},{0,20000,212},{0,20000,219},{0,20000,225}, +{0,20000,231},{0,20000,237},{0,20000,244},{0,20000,250},{1,20000,67}, +{1,20000,70},{1,20000,73},{1,20000,75},{1,20000,81},{1,20000,87}, +{1,20000,94},{1,20000,100},{1,20000,106},{1,20000,112},{1,20000,119}, +{1,20000,125},{1,20000,131},{1,20000,137},{1,20000,144},{1,20000,150}, +{1,20000,156},{1,20000,162},{1,20000,169},{1,20000,175},{1,20000,181}, +{1,20000,188},{1,20000,194},{1,20000,200},{1,20000,206},{1,20000,212}, +{1,20000,219},{1,20000,225},{1,20000,231},{1,20000,237},{1,20000,244}, +{1,20000,250},{1,20000,256},{1,20000,262},{1,20000,268},{1,20000,275}, +{1,20000,281},{1,20000,287},{1,20000,293},{1,20000,300},{1,20000,306}, +{1,20000,312},{1,20000,318},{1,20000,325},{1,20000,331},{1,20000,337}, +{1,20000,343},{1,20000,350},{1,20000,356},{1,20000,362},{1,20000,368}, +{1,20000,375},{1,20000,381},{1,20000,387},{1,20000,393},{1,20000,400} +}, +{// TABLE6 +{0,20000,39},{0,20000,42},{0,20000,45},{0,20000,47},{0,20000,50}, +{0,20000,53},{0,20000,59},{0,20000,62},{0,20000,64},{0,20000,67}, +{0,20000,70},{0,20000,73},{0,20000,75},{0,20000,81},{0,20000,87}, +{0,20000,94},{0,20000,100},{0,20000,106},{0,20000,112},{0,20000,119}, +{0,20000,125},{0,20000,131},{0,20000,137},{0,20000,144},{0,20000,150}, +{0,20000,156},{0,20000,162},{0,20000,168},{0,20000,175},{0,20000,181}, +{0,20000,185},{0,20000,194},{0,20000,200},{0,20000,206},{0,20000,212}, +{0,20000,219},{0,20000,225},{0,20000,231},{0,20000,237},{0,20000,244}, +{0,20000,250},{0,20000,260},{0,20000,270},{0,20000,280},{1,20000,55}, +{1,20000,58},{1,20000,63},{1,20000,68},{1,20000,75},{1,20000,81}, +{1,20000,87},{1,20000,94},{1,20000,100},{1,20000,106},{1,20000,112}, +{1,20000,119},{1,20000,125},{1,20000,131},{1,20000,137},{1,20000,144}, +{1,20000,150},{1,20000,156},{1,20000,162},{1,20000,169},{1,20000,175}, +{1,20000,181},{1,20000,188},{1,20000,194},{1,20000,200},{1,20000,206}, +{1,20000,212},{1,20000,219},{1,20000,225},{1,20000,231},{1,20000,237}, +{1,20000,244},{1,20000,250},{1,20000,256},{1,20000,262},{1,20000,268}, +{1,20000,275},{1,20000,281},{1,20000,287},{1,20000,293},{1,20000,300}, +{1,20000,306},{1,20000,312},{1,20000,318},{1,20000,325},{1,20000,331}, +{1,20000,337},{1,20000,343},{1,20000,350},{1,20000,356},{1,20000,362}, +{1,20000,368},{1,20000,375},{1,20000,381},{1,20000,387},{1,20000,400} +}, +{ // TABLE7 +{0,20000,39}, {0,20000,41}, {0,20000,42}, {0,20000,45}, {0,20000,47}, +{0,20000,48}, {0,20000,50}, {0,20000,53}, {0,20000,56}, {0,20000,59}, +{0,20000,62}, {0,20000,64}, {0,20000,67}, {0,20000,70}, {0,20000,73}, +{0,20000,75}, {0,20000,81}, {0,20000,87}, {0,20000,94}, {0,20000,106}, +{0,20000,119}, {0,20000,131}, {0,20000,144}, {0,20000,156}, {0,20000,168}, +{0,20000,181}, {0,20000,194}, {0,20000,206}, {0,20000,219}, {0,20000,231}, +{0,20000,244}, {0,20000,255}, {0,20000,265}, {0,20000,275}, {0,20000,285}, +{0,20000,295}, {0,20000,305}, {0,20000,315}, {0,20000,325}, {0,20000,335}, +{0,20000,345}, {0,20000,355}, {0,20000,365}, {0,20000,375}, {1,20000,67}, +{1,20000,70}, {1,20000,73}, {1,20000,75}, {1,20000,81}, {1,20000,87}, +{1,20000,94}, {1,20000,100}, {1,20000,106}, {1,20000,112}, {1,20000,119}, +{1,20000,125}, {1,20000,131}, {1,20000,137}, {1,20000,144}, {1,20000,150}, +{1,20000,156}, {1,20000,162}, {1,20000,169}, {1,20000,175}, {1,20000,181}, +{1,20000,188}, {1,20000,194}, {1,20000,200}, {1,20000,206}, {1,20000,212}, +{1,20000,219}, {1,20000,225}, {1,20000,231}, {1,20000,237}, {1,20000,244}, +{1,20000,250}, {1,20000,256}, {1,20000,262}, {1,20000,268}, {1,20000,275}, +{1,20000,281}, {1,20000,287}, {1,20000,293}, {1,20000,300}, {1,20000,306}, +{1,20000,312}, {1,20000,318}, {1,20000,325}, {1,20000,331}, {1,20000,337}, +{1,20000,343}, {1,20000,350}, {1,20000,356}, {1,20000,362}, {1,20000,368}, +{1,20000,375}, {1,20000,381}, {1,20000,387}, {1,20000,393}, {1,20000,400} +}, +{// TABLE8 +{0,20000,18},{0,20000,24},{0,20000,30},{0,20000,41},{0,20000,49}, +{0,20000,62},{0,20000,71},{0,20000,82},{0,20000,93},{0,20000,110}, +{0,20000,132},{0,20000,150},{0,20000,170},{0,20000,195},{0,20000,216}, +{0,20000,238},{0,20000,252},{0,20000,266},{0,20000,280},{1,20000,30}, +{1,20000,32},{1,20000,33},{1,20000,35},{1,20000,37},{1,20000,39}, +{1,20000,41},{1,20000,43},{1,20000,45},{1,20000,47},{1,20000,49}, +{1,20000,51},{1,20000,53},{1,20000,55},{1,20000,57},{1,20000,59}, +{1,20000,61},{1,20000,63},{1,20000,65},{1,20000,67},{1,20000,69}, +{1,20000,71},{1,20000,73},{1,20000,75},{1,20000,77},{1,20000,80}, +{1,20000,84},{1,20000,87},{1,20000,89},{1,20000,91},{1,20000,93}, +{1,20000,96},{1,20000,99},{1,20000,102},{1,20000,104},{1,20000,106}, +{1,20000,109},{1,20000,112},{1,20000,114},{1,20000,116},{1,20000,118}, +{1,20000,120},{1,20000,123},{1,20000,126},{1,20000,128},{1,20000,131}, +{1,20000,133},{1,20000,136},{1,20000,138},{1,20000,140},{1,20000,143}, +{1,20000,146},{1,20000,149},{1,20000,152},{1,20000,155},{1,20000,158}, +{1,20000,160},{1,20000,162},{1,20000,165},{1,20000,167},{1,20000,172}, +{1,20000,175},{1,20000,178},{1,20000,185},{1,20000,192},{1,20000,196}, +{1,20000,200},{1,20000,204},{1,20000,208},{1,20000,216},{1,20000,223}, +{1,20000,230},{1,20000,237},{1,20000,245},{1,20000,248},{1,20000,252}, +{1,20000,257},{1,20000,262},{1,20000,268},{1,20000,274},{1,20000,280}, +}, +{//TABLE9 +{0,20000,18}, {0,20000,21}, {0,20000,26}, {0,20000,38}, {0,20000,46}, +{0,20000,58}, {0,20000,67}, {0,20000,77}, {0,20000,90}, {0,20000,101}, +{0,20000,123}, {0,20000,140}, {0,20000,160}, {0,20000,190}, {0,20000,210}, +{0,20000,230}, {0,20000,245}, {0,20000,258}, {0,20000,270},{1,20000,24}, +{1,20000,26}, {1,20000,28}, {1,20000,30}, {1,20000,32}, {1,20000,34}, +{1,20000,36}, {1,20000,38}, {1,20000,40}, {1,20000,42}, {1,20000,44}, +{1,20000,46}, {1,20000,48}, {1,20000,50}, {1,20000,52}, {1,20000,54}, +{1,20000,56}, {1,20000,58}, {1,20000,60}, {1,20000,62}, {1,20000,64}, +{1,20000,66}, {1,20000,68}, {1,20000,70}, {1,20000,72}, {1,20000,74}, +{1,20000,76}, {1,20000,78}, {1,20000,80}, {1,20000,82}, {1,20000,84}, +{1,20000,86}, {1,20000,88}, {1,20000,90}, {1,20000,92}, {1,20000,94}, +{1,20000,96}, {1,20000,98}, {1,20000,100}, {1,20000,102}, {1,20000,104}, +{1,20000,106}, {1,20000,108}, {1,20000,110}, {1,20000,112}, {1,20000,114}, +{1,20000,116}, {1,20000,118}, {1,20000,120}, {1,20000,122}, {1,20000,124}, +{1,20000,126}, {1,20000,128}, {1,20000,130}, {1,20000,132}, {1,20000,134}, +{1,20000,136}, {1,20000,138}, {1,20000,142}, {1,20000,144}, {1,20000,148}, +{1,20000,152}, {1,20000,158}, {1,20000,161}, {1,20000,163}, {1,20000,166}, +{1,20000,169}, {1,20000,175}, {1,20000,180}, {1,20000,184}, {1,20000,187}, +{1,20000,192}, {1,20000,196}, {1,20000,199}, {1,20000,203}, {1,20000,207}, +{1,20000,211}, {1,20000,215}, {1,20000,219}, {1,20000,226}, {1,20000,230} +} +}; + +struct delayed_work FL_off; + +static void FL_module_off(void); + +void FL_off_func(struct work_struct *work); +int FL_suspend(void); + +//kay for LED thread +//static unsigned char LED_conitnuous=0; +static unsigned char LED_conitnuous=1; +static int LED_Flash_Count; +static int gKeepPowerAlive; +int gMxcPowerKeyIrqTriggered, g_power_key_pressed; +volatile int g_mxc_touch_triggered = 1; //gallen 100420 +int g_wakeup_by_alarm; +int gWifiEnabled=0; +static unsigned long g_usb_in_tick; // Joseph 101001 +static int g_ioctl_SD_status, g_ioctl_USB_status, g_ioctl_rotary_status,g_Cus_Ctrl_Led; +int g_mmc_card_detect_changed; // Joseph 20110125 +static DEFINE_SPINLOCK(led_flash_lock); +static DECLARE_WAIT_QUEUE_HEAD(LED_blink_WaitQueue); +static DECLARE_WAIT_QUEUE_HEAD(LED_freeze_WaitQueue); +static DECLARE_WAIT_QUEUE_HEAD(WheelKey_WaitQueue); +//////////////////// + +static unsigned int last_FL_duty = 0; +static unsigned int current_FL_freq = 0xFFFF; + + +static DECLARE_WAIT_QUEUE_HEAD(Reset_WaitQueue); + +extern int gIsCustomerUi; + +int ntx_charge_status (void); +int mxc_usb_plug_getstatus (void); + +void led_green (int isOn) +{ + + if(0x03!=gptHWCFG->m_val.bUIConfig) { + // do not check charging status in MP/RD mode + if(gMX6SL_ON_LED==gMX6SL_CHG_LED&&mxc_usb_plug_getstatus()) { + // skip control charge led while charging . + return ; + } + } + + + if (isOn) + gpio_direction_output (gMX6SL_ON_LED,0); + else { + switch(gptHWCFG->m_val.bPCB) { + case 33: + // E60Q2X . + gpio_direction_output (gMX6SL_ON_LED,1); + default : + gpio_direction_input (gMX6SL_ON_LED); + } + } +} + +void led_blue (int isOn) +{ + + switch(gptHWCFG->m_val.bLed) { + case 1: + if (isOn) + gpio_direction_output (gMX6SL_ACT_LED,0); + else + gpio_direction_input (gMX6SL_ACT_LED); + break; + } +} + +void led_red (int isOn) { + switch(gptHWCFG->m_val.bLed) { + //case 0:// Type1 . + case 1:// RGB + case 2:// RG + case 3:// RGH + case 7:// WH + if (isOn) { + gpio_direction_output (gMX6SL_CHG_LED,0); + } + else { + gpio_direction_input (gMX6SL_CHG_LED); + } + break; + } +} + + +//kay 20090925 +//check WiFi ID +static int check_hardware_wifi(void) +{ + return WIFI_NONE; +} + +//check Bluetooth ID +static int check_hardware_bt(void) +{ + return BLUETOOTH_NONE; +} + +static int check_hardware_cpu(void) +{ + return CPU_S3C2440; +} + +//static int check_hardeare_name(void) +int check_hardware_name(void) +{ + static int pcb_id = -1; + + if (0 >= pcb_id) { + switch(gptHWCFG->m_val.bPCB) + { + default: + pcb_id = gptHWCFG->m_val.bPCB; + break; + } + printk ("[%s-%d] PCBA ID is %d\n",__func__,__LINE__,pcb_id); + } + + return pcb_id; +} +EXPORT_SYMBOL(check_hardware_name); + +static int check_hardware_controller(void) +{ + return CONTROLLER_EPSON; +} + +static void collect_hardware_info(struct ebook_device_info *info) +{ + info->cpu = check_hardware_cpu(); + info->device_name = check_hardware_name(); + info->controller = check_hardware_controller(); + info->wifi = check_hardware_wifi(); + info->bluetooth = check_hardware_bt(); +} + +static int openDriver(struct inode *inode,struct file *filp) +{ + if(!Driver_Count) + Driver_Count++; + return 0; +} +static int releaseDriver(struct inode *inode,struct file *filp) +{ + if(Driver_Count) + Driver_Count--; + return 0; +} +static void bluetooth_reset(int i) +{ +} + +static void bluetooth_pwr(int i) +{ +} + +extern unsigned long g_kl25_result; +extern unsigned long g_kl25_action; +extern void ntx_wifi_power_ctrl (int isWifiEnable); + +extern u16 msp430_deviceid(void); +extern void msp430_auto_power(int minutes); +extern void msp430_power_off(void); +extern void msp430_pm_restart(void); +extern void msp430_powerkeep(int n); +extern int msp430_battery(void); +extern void msp430_fl_enable (int isEnable); + +int ricoh619_restart(void); +int ricoh619_battery_2_msp430_adc(void); +int ricoh619_charger_detect(void); +int ricoh619_dcin_status(void); + +extern int ht68f20_write_reg(unsigned int reg, unsigned int value); +extern unsigned int ht68f20_read_reg(unsigned int reg); +extern void ht68f20_enable(int isEnable); + +extern int up_write_reg(unsigned int reg, unsigned int value); +extern unsigned int up_read_reg(unsigned int reg); + +int g_power_key_debounce; // Joseph 20100921 for ESD + +static void fl_pwm_enable (int isEnable) +{ + static int s_pwm_enabled=1; + if(1==gptHWCFG->m_val.bFL_PWM) + { + if (s_pwm_enabled != isEnable) { + s_pwm_enabled = isEnable; + ht68f20_enable (isEnable); + if (isEnable) { + mxc_iomux_v3_setup_pad (MX6SL_PAD_I2C1_SCL__I2C1_SCL); + mxc_iomux_v3_setup_pad (MX6SL_PAD_I2C1_SDA__I2C1_SDA); + } + else { + mxc_iomux_v3_setup_pad (MX6SL_PAD_I2C1_SCL__GPIO_3_12); + mxc_iomux_v3_setup_pad (MX6SL_PAD_I2C1_SDA__GPIO_3_13); + } + } + } +} + +unsigned long long hwconfig = 0x0000000011000001LL; +EXPORT_SYMBOL(hwconfig); +unsigned char platform_type[32]; +EXPORT_SYMBOL(platform_type); + +static int __init early_hw(char *p) +{ + hwconfig = simple_strtoull(p, NULL, 16); + printk("hwconfig: %16llX\n", hwconfig); + return 0; +} +early_param("hwconfig", early_hw); + +//to parse hardware configuration bits +static int __init early_board(char *p) +{ + strncpy(platform_type, p, sizeof(platform_type)); + printk("board: %s\n", platform_type); + return 0; +} +early_param("board", early_board); + +int power_key_status (void) +{ + return gpio_get_value (gMX6SL_PWR_SW)?0:1; +} + +int fl_set_percentage(int iFL_Percentage) +{ + int iRet = 0; + int p=iFL_Percentage; + + + if(0==gptHWCFG->m_val.bFrontLight) + return -1; + + if(1==gptHWCFG->m_val.bFL_PWM) + { + // HT68F20 + + if (p) { + fl_pwm_enable (1); + if(delayed_work_pending(&FL_off)){ + cancel_delayed_work_sync(&FL_off); + printk("FL_off delayed work canceled"); + } + printk ("\nset front light level : %d\n",p); + if(p>0 && p<=100) + { + // temporary table + // for first 70 levels, fl_r_en = 0 + // duty = 27,34,41 .... 510 + // for 71~100 levels, fl_r_en =1 + // duty = 162, 174, 186, 198 ... 510 + int fl_r_en; + int duty; + if(p<=70){ + fl_r_en = 0; + duty = 20 + p*7; + } + else { + fl_r_en = 1; + duty = 150 + (p-70)*12; + } + if (last_FL_duty >= p) + gpio_direction_output (MX6SL_FL_R_EN, fl_r_en); + + ht68f20_write_reg (0xA6, duty&0xFF); // Set PWM duty + ht68f20_write_reg (0xA7, duty>>8); + printk ("Set front light duty : %d\n",duty); + + if (last_FL_duty < p) + gpio_direction_output (MX6SL_FL_R_EN, fl_r_en); + } + else{ + printk("Wrong number! level range from 0 to 100\n"); + } + if (0 == last_FL_duty){ + ht68f20_write_reg (0xA3, 0x01); // enable front light pwm + + msleep(100); + gpio_direction_output(MX6SL_FL_EN,giFL_ON); + } + } + else if(last_FL_duty != 0){ + printk ("FL PWM off command\n"); + ht68f20_write_reg(0xA3, 0); + schedule_delayed_work(&FL_off, 120); + } + last_FL_duty = p; + + } + else + { + if (p) { + if(delayed_work_pending(&FL_off)){ + cancel_delayed_work_sync(&FL_off); + printk("FL_off delayed work canceled"); + } + printk ("\nset front light level : %d\n",p); + if(p>0 && p<=100) + { + if( gptHWCFG->m_val.bFrontLight == 3){ //TABLE0a + up_write_reg (0xA5, 0x0100); + up_write_reg (0xA4, 0x9000); + up_write_reg (0xA7, FL_table0[p-1]&0xFF00); + up_write_reg (0xA6, FL_table0[p-1]<<8); + printk("PWMCNT : 0x%04x\n", FL_table0[p-1]); + } + else if( gptHWCFG->m_val.bFrontLight == 1 || gptHWCFG->m_val.bFrontLight == 2 ){ //TABLE0, TABLE0+ + if (0 == last_FL_duty){ + up_write_reg (0xA5, 0x0100); + up_write_reg (0xA4, 0x9000); + } + if(p<=50){ + gpio_direction_output(MX6SL_FL_R_EN,0); + up_write_reg (0xA7, FL_table0[2*(p-1)]&0xFF00); + up_write_reg (0xA6, FL_table0[2*(p-1)]<<8); + printk("PWMCNT : 0x%04x\n", FL_table0[2*(p-1)]); + }else{ + gpio_direction_output(MX6SL_FL_R_EN,1); + up_write_reg (0xA7, FL_table0[p-1]&0xFF00); + up_write_reg (0xA6, FL_table0[p-1]<<8); + printk("PWMCNT : 0x%04x\n", FL_table0[p-1]); + } + } + else{ + int t_no = gptHWCFG->m_val.bFrontLight-4; // mapping hwconfig to FL_table + int freq = 8000000/FL_table[t_no][p-1].freq; + + if (30 == gptHWCFG->m_val.bPCB && p==5) { //E606E2 + p=1; + } + + if (last_FL_duty >= p) + gpio_direction_output (MX6SL_FL_R_EN, FL_table[t_no][p-1].fl_r_en); + + if( freq != current_FL_freq){ + printk ("Set front light Frequency : %d\n",FL_table[t_no][p-1].freq); + up_write_reg (0xA5, freq&0xFF00); // Set Frequency 8M/freq + up_write_reg (0xA4, freq<<8); + current_FL_freq = freq; + } + up_write_reg (0xA7, FL_table[t_no][p-1].duty&0xFF00); // Set PWM duty + up_write_reg (0xA6, FL_table[t_no][p-1].duty<<8); + printk ("Set front light duty : %d\n",FL_table[t_no][p-1].duty); + + if (last_FL_duty < p) + gpio_direction_output (MX6SL_FL_R_EN, FL_table[t_no][p-1].fl_r_en); + } + } + else{ + printk("Wrong number! level range from 0 to 100\n"); + } + if (0 == last_FL_duty){ + up_write_reg (0xA1, 0xFF00); // Disable front light auto off timer + up_write_reg (0xA2, 0xFF00); + + up_write_reg (0xA3, 0x0100); // enable front light pwm + + msleep(100); + gpio_direction_output(MX6SL_FL_EN,giFL_ON); + msp430_fl_enable (1); + } + } + else if(last_FL_duty != 0){ + printk ("FL PWM off command\n"); + up_write_reg(0xA3, 0); + schedule_delayed_work(&FL_off, 120); + } + last_FL_duty = p; + } + return iRet; +} + + + + +static void ntx_system_reset(const char *pszDomain) +{ + if(pszDomain) { + printk("%s() ---%s reset ---\n",__FUNCTION__,pszDomain); + } + + if(0!=gptHWCFG->m_val.bFrontLight){ + up_write_reg (0xA3, 0); + msleep (1200); + + FL_module_off(); + } + + while (1) { + gKeepPowerAlive = 0; + if (1==gptHWCFG->m_val.bPMIC) { + // RC5T19 . + printk("%s() --- RC5T19 restarting system ---\n",__FUNCTION__); + ricoh619_restart (); + } + else { + printk("%s() --- MSP430 restarting system ---\n",__FUNCTION__); + msp430_pm_restart(); + } + sleep_on_timeout(&Reset_WaitQueue, 14*HZ/10); + } +} + +static void ntx_system_poweroff(const char *pszDomain) +{ + if(pszDomain) { + printk("%s() ---%s poweroff ---\n",__FUNCTION__,pszDomain); + } + if (!gKeepPowerAlive) { + + if(0!=gptHWCFG->m_val.bFrontLight){ + + if(0==gptHWCFG->m_val.bFL_PWM) { + // FL is controlled by MSP430 . + up_write_reg (0xA3, 0); + } + + msleep (1200); + + FL_module_off(); + } + + LED_conitnuous = 0; + led_green(0); + while (1) { + printk("Kernel---Power Down ---\n"); + if(1==gptHWCFG->m_val.bPMIC) + ricoh619_power_off(); + else + msp430_power_off(); + sleep_on_timeout(&Reset_WaitQueue, 14*HZ/10); + } + } + else { + printk("Kernel---in keep alive mode ---\n"); + } +} + +static int ioctlDriver(struct file *filp, unsigned int command, unsigned long arg) +{ + unsigned long i = 0, temp; + unsigned int p = arg;//*(unsigned int *)arg; + struct ebook_device_info info; + + if(!Driver_Count){ + printk("pvi_io : do not open\n"); + return -1; + } + + switch(command) + { + case POWER_OFF_COMMAND: + ntx_system_poweroff("POWER_OFF_COMMAND"); + break; + + case SYS_RESET_COMMAND: + ntx_system_reset("SYS_RESET_COMMAND"); + break; + + case SYS_AUTO_POWER_ON: + msp430_auto_power(p); + ntx_system_reset("SYS_AUTO_POWER_ON"); + break; + + case POWER_KEEP_COMMAND: + printk("Kernel---System Keep Alive --- %d\n",p); + gKeepPowerAlive=p; + if(1==gptHWCFG->m_val.bPMIC) + break; + if (gKeepPowerAlive) { + msp430_powerkeep(1); + wake_up_interruptible(&LED_freeze_WaitQueue); + } + else + msp430_powerkeep(0); + break; + + case CM_GET_BATTERY_STATUS: + if(1==gptHWCFG->m_val.bPMIC) { + i = ricoh619_battery_2_msp430_adc(); + } + else { + i = msp430_battery (); + } + if (0 == i) + i = 0x8000; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + + break; + + case AC_IN: + if(1==gptHWCFG->m_val.bPMIC) { + i = ricoh619_charger_detect()?1:0; + } + else + i = gpio_get_value (gMX6SL_NTX_ACIN_PG)?0:1; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_SD_IN: + g_ioctl_SD_status = gpio_get_value (MX6SL_EXT_SD_CD); + i = (g_ioctl_SD_status)?0:1; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_USB_Plug_IN: + if(1==gptHWCFG->m_val.bPMIC) { + g_ioctl_USB_status = ricoh619_charger_detect()?0:1; + } + else { + if (!g_ioctl_USB_status && gpio_get_value (gMX6SL_NTX_ACIN_PG)) { + msleep(200); // sleep 200ms to avoid system halt when USB plug out. + } + g_ioctl_USB_status = gpio_get_value (gMX6SL_NTX_ACIN_PG); + } + i = (g_ioctl_USB_status)?0:1; + if (!g_Cus_Ctrl_Led) { + led_red(g_ioctl_USB_status?0:1); + } + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case GET_LnBATT_CPU: + break; + case GET_VBATT_TH: + break; + case CM_AC_CK: + break; + case CM_CHARGE_STATUS: + i = ntx_charge_status(); + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + case CM_PWR_ON2: + break; + case CM_AUDIO_PWR: + break; + case CM_nLED: + //printk("CM_nLED %d\n",p); + led_green(p?1:0); + break; + + case CM_nLED_CPU: + break; + + case CM_SD_PROTECT: + i = 0; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_CONTROLLER: + i = 2; // 2: Epson controller. for micro window + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_USB_AC_STATUS: + i = 0; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_RTC_WAKEUP_FLAG: + if (!g_wakeup_by_alarm) { + if(1!=gptHWCFG->m_val.bPMIC) { + int tmp = up_read_reg (0x60); + if (0x8000 & tmp) { + printk ("[%s-%d] =================> Micro P MSP430 alarm triggered <===================\n", __func__, __LINE__); + g_wakeup_by_alarm = 1; + } + } + } + i = g_wakeup_by_alarm; // Joseph 091221 for slide show test. + g_wakeup_by_alarm = 0; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_SYSTEM_RESET: + ntx_system_reset("CM_SYSTEM_RESET"); + break; + + case CM_USB_HOST_PWR: + break; + + case CM_BLUETOOTH_PWR: + ntx_wifi_power_ctrl (p); + break; + + case CM_TELLPID: + if(p!=0){ + printk("PID %d\n",p); + __EBRMAIN_PID__= p; + } + break; + + case CM_LED_BLINK: + if (2==p) { + spin_lock(&led_flash_lock); + LED_Flash_Count++; + spin_unlock(&led_flash_lock); + } + if (!LED_conitnuous) + wake_up_interruptible(&LED_freeze_WaitQueue); + LED_conitnuous = p; + break; + + case CM_TOUCH_LOCK: + if(p==0) + { + __TOUCH_LOCK__ = 0; + }else{ + __TOUCH_LOCK__ = 1; + } + break; + + case CM_DEVICE_MODULE: + i = check_hardware_name(); + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_BLUETOOTH_RESET: + break; + + case CM_DEVICE_INFO: + collect_hardware_info(&info); + copy_to_user((void __user *)arg, &info, sizeof(info)); + break; + + case CM_ROTARY_STATUS: + break; + + case CM_ROTARY_ENABLE: + break; + + case CM_GET_KEYS: + i = 0; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + case CM_POWER_BTN: + case CM_GET_KEY_STATUS: + if (g_power_key_pressed) { + g_power_key_pressed = 0; + i = 1; + } + else { + i = power_key_status (); + + if (i) { + if (2 >= g_power_key_debounce) { // Joseph 20100921 for ESD + printk ("[%s-%d] power key bounce detected %d\n",__func__,__LINE__, g_power_key_debounce); + i=0; + } + else { + gMxcPowerKeyIrqTriggered = 0; + } + } + else if (gMxcPowerKeyIrqTriggered) { // POWER key interrupt triggered. + if (2 < g_power_key_debounce) { + i = 1; + } + else + printk ("[%s-%d] power key bounce detected %d\n",__func__,__LINE__,g_power_key_debounce); + gMxcPowerKeyIrqTriggered = 0; + } + } + + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + g_mxc_touch_triggered = 0; + break; + + case CM_GET_WHEEL_KEY_STATUS: + i=0; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_GET_KL25_STATUS: + i=g_kl25_result; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + g_kl25_result &= 0xFF; + break; + + case CM_GET_KL25_ACTION: + i=g_kl25_action ; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + g_kl25_action = 0; + break; + + case CM_3G_POWER: + break; + + case CM_3G_RF_OFF: + break; + + case CM_3G_RESET: + break; + + case CM_WIFI_CTRL: + ntx_wifi_power_ctrl (p); + break; + + case CM_3G_GET_WAKE_STATUS: + i = 0; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_SET_ALARM_WAKEUP: + break; + + case CM_GET_UP_VERSION: + if(1==gptHWCFG->m_val.bMicroP) { + i = 0; + } + else + i = msp430_deviceid(); + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + break; + + case CM_AUDIO_GET_VOLUME: + break; + + case CM_AUDIO_SET_VOLUME: + break; + + case CM_FRONT_LIGHT_SET: + fl_set_percentage(p); + break; + + case CM_FRONT_LIGHT_GETDUTY: + if(1==gptHWCFG->m_val.bFL_PWM) + { + int duty; + duty = ht68f20_read_reg(0xB0); + printk ("[%s-%d] Front light Duty : %d\%\n",__func__,__LINE__,duty); + } + break; + + case CM_FRONT_LIGHT_HT68F20_SETDUTY: + if(0!=gptHWCFG->m_val.bFrontLight && 1==gptHWCFG->m_val.bFL_PWM) + { + fl_pwm_enable (1); + if (p) { + printk ("\nSet front light duty : %3d\n",p); + ht68f20_write_reg (0xA6, p&0xFF); + ht68f20_write_reg (0xA7, p>>8); + if (0 == last_FL_duty){ + ht68f20_write_reg (0xA3, 0x01); + + msleep(100); + gpio_direction_output(MX6SL_FL_EN,giFL_ON); + } + } + else { + printk ("turn off front light\n"); + ht68f20_write_reg (0xA3, 0); + + FL_module_off(); + } + last_FL_duty = p; + } + break; + + case CM_FRONT_LIGHT_AVAILABLE: + { + i = (unsigned long) (gptHWCFG->m_val.bFrontLight?1:0) ; + copy_to_user((void __user *)arg, &i, sizeof(unsigned long)); + } + break; + + case CM_FRONT_LIGHT_DUTY: + if(0!=gptHWCFG->m_val.bFrontLight) + { + if (p) { + printk ("\nSet front light PWMCNT : 0x%4X\n",p); + printk ("Current front light Frequency : (8MHz/0x%4X)\n",current_FL_freq); + up_write_reg (0xA7, p&0xFF00); + up_write_reg (0xA6, p<<8); + if (0 == last_FL_duty){ + up_write_reg (0xA1, 0xFF00); + up_write_reg (0xA2, 0xFF00); +// up_write_reg (0xA5, 0xFF00); +// up_write_reg (0xA4, 0xFF00); + up_write_reg (0xA3, 0x0100); + + msleep(100); + gpio_direction_output(MX6SL_FL_EN,giFL_ON); + } + } + else { + printk ("turn off front light\n"); + up_write_reg (0xA3, 0); + FL_module_off(); + } + last_FL_duty = p; + } + break; + + case CM_FRONT_LIGHT_FREQUENCY: + if(0!=gptHWCFG->m_val.bFrontLight) + { + if (p) { + printk ("set front light Frequency : (8MHz/0x%4X)\n",p); +// up_write_reg (0xA4, (p<<8)); + up_write_reg (0xA5, p&0xFF00); + up_write_reg (0xA4, (p<<8)); + current_FL_freq = p; + } + } + break; + + case CM_FRONT_LIGHT_R_EN: + if(0!=gptHWCFG->m_val.bFrontLight) + { + printk ("set FL_R_EN : %d\n",p); + gpio_direction_output(MX6SL_FL_R_EN, p); + } + break; + + case CM_PLATFORM: + copy_to_user((void __user *)arg, &platform_type, 32); + break; + case CM_HWCONFIG: + copy_to_user((void __user *)arg, &hwconfig, sizeof(unsigned long + long)); + break; + case CM_SET_HWCONFIG: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + copy_from_user(&hwconfig, (void __user *)arg, sizeof(unsigned long + long)); + break; + +#ifdef TOUCH_HOME_LED + case CM_HOME_LED_ONOFF: + if(0x03==gptHWCFG->m_val.bUIConfig){ + extern void homeled_onoff(int iIsON); + switch(p){ + case 0: + homeled_onoff(0); + break; + + case 1: + homeled_onoff(1); + break; + + default: + homeled_onoff(1); + break; + } + } + break; +#endif //#ifdef TOUCH_HOME_LED + + default: + printk("pvi_io : do not get the command [%d]\n", command); + return -1; + } + return 0; +} + +static struct file_operations driverFops= { + .owner = THIS_MODULE, + .open = openDriver, + .unlocked_ioctl = ioctlDriver, + .release = releaseDriver, +}; +static struct miscdevice driverDevice = { + .minor = DEVICE_MINJOR, + .name = DEVICE_NAME, + .fops = &driverFops, +}; + +/* +void mxc_set_fl_duty (int duty) +{ + static unsigned int last_FL_duty = 0; + static unsigned int current_FL_freq = 0xFFFF; + int t_no = gptHWCFG->m_val.bFrontLight-4; // mapping hwconfig to FL_table + + if(0==gptHWCFG->m_val.bFrontLight) + return; + + if (duty) { + if(delayed_work_pending(&FL_off)){ + cancel_delayed_work_sync(&FL_off); + printk("FL_off delayed work canceled"); + } + printk ("\nset front light level : %d\n",duty); + + int freq = 8000000/FL_table[t_no][duty-1].freq; + + if (last_FL_duty >= duty) + gpio_direction_output (MX6SL_FL_R_EN, FL_table[t_no][duty-1].fl_r_en); + if (freq != current_FL_freq) { + up_write_reg (0xA5, freq&0xFF00); // Set Frequency 8M/freq + up_write_reg (0xA4, freq<<8); + current_FL_freq = freq; + } + up_write_reg (0xA7, FL_table[t_no][duty-1].duty&0xFF00); // Set PWM duty + up_write_reg (0xA6, FL_table[t_no][duty-1].duty<<8); + gpio_direction_output (MX6SL_FL_R_EN, FL_table[t_no][duty-1].fl_r_en); + + if (0 == last_FL_duty){ + up_write_reg (0xA1, 0xFF00); + up_write_reg (0xA2, 0xFF00); + + up_write_reg (0xA3, 0x0100); + + msleep(100); + gpio_direction_output(MX6SL_FL_EN,0); + } + } + else if (last_FL_duty) { + printk ("turn off front light\n"); + printk ("FL PWM off command\n"); + up_write_reg(0xA3, 0); + schedule_delayed_work(&FL_off, 120); + current_FL_freq = 0xFFFF; + } + last_FL_duty = duty; +} +*/ + +// ================================= Simulate MC13892 Signaling LED Driver ================================ +static struct timer_list green_led_timer, blue_led_timer, red_led_timer; +static unsigned char green_led_dc, blue_led_dc, red_led_dc, \ + green_led_flag, blue_led_flag, red_led_flag; +static int green_led_period,blue_led_period,red_led_period ; + +static void ntx_led_set_timer (struct timer_list *pTimer, unsigned char dc, int blink) +{ + int period; + + if (0 == dc || 0==blink) { + del_timer_sync(pTimer); + return; + } + + + switch (blink) { + case 1: + period = 100 / 8; // 1/8 s + break; + case 2: + period = 100; // 1 s + break; + case 3: + period = 200; // 2 s + break; + default: + if(blink>10) { + period = blink/10; + break; + } + return ; + } + + mod_timer(pTimer, jiffies + period); +} + +static void green_led_blink_func (unsigned long v) +{ + green_led_flag ^= 1; + led_green(green_led_flag?0:1); + ntx_led_set_timer (&green_led_timer, green_led_dc, green_led_period); +} + +static void blue_led_blink_func (unsigned long v) +{ + blue_led_flag ^= 1; + led_blue(blue_led_flag?0:1); + ntx_led_set_timer (&blue_led_timer, blue_led_dc, blue_led_period); +} + +static void red_led_blink_func (unsigned long v) +{ + red_led_flag ^= 1; + led_red(red_led_flag?0:1); + ntx_led_set_timer (&red_led_timer, red_led_dc, red_led_period); +} + +void ntx_led_blink (unsigned int channel, int period) +{ + //printk("%s,period=%d\n",__FUNCTION__,period); + g_Cus_Ctrl_Led = 1; + switch (channel) { + case 3: + red_led_period = period&3; + ntx_led_set_timer (&red_led_timer, red_led_dc, red_led_period); + if(0==period) { + led_red(0); + } + break; + case 4: + //green_led_period = period&3; + green_led_period = period; + ntx_led_set_timer (&green_led_timer, green_led_dc, green_led_period); + if(0==period) { + led_green(0); + } + break; + case 5: + blue_led_period = period&3; + ntx_led_set_timer (&blue_led_timer, blue_led_dc, blue_led_period); + if(0==period) { + led_blue(0); + } + break; + default: + break; + } +} + +void ntx_led_dc (unsigned int channel, unsigned char dc) +{ + LED_conitnuous = 0; + g_Cus_Ctrl_Led = 1; + switch (channel) { + case 3: + red_led_dc = dc; + red_led_flag = (dc)?0:1; + led_red(red_led_flag?0:1); + ntx_led_set_timer (&red_led_timer, red_led_dc, red_led_period); + break; + case 4: + green_led_dc = dc; + green_led_flag = (dc)?0:1; + led_green(green_led_flag?0:1); + ntx_led_set_timer (&green_led_timer, green_led_dc, green_led_period); + break; + case 5: + blue_led_dc = dc; + blue_led_flag = (dc)?0:1; + led_blue(blue_led_flag?0:1); + ntx_led_set_timer (&blue_led_timer, blue_led_dc, blue_led_period); + break; + default: + break; + } +} + +void ntx_led_current (unsigned int channel, unsigned char value) +{ + g_Cus_Ctrl_Led = 1; + if (!value) + ntx_led_dc (channel, 0); +} + +static void FL_module_off(void) +{ + if(giFL_ON) { + gpio_direction_output(MX6SL_FL_EN,0); + } + else { + gpio_direction_input(MX6SL_FL_EN); + } + gpio_direction_input(MX6SL_FL_R_EN); + fl_pwm_enable (0); + msp430_fl_enable (0); +} + +void FL_off_func(struct work_struct *work) +{ + printk("[%s-%d]FL PWR off\n",__FUNCTION__,__LINE__); + FL_module_off(); +} + +int FL_suspend(void){ + if(delayed_work_pending(&FL_off)){ + return -1; + } + return 0; +} + +static int sleep_thread(void) +{ +int rc = 0; + + set_current_state(TASK_INTERRUPTIBLE); + if(signal_pending(current)) + rc = -EINTR; + __set_current_state(TASK_RUNNING); + return rc; +} + +static int LED_Thread(void *param) +{ + sigset_t thread_signal_mask; + siginitsetinv(&thread_signal_mask, sigmask(SIGKILL)); + sigprocmask(SIG_SETMASK, &thread_signal_mask, NULL); + + while(1){ + if(freezing(current)){ + printk("freeze 0 !!!!!!!!!!!!!!!!!!!!\n"); + try_to_freeze(); + } + + if(LED_conitnuous == 0){ + interruptible_sleep_on(&LED_freeze_WaitQueue); + if(freezing(current)){ + printk("freeze 1!!!!!!!!!!!!!!!!!!!!\n"); + try_to_freeze(); + } + } + if (g_Cus_Ctrl_Led) { + LED_conitnuous = 0; + continue; + } + led_green(1); + while (gKeepPowerAlive) { + sleep_on_timeout(&Reset_WaitQueue,HZ*2); + msp430_powerkeep(1); + } + //start to blink LED; + if (2 == LED_conitnuous) { + spin_lock(&led_flash_lock); + LED_Flash_Count = 0; + LED_conitnuous = 0; + spin_unlock(&led_flash_lock); + sleep_on_timeout(&LED_blink_WaitQueue,HZ/10); + led_green(0); + sleep_on_timeout(&LED_blink_WaitQueue,HZ/10); + led_green(1); + sleep_on_timeout(&LED_blink_WaitQueue,HZ/10); + if (!green_led_dc) + led_green(0); + sleep_on_timeout(&LED_blink_WaitQueue,HZ/10); + } + else { + sleep_on_timeout(&LED_blink_WaitQueue,HZ/2); + if (!green_led_dc) + led_green(0); + sleep_on_timeout(&LED_blink_WaitQueue,HZ/2); + } + } + return 0; +} + +static struct timer_list power_key_timer; + +extern void mxc_kpp_report_key(int isDown,__u16 wKeyCode); +extern void gpiokeys_report_key(int isDown,__u16 wKeyCode); +extern void mxc_kpp_report_power(int isDown); +extern void gpiokeys_report_power(int isDown); +extern void gpiokeys_report_event(unsigned int type, unsigned int code, int value); +extern void mxc_kpp_report_event(unsigned int type, unsigned int code, int value); + +void ntx_report_key(int isDown,__u16 wKeyCode) +{ + if(NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bPCB_Flags,0)) { + // no keymatrix . + gpiokeys_report_key(isDown, wKeyCode); + }else{ + mxc_kpp_report_key(isDown, wKeyCode); + } +} + +void ntx_report_event(unsigned int type, unsigned int code, int value) +{ + if(NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bPCB_Flags,0)) { + // no keymatrix . + gpiokeys_report_event(type,code,value); + }else{ + mxc_kpp_report_event(type,code,value); + } +} + +void ntx_report_power(int isDown) +{ + ntx_report_key(isDown, KEY_POWER); +} + +static void power_key_chk(unsigned long v) +{ + int iPwrKeyState=power_key_status(); + if (iPwrKeyState) { + ++g_power_key_debounce; + if (2 == g_power_key_debounce) { + ntx_report_power(1); + } + mod_timer(&power_key_timer, jiffies + 1); + } + else { + ntx_report_power(0); + } + +#if 0 //[ debug code . + printk("%s():PwrKeyState=%d,debounce=%d,IsCustomUI=%d\n",__FUNCTION__, + iPwrKeyState,g_power_key_debounce,gIsCustomerUi); +#endif //] +} + +void power_key_int_function(void) +{ + gMxcPowerKeyIrqTriggered = 1; + g_power_key_debounce = 0; + mod_timer(&power_key_timer, jiffies + 1); +} + +static irqreturn_t power_key_int(int irq, void *dev_id) +{ + //printk("%s !!\n",__FUNCTION__); + power_key_int_function(); + return 0; +} + +int ntx_charge_status (void) +{ + int iIsUSBPlugged = 0; + + if (1==gptHWCFG->m_val.bPMIC) { + iIsUSBPlugged = ricoh619_dcin_status(); + } + else { + iIsUSBPlugged = gpio_get_value (gMX6SL_NTX_ACIN_PG)?0:1; + } + if (!iIsUSBPlugged) { + return 0; + } + else { + return (1 | (gpio_get_value (gMX6SL_NTX_CHG)?0:2)); + } +} + +int mxc_usb_plug_getstatus (void) +{ + //if (gIsCustomerUi) + { + int usb_status = 0; +#if 1 + if (1==gptHWCFG->m_val.bPMIC) { + usb_status = ricoh619_dcin_status(); + g_ioctl_USB_status = usb_status?0:1; + return usb_status; + } + else +#endif + usb_status = gpio_get_value (gMX6SL_NTX_ACIN_PG); + + DBG_MSG("%s(),USB status=%d\n",__FUNCTION__,g_ioctl_USB_status); + g_ioctl_USB_status = usb_status?0:1; + return g_ioctl_USB_status; + } + //else { + //return 0; + //} +} + +/*! + * Key raw pins interrupt handler. + */ +static irqreturn_t gpio_key_row_int(int irq, void *dev_id) +{ +// pr_info(KERN_INFO "key matrix pressed ...\n"); + return 0; +} + +// NTX_GPIO_KEYS +#define NTX_GPIO_KEYS_MAX 5 +static int gi_ntx_gpio_buttons_total = 0; +static struct gpio_keys_button ntx_gpio_buttons[NTX_GPIO_KEYS_MAX] = { + {0,}, +}; +static struct gpio_keys_platform_data ntx_gpio_key_data = { + .buttons=ntx_gpio_buttons, + .nbuttons=0, + .rep=0, +}; +static struct platform_device ntx_gpio_key_device = { + .name = "mxckpd", + .id = -1, + .dev = { + .platform_data = &ntx_gpio_key_data, + }, +}; + +static void mxc_pads_dse_setup(iomux_v3_cfg_t *pad_list, unsigned count,iomux_v3_cfg_t tDSE_PAD_VAL) +{ + iomux_v3_cfg_t *p = pad_list; + int i; + iomux_v3_cfg_t tDSE_PAD_MASK=(iomux_v3_cfg_t)0x38<<MUX_PAD_CTRL_SHIFT; + iomux_v3_cfg_t tDSE_PAD_Current; + + tDSE_PAD_VAL <<= MUX_PAD_CTRL_SHIFT; + tDSE_PAD_VAL &= tDSE_PAD_MASK; + + for(i=0;i<count;i++) { + mxc_iomux_v3_get_pad(p); + + tDSE_PAD_Current = *p; + + *p &= ~tDSE_PAD_MASK; + *p |= tDSE_PAD_VAL; + + //printk("PAD set 0x%llx->0x%llx \n",tDSE_PAD_Current,*p); + mxc_iomux_v3_setup_pad(*p); + p++; + } +} + +#define GPIO_BAT_LOW_INT IMX_GPIO_NR(3, 28) /* COL2 */ +static irqreturn_t bat_low_int(int irq, void *dev_id) +{ + printk ("[%s-%d] triggered!!\n", __func__, __LINE__); + return 0; +} + + +static int gpio_initials(void) +{ + int irq, ret; + int error; + + mxc_iomux_v3_setup_pad(MX6SL_PAD_KEY_COL2__GPIO_3_28); + gpio_request (GPIO_BAT_LOW_INT, "MX6SL_BAT_LOW"); + gpio_direction_input(GPIO_BAT_LOW_INT); +#if 0 + irq = gpio_to_irq(GPIO_BAT_LOW_INT); + ret = request_irq(irq, bat_low_int, IRQF_TRIGGER_FALLING, "bat_low", 0); + if (ret) + pr_info("register on-off key interrupt failed\n"); + else + enable_irq_wake(irq); +#endif +#ifndef CONFIG_ANDROID//[ + if(0==gptHWCFG->m_val.bUIStyle) { + // Ebrmain . + + power_key_timer.function = power_key_chk; + init_timer(&power_key_timer); + /* OFF_CHK */ + #ifdef GPIOFN_PWRKEY//[ + gpiofn_register(>NTX_PWR_GPIO_data); + #else //][!GPIOFN_PWRKEY + + gpio_direction_input(gMX6SL_PWR_SW); + { + /* Set power key as wakeup resource */ + irq = gpio_to_irq(gMX6SL_PWR_SW); + ret = request_irq(irq, power_key_int, IRQF_TRIGGER_FALLING, "power_key", 0); + if (ret) + pr_info("register on-off key interrupt failed\n"); + else + enable_irq_wake(irq); + } + } + #endif //]GPIOFN_PWRKEY +#endif//]CONFIG_ANDROID + + + gpio_direction_output(gMX6SL_IR_TOUCH_RST, 0); + msleep(20); + gpio_direction_input(gMX6SL_IR_TOUCH_RST); + + // MX6SL_FL_EN + if( 0 != gptHWCFG->m_val.bFrontLight ){ + if(NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bFrontLight_Flags,2)){ + // FL_EN invert . + //printk("FL_EN inverted !\n",__FUNCTION__); + giFL_ON=1; + } + if( 0 == NTXHWCFG_TST_FLAG(gptHWCFG->m_val.bFrontLight_Flags,0)){ + FL_module_off(); + } + INIT_DELAYED_WORK(&FL_off, FL_off_func); + } + +#ifdef _WIFI_ALWAYS_ON_ + set_irq_type(gpio_to_irq(gMX6SL_WIFI_INT), IRQF_TRIGGER_FALLING); +#endif + + if(40==gptHWCFG->m_val.bPCB||49==gptHWCFG->m_val.bPCB) { + // E60Q5X / E60QDX for EMI . + printk("EMMC DSE set to 48 ohm \n"); + mxc_pads_dse_setup(mx6sl_brd_ntx_sd4_pads, + ARRAY_SIZE(mx6sl_brd_ntx_sd4_pads),(iomux_v3_cfg_t)PAD_CTL_DSE_48ohm); + } + + // initial test point for ESD , Joseph 20100504 + return 0; +} + +#include <mach/hardware.h> +#define SSI1_IO_BASE_ADDR IO_ADDRESS(SSI1_BASE_ADDR) +#define SSI2_IO_BASE_ADDR IO_ADDRESS(SSI2_BASE_ADDR) +#define SSI1_SCR ((SSI1_IO_BASE_ADDR) + 0x10) +#define SSI2_SCR ((SSI2_IO_BASE_ADDR) + 0x10) + +#include <mach/arc_otg.h> +#include "crm_regs.h" +extern void __iomem *apll_base; +unsigned long gUart_ucr1; + +static iomux_v3_cfg_t ntx_suspend_enter_pads[] = { + // I2C1,I2C2 + MX6SL_PAD_I2C2_SCL__GPIO_3_14, + MX6SL_PAD_I2C2_SDA__GPIO_3_15, + MX6SL_PAD_I2C1_SCL__GPIO_3_12, + MX6SL_PAD_I2C1_SDA__GPIO_3_13, + // SD2 + MX6SL_PAD_SD2_CLK__GPIO_5_5, + MX6SL_PAD_SD2_CMD__GPIO_5_4, + MX6SL_PAD_SD2_DAT0__GPIO_5_1, + MX6SL_PAD_SD2_DAT1__GPIO_4_30, + MX6SL_PAD_SD2_DAT2__GPIO_5_3, + MX6SL_PAD_SD2_DAT3__GPIO_4_28, + // SD3 + MX6SL_PAD_SD3_CLK__GPIO_5_18, + MX6SL_PAD_SD3_CMD__GPIO_5_21, + MX6SL_PAD_SD3_DAT0__GPIO_5_19, + MX6SL_PAD_SD3_DAT1__GPIO_5_20, + MX6SL_PAD_SD3_DAT2__GPIO_5_16, + MX6SL_PAD_SD3_DAT3__GPIO_5_17, + // SD4 + MX6SL_PAD_FEC_TX_CLK__GPIO_4_21, + MX6SL_PAD_FEC_MDIO__GPIO_4_20, + MX6SL_PAD_FEC_RX_ER__GPIO_4_19, + MX6SL_PAD_FEC_CRS_DV__GPIO_4_25, + MX6SL_PAD_FEC_RXD1__GPIO_4_18, + MX6SL_PAD_FEC_TXD0__GPIO_4_24, + MX6SL_PAD_FEC_MDC__GPIO_4_23, + MX6SL_PAD_FEC_RXD0__GPIO_4_17, + MX6SL_PAD_FEC_TX_EN__GPIO_4_22, + MX6SL_PAD_FEC_TXD1__GPIO_4_16, + MX6SL_PAD_FEC_REF_CLK__GPIO_4_26, + + // TEST ONLY + MX6SL_PAD_ECSPI1_MISO__GPIO_4_10, + MX6SL_PAD_ECSPI1_MOSI__GPIO_4_9, + MX6SL_PAD_ECSPI1_SCLK__GPIO_4_8, + MX6SL_PAD_ECSPI1_SS0__GPIO_4_11, + + MX6SL_PAD_ECSPI2_MISO__GPIO_4_14, + MX6SL_PAD_ECSPI2_MOSI__GPIO_4_13, + MX6SL_PAD_ECSPI2_SCLK__GPIO_4_12, + MX6SL_PAD_ECSPI2_SS0__GPIO_4_15, + + MX6SL_PAD_EPDC_BDR0__GPIO_2_5, + MX6SL_PAD_EPDC_BDR1__GPIO_2_6, + MX6SL_PAD_EPDC_D0__GPIO_1_7, + MX6SL_PAD_EPDC_D1__GPIO_1_8, + MX6SL_PAD_EPDC_D10__GPIO_1_17, + MX6SL_PAD_EPDC_D11__GPIO_1_18, + MX6SL_PAD_EPDC_D12__GPIO_1_19, + MX6SL_PAD_EPDC_D13__GPIO_1_20, + MX6SL_PAD_EPDC_D14__GPIO_1_21, + MX6SL_PAD_EPDC_D15__GPIO_1_22, + MX6SL_PAD_EPDC_D2__GPIO_1_9, + MX6SL_PAD_EPDC_D3__GPIO_1_10, + MX6SL_PAD_EPDC_D4__GPIO_1_11, + MX6SL_PAD_EPDC_D5__GPIO_1_12, + MX6SL_PAD_EPDC_D6__GPIO_1_13, + MX6SL_PAD_EPDC_D7__GPIO_1_14, + MX6SL_PAD_EPDC_D8__GPIO_1_15, + MX6SL_PAD_EPDC_D9__GPIO_1_16, + MX6SL_PAD_EPDC_GDCLK__GPIO_1_31, + MX6SL_PAD_EPDC_GDOE__GPIO_2_0, + MX6SL_PAD_EPDC_GDRL__GPIO_2_1, + MX6SL_PAD_EPDC_GDSP__GPIO_2_2, +// MX6SL_PAD_EPDC_PWRCOM__GPIO_2_11, + MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7, + MX6SL_PAD_EPDC_PWRCTRL1__GPIO_2_8, + MX6SL_PAD_EPDC_PWRCTRL2__GPIO_2_9, + MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10, + MX6SL_PAD_EPDC_PWRINT__GPIO_2_12, + MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13, + MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14, + MX6SL_PAD_EPDC_SDCE0__GPIO_1_27, + MX6SL_PAD_EPDC_SDCE1__GPIO_1_28, + MX6SL_PAD_EPDC_SDCE2__GPIO_1_29, + MX6SL_PAD_EPDC_SDCE3__GPIO_1_30, + MX6SL_PAD_EPDC_SDCLK__GPIO_1_23, + MX6SL_PAD_EPDC_SDLE__GPIO_1_24, + MX6SL_PAD_EPDC_SDOE__GPIO_1_25, + MX6SL_PAD_EPDC_SDSHR__GPIO_1_26, + MX6SL_PAD_EPDC_VCOM0__GPIO_2_3, + MX6SL_PAD_EPDC_VCOM1__GPIO_2_4, + +/* +ffffff80 +000077ff +0000f000 +53ffff00 +003f003a +*/ + MX6SL_PAD_HSIC_DAT__GPIO_3_19, + MX6SL_PAD_HSIC_STROBE__GPIO_3_20, + MX6SL_PAD_KEY_COL0__GPIO_3_24, + MX6SL_PAD_KEY_COL1__GPIO_3_26, + MX6SL_PAD_KEY_COL2__GPIO_3_28, + MX6SL_PAD_KEY_COL3__GPIO_3_30, + MX6SL_PAD_KEY_COL4__GPIO_4_0, + MX6SL_PAD_KEY_COL5__GPIO_4_2, + MX6SL_PAD_KEY_COL6__GPIO_4_4, + MX6SL_PAD_KEY_COL7__GPIO_4_6, + MX6SL_PAD_KEY_ROW0__GPIO_3_25, + MX6SL_PAD_KEY_ROW1__GPIO_3_27, + MX6SL_PAD_KEY_ROW2__GPIO_3_29, + MX6SL_PAD_KEY_ROW3__GPIO_3_31, + MX6SL_PAD_KEY_ROW4__GPIO_4_1, + MX6SL_PAD_KEY_ROW5__GPIO_4_3, + MX6SL_PAD_KEY_ROW6__GPIO_4_5, + MX6SL_PAD_KEY_ROW7__GPIO_4_7, +/* +ffffff80 +000077ff +ff18f000 +57ffffff +003f003a +*/ + MX6SL_PAD_LCD_CLK__GPIO_2_15, + MX6SL_PAD_LCD_DAT0__GPIO_2_20, + MX6SL_PAD_LCD_DAT1__GPIO_2_21, + MX6SL_PAD_LCD_DAT10__GPIO_2_30, + MX6SL_PAD_LCD_DAT11__GPIO_2_31, + MX6SL_PAD_LCD_DAT12__GPIO_3_0, + MX6SL_PAD_LCD_DAT13__GPIO_3_1, + MX6SL_PAD_LCD_DAT14__GPIO_3_2, + MX6SL_PAD_LCD_DAT15__GPIO_3_3, + MX6SL_PAD_LCD_DAT16__GPIO_3_4, + MX6SL_PAD_LCD_DAT17__GPIO_3_5, + MX6SL_PAD_LCD_DAT18__GPIO_3_6, + MX6SL_PAD_LCD_DAT19__GPIO_3_7, + MX6SL_PAD_LCD_DAT2__GPIO_2_22, + MX6SL_PAD_LCD_DAT20__GPIO_3_8, + MX6SL_PAD_LCD_DAT21__GPIO_3_9, + MX6SL_PAD_LCD_DAT22__GPIO_3_10, + MX6SL_PAD_LCD_DAT23__GPIO_3_11, + MX6SL_PAD_LCD_DAT3__GPIO_2_23, + MX6SL_PAD_LCD_DAT4__GPIO_2_24, + MX6SL_PAD_LCD_DAT5__GPIO_2_25, + MX6SL_PAD_LCD_DAT6__GPIO_2_26, + MX6SL_PAD_LCD_DAT7__GPIO_2_27, + MX6SL_PAD_LCD_DAT8__GPIO_2_28, + MX6SL_PAD_LCD_DAT9__GPIO_2_29, + MX6SL_PAD_LCD_ENABLE__GPIO_2_16, + MX6SL_PAD_LCD_HSYNC__GPIO_2_17, + MX6SL_PAD_LCD_RESET__GPIO_2_19, + MX6SL_PAD_LCD_VSYNC__GPIO_2_18, + MX6SL_PAD_PWM1__GPIO_3_23, + MX6SL_PAD_REF_CLK_24M__GPIO_3_21, + MX6SL_PAD_REF_CLK_32K__GPIO_3_22, + MX6SL_PAD_SD1_CLK__GPIO_5_15, + MX6SL_PAD_SD1_CMD__GPIO_5_14, + MX6SL_PAD_SD1_DAT0__GPIO_5_11, + MX6SL_PAD_SD1_DAT1__GPIO_5_8, + MX6SL_PAD_SD1_DAT2__GPIO_5_13, + MX6SL_PAD_SD1_DAT3__GPIO_5_6, + MX6SL_PAD_SD1_DAT4__GPIO_5_12, + MX6SL_PAD_SD1_DAT5__GPIO_5_9, + MX6SL_PAD_SD1_DAT6__GPIO_5_7, + MX6SL_PAD_SD1_DAT7__GPIO_5_10, + MX6SL_PAD_SD2_DAT4__GPIO_5_2, + MX6SL_PAD_SD2_DAT5__GPIO_4_31, +// MX6SL_PAD_SD2_DAT6__GPIO_4_29, + MX6SL_PAD_SD2_DAT7__GPIO_5_0, + MX6SL_PAD_SD2_RST__GPIO_4_27, +// MX6SL_PAD_UART1_RXD__GPIO_3_16, +// MX6SL_PAD_UART1_TXD__GPIO_3_17, + MX6SL_PAD_WDOG_B__GPIO_3_18, +/* +0xffffff80 +0xfffff7ff +0xfffcffff +0xdfffffff +0x003fffff + + 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 +2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 1 +3 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +4 1 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +5 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + +*/ + +}; + +#define dump_pad_iomux_val(_pad_name,_iomux_v3cfg,pin_func_str,desc_str) \ + {\ + iomux_v3_cfg_t tDSE_PAD_Current;\ + tDSE_PAD_Current=_iomux_v3cfg;\ + mxc_iomux_v3_get_pad(&tDSE_PAD_Current);\ + printk("%s(%d):%s %s(%s)= 0x%llx \n",__func__,__LINE__,\ + desc_str,#_pad_name,pin_func_str,tDSE_PAD_Current);\ + printk("\tpadctrl=0x%x\n",(tDSE_PAD_Current>>MUX_PAD_CTRL_SHIFT)&0x43ffff);\ + printk("\tmode=0x%x\n",(tDSE_PAD_Current>>MUX_MODE_SHIFT)&0x1f);\ + printk("\tinput=0x%x\n",(tDSE_PAD_Current>>MUX_SEL_INPUT_SHIFT)&0xf);\ + } + +static unsigned int ntx_gpio_dir[5],ntx_gpio_insuspend_dir[5]; +static iomux_v3_cfg_t local_suspend_enter_pads[ARRAY_SIZE(ntx_suspend_enter_pads)]; +static iomux_v3_cfg_t ntx_suspend_exit_pads[ARRAY_SIZE(ntx_suspend_enter_pads)]; + +extern int fl_level; // If FL is on, value is 0-100. If FL is off, value is 0; +extern int fl_current; // Unit is 1uA. If FL is off, value is 0; +extern int slp_state; // 0:Suspend, 1:Hibernate +extern int idle_current; // Unit is 1uA. +extern int sus_current; // Unit is 1uA. +extern int hiber_current; // Unit is 1uA. +extern bool bat_alert_req_flg; // 0:Normal, 1:Re-synchronize request from system +void ricoh_suspend_state_sync(void) +{ + const int fl_currentA[] = { + 620 , 720 , 830 , 990 , 1120 , 1300 , 1460 , 1590 , 1750 , 2020 , // 01 ~ 10 + 2330 , 2610 , 2900 , 3260 , 3570 , 3900 , 4100 , 4300 , 4510 , 6230 , // 11 ~ 20 + 6640 , 6840 , 7270 , 7690 , 8100 , 8520 , 8930 , 9350 , 9810 , 10180, // 21 ~ 30 + 10610, 11010, 11430, 11860, 12310, 12700, 13160, 13560, 13960, 14370, // 31 ~ 40 + 14730, 15130, 15530, 15930, 16530, 17330, 17920, 18300, 18720, 19120, // 41 ~ 50 + 19720, 20320, 20930, 21320, 21720, 22330, 22940, 23340, 23760, 24170, // 51 ~ 60 + 24570, 25180, 25780, 26180, 26790, 27190, 27820, 28220, 28630, 29260, // 61 ~ 70 + 29860, 30500, 31090, 31700, 32310, 32740, 33140, 33760, 34200, 35230, // 71 ~ 80 + 35850, 36460, 37910, 39370, 40200, 41050, 41890, 42700, 44400, 45880, // 81 ~ 90 + 47360, 48860, 50560, 51160, 52000, 53070, 54150, 55440, 56710, 58000, // 91 ~ 100 + }; + fl_level = last_FL_duty; // If FL is on, value is 0-100. If FL is off, value is 0; + if (last_FL_duty) + fl_current = fl_currentA[last_FL_duty-1]; // Unit is 1uA. If FL is off, value is 0; + else + fl_current = 0; + slp_state = gSleep_Mode_Suspend?1:0; // 0:Suspend, 1:Hibernate + idle_current = 1000; // Unit is 1uA. + sus_current = 1900; // Unit is 1uA. + hiber_current = 889; // Unit is 1uA. + bat_alert_req_flg = 0; // 0:Normal, 1:Re-synchronize request from system +} + +//#define DUMP_PADS 1 +extern int mxc_epdc_fb_ep1v8_output(int iIsOutput); + +void ntx_gpio_suspend (void) +{ + g_wakeup_by_alarm = 0; + + + led_blue(0); + led_green(0); + + gpiofn_suspend(); + if (gSleep_Mode_Suspend) { + + ntx_gpio_insuspend_dir[0]=0xffffff80; + ntx_gpio_insuspend_dir[1]=0xfffff7ff; + ntx_gpio_insuspend_dir[2]=0xfffcffff; + ntx_gpio_insuspend_dir[3]=0xdfffffff; + ntx_gpio_insuspend_dir[4]=0x003fffff; + + + if(7==gptHWCFG->m_val.bDisplayCtrl) { + tps65185_ONOFF(0); + } + else if(8==gptHWCFG->m_val.bDisplayCtrl) { + fp9928_ONOFF(0); + } + //mxc_epdc_fb_ep1v8_output(0); + //gpio_direction_output (GPIO_EP_3V3_ON, 0); + //gpio_direction_output (MX6SL_EP_PWRALL, 0); + + + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SCL__GPIO_3_12); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SDA__GPIO_3_13); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C2_SCL__GPIO_3_14); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C2_SDA__GPIO_3_15); + + if(3==gptHWCFG->m_val.bTouchType || 4==gptHWCFG->m_val.bTouchType) { + if(0x03!=gptHWCFG->m_val.bUIConfig) { + // turn off ir touch power. + gpio_direction_output (gMX6SL_IR_TOUCH_INT, 0); + + gpio_direction_output (gMX6SL_IR_TOUCH_RST, 0); + gpio_direction_output (GPIO_IR_3V3_ON, 0); + } + } + + } + + gUart_ucr1 = __raw_readl(ioremap(MX6SL_UART1_BASE_ADDR, SZ_4K)+0x80); + __raw_writel(0, ioremap(MX6SL_UART1_BASE_ADDR, SZ_4K)+0x80); + + if (gSleep_Mode_Suspend) { + iomux_v3_cfg_t *p = local_suspend_enter_pads; + int i; + void __iomem *base; + unsigned long dwDisableBit ; + + /* Set PADCTRL to 0 for all IOMUX. */ + for (i = 0; i < ARRAY_SIZE(ntx_suspend_enter_pads); i++) { + *p = ntx_suspend_exit_pads[i] = ntx_suspend_enter_pads[i]; + + if(1==gptHWCFG->m_val.bPMIC) { + // pads for Ricoh PMIC . + // I2C3_SCL,I2C3_SDA,CHG,BAT_LOW_INT,PMU_INT + if( ((*p)==(MX6SL_PAD_REF_CLK_24M__GPIO_3_21)) || + ((*p)==(MX6SL_PAD_REF_CLK_32K__GPIO_3_22)) || + ((*p)==(MX6SL_PAD_SD1_CLK__GPIO_5_15)) || + ((*p)==(MX6SL_PAD_KEY_COL2__GPIO_3_28)) || + ((*p)==(MX6SL_PAD_SD1_DAT0__GPIO_5_11)) ) + { + continue ; + } + } + + if( (*p) == (MX6SL_PAD_SD3_CLK__GPIO_5_18) || + (*p) == (MX6SL_PAD_SD3_CMD__GPIO_5_21) || + (*p) == (MX6SL_PAD_SD3_DAT0__GPIO_5_19) || + (*p) == (MX6SL_PAD_SD3_DAT1__GPIO_5_20) || + (*p) == (MX6SL_PAD_SD3_DAT2__GPIO_5_16) || + (*p) == (MX6SL_PAD_SD3_DAT3__GPIO_5_17) ) + { + *p &= ~MUX_PAD_CTRL_MASK; + /* Enable the Pull down and the keeper + * Set the drive strength to 0. + */ + *p |= ((u64)0x3000 << MUX_PAD_CTRL_SHIFT); + } + else if((*p) == (MX6SL_PAD_FEC_MDIO__GPIO_4_20 )|| + (*p) == (MX6SL_PAD_FEC_TX_CLK__GPIO_4_21)|| + (*p) == (MX6SL_PAD_FEC_RX_ER__GPIO_4_19 )|| + (*p) == (MX6SL_PAD_FEC_CRS_DV__GPIO_4_25)|| + (*p) == (MX6SL_PAD_FEC_RXD1__GPIO_4_18 )|| + (*p) == (MX6SL_PAD_FEC_TXD0__GPIO_4_24 )|| + (*p) == (MX6SL_PAD_FEC_MDC__GPIO_4_23 )|| + (*p) == (MX6SL_PAD_FEC_RXD0__GPIO_4_17 )|| + (*p) == (MX6SL_PAD_FEC_TX_EN__GPIO_4_22 )|| + (*p) == (MX6SL_PAD_FEC_TXD1__GPIO_4_16 )|| + (*p) == (MX6SL_PAD_FEC_REF_CLK__GPIO_4_26)) + { + // EMMC PADS +#if 1 + if( 2==gptHWCFG->m_val.bIFlash ) +#else + if (37==gptHWCFG->m_val.bPCB /* E60QBX */|| +/* >=E60Q30A10 */((36==gptHWCFG->m_val.bPCB) && gptHWCFG->m_val.bPCB_REV>=0x10) || + 40==gptHWCFG->m_val.bPCB /* E60Q5X */ ) +#endif + { + *p &= ~MUX_PAD_CTRL_MASK; + /* Enable the Pull down and the keeper + * Set the drive strength to 0. + */ + *p |= ((u64)0x3000 << MUX_PAD_CTRL_SHIFT); + } + } + else if((*p) == (MX6SL_PAD_KEY_ROW5__GPIO_4_3) && + (((36==gptHWCFG->m_val.bPCB) && gptHWCFG->m_val.bPCB_REV>=0x10) || + (40==gptHWCFG->m_val.bPCB)||(47==gptHWCFG->m_val.bPCB)||(49==gptHWCFG->m_val.bPCB))) + { + // E60Q3X revA10 , E60Q5X , ED0Q0X , E60QDX + // GPIO 4_3 for EP_3V3_ON . + } + else if((*p) == (MX6SL_PAD_KEY_ROW3__GPIO_3_31) && (giISD_3V3_ON_Ctrl!=-1) ) + { + //only >=E60Q30A10 can turn off ISD_3V3 + + gpio_direction_output (GPIO_ISD_3V3_ON, giISD_3V3_ON_Ctrl?0:1); + } + else if( (*p) == (MX6SL_PAD_KEY_ROW4__GPIO_4_1) || + (*p) == (MX6SL_PAD_KEY_ROW5__GPIO_4_3) || + (*p) == (MX6SL_PAD_EPDC_SDCE2__GPIO_1_29) ) { + // pull down + *p &= ~MUX_PAD_CTRL_MASK; + *p |= ((u64)0x30b0 << MUX_PAD_CTRL_SHIFT); + } +/* else if( + (*p) == MX6SL_PAD_EPDC_BDR0__GPIO_2_5 || + (*p) == MX6SL_PAD_EPDC_BDR1__GPIO_2_6 || + (*p) == MX6SL_PAD_EPDC_D0__GPIO_1_7 || + (*p) == MX6SL_PAD_EPDC_D1__GPIO_1_8 || + (*p) == MX6SL_PAD_EPDC_D10__GPIO_1_17 || + (*p) == MX6SL_PAD_EPDC_D11__GPIO_1_18 || + (*p) == MX6SL_PAD_EPDC_D12__GPIO_1_19 || + (*p) == MX6SL_PAD_EPDC_D13__GPIO_1_20 || + (*p) == MX6SL_PAD_EPDC_D14__GPIO_1_21 || + (*p) == MX6SL_PAD_EPDC_D15__GPIO_1_22 || + (*p) == MX6SL_PAD_EPDC_D2__GPIO_1_9 || + (*p) == MX6SL_PAD_EPDC_D3__GPIO_1_10 || + (*p) == MX6SL_PAD_EPDC_D4__GPIO_1_11 || + (*p) == MX6SL_PAD_EPDC_D5__GPIO_1_12 || + (*p) == MX6SL_PAD_EPDC_D6__GPIO_1_13 || + (*p) == MX6SL_PAD_EPDC_D7__GPIO_1_14 || + (*p) == MX6SL_PAD_EPDC_D8__GPIO_1_15 || + (*p) == MX6SL_PAD_EPDC_D9__GPIO_1_16 || + (*p) == MX6SL_PAD_EPDC_GDCLK__GPIO_1_31 || + (*p) == MX6SL_PAD_EPDC_GDOE__GPIO_2_0 || + (*p) == MX6SL_PAD_EPDC_GDRL__GPIO_2_1 || + (*p) == MX6SL_PAD_EPDC_GDSP__GPIO_2_2 || + (*p) == MX6SL_PAD_EPDC_PWRCOM__GPIO_2_11 || + (*p) == MX6SL_PAD_EPDC_PWRCTRL0__GPIO_2_7 || + (*p) == MX6SL_PAD_EPDC_PWRCTRL1__GPIO_2_8 || + (*p) == MX6SL_PAD_EPDC_PWRCTRL2__GPIO_2_9 || + (*p) == MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10 || + (*p) == MX6SL_PAD_EPDC_PWRINT__GPIO_2_12 || + (*p) == MX6SL_PAD_EPDC_PWRSTAT__GPIO_2_13 || + (*p) == MX6SL_PAD_EPDC_PWRWAKEUP__GPIO_2_14 || + (*p) == MX6SL_PAD_EPDC_SDCE0__GPIO_1_27 || + (*p) == MX6SL_PAD_EPDC_SDCE1__GPIO_1_28 || + (*p) == MX6SL_PAD_EPDC_SDCE2__GPIO_1_29 || + (*p) == MX6SL_PAD_EPDC_SDCE3__GPIO_1_30 || + (*p) == MX6SL_PAD_EPDC_SDCLK__GPIO_1_23 || + (*p) == MX6SL_PAD_EPDC_SDLE__GPIO_1_24 || + (*p) == MX6SL_PAD_EPDC_SDOE__GPIO_1_25 || + (*p) == MX6SL_PAD_EPDC_SDSHR__GPIO_1_26 || + (*p) == MX6SL_PAD_EPDC_VCOM0__GPIO_2_3 || + (*p) == MX6SL_PAD_EPDC_VCOM1__GPIO_2_4 + ) { + *p &= ~MUX_PAD_CTRL_MASK; + *p |= ((u64)0x3000 << MUX_PAD_CTRL_SHIFT); + } +*/ + else if ( (*p) == MX6SL_PAD_SD2_DAT6__GPIO_4_29 || + (*p) == MX6SL_PAD_SD1_DAT6__GPIO_5_7 || + ((1==gptHWCFG->m_val.bLed)&&((*p)==MX6SL_PAD_SD1_DAT2__GPIO_5_13)) ) + { + // pull up + if((*p) == MX6SL_PAD_SD1_DAT6__GPIO_5_7&&(36==gptHWCFG->m_val.bPCB || 40==gptHWCFG->m_val.bPCB + || 49==gptHWCFG->m_val.bPCB)) + { + // E60Q3X/E60Q5X/E60QDX + // skip set pad of GP5_7 for Green LED . + } + else { + *p &= ~MUX_PAD_CTRL_MASK; + *p |= ((u64)0x0001b0b1 << MUX_PAD_CTRL_SHIFT); + } + } + else if( (*p) == MX6SL_PAD_EPDC_PWRCTRL3__GPIO_2_10) { + + if(0==giFL_ON) { + // open drain + *p &= ~MUX_PAD_CTRL_MASK; + *p |= ((u64)0x000108b0 << MUX_PAD_CTRL_SHIFT); + } + } + else { + if((36==gptHWCFG->m_val.bPCB||40==gptHWCFG->m_val.bPCB||49==gptHWCFG->m_val.bPCB) && + ((*p) == (MX6SL_PAD_SD1_DAT7__GPIO_5_10 )) ) + { + // E60Q3X ,E60Q5X, E60QDX + // skip setting home led to floating state . + } + else { + // floating + *p &= ~MUX_PAD_CTRL_MASK; + *p |= ((u64)0x000110b0 << MUX_PAD_CTRL_SHIFT); + } + } + p++; + } + + // Direction control . + mxc_iomux_v3_get_multiple_pads(ntx_suspend_exit_pads, + ARRAY_SIZE(ntx_suspend_exit_pads)); + +#ifdef DUMP_PADS//[ + dump_pad_iomux_val(MX6SL_PAD_REF_CLK_24M,MX6SL_PAD_REF_CLK_24M__GPIO_3_21, + "I2C3_SCL","before hibernation"); + dump_pad_iomux_val(MX6SL_PAD_REF_CLK_32K,MX6SL_PAD_REF_CLK_32K__GPIO_3_22, + "I2C3_SDA","before hibernation"); +#endif//] DUMP_PADS + mxc_iomux_v3_setup_multiple_pads(local_suspend_enter_pads, + ARRAY_SIZE(local_suspend_enter_pads)); + +#ifdef DUMP_PADS//[ + dump_pad_iomux_val(MX6SL_PAD_REF_CLK_24M,MX6SL_PAD_REF_CLK_24M__GPIO_3_21, + "I2C3_SCL","in hibernation"); + dump_pad_iomux_val(MX6SL_PAD_REF_CLK_32K,MX6SL_PAD_REF_CLK_32K__GPIO_3_22, + "I2C3_SDA","in hibernation"); +#endif//]DUMP_PADS + + if(giFL_ON) { + // set as output . + dwDisableBit = (unsigned long)(1<<10); + ntx_gpio_insuspend_dir[1] &= ~dwDisableBit; //GP2_10 + } + + if( (36==gptHWCFG->m_val.bPCB && gptHWCFG->m_val.bPCB_REV>=0x10) || + 40==gptHWCFG->m_val.bPCB || 49==gptHWCFG->m_val.bPCB) + { + // >=E60Q30A1 , E60Q5X , E60QDX + dwDisableBit = (unsigned long)(1<<3); + ntx_gpio_insuspend_dir[3] &= ~dwDisableBit; //GP4_3 for EP_3V3_ON output + dwDisableBit = (unsigned long)(1<<7); + ntx_gpio_insuspend_dir[4] &= ~dwDisableBit; //GP5_7 for POWER_LED output + dwDisableBit = (unsigned long)(1<<10); + ntx_gpio_insuspend_dir[4] &= ~dwDisableBit; //GP5_10 for HOME_LED output + } + else if(47==gptHWCFG->m_val.bPCB) + { + // ED0Q0X . + dwDisableBit = (unsigned long)(1<<3); + ntx_gpio_insuspend_dir[3] &= ~dwDisableBit; //GP4_3 for EP_3V3/1V8_ON output + dwDisableBit = (unsigned long)(1<<7); + ntx_gpio_insuspend_dir[4] &= ~dwDisableBit; //GP5_7 for (green)ACTION_LED output + } + + if(-1!=giISD_3V3_ON_Ctrl) { + dwDisableBit = (unsigned long)(1<<31); + ntx_gpio_insuspend_dir[2] &= ~dwDisableBit; //GP3_31 for ISD_3V3_ON output + } + + + base = IO_ADDRESS(GPIO1_BASE_ADDR); + ntx_gpio_dir[0] = __raw_readl(base+4); + __raw_writel( ntx_gpio_dir[0]&(~ntx_gpio_insuspend_dir[0]), base+4); + + base = IO_ADDRESS(GPIO2_BASE_ADDR); + ntx_gpio_dir[1] = __raw_readl(base+4); + __raw_writel( ntx_gpio_dir[1]&(~ntx_gpio_insuspend_dir[1]), base+4); + + base = IO_ADDRESS(GPIO3_BASE_ADDR); + ntx_gpio_dir[2] = __raw_readl(base+4); + __raw_writel( ntx_gpio_dir[2]&(~ntx_gpio_insuspend_dir[2]), base+4); + + base = IO_ADDRESS(GPIO4_BASE_ADDR); + ntx_gpio_dir[3] = __raw_readl(base+4); + __raw_writel( ntx_gpio_dir[3]&(~ntx_gpio_insuspend_dir[3]), base+4); + + base = IO_ADDRESS(GPIO5_BASE_ADDR); + ntx_gpio_dir[4] = __raw_readl(base+4); + __raw_writel( ntx_gpio_dir[4]&(~ntx_gpio_insuspend_dir[4]), base+4); + } +} + +void ntx_gpio_resume (void) +{ + if (gSleep_Mode_Suspend) { + void __iomem *base; + + base = IO_ADDRESS(GPIO1_BASE_ADDR); + __raw_writel( ntx_gpio_dir[0], base+4); + + base = IO_ADDRESS(GPIO2_BASE_ADDR); + __raw_writel( ntx_gpio_dir[1], base+4); + + base = IO_ADDRESS(GPIO3_BASE_ADDR); + __raw_writel( ntx_gpio_dir[2], base+4); + + base = IO_ADDRESS(GPIO4_BASE_ADDR); + __raw_writel( ntx_gpio_dir[3], base+4); + + base = IO_ADDRESS(GPIO5_BASE_ADDR); + __raw_writel( ntx_gpio_dir[4], base+4); + + mxc_iomux_v3_setup_multiple_pads(ntx_suspend_exit_pads, + ARRAY_SIZE(ntx_suspend_exit_pads)); + +#ifdef DUMP_PADS//[ + dump_pad_iomux_val(MX6SL_PAD_REF_CLK_24M,MX6SL_PAD_REF_CLK_24M__GPIO_3_21, + "I2C3_SCL","exit hibernation"); + dump_pad_iomux_val(MX6SL_PAD_REF_CLK_32K,MX6SL_PAD_REF_CLK_32K__GPIO_3_22, + "I2C3_SDA","exit hibernation"); +#endif//] DUMP_PADS + + } + __raw_writel(gUart_ucr1, ioremap(MX6SL_UART1_BASE_ADDR, SZ_4K)+0x80); + if (gSleep_Mode_Suspend) { + + if(-1!=giISD_3V3_ON_Ctrl) { + gpio_direction_output (GPIO_ISD_3V3_ON,giISD_3V3_ON_Ctrl?1:0); + } + + if(1==gptHWCFG->m_val.bLed) { + // Blue Led . + // ON_LED# + mxc_iomux_v3_setup_pad(MX6SL_PAD_SD1_DAT2__GPIO_5_13_PULLHIGH); + } + + + if((3==gptHWCFG->m_val.bTouchType || 4==gptHWCFG->m_val.bTouchType) && 0x03==gptHWCFG->m_val.bUIConfig) { + // IR Touch Type & MP/RD Mode for IR tool . + // reset ir touch + gpio_direction_output (gMX6SL_IR_TOUCH_RST, 0); + mdelay (20); + gpio_direction_output (gMX6SL_IR_TOUCH_RST, 1); + } + else { + // turn on ir touch power. + gpio_direction_output (GPIO_IR_3V3_ON, 1); + if (37 != gptHWCFG->m_val.bPCB) { + // E60QB0 . + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SCL__I2C1_SCL); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SDA__I2C1_SDA); + } + gpio_direction_input (gMX6SL_IR_TOUCH_INT); + mdelay (20); + gpio_direction_output (gMX6SL_IR_TOUCH_RST, 1); + } + + gpio_free(IMX_GPIO_NR(3, 14)); + gpio_free(IMX_GPIO_NR(3, 15)); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C2_SCL__I2C2_SCL); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C2_SDA__I2C2_SDA); + + //mxc_epdc_fb_ep1v8_output(1); + //gpio_direction_output (GPIO_EP_3V3_ON, 1); + //mdelay (5); + if(7==gptHWCFG->m_val.bDisplayCtrl) { + tps65185_ONOFF(1); + } + else if(8==gptHWCFG->m_val.bDisplayCtrl) { + fp9928_ONOFF(1); + } + //gpio_direction_output (MX6SL_EP_PWRALL, 1); + } + + gpiofn_resume(); + + if(36==gptHWCFG->m_val.bPCB || 40==gptHWCFG->m_val.bPCB || 49==gptHWCFG->m_val.bPCB) { + // E60Q3X/E60Q5X + if(mxc_usb_plug_getstatus()) { + led_red(1); + } + else { + led_red(0); + } + } + +#ifdef CONFIG_ANDROID //[ +#else //][!CONFIG_ANDROID + g_power_key_pressed = power_key_status(); // POWER key + if(0==gptHWCFG->m_val.bUIStyle) { + // Ebrmain . + if (g_power_key_pressed) + mod_timer(&power_key_timer, jiffies + 1); + } + + if (LED_conitnuous) + wake_up_interruptible(&LED_freeze_WaitQueue); + else { + ntx_led_blink (3, red_led_period); + ntx_led_blink (4, green_led_period); + ntx_led_blink (5, blue_led_period); + } +#endif //]CONFIG_ANDROID +} + + +#include <linux/regulator/consumer.h> +void ntx_gpio_touch_reset (void) +{ + struct regulator *reg_TP3V3 = NULL; + + printk ("[%s-%d] reset touch.\n",__func__,__LINE__); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SCL__GPIO_3_12); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SDA__GPIO_3_13); + + gpio_request(IMX_GPIO_NR(3, 12),"i2c1_scl"); + gpio_request(IMX_GPIO_NR(3, 13),"i2c1_sda"); + gpio_direction_output (IMX_GPIO_NR(3, 12), 0); + gpio_direction_output (IMX_GPIO_NR(3, 13), 0); + // turn off ir touch power. + gpio_direction_output (gMX6SL_IR_TOUCH_INT, 0); + gpio_direction_output(gMX6SL_IR_TOUCH_RST, 0); + if (1==gptHWCFG->m_val.bPMIC) { + reg_TP3V3 = regulator_get(NULL,"vdd_ir_3v3"); + if (IS_ERR(reg_TP3V3)) + printk ("[%s-%d] regulator_get vdd_ir_3v3 returned NULL!!\n",__func__,__LINE__); + else { + regulator_force_disable (reg_TP3V3); + } + } + else + gpio_direction_output (GPIO_IR_3V3_ON, 0); + msleep (200); + // turn on ir touch power. + if (1==gptHWCFG->m_val.bPMIC) { + if (IS_ERR(reg_TP3V3)) + printk ("[%s-%d] regulator_get vdd_ir_3v3 returned NULL!!\n",__func__,__LINE__); + else { + regulator_enable (reg_TP3V3); + regulator_put (reg_TP3V3); + } + } + else + gpio_direction_output (GPIO_IR_3V3_ON, 1); + gpio_free(IMX_GPIO_NR(3, 12)); + gpio_free(IMX_GPIO_NR(3, 13)); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SCL__I2C1_SCL); + mxc_iomux_v3_setup_pad(MX6SL_PAD_I2C1_SDA__I2C1_SDA); + gpio_direction_input (gMX6SL_IR_TOUCH_INT); + mdelay (20); + gpio_direction_output (gMX6SL_IR_TOUCH_RST, 1); +} + +void ntx_msp430_i2c_force_release (void) +{ + int retryCnt=20; + mxc_iomux_v3_setup_pad(MX6SL_PAD_REF_CLK_24M__GPIO_3_21); + gpio_request(MX6SL_I2C3_SDA, "i2c3_sda"); + gpio_direction_input (MX6SL_I2C3_SDA); + mxc_iomux_v3_setup_pad(MX6SL_PAD_REF_CLK_32K__GPIO_3_22); + gpio_request(MX6SL_I2C3_SCL, "i2c3_scl"); + gpio_direction_output (MX6SL_I2C3_SCL, 1); + // send clock out until i2c SDA released. + while (retryCnt-- && !gpio_get_value (MX6SL_I2C3_SDA)) { + gpio_set_value (MX6SL_I2C3_SCL,1); + udelay (5); + gpio_set_value (MX6SL_I2C3_SCL,0); + schedule_timeout (1); +// udelay (5); + } + // simulate i2c stop signal + gpio_direction_output (MX6SL_I2C3_SDA,0); + gpio_free(MX6SL_I2C3_SCL); + mxc_iomux_v3_setup_pad(MX6SL_PAD_REF_CLK_24M__I2C3_SCL); + udelay (2); + gpio_free(MX6SL_I2C3_SDA); + mxc_iomux_v3_setup_pad(MX6SL_PAD_REF_CLK_32K__I2C3_SDA); +} + + +void ntx_machine_restart(char mode, const char *cmd) +{ + if (cmd && ('\0' != *cmd)) { + printk("%s mode=%c,cmd=%s\n",__FUNCTION__,mode,cmd); + arm_machine_restart (mode, cmd); + } + else { + printk ("[%s-%d] do hardware reset...\n",__func__,__LINE__); + ntx_system_reset(0); + } +} + +void ntx_machine_poweroff(void) +{ + ntx_system_poweroff(__FUNCTION__); +} + +static int __init initDriver(void) +{ + int ret; + + ret = misc_register(&driverDevice); + if (ret < 0) { + printk("pvi_io: can't get major number\n"); + return ret; + } + + gpio_initials(); + + //start a kernel thread; + ret = kernel_thread(LED_Thread,NULL,CLONE_KERNEL); + if(ret < 0){ + printk("LED thread creat error\n"); + } + + //////////////////////// + green_led_timer.function = green_led_blink_func; + init_timer(&green_led_timer); + blue_led_timer.function = blue_led_blink_func; + init_timer(&blue_led_timer); + red_led_timer.function = red_led_blink_func; + init_timer(&red_led_timer); + + pm_power_off = ntx_machine_poweroff; + arm_pm_restart = ntx_machine_restart; + + return 0; +} +static void __exit exitDriver(void) { + misc_deregister(&driverDevice); +} +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joe"); +MODULE_VERSION("2007-9-20"); +MODULE_DESCRIPTION ("PVI_IO driver"); +module_init(initDriver); +module_exit(exitDriver); diff --git a/arch/arm/mach-mx6/mx6sl_ntx_pmic_pfuze100.c b/arch/arm/mach-mx6/mx6sl_ntx_pmic_pfuze100.c new file mode 100755 index 00000000..88f2c9c7 --- /dev/null +++ b/arch/arm/mach-mx6/mx6sl_ntx_pmic_pfuze100.c @@ -0,0 +1,471 @@ +/* + * 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., 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/err.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/pfuze.h> +#include <mach/irqs.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 PFUZE100_I2C_DEVICE_NAME "pfuze100" +/* 7-bit I2C bus slave address */ +#define PFUZE100_I2C_ADDR (0x08) + /*SWBST*/ +#define PFUZE100_SW1ASTANDBY 33 +#define PFUZE100_SW1ASTANDBY_STBY_VAL (0x19) /* 925mv */ +#define PFUZE100_SW1ASTANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SW1BSTANDBY 40 +#define PFUZE100_SW1BSTANDBY_STBY_VAL (0x19) /* 925mv */ +#define PFUZE100_SW1BSTANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SW1CSTANDBY 47 +#define PFUZE100_SW1CSTANDBY_STBY_VAL (0x19) /* 925mv */ +#define PFUZE100_SW1CSTANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SW2STANDBY 54 +#define PFUZE100_SW2STANDBY_STBY_VAL 0x0 +#define PFUZE100_SW2STANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SW3ASTANDBY 61 +#define PFUZE100_SW3ASTANDBY_STBY_VAL 0x0 +#define PFUZE100_SW3ASTANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SW3BSTANDBY 68 +#define PFUZE100_SW3BSTANDBY_STBY_VAL 0x0 +#define PFUZE100_SW3BSTANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SW4STANDBY 75 +#define PFUZE100_SW4STANDBY_STBY_VAL 0 +#define PFUZE100_SW4STANDBY_STBY_M (0x3f<<0) +#define PFUZE100_SWBSTCON1 102 +#define PFUZE100_SWBSTCON1_SWBSTMOD_VAL (0x1<<2) +#define PFUZE100_SWBSTCON1_SWBSTMOD_M (0x3<<2) +#define PFUZE100_SW1ACON 36 +#define PFUZE100_SW1ACON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1ACON_SPEED_M (0x3<<6) +#define PFUZE100_SW1CCON 49 +#define PFUZE100_SW1CCON_SPEED_VAL (0x1<<6) /*default */ +#define PFUZE100_SW1CCON_SPEED_M (0x3<<6) + +#ifdef CONFIG_MX6_INTER_LDO_BYPASS +static struct regulator_consumer_supply sw1_consumers[] = { + { + .supply = "VDDCORE", + } +}; +static struct regulator_consumer_supply sw1c_consumers[] = { + { + .supply = "VDDSOC", + }, +}; +#endif + +static struct regulator_consumer_supply sw2_consumers[] = { + { + .supply = "MICVDD", + .dev_name = "1-001a", + } +}; +static struct regulator_consumer_supply sw4_consumers[] = { + { + .supply = "AUD_1V8", + } +}; +static struct regulator_consumer_supply swbst_consumers[] = { + { + .supply = "SWBST_5V", + } +}; +static struct regulator_consumer_supply vgen1_consumers[] = { + { + .supply = "VGEN1_1V5", + } +}; +static struct regulator_consumer_supply vgen2_consumers[] = { + { + .supply = "VGEN2_1V5", + } +}; +static struct regulator_consumer_supply vgen3_consumers[] = { + { + .supply = "AVDD", + .dev_name = "1-001a", + }, + { + .supply = "DCVDD", + .dev_name = "1-001a", + }, + { + .supply = "CPVDD", + .dev_name = "1-001a", + }, + { + .supply = "PLLVDD", + .dev_name = "1-001a", + }, + { + .supply = "DBVDD", + .dev_name = "1-001a", + } +}; +static struct regulator_consumer_supply vgen4_consumers[] = { + { + .supply = "VGEN4_1V8", + } +}; +static struct regulator_consumer_supply vgen5_consumers[] = { + { + .supply = "VGEN5_2V8", + } +}; +static struct regulator_consumer_supply vgen6_consumers[] = { + { + .supply = "VGEN6_2V8", + } +}; + +static struct regulator_init_data sw1a_init = { + .constraints = { + .name = "PFUZE100_SW1A", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 650000, + .max_uV = 1437500, +#else + .min_uV = 300000, + .max_uV = 1875000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .boot_on = 1, + .always_on = 1, + }, +#ifdef CONFIG_MX6_INTER_LDO_BYPASS +#ifndef CONFIG_MACH_MX6SL_NTX + .num_consumer_supplies = ARRAY_SIZE(sw1_consumers), + .consumer_supplies = sw1_consumers, +#endif +#endif +}; + +static struct regulator_init_data sw1b_init = { + .constraints = { + .name = "PFUZE100_SW1B", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw1c_init = { + .constraints = { + .name = "PFUZE100_SW1C", + .min_uV = 300000, + .max_uV = 1875000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +#ifdef CONFIG_MX6_INTER_LDO_BYPASS +#ifndef CONFIG_MACH_MX6SL_NTX + .num_consumer_supplies = ARRAY_SIZE(sw1c_consumers), + .consumer_supplies = sw1c_consumers, +#endif +#endif +}; + +static struct regulator_init_data sw2_init = { + .constraints = { + .name = "PFUZE100_SW2", +#if PFUZE100_SW2_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw2_consumers), + .consumer_supplies = sw2_consumers, +}; + +static struct regulator_init_data sw3a_init = { + .constraints = { + .name = "PFUZE100_SW3A", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw3b_init = { + .constraints = { + .name = "PFUZE100_SW3B", +#if PFUZE100_SW3_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data sw4_init = { + .constraints = { + .name = "PFUZE100_SW4", +#if PFUZE100_SW4_VOL6 + .min_uV = 800000, + .max_uV = 3950000, +#else + .min_uV = 400000, + .max_uV = 1975000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(sw4_consumers), + .consumer_supplies = sw4_consumers, +}; + +static struct regulator_init_data swbst_init = { + .constraints = { + .name = "PFUZE100_SWBST", + .min_uV = 5000000, + .max_uV = 5150000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(swbst_consumers), + .consumer_supplies = swbst_consumers, +}; + +static struct regulator_init_data vsnvs_init = { + .constraints = { + .name = "PFUZE100_VSNVS", + .min_uV = 1200000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vrefddr_init = { + .constraints = { + .name = "PFUZE100_VREFDDR", + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct regulator_init_data vgen1_init = { + .constraints = { + .name = "PFUZE100_VGEN1", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen1_consumers), + .consumer_supplies = vgen1_consumers, +}; + +static struct regulator_init_data vgen2_init = { + .constraints = { + .name = "PFUZE100_VGEN2", +#ifdef PFUZE100_FIRST_VERSION + .min_uV = 1200000, + .max_uV = 1550000, +#else + .min_uV = 800000, + .max_uV = 1550000, +#endif + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen2_consumers), + .consumer_supplies = vgen2_consumers, + +}; + +static struct regulator_init_data vgen3_init = { + .constraints = { + .name = "PFUZE100_VGEN3", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen3_consumers), + .consumer_supplies = vgen3_consumers, +}; + +static struct regulator_init_data vgen4_init = { + .constraints = { + .name = "PFUZE100_VGEN4", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen4_consumers), + .consumer_supplies = vgen4_consumers, +}; + +static struct regulator_init_data vgen5_init = { + .constraints = { + .name = "PFUZE100_VGEN5", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen5_consumers), + .consumer_supplies = vgen5_consumers, +}; + +static struct regulator_init_data vgen6_init = { + .constraints = { + .name = "PFUZE100_VGEN6", + .min_uV = 1800000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + .valid_modes_mask = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen6_consumers), + .consumer_supplies = vgen6_consumers, +}; + +static int pfuze100_init(struct mc_pfuze *pfuze) +{ + int ret; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1ASTANDBY, + PFUZE100_SW1ASTANDBY_STBY_M, + PFUZE100_SW1ASTANDBY_STBY_VAL); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CSTANDBY, + PFUZE100_SW1CSTANDBY_STBY_M, + PFUZE100_SW1CSTANDBY_STBY_VAL); + if (ret) + goto err; + /*set SW1AB/SW1CDVSPEED as 25mV step each 4us,quick than 16us before.*/ + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1ACON, + PFUZE100_SW1ACON_SPEED_M, + PFUZE100_SW1ACON_SPEED_VAL); + if (ret) + goto err; + ret = pfuze_reg_rmw(pfuze, PFUZE100_SW1CCON, + PFUZE100_SW1CCON_SPEED_M, + PFUZE100_SW1CCON_SPEED_VAL); + if (ret) + goto err; + return 0; +err: + printk(KERN_ERR "pfuze100 init error!\n"); + return -1; +} + +static struct pfuze_regulator_init_data mx6q_sabreauto_pfuze100_regulators[] = { + {.id = PFUZE100_SW1A, .init_data = &sw1a_init}, +// {.id = PFUZE100_SW1B, .init_data = &sw1b_init}, + {.id = PFUZE100_SW1C, .init_data = &sw1c_init}, +#if 0 + {.id = PFUZE100_SW2, .init_data = &sw2_init}, + {.id = PFUZE100_SW3A, .init_data = &sw3a_init}, + {.id = PFUZE100_SW3B, .init_data = &sw3b_init}, + {.id = PFUZE100_SW4, .init_data = &sw4_init}, + {.id = PFUZE100_SWBST, .init_data = &swbst_init}, + {.id = PFUZE100_VSNVS, .init_data = &vsnvs_init}, + {.id = PFUZE100_VREFDDR, .init_data = &vrefddr_init}, + {.id = PFUZE100_VGEN1, .init_data = &vgen1_init}, + {.id = PFUZE100_VGEN2, .init_data = &vgen2_init}, + {.id = PFUZE100_VGEN3, .init_data = &vgen3_init}, + {.id = PFUZE100_VGEN4, .init_data = &vgen4_init}, + {.id = PFUZE100_VGEN5, .init_data = &vgen5_init}, + {.id = PFUZE100_VGEN6, .init_data = &vgen6_init}, +#endif +}; + +static struct pfuze_platform_data pfuze100_plat = { + .flags = PFUZE_USE_REGULATOR, + .num_regulators = ARRAY_SIZE(mx6q_sabreauto_pfuze100_regulators), + .regulators = mx6q_sabreauto_pfuze100_regulators, + .pfuze_init = pfuze100_init, +}; + +static struct i2c_board_info __initdata pfuze100_i2c_device = { + I2C_BOARD_INFO(PFUZE100_I2C_DEVICE_NAME, PFUZE100_I2C_ADDR), + .irq=0, + .platform_data = &pfuze100_plat, +}; + +int __init mx6sl_ntx_init_pfuze100(u32 int_gpio) +{ + if (int_gpio) + pfuze100_i2c_device.irq = gpio_to_irq(int_gpio); /*update INT gpio */ + return i2c_register_board_info(0, &pfuze100_i2c_device, 1); +} diff --git a/arch/arm/mach-mx6/mx6sl_wfi.S b/arch/arm/mach-mx6/mx6sl_wfi.S new file mode 100644 index 00000000..c51fcc77 --- /dev/null +++ b/arch/arm/mach-mx6/mx6sl_wfi.S @@ -0,0 +1,727 @@ +/* + * Copyright (C) 2012-2013 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> +#include <mach/hardware.h> +/* + * The code size is limited to 1.5K + * as we may need to store this code + * along with the suspend and DDR freq change + * code within 8K of IRAM. + */ + +#define IRAM_WAIT_SIZE MX6SL_WFI_IRAM_CODE_SIZE + +.extern iram_tlb_phys_addr +.extern mx6sl_wfi_iram_base +.extern mx6sl_wfi_iram_phys_addr + + .macro sl_ddr_io_save + + ldr r4, [r1, #0x30c] /* DRAM_DQM0 */ + ldr r5, [r1, #0x310] /* DRAM_DQM1 */ + ldr r6, [r1, #0x314] /* DRAM_DQM2 */ + ldr r7, [r1, #0x318] /* DRAM_DQM3 */ + stmfd r9!, {r4-r7} + + ldr r4, [r1, #0x5c4] /* GPR_B0DS */ + ldr r5, [r1, #0x5cc] /* GPR_B1DS */ + ldr r6, [r1, #0x5d4] /* GPR_B2DS */ + ldr r7, [r1, #0x5d8] /* GPR_B3DS */ + stmfd r9!, {r4-r7} + + ldr r4, [r1, #0x300] /* DRAM_CAS */ + ldr r5, [r1, #0x31c] /* DRAM_RAS */ + ldr r6, [r1, #0x338] /* DRAM_SDCLK_0 */ + ldr r7, [r1, #0x5ac] /* GPR_ADDS*/ + stmfd r9!, {r4-r7} + + ldr r4, [r1, #0x5b0] /* DDRMODE_CTL */ + ldr r5, [r1, #0x5c0] /* DDRMODE */ + ldr r6, [r1, #0x33c] /* DRAM_SODT0*/ + ldr r7, [r1, #0x340] /* DRAM_SODT1*/ + stmfd r9!, {r4-r7} + + ldr r4, [r1, #0x330] /* DRAM_SDCKE0 */ + ldr r5, [r1, #0x334] /* DRAM_SDCKE1 */ + ldr r6, [r1, #0x320] /* DRAM_RESET */ + stmfd r9!, {r4-r6} + + .endm + + .macro sl_ddr_io_restore + + /* r9 points to IRAM stack. + * r1 points to IOMUX base address. + * r8 points to MMDC base address. + */ + ldmea r9!, {r4-r7} + str r4, [r1, #0x30c] /* DRAM_DQM0 */ + str r5, [r1, #0x310] /* DRAM_DQM1 */ + str r6, [r1, #0x314] /* DRAM_DQM2 */ + str r7, [r1, #0x318] /* DRAM_DQM3 */ + + ldmea r9!, {r4-r7} + str r4, [r1, #0x5c4] /* GPR_B0DS */ + str r5, [r1, #0x5cc] /* GPR_B1DS */ + str r6, [r1, #0x5d4] /* GPR_B2DS */ + str r7, [r1, #0x5d8] /* GPR_B3DS */ + + ldmea r9!, {r4-r7} + str r4, [r1, #0x300] /* DRAM_CAS */ + str r5, [r1, #0x31c] /* DRAM_RAS */ + str r6, [r1, #0x338] /* DRAM_SDCLK_0 */ + str r7, [r1, #0x5ac] /* GPR_ADDS*/ + + ldmea r9!, {r4-r7} + str r4, [r1, #0x5b0] /* DDRMODE_CTL */ + str r5, [r1, #0x5c0] /* DDRMODE */ + str r6, [r1, #0x33c] /* DRAM_SODT0*/ + str r7, [r1, #0x340] /* DRAM_SODT1*/ + + ldmea r9!, {r4-r6} + str r4, [r1, #0x330] /* DRAM_SDCKE0 */ + str r5, [r1, #0x334] /* DRAM_SDCKE1 */ + str r6, [r1, #0x320] /* DRAM_RESET */ + + /* Need to reset the FIFO to avoid MMDC lockup + * caused because of floating/changing the + * configuration of many DDR IO pads. + */ + /* reset read FIFO, RST_RD_FIFO */ + ldr r7, =0x83c + ldr r6, [r8, r7] + orr r6, r6, #0x80000000 + str r6, [r8, r7] +fifo_reset1_wait: + ldr r6, [r8, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne fifo_reset1_wait + + /* reset FIFO a second time */ + ldr r6, [r8, r7] + orr r6, r6, #0x80000000 + str r6, [r8, r7] +fifo_reset2_wait: + ldr r6, [r8, r7] + and r6, r6, #0x80000000 + cmp r6, #0 + bne fifo_reset2_wait + + .endm + + .macro sl_ddr_io_set_lpm + + mov r4, #0 + str r4, [r1, #0x30c] /* DRAM_DQM0 */ + str r4, [r1, #0x310] /* DRAM_DQM1 */ + str r4, [r1, #0x314] /* DRAM_DQM2 */ + str r4, [r1, #0x318] /* DRAM_DQM3 */ + + str r4, [r1, #0x5c4] /* GPR_B0DS */ + str r4, [r1, #0x5cc] /* GPR_B1DS */ + str r4, [r1, #0x5d4] /* GPR_B2DS */ + str r4, [r1, #0x5d8] /* GPR_B3DS */ + + str r4, [r1, #0x300] /* DRAM_CAS */ + str r4, [r1, #0x31c] /* DRAM_RAS */ + str r4, [r1, #0x338] /* DRAM_SDCLK_0 */ + str r4, [r1, #0x5ac] /* GPR_ADDS*/ + + str r4, [r1, #0x5b0] /* DDRMODE_CTL */ + str r4, [r1, #0x5c0] /* DDRMODE */ + str r4, [r1, #0x33c] /* DRAM_SODT0*/ + str r4, [r1, #0x340] /* DRAM_SODT1*/ + + mov r4, #0x80000 + str r4, [r1, #0x320] /* DRAM_RESET */ + mov r4, #0x1000 + str r4, [r1, #0x330] /* DRAM_SDCKE0 */ + str r4, [r1, #0x334] /* DRAM_SDCKE1 */ + + .endm + + .align 3 +/* + * mx6sl_wait + * + * Idle the processor (eg, wait for interrupt). + * Make sure DDR is in self-refresh. + * IRQs are already disabled. + * r0 : arm_podf before WFI is entered + * r1: WFI IRAMcode base address. + */ +ENTRY(mx6sl_wait) + + push {r4-r12} + +mx6sl_lpm_wfi: + mov r11, r2 + + /* Get the IRAM data storage address. */ + mov r10, r1 + mov r9, r1 /* get suspend_iram_base */ + add r9, r9, #IRAM_WAIT_SIZE /* 1.5K */ + + /* + * To ensure no page table walks occur in DDR, we + * have a another page table stored in IRAM that only + * contains entries pointing to IRAM, AIPS1 and AIPS2. + * We need to set the TTBR1 to the new IRAM TLB. + * Do the following steps: + * 1. Flush the Branch Target Address Cache (BTAC) + * 2. Set TTBR1 to point to IRAM page table. + * 3. Disable page table walks in TTBR0 (PD0 = 1) + * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0 + * and 2-4G is translated by TTBR1. + */ + + ldr r6, =iram_tlb_phys_addr + ldr r7, [r6] + + /* Flush the BTAC. */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + /* Disable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + dsb + isb + + /* Store the IRAM table in TTBR1 */ + mcr p15, 0, r7, c2, c0, 1 + + /* Read TTBCR and set PD0=1, N = 1 */ + mrc p15, 0, r6, c2, c0, 2 + orr r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + + /* Disable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + bic r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + dsb + + /* + * Sync L2 and then disable it. + */ + dsb + ldr r1, =L2_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r6, =0x0 + str r6, [r1, #0x730] + /* Disable L2. */ + str r6, [r1, #0x100] + dsb + isb + + ldr r1, =MX6Q_IOMUXC_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + + /* Save the DDR IO state. */ + sl_ddr_io_save + + ldr r3, =ANATOP_BASE_ADDR + add r3, r3, #PERIPBASE_VIRT + ldr r2, =CCM_BASE_ADDR + add r2, r2, #PERIPBASE_VIRT + ldr r8, =MMDC_P0_BASE_ADDR + add r8, r8, #PERIPBASE_VIRT + + /* Disable Automatic power savings. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x01 + str r6, [r8, #0x404] + + /* Make the DDR explicitly enter self-refresh. */ + ldr r6, [r8, #0x404] + orr r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_set_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + bne poll_dvfs_set_1 + + /* set SBS step-by-step mode */ + ldr r6, [r8, #0x410] + orr r6, r6, #0x100 + str r6, [r8, #0x410] + + cmp r11, #1 + beq audio_mode + + /* Now set DDR rate to 1MHz. */ + /* DDR is from bypassed PLL2 on periph2_clk2 path. + * Set the periph2_clk2_podf to divide by 8. + */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x07 + str r6, [r2, #0x14] + + /* Now set MMDC PODF to divide by 3. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x10 + str r6, [r2, #0x14] + b mmdc_podf + +audio_mode: + /* MMDC is from PLL2_200M. + * Set the mmdc_podf to div by 8. + */ + ldr r6, [r2, #0x14] + orr r6, r6, #0x38 + str r6, [r2, #0x14] + + /* Loop till podf is accepted. */ +mmdc_podf: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne mmdc_podf + + /* Set the DDR IO in LPM state. */ + sl_ddr_io_set_lpm + + cmp r11, #1 + beq do_audio_arm_clk + + /* Check if none of the PLLs are + * locked, except PLL1 which will get + * bypassed below. + * We should not be here if PLL2 is not + * bypassed. + */ + ldr r7, =1 + /* USB1 PLL3 */ + ldr r6, [r3, #0x10] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* USB2 PLL7 */ + ldr r6, [r3, #0x20] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* Audio PLL4 */ + ldr r6, [r3, #0x70] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* Video PLL5 */ + ldr r6, [r3, #0xA0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + /* ENET PLL8 */ + ldr r6, [r3, #0xE0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + beq no_analog_saving + + b cont + +no_analog_saving: + ldr r7, =0 + +cont: + /*Set the AHB to 3MHz. AXI to 3MHz. */ + ldr r9, [r2, #0x14] + mov r6, r9 + orr r6, r6, #0x1c00 + orr r6, r6, #0x70000 + str r6, [r2, #0x14] + + /* Loop till podf is accepted. */ +ahb_podf: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne podf_loop + + /* Now set ARM to 24MHz. */ + /* Move ARM to be sourced from STEP_CLK + * after setting STEP_CLK to 24MHz. + */ + ldr r6, [r2, #0xc] + bic r6, r6, #0x100 + str r6, [r2, #0x0c] + /* Now PLL1_SW_CLK to step_clk. */ + ldr r6, [r2, #0x0c] + orr r6, r6, #0x4 + str r6, [r2, #0x0c] + + /* Bypass PLL1 and power it down. */ + ldr r6, =(1 << 16) + orr r6, r6, #0x1000 + str r6, [r3, #0x04] + + /* Set the ARM PODF to divide by 8. */ + /* IPG is at 1.5MHz here, we need ARM to + * run at the 12:5 ratio (WAIT mode issue). + */ + ldr r6, =0x7 + str r6, [r2, #0x10] + + /* Loop till podf is accepted. */ +podf_loop: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne podf_loop + + /* Check if we can save some + * in the Analog section. + */ + cmp r7, #0x1 + bne do_wfi + + /* Disable 1p1 brown out. */ + ldr r6, [r3, #0x110] + bic r6, r6, #0x2 + str r6, [r3, #0x110] + + /* Enable the weak 2P5 */ + ldr r6, [r3, #0x130] + orr r6, r6, #0x40000 + str r6, [r3, #0x130] + + /*Disable main 2p5. */ + ldr r6, [r3, #0x130] + bic r6, r6, #0x1 + str r6, [r3, #0x130] + + /* Set the OSC bias current to -37.5% + * to drop the power on VDDHIGH. + */ + ldr r6, [r3, #0x150] + orr r6, r6, #0xC000 + str r6, [r3, #0x150] + + /* Enable low power bandgap */ + ldr r6, [r3, #0x260] + orr r6, r6, #0x20 + str r6, [r3, #0x260] + + /* turn off the bias current + * from the regular bandgap. + */ + ldr r6, [r3, #0x260] + orr r6, r6, #0x80 + str r6, [r3, #0x260] + + /* Clear the REFTOP_SELFBIASOFF, + * self-bias circuit of the band gap. + * Per RM, should be cleared when + * band gap is powered down. + */ + ldr r6, [r3, #0x150] + bic r6, r6, #0x8 + str r6, [r3, #0x150] + + /*Power down the regular bandgap. */ + ldr r6, [r3, #0x150] + orr r6, r6, #0x1 + str r6, [r3, #0x150] + + b do_wfi + +do_audio_arm_clk: + /* + * ARM is from PLL2_PFD2_400M here. + * Switch ARM to bypassed PLL1. + */ + ldr r6, [r2, #0xC] + bic r6, r6, #0x4 + str r6, [r2, #0xC] + + /* + * Set the ARM_PODF to divide by 2 + * as IPG is at 4MHz, we cannot run + * ARM_CLK above 9.6MHz when + * system enters WAIT mode. + */ + ldr r6, =0x2 + str r6, [r2, #0x10] + + /* Loop till podf is accepted. */ +podf_loop_audio: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne podf_loop_audio + +do_wfi: + /* Now do WFI. */ + wfi + + /* Set original ARM PODF back. */ + str r0, [r2, #0x10] + + /* Loop till podf is accepted. */ +podf_loop1: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne podf_loop1 + + cmp r11, #1 + beq audio_arm_clk_restore + + /* + * Check if powered down + * analog components. + */ + cmp r7, #0x1 + bne skip_analog_restore + + /* Power up the regular bandgap. */ + ldr r6, [r3, #0x150] + bic r6, r6, #0x1 + str r6, [r3, #0x150] + + /* turn on the bias current + * from the regular bandgap. + */ + ldr r6, [r3, #0x260] + bic r6, r6, #0x80 + str r6, [r3, #0x260] + + /* Disable the low power bandgap */ + ldr r6, [r3, #0x260] + bic r6, r6, #0x20 + str r6, [r3, #0x260] + + /* + * Set the OSC bias current to max + * value for normal operation. + */ + ldr r6, [r3, #0x150] + bic r6, r6, #0xC000 + str r6, [r3, #0x150] + + /*Enable main 2p5. */ + ldr r6, [r3, #0x130] + orr r6, r6, #0x1 + str r6, [r3, #0x130] + + /* Ensure the 2P5 is up. */ +loop_2p5: + ldr r6, [r3, #0x130] + and r6, r6, #0x20000 + cmp r6, #0x20000 + bne loop_2p5 + + /* Disable the weak 2P5 */ + ldr r6, [r3, #0x130] + bic r6, r6, #0x40000 + str r6, [r3, #0x130] + + /* Enable 1p1 brown out. */ + ldr r6, [r3, #0x110] + orr r6, r6, #0x2 + str r6, [r3, #0x110] + +skip_analog_restore: + + /* Power up PLL1 and un-bypass it. */ + ldr r6, =(1 << 12) + str r6, [r3, #0x08] + + /* Wait for PLL1 to relock. */ +wait_for_pll_lock: + ldr r6, [r3, #0x0] + and r6, r6, #0x80000000 + cmp r6, #0x80000000 + bne wait_for_pll_lock + + ldr r6, =(1 << 16) + str r6, [r3, #0x08] + + /* Set PLL1_sw_clk back to PLL1. */ + ldr r6, [r2, #0x0c] + bic r6, r6, #0x4 + str r6, [r2, #0xc] + + /* Restore AHB/AXI back. */ + str r9, [r2, #0x14] + + /* Loop till podf is accepted. */ +ahb_podf1: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne podf_loop1 + + b wfi_restore + +audio_arm_clk_restore: + /* Move ARM back to PLL2_PFD2_400M */ + ldr r6, [r2, #0xC] + orr r6, r6, #0x4 + str r6, [r2, #0xC] + +wfi_restore: + mov r9, r10 /* get suspend_iram_base */ + add r9, r9, #IRAM_WAIT_SIZE /* 4K */ + + /* Restore the DDR IO before exiting self-refresh. */ + sl_ddr_io_restore + + cmp r11, #1 + beq mmdc_audio_restore + + /* Set MMDC back to 24MHz. */ + /* Set periph2_clk2_podf to divide by 1. */ + /* Now set MMDC PODF to divide by 1. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x3f + str r6, [r2, #0x14] + + b mmdc_podf1 + +mmdc_audio_restore: + /* Set MMDC back to 100MHz. */ + ldr r6, [r2, #0x14] + bic r6, r6, #0x38 + orr r6, r6, #0x8 + str r6, [r2, $0x14] + +mmdc_podf1: + ldr r6, [r2, #0x48] + cmp r6, #0x0 + bne mmdc_podf1 + + /* clear DVFS - exit from self refresh mode */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x200000 + str r6, [r8, #0x404] + +poll_dvfs_clear_1: + ldr r6, [r8, #0x404] + and r6, r6, #0x2000000 + cmp r6, #0x2000000 + beq poll_dvfs_clear_1 + + /* Enable Automatic power savings. */ + ldr r6, [r8, #0x404] + bic r6, r6, #0x01 + str r6, [r8, #0x404] + + /* clear SBS - unblock DDR accesses */ + ldr r6, [r8, #0x410] + bic r6, r6, #0x100 + str r6, [r8, #0x410] + + /* Enable L2. */ + ldr r1, =L2_BASE_ADDR + add r1, r1, #PERIPBASE_VIRT + ldr r6, =0x1 + str r6, [r1, #0x100] + + /* Enable L1 data cache. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x4 + mcr p15, 0, r6, c1, c0, 0 + + /* Restore the TTBCR */ + + dsb + isb + /* Read TTBCR and set PD0=0, N = 0 */ + mrc p15, 0, r6, c2, c0, 2 + bic r6, r6, #0x11 + mcr p15, 0, r6, c2, c0, 2 + + dsb + isb + + /* flush the TLB */ + ldr r6, =0x0 + mcr p15, 0, r6, c8, c3, 0 + dsb + isb + + /* Enable Branch Prediction, Z bit in SCTLR. */ + mrc p15, 0, r6, c1, c0, 0 + orr r6, r6, #0x800 + mcr p15, 0, r6, c1, c0, 0 + + /* Flush the Branch Target Address Cache (BTAC) */ + ldr r6, =0x0 + mcr p15, 0, r6, c7, c1, 6 + + + /* Add these nops so that the + * prefetcher will not try to get + * any instructions from DDR. + * The prefetch depth is about 23 + * on A9, so adding 25 nops. + */ + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + nop + nop + nop + nop + nop + + pop {r4-r12} + + /* Restore registers */ + mov pc, lr + + .type mx6sl_do_wait, #object +ENTRY(mx6sl_do_wait) + .word mx6sl_wait + .size mx6sl_wait, . - mx6sl_wait + diff --git a/arch/arm/mach-mx6/ntx_hwconfig.h b/arch/arm/mach-mx6/ntx_hwconfig.h new file mode 100755 index 00000000..cba4f94e --- /dev/null +++ b/arch/arm/mach-mx6/ntx_hwconfig.h @@ -0,0 +1,267 @@ +#ifndef __ntx_hwconfig_h//[ +#define __ntx_hwconfig_h + + +#ifdef __cplusplus //[ +extern "C" { +#endif //] __cplusplus + + +#define SYSHWCONFIG_SEEKSIZE (1024*512) + + +typedef struct tagNTXHWCFG_HDR { + char cMagicNameA[10];// should be "HW CONFIG " + char cVersionNameA[5];// should be "vx.x" + unsigned char bHWConfigSize;// v0.1=19 . +} NTXHWCFG_HDR ; + +typedef struct tagNTXHWCFG_VAL { + unsigned char bPCB;// + unsigned char bKeyPad;// key pad type . + unsigned char bAudioCodec;// + unsigned char bAudioAmp;// + unsigned char bWifi;// + unsigned char bBT;// + unsigned char bMobile;// + unsigned char bTouchCtrl;//touch controller . + unsigned char bTouchType;//touch type . + unsigned char bDisplayCtrl;// + unsigned char bDisplayPanel;// + unsigned char bRSensor;// + unsigned char bMicroP;// + unsigned char bCustomer;// + unsigned char bBattery;// + unsigned char bLed;// + unsigned char bRamSize;// ram size + unsigned char bIFlash; // internal flash type . + unsigned char bExternalMem;// external sd type . + unsigned char bRootFsType;// root fs type . + unsigned char bSysPartType;// system partition type . + unsigned char bProgressXHiByte; // Progress bar position while boot ,X + unsigned char bProgressXLoByte; // ,X + unsigned char bProgressYHiByte; // ,Y + unsigned char bProgressYLoByte; // ,Y + unsigned char bProgressCnts; // Cnt . + unsigned char bContentType; // Book content type . + unsigned char bCPU; //main cpu type . + unsigned char bUIStyle; // UI style . + unsigned char bRamType; // Ram Type . + unsigned char bUIConfig; // UI config . + unsigned char bDisplayResolution;// Display resolution . + unsigned char bFrontLight;// Front Light . + unsigned char bCPUFreq;// CPU frequency . + unsigned char bHallSensor;// Hall Sensor Controller . + unsigned char bDisplayBusWidth;// Display BUS width/bits . + unsigned char bFrontLight_Flags;// Front Light Flags . + unsigned char bPCB_Flags;// PCB Flags . + unsigned char bFrontLight_LED_Driver;// Front Light LED driver . + unsigned char bVCOM_10mV_HiByte;// VCOM mV High byte . + unsigned char bVCOM_10mV_LoByte;// VCOM mV Low byte . + unsigned char bPCB_REV;// PCB revision . + unsigned char bPCB_LVL;// PCB develop level . + unsigned char bHOME_LED_PWM;// HOME LED PWM source . + unsigned char bPMIC;// System PMIC . + unsigned char bFL_PWM;// FrontLight PWM source + unsigned char bRTC;// System RTC source + unsigned char bBootOpt;// Boot option + unsigned char bTouch2Ctrl;//touch controller . + unsigned char bTouch2Type;//touch type . + unsigned char bGPS;//GPS module . + unsigned char bFM;//FM module . +} NTXHWCFG_VAL ; + +typedef struct tagNTX_HWCONFG{ + NTXHWCFG_HDR m_hdr; + NTXHWCFG_VAL m_val; + unsigned char m_bReserveA[110-sizeof(NTXHWCFG_HDR)-sizeof(NTXHWCFG_VAL)]; +} NTX_HWCONFIG; + +// Filed types ... +#define FIELD_TYPE_IDXSTR 0 +#define FIELD_TYPE_BYTE 1 +#define FIELD_TYPE_FLAGS 2 + +// Filed Flags ... +#define FIELD_FLAGS_HW 0x0000 +#define FIELD_FLAGS_SW 0x0001 + + +typedef struct tagHwConfigField{ + char *szVersion; + char *szFieldName ; + int iFieldValueCnt; + char **szFieldValueA ; + unsigned short wFieldType; + unsigned short wFieldFlags; +} HwConfigField ; + + +extern const char * gszPCBA[]; +extern const char * gszKeyPadA[]; +extern const char * gszAudioCodecA[];// +extern const char * gszAudioAmpA[];// +extern const char * gszWifiA[];// +extern const char * gszBTA[];// +extern const char * gszMobileA[];// +extern const char * gszTouchCtrlA[];//touch controller . +extern const char * gszTouchTypeA[];// +extern const char * gszDisplayCtrlA[]; +extern const char * gszDisplayPanelA[]; +extern const char * gszRSensorA[];// +extern const char * gszMicroPA[];// +extern const char * gszCustomerA[];// +extern const char * gszBatteryA[];// +extern const char * gszLedA[];// +extern const char * gszRamSizeA[];// ram size +extern const char * gszIFlashA[]; // internal flash type . +extern const char * gszExternalMemA[];// external sd type . +extern const char * gszRootFsTypeA[];// root fs type . +extern const char * gszSysPartTypeA[];// system partition type . +extern const char * gszCPUA[];// cpu type . +extern const char * gszUIStyleA[];// UI Style (netronix UI/customer UI) . +extern const char * gszRAMTypeA[];// Ram Type . +extern const char * gszUIConfigA[];// UI Config . +extern const char * gszDisplayResolutionA[];// Display Resolution . +extern const char * gszFrontLightA[];// Front Light . +extern const char * gszCPUFreqA[];// CPU frequency . +extern const char * gszHallSensorA[];// Hall Sensor . +extern const char * gszDisplayBusWidthA[];// Display BUS width . +extern const char * gszFrontLightLEDrvA[];//Front Light LED driver IC . +extern const char * gszPCB_LVLA[];//PCB develop level . +extern const char * gszHOME_LED_PWMA[];// HOME LED PWM source . +extern const char * gszPMICA[];// System PMIC . +extern const char * gszFL_PWMA[];// FrontLight PWM source +extern const char * gszRTCA[];// System RTC source . +extern const char * gszFMA[];// System RTC source . +extern const char * gszGPSA[];// System RTC source . + + +// the return value of hw config apis . >=0 is success ,others is fail . +#define HWCFG_RET_SUCCESS (0) +#define HWCFG_RET_PTRERR (-1) // parameter include error pointer +#define HWCFG_RET_HDRNOTMATCH (-2) // hwconfig header magic not match . +#define HWCFG_RET_CFGVERTOOOLD (-3) // hwconfig tool version newer than config struct value (you should update the config file)... +#define HWCFG_RET_CFGVERTOONEW (-4) // hwconfig tool version older than config struct value (you should update the config tool)... +#define HWCFG_RET_CFGVERNOTMATCH (-5) // hwconfig tool version and config struct version not match ... +#define HWCFG_RET_CFGVERFMTERR (-6) // config version format error (must be vX.X) ... +#define HWCFG_RET_NOTHISFIELDIDX (-7) // field index error . +#define HWCFG_RET_NOTHISFIELDNAME (-8) // field name error . +#define HWCFG_RET_FILEOPENFAIL (-9) // file open fail . +#define HWCFG_RET_FILEWRITEFAIL (-10) // file open fail . +#define HWCFG_RET_FIELDTYPEERROR (-11) // field type error . +#define HWCFG_RET_FIELDTRDONLY (-12) // field read only . +#define HWCFG_RET_CFGVALFLAGIDXERROR (-13) // index of config's flags not avalible . +#define HWCFG_RET_CFGVALFLAGNAMEERROR (-14) // flag name of config not avalible . +#define HWCFG_RET_FIELDIDXOUTRANGE (-15) // field index out of range . + + +// ntx hardward config field index list ... +#define HWCFG_FLDIDX_PCB 0 +#define HWCFG_FLDIDX_KeyPad 1 +#define HWCFG_FLDIDX_AudioCodec 2 +#define HWCFG_FLDIDX_AudioAmp 3 +#define HWCFG_FLDIDX_Wifi 4 +#define HWCFG_FLDIDX_BT 5 +#define HWCFG_FLDIDX_Mobile 6 +#define HWCFG_FLDIDX_TouchCtrl 7 +#define HWCFG_FLDIDX_TouchType 8 +#define HWCFG_FLDIDX_DisplayCtrl 9 +#define HWCFG_FLDIDX_DisplayPanel 10 +#define HWCFG_FLDIDX_RSensor 11 +#define HWCFG_FLDIDX_MicroP 12 +#define HWCFG_FLDIDX_Customer 13 +#define HWCFG_FLDIDX_Battery 14 +#define HWCFG_FLDIDX_Led 15 +#define HWCFG_FLDIDX_RamSize 16 +#define HWCFG_FLDIDX_IFlash 17 +#define HWCFG_FLDIDX_ExternalMem 18 +#define HWCFG_FLDIDX_RootFsType 19 // v0.2 +#define HWCFG_FLDIDX_SysPartType 20 // v0.3 + +#define HWCFG_FLDIDX_ProgressXHiByte 21 // v0.4 +#define HWCFG_FLDIDX_ProgressXLoByte 22 // v0.4 +#define HWCFG_FLDIDX_ProgressYHiByte 23 // v0.4 +#define HWCFG_FLDIDX_ProgressYLoByte 24 // v0.4 +#define HWCFG_FLDIDX_ProgressCnts 25 // v0.4 + +#define HWCFG_FLDIDX_ContentType 26 // v0.5 +#define HWCFG_FLDIDX_CPU 27 // v0.6 +#define HWCFG_FLDIDX_UISTYLE 28 // v0.7 + +#define HWCFG_FLDIDX_RAMTYPE 29 // v0.8 +#define HWCFG_FLDIDX_UICONFIG 30 // v0.9 +#define HWCFG_FLDIDX_DISPLAYRESOLUTION 31 // v1.0 +#define HWCFG_FLDIDX_FRONTLIGHT 32 // v1.1 +#define HWCFG_FLDIDX_CPUFREQ 33 // v1.2 +#define HWCFG_FLDIDX_HALLSENSOR 34 // v1.3 +#define HWCFG_FLDIDX_DisplayBusWidth 35 // v1.4 +#define HWCFG_FLDIDX_FrontLight_Flags 36 // v1.5 +#define HWCFG_FLDIDX_PCB_Flags 37 // v1.6 +#define HWCFG_FLDIDX_FrontLight_LEDrv 38 // v1.7 +#define HWCFG_FLDIDX_VCOM_10mV_HiByte 39 // v1.8 +#define HWCFG_FLDIDX_VCOM_10mV_LoByte 40 // v1.8 +#define HWCFG_FLDIDX_PCB_REV 41 // v1.9 +#define HWCFG_FLDIDX_PCB_LVL 42 // v2.0 +#define HWCFG_FLDIDX_HOME_PWM 43 // v2.1 +#define HWCFG_FLDIDX_PMIC 44 // v2.1 +#define HWCFG_FLDIDX_FL_PWM 45// v2.1 +#define HWCFG_FLDIDX_RTC 46// v2.1 +#define HWCFG_FLDIDX_BOOTOPT 47// v2.2 +#define HWCFG_FLDIDX_Touch2Ctrl 48 // v2.3 +#define HWCFG_FLDIDX_Touch2Type 49 // v2.3 +#define HWCFG_FLDIDX_GPS 50 // v2.4 +#define HWCFG_FLDIDX_FM 51 // v2.4 + + + + +NTX_HWCONFIG *NtxHwCfg_Load(const char *szFileName,int iIsSeek); +NTX_HWCONFIG *NtxHwCfg_LoadEx(const char *szFileName,unsigned long dwIsSeek); +int NtxHwCfg_Save(const char *szFileName,int iIsSeek); +NTX_HWCONFIG *NtxHwCfg_Get(void); + + +int NtxHwCfg_GetTotalFlds(void);//¨ú±o¦@¦³´XÓÄæ¦ì. +int NtxHwCfg_GetFldVal(int iFldIdx,HwConfigField *O_ptHwCfgFld);//¨ú±o¤v©w¸qªºÄæ¦ìÈ. +unsigned char NtxHwCfg_FldStrVal2Val(int iFldIdx,char *szFldStrVal);//Äæ¦ìªº¦r¦êÈÂà´«¬°Äæ¦ì. +const char *NtxHwCfg_FldVal2StrVal(int iFldIdx,unsigned char bFldVal);//Äæ¦ìªºÈÂà´«¬°¦r¦êÈ. +int NtxHwCfg_FldName2Idx(const char *szFldName); +int NtxHwCfg_is_HW_Fld(int iFldIdx); +int NtxHwCfg_is_SW_Fld(int iFldIdx); + +int NtxHwCfg_ChkCfgHeaderEx2(NTX_HWCONFIG *pHdr,int iIsIgnoreVersion,const char *pcCompareHdrVersionA); +int NtxHwCfg_ChkCfgHeaderEx(NTX_HWCONFIG *pHdr,int iIsIgnoreVersion); +int NtxHwCfg_ChkCfgHeader(NTX_HWCONFIG *pHdr);//Àˬd²ÕºAªíÀY,ª©¥». +int NtxHwCfg_CfgUpgrade(NTX_HWCONFIG *pHdr);//®æ¦¡¤É¯Å¦Ü¤u¨ã¤@Pªºª©¥». + +int NtxHwCfg_GetCfgTotalFlds(NTX_HWCONFIG *pHdr);//¨ú±o²ÕºAÁ`¦@¦³´XÓÄæ¦ì. + +int NtxHwCfg_GetCfgFldVal(NTX_HWCONFIG *pHdr,int iFieldIdx); +const char *NtxHwCfg_GetCfgFldStrVal(NTX_HWCONFIG *pHdr,int iFieldIdx); +int NtxHwCfg_GetCfgFldFlagVal(NTX_HWCONFIG *pHdr,int iFieldIdx,int iFlagsIdx); +int NtxHwCfg_GetCfgFldFlagValByName(NTX_HWCONFIG *pHdr,int iFieldIdx,const char *pszFlagName); + +int NtxHwCfg_SetCfgFldVal(NTX_HWCONFIG *pHdr,int iFieldIdx,int iFieldVal); +int NtxHwCfg_SetCfgFldStrVal(NTX_HWCONFIG *pHdr,int iFieldIdx,const char *pszFieldStrVal); +int NtxHwCfg_SetCfgFldStrValEx(NTX_HWCONFIG *pHdr,int iFieldIdx,const char *pszFieldStrVal,int iHW_WR_Protect); +int NtxHwCfg_SetCfgFldFlagValByName(NTX_HWCONFIG *pHdr,int iFieldIdx,const char *pszFlagName,int iIsTurnON,int iHW_WR_Protect); + +int NtxHwCfg_SetCfgFldValDefs(NTX_HWCONFIG *I_pHdr,int I_iFieldIdx, + const char **I_pszFieldValDefs,int I_iTotalVals); + +int NtxHwCfg_CompareHdrFldVersion(NTX_HWCONFIG *pHdr,int iFieldIdx); + +// get field value name in hardware config struct ... +#define NTXHWCFG_GET_FLDCFGNAME(pHdr,_fld) gsz##_fld##A[pHdr->m_val.b##_fld] +// get print format by field in hardware config struct ... +#define NTXHWCFG_GET_FLDCFGPRTFMT(pHdr,_fld) "%s : %s",#_fld,NTXHWCFG_GET_FLDCFGNAME(pHdr,_fld) + +#define NTXHWCFG_TST_FLAG(_flags,_bit_n) ((_flags)&(0x01<<(_bit_n)))?1:0 + +#ifdef __cplusplus //[ +} +#endif //] __cplusplus + +#endif //] __ntx_hwconfig_h + diff --git a/arch/arm/mach-mx6/pcie.c b/arch/arm/mach-mx6/pcie.c new file mode 100644 index 00000000..fa37e07c --- /dev/null +++ b/arch/arm/mach-mx6/pcie.c @@ -0,0 +1,1161 @@ +/* + * arch/arm/mach-mx6/pcie.c + * + * PCIe host controller driver for IMX6 SOCs + * + * Copyright (C) 2012-2013 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Bits taken from arch/arm/mach-dove/pcie.c + * + * 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/pci.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/time.h> + +#include <mach/pcie.h> + +#include <asm/sizes.h> +#include <asm/signal.h> + +#include "crm_regs.h" +#ifdef CONFIG_PCI_MSI +#include "msi.h" +#endif + +/* Register Definitions */ +#define PRT_LOG_R_BaseAddress 0x700 + +/* Register DB_R0 */ +/* Debug Register 0 */ +#define DB_R0 (PRT_LOG_R_BaseAddress + 0x28) +#define DB_R0_RegisterSize 32 +#define DB_R0_RegisterResetValue 0x0 +#define DB_R0_RegisterResetMask 0xFFFFFFFF +/* End of Register Definition for DB_R0 */ + +/* Register DB_R1 */ +/* Debug Register 1 */ +#define DB_R1 (PRT_LOG_R_BaseAddress + 0x2c) +#define DB_R1_RegisterSize 32 +#define DB_R1_RegisterResetValue 0x0 +#define DB_R1_RegisterResetMask 0xFFFFFFFF +/* End of Register Definition for DB_R1 */ + +#define ATU_R_BaseAddress 0x900 +#define ATU_VIEWPORT_R (ATU_R_BaseAddress + 0x0) +#define ATU_REGION_CTRL1_R (ATU_R_BaseAddress + 0x4) +#define ATU_REGION_CTRL2_R (ATU_R_BaseAddress + 0x8) +#define ATU_REGION_LOWBASE_R (ATU_R_BaseAddress + 0xC) +#define ATU_REGION_UPBASE_R (ATU_R_BaseAddress + 0x10) +#define ATU_REGION_LIMIT_ADDR_R (ATU_R_BaseAddress + 0x14) +#define ATU_REGION_LOW_TRGT_ADDR_R (ATU_R_BaseAddress + 0x18) +#define ATU_REGION_UP_TRGT_ADDR_R (ATU_R_BaseAddress + 0x1C) + +/* Registers of PHY */ +/* Register PHY_STS_R */ +/* PHY Status Register */ +#define PHY_STS_R (PRT_LOG_R_BaseAddress + 0x110) + +/* Register PHY_CTRL_R */ +/* PHY Control Register */ +#define PHY_CTRL_R (PRT_LOG_R_BaseAddress + 0x114) + +#define SSP_CR_SUP_DIG_MPLL_OVRD_IN_LO 0x0011 +/* FIELD: RES_ACK_IN_OVRD [15:15] +// FIELD: RES_ACK_IN [14:14] +// FIELD: RES_REQ_IN_OVRD [13:13] +// FIELD: RES_REQ_IN [12:12] +// FIELD: RTUNE_REQ_OVRD [11:11] +// FIELD: RTUNE_REQ [10:10] +// FIELD: MPLL_MULTIPLIER_OVRD [9:9] +// FIELD: MPLL_MULTIPLIER [8:2] +// FIELD: MPLL_EN_OVRD [1:1] +// FIELD: MPLL_EN [0:0] +*/ + +#define SSP_CR_SUP_DIG_ATEOVRD 0x0010 +/* FIELD: ateovrd_en [2:2] +// FIELD: ref_usb2_en [1:1] +// FIELD: ref_clkdiv2 [0:0] +*/ + +#define SSP_CR_LANE0_DIG_RX_OVRD_IN_LO 0x1005 +/* FIELD: RX_LOS_EN_OVRD [13:13] +// FIELD: RX_LOS_EN [12:12] +// FIELD: RX_TERM_EN_OVRD [11:11] +// FIELD: RX_TERM_EN [10:10] +// FIELD: RX_BIT_SHIFT_OVRD [9:9] +// FIELD: RX_BIT_SHIFT [8:8] +// FIELD: RX_ALIGN_EN_OVRD [7:7] +// FIELD: RX_ALIGN_EN [6:6] +// FIELD: RX_DATA_EN_OVRD [5:5] +// FIELD: RX_DATA_EN [4:4] +// FIELD: RX_PLL_EN_OVRD [3:3] +// FIELD: RX_PLL_EN [2:2] +// FIELD: RX_INVERT_OVRD [1:1] +// FIELD: RX_INVERT [0:0] +*/ + +#define SSP_CR_LANE0_DIG_RX_ASIC_OUT 0x100D +/* FIELD: LOS [2:2] +// FIELD: PLL_STATE [1:1] +// FIELD: VALID [0:0] +*/ + +/* control bus bit definition */ +#define PCIE_CR_CTL_DATA_LOC 0 +#define PCIE_CR_CTL_CAP_ADR_LOC 16 +#define PCIE_CR_CTL_CAP_DAT_LOC 17 +#define PCIE_CR_CTL_WR_LOC 18 +#define PCIE_CR_CTL_RD_LOC 19 +#define PCIE_CR_STAT_DATA_LOC 0 +#define PCIE_CR_STAT_ACK_LOC 16 + +#define PCIE_CAP_STRUC_BaseAddress 0x70 + +/* Register LNK_CAP */ +/* PCIE Link cap */ +#define LNK_CAP (PCIE_CAP_STRUC_BaseAddress + 0xc) +#define LNK_CAP_RegisterSize 32 +#define LNK_CAP_RegisterResetValue 0x011cc12 +#define LNK_CAP_RegisterResetMask 0xffffffff + +#ifdef CONFIG_PCI_MSI +#define PCIE_RC_MSI_CAP 0x50 + +#define PCIE_PL_MSICA 0x820 +#define PCIE_PL_MSICUA 0x824 +#define PCIE_PL_MSIC_INT 0x828 + +#define MSIC_INT_EN 0x0 +#define MSIC_INT_MASK 0x4 +#define MSIC_INT_STATUS 0x8 +#endif + +/* End of Register Definitions */ + +#define PCIE_DBI_BASE_ADDR (PCIE_ARB_END_ADDR - SZ_16K + 1) + +#define PCIE_CONF_BUS(b) (((b) & 0xFF) << 16) +#define PCIE_CONF_DEV(d) (((d) & 0x1F) << 11) +#define PCIE_CONF_FUNC(f) (((f) & 0x7) << 8) +#define PCIE_CONF_REG(r) ((r) & ~0x3) + +/* + * The default values of the RC's reserved ddr memory + * used to verify EP mode. + * BTW, here is the layout of the 1G ddr on SD boards + * 0x1000_0000 ~ 0x4FFF_FFFF + */ +static u32 rc_ddr_test_region = 0x40000000; +static u32 rc_ddr_test_region_size = (SZ_16M - SZ_16K); + +#ifdef EP_SELF_IO_TEST +static void *rc_ddr_test_reg1, *rc_ddr_test_reg2; +static void __iomem *pcie_arb_base_addr; +static struct timeval tv1, tv2, tv3; +static u32 tv_count1, tv_count2; +#endif +static void __iomem *base; +static void __iomem *dbi_base; + +enum { + MemRdWr = 0, + MemRdLk = 1, + IORdWr = 2, + CfgRdWr0 = 4, + CfgRdWr1 = 5 +}; + +struct imx_pcie_port { + u8 index; + u8 root_bus_nr; + void __iomem *base; + void __iomem *dbi_base; + spinlock_t conf_lock; + + char io_space_name[16]; + char mem_space_name[16]; + + struct resource res[2]; +}; + +static struct imx_pcie_port imx_pcie_port[1]; +static int num_pcie_ports; + +static int pcie_phy_cr_read(int addr, int *data); +static int pcie_phy_cr_write(int addr, int data); +static void change_field(int *in, int start, int end, int val); + +/* IMX PCIE GPR configure routines */ +static inline void imx_pcie_clrset(u32 mask, u32 val, void __iomem *addr) +{ + writel(((readl(addr) & ~mask) | (val & mask)), addr); +} + +static struct imx_pcie_port *bus_to_port(int bus) +{ + int i; + + for (i = num_pcie_ports - 1; i >= 0; i--) { + int rbus = imx_pcie_port[i].root_bus_nr; + if (rbus != -1 && rbus == bus) + break; + } + + return i >= 0 ? imx_pcie_port + i : NULL; +} + +static int __init imx_pcie_setup(int nr, struct pci_sys_data *sys) +{ + struct imx_pcie_port *pp; + + if (nr >= num_pcie_ports) + return 0; + + pp = &imx_pcie_port[nr]; + pp->root_bus_nr = sys->busnr; + + /* + * IORESOURCE_IO + */ + snprintf(pp->io_space_name, sizeof(pp->io_space_name), + "PCIe %d I/O", pp->index); + pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0; + pp->res[0].name = pp->io_space_name; + if (pp->index == 0) { + pp->res[0].start = PCIE_ARB_BASE_ADDR + SZ_16M - SZ_2M; + pp->res[0].end = pp->res[0].start + SZ_1M - 1; + } + pp->res[0].flags = IORESOURCE_IO; + if (request_resource(&ioport_resource, &pp->res[0])) + panic("Request PCIe IO resource failed\n"); + sys->resource[0] = &pp->res[0]; + + /* + * IORESOURCE_MEM + */ + snprintf(pp->mem_space_name, sizeof(pp->mem_space_name), + "PCIe %d MEM", pp->index); + pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0; + pp->res[1].name = pp->mem_space_name; + if (pp->index == 0) { + pp->res[1].start = PCIE_ARB_BASE_ADDR; + pp->res[1].end = pp->res[1].start + SZ_16M - SZ_2M - 1; + } + pp->res[1].flags = IORESOURCE_MEM; + if (request_resource(&iomem_resource, &pp->res[1])) + panic("Request PCIe Memory resource failed\n"); + sys->resource[1] = &pp->res[1]; + + sys->resource[2] = NULL; + + return 1; +} + +static int imx_pcie_link_up(void __iomem *dbi_base) +{ + /* Check the pcie link up or link down */ + int iterations = 200; + u32 rc, ltssm, rx_valid, temp; + + do { + /* link is debug bit 36 debug 1 start in bit 32 */ + rc = readl(dbi_base + DB_R1) & (0x1 << (36 - 32)) ; + iterations--; + usleep_range(2000, 3000); + + /* From L0, initiate MAC entry to gen2 if EP/RC supports gen2. + * Wait 2ms (LTSSM timeout is 24ms, PHY lock is ~5us in gen2). + * If (MAC/LTSSM.state == Recovery.RcvrLock) + * && (PHY/rx_valid==0) then pulse PHY/rx_reset. Transition + * to gen2 is stuck + */ + pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_ASIC_OUT, &rx_valid); + ltssm = readl(dbi_base + DB_R0) & 0x3F; + if ((ltssm == 0x0D) && ((rx_valid & 0x01) == 0)) { + pr_info("Transition to gen2 is stuck, reset PHY!\n"); + pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, &temp); + change_field(&temp, 3, 3, 0x1); + change_field(&temp, 5, 5, 0x1); + pcie_phy_cr_write(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, + 0x0028); + usleep_range(2000, 3000); + pcie_phy_cr_read(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, &temp); + change_field(&temp, 3, 3, 0x0); + change_field(&temp, 5, 5, 0x0); + pcie_phy_cr_write(SSP_CR_LANE0_DIG_RX_OVRD_IN_LO, + 0x0000); + } + + if (iterations == 0) + pr_info("link up failed, DB_R0:0x%08x, DB_R1:0x%08x!\n" + , readl(dbi_base + DB_R0) + , readl(dbi_base + DB_R1)); + } while (!rc && iterations); + + if (!rc) + return 0; + return 1; +} + +static void imx_pcie_regions_setup(struct device *dev, void __iomem *dbi_base) +{ + struct imx_pcie_platform_data *pdata = dev->platform_data; +#ifdef CONFIG_PCI_MSI + unsigned int i; + void __iomem *p = dbi_base + PCIE_PL_MSIC_INT; +#endif + + /* + * i.MX6 defines 16MB in the AXI address map for PCIe. + * + * That address space excepted the pcie registers is + * split and defined into different regions by iATU, + * with sizes and offsets as follows: + * + * RC: + * 0x0100_0000 --- 0x01DF_FFFF 14MB IORESOURCE_MEM + * 0x01E0_0000 --- 0x01EF_FFFF 1MB IORESOURCE_IO + * 0x01F0_0000 --- 0x01FF_FFFF 1MB Cfg + MSI + Registers + * + * EP (default value): + * 0x0100_0000 --- 0x01FF_C000 16MB - 16KB IORESOURCE_MEM + */ + + /* CMD reg:I/O space, MEM space, and Bus Master Enable */ + writel(readl(dbi_base + PCI_COMMAND) + | PCI_COMMAND_IO + | PCI_COMMAND_MEMORY + | PCI_COMMAND_MASTER, + dbi_base + PCI_COMMAND); + + if (pdata->type_ep) { + /* + * configure the class_rev(emaluate one memory ram ep device), + * bar0 and bar1 of ep + */ + writel(0xdeadbeaf, dbi_base + PCI_VENDOR_ID); + writel(readl(dbi_base + PCI_CLASS_REVISION) + | (PCI_CLASS_MEMORY_RAM << 16), + dbi_base + PCI_CLASS_REVISION); + writel(0xdeadbeaf, dbi_base + PCI_SUBSYSTEM_VENDOR_ID); + + /* 32bit none-prefetchable 8M bytes memory on bar0 */ + writel(0x0, dbi_base + PCI_BASE_ADDRESS_0); + writel(SZ_8M - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_0); + + /* None used bar1 */ + writel(0x0, dbi_base + PCI_BASE_ADDRESS_1); + writel(0, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_1); + + /* 4K bytes IO on bar2 */ + writel(0x1, dbi_base + PCI_BASE_ADDRESS_2); + writel(SZ_4K - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_2); + + /* + * 32bit prefetchable 1M bytes memory on bar3 + * FIXME BAR MASK3 is not changable, the size + * is fixed to 256 bytes. + */ + writel(0x8, dbi_base + PCI_BASE_ADDRESS_3); + writel(SZ_1M - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_3); + + /* + * 64bit prefetchable 1M bytes memory on bar4-5. + * FIXME BAR4,5 are not enabled yet + */ + writel(0xc, dbi_base + PCI_BASE_ADDRESS_4); + writel(SZ_1M - 1, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_4); + writel(0, dbi_base + (1 << 12) + PCI_BASE_ADDRESS_5); + + /* + * region0 outbound used to access RC's reserved ddr memory + */ + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(PCIE_ARB_BASE_ADDR, dbi_base + ATU_REGION_LOWBASE_R); + writel(0, dbi_base + ATU_REGION_UPBASE_R); + writel(PCIE_ARB_BASE_ADDR + rc_ddr_test_region_size, + dbi_base + ATU_REGION_LIMIT_ADDR_R); + + writel(rc_ddr_test_region, + dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); + writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R); + writel(MemRdWr, dbi_base + ATU_REGION_CTRL1_R); + writel((1<<31), dbi_base + ATU_REGION_CTRL2_R); + } else { + /* Set the CLASS_REV of RC CFG header to PCI_CLASS_BRIDGE_PCI */ + writel(readl(dbi_base + PCI_CLASS_REVISION) + | (PCI_CLASS_BRIDGE_PCI << 16), + dbi_base + PCI_CLASS_REVISION); + + /* + * region0 outbound used to access target cfg + */ + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(PCIE_ARB_END_ADDR - SZ_1M + 1, + dbi_base + ATU_REGION_LOWBASE_R); + writel(PCIE_ARB_END_ADDR - SZ_64K, + dbi_base + ATU_REGION_LIMIT_ADDR_R); + writel(0, dbi_base + ATU_REGION_UPBASE_R); + + writel(0, dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); + writel(0, dbi_base + ATU_REGION_UP_TRGT_ADDR_R); + writel(CfgRdWr0, dbi_base + ATU_REGION_CTRL1_R); + writel((1<<31), dbi_base + ATU_REGION_CTRL2_R); + } + +#ifdef CONFIG_PCI_MSI + writel(MSI_MATCH_ADDR, dbi_base + PCIE_PL_MSICA); + writel(0, dbi_base + PCIE_PL_MSICUA); + for (i = 0; i < 8 ; i++) { + writel(0, p + MSIC_INT_EN); + writel(0xFFFFFFFF, p + MSIC_INT_MASK); + writel(0xFFFFFFFF, p + MSIC_INT_STATUS); + p += 12; + } +#endif +} + +#ifdef CONFIG_PCI_MSI +void imx_pcie_mask_irq(unsigned int pos, int set) +{ + unsigned int mask = 1 << (pos & 0x1F); + unsigned int val, newval; + void __iomem *p; + + p = dbi_base + PCIE_PL_MSIC_INT + MSIC_INT_MASK + ((pos >> 5) * 12); + + if (pos >= (8 * 32)) + return; + val = readl(p); + if (set) + newval = val | mask; + else + newval = val & ~mask; + if (val != newval) + writel(newval, p); +} + +void imx_pcie_enable_irq(unsigned int pos, int set) +{ + unsigned int mask = 1 << (pos & 0x1F); + unsigned int val, newval; + void __iomem *p; + + p = dbi_base + PCIE_PL_MSIC_INT + MSIC_INT_EN + ((pos >> 5) * 12); + + /* RC: MSI CAP enable */ + if (set) { + val = readl(dbi_base + PCIE_RC_MSI_CAP); + val |= (PCI_MSI_FLAGS_ENABLE << 16); + writel(val, dbi_base + PCIE_RC_MSI_CAP); + } + + if (pos >= (8 * 32)) + return; + val = readl(p); + if (set) + newval = val | mask; + else + newval = val & ~mask; + if (val != newval) + writel(newval, p); + if (set && (val != newval)) + imx_pcie_mask_irq(pos, 0); /* unmask when enabled */ + } + +unsigned int imx_pcie_msi_pending(unsigned int index) +{ + unsigned int val, mask; + void __iomem *p = dbi_base + PCIE_PL_MSIC_INT + (index * 12); + + if (index >= 8) + return 0; + val = readl(p + MSIC_INT_STATUS); + mask = readl(p + MSIC_INT_MASK); + val &= ~mask; + writel(val, p + MSIC_INT_STATUS); + return val; +} +#endif + +static int imx_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, + int size, u32 *val) +{ + struct imx_pcie_port *pp = bus_to_port(bus->number); + u32 va_address; + + /* Added to change transaction TYPE */ + if (bus->number < 2) { + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(CfgRdWr0, dbi_base + ATU_REGION_CTRL1_R); + } else { + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(CfgRdWr1, dbi_base + ATU_REGION_CTRL1_R); + } + + if (pp) { + if (devfn != 0) { + *val = 0xFFFFFFFF; + return PCIBIOS_DEVICE_NOT_FOUND; + } + + va_address = (u32)dbi_base + (where & ~0x3); + } else { + writel(0, dbi_base + ATU_VIEWPORT_R); + + writel((((PCIE_CONF_BUS(bus->number) + + PCIE_CONF_DEV(PCI_SLOT(devfn)) + + PCIE_CONF_FUNC(PCI_FUNC(devfn)))) << 8), + dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); + va_address = (u32)base + PCIE_CONF_REG(where); + } + + *val = readl(va_address); + + if (size == 1) + *val = (*val >> (8 * (where & 3))) & 0xFF; + else if (size == 2) + *val = (*val >> (8 * (where & 3))) & 0xFFFF; + + return PCIBIOS_SUCCESSFUL; +} + +static int imx_pcie_wr_conf(struct pci_bus *bus, u32 devfn, + int where, int size, u32 val) +{ + struct imx_pcie_port *pp = bus_to_port(bus->number); + u32 va_address = 0, mask = 0, tmp = 0; + int ret = PCIBIOS_SUCCESSFUL; + + /* Added to change transaction TYPE */ + if (bus->number < 2) { + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(CfgRdWr0, dbi_base + ATU_REGION_CTRL1_R); + } else { + writel(0, dbi_base + ATU_VIEWPORT_R); + writel(CfgRdWr1, dbi_base + ATU_REGION_CTRL1_R); + } + + if (pp) { + if (devfn != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + va_address = (u32)dbi_base + (where & ~0x3); + } else { + writel(0, dbi_base + ATU_VIEWPORT_R); + + writel((((PCIE_CONF_BUS(bus->number) + + PCIE_CONF_DEV(PCI_SLOT(devfn)) + + PCIE_CONF_FUNC(PCI_FUNC(devfn)))) << 8), + dbi_base + ATU_REGION_LOW_TRGT_ADDR_R); + va_address = (u32)base + PCIE_CONF_REG(where); + } + + if (size == 4) { + writel(val, va_address); + goto exit; + } + + if (size == 2) + mask = ~(0xFFFF << ((where & 0x3) * 8)); + else if (size == 1) + mask = ~(0xFF << ((where & 0x3) * 8)); + else + ret = PCIBIOS_BAD_REGISTER_NUMBER; + + tmp = readl(va_address) & mask; + tmp |= val << ((where & 0x3) * 8); + writel(tmp, va_address); +exit: + return ret; +} + +static struct pci_ops imx_pcie_ops = { + .read = imx_pcie_rd_conf, + .write = imx_pcie_wr_conf, +}; + +static struct pci_bus __init * +imx_pcie_scan_bus(int nr, struct pci_sys_data *sys) +{ + struct pci_bus *bus; + + if (nr < num_pcie_ports) { + bus = pci_scan_bus(sys->busnr, &imx_pcie_ops, sys); + } else { + bus = NULL; + BUG(); + } + + return bus; +} + +static int __init imx_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin) +{ + switch (pin) { + case 1: return MXC_INT_PCIE_3; + case 2: return MXC_INT_PCIE_2; + case 3: return MXC_INT_PCIE_1; + case 4: return MXC_INT_PCIE_0; + default: return -1; + } +} + +static struct hw_pci imx_pci __initdata = { + .nr_controllers = 1, + .swizzle = pci_std_swizzle, + .setup = imx_pcie_setup, + .scan = imx_pcie_scan_bus, + .map_irq = imx_pcie_map_irq, +}; + +/* PHY CR bus acess routines */ +static int pcie_phy_cr_ack_polling(int max_iterations, int exp_val) +{ + u32 temp_rd_data, wait_counter = 0; + + do { + temp_rd_data = readl(dbi_base + PHY_STS_R); + temp_rd_data = (temp_rd_data >> PCIE_CR_STAT_ACK_LOC) & 0x1; + wait_counter++; + } while ((wait_counter < max_iterations) && (temp_rd_data != exp_val)); + + if (temp_rd_data != exp_val) + return 0 ; + return 1 ; +} + +static int pcie_phy_cr_cap_addr(int addr) +{ + u32 temp_wr_data; + + /* write addr */ + temp_wr_data = addr << PCIE_CR_CTL_DATA_LOC ; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* capture addr */ + temp_wr_data |= (0x1 << PCIE_CR_CTL_CAP_ADR_LOC); + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack */ + if (!pcie_phy_cr_ack_polling(100, 1)) + return 0; + + /* deassert cap addr */ + temp_wr_data = addr << PCIE_CR_CTL_DATA_LOC; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack de-assetion */ + if (!pcie_phy_cr_ack_polling(100, 0)) + return 0 ; + + return 1 ; +} + +static int pcie_phy_cr_read(int addr , int *data) +{ + u32 temp_rd_data, temp_wr_data; + + /* write addr */ + /* cap addr */ + if (!pcie_phy_cr_cap_addr(addr)) + return 0; + + /* assert rd signal */ + temp_wr_data = 0x1 << PCIE_CR_CTL_RD_LOC; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack */ + if (!pcie_phy_cr_ack_polling(100, 1)) + return 0; + + /* after got ack return data */ + temp_rd_data = readl(dbi_base + PHY_STS_R); + *data = (temp_rd_data & (0xFFFF << PCIE_CR_STAT_DATA_LOC)) ; + + /* deassert rd signal */ + temp_wr_data = 0x0; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack de-assetion */ + if (!pcie_phy_cr_ack_polling(100, 0)) + return 0 ; + + return 1 ; + +} + +static int pcie_phy_cr_write(int addr, int data) +{ + u32 temp_wr_data; + + /* write addr */ + /* cap addr */ + if (!pcie_phy_cr_cap_addr(addr)) + return 0 ; + + temp_wr_data = data << PCIE_CR_CTL_DATA_LOC; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* capture data */ + temp_wr_data |= (0x1 << PCIE_CR_CTL_CAP_DAT_LOC); + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack */ + if (!pcie_phy_cr_ack_polling(100, 1)) + return 0 ; + + /* deassert cap data */ + temp_wr_data = data << PCIE_CR_CTL_DATA_LOC; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack de-assetion */ + if (!pcie_phy_cr_ack_polling(100, 0)) + return 0; + + /* assert wr signal */ + temp_wr_data = 0x1 << PCIE_CR_CTL_WR_LOC; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack */ + if (!pcie_phy_cr_ack_polling(100, 1)) + return 0; + + /* deassert wr signal */ + temp_wr_data = data << PCIE_CR_CTL_DATA_LOC; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + /* wait for ack de-assetion */ + if (!pcie_phy_cr_ack_polling(100, 0)) + return 0; + + temp_wr_data = 0x0 ; + writel(temp_wr_data, dbi_base + PHY_CTRL_R); + + return 1 ; +} + +static void change_field(int *in, int start, int end, int val) +{ + int mask; + + mask = ((0xFFFFFFFF << start) ^ (0xFFFFFFFF << (end + 1))) & 0xFFFFFFFF; + *in = (*in & ~mask) | (val << start); +} + +static void imx_pcie_enable_controller(struct device *dev) +{ + struct clk *pcie_clk; + struct imx_pcie_platform_data *pdata = dev->platform_data; + + /* Enable PCIE power */ + gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN"); + + /* activate PCIE_PWR_EN */ + gpio_direction_output(pdata->pcie_pwr_en, 1); + + imx_pcie_clrset(IOMUXC_GPR1_TEST_POWERDOWN, 0 << 18, IOMUXC_GPR1); + + + /* enable the clks */ + if (pdata->type_ep) { + pcie_clk = clk_get(NULL, "pcie_ep_clk"); + if (IS_ERR(pcie_clk)) + pr_err("no pcie_ep clock.\n"); + + if (clk_enable(pcie_clk)) { + pr_err("can't enable pcie_ep clock.\n"); + clk_put(pcie_clk); + } + } else { + pcie_clk = clk_get(NULL, "pcie_clk"); + if (IS_ERR(pcie_clk)) + pr_err("no pcie clock.\n"); + + if (clk_enable(pcie_clk)) { + pr_err("can't enable pcie clock.\n"); + clk_put(pcie_clk); + } + } + imx_pcie_clrset(IOMUXC_GPR1_PCIE_REF_CLK_EN, 1 << 16, IOMUXC_GPR1); +} + +static void card_reset(struct device *dev) +{ + struct imx_pcie_platform_data *pdata = dev->platform_data; + + /* PCIE RESET */ + gpio_request(pdata->pcie_rst, "PCIE RESET"); + + /* activate PERST_B */ + gpio_direction_output(pdata->pcie_rst, 0); + + /* Add one reset to the pcie external device */ + msleep(100); + + /* deactive PERST_B */ + gpio_direction_output(pdata->pcie_rst, 1); +} + +static void __init add_pcie_port(void __iomem *base, void __iomem *dbi_base, + struct imx_pcie_platform_data *pdata) +{ + struct clk *pcie_clk; + + if (imx_pcie_link_up(dbi_base)) { + struct imx_pcie_port *pp = &imx_pcie_port[num_pcie_ports++]; + + pr_info("IMX PCIe port: link up.\n"); + + pp->index = 0; + pp->root_bus_nr = -1; + pp->base = base; + pp->dbi_base = dbi_base; + spin_lock_init(&pp->conf_lock); + memset(pp->res, 0, sizeof(pp->res)); + } else { + pr_info("IMX PCIe port: link down!\n"); + + /* Release the clocks, and disable the power */ + pcie_clk = clk_get(NULL, "pcie_clk"); + if (IS_ERR(pcie_clk)) + pr_err("no pcie clock.\n"); + + clk_disable(pcie_clk); + clk_put(pcie_clk); + + imx_pcie_clrset(IOMUXC_GPR1_PCIE_REF_CLK_EN, 0 << 16, + IOMUXC_GPR1); + + /* Disable PCIE power */ + gpio_request(pdata->pcie_pwr_en, "PCIE POWER_EN"); + + /* activate PCIE_PWR_EN */ + gpio_direction_output(pdata->pcie_pwr_en, 0); + + imx_pcie_clrset(IOMUXC_GPR1_TEST_POWERDOWN, 1 << 18, + IOMUXC_GPR1); + } +} + +/* Added for PCI abort handling */ +static int imx6q_pcie_abort_handler(unsigned long addr, + unsigned int fsr, struct pt_regs *regs) +{ + /* + * If it was an imprecise abort, then we need to correct the + * return address to be _after_ the instruction. + */ + if (fsr & (1 << 10)) + regs->ARM_pc += 4; + return 0; +} + +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS +static ssize_t imx_pcie_rc_memw_info(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "imx-pcie-rc-memw-info start 0x%08x, size 0x%08x\n", + rc_ddr_test_region, rc_ddr_test_region_size); +} + +static ssize_t +imx_pcie_rc_memw_start(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 memw_start; + + sscanf(buf, "%x\n", &memw_start); + + if (memw_start < 0x10000000) { + dev_err(dev, "Invalid memory start address.\n"); + dev_info(dev, "For example: echo 0x41000000 > /sys/..."); + return -1; + } + + if (rc_ddr_test_region != memw_start) { + rc_ddr_test_region = memw_start; + /* Re-setup the iATU */ + imx_pcie_regions_setup(dev, dbi_base); + } + + return count; +} + +static ssize_t +imx_pcie_rc_memw_size(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + u32 memw_size; + + sscanf(buf, "%x\n", &memw_size); + + if ((memw_size > (SZ_16M - SZ_16K)) || (memw_size < SZ_64K)) { + dev_err(dev, "Invalid, should be [SZ_64K,SZ_16M - SZ_16KB].\n"); + dev_info(dev, "For example: echo 0x800000 > /sys/..."); + return -1; + } + + if (rc_ddr_test_region_size != memw_size) { + rc_ddr_test_region_size = memw_size; + /* Re-setup the iATU */ + imx_pcie_regions_setup(dev, dbi_base); + } + + return count; +} + +static DEVICE_ATTR(rc_memw_info, S_IRUGO, imx_pcie_rc_memw_info, NULL); +static DEVICE_ATTR(rc_memw_start_set, S_IWUGO, NULL, imx_pcie_rc_memw_start); +static DEVICE_ATTR(rc_memw_size_set, S_IWUGO, NULL, imx_pcie_rc_memw_size); + +static struct attribute *imx_pcie_attrs[] = { + /* + * The start address, and the limitation (64KB ~ (16MB - 16KB)) + * of the ddr mem window reserved by RC, and used for EP to access. + * BTW, these attrs are only configured at EP side. + */ + &dev_attr_rc_memw_info.attr, + &dev_attr_rc_memw_start_set.attr, + &dev_attr_rc_memw_size_set.attr, + NULL +}; + +static struct attribute_group imx_pcie_attrgroup = { + .attrs = imx_pcie_attrs, +}; +#endif + +static int __devinit imx_pcie_pltfm_probe(struct platform_device *pdev) +{ +#ifdef EP_SELF_IO_TEST + int i; +#endif + int ret = 0; + struct resource *mem; + struct device *dev = &pdev->dev; + struct imx_pcie_platform_data *pdata = dev->platform_data; + + pr_info("iMX6 PCIe %s mode %s entering.\n", + pdata->type_ep ? "PCIe EP" : "PCIe RC", __func__); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(dev, "no mmio space\n"); + return -EINVAL; + } + +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS + /* add attributes for device */ + ret = sysfs_create_group(&pdev->dev.kobj, &imx_pcie_attrgroup); + if (ret) + return -EINVAL; +#endif + + /* Added for PCI abort handling */ + hook_fault_code(16 + 6, imx6q_pcie_abort_handler, SIGBUS, 0, + "imprecise external abort"); + + base = ioremap_nocache(PCIE_ARB_END_ADDR - SZ_1M + 1, SZ_1M - SZ_16K); + if (!base) { + pr_err("error with ioremap in function %s\n", __func__); + ret = PTR_ERR(base); +#ifdef CONFIG_IMX_PCIE_EP_MODE_IN_EP_RC_SYS + sysfs_remove_group(&pdev->dev.kobj, &imx_pcie_attrgroup); +#endif + return ret; + } + + dbi_base = devm_ioremap(dev, mem->start, resource_size(mem)); + if (!dbi_base) { + dev_err(dev, "can't map %pR\n", mem); + ret = PTR_ERR(dbi_base); + goto err_base; + } + + /* FIXME the field name should be aligned to RM */ + imx_pcie_clrset(IOMUXC_GPR12_APP_LTSSM_ENABLE, 0 << 10, IOMUXC_GPR12); + + /* configure constant input signal to the pcie ctrl and phy */ + if (pdata->type_ep & 1) + /* EP */ + imx_pcie_clrset(IOMUXC_GPR12_DEVICE_TYPE, + PCI_EXP_TYPE_ENDPOINT << 12, IOMUXC_GPR12); + else + /* RC */ + imx_pcie_clrset(IOMUXC_GPR12_DEVICE_TYPE, + PCI_EXP_TYPE_ROOT_PORT << 12, IOMUXC_GPR12); + imx_pcie_clrset(IOMUXC_GPR12_LOS_LEVEL, 9 << 4, IOMUXC_GPR12); + + imx_pcie_clrset(IOMUXC_GPR8_TX_DEEMPH_GEN1, 0 << 0, IOMUXC_GPR8); + imx_pcie_clrset(IOMUXC_GPR8_TX_DEEMPH_GEN2_3P5DB, 0 << 6, IOMUXC_GPR8); + imx_pcie_clrset(IOMUXC_GPR8_TX_DEEMPH_GEN2_6DB, 20 << 12, IOMUXC_GPR8); + imx_pcie_clrset(IOMUXC_GPR8_TX_SWING_FULL, 127 << 18, IOMUXC_GPR8); + imx_pcie_clrset(IOMUXC_GPR8_TX_SWING_LOW, 127 << 25, IOMUXC_GPR8); + + /* Enable the pwr, clks and so on */ + imx_pcie_enable_controller(dev); + if (!(pdata->type_ep)) { + /*Only RC: togle the external card's reset */ + card_reset(dev) ; + + imx_pcie_regions_setup(dev, dbi_base); + } + + pr_info("PCIE: %s start link up.\n", __func__); + /* start link up */ + imx_pcie_clrset(IOMUXC_GPR12_APP_LTSSM_ENABLE, 1 << 10, IOMUXC_GPR12); + + if (pdata->type_ep) { +#ifdef EP_SELF_IO_TEST + /* Prepare the test regions and data */ + rc_ddr_test_reg1 = kzalloc(rc_ddr_test_region_size, GFP_KERNEL); + if (!rc_ddr_test_reg1) + pr_err("PCIe EP: can't alloc the test region1.\n"); + + rc_ddr_test_reg2 = kzalloc(rc_ddr_test_region_size, GFP_KERNEL); + if (!rc_ddr_test_reg2) { + kfree(rc_ddr_test_reg1); + pr_err("PCIe EP: can't alloc the test region2.\n"); + } + + pcie_arb_base_addr = ioremap_cached(PCIE_ARB_BASE_ADDR, + rc_ddr_test_region_size); + + if (!pcie_arb_base_addr) { + pr_err("error with ioremap in function %s\n", __func__); + ret = PTR_ERR(pcie_arb_base_addr); + kfree(rc_ddr_test_reg2); + kfree(rc_ddr_test_reg1); + goto err_base; + } + + for (i = 0; i < rc_ddr_test_region_size; i = i + 4) { + writel(0xE6600D00 + i, rc_ddr_test_reg1 + i); + writel(0xDEADBEAF, rc_ddr_test_reg2 + i); + } +#endif + + pr_info("PCIe EP: waiting for link up...\n"); + /* link is debug bit 36 debug 1 start in bit 32 */ + do { + usleep_range(10, 20); + } while ((readl(dbi_base + DB_R1) & 0x10) == 0); + /* Make sure that the PCIe link is up */ + if (imx_pcie_link_up(dbi_base)) { + pr_info("PCIe EP: link up.\n"); + } else { + pr_info("PCIe EP: ERROR link is down, exit!\n"); +#ifdef EP_SELF_IO_TEST + kfree(rc_ddr_test_reg2); + kfree(rc_ddr_test_reg1); + iounmap(pcie_arb_base_addr); +#endif + goto err_link_down; + } + + imx_pcie_regions_setup(dev, dbi_base); +#ifdef EP_SELF_IO_TEST + /* PCIe EP start the data transfer after link up */ + pr_info("PCIe EP: Starting data transfer...\n"); + do_gettimeofday(&tv1); + + memcpy((unsigned long *)pcie_arb_base_addr, + (unsigned long *)rc_ddr_test_reg1, 0xFFC000); + + do_gettimeofday(&tv2); + + memcpy((unsigned long *)rc_ddr_test_reg2, + (unsigned long *)pcie_arb_base_addr, 0xFFC000); + + do_gettimeofday(&tv3); + + if (memcmp(rc_ddr_test_reg2, rc_ddr_test_reg1, 0xFFC000) != 0) { + pr_info("PCIe EP: Data transfer is failed.\n"); + } else { + tv_count1 = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + + tv2.tv_usec - tv1.tv_usec; + tv_count2 = (tv3.tv_sec - tv2.tv_sec) * USEC_PER_SEC + + tv3.tv_usec - tv2.tv_usec; + + pr_info("PCIe EP: Data transfer is successful." + "tv_count1 %dus, tv_count2 %dus.\n", + tv_count1, tv_count2); + pr_info("PCIe EP: Data write speed is %ldMB/s.\n", + ((((0xFFC000/1024) * MSEC_PER_SEC))) + /(tv_count1)); + pr_info("PCIe EP: Data read speed is %ldMB/s.\n", + ((((0xFFC000/1024) * MSEC_PER_SEC))) + /(tv_count2)); + } +#endif + + } else { + /* add the pcie port */ + add_pcie_port(base, dbi_base, pdata); + + pci_common_init(&imx_pci); + } + return 0; + +err_link_down: + iounmap(dbi_base); + +err_base: + iounmap(base); + + return ret; +} + +static struct platform_driver imx_pcie_pltfm_driver = { + .driver = { + .name = "imx-pcie", + .owner = THIS_MODULE, + }, + .probe = imx_pcie_pltfm_probe, +}; + +/*****************************************************************************\ + * * + * Driver init/exit * + * * +\*****************************************************************************/ + +static int __init imx_pcie_drv_init(void) +{ + return platform_driver_register(&imx_pcie_pltfm_driver); +} + +static void __exit imx_pcie_drv_exit(void) +{ + platform_driver_unregister(&imx_pcie_pltfm_driver); +} + +module_init(imx_pcie_drv_init); +module_exit(imx_pcie_drv_exit); + +MODULE_DESCRIPTION("i.MX PCIE platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/arch/arm/mach-mx6/plat_hotplug.c b/arch/arm/mach-mx6/plat_hotplug.c new file mode 100644 index 00000000..20a33329 --- /dev/null +++ b/arch/arm/mach-mx6/plat_hotplug.c @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2011-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/kernel.h> +#include <linux/errno.h> +#include <linux/smp.h> +#include <linux/delay.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <linux/io.h> +#include "src-reg.h" +#include <linux/sched.h> +#include <asm/cacheflush.h> + +extern unsigned int num_cpu_idle_lock; +void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR); + +int platform_cpu_kill(unsigned int cpu) +{ + unsigned int val; + + val = jiffies; + /* wait secondary cpu to die, timeout is 50ms */ + while (__raw_readl(src_base + SRC_GPR1_OFFSET + (8 * cpu) + 4) == 0) { + if (time_after(jiffies, (unsigned long)(val + HZ / 20))) { + printk(KERN_WARNING "cpu %d: cpu could not die\n", cpu); + break; + } + } + + /* + * we're ready for shutdown now, so do it + */ + val = __raw_readl(src_base + SRC_SCR_OFFSET); + val &= ~(1 << (BP_SRC_SCR_CORES_DBG_RST + cpu)); + val |= (1 << (BP_SRC_SCR_CORE0_RST + cpu)); + __raw_writel(val, src_base + SRC_SCR_OFFSET); + + val = jiffies; + /* wait secondary cpu reset done, timeout is 10ms */ + while ((__raw_readl(src_base + SRC_SCR_OFFSET) & + (1 << (BP_SRC_SCR_CORE0_RST + cpu))) != 0) { + if (time_after(jiffies, (unsigned long)(val + HZ / 100))) { + printk(KERN_WARNING "cpu %d: cpu reset fail\n", cpu); + break; + } + } + + __raw_writel(0x0, src_base + SRC_GPR1_OFFSET + (8 * cpu) + 4); + return 1; +} + +/* + * platform-specific code to shutdown a CPU + * Called with IRQs disabled + */ +void platform_cpu_die(unsigned int cpu) +{ + unsigned int v; + if (cpu == 0) { + printk(KERN_ERR "CPU0 can't be disabled!\n"); + return; + } + flush_cache_all(); + asm volatile( + " mcr p15, 0, %1, c7, c5, 0\n" /* Invalidate I cache */ + " mcr p15, 0, %1, c7, c10, 4\n" /* DSB */ + /* + * Turn off coherency + */ + " mrc p15, 0, %0, c1, c0, 1\n" /* Disable SMP in ACTLR */ + " bic %0, %0, %3\n" + " mcr p15, 0, %0, c1, c0, 1\n" + " mrc p15, 0, %0, c1, c0, 0\n" /* Disable D cache in SCTLR */ + " bic %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 0\n" + : "=&r" (v) + : "r" (0), "Ir" (CR_C), "Ir" (0x40) + : "cc"); + /* Tell cpu0 to kill this core, as this core's cache is + already disabled, and we want to set a flag to tell cpu0 + to kill this core, so I write the flag to this core's SRC + parameter register, after cpu0 kill this core, it will + clear this register. */ + + __raw_writel(0x1, src_base + SRC_GPR1_OFFSET + (8 * cpu) + 4); + + for (;;) { + /* + * Execute WFI + */ + asm(".word 0xe320f003\n" + : + : + : "memory", "cc"); + printk(KERN_ERR "cpu %d wake up from wfi !!!\n", cpu); + } + asm volatile( + " mrc p15, 0, %0, c1, c0, 0\n" /* Enable D cache in SCTLR */ + " orr %0, %0, %1\n" + " mcr p15, 0, %0, c1, c0, 0\n" + " mrc p15, 0, %0, c1, c0, 1\n" /* Enable SMP in ACTLR */ + " orr %0, %0, %2\n" + " mcr p15, 0, %0, c1, c0, 1\n" + : "=&r" (v) + : "Ir" (CR_C), "Ir" (0x40) + : "cc"); + __raw_writel(0x0, src_base + SRC_GPR1_OFFSET + (8 * cpu) + 4); +} + +int platform_cpu_disable(unsigned int cpu) +{ + /* + * we don't allow CPU 0 to be shutdown (it is still too special + * e.g. clock tick interrupts) + */ + *((char *)(&num_cpu_idle_lock) + (u8)cpu) = 0xff; + return cpu == 0 ? -EPERM : 0; +} diff --git a/arch/arm/mach-mx6/platsmp.c b/arch/arm/mach-mx6/platsmp.c new file mode 100644 index 00000000..a21f0231 --- /dev/null +++ b/arch/arm/mach-mx6/platsmp.c @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2011-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/errno.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/jiffies.h> +#include <linux/smp.h> +#include <linux/io.h> +#include <asm/cacheflush.h> +#include <asm/mach-types.h> +#include <asm/localtimer.h> +#include <asm/smp_scu.h> +#include <asm/io.h> +#include <mach/hardware.h> +#include <mach/mx6.h> +#include <mach/smp.h> +#include "src-reg.h" + +static DEFINE_SPINLOCK(boot_lock); + +static void __iomem *scu_base_addr(void) +{ + return IO_ADDRESS(SCU_BASE_ADDR); +} + +void __cpuinit platform_secondary_init(unsigned int cpu) +{ + trace_hardirqs_off(); + + spin_lock(&boot_lock); + /* + * if any interrupts are already enabled for the primary + * core (e.g. timer irq), then they will not have been enabled + * for us: do so + */ + gic_secondary_init(0); + + /* + * Synchronise with the boot thread. + */ + + spin_unlock(&boot_lock); + +} + +int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) +{ + unsigned long boot_entry; + void __iomem *src_base = IO_ADDRESS(SRC_BASE_ADDR); + unsigned int val; + + /* + * set synchronisation state between this boot processor + * and the secondary one + */ + spin_lock(&boot_lock); + + /* set entry point for cpu1-cpu3*/ + boot_entry = virt_to_phys(mx6_secondary_startup); + + writel(boot_entry, src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu); + writel(0, src_base + SRC_GPR1_OFFSET + 4 * 2 * cpu + 4); + + smp_wmb(); + dsb(); + flush_cache_all(); + + /* reset cpu<n> */ + val = readl(src_base + SRC_SCR_OFFSET); + val |= 1 << (BP_SRC_SCR_CORE0_RST + cpu); + val |= 1 << (BP_SRC_SCR_CORES_DBG_RST + cpu); + writel(val, src_base + SRC_SCR_OFFSET); + + /* + * now the secondary core is starting up let it run its + * calibrations, then wait for it to finish + */ + spin_unlock(&boot_lock); + + return 0; + +} + +/* + * Initialise the CPU possible map early - this describes the CPUs + * which may be present or become present in the system. + */ +void __init smp_init_cpus(void) +{ + void __iomem *scu_base = scu_base_addr(); + unsigned int i, ncores; + + ncores = scu_base ? scu_get_core_count(scu_base) : 1; + + /* sanity check */ + if (ncores == 0) { + pr_err("mx6: strange CM count of 0? Default to 1\n"); + ncores = 1; + } + if (ncores > NR_CPUS) { + pr_warning("mx6: no. of cores (%d) greater than configured " + "maximum of %d - clipping\n", + ncores, NR_CPUS); + ncores = NR_CPUS; + } + + for (i = 0; i < ncores; i++) + set_cpu_possible(i, true); + + set_smp_cross_call(gic_raise_softirq); +} +static void __init wakeup_secondary(void) +{ + +} + +void __init platform_smp_prepare_cpus(unsigned int max_cpus) +{ + int i; + void __iomem *scu_base = scu_base_addr(); + + /* + * Initialise the present map, which describes the set of CPUs + * actually populated at the present time. + */ + for (i = 0; i < max_cpus; i++) + set_cpu_present(i, true); + + /* + * Initialise the SCU and wake up the secondary core using + * wakeup_secondary(). + */ + scu_enable(scu_base); + wakeup_secondary(); +} diff --git a/arch/arm/mach-mx6/pm.c b/arch/arm/mach-mx6/pm.c new file mode 100644 index 00000000..a6b4c748 --- /dev/null +++ b/arch/arm/mach-mx6/pm.c @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2011-2013 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/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/suspend.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/anatop-regulator.h> +#include <linux/proc_fs.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/imx-pm.h> +#include <mach/arc_otg.h> +#include <asm/hardware/cache-l2x0.h> +#include <asm/hardware/gic.h> +#ifdef CONFIG_ARCH_MX6Q +#include <mach/iomux-mx6q.h> +#endif +#include "crm_regs.h" +#include "src-reg.h" +#include "regs-anadig.h" + +#define SCU_CTRL_OFFSET 0x00 +#define GPC_IMR1_OFFSET 0x08 +#define GPC_IMR2_OFFSET 0x0c +#define GPC_IMR3_OFFSET 0x10 +#define GPC_IMR4_OFFSET 0x14 +#define GPC_ISR1_OFFSET 0x18 +#define GPC_ISR2_OFFSET 0x1c +#define GPC_ISR3_OFFSET 0x20 +#define GPC_ISR4_OFFSET 0x24 +#define GPC_CNTR_OFFSET 0x0 +#define GPC_PGC_DISP_PGCR_OFFSET 0x240 +#define GPC_PGC_DISP_PUPSCR_OFFSET 0x244 +#define GPC_PGC_DISP_PDNSCR_OFFSET 0x248 +#define GPC_PGC_DISP_SR_OFFSET 0x24c +#define GPC_PGC_GPU_PGCR_OFFSET 0x260 +#define GPC_PGC_CPU_PDN_OFFSET 0x2a0 +#define GPC_PGC_CPU_PUPSCR_OFFSET 0x2a4 +#define GPC_PGC_CPU_PDNSCR_OFFSET 0x2a8 +#define UART_UCR3_OFFSET 0x88 +#define UART_USR1_OFFSET 0x94 +#define UART_UCR3_AWAKEN (1 << 4) +#define UART_USR1_AWAKE (1 << 4) +#define LOCAL_TWD_LOAD_OFFSET 0x0 +#define LOCAL_TWD_COUNT_OFFSET 0x4 +#define LOCAL_TWD_CONTROL_OFFSET 0x8 +#define LOCAL_TWD_INT_OFFSET 0xc +#define ANATOP_REG_1P1_OFFSET 0x110 +#define ANATOP_REG_2P5_OFFSET 0x130 +#define ANATOP_REG_CORE_OFFSET 0x140 +#define VDD3P0_VOLTAGE 3200000 + +static struct clk *cpu_clk; +static struct clk *axi_clk; +static struct clk *periph_clk; +static struct clk *pll3_usb_otg_main_clk; +static struct regulator *vdd3p0_regulator; + +static struct pm_platform_data *pm_data; + + +#if defined(CONFIG_CPU_FREQ) +extern int set_cpu_freq(int wp); +#endif +extern void mx6_suspend(suspend_state_t state); +extern void mx6_init_irq(void); +extern unsigned int gpc_wake_irq[4]; +extern bool enable_wait_mode; +extern unsigned long save_ttbr1(void); +extern void restore_ttbr1(u32 ttbr1); +extern int pu_disable(struct anatop_regulator *sreg); + +static struct device *pm_dev; +struct clk *gpc_dvfs_clk; +static void __iomem *scu_base; +static void __iomem *gpc_base; +static void __iomem *src_base; +static void __iomem *local_twd_base; +static void __iomem *gic_dist_base; +static void __iomem *gic_cpu_base; +static void __iomem *anatop_base; + +static void (*suspend_in_iram)(suspend_state_t state, + unsigned long iram_paddr, unsigned long suspend_iram_base, unsigned int cpu_type) = NULL; +static unsigned long cpaddr; + +static u32 ccm_ccr, ccm_clpcr, scu_ctrl; +static u32 gpc_imr[4], gpc_cpu_pup, gpc_cpu_pdn, gpc_cpu, gpc_ctr, gpc_disp; +static u32 anatop[3], ccgr1, ccgr2, ccgr3, ccgr6; +static u32 ccm_analog_pfd528; +static u32 ccm_analog_pll3_480; +static u32 ccm_anadig_ana_misc2; +static bool usb_vbus_wakeup_enabled; + +void *suspend_iram_base; +unsigned long suspend_iram_phys_addr; + +/* + * The USB VBUS wakeup should be disabled to avoid vbus wake system + * up due to vbus comparator is closed at weak 2p5 mode. + */ +static void usb_power_down_handler(void) +{ + u32 temp; + bool usb_oh3_clk_already_on; + if ((__raw_readl(anatop_base + HW_ANADIG_ANA_MISC0) + & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) != 0) { + usb_vbus_wakeup_enabled = false; + return; + } + /* enable usb oh3 clock if needed*/ + temp = __raw_readl(MXC_CCM_CCGR6); + usb_oh3_clk_already_on = \ + ((temp & (MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET)) \ + == (MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET)); + if (!usb_oh3_clk_already_on) { + temp |= MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET; + __raw_writel(temp, MXC_CCM_CCGR6); + } + /* disable vbus wakeup */ + usb_vbus_wakeup_enabled = !!(USB_OTG_CTRL & UCTRL_WKUP_VBUS_EN); + if (usb_vbus_wakeup_enabled) { + USB_OTG_CTRL &= ~UCTRL_WKUP_VBUS_EN; + } + /* disable usb oh3 clock */ + if (!usb_oh3_clk_already_on) { + temp = __raw_readl(MXC_CCM_CCGR6); + temp &= ~(MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET); + __raw_writel(temp, MXC_CCM_CCGR6); + } +} + +static void usb_power_up_handler(void) +{ + /* enable vbus wakeup at runtime if needed */ + if (usb_vbus_wakeup_enabled) { + u32 temp; + bool usb_oh3_clk_already_on; + /* enable usb oh3 clock if needed*/ + temp = __raw_readl(MXC_CCM_CCGR6); + usb_oh3_clk_already_on = \ + ((temp & (MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET)) \ + == (MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET)); + if (!usb_oh3_clk_already_on) { + temp |= MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET; + __raw_writel(temp, MXC_CCM_CCGR6); + } + + /* restore usb wakeup enable setting */ + USB_OTG_CTRL |= UCTRL_WKUP_VBUS_EN; + + /* disable usb oh3 clock */ + if (!usb_oh3_clk_already_on) { + temp = __raw_readl(MXC_CCM_CCGR6); + temp &= ~(MXC_CCM_CCGRx_CG_MASK << MXC_CCM_CCGRx_CG0_OFFSET); + __raw_writel(temp, MXC_CCM_CCGR6); + } + } +} + + +static void disp_power_down(void) +{ + if (cpu_is_mx6sl() && (mx6sl_revision() >= IMX_CHIP_REVISION_1_2)) { + + __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_DISP_PUPSCR_OFFSET); + __raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_DISP_PDNSCR_OFFSET); + + __raw_writel(0x1, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); + __raw_writel(0x10, gpc_base + GPC_CNTR_OFFSET); + + /* Disable EPDC/LCDIF pix clock, and EPDC/LCDIF/PXP axi clock */ + __raw_writel(ccgr3 & + ~MXC_CCM_CCGRx_CG5_MASK & + ~MXC_CCM_CCGRx_CG4_MASK & + ~MXC_CCM_CCGRx_CG3_MASK & + ~MXC_CCM_CCGRx_CG2_MASK & + ~MXC_CCM_CCGRx_CG1_MASK, MXC_CCM_CCGR3); + + } +} + +static void disp_power_up(void) +{ + if (cpu_is_mx6sl() && (mx6sl_revision() >= IMX_CHIP_REVISION_1_2)) { + /* + * Need to enable EPDC/LCDIF pix clock, and + * EPDC/LCDIF/PXP axi clock before power up. + */ + __raw_writel(ccgr3 | + MXC_CCM_CCGRx_CG5_MASK | + MXC_CCM_CCGRx_CG4_MASK | + MXC_CCM_CCGRx_CG3_MASK | + MXC_CCM_CCGRx_CG2_MASK | + MXC_CCM_CCGRx_CG1_MASK, MXC_CCM_CCGR3); + + __raw_writel(0x0, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); + __raw_writel(0x20, gpc_base + GPC_CNTR_OFFSET); + __raw_writel(0x1, gpc_base + GPC_PGC_DISP_SR_OFFSET); + } +} + +static void mx6_suspend_store(void) +{ + /* save some settings before suspend */ + ccm_ccr = __raw_readl(MXC_CCM_CCR); + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR); + ccm_analog_pfd528 = __raw_readl(PFD_528_BASE_ADDR); + ccm_analog_pll3_480 = __raw_readl(PLL3_480_USB1_BASE_ADDR); + ccm_anadig_ana_misc2 = __raw_readl(MXC_PLL_BASE + HW_ANADIG_ANA_MISC2); + ccgr1 = __raw_readl(MXC_CCM_CCGR1); + ccgr2 = __raw_readl(MXC_CCM_CCGR2); + ccgr3 = __raw_readl(MXC_CCM_CCGR3); + ccgr6 = __raw_readl(MXC_CCM_CCGR6); + scu_ctrl = __raw_readl(scu_base + SCU_CTRL_OFFSET); + gpc_imr[0] = __raw_readl(gpc_base + GPC_IMR1_OFFSET); + gpc_imr[1] = __raw_readl(gpc_base + GPC_IMR2_OFFSET); + gpc_imr[2] = __raw_readl(gpc_base + GPC_IMR3_OFFSET); + gpc_imr[3] = __raw_readl(gpc_base + GPC_IMR4_OFFSET); + gpc_cpu_pup = __raw_readl(gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); + gpc_cpu_pdn = __raw_readl(gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); + gpc_cpu = __raw_readl(gpc_base + GPC_PGC_CPU_PDN_OFFSET); + gpc_ctr = __raw_readl(gpc_base + GPC_CNTR_OFFSET); + if (cpu_is_mx6sl()) + gpc_disp = __raw_readl(gpc_base + GPC_PGC_DISP_PGCR_OFFSET); + anatop[0] = __raw_readl(anatop_base + ANATOP_REG_2P5_OFFSET); + anatop[1] = __raw_readl(anatop_base + ANATOP_REG_CORE_OFFSET); + anatop[2] = __raw_readl(anatop_base + ANATOP_REG_1P1_OFFSET); +} + +static void mx6_suspend_restore(void) +{ + /* restore settings after suspend */ + __raw_writel(anatop[0], anatop_base + ANATOP_REG_2P5_OFFSET); + __raw_writel(anatop[1], anatop_base + ANATOP_REG_CORE_OFFSET); + __raw_writel(anatop[2], anatop_base + ANATOP_REG_1P1_OFFSET); + /* Per spec, the count needs to be zeroed and reconfigured on exit from + * low power mode + */ + __raw_writel(ccm_ccr & ~MXC_CCM_CCR_REG_BYPASS_CNT_MASK & + ~MXC_CCM_CCR_WB_COUNT_MASK, MXC_CCM_CCR); + udelay(50); + __raw_writel(ccm_ccr, MXC_CCM_CCR); + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + __raw_writel(scu_ctrl, scu_base + SCU_CTRL_OFFSET); + __raw_writel(gpc_imr[0], gpc_base + GPC_IMR1_OFFSET); + __raw_writel(gpc_imr[1], gpc_base + GPC_IMR2_OFFSET); + __raw_writel(gpc_imr[2], gpc_base + GPC_IMR3_OFFSET); + __raw_writel(gpc_imr[3], gpc_base + GPC_IMR4_OFFSET); + __raw_writel(gpc_cpu_pup, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); + __raw_writel(gpc_cpu_pdn, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); + __raw_writel(gpc_cpu, gpc_base + GPC_PGC_CPU_PDN_OFFSET); + if (cpu_is_mx6sl()) + __raw_writel(gpc_disp, gpc_base + GPC_PGC_DISP_PGCR_OFFSET); + __raw_writel(ccgr1, MXC_CCM_CCGR1); + __raw_writel(ccgr2, MXC_CCM_CCGR2); + __raw_writel(ccgr3, MXC_CCM_CCGR3); + __raw_writel(ccgr6, MXC_CCM_CCGR6); + __raw_writel(ccm_analog_pfd528, PFD_528_BASE_ADDR); + __raw_writel(ccm_analog_pll3_480, PLL3_480_USB1_BASE_ADDR); + __raw_writel(ccm_anadig_ana_misc2, MXC_PLL_BASE + HW_ANADIG_ANA_MISC2); +} + +static int mx6_suspend_enter(suspend_state_t state) +{ + unsigned int wake_irq_isr[4]; + unsigned int cpu_type; + struct gic_dist_state gds; + struct gic_cpu_state gcs; + bool arm_pg = false; + + if (cpu_is_mx6q()) + cpu_type = MXC_CPU_MX6Q; + else if (cpu_is_mx6dl()) + cpu_type = MXC_CPU_MX6DL; + else + cpu_type = MXC_CPU_MX6SL; + + wake_irq_isr[0] = __raw_readl(gpc_base + + GPC_ISR1_OFFSET) & gpc_wake_irq[0]; + wake_irq_isr[1] = __raw_readl(gpc_base + + GPC_ISR2_OFFSET) & gpc_wake_irq[1]; + wake_irq_isr[2] = __raw_readl(gpc_base + + GPC_ISR3_OFFSET) & gpc_wake_irq[2]; + wake_irq_isr[3] = __raw_readl(gpc_base + + GPC_ISR4_OFFSET) & gpc_wake_irq[3]; + if (wake_irq_isr[0] | wake_irq_isr[1] | + wake_irq_isr[2] | wake_irq_isr[3]) { + printk(KERN_INFO "There are wakeup irq pending,system resume!\n"); + printk(KERN_INFO "wake_irq_isr[0-3]: 0x%x, 0x%x, 0x%x, 0x%x\n", + wake_irq_isr[0], wake_irq_isr[1], + wake_irq_isr[2], wake_irq_isr[3]); + return 0; + } + mx6_suspend_store(); + + /* + * i.MX6dl TO1.0/i.MX6dq TO1.1/1.0 TKT094231: can't support + * ARM_POWER_OFF mode. + */ + if (state == PM_SUSPEND_MEM && + ((mx6dl_revision() == IMX_CHIP_REVISION_1_0) || + (cpu_is_mx6q() && mx6q_revision() <= IMX_CHIP_REVISION_1_1))) { + state = PM_SUSPEND_STANDBY; + } + + switch (state) { + case PM_SUSPEND_MEM: + disp_power_down(); + usb_power_down_handler(); +#ifndef CONFIG_MXC_GPU_VIV + pu_disable(NULL); +#endif + mxc_cpu_lp_set(ARM_POWER_OFF); + arm_pg = true; + break; + case PM_SUSPEND_STANDBY: + if (cpu_is_mx6sl()) { + disp_power_down(); + usb_power_down_handler(); +#ifndef CONFIG_MXC_GPU_VIV + pu_disable(NULL); +#endif + mxc_cpu_lp_set(STOP_XTAL_ON); + arm_pg = true; + } else + mxc_cpu_lp_set(STOP_POWER_OFF); + break; + default: + return -EINVAL; + } + + /* + * L2 can exit by 'reset' or Inband beacon (from remote EP) + * toggling phy_powerdown has same effect as 'inband beacon' + * So, toggle bit18 of GPR1, to fix errata + * "PCIe PCIe does not support L2 Power Down" + */ + __raw_writel(__raw_readl(IOMUXC_GPR1) | (1 << 18), IOMUXC_GPR1); + + if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY) { + u32 ttbr1; + + flush_cache_all(); + + if (arm_pg) { + /* preserve gic state */ + save_gic_dist_state(0, &gds); + save_gic_cpu_state(0, &gcs); + } + + if (pm_data && pm_data->suspend_enter) + pm_data->suspend_enter(); + + ttbr1 = save_ttbr1(); + suspend_in_iram(state, (unsigned long)suspend_iram_phys_addr, + (unsigned long)suspend_iram_base, cpu_type); + restore_ttbr1(ttbr1); + + if (pm_data && pm_data->suspend_exit) + pm_data->suspend_exit(); + + /* Reset the RBC counter. */ + /* All interrupts should be masked before the + * RBC counter is reset. + */ + /* Mask all interrupts. These will be unmasked by + * the mx6_suspend_restore routine below. + */ + __raw_writel(0xffffffff, gpc_base + 0x08); + __raw_writel(0xffffffff, gpc_base + 0x0c); + __raw_writel(0xffffffff, gpc_base + 0x10); + __raw_writel(0xffffffff, gpc_base + 0x14); + + /* Clear the RBC counter and RBC_EN bit. */ + /* Disable the REG_BYPASS_COUNTER. */ + __raw_writel(__raw_readl(MXC_CCM_CCR) & + ~MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR); + /* Make sure we clear REG_BYPASS_COUNT*/ + __raw_writel(__raw_readl(MXC_CCM_CCR) & + (~MXC_CCM_CCR_REG_BYPASS_CNT_MASK), MXC_CCM_CCR); + /* Need to wait for a minimum of 2 CLKILS (32KHz) for the + * counter to clear and reset. + */ + udelay(80); + + if (arm_pg) { + /* restore gic registers */ + restore_gic_dist_state(0, &gds); + restore_gic_cpu_state(0, &gcs); + } + if (state == PM_SUSPEND_MEM || (cpu_is_mx6sl())) { + usb_power_up_handler(); + disp_power_up(); + } + + mx6_suspend_restore(); + + __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, + anatop_base + HW_ANADIG_ANA_MISC0_CLR); + + } else { + cpu_do_idle(); + } + + /* + * L2 can exit by 'reset' or Inband beacon (from remote EP) + * toggling phy_powerdown has same effect as 'inband beacon' + * So, toggle bit18 of GPR1, to fix errata + * "PCIe PCIe does not support L2 Power Down" + */ + __raw_writel(__raw_readl(IOMUXC_GPR1) & (~(1 << 18)), IOMUXC_GPR1); + + return 0; +} + + +/* + * Called after processes are frozen, but before we shut down devices. + */ +static int mx6_suspend_prepare(void) +{ + int ret; + ret = regulator_disable(vdd3p0_regulator); + if (ret) { + printk(KERN_ERR "%s: failed to disable 3p0 regulator Err: %d\n", + __func__, ret); + } + return 0; +} + +/* + * Called before devices are re-setup. + */ +static void mx6_suspend_finish(void) +{ + int ret; + ret = regulator_enable(vdd3p0_regulator); + if (ret) { + printk(KERN_ERR "%s: failed to enable 3p0 regulator Err: %d\n", + __func__, ret); + } +} + +static int mx6_suspend_begin(suspend_state_t state) +{ + return 0; +} + +/* + * Called after devices are re-setup, but before processes are thawed. + */ + +static int mx6_pm_valid(suspend_state_t state) +{ + return (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX); +} + +struct platform_suspend_ops mx6_suspend_ops = { + .valid = mx6_pm_valid, + .begin = mx6_suspend_begin, + .prepare = mx6_suspend_prepare, + .enter = mx6_suspend_enter, + .finish = mx6_suspend_finish, +}; + +static int __devinit mx6_pm_probe(struct platform_device *pdev) +{ + pm_dev = &pdev->dev; + pm_data = pdev->dev.platform_data; + + return 0; +} + +static struct platform_driver mx6_pm_driver = { + .driver = { + .name = "imx_pm", + }, + .probe = mx6_pm_probe, +}; + +static int __init pm_init(void) +{ + int ret = 0; + scu_base = IO_ADDRESS(SCU_BASE_ADDR); + gpc_base = IO_ADDRESS(GPC_BASE_ADDR); + src_base = IO_ADDRESS(SRC_BASE_ADDR); + gic_dist_base = IO_ADDRESS(IC_DISTRIBUTOR_BASE_ADDR); + gic_cpu_base = IO_ADDRESS(IC_INTERFACES_BASE_ADDR); + local_twd_base = IO_ADDRESS(LOCAL_TWD_ADDR); + anatop_base = IO_ADDRESS(ANATOP_BASE_ADDR); + + pr_info("Static Power Management for Freescale i.MX6\n"); + + pr_info("wait mode is %s for i.MX6\n", enable_wait_mode ? + "enabled" : "disabled"); + + if (platform_driver_register(&mx6_pm_driver) != 0) { + printk(KERN_ERR "mx6_pm_driver register failed\n"); + return -ENODEV; + } + + suspend_set_ops(&mx6_suspend_ops); + /* Use preallocated IRAM memory. */ + suspend_iram_phys_addr = MX6_SUSPEND_IRAM_CODE; + + /* Dont ioremap the address, we have fixed the IRAM address at IRAM_BASE_ADDR_VIRT */ + suspend_iram_base = IRAM_BASE_ADDR_VIRT + (suspend_iram_phys_addr - IRAM_BASE_ADDR); + + pr_info("cpaddr = %x suspend_iram_base=%x\n", + (unsigned int)cpaddr, (unsigned int)suspend_iram_base); + + /* + * Need to run the suspend code from IRAM as the DDR needs + * to be put into low power mode manually. + */ + memcpy((void *)suspend_iram_base, mx6_suspend, MX6_SUSPEND_CODE_SIZE); + + suspend_in_iram = (void *)suspend_iram_base; + + 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); + } + axi_clk = clk_get(NULL, "axi_clk"); + if (IS_ERR(axi_clk)) { + printk(KERN_DEBUG "%s: failed to get axi_clk\n", __func__); + return PTR_ERR(axi_clk); + } + periph_clk = clk_get(NULL, "periph_clk"); + if (IS_ERR(periph_clk)) { + printk(KERN_DEBUG "%s: failed to get periph_clk\n", __func__); + return PTR_ERR(periph_clk); + } + pll3_usb_otg_main_clk = clk_get(NULL, "pll3_main_clk"); + if (IS_ERR(pll3_usb_otg_main_clk)) { + printk(KERN_DEBUG "%s: failed to get pll3_main_clk\n", __func__); + return PTR_ERR(pll3_usb_otg_main_clk); + } + + vdd3p0_regulator = regulator_get(NULL, "cpu_vdd3p0"); + if (IS_ERR(vdd3p0_regulator)) { + printk(KERN_ERR "%s: failed to get 3p0 regulator Err: %d\n", + __func__, ret); + return PTR_ERR(vdd3p0_regulator); + } + ret = regulator_set_voltage(vdd3p0_regulator, VDD3P0_VOLTAGE, + VDD3P0_VOLTAGE); + if (ret) { + printk(KERN_ERR "%s: failed to set 3p0 regulator voltage Err: %d\n", + __func__, ret); + } + ret = regulator_enable(vdd3p0_regulator); + if (ret) { + printk(KERN_ERR "%s: failed to enable 3p0 regulator Err: %d\n", + __func__, ret); + } + + printk(KERN_INFO "PM driver module loaded\n"); + + return 0; +} + +static void __exit pm_cleanup(void) +{ + /* Unregister the device structure */ + platform_driver_unregister(&mx6_pm_driver); + regulator_put(vdd3p0_regulator); +} + +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-mx6/regs-anadig.h b/arch/arm/mach-mx6/regs-anadig.h new file mode 100644 index 00000000..b1d16456 --- /dev/null +++ b/arch/arm/mach-mx6/regs-anadig.h @@ -0,0 +1,1011 @@ +/* + * Copyright (C) 2011-2013 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. + */ + +/* + * Freescale ANADIG Register Definitions + * + * This file is created by xml file. Don't Edit it. + * + * Xml Revision: 1.30 + * Template revision: 1.3 + */ + +#ifndef __ARCH_ARM___ANADIG_H +#define __ARCH_ARM___ANADIG_H + + +#define HW_ANADIG_PLL_SYS (0x00000000) +#define HW_ANADIG_PLL_SYS_SET (0x00000004) +#define HW_ANADIG_PLL_SYS_CLR (0x00000008) +#define HW_ANADIG_PLL_SYS_TOG (0x0000000c) + +#define BM_ANADIG_PLL_SYS_LOCK 0x80000000 +#define BP_ANADIG_PLL_SYS_RSVD0 20 +#define BM_ANADIG_PLL_SYS_RSVD0 0x7FF00000 +#define BF_ANADIG_PLL_SYS_RSVD0(v) \ + (((v) << 20) & BM_ANADIG_PLL_SYS_RSVD0) +#define BM_ANADIG_PLL_SYS_PLL_SEL 0x00080000 +#define BM_ANADIG_PLL_SYS_LVDS_24MHZ_SEL 0x00040000 +#define BM_ANADIG_PLL_SYS_LVDS_SEL 0x00020000 +#define BM_ANADIG_PLL_SYS_BYPASS 0x00010000 +#define BP_ANADIG_PLL_SYS_BYPASS_CLK_SRC 14 +#define BM_ANADIG_PLL_SYS_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_PLL_SYS_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_PLL_SYS_BYPASS_CLK_SRC) +#define BV_ANADIG_PLL_SYS_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_PLL_SYS_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_PLL_SYS_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_PLL_SYS_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_PLL_SYS_ENABLE 0x00002000 +#define BM_ANADIG_PLL_SYS_POWERDOWN 0x00001000 +#define BM_ANADIG_PLL_SYS_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_PLL_SYS_DOUBLE_CP 0x00000400 +#define BM_ANADIG_PLL_SYS_HALF_CP 0x00000200 +#define BM_ANADIG_PLL_SYS_DOUBLE_LF 0x00000100 +#define BM_ANADIG_PLL_SYS_HALF_LF 0x00000080 +#define BP_ANADIG_PLL_SYS_DIV_SELECT 0 +#define BM_ANADIG_PLL_SYS_DIV_SELECT 0x0000007F +#define BF_ANADIG_PLL_SYS_DIV_SELECT(v) \ + (((v) << 0) & BM_ANADIG_PLL_SYS_DIV_SELECT) + +#define HW_ANADIG_USB1_PLL_480_CTRL (0x00000010) +#define HW_ANADIG_USB1_PLL_480_CTRL_SET (0x00000014) +#define HW_ANADIG_USB1_PLL_480_CTRL_CLR (0x00000018) +#define HW_ANADIG_USB1_PLL_480_CTRL_TOG (0x0000001c) + +#define BM_ANADIG_USB1_PLL_480_CTRL_LOCK 0x80000000 +#define BP_ANADIG_USB1_PLL_480_CTRL_RSVD1 17 +#define BM_ANADIG_USB1_PLL_480_CTRL_RSVD1 0x7FFE0000 +#define BF_ANADIG_USB1_PLL_480_CTRL_RSVD1(v) \ + (((v) << 17) & BM_ANADIG_USB1_PLL_480_CTRL_RSVD1) +#define BM_ANADIG_USB1_PLL_480_CTRL_BYPASS 0x00010000 +#define BP_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC 14 +#define BM_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC) +#define BV_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_USB1_PLL_480_CTRL_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_USB1_PLL_480_CTRL_ENABLE 0x00002000 +#define BM_ANADIG_USB1_PLL_480_CTRL_POWER 0x00001000 +#define BM_ANADIG_USB1_PLL_480_CTRL_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_USB1_PLL_480_CTRL_DOUBLE_CP 0x00000400 +#define BM_ANADIG_USB1_PLL_480_CTRL_HALF_CP 0x00000200 +#define BM_ANADIG_USB1_PLL_480_CTRL_DOUBLE_LF 0x00000100 +#define BM_ANADIG_USB1_PLL_480_CTRL_HALF_LF 0x00000080 +#define BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS 0x00000040 +#define BM_ANADIG_USB1_PLL_480_CTRL_RSVD0 0x00000020 +#define BP_ANADIG_USB1_PLL_480_CTRL_CONTROL0 2 +#define BM_ANADIG_USB1_PLL_480_CTRL_CONTROL0 0x0000001C +#define BF_ANADIG_USB1_PLL_480_CTRL_CONTROL0(v) \ + (((v) << 2) & BM_ANADIG_USB1_PLL_480_CTRL_CONTROL0) +#define BP_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT 0 +#define BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT 0x00000003 +#define BF_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT(v) \ + (((v) << 0) & BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT) + +#define HW_ANADIG_USB2_PLL_480_CTRL (0x00000020) +#define HW_ANADIG_USB2_PLL_480_CTRL_SET (0x00000024) +#define HW_ANADIG_USB2_PLL_480_CTRL_CLR (0x00000028) +#define HW_ANADIG_USB2_PLL_480_CTRL_TOG (0x0000002c) + +#define BM_ANADIG_USB2_PLL_480_CTRL_LOCK 0x80000000 +#define BP_ANADIG_USB2_PLL_480_CTRL_RSVD1 17 +#define BM_ANADIG_USB2_PLL_480_CTRL_RSVD1 0x7FFE0000 +#define BF_ANADIG_USB2_PLL_480_CTRL_RSVD1(v) \ + (((v) << 17) & BM_ANADIG_USB2_PLL_480_CTRL_RSVD1) +#define BM_ANADIG_USB2_PLL_480_CTRL_BYPASS 0x00010000 +#define BP_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC 14 +#define BM_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC) +#define BV_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_USB2_PLL_480_CTRL_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_USB2_PLL_480_CTRL_ENABLE 0x00002000 +#define BM_ANADIG_USB2_PLL_480_CTRL_POWER 0x00001000 +#define BM_ANADIG_USB2_PLL_480_CTRL_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_USB2_PLL_480_CTRL_DOUBLE_CP 0x00000400 +#define BM_ANADIG_USB2_PLL_480_CTRL_HALF_CP 0x00000200 +#define BM_ANADIG_USB2_PLL_480_CTRL_DOUBLE_LF 0x00000100 +#define BM_ANADIG_USB2_PLL_480_CTRL_HALF_LF 0x00000080 +#define BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS 0x00000040 +#define BM_ANADIG_USB2_PLL_480_CTRL_RSVD0 0x00000020 +#define BP_ANADIG_USB2_PLL_480_CTRL_CONTROL0 2 +#define BM_ANADIG_USB2_PLL_480_CTRL_CONTROL0 0x0000001C +#define BF_ANADIG_USB2_PLL_480_CTRL_CONTROL0(v) \ + (((v) << 2) & BM_ANADIG_USB2_PLL_480_CTRL_CONTROL0) +#define BP_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT 0 +#define BM_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT 0x00000003 +#define BF_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT(v) \ + (((v) << 0) & BM_ANADIG_USB2_PLL_480_CTRL_DIV_SELECT) + +#define HW_ANADIG_PLL_528 (0x00000030) +#define HW_ANADIG_PLL_528_SET (0x00000034) +#define HW_ANADIG_PLL_528_CLR (0x00000038) +#define HW_ANADIG_PLL_528_TOG (0x0000003c) + +#define BM_ANADIG_PLL_528_LOCK 0x80000000 +#define BP_ANADIG_PLL_528_RSVD1 19 +#define BM_ANADIG_PLL_528_RSVD1 0x7FF80000 +#define BF_ANADIG_PLL_528_RSVD1(v) \ + (((v) << 19) & BM_ANADIG_PLL_528_RSVD1) +#define BM_ANADIG_PLL_528_PFD_OFFSET_EN 0x00040000 +#define BM_ANADIG_PLL_528_DITHER_ENABLE 0x00020000 +#define BM_ANADIG_PLL_528_BYPASS 0x00010000 +#define BP_ANADIG_PLL_528_BYPASS_CLK_SRC 14 +#define BM_ANADIG_PLL_528_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_PLL_528_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_PLL_528_BYPASS_CLK_SRC) +#define BV_ANADIG_PLL_528_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_PLL_528_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_PLL_528_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_PLL_528_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_PLL_528_ENABLE 0x00002000 +#define BM_ANADIG_PLL_528_POWERDOWN 0x00001000 +#define BM_ANADIG_PLL_528_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_PLL_528_DOUBLE_CP 0x00000400 +#define BM_ANADIG_PLL_528_HALF_CP 0x00000200 +#define BM_ANADIG_PLL_528_DOUBLE_LF 0x00000100 +#define BM_ANADIG_PLL_528_HALF_LF 0x00000080 +#define BP_ANADIG_PLL_528_RSVD0 1 +#define BM_ANADIG_PLL_528_RSVD0 0x0000007E +#define BF_ANADIG_PLL_528_RSVD0(v) \ + (((v) << 1) & BM_ANADIG_PLL_528_RSVD0) +#define BM_ANADIG_PLL_528_DIV_SELECT 0x00000001 + +#define HW_ANADIG_PLL_528_SS (0x00000040) + +#define BP_ANADIG_PLL_528_SS_STOP 16 +#define BM_ANADIG_PLL_528_SS_STOP 0xFFFF0000 +#define BF_ANADIG_PLL_528_SS_STOP(v) \ + (((v) << 16) & BM_ANADIG_PLL_528_SS_STOP) +#define BM_ANADIG_PLL_528_SS_ENABLE 0x00008000 +#define BP_ANADIG_PLL_528_SS_STEP 0 +#define BM_ANADIG_PLL_528_SS_STEP 0x00007FFF +#define BF_ANADIG_PLL_528_SS_STEP(v) \ + (((v) << 0) & BM_ANADIG_PLL_528_SS_STEP) + +#define HW_ANADIG_PLL_528_NUM (0x00000050) + +#define BP_ANADIG_PLL_528_NUM_RSVD0 30 +#define BM_ANADIG_PLL_528_NUM_RSVD0 0xC0000000 +#define BF_ANADIG_PLL_528_NUM_RSVD0(v) \ + (((v) << 30) & BM_ANADIG_PLL_528_NUM_RSVD0) +#define BP_ANADIG_PLL_528_NUM_A 0 +#define BM_ANADIG_PLL_528_NUM_A 0x3FFFFFFF +#define BF_ANADIG_PLL_528_NUM_A(v) \ + (((v) << 0) & BM_ANADIG_PLL_528_NUM_A) + +#define HW_ANADIG_PLL_528_DENOM (0x00000060) + +#define BP_ANADIG_PLL_528_DENOM_RSVD0 30 +#define BM_ANADIG_PLL_528_DENOM_RSVD0 0xC0000000 +#define BF_ANADIG_PLL_528_DENOM_RSVD0(v) \ + (((v) << 30) & BM_ANADIG_PLL_528_DENOM_RSVD0) +#define BP_ANADIG_PLL_528_DENOM_B 0 +#define BM_ANADIG_PLL_528_DENOM_B 0x3FFFFFFF +#define BF_ANADIG_PLL_528_DENOM_B(v) \ + (((v) << 0) & BM_ANADIG_PLL_528_DENOM_B) + +#define HW_ANADIG_PLL_AUDIO (0x00000070) +#define HW_ANADIG_PLL_AUDIO_SET (0x00000074) +#define HW_ANADIG_PLL_AUDIO_CLR (0x00000078) +#define HW_ANADIG_PLL_AUDIO_TOG (0x0000007c) + +#define BM_ANADIG_PLL_AUDIO_LOCK 0x80000000 +#define BP_ANADIG_PLL_AUDIO_RSVD0 22 +#define BM_ANADIG_PLL_AUDIO_RSVD0 0x7FC00000 +#define BF_ANADIG_PLL_AUDIO_RSVD0(v) \ + (((v) << 22) & BM_ANADIG_PLL_AUDIO_RSVD0) +#define BM_ANADIG_PLL_AUDIO_SSC_EN 0x00200000 +#define BP_ANADIG_PLL_AUDIO_TEST_DIV_SELECT 19 +#define BM_ANADIG_PLL_AUDIO_TEST_DIV_SELECT 0x00180000 +#define BF_ANADIG_PLL_AUDIO_TEST_DIV_SELECT(v) \ + (((v) << 19) & BM_ANADIG_PLL_AUDIO_TEST_DIV_SELECT) +#define BM_ANADIG_PLL_AUDIO_PFD_OFFSET_EN 0x00040000 +#define BM_ANADIG_PLL_AUDIO_DITHER_ENABLE 0x00020000 +#define BM_ANADIG_PLL_AUDIO_BYPASS 0x00010000 +#define BP_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC 14 +#define BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC) +#define BV_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_PLL_AUDIO_ENABLE 0x00002000 +#define BM_ANADIG_PLL_AUDIO_POWERDOWN 0x00001000 +#define BM_ANADIG_PLL_AUDIO_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_PLL_AUDIO_DOUBLE_CP 0x00000400 +#define BM_ANADIG_PLL_AUDIO_HALF_CP 0x00000200 +#define BM_ANADIG_PLL_AUDIO_DOUBLE_LF 0x00000100 +#define BM_ANADIG_PLL_AUDIO_HALF_LF 0x00000080 +#define BP_ANADIG_PLL_AUDIO_DIV_SELECT 0 +#define BM_ANADIG_PLL_AUDIO_DIV_SELECT 0x0000007F +#define BF_ANADIG_PLL_AUDIO_DIV_SELECT(v) \ + (((v) << 0) & BM_ANADIG_PLL_AUDIO_DIV_SELECT) + +#define HW_ANADIG_PLL_AUDIO_NUM (0x00000080) + +#define BP_ANADIG_PLL_AUDIO_NUM_RSVD0 30 +#define BM_ANADIG_PLL_AUDIO_NUM_RSVD0 0xC0000000 +#define BF_ANADIG_PLL_AUDIO_NUM_RSVD0(v) \ + (((v) << 30) & BM_ANADIG_PLL_AUDIO_NUM_RSVD0) +#define BP_ANADIG_PLL_AUDIO_NUM_A 0 +#define BM_ANADIG_PLL_AUDIO_NUM_A 0x3FFFFFFF +#define BF_ANADIG_PLL_AUDIO_NUM_A(v) \ + (((v) << 0) & BM_ANADIG_PLL_AUDIO_NUM_A) + +#define HW_ANADIG_PLL_AUDIO_DENOM (0x00000090) + +#define BP_ANADIG_PLL_AUDIO_DENOM_RSVD0 30 +#define BM_ANADIG_PLL_AUDIO_DENOM_RSVD0 0xC0000000 +#define BF_ANADIG_PLL_AUDIO_DENOM_RSVD0(v) \ + (((v) << 30) & BM_ANADIG_PLL_AUDIO_DENOM_RSVD0) +#define BP_ANADIG_PLL_AUDIO_DENOM_B 0 +#define BM_ANADIG_PLL_AUDIO_DENOM_B 0x3FFFFFFF +#define BF_ANADIG_PLL_AUDIO_DENOM_B(v) \ + (((v) << 0) & BM_ANADIG_PLL_AUDIO_DENOM_B) + +#define HW_ANADIG_PLL_VIDEO (0x000000a0) +#define HW_ANADIG_PLL_VIDEO_SET (0x000000a4) +#define HW_ANADIG_PLL_VIDEO_CLR (0x000000a8) +#define HW_ANADIG_PLL_VIDEO_TOG (0x000000ac) + +#define BM_ANADIG_PLL_VIDEO_LOCK 0x80000000 +#define BP_ANADIG_PLL_VIDEO_RSVD0 22 +#define BM_ANADIG_PLL_VIDEO_RSVD0 0x7FC00000 +#define BF_ANADIG_PLL_VIDEO_RSVD0(v) \ + (((v) << 22) & BM_ANADIG_PLL_VIDEO_RSVD0) +#define BM_ANADIG_PLL_VIDEO_SSC_EN 0x00200000 +#define BP_ANADIG_PLL_VIDEO_TEST_DIV_SELECT 19 +#define BM_ANADIG_PLL_VIDEO_TEST_DIV_SELECT 0x00180000 +#define BF_ANADIG_PLL_VIDEO_TEST_DIV_SELECT(v) \ + (((v) << 19) & BM_ANADIG_PLL_VIDEO_TEST_DIV_SELECT) +#define BM_ANADIG_PLL_VIDEO_PFD_OFFSET_EN 0x00040000 +#define BM_ANADIG_PLL_VIDEO_DITHER_ENABLE 0x00020000 +#define BM_ANADIG_PLL_VIDEO_BYPASS 0x00010000 +#define BP_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC 14 +#define BM_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC) +#define BV_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_PLL_VIDEO_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_PLL_VIDEO_ENABLE 0x00002000 +#define BM_ANADIG_PLL_VIDEO_POWERDOWN 0x00001000 +#define BM_ANADIG_PLL_VIDEO_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_PLL_VIDEO_DOUBLE_CP 0x00000400 +#define BM_ANADIG_PLL_VIDEO_HALF_CP 0x00000200 +#define BM_ANADIG_PLL_VIDEO_DOUBLE_LF 0x00000100 +#define BM_ANADIG_PLL_VIDEO_HALF_LF 0x00000080 +#define BP_ANADIG_PLL_VIDEO_DIV_SELECT 0 +#define BM_ANADIG_PLL_VIDEO_DIV_SELECT 0x0000007F +#define BF_ANADIG_PLL_VIDEO_DIV_SELECT(v) \ + (((v) << 0) & BM_ANADIG_PLL_VIDEO_DIV_SELECT) + +#define HW_ANADIG_PLL_VIDEO_NUM (0x000000b0) + +#define BP_ANADIG_PLL_VIDEO_NUM_RSVD0 30 +#define BM_ANADIG_PLL_VIDEO_NUM_RSVD0 0xC0000000 +#define BF_ANADIG_PLL_VIDEO_NUM_RSVD0(v) \ + (((v) << 30) & BM_ANADIG_PLL_VIDEO_NUM_RSVD0) +#define BP_ANADIG_PLL_VIDEO_NUM_A 0 +#define BM_ANADIG_PLL_VIDEO_NUM_A 0x3FFFFFFF +#define BF_ANADIG_PLL_VIDEO_NUM_A(v) \ + (((v) << 0) & BM_ANADIG_PLL_VIDEO_NUM_A) + +#define HW_ANADIG_PLL_VIDEO_DENOM (0x000000c0) + +#define BP_ANADIG_PLL_VIDEO_DENOM_RSVD0 30 +#define BM_ANADIG_PLL_VIDEO_DENOM_RSVD0 0xC0000000 +#define BF_ANADIG_PLL_VIDEO_DENOM_RSVD0(v) \ + (((v) << 30) & BM_ANADIG_PLL_VIDEO_DENOM_RSVD0) +#define BP_ANADIG_PLL_VIDEO_DENOM_B 0 +#define BM_ANADIG_PLL_VIDEO_DENOM_B 0x3FFFFFFF +#define BF_ANADIG_PLL_VIDEO_DENOM_B(v) \ + (((v) << 0) & BM_ANADIG_PLL_VIDEO_DENOM_B) + +#define HW_ANADIG_PLL_MLB (0x000000d0) +#define HW_ANADIG_PLL_MLB_SET (0x000000d4) +#define HW_ANADIG_PLL_MLB_CLR (0x000000d8) +#define HW_ANADIG_PLL_MLB_TOG (0x000000dc) + +#define BM_ANADIG_PLL_MLB_LOCK 0x80000000 +#define BP_ANADIG_PLL_MLB_RSVD2 29 +#define BM_ANADIG_PLL_MLB_RSVD2 0x60000000 +#define BF_ANADIG_PLL_MLB_RSVD2(v) \ + (((v) << 29) & BM_ANADIG_PLL_MLB_RSVD2) +#define BP_ANADIG_PLL_MLB_MLB_FLT_RES_SEL 26 +#define BM_ANADIG_PLL_MLB_MLB_FLT_RES_SEL 0x1C000000 +#define BF_ANADIG_PLL_MLB_MLB_FLT_RES_SEL(v) \ + (((v) << 26) & BM_ANADIG_PLL_MLB_MLB_FLT_RES_SEL) +#define BP_ANADIG_PLL_MLB_RX_CLK_DELAY_CFG 23 +#define BM_ANADIG_PLL_MLB_RX_CLK_DELAY_CFG 0x03800000 +#define BF_ANADIG_PLL_MLB_RX_CLK_DELAY_CFG(v) \ + (((v) << 23) & BM_ANADIG_PLL_MLB_RX_CLK_DELAY_CFG) +#define BP_ANADIG_PLL_MLB_VDDD_DELAY_CFG 20 +#define BM_ANADIG_PLL_MLB_VDDD_DELAY_CFG 0x00700000 +#define BF_ANADIG_PLL_MLB_VDDD_DELAY_CFG(v) \ + (((v) << 20) & BM_ANADIG_PLL_MLB_VDDD_DELAY_CFG) +#define BP_ANADIG_PLL_MLB_VDDA_DELAY_CFG 17 +#define BM_ANADIG_PLL_MLB_VDDA_DELAY_CFG 0x000E0000 +#define BF_ANADIG_PLL_MLB_VDDA_DELAY_CFG(v) \ + (((v) << 17) & BM_ANADIG_PLL_MLB_VDDA_DELAY_CFG) +#define BM_ANADIG_PLL_MLB_BYPASS 0x00010000 +#define BP_ANADIG_PLL_MLB_RSVD1 14 +#define BM_ANADIG_PLL_MLB_RSVD1 0x0000C000 +#define BF_ANADIG_PLL_MLB_RSVD1(v) \ + (((v) << 14) & BM_ANADIG_PLL_MLB_RSVD1) +#define BP_ANADIG_PLL_MLB_PHASE_SEL 12 +#define BM_ANADIG_PLL_MLB_PHASE_SEL 0x00003000 +#define BF_ANADIG_PLL_MLB_PHASE_SEL(v) \ + (((v) << 12) & BM_ANADIG_PLL_MLB_PHASE_SEL) +#define BM_ANADIG_PLL_MLB_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_PLL_MLB_DOUBLE_CP 0x00000400 +#define BM_ANADIG_PLL_MLB_HALF_CP 0x00000200 +#define BP_ANADIG_PLL_MLB_RSVD0 0 +#define BM_ANADIG_PLL_MLB_RSVD0 0x000001FF +#define BF_ANADIG_PLL_MLB_RSVD0(v) \ + (((v) << 0) & BM_ANADIG_PLL_MLB_RSVD0) + +#define HW_ANADIG_PLL_ENET (0x000000e0) +#define HW_ANADIG_PLL_ENET_SET (0x000000e4) +#define HW_ANADIG_PLL_ENET_CLR (0x000000e8) +#define HW_ANADIG_PLL_ENET_TOG (0x000000ec) + +#define BM_ANADIG_PLL_ENET_LOCK 0x80000000 +#define BP_ANADIG_PLL_ENET_RSVD1 21 +#define BM_ANADIG_PLL_ENET_RSVD1 0x7FE00000 +#define BF_ANADIG_PLL_ENET_RSVD1(v) \ + (((v) << 21) & BM_ANADIG_PLL_ENET_RSVD1) +#define BM_ANADIG_PLL_ENET_ENABLE_SATA 0x00100000 +#define BM_ANADIG_PLL_ENET_ENABLE_PCIE 0x00080000 +#define BM_ANADIG_PLL_ENET_PFD_OFFSET_EN 0x00040000 +#define BM_ANADIG_PLL_ENET_DITHER_ENABLE 0x00020000 +#define BM_ANADIG_PLL_ENET_BYPASS 0x00010000 +#define BP_ANADIG_PLL_ENET_BYPASS_CLK_SRC 14 +#define BM_ANADIG_PLL_ENET_BYPASS_CLK_SRC 0x0000C000 +#define BF_ANADIG_PLL_ENET_BYPASS_CLK_SRC(v) \ + (((v) << 14) & BM_ANADIG_PLL_ENET_BYPASS_CLK_SRC) +#define BV_ANADIG_PLL_ENET_BYPASS_CLK_SRC__OSC_24M 0x0 +#define BV_ANADIG_PLL_ENET_BYPASS_CLK_SRC__ANACLK_1 0x1 +#define BV_ANADIG_PLL_ENET_BYPASS_CLK_SRC__ANACLK_2 0x2 +#define BV_ANADIG_PLL_ENET_BYPASS_CLK_SRC__XOR 0x3 +#define BM_ANADIG_PLL_ENET_ENABLE 0x00002000 +#define BM_ANADIG_PLL_ENET_POWERDOWN 0x00001000 +#define BM_ANADIG_PLL_ENET_HOLD_RING_OFF 0x00000800 +#define BM_ANADIG_PLL_ENET_DOUBLE_CP 0x00000400 +#define BM_ANADIG_PLL_ENET_HALF_CP 0x00000200 +#define BM_ANADIG_PLL_ENET_DOUBLE_LF 0x00000100 +#define BM_ANADIG_PLL_ENET_HALF_LF 0x00000080 +#define BP_ANADIG_PLL_ENET_RSVD0 2 +#define BM_ANADIG_PLL_ENET_RSVD0 0x0000007C +#define BF_ANADIG_PLL_ENET_RSVD0(v) \ + (((v) << 2) & BM_ANADIG_PLL_ENET_RSVD0) +#define BP_ANADIG_PLL_ENET_DIV_SELECT 0 +#define BM_ANADIG_PLL_ENET_DIV_SELECT 0x00000003 +#define BF_ANADIG_PLL_ENET_DIV_SELECT(v) \ + (((v) << 0) & BM_ANADIG_PLL_ENET_DIV_SELECT) + +#define HW_ANADIG_PFD_480 (0x000000f0) +#define HW_ANADIG_PFD_480_SET (0x000000f4) +#define HW_ANADIG_PFD_480_CLR (0x000000f8) +#define HW_ANADIG_PFD_480_TOG (0x000000fc) + +#define BM_ANADIG_PFD_480_PFD3_CLKGATE 0x80000000 +#define BM_ANADIG_PFD_480_PFD3_STABLE 0x40000000 +#define BP_ANADIG_PFD_480_PFD3_FRAC 24 +#define BM_ANADIG_PFD_480_PFD3_FRAC 0x3F000000 +#define BF_ANADIG_PFD_480_PFD3_FRAC(v) \ + (((v) << 24) & BM_ANADIG_PFD_480_PFD3_FRAC) +#define BM_ANADIG_PFD_480_PFD2_CLKGATE 0x00800000 +#define BM_ANADIG_PFD_480_PFD2_STABLE 0x00400000 +#define BP_ANADIG_PFD_480_PFD2_FRAC 16 +#define BM_ANADIG_PFD_480_PFD2_FRAC 0x003F0000 +#define BF_ANADIG_PFD_480_PFD2_FRAC(v) \ + (((v) << 16) & BM_ANADIG_PFD_480_PFD2_FRAC) +#define BM_ANADIG_PFD_480_PFD1_CLKGATE 0x00008000 +#define BM_ANADIG_PFD_480_PFD1_STABLE 0x00004000 +#define BP_ANADIG_PFD_480_PFD1_FRAC 8 +#define BM_ANADIG_PFD_480_PFD1_FRAC 0x00003F00 +#define BF_ANADIG_PFD_480_PFD1_FRAC(v) \ + (((v) << 8) & BM_ANADIG_PFD_480_PFD1_FRAC) +#define BM_ANADIG_PFD_480_PFD0_CLKGATE 0x00000080 +#define BM_ANADIG_PFD_480_PFD0_STABLE 0x00000040 +#define BP_ANADIG_PFD_480_PFD0_FRAC 0 +#define BM_ANADIG_PFD_480_PFD0_FRAC 0x0000003F +#define BF_ANADIG_PFD_480_PFD0_FRAC(v) \ + (((v) << 0) & BM_ANADIG_PFD_480_PFD0_FRAC) + +#define HW_ANADIG_PFD_528 (0x00000100) +#define HW_ANADIG_PFD_528_SET (0x00000104) +#define HW_ANADIG_PFD_528_CLR (0x00000108) +#define HW_ANADIG_PFD_528_TOG (0x0000010c) + +#define BM_ANADIG_PFD_528_PFD3_CLKGATE 0x80000000 +#define BM_ANADIG_PFD_528_PFD3_STABLE 0x40000000 +#define BP_ANADIG_PFD_528_PFD3_FRAC 24 +#define BM_ANADIG_PFD_528_PFD3_FRAC 0x3F000000 +#define BF_ANADIG_PFD_528_PFD3_FRAC(v) \ + (((v) << 24) & BM_ANADIG_PFD_528_PFD3_FRAC) +#define BM_ANADIG_PFD_528_PFD2_CLKGATE 0x00800000 +#define BM_ANADIG_PFD_528_PFD2_STABLE 0x00400000 +#define BP_ANADIG_PFD_528_PFD2_FRAC 16 +#define BM_ANADIG_PFD_528_PFD2_FRAC 0x003F0000 +#define BF_ANADIG_PFD_528_PFD2_FRAC(v) \ + (((v) << 16) & BM_ANADIG_PFD_528_PFD2_FRAC) +#define BM_ANADIG_PFD_528_PFD1_CLKGATE 0x00008000 +#define BM_ANADIG_PFD_528_PFD1_STABLE 0x00004000 +#define BP_ANADIG_PFD_528_PFD1_FRAC 8 +#define BM_ANADIG_PFD_528_PFD1_FRAC 0x00003F00 +#define BF_ANADIG_PFD_528_PFD1_FRAC(v) \ + (((v) << 8) & BM_ANADIG_PFD_528_PFD1_FRAC) +#define BM_ANADIG_PFD_528_PFD0_CLKGATE 0x00000080 +#define BM_ANADIG_PFD_528_PFD0_STABLE 0x00000040 +#define BP_ANADIG_PFD_528_PFD0_FRAC 0 +#define BM_ANADIG_PFD_528_PFD0_FRAC 0x0000003F +#define BF_ANADIG_PFD_528_PFD0_FRAC(v) \ + (((v) << 0) & BM_ANADIG_PFD_528_PFD0_FRAC) + +#define HW_ANADIG_REG_1P1 (0x00000110) +#define HW_ANADIG_REG_1P1_SET (0x00000114) +#define HW_ANADIG_REG_1P1_CLR (0x00000118) +#define HW_ANADIG_REG_1P1_TOG (0x0000011c) + +#define BP_ANADIG_REG_1P1_RSVD2 18 +#define BM_ANADIG_REG_1P1_RSVD2 0xFFFC0000 +#define BF_ANADIG_REG_1P1_RSVD2(v) \ + (((v) << 18) & BM_ANADIG_REG_1P1_RSVD2) +#define BM_ANADIG_REG_1P1_OK_VDD1P1 0x00020000 +#define BM_ANADIG_REG_1P1_BO_VDD1P1 0x00010000 +#define BP_ANADIG_REG_1P1_RSVD1 13 +#define BM_ANADIG_REG_1P1_RSVD1 0x0000E000 +#define BF_ANADIG_REG_1P1_RSVD1(v) \ + (((v) << 13) & BM_ANADIG_REG_1P1_RSVD1) +#define BP_ANADIG_REG_1P1_OUTPUT_TRG 8 +#define BM_ANADIG_REG_1P1_OUTPUT_TRG 0x00001F00 +#define BF_ANADIG_REG_1P1_OUTPUT_TRG(v) \ + (((v) << 8) & BM_ANADIG_REG_1P1_OUTPUT_TRG) +#define BM_ANADIG_REG_1P1_RSVD0 0x00000080 +#define BP_ANADIG_REG_1P1_BO_OFFSET 4 +#define BM_ANADIG_REG_1P1_BO_OFFSET 0x00000070 +#define BF_ANADIG_REG_1P1_BO_OFFSET(v) \ + (((v) << 4) & BM_ANADIG_REG_1P1_BO_OFFSET) +#define BM_ANADIG_REG_1P1_ENABLE_PULLDOWN 0x00000008 +#define BM_ANADIG_REG_1P1_ENABLE_ILIMIT 0x00000004 +#define BM_ANADIG_REG_1P1_ENABLE_BO 0x00000002 +#define BM_ANADIG_REG_1P1_ENABLE_LINREG 0x00000001 + +#define HW_ANADIG_REG_3P0 (0x00000120) +#define HW_ANADIG_REG_3P0_SET (0x00000124) +#define HW_ANADIG_REG_3P0_CLR (0x00000128) +#define HW_ANADIG_REG_3P0_TOG (0x0000012c) + +#define BP_ANADIG_REG_3P0_RSVD2 18 +#define BM_ANADIG_REG_3P0_RSVD2 0xFFFC0000 +#define BF_ANADIG_REG_3P0_RSVD2(v) \ + (((v) << 18) & BM_ANADIG_REG_3P0_RSVD2) +#define BM_ANADIG_REG_3P0_OK_VDD3P0 0x00020000 +#define BM_ANADIG_REG_3P0_BO_VDD3P0 0x00010000 +#define BP_ANADIG_REG_3P0_RSVD1 13 +#define BM_ANADIG_REG_3P0_RSVD1 0x0000E000 +#define BF_ANADIG_REG_3P0_RSVD1(v) \ + (((v) << 13) & BM_ANADIG_REG_3P0_RSVD1) +#define BP_ANADIG_REG_3P0_OUTPUT_TRG 8 +#define BM_ANADIG_REG_3P0_OUTPUT_TRG 0x00001F00 +#define BF_ANADIG_REG_3P0_OUTPUT_TRG(v) \ + (((v) << 8) & BM_ANADIG_REG_3P0_OUTPUT_TRG) +#define BM_ANADIG_REG_3P0_VBUS_SEL 0x00000080 +#define BP_ANADIG_REG_3P0_BO_OFFSET 4 +#define BM_ANADIG_REG_3P0_BO_OFFSET 0x00000070 +#define BF_ANADIG_REG_3P0_BO_OFFSET(v) \ + (((v) << 4) & BM_ANADIG_REG_3P0_BO_OFFSET) +#define BM_ANADIG_REG_3P0_RSVD0 0x00000008 +#define BM_ANADIG_REG_3P0_ENABLE_ILIMIT 0x00000004 +#define BM_ANADIG_REG_3P0_ENABLE_BO 0x00000002 +#define BM_ANADIG_REG_3P0_ENABLE_LINREG 0x00000001 + +#define HW_ANADIG_REG_2P5 (0x00000130) +#define HW_ANADIG_REG_2P5_SET (0x00000134) +#define HW_ANADIG_REG_2P5_CLR (0x00000138) +#define HW_ANADIG_REG_2P5_TOG (0x0000013c) + +#define BP_ANADIG_REG_2P5_RSVD2 19 +#define BM_ANADIG_REG_2P5_RSVD2 0xFFF80000 +#define BF_ANADIG_REG_2P5_RSVD2(v) \ + (((v) << 19) & BM_ANADIG_REG_2P5_RSVD2) +#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x00040000 +#define BM_ANADIG_REG_2P5_OK_VDD2P5 0x00020000 +#define BM_ANADIG_REG_2P5_BO_VDD2P5 0x00010000 +#define BP_ANADIG_REG_2P5_RSVD1 13 +#define BM_ANADIG_REG_2P5_RSVD1 0x0000E000 +#define BF_ANADIG_REG_2P5_RSVD1(v) \ + (((v) << 13) & BM_ANADIG_REG_2P5_RSVD1) +#define BP_ANADIG_REG_2P5_OUTPUT_TRG 8 +#define BM_ANADIG_REG_2P5_OUTPUT_TRG 0x00001F00 +#define BF_ANADIG_REG_2P5_OUTPUT_TRG(v) \ + (((v) << 8) & BM_ANADIG_REG_2P5_OUTPUT_TRG) +#define BM_ANADIG_REG_2P5_RSVD0 0x00000080 +#define BP_ANADIG_REG_2P5_BO_OFFSET 4 +#define BM_ANADIG_REG_2P5_BO_OFFSET 0x00000070 +#define BF_ANADIG_REG_2P5_BO_OFFSET(v) \ + (((v) << 4) & BM_ANADIG_REG_2P5_BO_OFFSET) +#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x00000008 +#define BM_ANADIG_REG_2P5_ENABLE_ILIMIT 0x00000004 +#define BM_ANADIG_REG_2P5_ENABLE_BO 0x00000002 +#define BM_ANADIG_REG_2P5_ENABLE_LINREG 0x00000001 + +#define HW_ANADIG_REG_CORE (0x00000140) +#define HW_ANADIG_REG_CORE_SET (0x00000144) +#define HW_ANADIG_REG_CORE_CLR (0x00000148) +#define HW_ANADIG_REG_CORE_TOG (0x0000014c) + +#define BM_ANADIG_REG_CORE_REF_SHIFT 0x80000000 +#define BM_ANADIG_REG_CORE_RSVD0 0x40000000 +#define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000 +#define BP_ANADIG_REG_CORE_RAMP_RATE 27 +#define BM_ANADIG_REG_CORE_RAMP_RATE 0x18000000 +#define BF_ANADIG_REG_CORE_RAMP_RATE(v) \ + (((v) << 27) & BM_ANADIG_REG_CORE_RAMP_RATE) +#define BP_ANADIG_REG_CORE_REG2_ADJ 23 +#define BM_ANADIG_REG_CORE_REG2_ADJ 0x07800000 +#define BF_ANADIG_REG_CORE_REG2_ADJ(v) \ + (((v) << 23) & BM_ANADIG_REG_CORE_REG2_ADJ) +#define BP_ANADIG_REG_CORE_REG2_TRG 18 +#define BM_ANADIG_REG_CORE_REG2_TRG 0x007C0000 +#define BF_ANADIG_REG_CORE_REG2_TRG(v) \ + (((v) << 18) & BM_ANADIG_REG_CORE_REG2_TRG) +#define BP_ANADIG_REG_CORE_REG1_ADJ 14 +#define BM_ANADIG_REG_CORE_REG1_ADJ 0x0003C000 +#define BF_ANADIG_REG_CORE_REG1_ADJ(v) \ + (((v) << 14) & BM_ANADIG_REG_CORE_REG1_ADJ) +#define BP_ANADIG_REG_CORE_REG1_TRG 9 +#define BM_ANADIG_REG_CORE_REG1_TRG 0x00003E00 +#define BF_ANADIG_REG_CORE_REG1_TRG(v) \ + (((v) << 9) & BM_ANADIG_REG_CORE_REG1_TRG) +#define BP_ANADIG_REG_CORE_REG0_ADJ 5 +#define BM_ANADIG_REG_CORE_REG0_ADJ 0x000001E0 +#define BF_ANADIG_REG_CORE_REG0_ADJ(v) \ + (((v) << 5) & BM_ANADIG_REG_CORE_REG0_ADJ) +#define BP_ANADIG_REG_CORE_REG0_TRG 0 +#define BM_ANADIG_REG_CORE_REG0_TRG 0x0000001F +#define BF_ANADIG_REG_CORE_REG0_TRG(v) \ + (((v) << 0) & BM_ANADIG_REG_CORE_REG0_TRG) + +#define HW_ANADIG_ANA_MISC0 (0x00000150) +#define HW_ANADIG_ANA_MISC0_SET (0x00000154) +#define HW_ANADIG_ANA_MISC0_CLR (0x00000158) +#define HW_ANADIG_ANA_MISC0_TOG (0x0000015c) + +#define BP_ANADIG_ANA_MISC0_RSVD2 29 +#define BM_ANADIG_ANA_MISC0_RSVD2 0xE0000000 +#define BF_ANADIG_ANA_MISC0_RSVD2(v) \ + (((v) << 29) & BM_ANADIG_ANA_MISC0_RSVD2) +#define BP_ANADIG_ANA_MISC0_CLKGATE_DELAY 26 +#define BM_ANADIG_ANA_MISC0_CLKGATE_DELAY 0x1C000000 +#define BF_ANADIG_ANA_MISC0_CLKGATE_DELAY(v) \ + (((v) << 26) & BM_ANADIG_ANA_MISC0_CLKGATE_DELAY) +#define BM_ANADIG_ANA_MISC0_CLKGATE_CTRL 0x02000000 +#define BP_ANADIG_ANA_MISC0_ANAMUX 21 +#define BM_ANADIG_ANA_MISC0_ANAMUX 0x01E00000 +#define BF_ANADIG_ANA_MISC0_ANAMUX(v) \ + (((v) << 21) & BM_ANADIG_ANA_MISC0_ANAMUX) +#define BM_ANADIG_ANA_MISC0_ANAMUX_EN 0x00100000 +#define BP_ANADIG_ANA_MISC0_WBCP_VPW_THRESH 18 +#define BM_ANADIG_ANA_MISC0_WBCP_VPW_THRESH 0x000C0000 +#define BF_ANADIG_ANA_MISC0_WBCP_VPW_THRESH(v) \ + (((v) << 18) & BM_ANADIG_ANA_MISC0_WBCP_VPW_THRESH) +#define BM_ANADIG_ANA_MISC0_OSC_XTALOK_EN 0x00020000 +#define BM_ANADIG_ANA_MISC0_OSC_XTALOK 0x00010000 +#define BP_ANADIG_ANA_MISC0_OSC_I 14 +#define BM_ANADIG_ANA_MISC0_OSC_I 0x0000C000 +#define BF_ANADIG_ANA_MISC0_OSC_I(v) \ + (((v) << 14) & BM_ANADIG_ANA_MISC0_OSC_I) +#define BM_ANADIG_ANA_MISC0_RTC_RINGOSC_EN 0x00002000 +#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG \ + (cpu_is_mx6sl() ? 0x00000800 : 0x00001000) +#define BP_ANADIG_ANA_MISC0_RSVD0 10 +#define BM_ANADIG_ANA_MISC0_RSVD0 0x00000C00 +#define BF_ANADIG_ANA_MISC0_RSVD0(v) \ + (((v) << 10) & BM_ANADIG_ANA_MISC0_RSVD0) +#define BP_ANADIG_ANA_MISC0_REFTOP_BIAS_TST 8 +#define BM_ANADIG_ANA_MISC0_REFTOP_BIAS_TST 0x00000300 +#define BF_ANADIG_ANA_MISC0_REFTOP_BIAS_TST(v) \ + (((v) << 8) & BM_ANADIG_ANA_MISC0_REFTOP_BIAS_TST) +#define BM_ANADIG_ANA_MISC0_REFTOP_VBGUP 0x00000080 +#define BP_ANADIG_ANA_MISC0_REFTOP_VBGADJ 4 +#define BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ 0x00000070 +#define BF_ANADIG_ANA_MISC0_REFTOP_VBGADJ(v) \ + (((v) << 4) & BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ) +#define BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF 0x00000008 +#define BM_ANADIG_ANA_MISC0_REFTOP_LOWPOWER 0x00000004 +#define BM_ANADIG_ANA_MISC0_REFTOP_PWDVBGUP 0x00000002 +#define BM_ANADIG_ANA_MISC0_REFTOP_PWD 0x00000001 + +#define HW_ANADIG_ANA_MISC1 (0x00000160) +#define HW_ANADIG_ANA_MISC1_SET (0x00000164) +#define HW_ANADIG_ANA_MISC1_CLR (0x00000168) +#define HW_ANADIG_ANA_MISC1_TOG (0x0000016c) + +#define BM_ANADIG_ANA_MISC1_IRQ_DIG_BO 0x80000000 +#define BM_ANADIG_ANA_MISC1_IRQ_ANA_BO 0x40000000 +#define BM_ANADIG_ANA_MISC1_IRQ_TEMPSENSE_BO 0x20000000 +#define BP_ANADIG_ANA_MISC1_RSVD0 14 +#define BM_ANADIG_ANA_MISC1_RSVD0 0x1FFFC000 +#define BF_ANADIG_ANA_MISC1_RSVD0(v) \ + (((v) << 14) & BM_ANADIG_ANA_MISC1_RSVD0) +#define BM_ANADIG_ANA_MISC1_LVDSCLK2_IBEN 0x00002000 +#define BM_ANADIG_ANA_MISC1_LVDSCLK1_IBEN 0x00001000 +#define BM_ANADIG_ANA_MISC1_LVDSCLK2_OBEN 0x00000800 +#define BM_ANADIG_ANA_MISC1_LVDSCLK1_OBEN 0x00000400 +#define BP_ANADIG_ANA_MISC1_LVDS2_CLK_SEL 5 +#define BM_ANADIG_ANA_MISC1_LVDS2_CLK_SEL 0x000003E0 +#define BF_ANADIG_ANA_MISC1_LVDS2_CLK_SEL(v) \ + (((v) << 5) & BM_ANADIG_ANA_MISC1_LVDS2_CLK_SEL) +#define BP_ANADIG_ANA_MISC1_LVDS1_CLK_SEL 0 +#define BM_ANADIG_ANA_MISC1_LVDS1_CLK_SEL 0x0000001F +#define BF_ANADIG_ANA_MISC1_LVDS1_CLK_SEL(v) \ + (((v) << 0) & BM_ANADIG_ANA_MISC1_LVDS1_CLK_SEL) + +#define HW_ANADIG_ANA_MISC2 (0x00000170) +#define HW_ANADIG_ANA_MISC2_SET (0x00000174) +#define HW_ANADIG_ANA_MISC2_CLR (0x00000178) +#define HW_ANADIG_ANA_MISC2_TOG (0x0000017c) + +#define BP_ANADIG_ANA_MISC2_CONTROL3 30 +#define BM_ANADIG_ANA_MISC2_CONTROL3 0xC0000000 +#define BF_ANADIG_ANA_MISC2_CONTROL3(v) \ + (((v) << 30) & BM_ANADIG_ANA_MISC2_CONTROL3) +#define BP_ANADIG_ANA_MISC2_REG2_STEP_TIME 28 +#define BM_ANADIG_ANA_MISC2_REG2_STEP_TIME 0x30000000 +#define BF_ANADIG_ANA_MISC2_REG2_STEP_TIME(v) \ + (((v) << 28) & BM_ANADIG_ANA_MISC2_REG2_STEP_TIME) +#define BP_ANADIG_ANA_MISC2_REG1_STEP_TIME 26 +#define BM_ANADIG_ANA_MISC2_REG1_STEP_TIME 0x0C000000 +#define BF_ANADIG_ANA_MISC2_REG1_STEP_TIME(v) \ + (((v) << 26) & BM_ANADIG_ANA_MISC2_REG1_STEP_TIME) +#define BP_ANADIG_ANA_MISC2_REG0_STEP_TIME 24 +#define BM_ANADIG_ANA_MISC2_REG0_STEP_TIME 0x03000000 +#define BF_ANADIG_ANA_MISC2_REG0_STEP_TIME(v) \ + (((v) << 24) & BM_ANADIG_ANA_MISC2_REG0_STEP_TIME) +#define BM_ANADIG_ANA_MISC2_CONTROL2 0x00800000 +#define BM_ANADIG_ANA_MISC2_REG2_OK 0x00400000 +#define BM_ANADIG_ANA_MISC2_REG2_ENABLE_BO 0x00200000 +#define BM_ANADIG_ANA_MISC2_RSVD2 0x00100000 +#define BM_ANADIG_ANA_MISC2_REG2_BO_STATUS 0x00080000 +#define BP_ANADIG_ANA_MISC2_REG2_BO_OFFSET 16 +#define BM_ANADIG_ANA_MISC2_REG2_BO_OFFSET 0x00070000 +#define BF_ANADIG_ANA_MISC2_REG2_BO_OFFSET(v) \ + (((v) << 16) & BM_ANADIG_ANA_MISC2_REG2_BO_OFFSET) +#define BM_ANADIG_ANA_MISC2_CONTROL1 0x00008000 +#define BM_ANADIG_ANA_MISC2_REG1_OK 0x00004000 +#define BM_ANADIG_ANA_MISC2_REG1_ENABLE_BO 0x00002000 +#define BM_ANADIG_ANA_MISC2_RSVD1 0x00001000 +#define BM_ANADIG_ANA_MISC2_REG1_BO_STATUS 0x00000800 +#define BP_ANADIG_ANA_MISC2_REG1_BO_OFFSET 8 +#define BM_ANADIG_ANA_MISC2_REG1_BO_OFFSET 0x00000700 +#define BF_ANADIG_ANA_MISC2_REG1_BO_OFFSET(v) \ + (((v) << 8) & BM_ANADIG_ANA_MISC2_REG1_BO_OFFSET) +#define BM_ANADIG_ANA_MISC2_CONTROL0 0x00000080 +#define BM_ANADIG_ANA_MISC2_REG0_OK 0x00000040 +#define BM_ANADIG_ANA_MISC2_REG0_ENABLE_BO 0x00000020 +#define BM_ANADIG_ANA_MISC2_RSVD0 0x00000010 +#define BM_ANADIG_ANA_MISC2_REG0_BO_STATUS 0x00000008 +#define BP_ANADIG_ANA_MISC2_REG0_BO_OFFSET 0 +#define BM_ANADIG_ANA_MISC2_REG0_BO_OFFSET 0x00000007 +#define BF_ANADIG_ANA_MISC2_REG0_BO_OFFSET(v) \ + (((v) << 0) & BM_ANADIG_ANA_MISC2_REG0_BO_OFFSET) + +#define HW_ANADIG_TEMPSENSE0 (0x00000180) +#define HW_ANADIG_TEMPSENSE0_SET (0x00000184) +#define HW_ANADIG_TEMPSENSE0_CLR (0x00000188) +#define HW_ANADIG_TEMPSENSE0_TOG (0x0000018c) + +#define BP_ANADIG_TEMPSENSE0_ALARM_VALUE 20 +#define BM_ANADIG_TEMPSENSE0_ALARM_VALUE 0xFFF00000 +#define BF_ANADIG_TEMPSENSE0_ALARM_VALUE(v) \ + (((v) << 20) & BM_ANADIG_TEMPSENSE0_ALARM_VALUE) +#define BP_ANADIG_TEMPSENSE0_TEMP_VALUE 8 +#define BM_ANADIG_TEMPSENSE0_TEMP_VALUE 0x000FFF00 +#define BF_ANADIG_TEMPSENSE0_TEMP_VALUE(v) \ + (((v) << 8) & BM_ANADIG_TEMPSENSE0_TEMP_VALUE) +#define BM_ANADIG_TEMPSENSE0_RSVD0 0x00000080 +#define BM_ANADIG_TEMPSENSE0_TEST 0x00000040 +#define BP_ANADIG_TEMPSENSE0_VBGADJ 3 +#define BM_ANADIG_TEMPSENSE0_VBGADJ 0x00000038 +#define BF_ANADIG_TEMPSENSE0_VBGADJ(v) \ + (((v) << 3) & BM_ANADIG_TEMPSENSE0_VBGADJ) +#define BM_ANADIG_TEMPSENSE0_FINISHED 0x00000004 +#define BM_ANADIG_TEMPSENSE0_MEASURE_TEMP 0x00000002 +#define BM_ANADIG_TEMPSENSE0_POWER_DOWN 0x00000001 + +#define HW_ANADIG_TEMPSENSE1 (0x00000190) +#define HW_ANADIG_TEMPSENSE1_SET (0x00000194) +#define HW_ANADIG_TEMPSENSE1_CLR (0x00000198) +#define HW_ANADIG_TEMPSENSE1_TOG (0x0000019c) + +#define BP_ANADIG_TEMPSENSE1_RSVD0 16 +#define BM_ANADIG_TEMPSENSE1_RSVD0 0xFFFF0000 +#define BF_ANADIG_TEMPSENSE1_RSVD0(v) \ + (((v) << 16) & BM_ANADIG_TEMPSENSE1_RSVD0) +#define BP_ANADIG_TEMPSENSE1_MEASURE_FREQ 0 +#define BM_ANADIG_TEMPSENSE1_MEASURE_FREQ 0x0000FFFF +#define BF_ANADIG_TEMPSENSE1_MEASURE_FREQ(v) \ + (((v) << 0) & BM_ANADIG_TEMPSENSE1_MEASURE_FREQ) + +#define HW_ANADIG_USB1_VBUS_DETECT (0x000001a0) +#define HW_ANADIG_USB1_VBUS_DETECT_SET (0x000001a4) +#define HW_ANADIG_USB1_VBUS_DETECT_CLR (0x000001a8) +#define HW_ANADIG_USB1_VBUS_DETECT_TOG (0x000001ac) + +#define BM_ANADIG_USB1_VBUS_DETECT_EN_CHARGER_RESISTOR 0x80000000 +#define BP_ANADIG_USB1_VBUS_DETECT_RSVD2 28 +#define BM_ANADIG_USB1_VBUS_DETECT_RSVD2 0x70000000 +#define BF_ANADIG_USB1_VBUS_DETECT_RSVD2(v) \ + (((v) << 28) & BM_ANADIG_USB1_VBUS_DETECT_RSVD2) +#define BM_ANADIG_USB1_VBUS_DETECT_CHARGE_VBUS 0x08000000 +#define BM_ANADIG_USB1_VBUS_DETECT_DISCHARGE_VBUS 0x04000000 +#define BP_ANADIG_USB1_VBUS_DETECT_RSVD1 21 +#define BM_ANADIG_USB1_VBUS_DETECT_RSVD1 0x03E00000 +#define BF_ANADIG_USB1_VBUS_DETECT_RSVD1(v) \ + (((v) << 21) & BM_ANADIG_USB1_VBUS_DETECT_RSVD1) +#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_PWRUP_CMPS 0x00100000 +#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_5VDETECT 0x00080000 +#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_TO_B 0x00040000 +#define BP_ANADIG_USB1_VBUS_DETECT_RSVD0 8 +#define BM_ANADIG_USB1_VBUS_DETECT_RSVD0 0x0003FF00 +#define BF_ANADIG_USB1_VBUS_DETECT_RSVD0(v) \ + (((v) << 8) & BM_ANADIG_USB1_VBUS_DETECT_RSVD0) +#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_OVERRIDE 0x00000080 +#define BM_ANADIG_USB1_VBUS_DETECT_AVALID_OVERRIDE 0x00000040 +#define BM_ANADIG_USB1_VBUS_DETECT_BVALID_OVERRIDE 0x00000020 +#define BM_ANADIG_USB1_VBUS_DETECT_SESSEND_OVERRIDE 0x00000010 +#define BM_ANADIG_USB1_VBUS_DETECT_VBUS_OVERRIDE_EN 0x00000008 +#define BP_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH 0 +#define BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH 0x00000007 +#define BF_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH(v) \ + (((v) << 0) & BM_ANADIG_USB1_VBUS_DETECT_VBUSVALID_THRESH) + +#define HW_ANADIG_USB1_CHRG_DETECT (0x000001b0) +#define HW_ANADIG_USB1_CHRG_DETECT_SET (0x000001b4) +#define HW_ANADIG_USB1_CHRG_DETECT_CLR (0x000001b8) +#define HW_ANADIG_USB1_CHRG_DETECT_TOG (0x000001bc) + +#define BP_ANADIG_USB1_CHRG_DETECT_RSVD2 24 +#define BM_ANADIG_USB1_CHRG_DETECT_RSVD2 0xFF000000 +#define BF_ANADIG_USB1_CHRG_DETECT_RSVD2(v) \ + (((v) << 24) & BM_ANADIG_USB1_CHRG_DETECT_RSVD2) +#define BM_ANADIG_USB1_CHRG_DETECT_BGR_BIAS 0x00800000 +#define BP_ANADIG_USB1_CHRG_DETECT_RSVD1 21 +#define BM_ANADIG_USB1_CHRG_DETECT_RSVD1 0x00600000 +#define BF_ANADIG_USB1_CHRG_DETECT_RSVD1(v) \ + (((v) << 21) & BM_ANADIG_USB1_CHRG_DETECT_RSVD1) +#define BM_ANADIG_USB1_CHRG_DETECT_EN_B 0x00100000 +#define BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B 0x00080000 +#define BM_ANADIG_USB1_CHRG_DETECT_CHK_CONTACT 0x00040000 +#define BP_ANADIG_USB1_CHRG_DETECT_RSVD0 1 +#define BM_ANADIG_USB1_CHRG_DETECT_RSVD0 0x0003FFFE +#define BF_ANADIG_USB1_CHRG_DETECT_RSVD0(v) \ + (((v) << 1) & BM_ANADIG_USB1_CHRG_DETECT_RSVD0) +#define BM_ANADIG_USB1_CHRG_DETECT_FORCE_DETECT 0x00000001 + +#define HW_ANADIG_USB1_VBUS_DET_STAT (0x000001c0) +#define HW_ANADIG_USB1_VBUS_DET_STAT_SET (0x000001c4) +#define HW_ANADIG_USB1_VBUS_DET_STAT_CLR (0x000001c8) +#define HW_ANADIG_USB1_VBUS_DET_STAT_TOG (0x000001cc) + +#define BP_ANADIG_USB1_VBUS_DET_STAT_RSVD0 4 +#define BM_ANADIG_USB1_VBUS_DET_STAT_RSVD0 0xFFFFFFF0 +#define BF_ANADIG_USB1_VBUS_DET_STAT_RSVD0(v) \ + (((v) << 4) & BM_ANADIG_USB1_VBUS_DET_STAT_RSVD0) +#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID 0x00000008 +#define BM_ANADIG_USB1_VBUS_DET_STAT_AVALID 0x00000004 +#define BM_ANADIG_USB1_VBUS_DET_STAT_BVALID 0x00000002 +#define BM_ANADIG_USB1_VBUS_DET_STAT_SESSEND 0x00000001 + +#define HW_ANADIG_USB1_CHRG_DET_STAT (0x000001d0) +#define HW_ANADIG_USB1_CHRG_DET_STAT_SET (0x000001d4) +#define HW_ANADIG_USB1_CHRG_DET_STAT_CLR (0x000001d8) +#define HW_ANADIG_USB1_CHRG_DET_STAT_TOG (0x000001dc) + +#define BP_ANADIG_USB1_CHRG_DET_STAT_RSVD0 4 +#define BM_ANADIG_USB1_CHRG_DET_STAT_RSVD0 0xFFFFFFF0 +#define BF_ANADIG_USB1_CHRG_DET_STAT_RSVD0(v) \ + (((v) << 4) & BM_ANADIG_USB1_CHRG_DET_STAT_RSVD0) +#define BM_ANADIG_USB1_CHRG_DET_STAT_DP_STATE 0x00000008 +#define BM_ANADIG_USB1_CHRG_DET_STAT_DM_STATE 0x00000004 +#define BM_ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED 0x00000002 +#define BM_ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT 0x00000001 + +#define HW_ANADIG_USB1_LOOPBACK (0x000001e0) +#define HW_ANADIG_USB1_LOOPBACK_SET (0x000001e4) +#define HW_ANADIG_USB1_LOOPBACK_CLR (0x000001e8) +#define HW_ANADIG_USB1_LOOPBACK_TOG (0x000001ec) + +#define BP_ANADIG_USB1_LOOPBACK_RSVD0 9 +#define BM_ANADIG_USB1_LOOPBACK_RSVD0 0xFFFFFE00 +#define BF_ANADIG_USB1_LOOPBACK_RSVD0(v) \ + (((v) << 9) & BM_ANADIG_USB1_LOOPBACK_RSVD0) +#define BM_ANADIG_USB1_LOOPBACK_UTMO_DIG_TST1 0x00000100 +#define BM_ANADIG_USB1_LOOPBACK_UTMO_DIG_TST0 0x00000080 +#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_HIZ 0x00000040 +#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN 0x00000020 +#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_LS_MODE 0x00000010 +#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_HS_MODE 0x00000008 +#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 0x00000004 +#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST0 0x00000002 +#define BM_ANADIG_USB1_LOOPBACK_UTMI_TESTSTART 0x00000001 + +#define HW_ANADIG_USB1_MISC (0x000001f0) +#define HW_ANADIG_USB1_MISC_SET (0x000001f4) +#define HW_ANADIG_USB1_MISC_CLR (0x000001f8) +#define HW_ANADIG_USB1_MISC_TOG (0x000001fc) + +#define BM_ANADIG_USB1_MISC_RSVD1 0x80000000 +#define BM_ANADIG_USB1_MISC_EN_CLK_UTMI 0x40000000 +#define BM_ANADIG_USB1_MISC_RX_VPIN_FS 0x20000000 +#define BM_ANADIG_USB1_MISC_RX_VMIN_FS 0x10000000 +#define BM_ANADIG_USB1_MISC_RX_RXD_FS 0x08000000 +#define BM_ANADIG_USB1_MISC_RX_SQUELCH 0x04000000 +#define BM_ANADIG_USB1_MISC_RX_DISCON_DET 0x02000000 +#define BM_ANADIG_USB1_MISC_RX_HS_DATA 0x01000000 +#define BP_ANADIG_USB1_MISC_RSVD0 2 +#define BM_ANADIG_USB1_MISC_RSVD0 0x00FFFFFC +#define BF_ANADIG_USB1_MISC_RSVD0(v) \ + (((v) << 2) & BM_ANADIG_USB1_MISC_RSVD0) +#define BM_ANADIG_USB1_MISC_EN_DEGLITCH 0x00000002 +#define BM_ANADIG_USB1_MISC_HS_USE_EXTERNAL_R 0x00000001 + +#define HW_ANADIG_USB2_VBUS_DETECT (0x00000200) +#define HW_ANADIG_USB2_VBUS_DETECT_SET (0x00000204) +#define HW_ANADIG_USB2_VBUS_DETECT_CLR (0x00000208) +#define HW_ANADIG_USB2_VBUS_DETECT_TOG (0x0000020c) + +#define BM_ANADIG_USB2_VBUS_DETECT_EN_CHARGER_RESISTOR 0x80000000 +#define BP_ANADIG_USB2_VBUS_DETECT_RSVD2 28 +#define BM_ANADIG_USB2_VBUS_DETECT_RSVD2 0x70000000 +#define BF_ANADIG_USB2_VBUS_DETECT_RSVD2(v) \ + (((v) << 28) & BM_ANADIG_USB2_VBUS_DETECT_RSVD2) +#define BM_ANADIG_USB2_VBUS_DETECT_CHARGE_VBUS 0x08000000 +#define BM_ANADIG_USB2_VBUS_DETECT_DISCHARGE_VBUS 0x04000000 +#define BP_ANADIG_USB2_VBUS_DETECT_RSVD1 21 +#define BM_ANADIG_USB2_VBUS_DETECT_RSVD1 0x03E00000 +#define BF_ANADIG_USB2_VBUS_DETECT_RSVD1(v) \ + (((v) << 21) & BM_ANADIG_USB2_VBUS_DETECT_RSVD1) +#define BM_ANADIG_USB2_VBUS_DETECT_VBUSVALID_PWRUP_CMPS 0x00100000 +#define BM_ANADIG_USB2_VBUS_DETECT_VBUSVALID_5VDETECT 0x00080000 +#define BM_ANADIG_USB2_VBUS_DETECT_VBUSVALID_TO_B 0x00040000 +#define BP_ANADIG_USB2_VBUS_DETECT_RSVD0 3 +#define BM_ANADIG_USB2_VBUS_DETECT_RSVD0 0x0003FFF8 +#define BF_ANADIG_USB2_VBUS_DETECT_RSVD0(v) \ + (((v) << 3) & BM_ANADIG_USB2_VBUS_DETECT_RSVD0) +#define BP_ANADIG_USB2_VBUS_DETECT_VBUSVALID_THRESH 0 +#define BM_ANADIG_USB2_VBUS_DETECT_VBUSVALID_THRESH 0x00000007 +#define BF_ANADIG_USB2_VBUS_DETECT_VBUSVALID_THRESH(v) \ + (((v) << 0) & BM_ANADIG_USB2_VBUS_DETECT_VBUSVALID_THRESH) + +#define HW_ANADIG_USB2_CHRG_DETECT (0x00000210) +#define HW_ANADIG_USB2_CHRG_DETECT_SET (0x00000214) +#define HW_ANADIG_USB2_CHRG_DETECT_CLR (0x00000218) +#define HW_ANADIG_USB2_CHRG_DETECT_TOG (0x0000021c) + +#define BP_ANADIG_USB2_CHRG_DETECT_RSVD2 24 +#define BM_ANADIG_USB2_CHRG_DETECT_RSVD2 0xFF000000 +#define BF_ANADIG_USB2_CHRG_DETECT_RSVD2(v) \ + (((v) << 24) & BM_ANADIG_USB2_CHRG_DETECT_RSVD2) +#define BM_ANADIG_USB2_CHRG_DETECT_BGR_BIAS 0x00800000 +#define BP_ANADIG_USB2_CHRG_DETECT_RSVD1 21 +#define BM_ANADIG_USB2_CHRG_DETECT_RSVD1 0x00600000 +#define BF_ANADIG_USB2_CHRG_DETECT_RSVD1(v) \ + (((v) << 21) & BM_ANADIG_USB2_CHRG_DETECT_RSVD1) +#define BM_ANADIG_USB2_CHRG_DETECT_EN_B 0x00100000 +#define BM_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B 0x00080000 +#define BM_ANADIG_USB2_CHRG_DETECT_CHK_CONTACT 0x00040000 +#define BP_ANADIG_USB2_CHRG_DETECT_RSVD0 1 +#define BM_ANADIG_USB2_CHRG_DETECT_RSVD0 0x0003FFFE +#define BF_ANADIG_USB2_CHRG_DETECT_RSVD0(v) \ + (((v) << 1) & BM_ANADIG_USB2_CHRG_DETECT_RSVD0) +#define BM_ANADIG_USB2_CHRG_DETECT_FORCE_DETECT 0x00000001 + +#define HW_ANADIG_USB2_VBUS_DET_STAT (0x00000220) +#define HW_ANADIG_USB2_VBUS_DET_STAT_SET (0x00000224) +#define HW_ANADIG_USB2_VBUS_DET_STAT_CLR (0x00000228) +#define HW_ANADIG_USB2_VBUS_DET_STAT_TOG (0x0000022c) + +#define BP_ANADIG_USB2_VBUS_DET_STAT_RSVD0 4 +#define BM_ANADIG_USB2_VBUS_DET_STAT_RSVD0 0xFFFFFFF0 +#define BF_ANADIG_USB2_VBUS_DET_STAT_RSVD0(v) \ + (((v) << 4) & BM_ANADIG_USB2_VBUS_DET_STAT_RSVD0) +#define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID 0x00000008 +#define BM_ANADIG_USB2_VBUS_DET_STAT_AVALID 0x00000004 +#define BM_ANADIG_USB2_VBUS_DET_STAT_BVALID 0x00000002 +#define BM_ANADIG_USB2_VBUS_DET_STAT_SESSEND 0x00000001 + +#define HW_ANADIG_USB2_CHRG_DET_STAT (0x00000230) +#define HW_ANADIG_USB2_CHRG_DET_STAT_SET (0x00000234) +#define HW_ANADIG_USB2_CHRG_DET_STAT_CLR (0x00000238) +#define HW_ANADIG_USB2_CHRG_DET_STAT_TOG (0x0000023c) + +#define BP_ANADIG_USB2_CHRG_DET_STAT_RSVD0 4 +#define BM_ANADIG_USB2_CHRG_DET_STAT_RSVD0 0xFFFFFFF0 +#define BF_ANADIG_USB2_CHRG_DET_STAT_RSVD0(v) \ + (((v) << 4) & BM_ANADIG_USB2_CHRG_DET_STAT_RSVD0) +#define BM_ANADIG_USB2_CHRG_DET_STAT_DP_STATE 0x00000008 +#define BM_ANADIG_USB2_CHRG_DET_STAT_DM_STATE 0x00000004 +#define BM_ANADIG_USB2_CHRG_DET_STAT_CHRG_DETECTED 0x00000002 +#define BM_ANADIG_USB2_CHRG_DET_STAT_PLUG_CONTACT 0x00000001 + +#define HW_ANADIG_USB2_LOOPBACK (0x00000240) +#define HW_ANADIG_USB2_LOOPBACK_SET (0x00000244) +#define HW_ANADIG_USB2_LOOPBACK_CLR (0x00000248) +#define HW_ANADIG_USB2_LOOPBACK_TOG (0x0000024c) + +#define BP_ANADIG_USB2_LOOPBACK_RSVD0 9 +#define BM_ANADIG_USB2_LOOPBACK_RSVD0 0xFFFFFE00 +#define BF_ANADIG_USB2_LOOPBACK_RSVD0(v) \ + (((v) << 9) & BM_ANADIG_USB2_LOOPBACK_RSVD0) +#define BM_ANADIG_USB2_LOOPBACK_UTMO_DIG_TST1 0x00000100 +#define BM_ANADIG_USB2_LOOPBACK_UTMO_DIG_TST0 0x00000080 +#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_HIZ 0x00000040 +#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN 0x00000020 +#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_LS_MODE 0x00000010 +#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_HS_MODE 0x00000008 +#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 0x00000004 +#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST0 0x00000002 +#define BM_ANADIG_USB2_LOOPBACK_UTMI_TESTSTART 0x00000001 + +#define HW_ANADIG_USB2_MISC (0x00000250) +#define HW_ANADIG_USB2_MISC_SET (0x00000254) +#define HW_ANADIG_USB2_MISC_CLR (0x00000258) +#define HW_ANADIG_USB2_MISC_TOG (0x0000025c) + +#define BM_ANADIG_USB2_MISC_RSVD1 0x80000000 +#define BM_ANADIG_USB2_MISC_EN_CLK_UTMI 0x40000000 +#define BM_ANADIG_USB2_MISC_RX_VPIN_FS 0x20000000 +#define BM_ANADIG_USB2_MISC_RX_VMIN_FS 0x10000000 +#define BM_ANADIG_USB2_MISC_RX_RXD_FS 0x08000000 +#define BM_ANADIG_USB2_MISC_RX_SQUELCH 0x04000000 +#define BM_ANADIG_USB2_MISC_RX_DISCON_DET 0x02000000 +#define BM_ANADIG_USB2_MISC_RX_HS_DATA 0x01000000 +#define BP_ANADIG_USB2_MISC_RSVD0 2 +#define BM_ANADIG_USB2_MISC_RSVD0 0x00FFFFFC +#define BF_ANADIG_USB2_MISC_RSVD0(v) \ + (((v) << 2) & BM_ANADIG_USB2_MISC_RSVD0) +#define BM_ANADIG_USB2_MISC_EN_DEGLITCH 0x00000002 +#define BM_ANADIG_USB2_MISC_HS_USE_EXTERNAL_R 0x00000001 + +#define HW_ANADIG_DIGPROG (0x00000260) + +#define BP_ANADIG_DIGPROG_RSVD 24 +#define BM_ANADIG_DIGPROG_RSVD 0xFF000000 +#define BF_ANADIG_DIGPROG_RSVD(v) \ + (((v) << 24) & BM_ANADIG_DIGPROG_RSVD) +#define BP_ANADIG_DIGPROG_MAJOR 8 +#define BM_ANADIG_DIGPROG_MAJOR 0x00FFFF00 +#define BF_ANADIG_DIGPROG_MAJOR(v) \ + (((v) << 8) & BM_ANADIG_DIGPROG_MAJOR) +#define BP_ANADIG_DIGPROG_MINOR 0 +#define BM_ANADIG_DIGPROG_MINOR 0x000000FF +#define BF_ANADIG_DIGPROG_MINOR(v) \ + (((v) << 0) & BM_ANADIG_DIGPROG_MINOR) +#endif /* __ARCH_ARM___ANADIG_H */ diff --git a/arch/arm/mach-mx6/serial.h b/arch/arm/mach-mx6/serial.h new file mode 100644 index 00000000..c510b59b --- /dev/null +++ b/arch/arm/mach-mx6/serial.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#ifndef __ARCH_ARM_MACH_MX51_SERIAL_H__ +#define __ARCH_ARM_MACH_MX51_SERIAL_H__ + +/* UART 1 configuration */ +/*! + * This specifies the threshold at which the CTS pin is deasserted by the + * RXFIFO. Set this value in Decimal to anything from 0 to 32 for + * hardware-driven hardware flow control. Read the HW spec while specifying + * this value. When using interrupt-driven software controlled hardware + * flow control set this option to -1. + */ +#define UART1_UCR4_CTSTL 16 +/*! + * Specify the size of the DMA receive buffer. The minimum buffer size is 512 + * bytes. The buffer size should be a multiple of 256. + */ +#define UART1_DMA_RXBUFSIZE 1024 +/*! + * Specify the MXC UART's Receive Trigger Level. This controls the threshold at + * which a maskable interrupt is generated by the RxFIFO. Set this value in + * Decimal to anything from 0 to 32. Read the HW spec while specifying this + * value. + */ +#define UART1_UFCR_RXTL 16 +/*! + * Specify the MXC UART's Transmit Trigger Level. This controls the threshold at + * which a maskable interrupt is generated by the TxFIFO. Set this value in + * Decimal to anything from 0 to 32. Read the HW spec while specifying this + * value. + */ +#define UART1_UFCR_TXTL 16 +#define UART1_DMA_ENABLE 0 +/* UART 2 configuration */ +#define UART2_UCR4_CTSTL -1 +#define UART2_DMA_ENABLE 1 +#define UART2_DMA_RXBUFSIZE 512 +#define UART2_UFCR_RXTL 16 +#define UART2_UFCR_TXTL 16 +/* UART 3 configuration */ +#define UART3_UCR4_CTSTL 16 +#define UART3_DMA_ENABLE 0 +#define UART3_DMA_RXBUFSIZE 1024 +#define UART3_UFCR_RXTL 16 +#define UART3_UFCR_TXTL 16 +/* UART 4 configuration */ +#define UART4_UCR4_CTSTL -1 +#define UART4_DMA_ENABLE 0 +#define UART4_DMA_RXBUFSIZE 512 +#define UART4_UFCR_RXTL 16 +#define UART4_UFCR_TXTL 16 +/* UART 5 configuration */ +#define UART5_UCR4_CTSTL -1 +#define UART5_DMA_ENABLE 0 +#define UART5_DMA_RXBUFSIZE 512 +#define UART5_UFCR_RXTL 16 +#define UART5_UFCR_TXTL 16 + +#endif /* __ARCH_ARM_MACH_MX51_SERIAL_H__ */ diff --git a/arch/arm/mach-mx6/src-reg.h b/arch/arm/mach-mx6/src-reg.h new file mode 100644 index 00000000..dc13e431 --- /dev/null +++ b/arch/arm/mach-mx6/src-reg.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +/* + * This file is created by xml file. Don't Edit it. + * + * Xml Revision: 1.30 + * Template revision: 1.3 + */ +#ifndef _SRC_REGISTER_HEADER_ +#define _SRC_REGISTER_HEADER_ + +#define SRC_SCR_OFFSET 0x000 +#define SRC_SBMR_OFFSET 0x004 +#define SRC_SRSR_OFFSET 0x008 +#define SRC_SAIAR_OFFSET 0x00c +#define SRC_SAIRAR_OFFSET 0x010 +#define SRC_SISR_OFFSET 0x014 +#define SRC_SIMR_OFFSET 0x018 +#define SRC_SBMR2_OFFSET 0x01c +#define SRC_GPR1_OFFSET 0x020 +#define SRC_GPR2_OFFSET 0x024 +#define SRC_GPR3_OFFSET 0x028 +#define SRC_GPR4_OFFSET 0x02c +#define SRC_GPR5_OFFSET 0x030 +#define SRC_GPR6_OFFSET 0x034 +#define SRC_GPR7_OFFSET 0x038 +#define SRC_GPR8_OFFSET 0x03c +#define SRC_GPR9_OFFSET 0x040 +#define SRC_GPR10_OFFSET 0x044 + +#define BP_SRC_SCR_CORE0_RST 13 +#define BP_SRC_SCR_CORES_DBG_RST 21 +#define BP_SRC_SCR_CORE1_ENABLE 22 + +#endif diff --git a/arch/arm/mach-mx6/system.c b/arch/arm/mach-mx6/system.c new file mode 100644 index 00000000..a195094b --- /dev/null +++ b/arch/arm/mach-mx6/system.c @@ -0,0 +1,682 @@ +/* + * Copyright (C) 2011-2013 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/clk.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/pmic_external.h> +#include <linux/clockchips.h> +#include <linux/hrtimer.h> +#include <linux/tick.h> +#include <asm/io.h> +#include <mach/hardware.h> +#include <mach/clock.h> +#include <asm/proc-fns.h> +#include <asm/system.h> +#include <asm/hardware/gic.h> +#include "crm_regs.h" +#include "regs-anadig.h" + +#include "ntx_hwconfig.h" + + +#define SCU_CTRL 0x00 +#define SCU_CONFIG 0x04 +#define SCU_CPU_STATUS 0x08 +#define SCU_INVALIDATE 0x0c +#define SCU_FPGA_REVISION 0x10 +#define GPC_CNTR_OFFSET 0x0 +#define GPC_PGC_GPU_PGCR_OFFSET 0x260 +#define GPC_PGC_CPU_PDN_OFFSET 0x2a0 +#define GPC_PGC_CPU_PUPSCR_OFFSET 0x2a4 +#define GPC_PGC_CPU_PDNSCR_OFFSET 0x2a8 + +#define MODULE_CLKGATE (1 << 30) +#define MODULE_SFTRST (1 << 31) + +extern unsigned int gpc_wake_irq[4]; + +static void __iomem *gpc_base = IO_ADDRESS(GPC_BASE_ADDR); +extern struct clk *mmdc_ch0_axi; + +volatile unsigned int num_cpu_idle; +volatile unsigned int num_cpu_idle_lock = 0x0; +int wait_mode_arm_podf; +int cur_arm_podf; +bool enet_is_active; +void arch_idle_with_workaround(int cpu); + +extern void *mx6sl_wfi_iram_base; +extern void (*mx6sl_wfi_iram)(int arm_podf, unsigned long wfi_iram_addr, \ + int audio_mode); +extern void mx6_wait(void *num_cpu_idle_lock, void *num_cpu_idle, \ + int wait_arm_podf, int cur_arm_podf); +extern unsigned long save_ttbr1(void); +extern void restore_ttbr1(u32 ttbr1); + +extern bool enable_wait_mode; +extern int low_bus_freq_mode; +extern int audio_bus_freq_mode; +extern bool mem_clk_on_in_wait; +extern int chip_rev; + +extern volatile NTX_HWCONFIG *gptHWCFG; + +void gpc_set_wakeup(unsigned int irq[4]) +{ + /* Mask all wake up source */ + __raw_writel(~irq[0], gpc_base + 0x8); + __raw_writel(~irq[1], gpc_base + 0xc); + __raw_writel(~irq[2], gpc_base + 0x10); + __raw_writel(~irq[3], gpc_base + 0x14); + + return; +} + +void gpc_mask_single_irq(int irq, bool enable) +{ + void __iomem *reg; + u32 val; + + reg = gpc_base + 0x8 + (irq / 32 - 1) * 4; + val = __raw_readl(reg); + if (enable) + val |= 1 << (irq % 32); + else + val &= ~(1 << (irq % 32)); + __raw_writel(val, reg); + + return; +} + +/* set cpu low power mode before WFI instruction */ +void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode) +{ + + int stop_mode = 0; + void __iomem *anatop_base = IO_ADDRESS(ANATOP_BASE_ADDR); + u32 ccm_clpcr, anatop_val; + + ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK); + /* + * CCM state machine has restriction that, everytime enable + * LPM mode, we need to make sure last wakeup from LPM mode + * is a dsm_wakeup_signal, which means the wakeup source + * must be seen by GPC, then CCM will clean its state machine + * and re-sample necessary signal to decide whether it can + * enter LPM mode. Here we force irq #32 to be always pending, + * unmask it before we enable LPM mode and mask it after LPM + * is enabled, this flow will make sure CCM state machine in + * reliable state before we enter LPM mode. + */ + gpc_mask_single_irq(MXC_INT_GPR, false); + + 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: + case ARM_POWER_OFF: + if (mode == WAIT_UNCLOCKED_POWER_OFF) { + ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET; + if (cpu_is_mx6sl()) { + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS; + ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY; + } else + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS; + stop_mode = 0; + } else if (mode == STOP_POWER_OFF) { + 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; + if (cpu_is_mx6sl()) { + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS; + ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY; + } else + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS; + stop_mode = 1; + } 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; + if (cpu_is_mx6sl()) { + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS; + ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY; + } else + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS; + stop_mode = 2; + } + break; + case STOP_XTAL_ON: + ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET; + ccm_clpcr |= MXC_CCM_CLPCR_VSTBY; + ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS; + if (cpu_is_mx6sl()) { + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS; + ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY; + } else + ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS; + stop_mode = 3; + + break; + default: + printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode); + gpc_mask_single_irq(MXC_INT_GPR, true); + return; + } + + if (stop_mode > 0) { + gpc_set_wakeup(gpc_wake_irq); + /* Power down and power up sequence */ + /* The PUPSCR counter counts in terms of CLKIL (32KHz) cycles. + * The PUPSCR should include the time it takes for the ARM LDO to + * ramp up. + */ + __raw_writel(0xf0f, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET); + /* The PDNSCR is a counter that counts in IPG_CLK cycles. This counter + * can be set to minimum values to power down faster. + */ + __raw_writel(0x101, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET); + if (stop_mode >= 2) { + /* dormant mode, need to power off the arm core */ + __raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET); +#if 0 + if (cpu_is_mx6q() || cpu_is_mx6dl() && (4!=gptHWCFG->m_val.bRamType) ) +#else + if( cpu_is_mx6q() || cpu_is_mx6dl() ) +#endif + { + /* If stop_mode_config is clear, then 2P5 will be off, + need to enable weak 2P5, as DDR IO need 2P5 as + pre-driver */ + if ((__raw_readl(anatop_base + HW_ANADIG_ANA_MISC0) + & BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) { + /* Enable weak 2P5 linear regulator */ + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_REG_2P5); + anatop_val |= BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG; + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_REG_2P5); + } + if (mx6q_revision() != IMX_CHIP_REVISION_1_0) { + /* Enable fet_odrive */ + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_REG_CORE); + anatop_val |= BM_ANADIG_REG_CORE_FET_ODRIVE; + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_REG_CORE); + } + } else { + if (stop_mode == 2) { +#if 1 + /* Disable VDDHIGH_IN to VDDSNVS_IN + * power path, only used when VDDSNVS_IN + * is powered by dedicated + * power rail */ + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_ANA_MISC0); + anatop_val |= BM_ANADIG_ANA_MISC0_RTC_RINGOSC_EN; + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_ANA_MISC0); +#endif + /* Need to enable pull down if 2P5 is disabled */ + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_REG_2P5); + +#if 1 //[ + if ( /* <= E60Q2XA14 */ + (33==gptHWCFG->m_val.bPCB && gptHWCFG->m_val.bPCB_REV<=0x14 ) || + /* <= E60Q30BXX */ + (36==gptHWCFG->m_val.bPCB && gptHWCFG->m_val.bPCB_LVL==1 ) || + /* <= E60QBXA00 */ + (37==gptHWCFG->m_val.bPCB && gptHWCFG->m_val.bPCB_REV<=0 ) ) + { + //printk("%s<=E60Q2XA14|<=E60Q3XA00\n",__FUNCTION__); + /* Enable weak 2P5 linear regulator */ + anatop_val |= BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG| + BM_ANADIG_REG_2P5_ENABLE_ILIMIT; + } + else + { + anatop_val |= (BM_ANADIG_REG_2P5_ENABLE_ILIMIT| + BM_ANADIG_REG_2P5_ENABLE_PULLDOWN); + } +#endif //] + + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_REG_2P5); + + anatop_val = __raw_readl(anatop_base + + HW_ANADIG_REG_1P1); + anatop_val |= BM_ANADIG_REG_1P1_ENABLE_ILIMIT; + __raw_writel(anatop_val, anatop_base + + HW_ANADIG_REG_1P1); + } + } + if (stop_mode != 3) { + /* Make sure we clear WB_COUNT + * and re-config it. + */ + __raw_writel(__raw_readl(MXC_CCM_CCR) & + (~MXC_CCM_CCR_WB_COUNT_MASK), + MXC_CCM_CCR); + /* Reconfigure WB, need to set WB counter + * to 0x7 to make sure it work normally */ + __raw_writel(__raw_readl(MXC_CCM_CCR) | + (0x7 << MXC_CCM_CCR_WB_COUNT_OFFSET), + MXC_CCM_CCR); + + /* Set WB_PER enable */ + ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM; + } + } + if (cpu_is_mx6sl() || + (mx6q_revision() > IMX_CHIP_REVISION_1_1) || + (mx6dl_revision() > IMX_CHIP_REVISION_1_0)) { + u32 reg; + /* We need to allow the memories to be clock gated + * in STOP mode, else the power consumption will + * be very high. + */ + reg = __raw_readl(MXC_CCM_CGPR); + reg |= MXC_CCM_CGPR_MEM_IPG_STOP_MASK; + if (!cpu_is_mx6sl() && stop_mode >= 2) { + /* + * For MX6QTO1.2 or later and MX6DLTO1.1 or later, + * ensure that the CCM_CGPR bit 17 is cleared before + * dormant mode is entered. + */ + reg &= ~MXC_CCM_CGPR_WAIT_MODE_FIX; + } + __raw_writel(reg, MXC_CCM_CGPR); + } + } + __raw_writel(ccm_clpcr, MXC_CCM_CLPCR); + gpc_mask_single_irq(MXC_INT_GPR, true); +} + +extern int tick_broadcast_oneshot_active(void); + +void ca9_do_idle(void) +{ + do { + cpu_do_idle(); + } while (__raw_readl(gic_cpu_base_addr + GIC_CPU_HIGHPRI) == 1023); +} + +void arch_idle_single_core(void) +{ + u32 reg; + + if (cpu_is_mx6dl() && chip_rev > IMX_CHIP_REVISION_1_0) { + /* + * MX6DLS TO1.1 has the HW fix for the WAIT mode issue. + * Ensure that the CGPR bit 17 is set to enable the fix. + */ + reg = __raw_readl(MXC_CCM_CGPR); + reg |= MXC_CCM_CGPR_WAIT_MODE_FIX; + __raw_writel(reg, MXC_CCM_CGPR); + + ca9_do_idle(); + } else { + if (low_bus_freq_mode || audio_bus_freq_mode) { + int ddr_usecount = 0; + if ((mmdc_ch0_axi != NULL)) + ddr_usecount = clk_get_usecount(mmdc_ch0_axi); + + if (cpu_is_mx6sl() && (ddr_usecount == 1) && + (low_bus_freq_mode || audio_bus_freq_mode)) { + /* In this mode PLL2 i already in bypass, + * ARM is sourced from PLL1. The code in IRAM + * will set ARM to be sourced from STEP_CLK + * at 24MHz. It will also set DDR to 1MHz to + * reduce power. + */ + u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR); + u32 ttbr1; + + outer_sync(); + /* Need to run WFI code from IRAM so that + * we can lower DDR freq. + */ + ttbr1 = save_ttbr1(); + mx6sl_wfi_iram(org_arm_podf, + (unsigned long)mx6sl_wfi_iram_base, + audio_bus_freq_mode); + restore_ttbr1(ttbr1); + } else { + /* Need to set ARM to run at 24MHz since IPG + * is at 12MHz. This is valid for audio mode on + * MX6SL, and all low power modes on MX6DLS. + */ + if (cpu_is_mx6sl() && low_bus_freq_mode) { + /* ARM is from PLL1, need to switch to + * STEP_CLK sourced from 24MHz. + */ + /* Swtich STEP_CLK to 24MHz. */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_STEP_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + /* Set PLL1_SW_CLK to be from + *STEP_CLK. + */ + reg = __raw_readl(MXC_CCM_CCSR); + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + + } else { + /* PLL1_SW_CLK is sourced from + * PLL2_PFD2_400MHz at this point. + * Move it to bypassed PLL1. + */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } + ca9_do_idle(); + + if (cpu_is_mx6sl() && low_bus_freq_mode) { + /* Set PLL1_SW_CLK to be from PLL1 */ + reg = __raw_readl(MXC_CCM_CCSR); + reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } else { + reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL; + __raw_writel(reg, MXC_CCM_CCSR); + } + } + } else { + /* + * Implement the 12:5 ARM:IPG_CLK ratio + * workaround for the WAIT mode issue. + * We can directly use the divider to drop the ARM + * core freq in a single core environment. + * Set the ARM_PODF to get the max freq possible + * to avoid the WAIT mode issue when IPG is at 66MHz. + */ + __raw_writel(wait_mode_arm_podf, MXC_CCM_CACRR); + while (__raw_readl(MXC_CCM_CDHIPR)) + ; + ca9_do_idle(); + + __raw_writel(cur_arm_podf - 1, MXC_CCM_CACRR); + } + } +} + +void arch_idle_with_workaround(int cpu) +{ + u32 podf = wait_mode_arm_podf; + + *((char *)(&num_cpu_idle_lock) + (char)cpu) = 0x0; + + if (low_bus_freq_mode || audio_bus_freq_mode) + /* In case when IPG is at 12MHz, we need to ensure that + * ARM is at 24MHz, as the max freq ARM can run at is + *~28.8MHz. + */ + podf = 0; + + mx6_wait((void *)&num_cpu_idle_lock, + (void *)&num_cpu_idle, + podf, cur_arm_podf - 1); + +} + +void arch_idle_multi_core(int cpu) +{ + u32 reg; + + /* iMX6Q and iMX6DL */ + if ((cpu_is_mx6q() && chip_rev >= IMX_CHIP_REVISION_1_2) || + (cpu_is_mx6dl() && chip_rev >= IMX_CHIP_REVISION_1_1)) { + /* + * This code should only be executed on MX6QTO1.2 or later + * and MX6DL TO1.1 or later. + * These chips have the HW fix for the WAIT mode issue. + * Ensure that the CGPR bit 17 is set to enable the fix. + */ + + reg = __raw_readl(MXC_CCM_CGPR); + reg |= MXC_CCM_CGPR_WAIT_MODE_FIX; + __raw_writel(reg, MXC_CCM_CGPR); + + ca9_do_idle(); + } else + arch_idle_with_workaround(cpu); +} + +void arch_idle(void) +{ + int cpu = smp_processor_id(); + + if (enable_wait_mode) { +#ifdef CONFIG_LOCAL_TIMERS + if (!tick_broadcast_oneshot_active() + || !tick_oneshot_mode_active()) + return; + + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu); +#endif + if (enet_is_active) + /* Don't allow the chip to enter WAIT mode if enet is active + * and the GPIO workaround for ENET interrupts is not used, + * since all ENET interrupts donot wake up the SOC. + */ + mxc_cpu_lp_set(WAIT_CLOCKED); + else + mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF); + if (mem_clk_on_in_wait) { + u32 reg; + /* + * MX6SL, MX6Q (TO1.2 or later) and + * MX6DL (TO1.1 or later) have a bit in + * CCM_CGPR that when cleared keeps the + * clocks to memories ON when ARM is in WFI. + * This mode can be used when IPG clock is + * very low (12MHz) and the ARM:IPG ratio + * perhaps cannot be maintained. + */ + reg = __raw_readl(MXC_CCM_CGPR); + reg &= ~MXC_CCM_CGPR_MEM_IPG_STOP_MASK; + __raw_writel(reg, MXC_CCM_CGPR); + + ca9_do_idle(); + } else if (num_possible_cpus() == 1) + /* iMX6SL or iMX6DLS */ + arch_idle_single_core(); + else + arch_idle_multi_core(cpu); +#ifdef CONFIG_LOCAL_TIMERS + clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); +#endif + } else { + mxc_cpu_lp_set(WAIT_CLOCKED); + ca9_do_idle(); + } +} + +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 &= ~MODULE_SFTRST; /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & MODULE_SFTRST) == 0) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when enabling\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~MODULE_CLKGATE; /* clear CLKGATE */ + __raw_writel(c, hwreg); + + if (!just_enable) { + c = __raw_readl(hwreg); + c |= MODULE_SFTRST; /* now again set SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* poll until CLKGATE set */ + if (__raw_readl(hwreg) & MODULE_CLKGATE) + break; + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when resetting\n", + __func__, hwreg); + return -ETIME; + } + + c = __raw_readl(hwreg); + c &= ~MODULE_SFTRST; /* clear SFTRST */ + __raw_writel(c, hwreg); + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & MODULE_SFTRST) == 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 &= ~MODULE_CLKGATE; /* clear CLKGATE */ + __raw_writel(c, hwreg); + } + for (timeout = 1000000; timeout > 0; timeout--) + /* still in SFTRST state ? */ + if ((__raw_readl(hwreg) & MODULE_CLKGATE) == 0) + break; + + if (timeout <= 0) { + printk(KERN_ERR "%s(%p): timeout when unclockgating\n", + __func__, hwreg); + return -ETIME; + } + + return 0; +} + +static 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; +} + + +#define BOOT_MODE_SERIAL_ROM (0x00000030) +#define PERSIST_WATCHDOG_RESET_BOOT (0x10000000) +/*BOOT_CFG1[7..4] = 0x3 Boot from Serial ROM (I2C/SPI)*/ + +#ifdef CONFIG_MXC_REBOOT_MFGMODE +void do_switch_mfgmode(void) +{ + u32 reg; + + /* + * During reset, if GPR10[28] is 1, ROM will copy GPR9[25:0] + * to SBMR1, which will determine what is the boot device. + * Here SERIAL_ROM mode is selected + */ + reg = __raw_readl(SRC_BASE_ADDR + SRC_GPR9); + reg |= BOOT_MODE_SERIAL_ROM; + __raw_writel(reg, SRC_BASE_ADDR + SRC_GPR9); + + reg = __raw_readl(SRC_BASE_ADDR + SRC_GPR10); + reg |= PERSIST_WATCHDOG_RESET_BOOT; + __raw_writel(reg, SRC_BASE_ADDR + SRC_GPR10); + +} + +void mxc_clear_mfgmode(void) +{ + u32 reg; + reg = __raw_readl(SRC_BASE_ADDR + SRC_GPR9); + + reg &= ~BOOT_MODE_SERIAL_ROM; + __raw_writel(reg, SRC_BASE_ADDR + SRC_GPR9); + + reg = __raw_readl(SRC_BASE_ADDR + SRC_GPR10); + reg &= ~PERSIST_WATCHDOG_RESET_BOOT; + __raw_writel(reg, SRC_BASE_ADDR + SRC_GPR10); +} +#endif + +#ifdef CONFIG_MXC_REBOOT_ANDROID_CMD +/* This function will set a bit on SNVS_LPGPR[7-8] bits to enter + * special boot mode. These bits will not clear by watchdog reset, so + * it can be checked by bootloader to choose enter different mode.*/ + +#define ANDROID_RECOVERY_BOOT (1 << 7) +#define ANDROID_FASTBOOT_BOOT (1 << 8) + +void do_switch_recovery(void) +{ + u32 reg; + + reg = __raw_readl(MX6Q_SNVS_BASE_ADDR + SNVS_LPGPR); + reg |= ANDROID_RECOVERY_BOOT; + __raw_writel(reg, MX6Q_SNVS_BASE_ADDR + SNVS_LPGPR); +} + +void do_switch_fastboot(void) +{ + u32 reg; + + reg = __raw_readl(MX6Q_SNVS_BASE_ADDR + SNVS_LPGPR); + reg |= ANDROID_FASTBOOT_BOOT; + __raw_writel(reg, MX6Q_SNVS_BASE_ADDR + SNVS_LPGPR); +} +#endif + +int mxs_reset_block(void __iomem *hwreg) +{ + return _mxs_reset_block(hwreg, false); +} +EXPORT_SYMBOL(mxs_reset_block); diff --git a/arch/arm/mach-mx6/usb.h b/arch/arm/mach-mx6/usb.h new file mode 100644 index 00000000..819e45e5 --- /dev/null +++ b/arch/arm/mach-mx6/usb.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011-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/common.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 bool usb_icbug_swfix_need(void); +extern void __init mx6_usb_h2_init(void); +extern void __init mx6_usb_h3_init(void); + +typedef void (*driver_vbus_func)(bool); +extern void mx6_set_host3_vbus_func(driver_vbus_func); +extern void mx6_set_host2_vbus_func(driver_vbus_func); +extern void mx6_set_host1_vbus_func(driver_vbus_func); +extern void mx6_set_otghost_vbus_func(driver_vbus_func); +extern void mx6_get_otghost_vbus_func(driver_vbus_func *driver_vbus); +extern void mx6_get_host1_vbus_func(driver_vbus_func *driver_vbus); +extern struct platform_device anatop_thermal_device; +extern struct platform_device mxc_usbdr_otg_device; +extern struct platform_device mxc_usbdr_udc_device; +extern struct platform_device mxc_usbdr_host_device; +extern struct platform_device mxc_usbdr_wakeup_device; +extern struct platform_device mxc_usbh1_device; +extern struct platform_device mxc_usbh1_wakeup_device; + +/* + * 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; +#define imx_fsl_usb2_wakeup_data_entry_single(soc, _id, hs) \ + { \ + .id = _id, \ + .irq_phy = soc ## _INT_USB_PHY ## _id, \ + .irq_core = soc ## _INT_USB_ ## hs, \ + } +#define imx_mxc_ehci_data_entry_single(soc, _id, hs) \ + { \ + .id = _id, \ + .iobase = soc ## _USB_ ## hs ## _BASE_ADDR, \ + .irq = soc ## _INT_USB_ ## hs, \ + } +#define imx_fsl_usb2_otg_data_entry_single(soc) \ + { \ + .iobase = soc ## _USB_OTG_BASE_ADDR, \ + .irq = soc ## _INT_USB_OTG, \ + } +#define imx_fsl_usb2_udc_data_entry_single(soc) \ + { \ + .iobase = soc ## _USB_OTG_BASE_ADDR, \ + .irq = soc ## _INT_USB_OTG, \ + } + diff --git a/arch/arm/mach-mx6/usb_dr.c b/arch/arm/mach-mx6/usb_dr.c new file mode 100644 index 00000000..cba9c541 --- /dev/null +++ b/arch/arm/mach-mx6/usb_dr.c @@ -0,0 +1,795 @@ +/* + * 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/kernel.h> +#include <linux/types.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/fsl_devices.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <mach/arc_otg.h> +#include <mach/hardware.h> +#include "devices-imx6q.h" +#include "regs-anadig.h" +#include "usb.h" + +DEFINE_MUTEX(otg_wakeup_enable_mutex); +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 void _dr_discharge_line(bool enable); +extern bool usb_icbug_swfix_need(void); +static void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, \ + bool enable); +static u32 wakeup_irq_enable_src; /* only useful at otg mode */ +static u32 low_power_enable_src; /* only useful at otg mode */ + +/* The usb_phy1_clk do not have enable/disable function at clock.c + * and PLL output for usb1's phy should be always enabled. + * usb_phy1_clk only stands for usb uses pll3 as its parent. + */ +static struct clk *usb_phy1_clk; +static struct clk *usb_oh3_clk; +static u8 otg_used; + +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", + .phy_regs = USB_PHY0_BASE_ADDR, + .dr_discharge_line = _dr_discharge_line, + .lowpower = true, /* Default driver low power is true */ +}; + +/* 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, +}; + +static void usbotg_internal_phy_clock_gate(bool on) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + if (on) { + __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_CLR); + } else { + __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_SET); + } +} + +static int usb_phy_enable(struct fsl_usb2_platform_data *pdata) +{ + u32 tmp; + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + void __iomem *phy_ctrl; + + /* Stop then Reset */ + UOG_USBCMD &= ~UCMD_RUN_STOP; + while (UOG_USBCMD & UCMD_RUN_STOP) + ; + + UOG_USBCMD |= UCMD_RESET; + while ((UOG_USBCMD) & (UCMD_RESET)) + ; + + /* + * If the controller reset does not put the PHY be out of + * low power mode, do it manually. + */ + if (UOG_PORTSC1 & PORTSC_PHCD) { + UOG_PORTSC1 &= ~PORTSC_PHCD; + mdelay(1); + } + + /* Reset USBPHY module */ + phy_ctrl = phy_reg + HW_USBPHY_CTRL; + tmp = __raw_readl(phy_ctrl); + tmp |= BM_USBPHY_CTRL_SFTRST; + __raw_writel(tmp, phy_ctrl); + udelay(10); + + /* Remove CLKGATE and SFTRST */ + tmp = __raw_readl(phy_ctrl); + tmp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST); + __raw_writel(tmp, phy_ctrl); + udelay(10); + + /* Power up the PHY */ + __raw_writel(0, phy_reg + HW_USBPHY_PWD); + if ((pdata->operating_mode == FSL_USB2_DR_HOST) || + (pdata->operating_mode == FSL_USB2_DR_OTG)) { + /* enable FS/LS device */ + __raw_writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3 + , phy_reg + HW_USBPHY_CTRL_SET); + } + + if (!usb_icbug_swfix_need()) + __raw_writel((1 << 17), phy_reg + HW_USBPHY_IP_SET); + if (cpu_is_mx6sl()) + __raw_writel((1 << 18), phy_reg + HW_USBPHY_IP_SET); + return 0; +} +/* Notes: configure USB clock*/ +static int usbotg_init_ext(struct platform_device *pdev) +{ + struct clk *usb_clk; + u32 ret; + + /* at mx6q: this clock is AHB clock for usb core */ + 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; + + ret = usbotg_init(pdev); + if (ret) { + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + clk_disable(usb_phy1_clk); + clk_put(usb_phy1_clk); + printk(KERN_ERR "otg init fails......\n"); + return ret; + } + if (!otg_used) { + wakeup_irq_enable_src = 0; + low_power_enable_src = 0; + usb_phy_enable(pdev->dev.platform_data); + enter_phy_lowpower_suspend(pdev->dev.platform_data, false); + /*after the phy reset,can not read the readingvalue for id/vbus at + * the register of otgsc ,cannot read at once ,need delay 3 ms + */ + mdelay(3); + } + otg_used++; + +#if 0 + printk("%s(%d):usb_oh3_clk:%d, usb_phy_clk1_ref_count:%d\n", + __FUNCTION__,__LINE__,clk_get_usecount(usb_oh3_clk), + clk_get_usecount(usb_phy1_clk)); +#endif + + return ret; +} + +static void usbotg_uninit_ext(struct platform_device *pdev) +{ + otg_used--; + if (!otg_used) { + //clk_disable(usb_phy1_clk); + clk_put(usb_phy1_clk); + clk_put(usb_oh3_clk); + } +#if 0 + printk("%s(%d):otg_used=%d,usb_oh3_clk:%d, usb_phy_clk1_ref_count:%d\n", + __FUNCTION__,__LINE__,otg_used,clk_get_usecount(usb_oh3_clk), + clk_get_usecount(usb_phy1_clk)); +#endif +} + +static void usbotg_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_oh3_clk); + clk_enable(usb_phy1_clk); + } else { + clk_disable(usb_phy1_clk); + clk_disable(usb_oh3_clk); + } + //printk("usb_oh3_clk:%d, usb_phy_clk1_ref_count:%d\n", clk_get_usecount(usb_oh3_clk), clk_get_usecount(usb_phy1_clk)); +} + +static void dr_platform_phy_power_on(void) +{ + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, + anatop_base_addr + HW_ANADIG_ANA_MISC0_SET); +} + +static void _dr_discharge_line(bool enable) +{ + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + + pr_debug("DR: %s enable is %d\n", __func__, enable); + if (enable) { + __raw_writel(BM_USBPHY_DEBUG_CLKGATE, phy_reg + HW_USBPHY_DEBUG_CLR); + __raw_writel(BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 + |BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN, + anatop_base_addr + HW_ANADIG_USB1_LOOPBACK); + } else { + __raw_writel(0x0, + anatop_base_addr + HW_ANADIG_USB1_LOOPBACK); + __raw_writel(BM_USBPHY_DEBUG_CLKGATE, phy_reg + HW_USBPHY_DEBUG_SET); + } +} + +/* 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 void enter_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + u32 tmp; + pr_debug("DR: %s begins, enable is %d\n", __func__, enable); + + if (enable) { + UOG_PORTSC1 |= PORTSC_PHCD; + tmp = (BM_USBPHY_PWD_TXPWDFS + | BM_USBPHY_PWD_TXPWDIBIAS + | BM_USBPHY_PWD_TXPWDV2I + | BM_USBPHY_PWD_RXPWDENV + | BM_USBPHY_PWD_RXPWD1PT1 + | BM_USBPHY_PWD_RXPWDDIFF + | BM_USBPHY_PWD_RXPWDRX); + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET); + usbotg_internal_phy_clock_gate(false); + + } else { + if (UOG_PORTSC1 & PORTSC_PHCD) + UOG_PORTSC1 &= ~PORTSC_PHCD; + + /* Wait PHY clock stable */ + mdelay(1); + + usbotg_internal_phy_clock_gate(true); + + udelay(2); + + tmp = (BM_USBPHY_PWD_TXPWDFS + | BM_USBPHY_PWD_TXPWDIBIAS + | BM_USBPHY_PWD_TXPWDV2I + | BM_USBPHY_PWD_RXPWDENV + | BM_USBPHY_PWD_RXPWD1PT1 + | BM_USBPHY_PWD_RXPWDDIFF + | BM_USBPHY_PWD_RXPWDRX); + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR); + /* + * The PHY works at 32Khz clock when it is at low power mode, + * it needs 10 clocks from 32Khz to normal work state, so + * 500us is the safe value for PHY enters stable status + * according to IC engineer. + * + * Besides, the digital value needs 1ms debounce time to + * wait the value to be stable. We have expected the + * value from OTGSC is correct after calling this API. + * + * So delay 2ms is a save value. + */ + mdelay(2); + + } + pr_debug("DR: %s ends, enable is %d\n", __func__, enable); +} + +static void __phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, 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"); + enter_phy_lowpower_suspend(pdata, enable); + } +#else + enter_phy_lowpower_suspend(pdata, enable); +#endif + } else { + pr_debug("phy lowpower disable\n"); + enter_phy_lowpower_suspend(pdata, enable); + low_power_enable_src &= ~source; + } +} + +static void otg_wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + + pr_debug("%s, enable is %d\n", __func__, enable); + if (enable) { + __raw_writel(BM_USBPHY_CTRL_ENDPDMCHG_WKUP + | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS + | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD + | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE + | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE + | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_SET); + USB_OTG_CTRL |= UCTRL_OWIE; + } else { + __raw_writel(BM_USBPHY_CTRL_ENDPDMCHG_WKUP + | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS + | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD + | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE + | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE + | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_CLR); + USB_OTG_CTRL &= ~UCTRL_OWIE; + /* 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 __wakeup_irq_enable(struct fsl_usb2_platform_data *pdata, 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)) { + otg_wake_up_enable(pdata, on); + } +#else + otg_wake_up_enable(pdata, on); +#endif + } else { + otg_wake_up_enable(pdata, on); + 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); + } +} + +/* 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) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + int wakeup_req = USB_OTG_CTRL & UCTRL_OWIR; + + printk(KERN_INFO "\n %s: wakeup_req=%d, USB_OTG_CTRL=%08x, UOG_OTGSC=%08x, UOG_USBSTS=%08x, UOG_PORTSC1=%08x, USBPHY_CTRL=%08x\n", + __func__, wakeup_req?1:0, USB_OTG_CTRL, UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, __raw_readl(phy_reg + HW_USBPHY_CTRL)); + + 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) + */ + __raw_writel(BM_USBPHY_CTRL_ENDPDMCHG_WKUP, phy_reg + HW_USBPHY_CTRL_CLR); + UOG_OTGSC |= 0x007f0000; + + USB_OTG_CTRL &= ~UCTRL_OWIE; + udelay(100); + __raw_writel(BM_USBPHY_CTRL_ENDPDMCHG_WKUP, phy_reg + HW_USBPHY_CTRL_SET); + USB_OTG_CTRL |= UCTRL_OWIE; + } + else { + /* spurious USB wakeup but WIR does not set, let's software use the + * bit UCTRL_WKUP_SW as an indication of software OWIR + */ + USB_OTG_CTRL &= ~UCTRL_OWIE; + udelay(100); + USB_OTG_CTRL |= UCTRL_OWIE; + USB_OTG_CTRL |= UCTRL_WKUP_SW; + } +} + +/* End of Common operation for DR port */ + +#ifdef CONFIG_USB_EHCI_ARC_OTG +/* Beginning of host related operation for DR port */ +static void fsl_platform_otg_set_usb_phy_dis( + struct fsl_usb2_platform_data *pdata, bool enable) +{ + u32 usb_phy_ctrl_dcdt = 0; + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + usb_phy_ctrl_dcdt = __raw_readl( + MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL) & + BM_USBPHY_CTRL_ENHOSTDISCONDETECT; + if (enable) { + if (usb_phy_ctrl_dcdt == 0) { + __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_CLR); + + __raw_writel(BM_USBPHY_PWD_RXPWDENV, + MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_SET); + + udelay(300); + + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_SET); + + UOG_USBSTS |= (1 << 7); + + while ((UOG_USBSTS & (1 << 7)) == 0) + ; + + udelay(2); + + __raw_writel(BM_USBPHY_PWD_RXPWDENV, + MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_CLR); + + __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET); + + } + } else { + if (usb_phy_ctrl_dcdt + == BM_USBPHY_CTRL_ENHOSTDISCONDETECT) + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_CLR); + } +} + +static void _host_platform_rh_suspend_swfix(struct fsl_usb2_platform_data *pdata) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + u32 tmp; + u32 index = 0; + + /* before we set and then clear PWD bit, + * we must wait LS to be suspend */ + if ((UOG_PORTSC1 & (3 << 26)) != (1 << 26)) { + while (((UOG_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_J_STATE) && + (index < 1000)) { + index++; + udelay(4); + } + } else { + while (((UOG_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_K_STATE) && + (index < 1000)) { + index++; + udelay(4); + } + } + + if (index >= 1000) + printk(KERN_INFO "%s big error\n", __func__); + + tmp = (BM_USBPHY_PWD_TXPWDFS + | BM_USBPHY_PWD_TXPWDIBIAS + | BM_USBPHY_PWD_TXPWDV2I + | BM_USBPHY_PWD_RXPWDENV + | BM_USBPHY_PWD_RXPWD1PT1 + | BM_USBPHY_PWD_RXPWDDIFF + | BM_USBPHY_PWD_RXPWDRX); + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET); + + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR); + + fsl_platform_otg_set_usb_phy_dis(pdata, 0); +} + +static void _host_platform_rh_resume_swfix(struct fsl_usb2_platform_data *pdata) +{ + u32 index = 0; + + if ((UOG_PORTSC1 & (PORTSC_PORT_SPEED_MASK)) != PORTSC_PORT_SPEED_HIGH) + return ; + while ((UOG_PORTSC1 & PORTSC_PORT_FORCE_RESUME) + && (index < 1000)) { + udelay(500); + index++; + } + if (index >= 1000) + printk(KERN_ERR "failed to wait for the resume finished in %s() line:%d\n", + __func__, __LINE__); + /* We should add some delay to wait for the device switch to + * High-Speed 45ohm termination resistors mode. */ + udelay(500); + fsl_platform_otg_set_usb_phy_dis(pdata, 1); +} +static void _host_platform_rh_suspend(struct fsl_usb2_platform_data *pdata) +{ + /*for mx6sl ,we do not need any sw fix*/ + if (cpu_is_mx6sl()) + return ; + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_CLR); +} + +static void _host_platform_rh_resume(struct fsl_usb2_platform_data *pdata) +{ + u32 index = 0; + + /*for mx6sl ,we do not need any sw fix*/ + if (cpu_is_mx6sl()) + return ; + if ((UOG_PORTSC1 & (PORTSC_PORT_SPEED_MASK)) != PORTSC_PORT_SPEED_HIGH) + return ; + while ((UOG_PORTSC1 & PORTSC_PORT_FORCE_RESUME) + && (index < 1000)) { + udelay(500); + index++; + } + if (index >= 1000) + printk(KERN_ERR "failed to wait for the resume finished in %s() line:%d\n", + __func__, __LINE__); + /* We should add some delay to wait for the device switch to + * High-Speed 45ohm termination resistors mode. */ + udelay(500); + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_SET); +} + +static void _host_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __phy_lowpower_suspend(pdata, enable, ENABLED_BY_HOST); +} + +static void _host_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + void __iomem *phy_reg __maybe_unused = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + mutex_lock(&otg_wakeup_enable_mutex); + __wakeup_irq_enable(pdata, enable, ENABLED_BY_HOST); +#ifdef CONFIG_USB_OTG + if (enable) { + pr_debug("host wakeup enable\n"); + USB_OTG_CTRL |= UCTRL_WKUP_ID_EN; + __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP, phy_reg + HW_USBPHY_CTRL_SET); + } else { + pr_debug("host wakeup disable\n"); + __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP, phy_reg + HW_USBPHY_CTRL_CLR); + USB_OTG_CTRL &= ~UCTRL_WKUP_ID_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); + } + pr_debug("the otgsc is 0x%x, usbsts is 0x%x, portsc is 0x%x, otgctrl: 0x%x\n", UOG_OTGSC, UOG_USBSTS, UOG_PORTSC1, USB_OTG_CTRL); +#endif + mutex_unlock(&otg_wakeup_enable_mutex); +} + +static enum usb_wakeup_event _is_host_wakeup(struct fsl_usb2_platform_data *pdata) +{ + u32 wakeup_req = USB_OTG_CTRL & UCTRL_OWIR; + u32 otgsc = UOG_OTGSC; + + if (wakeup_req) { + 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); + } + else { + // no hardware OWIR, let check if there is software OWIR + if (USB_OTG_CTRL & UCTRL_WKUP_SW) { + wakeup_req = UCTRL_WKUP_SW; + } + } + /* if ID change sts, it is a host wakeup event */ + if (otgsc & OTGSC_IS_USB_ID) { + pr_debug("otg host ID wakeup\n"); + USB_OTG_CTRL &= (~UCTRL_WKUP_SW); + return WAKEUP_EVENT_ID; + } + if (wakeup_req && (!(otgsc & OTGSC_STS_USB_ID))) { + pr_debug("otg host Remote wakeup\n"); + USB_OTG_CTRL &= (~UCTRL_WKUP_SW); + return WAKEUP_EVENT_DPDM; + } + return WAKEUP_EVENT_INVALID; +} + +static void host_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _host_phy_lowpower_suspend(pdata, false); + _host_wakeup_enable(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_phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + __phy_lowpower_suspend(pdata, enable, ENABLED_BY_DEVICE); +} + +static void _device_wakeup_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY0_BASE_ADDR); + mutex_lock(&otg_wakeup_enable_mutex); + __wakeup_irq_enable(pdata, enable, ENABLED_BY_DEVICE); + /* if udc is not used by any gadget, we can not enable the vbus wakeup */ + if (!pdata->port_enables) { + USB_OTG_CTRL &= ~UCTRL_WKUP_VBUS_EN; + mutex_unlock(&otg_wakeup_enable_mutex); + return; + } + if (enable) { + pr_debug("device wakeup enable\n"); + USB_OTG_CTRL |= UCTRL_WKUP_VBUS_EN; + __raw_writel(BM_USBPHY_CTRL_ENVBUSCHG_WKUP, phy_reg + HW_USBPHY_CTRL_SET); + } else { + pr_debug("device wakeup disable\n"); + __raw_writel(BM_USBPHY_CTRL_ENVBUSCHG_WKUP, phy_reg + HW_USBPHY_CTRL_CLR); + USB_OTG_CTRL &= ~UCTRL_WKUP_VBUS_EN; + } + mutex_unlock(&otg_wakeup_enable_mutex); +} + +static enum usb_wakeup_event _is_device_wakeup(struct fsl_usb2_platform_data *pdata) +{ + int wakeup_req = (USB_OTG_CTRL & UCTRL_OWIR); + pr_debug("%s\n", __func__); + + if (!wakeup_req) { + // no hardware OWIR, let check if there is software OWIR + if (USB_OTG_CTRL & UCTRL_WKUP_SW) { + wakeup_req = UCTRL_WKUP_SW; + } + } + + /* 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"); + USB_OTG_CTRL &= (~UCTRL_WKUP_SW); + 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"); + USB_OTG_CTRL &= (~UCTRL_WKUP_SW); + 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"); + USB_OTG_CTRL &= (~UCTRL_WKUP_SW); + 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"); + USB_OTG_CTRL &= (~UCTRL_WKUP_SW); + return WAKEUP_EVENT_VBUS; + } + + return WAKEUP_EVENT_INVALID; +} + +static void device_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _device_phy_lowpower_suspend(pdata, false); + _device_wakeup_enable(pdata, false); +} + +/* end of device related operation for DR port */ +#endif /* CONFIG_USB_GADGET_ARC */ + +static struct platform_device *pdev[3], *pdev_wakeup; +static driver_vbus_func mx6_set_usb_otg_vbus; +static int devnum; +static int __init mx6_usb_dr_init(void) +{ + int i = 0; + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + struct imx_fsl_usb2_wakeup_data __maybe_unused imx6q_fsl_otg_wakeup_data = + imx_fsl_usb2_wakeup_data_entry_single(MX6Q, 0, OTG); + struct imx_mxc_ehci_data __maybe_unused imx6q_mxc_ehci_otg_data = + imx_mxc_ehci_data_entry_single(MX6Q, 0, OTG); + struct imx_fsl_usb2_udc_data __maybe_unused imx6q_fsl_usb2_udc_data = + imx_fsl_usb2_udc_data_entry_single(MX6Q); + struct imx_fsl_usb2_otg_data __maybe_unused imx6q_fsl_usb2_otg_data = + imx_fsl_usb2_otg_data_entry_single(MX6Q); + + /* Some phy and power's special controls for otg + * 1. The external charger detector needs to be disabled + * or the signal at DP will be poor + * 2. The EN_USB_CLKS is always enabled. + * The PLL's power is controlled by usb and others who + * use pll3 too. + */ + __raw_writel(BM_ANADIG_USB1_CHRG_DETECT_EN_B \ + | BM_ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B, \ + anatop_base_addr + HW_ANADIG_USB1_CHRG_DETECT); + __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET); + mx6_get_otghost_vbus_func(&mx6_set_usb_otg_vbus); + dr_utmi_config.platform_driver_vbus = mx6_set_usb_otg_vbus; +#ifdef CONFIG_USB_OTG + /* wake_up_enable 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; + pdev[i] = imx6q_add_fsl_usb2_otg(&dr_utmi_config); + dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data; + i++; +#endif +#ifdef CONFIG_USB_GADGET_ARC + dr_utmi_config.operating_mode = DR_UDC_MODE; + dr_utmi_config.wake_up_enable = _device_wakeup_enable; + dr_utmi_config.platform_rh_suspend = NULL; + dr_utmi_config.platform_rh_resume = NULL; + dr_utmi_config.platform_set_disconnect_det = NULL; + 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; + dr_utmi_config.charger_base_addr = anatop_base_addr; + dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on; + pdev[i] = imx6q_add_fsl_usb2_udc(&dr_utmi_config); + dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data; + i++; +#endif +#ifdef CONFIG_USB_EHCI_ARC_OTG + dr_utmi_config.operating_mode = DR_HOST_MODE; + dr_utmi_config.wake_up_enable = _host_wakeup_enable; + if (usb_icbug_swfix_need()) { + dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend_swfix; + dr_utmi_config.platform_rh_resume = _host_platform_rh_resume_swfix; + } else { + dr_utmi_config.platform_rh_suspend = _host_platform_rh_suspend; + dr_utmi_config.platform_rh_resume = _host_platform_rh_resume; + } + dr_utmi_config.platform_set_disconnect_det = fsl_platform_otg_set_usb_phy_dis; + 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; + dr_utmi_config.platform_phy_power_on = dr_platform_phy_power_on; + pdev[i] = imx6q_add_fsl_ehci_otg(&dr_utmi_config); + dr_wakeup_config.usb_pdata[i] = pdev[i]->dev.platform_data; + i++; +#endif + devnum = i; + /* register wakeup device */ + pdev_wakeup = imx6q_add_fsl_usb2_otg_wakeup(&dr_wakeup_config); + for (i = 0; i < devnum; i++) { + platform_device_add(pdev[i]); + ((struct fsl_usb2_platform_data *)(pdev[i]->dev.platform_data))->wakeup_pdata = + (struct fsl_usb2_wakeup_platform_data *)(pdev_wakeup->dev.platform_data); + } + return 0; +} +module_init(mx6_usb_dr_init); + +static void __exit mx6_usb_dr_exit(void) +{ + int i; + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + + for (i = 0; i < devnum; i++) + platform_device_del(pdev[devnum-i-1]); + platform_device_unregister(pdev_wakeup); + otg_used = 0; + __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_CLR); + return ; +} +module_exit(mx6_usb_dr_exit); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_LICENSE("GPL"); + diff --git a/arch/arm/mach-mx6/usb_h1.c b/arch/arm/mach-mx6/usb_h1.c new file mode 100644 index 00000000..cfbced8f --- /dev/null +++ b/arch/arm/mach-mx6/usb_h1.c @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2011-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/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 <linux/io.h> +#include <linux/delay.h> +#include <mach/arc_otg.h> +#include <mach/hardware.h> +#include "devices-imx6q.h" +#include "regs-anadig.h" +#include "usb.h" + +static struct clk *usb_oh3_clk; +extern int clk_get_usecount(struct clk *clk); +static struct fsl_usb2_platform_data usbh1_config; + +static void fsl_platform_h1_set_usb_phy_dis( + struct fsl_usb2_platform_data *pdata, bool enable) +{ + u32 usb_phy_ctrl_dcdt = 0; + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + usb_phy_ctrl_dcdt = __raw_readl( + MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_CTRL) & + BM_USBPHY_CTRL_ENHOSTDISCONDETECT; + if (enable) { + if (usb_phy_ctrl_dcdt == 0) { + __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_CLR); + + __raw_writel(BM_USBPHY_PWD_RXPWDENV, + MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_SET); + + udelay(300); + + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_SET); + + UH1_USBSTS |= (1 << 7); + + while ((UH1_USBSTS & (1 << 7)) == 0) + ; + + udelay(2); + + __raw_writel(BM_USBPHY_PWD_RXPWDENV, + MX6_IO_ADDRESS(pdata->phy_regs) + HW_USBPHY_PWD_CLR); + + __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_SET); + + } + } else { + if (usb_phy_ctrl_dcdt + == BM_USBPHY_CTRL_ENHOSTDISCONDETECT) + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_CLR); + } +} + +static void usbh1_internal_phy_clock_gate(bool on) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR); + if (on) { + __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_CLR); + } else { + __raw_writel(BM_USBPHY_CTRL_CLKGATE, phy_reg + HW_USBPHY_CTRL_SET); + } +} + +static void usbh1_platform_phy_power_on(void) +{ + void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + __raw_writel(BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG, + anatop_base_addr + HW_ANADIG_ANA_MISC0_SET); +} + +static int usb_phy_enable(struct fsl_usb2_platform_data *pdata) +{ + u32 tmp; + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR); + void __iomem *phy_ctrl; + + /* Stop then Reset */ + UH1_USBCMD &= ~UCMD_RUN_STOP; + while (UH1_USBCMD & UCMD_RUN_STOP) + ; + + UH1_USBCMD |= UCMD_RESET; + while ((UH1_USBCMD) & (UCMD_RESET)) + ; + /* + * If the controller reset does not put the PHY be out of + * low power mode, do it manually. + */ + if (UH1_PORTSC1 & PORTSC_PHCD) { + UH1_PORTSC1 &= ~PORTSC_PHCD; + mdelay(1); + } + + /* Reset USBPHY module */ + phy_ctrl = phy_reg + HW_USBPHY_CTRL; + tmp = __raw_readl(phy_ctrl); + tmp |= BM_USBPHY_CTRL_SFTRST; + __raw_writel(tmp, phy_ctrl); + udelay(10); + + /* Remove CLKGATE and SFTRST */ + tmp = __raw_readl(phy_ctrl); + tmp &= ~(BM_USBPHY_CTRL_CLKGATE | BM_USBPHY_CTRL_SFTRST); + __raw_writel(tmp, phy_ctrl); + udelay(10); + + /* Power up the PHY */ + __raw_writel(0, phy_reg + HW_USBPHY_PWD); + /* enable FS/LS device */ + tmp = __raw_readl(phy_reg + HW_USBPHY_CTRL); + tmp |= (BM_USBPHY_CTRL_ENUTMILEVEL2 | BM_USBPHY_CTRL_ENUTMILEVEL3); + __raw_writel(tmp, phy_reg + HW_USBPHY_CTRL); + + if (!usb_icbug_swfix_need()) + __raw_writel((1 << 17), phy_reg + HW_USBPHY_IP_SET); + if (cpu_is_mx6sl()) + __raw_writel((1 << 18), phy_reg + HW_USBPHY_IP_SET); + return 0; +} +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret; + struct clk *usb_clk; + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + ret = fsl_usb_host_init(pdev); + if (ret) { + printk(KERN_ERR "host1 init fails......\n"); + clk_disable(usb_oh3_clk); + clk_put(usb_oh3_clk); + return ret; + } + usbh1_internal_phy_clock_gate(true); + usb_phy_enable(pdev->dev.platform_data); + + return 0; +} + +static void fsl_usb_host_uninit_ext(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + fsl_usb_host_uninit(pdata); + + clk_put(usb_oh3_clk); + +} + +static void usbh1_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_oh3_clk); + } else { + clk_disable(usb_oh3_clk); + } +} + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR); + + pr_debug("host1, %s, enable is %d\n", __func__, enable); + if (enable) { + __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP | BM_USBPHY_CTRL_ENVBUSCHG_WKUP + | BM_USBPHY_CTRL_ENDPDMCHG_WKUP + | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS + | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD + | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE + | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE + | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_SET); + USB_H1_CTRL |= (UCTRL_OWIE); + } else { + __raw_writel(BM_USBPHY_CTRL_ENIDCHG_WKUP | BM_USBPHY_CTRL_ENVBUSCHG_WKUP + | BM_USBPHY_CTRL_ENDPDMCHG_WKUP + | BM_USBPHY_CTRL_ENAUTOSET_USBCLKS + | BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD + | BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE + | BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE + | BM_USBPHY_CTRL_ENAUTO_PWRON_PLL , phy_reg + HW_USBPHY_CTRL_CLR); + USB_H1_CTRL &= ~(UCTRL_OWIE); + /* 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 usbh1_platform_rh_suspend_swfix(struct fsl_usb2_platform_data *pdata) +{ + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR); + u32 tmp; + u32 index = 0; + + /* before we set and then clear PWD bit, + * we must wait LS to be J */ + if ((UH1_PORTSC1 & (3 << 26)) != (1 << 26)) { + while (((UH1_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_J_STATE) && + (index < 1000)) { + index++; + udelay(4); + } + } else { + while (((UH1_PORTSC1 & PORTSC_LS_MASK) != PORTSC_LS_K_STATE) && + (index < 1000)) { + index++; + udelay(4); + } + } + + if (index >= 1000) + printk(KERN_INFO "%s big error\n", __func__); + + tmp = (BM_USBPHY_PWD_TXPWDFS + | BM_USBPHY_PWD_TXPWDIBIAS + | BM_USBPHY_PWD_TXPWDV2I + | BM_USBPHY_PWD_RXPWDENV + | BM_USBPHY_PWD_RXPWD1PT1 + | BM_USBPHY_PWD_RXPWDDIFF + | BM_USBPHY_PWD_RXPWDRX); + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET); + + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR); + + fsl_platform_h1_set_usb_phy_dis(pdata, 0); +} + +static void usbh1_platform_rh_resume_swfix(struct fsl_usb2_platform_data *pdata) +{ + u32 index = 0; + + if ((UH1_PORTSC1 & (PORTSC_PORT_SPEED_MASK)) != PORTSC_PORT_SPEED_HIGH) + return ; + while ((UH1_PORTSC1 & PORTSC_PORT_FORCE_RESUME) + && (index < 1000)) { + udelay(500); + index++; + } + if (index >= 1000) + printk(KERN_ERR "failed to wait for the resume finished in %s() line:%d\n", + __func__, __LINE__); + /* We should add some delay to wait for the device switch to + * High-Speed 45ohm termination resistors mode. */ + udelay(500); + fsl_platform_h1_set_usb_phy_dis(pdata, 1); +} + +static void usbh1_platform_rh_suspend(struct fsl_usb2_platform_data *pdata) +{ + /*for mx6sl ,we do not need any sw fix*/ + if (cpu_is_mx6sl()) + return ; + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_CLR); +} + +static void usbh1_platform_rh_resume(struct fsl_usb2_platform_data *pdata) +{ + u32 index = 0; + + /*for mx6sl ,we do not need any sw fix*/ + if (cpu_is_mx6sl()) + return ; + if ((UH1_PORTSC1 & (PORTSC_PORT_SPEED_MASK)) != PORTSC_PORT_SPEED_HIGH) + return ; + while ((UH1_PORTSC1 & PORTSC_PORT_FORCE_RESUME) + && (index < 1000)) { + udelay(500); + index++; + } + if (index >= 1000) + printk(KERN_ERR "failed to wait for the resume finished in %s() line:%d\n", + __func__, __LINE__); + /* We should add some delay to wait for the device switch to + * High-Speed 45ohm termination resistors mode. */ + udelay(500); + __raw_writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, + MX6_IO_ADDRESS(pdata->phy_regs) + + HW_USBPHY_CTRL_SET); +} + +static void _phy_lowpower_suspend(struct fsl_usb2_platform_data *pdata, bool enable) +{ + u32 tmp; + void __iomem *phy_reg = MX6_IO_ADDRESS(USB_PHY1_BASE_ADDR); + pr_debug("host1, %s, enable is %d\n", __func__, enable); + if (enable) { + UH1_PORTSC1 |= PORTSC_PHCD; + + pr_debug("%s, Poweroff UTMI \n", __func__); + + tmp = (BM_USBPHY_PWD_TXPWDFS + | BM_USBPHY_PWD_TXPWDIBIAS + | BM_USBPHY_PWD_TXPWDV2I + | BM_USBPHY_PWD_RXPWDENV + | BM_USBPHY_PWD_RXPWD1PT1 + | BM_USBPHY_PWD_RXPWDDIFF + | BM_USBPHY_PWD_RXPWDRX); + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_SET); + + usbh1_internal_phy_clock_gate(false); + } else { + if (UH1_PORTSC1 & PORTSC_PHCD) + UH1_PORTSC1 &= ~PORTSC_PHCD; + + /* Wait PHY clock stable */ + mdelay(1); + + usbh1_internal_phy_clock_gate(true); + + udelay(2); + + tmp = (BM_USBPHY_PWD_TXPWDFS + | BM_USBPHY_PWD_TXPWDIBIAS + | BM_USBPHY_PWD_TXPWDV2I + | BM_USBPHY_PWD_RXPWDENV + | BM_USBPHY_PWD_RXPWD1PT1 + | BM_USBPHY_PWD_RXPWDDIFF + | BM_USBPHY_PWD_RXPWDRX); + __raw_writel(tmp, phy_reg + HW_USBPHY_PWD_CLR); + /* + * The PHY works at 32Khz clock when it is at low power mode, + * it needs 10 clocks from 32Khz to normal work state, so + * 500us is the safe value for PHY enters stable status + * according to IC engineer. + */ + udelay(500); + } +} + +static enum usb_wakeup_event _is_usbh1_wakeup(struct fsl_usb2_platform_data *pdata) +{ + u32 wakeup_req = USB_H1_CTRL & UCTRL_OWIR; + + if (wakeup_req) + return WAKEUP_EVENT_DPDM; + pr_err("host1, %s, invalid wake up\n", __func__); + 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 = USB_H1_CTRL & UCTRL_OWIR; + + if (wakeup_req != 0) { + printk(KERN_INFO "Unknown wakeup.(H1 OTGSC 0x%x)\n", UH1_OTGSC); + /* Disable OWIE to clear OWIR, wait 3 clock + * cycles of standly clock(32KHz) + */ + USB_H1_CTRL &= ~UCTRL_OWIE; + udelay(100); + USB_H1_CTRL |= UCTRL_OWIE; + } +} + +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, + .platform_set_disconnect_det = fsl_platform_h1_set_usb_phy_dis, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .is_wakeup_event = _is_usbh1_wakeup, + .wakeup_handler = h1_wakeup_handler, + .platform_phy_power_on = usbh1_platform_phy_power_on, + .transceiver = "utmi", + .phy_regs = USB_PHY1_BASE_ADDR, +}; +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, +}; + +static struct platform_device *pdev, *pdev_wakeup; +static driver_vbus_func mx6_set_usb_host1_vbus; + +static int __init mx6_usb_h1_init(void) +{ + static void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + struct imx_fsl_usb2_wakeup_data imx6q_fsl_hs_wakeup_data[] = { + imx_fsl_usb2_wakeup_data_entry_single(MX6Q, 1, HS1)}; + struct imx_fsl_usb2_wakeup_data imx6sl_fsl_hs_wakeup_data[] = { + imx_fsl_usb2_wakeup_data_entry_single(MX6SL, 1, HS1)}; + struct imx_mxc_ehci_data imx6q_mxc_ehci_hs_data[] = { + imx_mxc_ehci_data_entry_single(MX6Q, 1, HS1)}; + struct imx_mxc_ehci_data imx6sl_mxc_ehci_hs_data[] = { + imx_mxc_ehci_data_entry_single(MX6SL, 1, HS1)}; + + mx6_get_host1_vbus_func(&mx6_set_usb_host1_vbus); + if (mx6_set_usb_host1_vbus) + mx6_set_usb_host1_vbus(true); + + /* Some phy and power's special controls for host1 + * 1. The external charger detector needs to be disabled + * or the signal at DP will be poor + * 2. The PLL's power and output to usb for host 1 + * is totally controlled by IC, so the Software only needs + * to enable them at initializtion. + */ + __raw_writel(BM_ANADIG_USB2_CHRG_DETECT_EN_B \ + | BM_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B, \ + anatop_base_addr + HW_ANADIG_USB2_CHRG_DETECT); + __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_BYPASS, + anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_CLR); + __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_ENABLE \ + | BM_ANADIG_USB2_PLL_480_CTRL_POWER \ + | BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, \ + anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_SET); + + usbh1_config.wakeup_pdata = &usbh1_wakeup_config; + if (usb_icbug_swfix_need()) { + usbh1_config.platform_rh_suspend = usbh1_platform_rh_suspend_swfix; + usbh1_config.platform_rh_resume = usbh1_platform_rh_resume_swfix; + } else { + usbh1_config.platform_rh_suspend = usbh1_platform_rh_suspend; + usbh1_config.platform_rh_resume = usbh1_platform_rh_resume; + } + if (cpu_is_mx6sl()) + pdev = imx6sl_add_fsl_ehci_hs(1, &usbh1_config); + else + pdev = imx6q_add_fsl_ehci_hs(1, &usbh1_config); + usbh1_wakeup_config.usb_pdata[0] = pdev->dev.platform_data; + if (cpu_is_mx6sl()) + pdev_wakeup = imx6sl_add_fsl_usb2_hs_wakeup(1, &usbh1_wakeup_config); + else + pdev_wakeup = imx6q_add_fsl_usb2_hs_wakeup(1, &usbh1_wakeup_config); + platform_device_add(pdev); + ((struct fsl_usb2_platform_data *)(pdev->dev.platform_data))->wakeup_pdata = + (struct fsl_usb2_wakeup_platform_data *)(pdev_wakeup->dev.platform_data); + return 0; +} +module_init(mx6_usb_h1_init); + +static void __exit mx6_usb_h1_exit(void) +{ + static void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + + platform_device_unregister(pdev); + platform_device_unregister(pdev_wakeup); + __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_BYPASS, + anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_SET); + __raw_writel(BM_ANADIG_USB2_PLL_480_CTRL_ENABLE \ + | BM_ANADIG_USB2_PLL_480_CTRL_POWER \ + | BM_ANADIG_USB2_PLL_480_CTRL_EN_USB_CLKS, \ + anatop_base_addr + HW_ANADIG_USB2_PLL_480_CTRL_CLR); + if (mx6_set_usb_host1_vbus) + mx6_set_usb_host1_vbus(false); + + return ; +} +module_exit(mx6_usb_h1_exit); + +MODULE_AUTHOR("Freescale Semiconductor"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-mx6/usb_h2.c b/arch/arm/mach-mx6/usb_h2.c new file mode 100644 index 00000000..2577abd4 --- /dev/null +++ b/arch/arm/mach-mx6/usb_h2.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2011-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. + * + * High Speed Inter Chip code for i.MX6, this file is for HSIC port 1 + */ + +#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 <linux/io.h> +#include <linux/delay.h> +#include <mach/arc_otg.h> +#include <mach/hardware.h> +#include <mach/iomux-mx6q.h> +#include <mach/iomux-mx6dl.h> +#include <mach/iomux-mx6sl.h> +#include "devices-imx6q.h" +#include "regs-anadig.h" +#include "usb.h" + +static struct clk *usb_oh3_clk; +static struct clk *usb_phy3_clk; + +extern int clk_get_usecount(struct clk *clk); +static struct fsl_usb2_platform_data usbh2_config; + +static void usbh2_internal_phy_clock_gate(bool on) +{ + if (on) { + /* must turn on the 480M clock, otherwise + * there will be a 10ms delay before host + * controller send out resume signal*/ + USB_H2_CTRL |= UCTRL_UTMI_ON_CLOCK; + USB_UH2_HSIC_CTRL |= HSIC_CLK_ON; + } else { + USB_UH2_HSIC_CTRL &= ~HSIC_CLK_ON; + /* can't turn off this clock, otherwise + * there will be a 10ms delay before host + * controller send out resume signal*/ + /*USB_H2_CTRL &= ~UCTRL_UTMI_ON_CLOCK*/; + } +} + +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret; + struct clk *usb_clk; + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + usb_clk = clk_get(NULL, "usb_phy3_clk"); + clk_enable(usb_clk); + usb_phy3_clk = usb_clk; + + ret = fsl_usb_host_init(pdev); + if (ret) { + printk(KERN_ERR "host1 init fails......\n"); + return ret; + } + usbh2_internal_phy_clock_gate(true); + /* Host2 HSIC enable */ + USB_UH2_HSIC_CTRL |= HSIC_EN; + + return 0; +} + +static void fsl_usb_host_uninit_ext(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + fsl_usb_host_uninit(pdata); + + clk_put(usb_phy3_clk); + + clk_put(usb_oh3_clk); + +} + +static void usbh2_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_oh3_clk); + clk_enable(usb_phy3_clk); + usbh2_internal_phy_clock_gate(true); + } else { + usbh2_internal_phy_clock_gate(false); + clk_disable(usb_phy3_clk); + clk_disable(usb_oh3_clk); + } +} + +void mx6_set_host2_vbus_func(driver_vbus_func driver_vbus) +{ + usbh2_config.platform_driver_vbus = driver_vbus; +} + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + pr_debug("host2, %s, enable is %d\n", __func__, enable); + /* for HSIC, no disconnect nor connect + * we need to disable the WKDS, WKCN */ + UH2_PORTSC1 &= ~(PORTSC_WKDC | PORTSC_WKCN); + + if (enable) { + USB_H2_CTRL |= (UCTRL_OWIE); + } else { + USB_H2_CTRL &= ~(UCTRL_OWIE); + /* 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("host2, %s, enable is %d\n", __func__, enable); + if (enable) + UH2_PORTSC1 |= PORTSC_PHCD; + else + UH2_PORTSC1 &= ~PORTSC_PHCD; + +} + +static enum usb_wakeup_event _is_usbh2_wakeup(struct fsl_usb2_platform_data *pdata) +{ + u32 wakeup_req = USB_H2_CTRL & UCTRL_OWIR; + + if (wakeup_req) + return WAKEUP_EVENT_DPDM; + pr_err("host2, %s, invalid wake up\n", __func__); + 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) +{ + u32 wakeup_req = USB_H2_CTRL & UCTRL_OWIR; + pr_debug("%s\n", __func__); + + if (wakeup_req != 0) { + /* Disable H2 wakeup enable to clear H2 wakeup request, wait 3 clock + * cycles of standly clock(32KHz) + */ + USB_H2_CTRL &= ~UCTRL_OWIE; + udelay(100); + USB_H2_CTRL |= UCTRL_OWIE; + } +} + +static void hsic_start(void) +{ + pr_debug("%s\n", __func__); + /* strobe 47K pull up */ + if (cpu_is_mx6q()) + mxc_iomux_v3_setup_pad( + MX6Q_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE_START); + else if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_pad( + MX6DL_PAD_RGMII_TX_CTL__USBOH3_H2_STROBE_START); + else if (cpu_is_mx6sl()) + mxc_iomux_v3_setup_pad( + MX6SL_PAD_HSIC_STROBE__USB_H_STROBE_START); +} + +static void hsic_device_connected(void) +{ + pr_debug("%s\n", __func__); + if (!(USB_UH2_HSIC_CTRL & HSIC_DEV_CONN)) + USB_UH2_HSIC_CTRL |= HSIC_DEV_CONN; +} + +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_HSIC, + .power_budget = 500, /* 500 mA max power */ + .wake_up_enable = _wake_up_enable, + .usb_clock_for_pm = usbh2_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .is_wakeup_event = _is_usbh2_wakeup, + .wakeup_handler = h2_wakeup_handler, + .transceiver = "hsic_xcvr", + .hsic_post_ops = hsic_start, + .hsic_device_connected = hsic_device_connected, +}; + +static struct fsl_usb2_wakeup_platform_data usbh2_wakeup_config = { + .name = "usbh2 wakeup", + .usb_clock_for_pm = usbh2_clock_gate, + .usb_pdata = {&usbh2_config, NULL, NULL}, + .usb_wakeup_exhandle = usbh2_wakeup_event_clear, +}; + +void __init mx6_usb_h2_init(void) +{ + struct platform_device *pdev, *pdev_wakeup; + static void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + usbh2_config.wakeup_pdata = &usbh2_wakeup_config; + if (cpu_is_mx6sl()) + pdev = imx6sl_add_fsl_ehci_hs(2, &usbh2_config); + else + pdev = imx6q_add_fsl_ehci_hs(2, &usbh2_config); + + usbh2_wakeup_config.usb_pdata[0] = pdev->dev.platform_data; + if (cpu_is_mx6sl()) + pdev_wakeup = imx6sl_add_fsl_usb2_hs_wakeup(2, &usbh2_wakeup_config); + else + pdev_wakeup = imx6q_add_fsl_usb2_hs_wakeup(2, &usbh2_wakeup_config); + platform_device_add(pdev); + ((struct fsl_usb2_platform_data *)(pdev->dev.platform_data))->wakeup_pdata = + pdev_wakeup->dev.platform_data; + /* Some phy and power's special controls for host2 + * 1. Its 480M is from OTG's 480M + * 2. EN_USB_CLKS should always be opened + */ + __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET); + /* must change the clkgate delay to 2 or 3 to avoid + * 24M OSCI clock not stable issue */ + __raw_writel(BF_ANADIG_ANA_MISC0_CLKGATE_DELAY(3), + anatop_base_addr + HW_ANADIG_ANA_MISC0); +} diff --git a/arch/arm/mach-mx6/usb_h3.c b/arch/arm/mach-mx6/usb_h3.c new file mode 100644 index 00000000..a057269c --- /dev/null +++ b/arch/arm/mach-mx6/usb_h3.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2011-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. + * + * High Speed Inter Chip code for i.MX6, this file is for HSIC port 2 + */ + +#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 <linux/io.h> +#include <linux/delay.h> +#include <mach/arc_otg.h> +#include <mach/hardware.h> +#include <mach/iomux-mx6q.h> +#include <mach/iomux-mx6dl.h> +#include "devices-imx6q.h" +#include "regs-anadig.h" +#include "usb.h" + +static struct clk *usb_oh3_clk; +static struct clk *usb_phy4_clk; + +extern int clk_get_usecount(struct clk *clk); +static struct fsl_usb2_platform_data usbh3_config; + +static void usbh3_internal_phy_clock_gate(bool on) +{ + if (on) { + /* must turn on the 480M clock, otherwise + * there will be a 10ms delay before host + * controller send out resume signal*/ + USB_H3_CTRL |= UCTRL_UTMI_ON_CLOCK; + USB_UH3_HSIC_CTRL |= HSIC_CLK_ON; + } else { + USB_UH3_HSIC_CTRL &= ~HSIC_CLK_ON; + /* can't turn off this clock, otherwise + * there will be a 10ms delay before host + * controller send out resume signal*/ + /*USB_H3_CTRL &= ~UCTRL_UTMI_ON_CLOCK;*/ + } +} + +static int fsl_usb_host_init_ext(struct platform_device *pdev) +{ + int ret; + struct clk *usb_clk; + usb_clk = clk_get(NULL, "usboh3_clk"); + clk_enable(usb_clk); + usb_oh3_clk = usb_clk; + + usb_clk = clk_get(NULL, "usb_phy4_clk"); + clk_enable(usb_clk); + usb_phy4_clk = usb_clk; + + ret = fsl_usb_host_init(pdev); + if (ret) { + printk(KERN_ERR "host1 init fails......\n"); + return ret; + } + usbh3_internal_phy_clock_gate(true); + + /* Host3 HSIC enable */ + USB_UH3_HSIC_CTRL |= HSIC_EN; + + return 0; +} + +static void fsl_usb_host_uninit_ext(struct platform_device *pdev) +{ + struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; + + fsl_usb_host_uninit(pdata); + + clk_put(usb_phy4_clk); + + clk_put(usb_oh3_clk); + +} + +static void usbh3_clock_gate(bool on) +{ + pr_debug("%s: on is %d\n", __func__, on); + if (on) { + clk_enable(usb_oh3_clk); + clk_enable(usb_phy4_clk); + usbh3_internal_phy_clock_gate(true); + } else { + usbh3_internal_phy_clock_gate(false); + clk_disable(usb_phy4_clk); + clk_disable(usb_oh3_clk); + } +} + +void mx6_set_host3_vbus_func(driver_vbus_func driver_vbus) +{ + usbh3_config.platform_driver_vbus = driver_vbus; +} + +static void _wake_up_enable(struct fsl_usb2_platform_data *pdata, bool enable) +{ + pr_debug("host3, %s, enable is %d\n", __func__, enable); + /* for HSIC, no disconnect nor connect + * we need to disable the WKDS, WKCN */ + UH3_PORTSC1 &= ~(PORTSC_WKDC | PORTSC_WKCN); + + if (enable) { + USB_H3_CTRL |= (UCTRL_OWIE); + } else { + USB_H3_CTRL &= ~(UCTRL_OWIE); + /* 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("host3, %s, enable is %d\n", __func__, enable); + if (enable) + UH3_PORTSC1 |= PORTSC_PHCD; + else + UH3_PORTSC1 &= ~PORTSC_PHCD; + +} + +static enum usb_wakeup_event _is_usbh3_wakeup(struct fsl_usb2_platform_data *pdata) +{ + u32 wakeup_req = USB_H3_CTRL & UCTRL_OWIR; + + if (wakeup_req) + return WAKEUP_EVENT_DPDM; + pr_err("host3, %s, invalid wake up\n", __func__); + return WAKEUP_EVENT_INVALID; +} + +static void usbh3_wakeup_handler(struct fsl_usb2_platform_data *pdata) +{ + _wake_up_enable(pdata, false); + _phy_lowpower_suspend(pdata, false); +} + +static void usbh3_wakeup_event_clear(void) +{ + u32 wakeup_req = USB_H3_CTRL & UCTRL_OWIR; + pr_debug("%s\n", __func__); + + if (wakeup_req != 0) { + /* Disable H3 wakeup enable to clear H3 wakeup request, wait 3 clock + * cycles of standly clock(32KHz) + */ + USB_H3_CTRL &= ~UCTRL_OWIE; + udelay(100); + USB_H3_CTRL |= UCTRL_OWIE; + } +} + +static void hsic_start(void) +{ + pr_debug("%s", __func__); + /* strobe 47K pull up */ + if (cpu_is_mx6q()) + mxc_iomux_v3_setup_pad( + MX6Q_PAD_RGMII_RXC__USBOH3_H3_STROBE_START); + else if (cpu_is_mx6dl()) + mxc_iomux_v3_setup_pad( + MX6DL_PAD_RGMII_RXC__USBOH3_H3_STROBE_START); +} + +static void hsic_device_connected(void) +{ + pr_debug("%s\n", __func__); + if (!(USB_UH3_HSIC_CTRL & HSIC_DEV_CONN)) + USB_UH3_HSIC_CTRL |= HSIC_DEV_CONN; +} + +static struct fsl_usb2_platform_data usbh3_config = { + .name = "Host 3", + .init = fsl_usb_host_init_ext, + .exit = fsl_usb_host_uninit_ext, + .operating_mode = FSL_USB2_MPH_HOST, + .phy_mode = FSL_USB2_PHY_HSIC, + .power_budget = 500, /* 500 mA max power */ + .wake_up_enable = _wake_up_enable, + .usb_clock_for_pm = usbh3_clock_gate, + .phy_lowpower_suspend = _phy_lowpower_suspend, + .is_wakeup_event = _is_usbh3_wakeup, + .wakeup_handler = usbh3_wakeup_handler, + .transceiver = "hsic_xcvr", + .hsic_post_ops = hsic_start, + .hsic_device_connected = hsic_device_connected, +}; + +static struct fsl_usb2_wakeup_platform_data usbh3_wakeup_config = { + .name = "usbh3 wakeup", + .usb_clock_for_pm = usbh3_clock_gate, + .usb_pdata = {&usbh3_config, NULL, NULL}, + .usb_wakeup_exhandle = usbh3_wakeup_event_clear, +}; + +void __init mx6_usb_h3_init(void) +{ + struct platform_device *pdev, *pdev_wakeup; + static void __iomem *anatop_base_addr = MX6_IO_ADDRESS(ANATOP_BASE_ADDR); + usbh3_config.wakeup_pdata = &usbh3_wakeup_config; + pdev = imx6q_add_fsl_ehci_hs(3, &usbh3_config); + usbh3_wakeup_config.usb_pdata[0] = pdev->dev.platform_data; + pdev_wakeup = imx6q_add_fsl_usb2_hs_wakeup(3, &usbh3_wakeup_config); + platform_device_add(pdev); + ((struct fsl_usb2_platform_data *)(pdev->dev.platform_data))->wakeup_pdata = + pdev_wakeup->dev.platform_data; + + /* Some phy and power's special controls for host3 + * 1. Its 480M is from OTG's 480M + * 2. EN_USB_CLKS should always be opened + */ + __raw_writel(BM_ANADIG_USB1_PLL_480_CTRL_EN_USB_CLKS, + anatop_base_addr + HW_ANADIG_USB1_PLL_480_CTRL_SET); + /* must change the clkgate delay to 2 or 3 to avoid + * 24M OSCI clock not stable issue */ + __raw_writel(BF_ANADIG_ANA_MISC0_CLKGATE_DELAY(3), + anatop_base_addr + HW_ANADIG_ANA_MISC0); +} |