diff options
Diffstat (limited to 'arch/arm/mach-imx')
77 files changed, 19609 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig new file mode 100755 index 00000000..edc9a61c --- /dev/null +++ b/arch/arm/mach-imx/Kconfig @@ -0,0 +1,608 @@ +config IMX_HAVE_DMA_V1 + bool +# +# ARCH_MX31 and ARCH_MX35 are left for compatibility +# Some usages assume that having one of them implies not having (e.g.) ARCH_MX2. +# To easily distinguish good and reviewed from unreviewed usages new (and IMHO +# more sensible) names are used: SOC_IMX31 and SOC_IMX35 +config ARCH_MX31 + bool + +config ARCH_MX35 + bool + +config SOC_IMX1 + bool + select CPU_ARM920T + select IMX_HAVE_DMA_V1 + select IMX_HAVE_IOMUX_V1 + select MXC_AVIC + +config SOC_IMX21 + bool + select CPU_ARM926T + select ARCH_MXC_AUDMUX_V1 + select IMX_HAVE_DMA_V1 + select IMX_HAVE_IOMUX_V1 + select MXC_AVIC + +config SOC_IMX25 + bool + select CPU_ARM926T + select ARCH_MXC_AUDMUX_V2 + select ARCH_MXC_IOMUX_V3 + select MXC_AVIC + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_MXC_PWM + +config SOC_IMX27 + bool + select CPU_ARM926T + select ARCH_MXC_AUDMUX_V1 + select IMX_HAVE_DMA_V1 + select IMX_HAVE_IOMUX_V1 + select MXC_AVIC + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_MXC_PWM + +config SOC_IMX31 + bool + select CPU_V6 + select IMX_HAVE_PLATFORM_MXC_RNGA + select ARCH_MXC_AUDMUX_V2 + select ARCH_MX31 + select MXC_AVIC + +config SOC_IMX35 + bool + select CPU_V6 + select ARCH_MXC_IOMUX_V3 + select ARCH_MXC_AUDMUX_V2 + select HAVE_EPIT + select ARCH_MX35 + select MXC_AVIC + select IMX_HAVE_PLATFORM_FEC + select IMX_HAVE_PLATFORM_MXC_PWM + + +if ARCH_MX1 + +comment "MX1 platforms:" +config MACH_MXLADS + bool + +config ARCH_MX1ADS + bool "MX1ADS platform" + select MACH_MXLADS + select SOC_IMX1 + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + help + Say Y here if you are using Motorola MX1ADS/MXLADS boards + +config MACH_SCB9328 + bool "Synertronixx scb9328" + select IMX_HAVE_PLATFORM_IMX_UART + help + Say Y here if you are using a Synertronixx scb9328 board + +config MACH_APF9328 + bool "APF9328" + select SOC_IMX1 + select IMX_HAVE_PLATFORM_IMX_UART + help + Say Yes here if you are using the Armadeus APF9328 development board + +endif + +if ARCH_MX2 + +choice + prompt "CPUs:" + default MACH_MX21 + +config MACH_MX21 + bool "i.MX21 support" + help + This enables support for Freescale's MX2 based i.MX21 processor. + +config MACH_MX27 + bool "i.MX27 support" + help + This enables support for Freescale's MX2 based i.MX27 processor. + +endchoice + +endif + +if MACH_MX21 + +comment "MX21 platforms:" + +config MACH_MX21ADS + bool "MX21ADS platform" + select SOC_IMX21 + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + help + Include support for MX21ADS platform. This includes specific + configurations for the board and its peripherals. + +endif + +if ARCH_MX25 + +comment "MX25 platforms:" + +config MACH_MX25_3DS + bool "Support MX25PDK (3DS) Platform" + select SOC_IMX25 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMXDI_RTC + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + +config MACH_EUKREA_CPUIMX25 + bool "Support Eukrea CPUIMX25 Platform" + select SOC_IMX25 + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMXDI_RTC + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select MXC_ULPI if USB_ULPI + +choice + prompt "Baseboard" + depends on MACH_EUKREA_CPUIMX25 + default MACH_EUKREA_MBIMXSD25_BASEBOARD + +config MACH_EUKREA_MBIMXSD25_BASEBOARD + bool "Eukrea MBIMXSD development board" + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_IMX_SSI + help + This adds board specific devices that can be found on Eukrea's + MBIMXSD evaluation board. + +endchoice + +endif + +if MACH_MX27 + +comment "MX27 platforms:" + +config MACH_MX27ADS + bool "MX27ADS platform" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_MXC_W1 + help + Include support for MX27ADS platform. This includes specific + configurations for the board and its peripherals. + +config MACH_PCM038 + bool "Phytec phyCORE-i.MX27 CPU module (pcm038)" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_MXC_W1 + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + help + Include support for phyCORE-i.MX27 (aka pcm038) platform. This + includes specific configurations for the module and its peripherals. + +choice + prompt "Baseboard" + depends on MACH_PCM038 + default MACH_PCM970_BASEBOARD + +config MACH_PCM970_BASEBOARD + bool "PHYTEC PCM970 development board" + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_MXC_MMC + help + This adds board specific devices that can be found on Phytec's + PCM970 evaluation board. + +endchoice + +config MACH_CPUIMX27 + bool "Eukrea CPUIMX27 module" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_MXC_W1 + select MXC_ULPI if USB_ULPI + help + Include support for Eukrea CPUIMX27 platform. This includes + specific configurations for the module and its peripherals. + +config MACH_EUKREA_CPUIMX27_USESDHC2 + bool "CPUIMX27 integrates SDHC2 module" + depends on MACH_CPUIMX27 + select IMX_HAVE_PLATFORM_MXC_MMC + help + This adds support for the internal SDHC2 used on CPUIMX27 + for wifi or eMMC. + +config MACH_EUKREA_CPUIMX27_USEUART4 + bool "CPUIMX27 integrates UART4 module" + depends on MACH_CPUIMX27 + help + This adds support for the internal UART4 used on CPUIMX27 + for bluetooth. + +choice + prompt "Baseboard" + depends on MACH_CPUIMX27 + default MACH_EUKREA_MBIMX27_BASEBOARD + +config MACH_EUKREA_MBIMX27_BASEBOARD + bool "Eukrea MBIMX27 development board" + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_SPI_IMX + help + This adds board specific devices that can be found on Eukrea's + MBIMX27 evaluation board. + +endchoice + +config MACH_MX27_3DS + bool "MX27PDK platform" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_DEBUG_BOARD + select MXC_ULPI if USB_ULPI + help + Include support for MX27PDK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_IMX27_VISSTRIM_M10 + bool "Vista Silicon i.MX27 Visstrim_m10" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_EHCI + help + Include support for Visstrim_m10 platform and its different variants. + This includes specific configurations for the board and its + peripherals. + +config MACH_IMX27LITE + bool "LogicPD MX27 LITEKIT platform" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX_SSI + help + Include support for MX27 LITEKIT platform. This includes specific + configurations for the board and its peripherals. + +config MACH_PCA100 + bool "Phytec phyCARD-s (pca100)" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_MXC_W1 + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + help + Include support for phyCARD-s (aka pca100) platform. This + includes specific configurations for the module and its peripherals. + +config MACH_MXT_TD60 + bool "Maxtrack i-MXT TD60" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_IMX_FB + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + help + Include support for i-MXT (aka td60) platform. This + includes specific configurations for the module and its peripherals. + +config MACH_IMX27IPCAM + bool "IMX27 IPCAM platform" + select SOC_IMX27 + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_UART + help + Include support for IMX27 IPCAM platform. This includes specific + configurations for the board and its peripherals. + +endif + +if ARCH_MX3 + +comment "MX31 platforms:" + +config MACH_MX31ADS + bool "Support MX31ADS platforms" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_UART + default y + help + Include support for MX31ADS platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX31ADS_WM1133_EV1 + bool "Support Wolfson Microelectronics 1133-EV1 module" + depends on MACH_MX31ADS + depends on MFD_WM8350_I2C + depends on REGULATOR_WM8350 + select MFD_WM8350_CONFIG_MODE_0 + select MFD_WM8352_CONFIG_MODE_0 + help + Include support for the Wolfson Microelectronics 1133-EV1 PMU + and audio module for the MX31ADS platform. + +config MACH_MX31LILLY + bool "Support MX31 LILLY-1131 platforms (INCO startec)" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + help + Include support for mx31 based LILLY1131 modules. This includes + specific configurations for the board and its peripherals. + +config MACH_MX31LITE + bool "Support MX31 LITEKIT (LogicPD)" + select SOC_IMX31 + select MXC_ULPI if USB_ULPI + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_MXC_RTC + select IMX_HAVE_PLATFORM_SPI_IMX + help + Include support for MX31 LITEKIT platform. This includes specific + configurations for the board and its peripherals. + +config MACH_PCM037 + bool "Support Phytec pcm037 (i.MX31) platforms" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_MXC_W1 + select MXC_ULPI if USB_ULPI + help + Include support for Phytec pcm037 platform. This includes + specific configurations for the board and its peripherals. + +config MACH_PCM037_EET + bool "Support pcm037 EET board extensions" + depends on MACH_PCM037 + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_SPI_IMX + help + Add support for PCM037 EET baseboard extensions. If you are using the + OLED display with EET, use "video=mx3fb:CMEL-OLED" kernel + command-line parameter. + +config MACH_MX31_3DS + bool "Support MX31PDK (3DS)" + select SOC_IMX31 + select MXC_DEBUG_BOARD + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_KEYPAD + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + help + Include support for MX31PDK (3DS) platform. This includes specific + configurations for the board and its peripherals. + +config MACH_MX31_3DS_MXC_NAND_USE_BBT + bool "Make the MXC NAND driver use the in flash Bad Block Table" + depends on MACH_MX31_3DS + depends on MTD_NAND_MXC + help + Enable this if you want that the MXC NAND driver uses the in flash + Bad Block Table to know what blocks are bad instead of scanning the + entire flash looking for bad block markers. + +config MACH_MX31MOBOARD + bool "Support mx31moboard platforms (EPFL Mobots group)" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_SPI_IMX + select MXC_ULPI if USB_ULPI + help + Include support for mx31moboard platform. This includes specific + configurations for the board and its peripherals. + +config MACH_QONG + bool "Support Dave/DENX QongEVB-LITE platform" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_IMX_UART + help + Include support for Dave/DENX QongEVB-LITE platform. This includes + specific configurations for the board and its peripherals. + +config MACH_ARMADILLO5X0 + bool "Support Atmark Armadillo-500 Development Base Board" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_MMC + select IMX_HAVE_PLATFORM_MXC_NAND + select MXC_ULPI if USB_ULPI + help + Include support for Atmark Armadillo-500 platform. This includes + specific configurations for the board and its peripherals. + +config MACH_KZM_ARM11_01 + bool "Support KZM-ARM11-01(Kyoto Microcomputer)" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_IMX_UART + help + Include support for KZM-ARM11-01. This includes specific + configurations for the board and its peripherals. + +config MACH_BUG + bool "Support Buglabs BUGBase platform" + select SOC_IMX31 + select IMX_HAVE_PLATFORM_IMX_UART + default y + help + Include support for BUGBase 1.3 platform. This includes specific + configurations for the board and its peripherals. + +comment "MX35 platforms:" + +config MACH_PCM043 + bool "Support Phytec pcm043 (i.MX35) platforms" + select SOC_IMX35 + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select MXC_ULPI if USB_ULPI + help + Include support for Phytec pcm043 platform. This includes + specific configurations for the board and its peripherals. + +config MACH_MX35_3DS + bool "Support MX35PDK platform" + select SOC_IMX35 + select MXC_DEBUG_BOARD + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + help + Include support for MX35PDK platform. This includes specific + configurations for the board and its peripherals. + +config MACH_EUKREA_CPUIMX35 + bool "Support Eukrea CPUIMX35 Platform" + select SOC_IMX35 + select IMX_HAVE_PLATFORM_FLEXCAN + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + select MXC_ULPI if USB_ULPI + help + Include support for Eukrea CPUIMX35 platform. This includes + specific configurations for the board and its peripherals. + +choice + prompt "Baseboard" + depends on MACH_EUKREA_CPUIMX35 + default MACH_EUKREA_MBIMXSD35_BASEBOARD + +config MACH_EUKREA_MBIMXSD35_BASEBOARD + bool "Eukrea MBIMXSD development board" + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_IMX_SSI + select IMX_HAVE_PLATFORM_IPU_CORE + help + This adds board specific devices that can be found on Eukrea's + MBIMXSD evaluation board. + +endchoice + +config MACH_VPR200 + bool "Support VPR200 platform" + select SOC_IMX35 + select IMX_HAVE_PLATFORM_FSL_USB2_UDC + select IMX_HAVE_PLATFORM_GPIO_KEYS + select IMX_HAVE_PLATFORM_IMX2_WDT + select IMX_HAVE_PLATFORM_IMX_UART + select IMX_HAVE_PLATFORM_IMX_I2C + select IMX_HAVE_PLATFORM_IPU_CORE + select IMX_HAVE_PLATFORM_MXC_EHCI + select IMX_HAVE_PLATFORM_MXC_NAND + select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX + help + Include support for VPR200 platform. This includes specific + configurations for the board and its peripherals. + +endif diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile new file mode 100644 index 00000000..e9eb36da --- /dev/null +++ b/arch/arm/mach-imx/Makefile @@ -0,0 +1,63 @@ +obj-$(CONFIG_IMX_HAVE_DMA_V1) += dma-v1.o + +obj-$(CONFIG_ARCH_MX1) += clock-imx1.o mm-imx1.o +obj-$(CONFIG_MACH_MX21) += clock-imx21.o mm-imx21.o + +obj-$(CONFIG_ARCH_MX25) += clock-imx25.o mm-imx25.o ehci-imx25.o + +obj-$(CONFIG_MACH_MX27) += cpu-imx27.o pm-imx27.o +obj-$(CONFIG_MACH_MX27) += clock-imx27.o mm-imx27.o ehci-imx27.o + +obj-$(CONFIG_SOC_IMX31) += mm-imx31.o cpu-imx31.o clock-imx31.o iomux-imx31.o ehci-imx31.o +obj-$(CONFIG_SOC_IMX35) += mm-imx35.o cpu-imx35.o clock-imx35.o ehci-imx35.o +obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o + +# Support for CMOS sensor interface +obj-$(CONFIG_MX1_VIDEO) += mx1-camera-fiq.o mx1-camera-fiq-ksym.o + +# i.MX1 based machines +obj-$(CONFIG_ARCH_MX1ADS) += mach-mx1ads.o +obj-$(CONFIG_MACH_SCB9328) += mach-scb9328.o +obj-$(CONFIG_MACH_APF9328) += mach-apf9328.o + +# i.MX21 based machines +obj-$(CONFIG_MACH_MX21ADS) += mach-mx21ads.o + +# i.MX25 based machines +obj-$(CONFIG_MACH_MX25_3DS) += mach-mx25_3ds.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX25) += mach-eukrea_cpuimx25.o +obj-$(CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD) += eukrea_mbimxsd25-baseboard.o + +# i.MX27 based machines +obj-$(CONFIG_MACH_MX27ADS) += mach-mx27ads.o +obj-$(CONFIG_MACH_PCM038) += mach-pcm038.o +obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o +obj-$(CONFIG_MACH_MX27_3DS) += mach-mx27_3ds.o +obj-$(CONFIG_MACH_IMX27LITE) += mach-imx27lite.o +obj-$(CONFIG_MACH_IMX27_VISSTRIM_M10) += mach-imx27_visstrim_m10.o +obj-$(CONFIG_MACH_CPUIMX27) += mach-cpuimx27.o +obj-$(CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD) += eukrea_mbimx27-baseboard.o +obj-$(CONFIG_MACH_PCA100) += mach-pca100.o +obj-$(CONFIG_MACH_MXT_TD60) += mach-mxt_td60.o +obj-$(CONFIG_MACH_IMX27IPCAM) += mach-imx27ipcam.o + +# i.MX31 based machines +obj-$(CONFIG_MACH_MX31ADS) += mach-mx31ads.o +obj-$(CONFIG_MACH_MX31LILLY) += mach-mx31lilly.o mx31lilly-db.o +obj-$(CONFIG_MACH_MX31LITE) += mach-mx31lite.o mx31lite-db.o +obj-$(CONFIG_MACH_PCM037) += mach-pcm037.o +obj-$(CONFIG_MACH_PCM037_EET) += mach-pcm037_eet.o +obj-$(CONFIG_MACH_MX31_3DS) += mach-mx31_3ds.o +obj-$(CONFIG_MACH_MX31MOBOARD) += mach-mx31moboard.o mx31moboard-devboard.o \ + mx31moboard-marxbot.o mx31moboard-smartbot.o +obj-$(CONFIG_MACH_QONG) += mach-qong.o +obj-$(CONFIG_MACH_ARMADILLO5X0) += mach-armadillo5x0.o +obj-$(CONFIG_MACH_KZM_ARM11_01) += mach-kzm_arm11_01.o +obj-$(CONFIG_MACH_BUG) += mach-bug.o + +# i.MX35 based machines +obj-$(CONFIG_MACH_PCM043) += mach-pcm043.o +obj-$(CONFIG_MACH_MX35_3DS) += mach-mx35_3ds.o +obj-$(CONFIG_MACH_EUKREA_CPUIMX35) += mach-cpuimx35.o +obj-$(CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD) += eukrea_mbimxsd35-baseboard.o +obj-$(CONFIG_MACH_VPR200) += mach-vpr200.o diff --git a/arch/arm/mach-imx/Makefile.boot b/arch/arm/mach-imx/Makefile.boot new file mode 100644 index 00000000..ebee18b3 --- /dev/null +++ b/arch/arm/mach-imx/Makefile.boot @@ -0,0 +1,19 @@ +zreladdr-$(CONFIG_ARCH_MX1) := 0x08008000 +params_phys-$(CONFIG_ARCH_MX1) := 0x08000100 +initrd_phys-$(CONFIG_ARCH_MX1) := 0x08800000 + +zreladdr-$(CONFIG_MACH_MX21) := 0xC0008000 +params_phys-$(CONFIG_MACH_MX21) := 0xC0000100 +initrd_phys-$(CONFIG_MACH_MX21) := 0xC0800000 + +zreladdr-$(CONFIG_ARCH_MX25) := 0x80008000 +params_phys-$(CONFIG_ARCH_MX25) := 0x80000100 +initrd_phys-$(CONFIG_ARCH_MX25) := 0x80800000 + +zreladdr-$(CONFIG_MACH_MX27) := 0xA0008000 +params_phys-$(CONFIG_MACH_MX27) := 0xA0000100 +initrd_phys-$(CONFIG_MACH_MX27) := 0xA0800000 + +zreladdr-$(CONFIG_ARCH_MX3) := 0x80008000 +params_phys-$(CONFIG_ARCH_MX3) := 0x80000100 +initrd_phys-$(CONFIG_ARCH_MX3) := 0x80800000 diff --git a/arch/arm/mach-imx/cache-l2x0.c b/arch/arm/mach-imx/cache-l2x0.c new file mode 100644 index 00000000..69d1322a --- /dev/null +++ b/arch/arm/mach-imx/cache-l2x0.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009-2010 Pengutronix + * Sascha Hauer <s.hauer@pengutronix.de> + * Juergen Beisert <j.beisert@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/err.h> +#include <linux/kernel.h> + +#include <asm/hardware/cache-l2x0.h> + +#include <mach/hardware.h> + +static int mxc_init_l2x0(void) +{ + void __iomem *l2x0_base; + void __iomem *clkctl_base; + + if (!cpu_is_mx31() && !cpu_is_mx35()) + return 0; + +/* + * First of all, we must repair broken chip settings. There are some + * i.MX35 CPUs in the wild, comming with bogus L2 cache settings. These + * misconfigured CPUs will run amok immediately when the L2 cache gets enabled. + * Workaraound is to setup the correct register setting prior enabling the + * L2 cache. This should not hurt already working CPUs, as they are using the + * same value. + */ +#define L2_MEM_VAL 0x10 + + clkctl_base = ioremap(MX35_CLKCTL_BASE_ADDR, 4096); + if (clkctl_base != NULL) { + writel(0x00000515, clkctl_base + L2_MEM_VAL); + iounmap(clkctl_base); + } else { + pr_err("L2 cache: Cannot fix timing. Trying to continue without\n"); + } + + l2x0_base = ioremap(MX3x_L2CC_BASE_ADDR, 4096); + if (IS_ERR(l2x0_base)) { + printk(KERN_ERR "remapping L2 cache area failed with %ld\n", + PTR_ERR(l2x0_base)); + return 0; + } + + l2x0_init(l2x0_base, 0x00030024, 0x00000000); + + return 0; +} +arch_initcall(mxc_init_l2x0); diff --git a/arch/arm/mach-imx/clock-imx1.c b/arch/arm/mach-imx/clock-imx1.c new file mode 100644 index 00000000..dcc41728 --- /dev/null +++ b/arch/arm/mach-imx/clock-imx1.c @@ -0,0 +1,636 @@ +/* + * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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 St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/math64.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include <mach/common.h> + +#define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off))) + +/* CCM register addresses */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_PCDR IO_ADDR_CCM(0x20) + +#define CCM_CSCR_CLKO_OFFSET 29 +#define CCM_CSCR_CLKO_MASK (0x7 << 29) +#define CCM_CSCR_USB_OFFSET 26 +#define CCM_CSCR_USB_MASK (0x7 << 26) +#define CCM_CSCR_OSC_EN_SHIFT 17 +#define CCM_CSCR_SYSTEM_SEL (1 << 16) +#define CCM_CSCR_BCLK_OFFSET 10 +#define CCM_CSCR_BCLK_MASK (0xf << 10) +#define CCM_CSCR_PRESC (1 << 15) + +#define CCM_PCDR_PCLK3_OFFSET 16 +#define CCM_PCDR_PCLK3_MASK (0x7f << 16) +#define CCM_PCDR_PCLK2_OFFSET 4 +#define CCM_PCDR_PCLK2_MASK (0xf << 4) +#define CCM_PCDR_PCLK1_OFFSET 0 +#define CCM_PCDR_PCLK1_MASK 0xf + +#define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off))) + +/* SCM register addresses */ +#define SCM_GCCR IO_ADDR_SCM(0xc) + +#define SCM_GCCR_DMA_CLK_EN_OFFSET 3 +#define SCM_GCCR_CSI_CLK_EN_OFFSET 2 +#define SCM_GCCR_MMA_CLK_EN_OFFSET 1 +#define SCM_GCCR_USBD_CLK_EN_OFFSET 0 + +static int _clk_enable(struct clk *clk) +{ + unsigned int reg; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + unsigned int reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size, + struct clk *parent) +{ + int i; + + for (i = 0; i < size; i++) + if (parent == clk_arr[i]) + return i; + + return -EINVAL; +} + +static unsigned long +_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit) +{ + int div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div > limit) + div = limit; + + return parent_rate / div; +} + +static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->round_rate(clk->parent, rate); +} + +static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->set_rate(clk->parent, rate); +} + +static unsigned long clk16m_get_rate(struct clk *clk) +{ + return 16000000; +} + +static struct clk clk16m = { + .get_rate = clk16m_get_rate, + .enable = _clk_enable, + .enable_reg = CCM_CSCR, + .enable_shift = CCM_CSCR_OSC_EN_SHIFT, + .disable = _clk_disable, +}; + +/* in Hz */ +static unsigned long clk32_rate; + +static unsigned long clk32_get_rate(struct clk *clk) +{ + return clk32_rate; +} + +static struct clk clk32 = { + .get_rate = clk32_get_rate, +}; + +static unsigned long clk32_premult_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) * 512; +} + +static struct clk clk32_premult = { + .parent = &clk32, + .get_rate = clk32_premult_get_rate, +}; + +static const struct clk *prem_clk_clocks[] = { + &clk32_premult, + &clk16m, +}; + +static int prem_clk_set_parent(struct clk *clk, struct clk *parent) +{ + int i; + unsigned int reg = __raw_readl(CCM_CSCR); + + i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks), + parent); + + switch (i) { + case 0: + reg &= ~CCM_CSCR_SYSTEM_SEL; + break; + case 1: + reg |= CCM_CSCR_SYSTEM_SEL; + break; + default: + return i; + } + + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static struct clk prem_clk = { + .set_parent = prem_clk_set_parent, +}; + +static unsigned long system_clk_get_rate(struct clk *clk) +{ + return mxc_decode_pll(__raw_readl(CCM_SPCTL0), + clk_get_rate(clk->parent)); +} + +static struct clk system_clk = { + .parent = &prem_clk, + .get_rate = system_clk_get_rate, +}; + +static unsigned long mcu_clk_get_rate(struct clk *clk) +{ + return mxc_decode_pll(__raw_readl(CCM_MPCTL0), + clk_get_rate(clk->parent)); +} + +static struct clk mcu_clk = { + .parent = &clk32_premult, + .get_rate = mcu_clk_get_rate, +}; + +static unsigned long fclk_get_rate(struct clk *clk) +{ + unsigned long fclk = clk_get_rate(clk->parent); + + if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC) + fclk /= 2; + + return fclk; +} + +static struct clk fclk = { + .parent = &mcu_clk, + .get_rate = fclk_get_rate, +}; + +/* + * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA ) + */ +static unsigned long hclk_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & + CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1); +} + +static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 16); +} + +static int hclk_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 16 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_CSCR); + reg &= ~CCM_CSCR_BCLK_MASK; + reg |= div << CCM_CSCR_BCLK_OFFSET; + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static struct clk hclk = { + .parent = &system_clk, + .get_rate = hclk_get_rate, + .round_rate = hclk_round_rate, + .set_rate = hclk_set_rate, +}; + +static unsigned long clk48m_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) & + CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1); +} + +static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 8); +} + +static int clk48m_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 8 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_CSCR); + reg &= ~CCM_CSCR_USB_MASK; + reg |= div << CCM_CSCR_USB_OFFSET; + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static struct clk clk48m = { + .parent = &system_clk, + .get_rate = clk48m_get_rate, + .round_rate = clk48m_round_rate, + .set_rate = clk48m_set_rate, +}; + +/* + * get peripheral clock 1 ( UART[12], Timer[12], PWM ) + */ +static unsigned long perclk1_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & + CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1); +} + +static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 16); +} + +static int perclk1_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 16 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_PCDR); + reg &= ~CCM_PCDR_PCLK1_MASK; + reg |= div << CCM_PCDR_PCLK1_OFFSET; + __raw_writel(reg, CCM_PCDR); + + return 0; +} + +/* + * get peripheral clock 2 ( LCD, SD, SPI[12] ) + */ +static unsigned long perclk2_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & + CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1); +} + +static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 16); +} + +static int perclk2_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 16 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_PCDR); + reg &= ~CCM_PCDR_PCLK2_MASK; + reg |= div << CCM_PCDR_PCLK2_OFFSET; + __raw_writel(reg, CCM_PCDR); + + return 0; +} + +/* + * get peripheral clock 3 ( SSI ) + */ +static unsigned long perclk3_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) & + CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1); +} + +static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_simple_round_rate(clk, rate, 128); +} + +static int perclk3_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned int div; + unsigned int reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 128 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_PCDR); + reg &= ~CCM_PCDR_PCLK3_MASK; + reg |= div << CCM_PCDR_PCLK3_OFFSET; + __raw_writel(reg, CCM_PCDR); + + return 0; +} + +static struct clk perclk[] = { + { + .id = 0, + .parent = &system_clk, + .get_rate = perclk1_get_rate, + .round_rate = perclk1_round_rate, + .set_rate = perclk1_set_rate, + }, { + .id = 1, + .parent = &system_clk, + .get_rate = perclk2_get_rate, + .round_rate = perclk2_round_rate, + .set_rate = perclk2_set_rate, + }, { + .id = 2, + .parent = &system_clk, + .get_rate = perclk3_get_rate, + .round_rate = perclk3_round_rate, + .set_rate = perclk3_set_rate, + } +}; + +static const struct clk *clko_clocks[] = { + &perclk[0], + &hclk, + &clk48m, + &clk16m, + &prem_clk, + &fclk, +}; + +static int clko_set_parent(struct clk *clk, struct clk *parent) +{ + int i; + unsigned int reg; + + i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent); + if (i < 0) + return i; + + reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK; + reg |= i << CCM_CSCR_CLKO_OFFSET; + __raw_writel(reg, CCM_CSCR); + + if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) { + clk->set_rate = _clk_parent_set_rate; + clk->round_rate = _clk_parent_round_rate; + } else { + clk->set_rate = NULL; + clk->round_rate = NULL; + } + + return 0; +} + +static struct clk clko_clk = { + .set_parent = clko_set_parent, +}; + +static struct clk dma_clk = { + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk csi_clk = { + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk mma_clk = { + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk usbd_clk = { + .parent = &clk48m, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + .enable = _clk_enable, + .enable_reg = SCM_GCCR, + .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk gpt_clk = { + .parent = &perclk[0], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk uart_clk = { + .parent = &perclk[0], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk i2c_clk = { + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk spi_clk = { + .parent = &perclk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk sdhc_clk = { + .parent = &perclk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk lcdc_clk = { + .parent = &perclk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk mshc_clk = { + .parent = &hclk, + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk ssi_clk = { + .parent = &perclk[2], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, +}; + +static struct clk rtc_clk = { + .parent = &clk32, +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, +static struct clk_lookup lookups[] __initdata = { + _REGISTER_CLOCK(NULL, "dma", dma_clk) + _REGISTER_CLOCK("mx1-camera.0", NULL, csi_clk) + _REGISTER_CLOCK(NULL, "mma", mma_clk) + _REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk) + _REGISTER_CLOCK(NULL, "gpt", gpt_clk) + _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) + _REGISTER_CLOCK("imx1-cspi.0", NULL, spi_clk) + _REGISTER_CLOCK("imx1-cspi.1", NULL, spi_clk) + _REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk) + _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) + _REGISTER_CLOCK(NULL, "mshc", mshc_clk) + _REGISTER_CLOCK(NULL, "ssi", ssi_clk) + _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk) +}; + +int __init mx1_clocks_init(unsigned long fref) +{ + unsigned int reg; + + /* disable clocks we are able to */ + __raw_writel(0, SCM_GCCR); + + clk32_rate = fref; + reg = __raw_readl(CCM_CSCR); + + /* detect clock reference for system PLL */ + if (reg & CCM_CSCR_SYSTEM_SEL) { + prem_clk.parent = &clk16m; + } else { + /* ensure that oscillator is disabled */ + reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT); + __raw_writel(reg, CCM_CSCR); + prem_clk.parent = &clk32_premult; + } + + /* detect reference for CLKO */ + reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET; + clko_clk.parent = (struct clk *)clko_clocks[reg]; + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + clk_enable(&hclk); + clk_enable(&fclk); + + mxc_timer_init(&gpt_clk, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR), + MX1_TIM1_INT); + + return 0; +} diff --git a/arch/arm/mach-imx/clock-imx21.c b/arch/arm/mach-imx/clock-imx21.c new file mode 100644 index 00000000..bf30a8c7 --- /dev/null +++ b/arch/arm/mach-imx/clock-imx21.c @@ -0,0 +1,1239 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * 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/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/clkdev.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <asm/div64.h> + +#define IO_ADDR_CCM(off) (MX21_IO_ADDRESS(MX21_CCM_BASE_ADDR + (off))) + +/* Register offsets */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_MPCTL1 IO_ADDR_CCM(0x8) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_SPCTL1 IO_ADDR_CCM(0x10) +#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) +#define CCM_PCDR0 IO_ADDR_CCM(0x18) +#define CCM_PCDR1 IO_ADDR_CCM(0x1c) +#define CCM_PCCR0 IO_ADDR_CCM(0x20) +#define CCM_PCCR1 IO_ADDR_CCM(0x24) +#define CCM_CCSR IO_ADDR_CCM(0x28) +#define CCM_PMCTL IO_ADDR_CCM(0x2c) +#define CCM_PMCOUNT IO_ADDR_CCM(0x30) +#define CCM_WKGDCTL IO_ADDR_CCM(0x34) + +#define CCM_CSCR_PRESC_OFFSET 29 +#define CCM_CSCR_PRESC_MASK (0x7 << CCM_CSCR_PRESC_OFFSET) + +#define CCM_CSCR_USB_OFFSET 26 +#define CCM_CSCR_USB_MASK (0x7 << CCM_CSCR_USB_OFFSET) +#define CCM_CSCR_SD_OFFSET 24 +#define CCM_CSCR_SD_MASK (0x3 << CCM_CSCR_SD_OFFSET) +#define CCM_CSCR_SPLLRES (1 << 22) +#define CCM_CSCR_MPLLRES (1 << 21) +#define CCM_CSCR_SSI2_OFFSET 20 +#define CCM_CSCR_SSI2 (1 << CCM_CSCR_SSI2_OFFSET) +#define CCM_CSCR_SSI1_OFFSET 19 +#define CCM_CSCR_SSI1 (1 << CCM_CSCR_SSI1_OFFSET) +#define CCM_CSCR_FIR_OFFSET 18 +#define CCM_CSCR_FIR (1 << CCM_CSCR_FIR_OFFSET) +#define CCM_CSCR_SP (1 << 17) +#define CCM_CSCR_MCU (1 << 16) +#define CCM_CSCR_BCLK_OFFSET 10 +#define CCM_CSCR_BCLK_MASK (0xf << CCM_CSCR_BCLK_OFFSET) +#define CCM_CSCR_IPDIV_OFFSET 9 +#define CCM_CSCR_IPDIV (1 << CCM_CSCR_IPDIV_OFFSET) + +#define CCM_CSCR_OSC26MDIV (1 << 4) +#define CCM_CSCR_OSC26M (1 << 3) +#define CCM_CSCR_FPM (1 << 2) +#define CCM_CSCR_SPEN (1 << 1) +#define CCM_CSCR_MPEN 1 + +#define CCM_MPCTL0_CPLM (1 << 31) +#define CCM_MPCTL0_PD_OFFSET 26 +#define CCM_MPCTL0_PD_MASK (0xf << 26) +#define CCM_MPCTL0_MFD_OFFSET 16 +#define CCM_MPCTL0_MFD_MASK (0x3ff << 16) +#define CCM_MPCTL0_MFI_OFFSET 10 +#define CCM_MPCTL0_MFI_MASK (0xf << 10) +#define CCM_MPCTL0_MFN_OFFSET 0 +#define CCM_MPCTL0_MFN_MASK 0x3ff + +#define CCM_MPCTL1_LF (1 << 15) +#define CCM_MPCTL1_BRMO (1 << 6) + +#define CCM_SPCTL0_CPLM (1 << 31) +#define CCM_SPCTL0_PD_OFFSET 26 +#define CCM_SPCTL0_PD_MASK (0xf << 26) +#define CCM_SPCTL0_MFD_OFFSET 16 +#define CCM_SPCTL0_MFD_MASK (0x3ff << 16) +#define CCM_SPCTL0_MFI_OFFSET 10 +#define CCM_SPCTL0_MFI_MASK (0xf << 10) +#define CCM_SPCTL0_MFN_OFFSET 0 +#define CCM_SPCTL0_MFN_MASK 0x3ff + +#define CCM_SPCTL1_LF (1 << 15) +#define CCM_SPCTL1_BRMO (1 << 6) + +#define CCM_OSC26MCTL_PEAK_OFFSET 16 +#define CCM_OSC26MCTL_PEAK_MASK (0x3 << 16) +#define CCM_OSC26MCTL_AGC_OFFSET 8 +#define CCM_OSC26MCTL_AGC_MASK (0x3f << 8) +#define CCM_OSC26MCTL_ANATEST_OFFSET 0 +#define CCM_OSC26MCTL_ANATEST_MASK 0x3f + +#define CCM_PCDR0_SSI2BAUDDIV_OFFSET 26 +#define CCM_PCDR0_SSI2BAUDDIV_MASK (0x3f << 26) +#define CCM_PCDR0_SSI1BAUDDIV_OFFSET 16 +#define CCM_PCDR0_SSI1BAUDDIV_MASK (0x3f << 16) +#define CCM_PCDR0_NFCDIV_OFFSET 12 +#define CCM_PCDR0_NFCDIV_MASK (0xf << 12) +#define CCM_PCDR0_48MDIV_OFFSET 5 +#define CCM_PCDR0_48MDIV_MASK (0x7 << CCM_PCDR0_48MDIV_OFFSET) +#define CCM_PCDR0_FIRIDIV_OFFSET 0 +#define CCM_PCDR0_FIRIDIV_MASK 0x1f +#define CCM_PCDR1_PERDIV4_OFFSET 24 +#define CCM_PCDR1_PERDIV4_MASK (0x3f << 24) +#define CCM_PCDR1_PERDIV3_OFFSET 16 +#define CCM_PCDR1_PERDIV3_MASK (0x3f << 16) +#define CCM_PCDR1_PERDIV2_OFFSET 8 +#define CCM_PCDR1_PERDIV2_MASK (0x3f << 8) +#define CCM_PCDR1_PERDIV1_OFFSET 0 +#define CCM_PCDR1_PERDIV1_MASK 0x3f + +#define CCM_PCCR_HCLK_CSI_OFFSET 31 +#define CCM_PCCR_HCLK_CSI_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_DMA_OFFSET 30 +#define CCM_PCCR_HCLK_DMA_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_BROM_OFFSET 28 +#define CCM_PCCR_HCLK_BROM_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_EMMA_OFFSET 27 +#define CCM_PCCR_HCLK_EMMA_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_LCDC_OFFSET 26 +#define CCM_PCCR_HCLK_LCDC_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_SLCDC_OFFSET 25 +#define CCM_PCCR_HCLK_SLCDC_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_USBOTG_OFFSET 24 +#define CCM_PCCR_HCLK_USBOTG_REG CCM_PCCR0 +#define CCM_PCCR_HCLK_BMI_OFFSET 23 +#define CCM_PCCR_BMI_MASK (1 << CCM_PCCR_BMI_MASK) +#define CCM_PCCR_HCLK_BMI_REG CCM_PCCR0 +#define CCM_PCCR_PERCLK4_OFFSET 22 +#define CCM_PCCR_PERCLK4_REG CCM_PCCR0 +#define CCM_PCCR_SLCDC_OFFSET 21 +#define CCM_PCCR_SLCDC_REG CCM_PCCR0 +#define CCM_PCCR_FIRI_BAUD_OFFSET 20 +#define CCM_PCCR_FIRI_BAUD_MASK (1 << CCM_PCCR_FIRI_BAUD_MASK) +#define CCM_PCCR_FIRI_BAUD_REG CCM_PCCR0 +#define CCM_PCCR_NFC_OFFSET 19 +#define CCM_PCCR_NFC_REG CCM_PCCR0 +#define CCM_PCCR_LCDC_OFFSET 18 +#define CCM_PCCR_LCDC_REG CCM_PCCR0 +#define CCM_PCCR_SSI1_BAUD_OFFSET 17 +#define CCM_PCCR_SSI1_BAUD_REG CCM_PCCR0 +#define CCM_PCCR_SSI2_BAUD_OFFSET 16 +#define CCM_PCCR_SSI2_BAUD_REG CCM_PCCR0 +#define CCM_PCCR_EMMA_OFFSET 15 +#define CCM_PCCR_EMMA_REG CCM_PCCR0 +#define CCM_PCCR_USBOTG_OFFSET 14 +#define CCM_PCCR_USBOTG_REG CCM_PCCR0 +#define CCM_PCCR_DMA_OFFSET 13 +#define CCM_PCCR_DMA_REG CCM_PCCR0 +#define CCM_PCCR_I2C1_OFFSET 12 +#define CCM_PCCR_I2C1_REG CCM_PCCR0 +#define CCM_PCCR_GPIO_OFFSET 11 +#define CCM_PCCR_GPIO_REG CCM_PCCR0 +#define CCM_PCCR_SDHC2_OFFSET 10 +#define CCM_PCCR_SDHC2_REG CCM_PCCR0 +#define CCM_PCCR_SDHC1_OFFSET 9 +#define CCM_PCCR_SDHC1_REG CCM_PCCR0 +#define CCM_PCCR_FIRI_OFFSET 8 +#define CCM_PCCR_FIRI_MASK (1 << CCM_PCCR_BAUD_MASK) +#define CCM_PCCR_FIRI_REG CCM_PCCR0 +#define CCM_PCCR_SSI2_IPG_OFFSET 7 +#define CCM_PCCR_SSI2_REG CCM_PCCR0 +#define CCM_PCCR_SSI1_IPG_OFFSET 6 +#define CCM_PCCR_SSI1_REG CCM_PCCR0 +#define CCM_PCCR_CSPI2_OFFSET 5 +#define CCM_PCCR_CSPI2_REG CCM_PCCR0 +#define CCM_PCCR_CSPI1_OFFSET 4 +#define CCM_PCCR_CSPI1_REG CCM_PCCR0 +#define CCM_PCCR_UART4_OFFSET 3 +#define CCM_PCCR_UART4_REG CCM_PCCR0 +#define CCM_PCCR_UART3_OFFSET 2 +#define CCM_PCCR_UART3_REG CCM_PCCR0 +#define CCM_PCCR_UART2_OFFSET 1 +#define CCM_PCCR_UART2_REG CCM_PCCR0 +#define CCM_PCCR_UART1_OFFSET 0 +#define CCM_PCCR_UART1_REG CCM_PCCR0 + +#define CCM_PCCR_OWIRE_OFFSET 31 +#define CCM_PCCR_OWIRE_REG CCM_PCCR1 +#define CCM_PCCR_KPP_OFFSET 30 +#define CCM_PCCR_KPP_REG CCM_PCCR1 +#define CCM_PCCR_RTC_OFFSET 29 +#define CCM_PCCR_RTC_REG CCM_PCCR1 +#define CCM_PCCR_PWM_OFFSET 28 +#define CCM_PCCR_PWM_REG CCM_PCCR1 +#define CCM_PCCR_GPT3_OFFSET 27 +#define CCM_PCCR_GPT3_REG CCM_PCCR1 +#define CCM_PCCR_GPT2_OFFSET 26 +#define CCM_PCCR_GPT2_REG CCM_PCCR1 +#define CCM_PCCR_GPT1_OFFSET 25 +#define CCM_PCCR_GPT1_REG CCM_PCCR1 +#define CCM_PCCR_WDT_OFFSET 24 +#define CCM_PCCR_WDT_REG CCM_PCCR1 +#define CCM_PCCR_CSPI3_OFFSET 23 +#define CCM_PCCR_CSPI3_REG CCM_PCCR1 + +#define CCM_PCCR_CSPI1_MASK (1 << CCM_PCCR_CSPI1_OFFSET) +#define CCM_PCCR_CSPI2_MASK (1 << CCM_PCCR_CSPI2_OFFSET) +#define CCM_PCCR_CSPI3_MASK (1 << CCM_PCCR_CSPI3_OFFSET) +#define CCM_PCCR_DMA_MASK (1 << CCM_PCCR_DMA_OFFSET) +#define CCM_PCCR_EMMA_MASK (1 << CCM_PCCR_EMMA_OFFSET) +#define CCM_PCCR_GPIO_MASK (1 << CCM_PCCR_GPIO_OFFSET) +#define CCM_PCCR_GPT1_MASK (1 << CCM_PCCR_GPT1_OFFSET) +#define CCM_PCCR_GPT2_MASK (1 << CCM_PCCR_GPT2_OFFSET) +#define CCM_PCCR_GPT3_MASK (1 << CCM_PCCR_GPT3_OFFSET) +#define CCM_PCCR_HCLK_BROM_MASK (1 << CCM_PCCR_HCLK_BROM_OFFSET) +#define CCM_PCCR_HCLK_CSI_MASK (1 << CCM_PCCR_HCLK_CSI_OFFSET) +#define CCM_PCCR_HCLK_DMA_MASK (1 << CCM_PCCR_HCLK_DMA_OFFSET) +#define CCM_PCCR_HCLK_EMMA_MASK (1 << CCM_PCCR_HCLK_EMMA_OFFSET) +#define CCM_PCCR_HCLK_LCDC_MASK (1 << CCM_PCCR_HCLK_LCDC_OFFSET) +#define CCM_PCCR_HCLK_SLCDC_MASK (1 << CCM_PCCR_HCLK_SLCDC_OFFSET) +#define CCM_PCCR_HCLK_USBOTG_MASK (1 << CCM_PCCR_HCLK_USBOTG_OFFSET) +#define CCM_PCCR_I2C1_MASK (1 << CCM_PCCR_I2C1_OFFSET) +#define CCM_PCCR_KPP_MASK (1 << CCM_PCCR_KPP_OFFSET) +#define CCM_PCCR_LCDC_MASK (1 << CCM_PCCR_LCDC_OFFSET) +#define CCM_PCCR_NFC_MASK (1 << CCM_PCCR_NFC_OFFSET) +#define CCM_PCCR_OWIRE_MASK (1 << CCM_PCCR_OWIRE_OFFSET) +#define CCM_PCCR_PERCLK4_MASK (1 << CCM_PCCR_PERCLK4_OFFSET) +#define CCM_PCCR_PWM_MASK (1 << CCM_PCCR_PWM_OFFSET) +#define CCM_PCCR_RTC_MASK (1 << CCM_PCCR_RTC_OFFSET) +#define CCM_PCCR_SDHC1_MASK (1 << CCM_PCCR_SDHC1_OFFSET) +#define CCM_PCCR_SDHC2_MASK (1 << CCM_PCCR_SDHC2_OFFSET) +#define CCM_PCCR_SLCDC_MASK (1 << CCM_PCCR_SLCDC_OFFSET) +#define CCM_PCCR_SSI1_BAUD_MASK (1 << CCM_PCCR_SSI1_BAUD_OFFSET) +#define CCM_PCCR_SSI1_IPG_MASK (1 << CCM_PCCR_SSI1_IPG_OFFSET) +#define CCM_PCCR_SSI2_BAUD_MASK (1 << CCM_PCCR_SSI2_BAUD_OFFSET) +#define CCM_PCCR_SSI2_IPG_MASK (1 << CCM_PCCR_SSI2_IPG_OFFSET) +#define CCM_PCCR_UART1_MASK (1 << CCM_PCCR_UART1_OFFSET) +#define CCM_PCCR_UART2_MASK (1 << CCM_PCCR_UART2_OFFSET) +#define CCM_PCCR_UART3_MASK (1 << CCM_PCCR_UART3_OFFSET) +#define CCM_PCCR_UART4_MASK (1 << CCM_PCCR_UART4_OFFSET) +#define CCM_PCCR_USBOTG_MASK (1 << CCM_PCCR_USBOTG_OFFSET) +#define CCM_PCCR_WDT_MASK (1 << CCM_PCCR_WDT_OFFSET) + +#define CCM_CCSR_32KSR (1 << 15) + +#define CCM_CCSR_CLKMODE1 (1 << 9) +#define CCM_CCSR_CLKMODE0 (1 << 8) + +#define CCM_CCSR_CLKOSEL_OFFSET 0 +#define CCM_CCSR_CLKOSEL_MASK 0x1f + +#define SYS_FMCR 0x14 /* Functional Muxing Control Reg */ +#define SYS_CHIP_ID 0x00 /* The offset of CHIP ID register */ + +static int _clk_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static unsigned long _clk_generic_round_rate(struct clk *clk, + unsigned long rate, + u32 max_divisor) +{ + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div > max_divisor) + div = max_divisor; + + return parent_rate / div; +} + +static int _clk_spll_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(CCM_CSCR); + reg |= CCM_CSCR_SPEN; + __raw_writel(reg, CCM_CSCR); + + while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0) + ; + return 0; +} + +static void _clk_spll_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(CCM_CSCR); + reg &= ~CCM_CSCR_SPEN; + __raw_writel(reg, CCM_CSCR); +} + + +#define CSCR() (__raw_readl(CCM_CSCR)) +#define PCDR0() (__raw_readl(CCM_PCDR0)) +#define PCDR1() (__raw_readl(CCM_PCDR1)) + +static unsigned long _clk_perclkx_round_rate(struct clk *clk, + unsigned long rate) +{ + return _clk_generic_round_rate(clk, rate, 64); +} + +static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (clk->id < 0 || clk->id > 3) + return -EINVAL; + + div = parent_rate / rate; + if (div > 64 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + div--; + + reg = + __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK << + (clk->id << 3)); + reg |= div << (clk->id << 3); + __raw_writel(reg, CCM_PCDR1); + + return 0; +} + +static unsigned long _clk_usb_recalc(struct clk *clk) +{ + unsigned long usb_pdf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET; + + return parent_rate / (usb_pdf + 1U); +} + +static unsigned long _clk_usb_round_rate(struct clk *clk, + unsigned long rate) +{ + return _clk_generic_round_rate(clk, rate, 8); +} + +static int _clk_usb_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (div > 8 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + div--; + + reg = CSCR() & ~CCM_CSCR_USB_MASK; + reg |= div << CCM_CSCR_USB_OFFSET; + __raw_writel(reg, CCM_CSCR); + + return 0; +} + +static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf) +{ + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */ + + return 2UL * parent_rate / pdf; +} + +static unsigned long _clk_ssi1_recalc(struct clk *clk) +{ + return _clk_ssix_recalc(clk, + (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK) + >> CCM_PCDR0_SSI1BAUDDIV_OFFSET); +} + +static unsigned long _clk_ssi2_recalc(struct clk *clk) +{ + return _clk_ssix_recalc(clk, + (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >> + CCM_PCDR0_SSI2BAUDDIV_OFFSET); +} + +static unsigned long _clk_nfc_recalc(struct clk *clk) +{ + unsigned long nfc_pdf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + nfc_pdf = (PCDR0() & CCM_PCDR0_NFCDIV_MASK) + >> CCM_PCDR0_NFCDIV_OFFSET; + + return parent_rate / (nfc_pdf + 1); +} + +static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->round_rate(clk->parent, rate); +} + +static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->set_rate(clk->parent, rate); +} + +static unsigned long external_high_reference; /* in Hz */ + +static unsigned long get_high_reference_clock_rate(struct clk *clk) +{ + return external_high_reference; +} + +/* + * the high frequency external clock reference + * Default case is 26MHz. + */ +static struct clk ckih_clk = { + .get_rate = get_high_reference_clock_rate, +}; + +static unsigned long external_low_reference; /* in Hz */ + +static unsigned long get_low_reference_clock_rate(struct clk *clk) +{ + return external_low_reference; +} + +/* + * the low frequency external clock reference + * Default case is 32.768kHz. + */ +static struct clk ckil_clk = { + .get_rate = get_low_reference_clock_rate, +}; + + +static unsigned long _clk_fpm_recalc(struct clk *clk) +{ + return clk_get_rate(clk->parent) * 512; +} + +/* Output of frequency pre multiplier */ +static struct clk fpm_clk = { + .parent = &ckil_clk, + .get_rate = _clk_fpm_recalc, +}; + +static unsigned long get_mpll_clk(struct clk *clk) +{ + uint32_t reg; + unsigned long ref_clk; + unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; + unsigned long long temp; + + ref_clk = clk_get_rate(clk->parent); + + reg = __raw_readl(CCM_MPCTL0); + pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET; + mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET; + mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET; + mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET; + + mfi = (mfi <= 5) ? 5 : mfi; + temp = 2LL * ref_clk * mfn; + do_div(temp, mfd + 1); + temp = 2LL * ref_clk * mfi + temp; + do_div(temp, pdf + 1); + + return (unsigned long)temp; +} + +static struct clk mpll_clk = { + .parent = &ckih_clk, + .get_rate = get_mpll_clk, +}; + +static unsigned long _clk_fclk_get_rate(struct clk *clk) +{ + unsigned long parent_rate; + u32 div; + + div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET; + parent_rate = clk_get_rate(clk->parent); + + return parent_rate / (div+1); +} + +static struct clk fclk_clk = { + .parent = &mpll_clk, + .get_rate = _clk_fclk_get_rate +}; + +static unsigned long get_spll_clk(struct clk *clk) +{ + uint32_t reg; + unsigned long ref_clk; + unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; + unsigned long long temp; + + ref_clk = clk_get_rate(clk->parent); + + reg = __raw_readl(CCM_SPCTL0); + pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET; + mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET; + mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET; + mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET; + + mfi = (mfi <= 5) ? 5 : mfi; + temp = 2LL * ref_clk * mfn; + do_div(temp, mfd + 1); + temp = 2LL * ref_clk * mfi + temp; + do_div(temp, pdf + 1); + + return (unsigned long)temp; +} + +static struct clk spll_clk = { + .parent = &ckih_clk, + .get_rate = get_spll_clk, + .enable = _clk_spll_enable, + .disable = _clk_spll_disable, +}; + +static unsigned long get_hclk_clk(struct clk *clk) +{ + unsigned long rate; + unsigned long bclk_pdf; + + bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK) + >> CCM_CSCR_BCLK_OFFSET; + + rate = clk_get_rate(clk->parent); + return rate / (bclk_pdf + 1); +} + +static struct clk hclk_clk = { + .parent = &fclk_clk, + .get_rate = get_hclk_clk, +}; + +static unsigned long get_ipg_clk(struct clk *clk) +{ + unsigned long rate; + unsigned long ipg_pdf; + + ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET; + + rate = clk_get_rate(clk->parent); + return rate / (ipg_pdf + 1); +} + +static struct clk ipg_clk = { + .parent = &hclk_clk, + .get_rate = get_ipg_clk, +}; + +static unsigned long _clk_perclkx_recalc(struct clk *clk) +{ + unsigned long perclk_pdf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (clk->id < 0 || clk->id > 3) + return 0; + + perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK; + + return parent_rate / (perclk_pdf + 1); +} + +static struct clk per_clk[] = { + { + .id = 0, + .parent = &mpll_clk, + .get_rate = _clk_perclkx_recalc, + }, { + .id = 1, + .parent = &mpll_clk, + .get_rate = _clk_perclkx_recalc, + }, { + .id = 2, + .parent = &mpll_clk, + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .get_rate = _clk_perclkx_recalc, + /* Enable/Disable done via lcd_clkc[1] */ + }, { + .id = 3, + .parent = &mpll_clk, + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .get_rate = _clk_perclkx_recalc, + /* Enable/Disable done via csi_clk[1] */ + }, +}; + +static struct clk uart_ipg_clk[]; + +static struct clk uart_clk[] = { + { + .id = 0, + .parent = &per_clk[0], + .secondary = &uart_ipg_clk[0], + }, { + .id = 1, + .parent = &per_clk[0], + .secondary = &uart_ipg_clk[1], + }, { + .id = 2, + .parent = &per_clk[0], + .secondary = &uart_ipg_clk[2], + }, { + .id = 3, + .parent = &per_clk[0], + .secondary = &uart_ipg_clk[3], + }, +}; + +static struct clk uart_ipg_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_UART1_REG, + .enable_shift = CCM_PCCR_UART1_OFFSET, + .disable = _clk_disable, + }, { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_UART2_REG, + .enable_shift = CCM_PCCR_UART2_OFFSET, + .disable = _clk_disable, + }, { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_UART3_REG, + .enable_shift = CCM_PCCR_UART3_OFFSET, + .disable = _clk_disable, + }, { + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_UART4_REG, + .enable_shift = CCM_PCCR_UART4_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk gpt_ipg_clk[]; + +static struct clk gpt_clk[] = { + { + .id = 0, + .parent = &per_clk[0], + .secondary = &gpt_ipg_clk[0], + }, { + .id = 1, + .parent = &per_clk[0], + .secondary = &gpt_ipg_clk[1], + }, { + .id = 2, + .parent = &per_clk[0], + .secondary = &gpt_ipg_clk[2], + }, +}; + +static struct clk gpt_ipg_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_GPT1_REG, + .enable_shift = CCM_PCCR_GPT1_OFFSET, + .disable = _clk_disable, + }, { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_GPT2_REG, + .enable_shift = CCM_PCCR_GPT2_OFFSET, + .disable = _clk_disable, + }, { + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_GPT3_REG, + .enable_shift = CCM_PCCR_GPT3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk pwm_clk[] = { + { + .parent = &per_clk[0], + .secondary = &pwm_clk[1], + }, { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_PWM_REG, + .enable_shift = CCM_PCCR_PWM_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk sdhc_ipg_clk[]; + +static struct clk sdhc_clk[] = { + { + .id = 0, + .parent = &per_clk[1], + .secondary = &sdhc_ipg_clk[0], + }, { + .id = 1, + .parent = &per_clk[1], + .secondary = &sdhc_ipg_clk[1], + }, +}; + +static struct clk sdhc_ipg_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SDHC1_REG, + .enable_shift = CCM_PCCR_SDHC1_OFFSET, + .disable = _clk_disable, + }, { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SDHC2_REG, + .enable_shift = CCM_PCCR_SDHC2_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk cspi_ipg_clk[]; + +static struct clk cspi_clk[] = { + { + .id = 0, + .parent = &per_clk[1], + .secondary = &cspi_ipg_clk[0], + }, { + .id = 1, + .parent = &per_clk[1], + .secondary = &cspi_ipg_clk[1], + }, { + .id = 2, + .parent = &per_clk[1], + .secondary = &cspi_ipg_clk[2], + }, +}; + +static struct clk cspi_ipg_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_CSPI1_REG, + .enable_shift = CCM_PCCR_CSPI1_OFFSET, + .disable = _clk_disable, + }, { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_CSPI2_REG, + .enable_shift = CCM_PCCR_CSPI2_OFFSET, + .disable = _clk_disable, + }, { + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_CSPI3_REG, + .enable_shift = CCM_PCCR_CSPI3_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk lcdc_clk[] = { + { + .parent = &per_clk[2], + .secondary = &lcdc_clk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + }, { + .parent = &ipg_clk, + .secondary = &lcdc_clk[2], + .enable = _clk_enable, + .enable_reg = CCM_PCCR_LCDC_REG, + .enable_shift = CCM_PCCR_LCDC_OFFSET, + .disable = _clk_disable, + }, { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_LCDC_REG, + .enable_shift = CCM_PCCR_HCLK_LCDC_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk csi_clk[] = { + { + .parent = &per_clk[3], + .secondary = &csi_clk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate, + }, { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_CSI_REG, + .enable_shift = CCM_PCCR_HCLK_CSI_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk usb_clk[] = { + { + .parent = &spll_clk, + .secondary = &usb_clk[1], + .get_rate = _clk_usb_recalc, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_USBOTG_REG, + .enable_shift = CCM_PCCR_USBOTG_OFFSET, + .disable = _clk_disable, + .round_rate = _clk_usb_round_rate, + .set_rate = _clk_usb_set_rate, + }, { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_USBOTG_REG, + .enable_shift = CCM_PCCR_HCLK_USBOTG_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk ssi_ipg_clk[]; + +static struct clk ssi_clk[] = { + { + .id = 0, + .parent = &mpll_clk, + .secondary = &ssi_ipg_clk[0], + .get_rate = _clk_ssi1_recalc, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SSI1_BAUD_REG, + .enable_shift = CCM_PCCR_SSI1_BAUD_OFFSET, + .disable = _clk_disable, + }, { + .id = 1, + .parent = &mpll_clk, + .secondary = &ssi_ipg_clk[1], + .get_rate = _clk_ssi2_recalc, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SSI2_BAUD_REG, + .enable_shift = CCM_PCCR_SSI2_BAUD_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk ssi_ipg_clk[] = { + { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SSI1_REG, + .enable_shift = CCM_PCCR_SSI1_IPG_OFFSET, + .disable = _clk_disable, + }, { + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SSI2_REG, + .enable_shift = CCM_PCCR_SSI2_IPG_OFFSET, + .disable = _clk_disable, + }, +}; + + +static struct clk nfc_clk = { + .parent = &fclk_clk, + .get_rate = _clk_nfc_recalc, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_NFC_REG, + .enable_shift = CCM_PCCR_NFC_OFFSET, + .disable = _clk_disable, +}; + +static struct clk dma_clk[] = { + { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_DMA_REG, + .enable_shift = CCM_PCCR_DMA_OFFSET, + .disable = _clk_disable, + .secondary = &dma_clk[1], + }, { + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_DMA_REG, + .enable_shift = CCM_PCCR_HCLK_DMA_OFFSET, + .disable = _clk_disable, + }, +}; + +static struct clk brom_clk = { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_BROM_REG, + .enable_shift = CCM_PCCR_HCLK_BROM_OFFSET, + .disable = _clk_disable, +}; + +static struct clk emma_clk[] = { + { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_EMMA_REG, + .enable_shift = CCM_PCCR_EMMA_OFFSET, + .disable = _clk_disable, + .secondary = &emma_clk[1], + }, { + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_EMMA_REG, + .enable_shift = CCM_PCCR_HCLK_EMMA_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk slcdc_clk[] = { + { + .parent = &hclk_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_SLCDC_REG, + .enable_shift = CCM_PCCR_SLCDC_OFFSET, + .disable = _clk_disable, + .secondary = &slcdc_clk[1], + }, { + .enable = _clk_enable, + .enable_reg = CCM_PCCR_HCLK_SLCDC_REG, + .enable_shift = CCM_PCCR_HCLK_SLCDC_OFFSET, + .disable = _clk_disable, + } +}; + +static struct clk wdog_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_WDT_REG, + .enable_shift = CCM_PCCR_WDT_OFFSET, + .disable = _clk_disable, +}; + +static struct clk gpio_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_GPIO_REG, + .enable_shift = CCM_PCCR_GPIO_OFFSET, + .disable = _clk_disable, +}; + +static struct clk i2c_clk = { + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_I2C1_REG, + .enable_shift = CCM_PCCR_I2C1_OFFSET, + .disable = _clk_disable, +}; + +static struct clk kpp_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_KPP_REG, + .enable_shift = CCM_PCCR_KPP_OFFSET, + .disable = _clk_disable, +}; + +static struct clk owire_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_OWIRE_REG, + .enable_shift = CCM_PCCR_OWIRE_OFFSET, + .disable = _clk_disable, +}; + +static struct clk rtc_clk = { + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = CCM_PCCR_RTC_REG, + .enable_shift = CCM_PCCR_RTC_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate) +{ + return _clk_generic_round_rate(clk, rate, 8); +} + +static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 8 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + div--; + + reg = __raw_readl(CCM_PCDR0); + + if (clk->parent == &usb_clk[0]) { + reg &= ~CCM_PCDR0_48MDIV_MASK; + reg |= div << CCM_PCDR0_48MDIV_OFFSET; + } + __raw_writel(reg, CCM_PCDR0); + + return 0; +} + +static unsigned long _clk_clko_recalc(struct clk *clk) +{ + u32 div = 0; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (clk->parent == &usb_clk[0]) /* 48M */ + div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_48MDIV_MASK + >> CCM_PCDR0_48MDIV_OFFSET; + div++; + + return parent_rate / div; +} + +static struct clk clko_clk; + +static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK; + + if (parent == &ckil_clk) + reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &fpm_clk) + reg |= 1 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &ckih_clk) + reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == mpll_clk.parent) + reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == spll_clk.parent) + reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &mpll_clk) + reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &spll_clk) + reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &fclk_clk) + reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &hclk_clk) + reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &ipg_clk) + reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &per_clk[0]) + reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &per_clk[1]) + reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &per_clk[2]) + reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &per_clk[3]) + reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &ssi_clk[0]) + reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &ssi_clk[1]) + reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &nfc_clk) + reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &usb_clk[0]) + reg |= 0x14 << CCM_CCSR_CLKOSEL_OFFSET; + else if (parent == &clko_clk) + reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET; + else + return -EINVAL; + + __raw_writel(reg, CCM_CCSR); + + return 0; +} + +static struct clk clko_clk = { + .get_rate = _clk_clko_recalc, + .set_rate = _clk_clko_set_rate, + .round_rate = _clk_clko_round_rate, + .set_parent = _clk_clko_set_parent, +}; + + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, +static struct clk_lookup lookups[] = { +/* It's unlikely that any driver wants one of them directly: + _REGISTER_CLOCK(NULL, "ckih", ckih_clk) + _REGISTER_CLOCK(NULL, "ckil", ckil_clk) + _REGISTER_CLOCK(NULL, "fpm", fpm_clk) + _REGISTER_CLOCK(NULL, "mpll", mpll_clk) + _REGISTER_CLOCK(NULL, "spll", spll_clk) + _REGISTER_CLOCK(NULL, "fclk", fclk_clk) + _REGISTER_CLOCK(NULL, "hclk", hclk_clk) + _REGISTER_CLOCK(NULL, "ipg", ipg_clk) +*/ + _REGISTER_CLOCK(NULL, "perclk1", per_clk[0]) + _REGISTER_CLOCK(NULL, "perclk2", per_clk[1]) + _REGISTER_CLOCK(NULL, "perclk3", per_clk[2]) + _REGISTER_CLOCK(NULL, "perclk4", per_clk[3]) + _REGISTER_CLOCK(NULL, "clko", clko_clk) + _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0]) + _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1]) + _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2]) + _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[3]) + _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0]) + _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1]) + _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2]) + _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0]) + _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0]) + _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1]) + _REGISTER_CLOCK("imx21-cspi.0", NULL, cspi_clk[0]) + _REGISTER_CLOCK("imx21-cspi.1", NULL, cspi_clk[1]) + _REGISTER_CLOCK("imx21-cspi.2", NULL, cspi_clk[2]) + _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0]) + _REGISTER_CLOCK(NULL, "csi", csi_clk[0]) + _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0]) + _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0]) + _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1]) + _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) + _REGISTER_CLOCK(NULL, "dma", dma_clk[0]) + _REGISTER_CLOCK(NULL, "brom", brom_clk) + _REGISTER_CLOCK(NULL, "emma", emma_clk[0]) + _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0]) + _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) + _REGISTER_CLOCK(NULL, "gpio", gpio_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) + _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk) + _REGISTER_CLOCK(NULL, "owire", owire_clk) + _REGISTER_CLOCK(NULL, "rtc", rtc_clk) +}; + +/* + * must be called very early to get information about the + * available clock rate when the timer framework starts + */ +int __init mx21_clocks_init(unsigned long lref, unsigned long href) +{ + u32 cscr; + + external_low_reference = lref; + external_high_reference = href; + + /* detect clock reference for both system PLL */ + cscr = CSCR(); + if (cscr & CCM_CSCR_MCU) + mpll_clk.parent = &ckih_clk; + else + mpll_clk.parent = &fpm_clk; + + if (cscr & CCM_CSCR_SP) + spll_clk.parent = &ckih_clk; + else + spll_clk.parent = &fpm_clk; + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + /* Turn off all clock gates */ + __raw_writel(0, CCM_PCCR0); + __raw_writel(CCM_PCCR_GPT1_MASK, CCM_PCCR1); + + /* This turns of the serial PLL as well */ + spll_clk.disable(&spll_clk); + + /* This will propagate to all children and init all the clock rates. */ + clk_enable(&per_clk[0]); + clk_enable(&gpio_clk); + +#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) + clk_enable(&uart_clk[0]); +#endif + + mxc_timer_init(&gpt_clk[0], MX21_IO_ADDRESS(MX21_GPT1_BASE_ADDR), + MX21_INT_GPT1); + return 0; +} diff --git a/arch/arm/mach-imx/clock-imx25.c b/arch/arm/mach-imx/clock-imx25.c new file mode 100644 index 00000000..a65838fc --- /dev/null +++ b/arch/arm/mach-imx/clock-imx25.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2009 by Sascha Hauer, Pengutronix + * + * 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/list.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/mx25.h> + +#define CRM_BASE MX25_IO_ADDRESS(MX25_CRM_BASE_ADDR) + +#define CCM_MPCTL 0x00 +#define CCM_UPCTL 0x04 +#define CCM_CCTL 0x08 +#define CCM_CGCR0 0x0C +#define CCM_CGCR1 0x10 +#define CCM_CGCR2 0x14 +#define CCM_PCDR0 0x18 +#define CCM_PCDR1 0x1C +#define CCM_PCDR2 0x20 +#define CCM_PCDR3 0x24 +#define CCM_RCSR 0x28 +#define CCM_CRDR 0x2C +#define CCM_DCVR0 0x30 +#define CCM_DCVR1 0x34 +#define CCM_DCVR2 0x38 +#define CCM_DCVR3 0x3c +#define CCM_LTR0 0x40 +#define CCM_LTR1 0x44 +#define CCM_LTR2 0x48 +#define CCM_LTR3 0x4c + +static unsigned long get_rate_mpll(void) +{ + ulong mpctl = __raw_readl(CRM_BASE + CCM_MPCTL); + + return mxc_decode_pll(mpctl, 24000000); +} + +static unsigned long get_rate_upll(void) +{ + ulong mpctl = __raw_readl(CRM_BASE + CCM_UPCTL); + + return mxc_decode_pll(mpctl, 24000000); +} + +unsigned long get_rate_arm(struct clk *clk) +{ + unsigned long cctl = readl(CRM_BASE + CCM_CCTL); + unsigned long rate = get_rate_mpll(); + + if (cctl & (1 << 14)) + rate = (rate * 3) >> 2; + + return rate / ((cctl >> 30) + 1); +} + +static unsigned long get_rate_ahb(struct clk *clk) +{ + unsigned long cctl = readl(CRM_BASE + CCM_CCTL); + + return get_rate_arm(NULL) / (((cctl >> 28) & 0x3) + 1); +} + +static unsigned long get_rate_ipg(struct clk *clk) +{ + return get_rate_ahb(NULL) >> 1; +} + +static unsigned long get_rate_per(int per) +{ + unsigned long ofs = (per & 0x3) * 8; + unsigned long reg = per & ~0x3; + unsigned long val = (readl(CRM_BASE + CCM_PCDR0 + reg) >> ofs) & 0x3f; + unsigned long fref; + + if (readl(CRM_BASE + 0x64) & (1 << per)) + fref = get_rate_upll(); + else + fref = get_rate_ahb(NULL); + + return fref / (val + 1); +} + +static unsigned long get_rate_uart(struct clk *clk) +{ + return get_rate_per(15); +} + +static unsigned long get_rate_ssi2(struct clk *clk) +{ + return get_rate_per(14); +} + +static unsigned long get_rate_ssi1(struct clk *clk) +{ + return get_rate_per(13); +} + +static unsigned long get_rate_i2c(struct clk *clk) +{ + return get_rate_per(6); +} + +static unsigned long get_rate_nfc(struct clk *clk) +{ + return get_rate_per(8); +} + +static unsigned long get_rate_gpt(struct clk *clk) +{ + return get_rate_per(5); +} + +static unsigned long get_rate_lcdc(struct clk *clk) +{ + return get_rate_per(7); +} + +static unsigned long get_rate_esdhc1(struct clk *clk) +{ + return get_rate_per(3); +} + +static unsigned long get_rate_esdhc2(struct clk *clk) +{ + return get_rate_per(4); +} + +static unsigned long get_rate_csi(struct clk *clk) +{ + return get_rate_per(0); +} + +static unsigned long get_rate_otg(struct clk *clk) +{ + unsigned long cctl = readl(CRM_BASE + CCM_CCTL); + unsigned long rate = get_rate_upll(); + + return (cctl & (1 << 23)) ? 0 : rate / ((0x3F & (cctl >> 16)) + 1); +} + +static int clk_cgcr_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void clk_cgcr_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +#define DEFINE_CLOCK(name, i, er, es, gr, sr, s) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = CRM_BASE + er, \ + .enable_shift = es, \ + .get_rate = gr, \ + .set_rate = sr, \ + .enable = clk_cgcr_enable, \ + .disable = clk_cgcr_disable, \ + .secondary = s, \ + } + +/* + * Note: the following IPG clock gating bits are wrongly marked "Reserved" in + * the i.MX25 Reference Manual Rev 1, table 15-13. The information below is + * taken from the Freescale released BSP. + * + * bit reg offset clock + * + * 0 CGCR1 0 AUDMUX + * 12 CGCR1 12 ESAI + * 16 CGCR1 16 GPIO1 + * 17 CGCR1 17 GPIO2 + * 18 CGCR1 18 GPIO3 + * 23 CGCR1 23 I2C1 + * 24 CGCR1 24 I2C2 + * 25 CGCR1 25 I2C3 + * 27 CGCR1 27 IOMUXC + * 28 CGCR1 28 KPP + * 30 CGCR1 30 OWIRE + * 36 CGCR2 4 RTIC + * 51 CGCR2 19 WDOG + */ + +DEFINE_CLOCK(gpt_clk, 0, CCM_CGCR0, 5, get_rate_gpt, NULL, NULL); +DEFINE_CLOCK(uart_per_clk, 0, CCM_CGCR0, 15, get_rate_uart, NULL, NULL); +DEFINE_CLOCK(ssi1_per_clk, 0, CCM_CGCR0, 13, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(ssi2_per_clk, 0, CCM_CGCR0, 14, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(cspi1_clk, 0, CCM_CGCR1, 5, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(cspi2_clk, 0, CCM_CGCR1, 6, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(cspi3_clk, 0, CCM_CGCR1, 7, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(esdhc1_ahb_clk, 0, CCM_CGCR0, 21, get_rate_esdhc1, NULL, NULL); +DEFINE_CLOCK(esdhc1_per_clk, 0, CCM_CGCR0, 3, get_rate_esdhc1, NULL, + &esdhc1_ahb_clk); +DEFINE_CLOCK(esdhc2_ahb_clk, 0, CCM_CGCR0, 22, get_rate_esdhc2, NULL, NULL); +DEFINE_CLOCK(esdhc2_per_clk, 0, CCM_CGCR0, 4, get_rate_esdhc2, NULL, + &esdhc2_ahb_clk); +DEFINE_CLOCK(sdma_ahb_clk, 0, CCM_CGCR0, 26, NULL, NULL, NULL); +DEFINE_CLOCK(fec_ahb_clk, 0, CCM_CGCR0, 23, NULL, NULL, NULL); +DEFINE_CLOCK(lcdc_ahb_clk, 0, CCM_CGCR0, 24, NULL, NULL, NULL); +DEFINE_CLOCK(lcdc_per_clk, 0, CCM_CGCR0, 7, NULL, NULL, &lcdc_ahb_clk); +DEFINE_CLOCK(csi_ahb_clk, 0, CCM_CGCR0, 18, get_rate_csi, NULL, NULL); +DEFINE_CLOCK(csi_per_clk, 0, CCM_CGCR0, 0, get_rate_csi, NULL, &csi_ahb_clk); +DEFINE_CLOCK(uart1_clk, 0, CCM_CGCR2, 14, get_rate_uart, NULL, &uart_per_clk); +DEFINE_CLOCK(uart2_clk, 0, CCM_CGCR2, 15, get_rate_uart, NULL, &uart_per_clk); +DEFINE_CLOCK(uart3_clk, 0, CCM_CGCR2, 16, get_rate_uart, NULL, &uart_per_clk); +DEFINE_CLOCK(uart4_clk, 0, CCM_CGCR2, 17, get_rate_uart, NULL, &uart_per_clk); +DEFINE_CLOCK(uart5_clk, 0, CCM_CGCR2, 18, get_rate_uart, NULL, &uart_per_clk); +DEFINE_CLOCK(nfc_clk, 0, CCM_CGCR0, 8, get_rate_nfc, NULL, NULL); +DEFINE_CLOCK(usbotg_clk, 0, CCM_CGCR0, 28, get_rate_otg, NULL, NULL); +DEFINE_CLOCK(pwm1_clk, 0, CCM_CGCR1, 31, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(pwm2_clk, 0, CCM_CGCR2, 0, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(pwm3_clk, 0, CCM_CGCR2, 1, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(pwm4_clk, 0, CCM_CGCR2, 2, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(kpp_clk, 0, CCM_CGCR1, 28, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(tsc_clk, 0, CCM_CGCR2, 13, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(i2c_clk, 0, CCM_CGCR0, 6, get_rate_i2c, NULL, NULL); +DEFINE_CLOCK(fec_clk, 0, CCM_CGCR1, 15, get_rate_ipg, NULL, &fec_ahb_clk); +DEFINE_CLOCK(dryice_clk, 0, CCM_CGCR1, 8, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(lcdc_clk, 0, CCM_CGCR1, 29, get_rate_lcdc, NULL, &lcdc_per_clk); +DEFINE_CLOCK(wdt_clk, 0, CCM_CGCR2, 19, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(ssi1_clk, 0, CCM_CGCR2, 11, get_rate_ssi1, NULL, &ssi1_per_clk); +DEFINE_CLOCK(ssi2_clk, 1, CCM_CGCR2, 12, get_rate_ssi2, NULL, &ssi2_per_clk); +DEFINE_CLOCK(sdma_clk, 0, CCM_CGCR2, 6, get_rate_ipg, NULL, &sdma_ahb_clk); +DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGCR1, 13, get_rate_esdhc1, NULL, + &esdhc1_per_clk); +DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGCR1, 14, get_rate_esdhc2, NULL, + &esdhc2_per_clk); +DEFINE_CLOCK(audmux_clk, 0, CCM_CGCR1, 0, NULL, NULL, NULL); +DEFINE_CLOCK(csi_clk, 0, CCM_CGCR1, 4, get_rate_csi, NULL, &csi_per_clk); +DEFINE_CLOCK(can1_clk, 0, CCM_CGCR1, 2, get_rate_ipg, NULL, NULL); +DEFINE_CLOCK(can2_clk, 1, CCM_CGCR1, 3, get_rate_ipg, NULL, NULL); + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) + _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk) + _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk) + _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) + _REGISTER_CLOCK("imx25-cspi.0", NULL, cspi1_clk) + _REGISTER_CLOCK("imx25-cspi.1", NULL, cspi2_clk) + _REGISTER_CLOCK("imx25-cspi.2", NULL, cspi3_clk) + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk) + _REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk) + _REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk) + _REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk) + _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk) + _REGISTER_CLOCK("mx25-adc", NULL, tsc_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk) + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c_clk) + _REGISTER_CLOCK("fec.0", NULL, fec_clk) + _REGISTER_CLOCK("imxdi_rtc.0", NULL, dryice_clk) + _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) + _REGISTER_CLOCK("imx2-wdt.0", NULL, wdt_clk) + _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) + _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) + _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk) + _REGISTER_CLOCK(NULL, "audmux", audmux_clk) + _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) + _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk) +}; + +int __init mx25_clocks_init(void) +{ + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + /* Turn off all clocks except the ones we need to survive, namely: + * EMI, GPIO1-3 (CCM_CGCR1[18:16]), GPT1, IOMUXC (CCM_CGCR1[27]), IIM, + * SCC + */ + __raw_writel((1 << 19), CRM_BASE + CCM_CGCR0); + __raw_writel((0xf << 16) | (3 << 26), CRM_BASE + CCM_CGCR1); + __raw_writel((1 << 5), CRM_BASE + CCM_CGCR2); +#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) + clk_enable(&uart1_clk); +#endif + + /* Clock source for lcdc and csi is upll */ + __raw_writel(__raw_readl(CRM_BASE+0x64) | (1 << 7) | (1 << 0), + CRM_BASE + 0x64); + + mxc_timer_init(&gpt_clk, MX25_IO_ADDRESS(MX25_GPT1_BASE_ADDR), 54); + + return 0; +} diff --git a/arch/arm/mach-imx/clock-imx27.c b/arch/arm/mach-imx/clock-imx27.c new file mode 100644 index 00000000..583f2515 --- /dev/null +++ b/arch/arm/mach-imx/clock-imx27.c @@ -0,0 +1,763 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * 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/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/clkdev.h> + +#include <asm/div64.h> + +#include <mach/clock.h> +#include <mach/common.h> +#include <mach/hardware.h> + +#define IO_ADDR_CCM(off) (MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR + (off))) + +/* Register offsets */ +#define CCM_CSCR IO_ADDR_CCM(0x0) +#define CCM_MPCTL0 IO_ADDR_CCM(0x4) +#define CCM_MPCTL1 IO_ADDR_CCM(0x8) +#define CCM_SPCTL0 IO_ADDR_CCM(0xc) +#define CCM_SPCTL1 IO_ADDR_CCM(0x10) +#define CCM_OSC26MCTL IO_ADDR_CCM(0x14) +#define CCM_PCDR0 IO_ADDR_CCM(0x18) +#define CCM_PCDR1 IO_ADDR_CCM(0x1c) +#define CCM_PCCR0 IO_ADDR_CCM(0x20) +#define CCM_PCCR1 IO_ADDR_CCM(0x24) +#define CCM_CCSR IO_ADDR_CCM(0x28) +#define CCM_PMCTL IO_ADDR_CCM(0x2c) +#define CCM_PMCOUNT IO_ADDR_CCM(0x30) +#define CCM_WKGDCTL IO_ADDR_CCM(0x34) + +#define CCM_CSCR_UPDATE_DIS (1 << 31) +#define CCM_CSCR_SSI2 (1 << 23) +#define CCM_CSCR_SSI1 (1 << 22) +#define CCM_CSCR_VPU (1 << 21) +#define CCM_CSCR_MSHC (1 << 20) +#define CCM_CSCR_SPLLRES (1 << 19) +#define CCM_CSCR_MPLLRES (1 << 18) +#define CCM_CSCR_SP (1 << 17) +#define CCM_CSCR_MCU (1 << 16) +#define CCM_CSCR_OSC26MDIV (1 << 4) +#define CCM_CSCR_OSC26M (1 << 3) +#define CCM_CSCR_FPM (1 << 2) +#define CCM_CSCR_SPEN (1 << 1) +#define CCM_CSCR_MPEN (1 << 0) + +/* i.MX27 TO 2+ */ +#define CCM_CSCR_ARM_SRC (1 << 15) + +#define CCM_SPCTL1_LF (1 << 15) +#define CCM_SPCTL1_BRMO (1 << 6) + +static struct clk mpll_main1_clk, mpll_main2_clk; + +static int clk_pccr_enable(struct clk *clk) +{ + unsigned long reg; + + if (!clk->enable_reg) + return 0; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void clk_pccr_disable(struct clk *clk) +{ + unsigned long reg; + + if (!clk->enable_reg) + return; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int clk_spll_enable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(CCM_CSCR); + reg |= CCM_CSCR_SPEN; + __raw_writel(reg, CCM_CSCR); + + while (!(__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF)); + + return 0; +} + +static void clk_spll_disable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(CCM_CSCR); + reg &= ~CCM_CSCR_SPEN; + __raw_writel(reg, CCM_CSCR); +} + +static int clk_cpu_set_parent(struct clk *clk, struct clk *parent) +{ + int cscr = __raw_readl(CCM_CSCR); + + if (clk->parent == parent) + return 0; + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { + if (parent == &mpll_main1_clk) { + cscr |= CCM_CSCR_ARM_SRC; + } else { + if (parent == &mpll_main2_clk) + cscr &= ~CCM_CSCR_ARM_SRC; + else + return -EINVAL; + } + __raw_writel(cscr, CCM_CSCR); + clk->parent = parent; + return 0; + } + return -ENODEV; +} + +static unsigned long round_rate_cpu(struct clk *clk, unsigned long rate) +{ + int div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div > 4) + div = 4; + + return parent_rate / div; +} + +static int set_rate_cpu(struct clk *clk, unsigned long rate) +{ + unsigned int div; + uint32_t reg; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + + if (div > 4 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + + div--; + + reg = __raw_readl(CCM_CSCR); + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { + reg &= ~(3 << 12); + reg |= div << 12; + reg &= ~(CCM_CSCR_FPM | CCM_CSCR_SPEN); + __raw_writel(reg | CCM_CSCR_UPDATE_DIS, CCM_CSCR); + } else { + printk(KERN_ERR "Can't set CPU frequency!\n"); + } + + return 0; +} + +static unsigned long round_rate_per(struct clk *clk, unsigned long rate) +{ + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + div = parent_rate / rate; + if (parent_rate % rate) + div++; + + if (div > 64) + div = 64; + + return parent_rate / div; +} + +static int set_rate_per(struct clk *clk, unsigned long rate) +{ + u32 reg; + u32 div; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (clk->id < 0 || clk->id > 3) + return -EINVAL; + + div = parent_rate / rate; + if (div > 64 || div < 1 || ((parent_rate / div) != rate)) + return -EINVAL; + div--; + + reg = __raw_readl(CCM_PCDR1) & ~(0x3f << (clk->id << 3)); + reg |= div << (clk->id << 3); + __raw_writel(reg, CCM_PCDR1); + + return 0; +} + +static unsigned long get_rate_usb(struct clk *clk) +{ + unsigned long usb_pdf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + usb_pdf = (__raw_readl(CCM_CSCR) >> 28) & 0x7; + + return parent_rate / (usb_pdf + 1U); +} + +static unsigned long get_rate_ssix(struct clk *clk, unsigned long pdf) +{ + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + pdf += 4; /* MX27 TO2+ */ + else + pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */ + + return 2UL * parent_rate / pdf; +} + +static unsigned long get_rate_ssi1(struct clk *clk) +{ + return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 16) & 0x3f); +} + +static unsigned long get_rate_ssi2(struct clk *clk) +{ + return get_rate_ssix(clk, (__raw_readl(CCM_PCDR0) >> 26) & 0x3f); +} + +static unsigned long get_rate_nfc(struct clk *clk) +{ + unsigned long nfc_pdf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + nfc_pdf = (__raw_readl(CCM_PCDR0) >> 6) & 0xf; + else + nfc_pdf = (__raw_readl(CCM_PCDR0) >> 12) & 0xf; + + return parent_rate / (nfc_pdf + 1); +} + +static unsigned long get_rate_vpu(struct clk *clk) +{ + unsigned long vpu_pdf; + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { + vpu_pdf = (__raw_readl(CCM_PCDR0) >> 10) & 0x3f; + vpu_pdf += 4; + } else { + vpu_pdf = (__raw_readl(CCM_PCDR0) >> 8) & 0xf; + vpu_pdf = (vpu_pdf < 2) ? 124 : vpu_pdf; + } + + return 2UL * parent_rate / vpu_pdf; +} + +static unsigned long round_rate_parent(struct clk *clk, unsigned long rate) +{ + return clk->parent->round_rate(clk->parent, rate); +} + +static unsigned long get_rate_parent(struct clk *clk) +{ + return clk_get_rate(clk->parent); +} + +static int set_rate_parent(struct clk *clk, unsigned long rate) +{ + return clk->parent->set_rate(clk->parent, rate); +} + +/* in Hz */ +static unsigned long external_high_reference = 26000000; + +static unsigned long get_rate_high_reference(struct clk *clk) +{ + return external_high_reference; +} + +/* in Hz */ +static unsigned long external_low_reference = 32768; + +static unsigned long get_rate_low_reference(struct clk *clk) +{ + return external_low_reference; +} + +static unsigned long get_rate_fpm(struct clk *clk) +{ + return clk_get_rate(clk->parent) * 1024; +} + +static unsigned long get_rate_mpll(struct clk *clk) +{ + return mxc_decode_pll(__raw_readl(CCM_MPCTL0), + clk_get_rate(clk->parent)); +} + +static unsigned long get_rate_mpll_main(struct clk *clk) +{ + unsigned long parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + /* i.MX27 TO2: + * clk->id == 0: arm clock source path 1 which is from 2 * MPLL / 2 + * clk->id == 1: arm clock source path 2 which is from 2 * MPLL / 3 + */ + if (mx27_revision() >= IMX_CHIP_REVISION_2_0 && clk->id == 1) + return 2UL * parent_rate / 3UL; + + return parent_rate; +} + +static unsigned long get_rate_spll(struct clk *clk) +{ + uint32_t reg; + unsigned long rate; + + rate = clk_get_rate(clk->parent); + + reg = __raw_readl(CCM_SPCTL0); + + /* On TO2 we have to write the value back. Otherwise we + * read 0 from this register the next time. + */ + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + __raw_writel(reg, CCM_SPCTL0); + + return mxc_decode_pll(reg, rate); +} + +static unsigned long get_rate_cpu(struct clk *clk) +{ + u32 div; + unsigned long rate; + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + div = (__raw_readl(CCM_CSCR) >> 12) & 0x3; + else + div = (__raw_readl(CCM_CSCR) >> 13) & 0x7; + + rate = clk_get_rate(clk->parent); + return rate / (div + 1); +} + +static unsigned long get_rate_ahb(struct clk *clk) +{ + unsigned long rate, bclk_pdf; + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + bclk_pdf = (__raw_readl(CCM_CSCR) >> 8) & 0x3; + else + bclk_pdf = (__raw_readl(CCM_CSCR) >> 9) & 0xf; + + rate = clk_get_rate(clk->parent); + return rate / (bclk_pdf + 1); +} + +static unsigned long get_rate_ipg(struct clk *clk) +{ + unsigned long rate, ipg_pdf; + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) + return clk_get_rate(clk->parent); + else + ipg_pdf = (__raw_readl(CCM_CSCR) >> 8) & 1; + + rate = clk_get_rate(clk->parent); + return rate / (ipg_pdf + 1); +} + +static unsigned long get_rate_per(struct clk *clk) +{ + unsigned long perclk_pdf, parent_rate; + + parent_rate = clk_get_rate(clk->parent); + + if (clk->id < 0 || clk->id > 3) + return 0; + + perclk_pdf = (__raw_readl(CCM_PCDR1) >> (clk->id << 3)) & 0x3f; + + return parent_rate / (perclk_pdf + 1); +} + +/* + * the high frequency external clock reference + * Default case is 26MHz. Could be changed at runtime + * with a call to change_external_high_reference() + */ +static struct clk ckih_clk = { + .get_rate = get_rate_high_reference, +}; + +static struct clk mpll_clk = { + .parent = &ckih_clk, + .get_rate = get_rate_mpll, +}; + +/* For i.MX27 TO2, it is the MPLL path 1 of ARM core + * It provides the clock source whose rate is same as MPLL + */ +static struct clk mpll_main1_clk = { + .id = 0, + .parent = &mpll_clk, + .get_rate = get_rate_mpll_main, +}; + +/* For i.MX27 TO2, it is the MPLL path 2 of ARM core + * It provides the clock source whose rate is same MPLL * 2 / 3 + */ +static struct clk mpll_main2_clk = { + .id = 1, + .parent = &mpll_clk, + .get_rate = get_rate_mpll_main, +}; + +static struct clk ahb_clk = { + .parent = &mpll_main2_clk, + .get_rate = get_rate_ahb, +}; + +static struct clk ipg_clk = { + .parent = &ahb_clk, + .get_rate = get_rate_ipg, +}; + +static struct clk cpu_clk = { + .parent = &mpll_main2_clk, + .set_parent = clk_cpu_set_parent, + .round_rate = round_rate_cpu, + .get_rate = get_rate_cpu, + .set_rate = set_rate_cpu, +}; + +static struct clk spll_clk = { + .parent = &ckih_clk, + .get_rate = get_rate_spll, + .enable = clk_spll_enable, + .disable = clk_spll_disable, +}; + +/* + * the low frequency external clock reference + * Default case is 32.768kHz. + */ +static struct clk ckil_clk = { + .get_rate = get_rate_low_reference, +}; + +/* Output of frequency pre multiplier */ +static struct clk fpm_clk = { + .parent = &ckil_clk, + .get_rate = get_rate_fpm, +}; + +#define PCCR0 CCM_PCCR0 +#define PCCR1 CCM_PCCR1 + +#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = gr, \ + .enable = clk_pccr_enable, \ + .disable = clk_pccr_disable, \ + .secondary = s, \ + .parent = p, \ + } + +#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = get_rate_##getsetround, \ + .set_rate = set_rate_##getsetround, \ + .round_rate = round_rate_##getsetround, \ + .enable = clk_pccr_enable, \ + .disable = clk_pccr_disable, \ + .secondary = s, \ + .parent = p, \ + } + +/* Forward declaration to keep the following list in order */ +static struct clk slcdc_clk1, sahara2_clk1, rtic_clk1, fec_clk1, emma_clk1, + dma_clk1, lcdc_clk2, vpu_clk1; + +/* All clocks we can gate through PCCRx in the order of PCCRx bits */ +DEFINE_CLOCK(ssi2_clk1, 1, PCCR0, 0, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(ssi1_clk1, 0, PCCR0, 1, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(slcdc_clk, 0, PCCR0, 2, NULL, &slcdc_clk1, &ahb_clk); +DEFINE_CLOCK(sdhc3_clk1, 0, PCCR0, 3, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(sdhc2_clk1, 0, PCCR0, 4, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(sdhc1_clk1, 0, PCCR0, 5, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(scc_clk, 0, PCCR0, 6, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(sahara2_clk, 0, PCCR0, 7, NULL, &sahara2_clk1, &ahb_clk); +DEFINE_CLOCK(rtic_clk, 0, PCCR0, 8, NULL, &rtic_clk1, &ahb_clk); +DEFINE_CLOCK(rtc_clk, 0, PCCR0, 9, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(pwm_clk1, 0, PCCR0, 11, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(owire_clk, 0, PCCR0, 12, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(mstick_clk1, 0, PCCR0, 13, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(lcdc_clk1, 0, PCCR0, 14, NULL, &lcdc_clk2, &ipg_clk); +DEFINE_CLOCK(kpp_clk, 0, PCCR0, 15, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(iim_clk, 0, PCCR0, 16, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(i2c2_clk, 1, PCCR0, 17, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(i2c1_clk, 0, PCCR0, 18, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpt6_clk1, 0, PCCR0, 29, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpt5_clk1, 0, PCCR0, 20, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpt4_clk1, 0, PCCR0, 21, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpt3_clk1, 0, PCCR0, 22, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpt2_clk1, 0, PCCR0, 23, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpt1_clk1, 0, PCCR0, 24, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(gpio_clk, 0, PCCR0, 25, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(fec_clk, 0, PCCR0, 26, NULL, &fec_clk1, &ahb_clk); +DEFINE_CLOCK(emma_clk, 0, PCCR0, 27, NULL, &emma_clk1, &ahb_clk); +DEFINE_CLOCK(dma_clk, 0, PCCR0, 28, NULL, &dma_clk1, &ahb_clk); +DEFINE_CLOCK(cspi13_clk1, 0, PCCR0, 29, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(cspi2_clk1, 0, PCCR0, 30, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(cspi1_clk1, 0, PCCR0, 31, NULL, NULL, &ipg_clk); + +DEFINE_CLOCK(mstick_clk, 0, PCCR1, 2, NULL, &mstick_clk1, &ipg_clk); +DEFINE_CLOCK(nfc_clk, 0, PCCR1, 3, get_rate_nfc, NULL, &cpu_clk); +DEFINE_CLOCK(ssi2_clk, 1, PCCR1, 4, get_rate_ssi2, &ssi2_clk1, &mpll_main2_clk); +DEFINE_CLOCK(ssi1_clk, 0, PCCR1, 5, get_rate_ssi1, &ssi1_clk1, &mpll_main2_clk); +DEFINE_CLOCK(vpu_clk, 0, PCCR1, 6, get_rate_vpu, &vpu_clk1, &mpll_main2_clk); +DEFINE_CLOCK1(per4_clk, 3, PCCR1, 7, per, NULL, &mpll_main2_clk); +DEFINE_CLOCK1(per3_clk, 2, PCCR1, 8, per, NULL, &mpll_main2_clk); +DEFINE_CLOCK1(per2_clk, 1, PCCR1, 9, per, NULL, &mpll_main2_clk); +DEFINE_CLOCK1(per1_clk, 0, PCCR1, 10, per, NULL, &mpll_main2_clk); +DEFINE_CLOCK(usb_clk1, 0, PCCR1, 11, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(slcdc_clk1, 0, PCCR1, 12, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(sahara2_clk1, 0, PCCR1, 13, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(rtic_clk1, 0, PCCR1, 14, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(lcdc_clk2, 0, PCCR1, 15, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(vpu_clk1, 0, PCCR1, 16, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(fec_clk1, 0, PCCR1, 17, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(emma_clk1, 0, PCCR1, 18, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(emi_clk, 0, PCCR1, 19, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(dma_clk1, 0, PCCR1, 20, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(csi_clk1, 0, PCCR1, 21, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(brom_clk, 0, PCCR1, 22, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(ata_clk, 0, PCCR1, 23, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(wdog_clk, 0, PCCR1, 24, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(usb_clk, 0, PCCR1, 25, get_rate_usb, &usb_clk1, &spll_clk); +DEFINE_CLOCK(uart6_clk1, 0, PCCR1, 26, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(uart5_clk1, 0, PCCR1, 27, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(uart4_clk1, 0, PCCR1, 28, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(uart3_clk1, 0, PCCR1, 29, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(uart2_clk1, 0, PCCR1, 30, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(uart1_clk1, 0, PCCR1, 31, NULL, NULL, &ipg_clk); + +/* Clocks we cannot directly gate, but drivers need their rates */ +DEFINE_CLOCK(cspi1_clk, 0, NULL, 0, NULL, &cspi1_clk1, &per2_clk); +DEFINE_CLOCK(cspi2_clk, 1, NULL, 0, NULL, &cspi2_clk1, &per2_clk); +DEFINE_CLOCK(cspi3_clk, 2, NULL, 0, NULL, &cspi13_clk1, &per2_clk); +DEFINE_CLOCK(sdhc1_clk, 0, NULL, 0, NULL, &sdhc1_clk1, &per2_clk); +DEFINE_CLOCK(sdhc2_clk, 1, NULL, 0, NULL, &sdhc2_clk1, &per2_clk); +DEFINE_CLOCK(sdhc3_clk, 2, NULL, 0, NULL, &sdhc3_clk1, &per2_clk); +DEFINE_CLOCK(pwm_clk, 0, NULL, 0, NULL, &pwm_clk1, &per1_clk); +DEFINE_CLOCK(gpt1_clk, 0, NULL, 0, NULL, &gpt1_clk1, &per1_clk); +DEFINE_CLOCK(gpt2_clk, 1, NULL, 0, NULL, &gpt2_clk1, &per1_clk); +DEFINE_CLOCK(gpt3_clk, 2, NULL, 0, NULL, &gpt3_clk1, &per1_clk); +DEFINE_CLOCK(gpt4_clk, 3, NULL, 0, NULL, &gpt4_clk1, &per1_clk); +DEFINE_CLOCK(gpt5_clk, 4, NULL, 0, NULL, &gpt5_clk1, &per1_clk); +DEFINE_CLOCK(gpt6_clk, 5, NULL, 0, NULL, &gpt6_clk1, &per1_clk); +DEFINE_CLOCK(uart1_clk, 0, NULL, 0, NULL, &uart1_clk1, &per1_clk); +DEFINE_CLOCK(uart2_clk, 1, NULL, 0, NULL, &uart2_clk1, &per1_clk); +DEFINE_CLOCK(uart3_clk, 2, NULL, 0, NULL, &uart3_clk1, &per1_clk); +DEFINE_CLOCK(uart4_clk, 3, NULL, 0, NULL, &uart4_clk1, &per1_clk); +DEFINE_CLOCK(uart5_clk, 4, NULL, 0, NULL, &uart5_clk1, &per1_clk); +DEFINE_CLOCK(uart6_clk, 5, NULL, 0, NULL, &uart6_clk1, &per1_clk); +DEFINE_CLOCK1(lcdc_clk, 0, NULL, 0, parent, &lcdc_clk1, &per3_clk); +DEFINE_CLOCK1(csi_clk, 0, NULL, 0, parent, &csi_clk1, &per4_clk); + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) + _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk) + _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk) + _REGISTER_CLOCK("imx-uart.5", NULL, uart6_clk) + _REGISTER_CLOCK(NULL, "gpt1", gpt1_clk) + _REGISTER_CLOCK(NULL, "gpt2", gpt2_clk) + _REGISTER_CLOCK(NULL, "gpt3", gpt3_clk) + _REGISTER_CLOCK(NULL, "gpt4", gpt4_clk) + _REGISTER_CLOCK(NULL, "gpt5", gpt5_clk) + _REGISTER_CLOCK(NULL, "gpt6", gpt6_clk) + _REGISTER_CLOCK("mxc_pwm.0", NULL, pwm_clk) + _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk) + _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk) + _REGISTER_CLOCK("mxc-mmc.2", NULL, sdhc3_clk) + _REGISTER_CLOCK("imx27-cspi.0", NULL, cspi1_clk) + _REGISTER_CLOCK("imx27-cspi.1", NULL, cspi2_clk) + _REGISTER_CLOCK("imx27-cspi.2", NULL, cspi3_clk) + _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk) + _REGISTER_CLOCK("mx2-camera.0", NULL, csi_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk1) + _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk1) + _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk1) + _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk1) + _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) + _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) + _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) + _REGISTER_CLOCK(NULL, "vpu", vpu_clk) + _REGISTER_CLOCK(NULL, "dma", dma_clk) + _REGISTER_CLOCK(NULL, "rtic", rtic_clk) + _REGISTER_CLOCK(NULL, "brom", brom_clk) + _REGISTER_CLOCK(NULL, "emma", emma_clk) + _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk) + _REGISTER_CLOCK("fec.0", NULL, fec_clk) + _REGISTER_CLOCK(NULL, "emi", emi_clk) + _REGISTER_CLOCK(NULL, "sahara2", sahara2_clk) + _REGISTER_CLOCK(NULL, "ata", ata_clk) + _REGISTER_CLOCK(NULL, "mstick", mstick_clk) + _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) + _REGISTER_CLOCK(NULL, "gpio", gpio_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) + _REGISTER_CLOCK(NULL, "iim", iim_clk) + _REGISTER_CLOCK(NULL, "kpp", kpp_clk) + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk) + _REGISTER_CLOCK(NULL, "rtc", rtc_clk) + _REGISTER_CLOCK(NULL, "scc", scc_clk) +}; + +/* Adjust the clock path for TO2 and later */ +static void __init to2_adjust_clocks(void) +{ + unsigned long cscr = __raw_readl(CCM_CSCR); + + if (mx27_revision() >= IMX_CHIP_REVISION_2_0) { + if (cscr & CCM_CSCR_ARM_SRC) + cpu_clk.parent = &mpll_main1_clk; + + if (!(cscr & CCM_CSCR_SSI2)) + ssi1_clk.parent = &spll_clk; + + if (!(cscr & CCM_CSCR_SSI1)) + ssi1_clk.parent = &spll_clk; + + if (!(cscr & CCM_CSCR_VPU)) + vpu_clk.parent = &spll_clk; + } else { + cpu_clk.parent = &mpll_clk; + cpu_clk.set_parent = NULL; + cpu_clk.round_rate = NULL; + cpu_clk.set_rate = NULL; + ahb_clk.parent = &mpll_clk; + + per1_clk.parent = &mpll_clk; + per2_clk.parent = &mpll_clk; + per3_clk.parent = &mpll_clk; + per4_clk.parent = &mpll_clk; + + ssi1_clk.parent = &mpll_clk; + ssi2_clk.parent = &mpll_clk; + + vpu_clk.parent = &mpll_clk; + } +} + +/* + * must be called very early to get information about the + * available clock rate when the timer framework starts + */ +int __init mx27_clocks_init(unsigned long fref) +{ + u32 cscr = __raw_readl(CCM_CSCR); + + external_high_reference = fref; + + /* detect clock reference for both system PLLs */ + if (cscr & CCM_CSCR_MCU) + mpll_clk.parent = &ckih_clk; + else + mpll_clk.parent = &fpm_clk; + + if (cscr & CCM_CSCR_SP) + spll_clk.parent = &ckih_clk; + else + spll_clk.parent = &fpm_clk; + + to2_adjust_clocks(); + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + /* Turn off all clocks we do not need */ + __raw_writel(0, CCM_PCCR0); + __raw_writel((1 << 10) | (1 << 19), CCM_PCCR1); + + spll_clk.disable(&spll_clk); + + /* enable basic clocks */ + clk_enable(&per1_clk); + clk_enable(&gpio_clk); + clk_enable(&emi_clk); + clk_enable(&iim_clk); + +#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) + clk_enable(&uart1_clk); +#endif + + mxc_timer_init(&gpt1_clk, MX27_IO_ADDRESS(MX27_GPT1_BASE_ADDR), + MX27_INT_GPT1); + + return 0; +} + diff --git a/arch/arm/mach-imx/clock-imx31.c b/arch/arm/mach-imx/clock-imx31.c new file mode 100644 index 00000000..25f343fc --- /dev/null +++ b/arch/arm/mach-imx/clock-imx31.c @@ -0,0 +1,629 @@ +/* + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/clkdev.h> + +#include <asm/div64.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include <mach/mx31.h> +#include <mach/common.h> + +#include "crmregs-imx31.h" + +#define PRE_DIV_MIN_FREQ 10000000 /* Minimum Frequency after Predivider */ + +static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post) +{ + u32 min_pre, temp_pre, old_err, err; + + if (div >= 512) { + *pre = 8; + *post = 64; + } else if (div >= 64) { + min_pre = (div - 1) / 64 + 1; + old_err = 8; + for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { + err = div % temp_pre; + if (err == 0) { + *pre = temp_pre; + break; + } + err = temp_pre - err; + if (err < old_err) { + old_err = err; + *pre = temp_pre; + } + } + *post = (div + *pre - 1) / *pre; + } else if (div <= 8) { + *pre = div; + *post = 1; + } else { + *pre = 1; + *post = div; + } +} + +static struct clk mcu_pll_clk; +static struct clk serial_pll_clk; +static struct clk ipg_clk; +static struct clk ckih_clk; + +static int cgr_enable(struct clk *clk) +{ + u32 reg; + + if (!clk->enable_reg) + return 0; + + reg = __raw_readl(clk->enable_reg); + reg |= 3 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void cgr_disable(struct clk *clk) +{ + u32 reg; + + if (!clk->enable_reg) + return; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(3 << clk->enable_shift); + + /* special case for EMI clock */ + if (clk->enable_reg == MXC_CCM_CGR2 && clk->enable_shift == 8) + reg |= (1 << clk->enable_shift); + + __raw_writel(reg, clk->enable_reg); +} + +static unsigned long pll_ref_get_rate(void) +{ + unsigned long ccmr; + unsigned int prcs; + + ccmr = __raw_readl(MXC_CCM_CCMR); + prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET; + if (prcs == 0x1) + return CKIL_CLK_FREQ * 1024; + else + return clk_get_rate(&ckih_clk); +} + +static unsigned long usb_pll_get_rate(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_UPCTL); + + return mxc_decode_pll(reg, pll_ref_get_rate()); +} + +static unsigned long serial_pll_get_rate(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_SRPCTL); + + return mxc_decode_pll(reg, pll_ref_get_rate()); +} + +static unsigned long mcu_pll_get_rate(struct clk *clk) +{ + unsigned long reg, ccmr; + + ccmr = __raw_readl(MXC_CCM_CCMR); + + if (!(ccmr & MXC_CCM_CCMR_MPE) || (ccmr & MXC_CCM_CCMR_MDS)) + return clk_get_rate(&ckih_clk); + + reg = __raw_readl(MXC_CCM_MPCTL); + + return mxc_decode_pll(reg, pll_ref_get_rate()); +} + +static int usb_pll_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCMR); + reg |= MXC_CCM_CCMR_UPE; + __raw_writel(reg, MXC_CCM_CCMR); + + /* No lock bit on MX31, so using max time from spec */ + udelay(80); + + return 0; +} + +static void usb_pll_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCMR); + reg &= ~MXC_CCM_CCMR_UPE; + __raw_writel(reg, MXC_CCM_CCMR); +} + +static int serial_pll_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCMR); + reg |= MXC_CCM_CCMR_SPE; + __raw_writel(reg, MXC_CCM_CCMR); + + /* No lock bit on MX31, so using max time from spec */ + udelay(80); + + return 0; +} + +static void serial_pll_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CCMR); + reg &= ~MXC_CCM_CCMR_SPE; + __raw_writel(reg, MXC_CCM_CCMR); +} + +#define PDR0(mask, off) ((__raw_readl(MXC_CCM_PDR0) & mask) >> off) +#define PDR1(mask, off) ((__raw_readl(MXC_CCM_PDR1) & mask) >> off) +#define PDR2(mask, off) ((__raw_readl(MXC_CCM_PDR2) & mask) >> off) + +static unsigned long mcu_main_get_rate(struct clk *clk) +{ + u32 pmcr0 = __raw_readl(MXC_CCM_PMCR0); + + if ((pmcr0 & MXC_CCM_PMCR0_DFSUP1) == MXC_CCM_PMCR0_DFSUP1_SPLL) + return clk_get_rate(&serial_pll_clk); + else + return clk_get_rate(&mcu_pll_clk); +} + +static unsigned long ahb_get_rate(struct clk *clk) +{ + unsigned long max_pdf; + + max_pdf = PDR0(MXC_CCM_PDR0_MAX_PODF_MASK, + MXC_CCM_PDR0_MAX_PODF_OFFSET); + return clk_get_rate(clk->parent) / (max_pdf + 1); +} + +static unsigned long ipg_get_rate(struct clk *clk) +{ + unsigned long ipg_pdf; + + ipg_pdf = PDR0(MXC_CCM_PDR0_IPG_PODF_MASK, + MXC_CCM_PDR0_IPG_PODF_OFFSET); + return clk_get_rate(clk->parent) / (ipg_pdf + 1); +} + +static unsigned long nfc_get_rate(struct clk *clk) +{ + unsigned long nfc_pdf; + + nfc_pdf = PDR0(MXC_CCM_PDR0_NFC_PODF_MASK, + MXC_CCM_PDR0_NFC_PODF_OFFSET); + return clk_get_rate(clk->parent) / (nfc_pdf + 1); +} + +static unsigned long hsp_get_rate(struct clk *clk) +{ + unsigned long hsp_pdf; + + hsp_pdf = PDR0(MXC_CCM_PDR0_HSP_PODF_MASK, + MXC_CCM_PDR0_HSP_PODF_OFFSET); + return clk_get_rate(clk->parent) / (hsp_pdf + 1); +} + +static unsigned long usb_get_rate(struct clk *clk) +{ + unsigned long usb_pdf, usb_prepdf; + + usb_pdf = PDR1(MXC_CCM_PDR1_USB_PODF_MASK, + MXC_CCM_PDR1_USB_PODF_OFFSET); + usb_prepdf = PDR1(MXC_CCM_PDR1_USB_PRDF_MASK, + MXC_CCM_PDR1_USB_PRDF_OFFSET); + return clk_get_rate(clk->parent) / (usb_prepdf + 1) / (usb_pdf + 1); +} + +static unsigned long csi_get_rate(struct clk *clk) +{ + u32 reg, pre, post; + + reg = __raw_readl(MXC_CCM_PDR0); + pre = (reg & MXC_CCM_PDR0_CSI_PRDF_MASK) >> + MXC_CCM_PDR0_CSI_PRDF_OFFSET; + pre++; + post = (reg & MXC_CCM_PDR0_CSI_PODF_MASK) >> + MXC_CCM_PDR0_CSI_PODF_OFFSET; + post++; + return clk_get_rate(clk->parent) / (pre * post); +} + +static unsigned long csi_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post, parent = clk_get_rate(clk->parent); + u32 div = parent / rate; + + if (parent % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent / (pre * post); +} + +static int csi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post, parent = clk_get_rate(clk->parent); + + div = parent / rate; + + if ((parent / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set CSI clock divider */ + reg = __raw_readl(MXC_CCM_PDR0) & + ~(MXC_CCM_PDR0_CSI_PODF_MASK | MXC_CCM_PDR0_CSI_PRDF_MASK); + reg |= (post - 1) << MXC_CCM_PDR0_CSI_PODF_OFFSET; + reg |= (pre - 1) << MXC_CCM_PDR0_CSI_PRDF_OFFSET; + __raw_writel(reg, MXC_CCM_PDR0); + + return 0; +} + +static unsigned long ssi1_get_rate(struct clk *clk) +{ + unsigned long ssi1_pdf, ssi1_prepdf; + + ssi1_pdf = PDR1(MXC_CCM_PDR1_SSI1_PODF_MASK, + MXC_CCM_PDR1_SSI1_PODF_OFFSET); + ssi1_prepdf = PDR1(MXC_CCM_PDR1_SSI1_PRE_PODF_MASK, + MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET); + return clk_get_rate(clk->parent) / (ssi1_prepdf + 1) / (ssi1_pdf + 1); +} + +static unsigned long ssi2_get_rate(struct clk *clk) +{ + unsigned long ssi2_pdf, ssi2_prepdf; + + ssi2_pdf = PDR1(MXC_CCM_PDR1_SSI2_PODF_MASK, + MXC_CCM_PDR1_SSI2_PODF_OFFSET); + ssi2_prepdf = PDR1(MXC_CCM_PDR1_SSI2_PRE_PODF_MASK, + MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET); + return clk_get_rate(clk->parent) / (ssi2_prepdf + 1) / (ssi2_pdf + 1); +} + +static unsigned long firi_get_rate(struct clk *clk) +{ + unsigned long firi_pdf, firi_prepdf; + + firi_pdf = PDR1(MXC_CCM_PDR1_FIRI_PODF_MASK, + MXC_CCM_PDR1_FIRI_PODF_OFFSET); + firi_prepdf = PDR1(MXC_CCM_PDR1_FIRI_PRE_PODF_MASK, + MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET); + return clk_get_rate(clk->parent) / (firi_prepdf + 1) / (firi_pdf + 1); +} + +static unsigned long firi_round_rate(struct clk *clk, unsigned long rate) +{ + u32 pre, post; + u32 parent = clk_get_rate(clk->parent); + u32 div = parent / rate; + + if (parent % rate) + div++; + + __calc_pre_post_dividers(div, &pre, &post); + + return parent / (pre * post); + +} + +static int firi_set_rate(struct clk *clk, unsigned long rate) +{ + u32 reg, div, pre, post, parent = clk_get_rate(clk->parent); + + div = parent / rate; + + if ((parent / div) != rate) + return -EINVAL; + + __calc_pre_post_dividers(div, &pre, &post); + + /* Set FIRI clock divider */ + reg = __raw_readl(MXC_CCM_PDR1) & + ~(MXC_CCM_PDR1_FIRI_PODF_MASK | MXC_CCM_PDR1_FIRI_PRE_PODF_MASK); + reg |= (pre - 1) << MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET; + reg |= (post - 1) << MXC_CCM_PDR1_FIRI_PODF_OFFSET; + __raw_writel(reg, MXC_CCM_PDR1); + + return 0; +} + +static unsigned long mbx_get_rate(struct clk *clk) +{ + return clk_get_rate(clk->parent) / 2; +} + +static unsigned long mstick1_get_rate(struct clk *clk) +{ + unsigned long msti_pdf; + + msti_pdf = PDR2(MXC_CCM_PDR2_MST1_PDF_MASK, + MXC_CCM_PDR2_MST1_PDF_OFFSET); + return clk_get_rate(clk->parent) / (msti_pdf + 1); +} + +static unsigned long mstick2_get_rate(struct clk *clk) +{ + unsigned long msti_pdf; + + msti_pdf = PDR2(MXC_CCM_PDR2_MST2_PDF_MASK, + MXC_CCM_PDR2_MST2_PDF_OFFSET); + return clk_get_rate(clk->parent) / (msti_pdf + 1); +} + +static unsigned long ckih_rate; + +static unsigned long clk_ckih_get_rate(struct clk *clk) +{ + return ckih_rate; +} + +static unsigned long clk_ckil_get_rate(struct clk *clk) +{ + return CKIL_CLK_FREQ; +} + +static struct clk ckih_clk = { + .get_rate = clk_ckih_get_rate, +}; + +static struct clk mcu_pll_clk = { + .parent = &ckih_clk, + .get_rate = mcu_pll_get_rate, +}; + +static struct clk mcu_main_clk = { + .parent = &mcu_pll_clk, + .get_rate = mcu_main_get_rate, +}; + +static struct clk serial_pll_clk = { + .parent = &ckih_clk, + .get_rate = serial_pll_get_rate, + .enable = serial_pll_enable, + .disable = serial_pll_disable, +}; + +static struct clk usb_pll_clk = { + .parent = &ckih_clk, + .get_rate = usb_pll_get_rate, + .enable = usb_pll_enable, + .disable = usb_pll_disable, +}; + +static struct clk ahb_clk = { + .parent = &mcu_main_clk, + .get_rate = ahb_get_rate, +}; + +#define DEFINE_CLOCK(name, i, er, es, gr, s, p) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = gr, \ + .enable = cgr_enable, \ + .disable = cgr_disable, \ + .secondary = s, \ + .parent = p, \ + } + +#define DEFINE_CLOCK1(name, i, er, es, getsetround, s, p) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = er, \ + .enable_shift = es, \ + .get_rate = getsetround##_get_rate, \ + .set_rate = getsetround##_set_rate, \ + .round_rate = getsetround##_round_rate, \ + .enable = cgr_enable, \ + .disable = cgr_disable, \ + .secondary = s, \ + .parent = p, \ + } + +DEFINE_CLOCK(perclk_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(ckil_clk, 0, NULL, 0, clk_ckil_get_rate, NULL, NULL); + +DEFINE_CLOCK(sdhc1_clk, 0, MXC_CCM_CGR0, 0, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(sdhc2_clk, 1, MXC_CCM_CGR0, 2, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CGR0, 4, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(epit1_clk, 0, MXC_CCM_CGR0, 6, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(epit2_clk, 1, MXC_CCM_CGR0, 8, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(iim_clk, 0, MXC_CCM_CGR0, 10, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(ata_clk, 0, MXC_CCM_CGR0, 12, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(sdma_clk1, 0, MXC_CCM_CGR0, 14, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(cspi3_clk, 2, MXC_CCM_CGR0, 16, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(rng_clk, 0, MXC_CCM_CGR0, 18, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(uart1_clk, 0, MXC_CCM_CGR0, 20, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(uart2_clk, 1, MXC_CCM_CGR0, 22, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(ssi1_clk, 0, MXC_CCM_CGR0, 24, ssi1_get_rate, NULL, &serial_pll_clk); +DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CGR0, 26, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CGR0, 28, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(i2c3_clk, 2, MXC_CCM_CGR0, 30, NULL, NULL, &perclk_clk); + +DEFINE_CLOCK(mpeg4_clk, 0, MXC_CCM_CGR1, 0, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(mstick1_clk, 0, MXC_CCM_CGR1, 2, mstick1_get_rate, NULL, &usb_pll_clk); +DEFINE_CLOCK(mstick2_clk, 1, MXC_CCM_CGR1, 4, mstick2_get_rate, NULL, &usb_pll_clk); +DEFINE_CLOCK1(csi_clk, 0, MXC_CCM_CGR1, 6, csi, NULL, &serial_pll_clk); +DEFINE_CLOCK(rtc_clk, 0, MXC_CCM_CGR1, 8, NULL, NULL, &ckil_clk); +DEFINE_CLOCK(wdog_clk, 0, MXC_CCM_CGR1, 10, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(pwm_clk, 0, MXC_CCM_CGR1, 12, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(usb_clk2, 0, MXC_CCM_CGR1, 18, usb_get_rate, NULL, &ahb_clk); +DEFINE_CLOCK(kpp_clk, 0, MXC_CCM_CGR1, 20, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(ipu_clk, 0, MXC_CCM_CGR1, 22, hsp_get_rate, NULL, &mcu_main_clk); +DEFINE_CLOCK(uart3_clk, 2, MXC_CCM_CGR1, 24, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(uart4_clk, 3, MXC_CCM_CGR1, 26, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(uart5_clk, 4, MXC_CCM_CGR1, 28, NULL, NULL, &perclk_clk); +DEFINE_CLOCK(owire_clk, 0, MXC_CCM_CGR1, 30, NULL, NULL, &perclk_clk); + +DEFINE_CLOCK(ssi2_clk, 1, MXC_CCM_CGR2, 0, ssi2_get_rate, NULL, &serial_pll_clk); +DEFINE_CLOCK(cspi1_clk, 0, MXC_CCM_CGR2, 2, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(cspi2_clk, 1, MXC_CCM_CGR2, 4, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(mbx_clk, 0, MXC_CCM_CGR2, 6, mbx_get_rate, NULL, &ahb_clk); +DEFINE_CLOCK(emi_clk, 0, MXC_CCM_CGR2, 8, NULL, NULL, &ahb_clk); +DEFINE_CLOCK(rtic_clk, 0, MXC_CCM_CGR2, 10, NULL, NULL, &ahb_clk); +DEFINE_CLOCK1(firi_clk, 0, MXC_CCM_CGR2, 12, firi, NULL, &usb_pll_clk); + +DEFINE_CLOCK(sdma_clk2, 0, NULL, 0, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(usb_clk1, 0, NULL, 0, usb_get_rate, NULL, &usb_pll_clk); +DEFINE_CLOCK(nfc_clk, 0, NULL, 0, nfc_get_rate, NULL, &ahb_clk); +DEFINE_CLOCK(scc_clk, 0, NULL, 0, NULL, NULL, &ipg_clk); +DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk); + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK(NULL, "emi", emi_clk) + _REGISTER_CLOCK("imx31-cspi.0", NULL, cspi1_clk) + _REGISTER_CLOCK("imx31-cspi.1", NULL, cspi2_clk) + _REGISTER_CLOCK("imx31-cspi.2", NULL, cspi3_clk) + _REGISTER_CLOCK(NULL, "gpt", gpt_clk) + _REGISTER_CLOCK(NULL, "pwm", pwm_clk) + _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) + _REGISTER_CLOCK(NULL, "rtc", rtc_clk) + _REGISTER_CLOCK(NULL, "epit", epit1_clk) + _REGISTER_CLOCK(NULL, "epit", epit2_clk) + _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) + _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) + _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) + _REGISTER_CLOCK(NULL, "kpp", kpp_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk1) + _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk2) + _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk1) + _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk2) + _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk1) + _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk2) + _REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1) + _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2) + _REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk) + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) + _REGISTER_CLOCK("imx-uart.3", NULL, uart4_clk) + _REGISTER_CLOCK("imx-uart.4", NULL, uart5_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) + _REGISTER_CLOCK("mxc_w1.0", NULL, owire_clk) + _REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc1_clk) + _REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc2_clk) + _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) + _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) + _REGISTER_CLOCK(NULL, "firi", firi_clk) + _REGISTER_CLOCK(NULL, "ata", ata_clk) + _REGISTER_CLOCK(NULL, "rtic", rtic_clk) + _REGISTER_CLOCK(NULL, "rng", rng_clk) + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk1) + _REGISTER_CLOCK(NULL, "sdma_ipg", sdma_clk2) + _REGISTER_CLOCK(NULL, "mstick", mstick1_clk) + _REGISTER_CLOCK(NULL, "mstick", mstick2_clk) + _REGISTER_CLOCK(NULL, "scc", scc_clk) + _REGISTER_CLOCK(NULL, "iim", iim_clk) + _REGISTER_CLOCK(NULL, "mpeg4", mpeg4_clk) + _REGISTER_CLOCK(NULL, "mbx", mbx_clk) +}; + +int __init mx31_clocks_init(unsigned long fref) +{ + u32 reg; + + ckih_rate = fref; + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + /* change the csi_clk parent if necessary */ + reg = __raw_readl(MXC_CCM_CCMR); + if (!(reg & MXC_CCM_CCMR_CSCS)) + if (clk_set_parent(&csi_clk, &usb_pll_clk)) + pr_err("%s: error changing csi_clk parent\n", __func__); + + + /* Turn off all possible clocks */ + __raw_writel((3 << 4), MXC_CCM_CGR0); + __raw_writel(0, MXC_CCM_CGR1); + __raw_writel((3 << 8) | (3 << 14) | (3 << 16)| + 1 << 27 | 1 << 28, /* Bit 27 and 28 are not defined for + MX32, but still required to be set */ + MXC_CCM_CGR2); + + /* + * Before turning off usb_pll make sure ipg_per_clk is generated + * by ipg_clk and not usb_pll. + */ + __raw_writel(__raw_readl(MXC_CCM_CCMR) | (1 << 24), MXC_CCM_CCMR); + + usb_pll_disable(&usb_pll_clk); + + pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk)); + + clk_enable(&gpt_clk); + clk_enable(&emi_clk); + clk_enable(&iim_clk); + + clk_enable(&serial_pll_clk); + + mx31_read_cpu_rev(); + + if (mx31_revision() >= IMX_CHIP_REVISION_2_0) { + reg = __raw_readl(MXC_CCM_PMCR1); + /* No PLL restart on DVFS switch; enable auto EMI handshake */ + reg |= MXC_CCM_PMCR1_PLLRDIS | MXC_CCM_PMCR1_EMIRQ_EN; + __raw_writel(reg, MXC_CCM_PMCR1); + } + + mxc_timer_init(&ipg_clk, MX31_IO_ADDRESS(MX31_GPT1_BASE_ADDR), + MX31_INT_GPT); + + return 0; +} diff --git a/arch/arm/mach-imx/clock-imx35.c b/arch/arm/mach-imx/clock-imx35.c new file mode 100644 index 00000000..5a4cc1ea --- /dev/null +++ b/arch/arm/mach-imx/clock-imx35.c @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2009 by Sascha Hauer, Pengutronix + * + * 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/list.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/clkdev.h> + +#include <mach/clock.h> +#include <mach/hardware.h> +#include <mach/common.h> + +#define CCM_BASE MX35_IO_ADDRESS(MX35_CCM_BASE_ADDR) + +#define CCM_CCMR 0x00 +#define CCM_PDR0 0x04 +#define CCM_PDR1 0x08 +#define CCM_PDR2 0x0C +#define CCM_PDR3 0x10 +#define CCM_PDR4 0x14 +#define CCM_RCSR 0x18 +#define CCM_MPCTL 0x1C +#define CCM_PPCTL 0x20 +#define CCM_ACMR 0x24 +#define CCM_COSR 0x28 +#define CCM_CGR0 0x2C +#define CCM_CGR1 0x30 +#define CCM_CGR2 0x34 +#define CCM_CGR3 0x38 + +#ifdef HAVE_SET_RATE_SUPPORT +static void calc_dividers(u32 div, u32 *pre, u32 *post, u32 maxpost) +{ + u32 min_pre, temp_pre, old_err, err; + + min_pre = (div - 1) / maxpost + 1; + old_err = 8; + + for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) { + if (div > (temp_pre * maxpost)) + break; + + if (div < (temp_pre * temp_pre)) + continue; + + 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; +} + +/* get the best values for a 3-bit divider combined with a 6-bit divider */ +static void calc_dividers_3_6(u32 div, u32 *pre, u32 *post) +{ + if (div >= 512) { + *pre = 8; + *post = 64; + } else if (div >= 64) { + calc_dividers(div, pre, post, 64); + } else if (div <= 8) { + *pre = div; + *post = 1; + } else { + *pre = 1; + *post = div; + } +} + +/* get the best values for two cascaded 3-bit dividers */ +static void calc_dividers_3_3(u32 div, u32 *pre, u32 *post) +{ + if (div >= 64) { + *pre = *post = 8; + } else if (div > 8) { + calc_dividers(div, pre, post, 8); + } else { + *pre = 1; + *post = div; + } +} +#endif + +static unsigned long get_rate_mpll(void) +{ + ulong mpctl = __raw_readl(CCM_BASE + CCM_MPCTL); + + return mxc_decode_pll(mpctl, 24000000); +} + +static unsigned long get_rate_ppll(void) +{ + ulong ppctl = __raw_readl(CCM_BASE + CCM_PPCTL); + + return mxc_decode_pll(ppctl, 24000000); +} + +struct arm_ahb_div { + unsigned char arm, ahb, sel; +}; + +static struct arm_ahb_div clk_consumer[] = { + { .arm = 1, .ahb = 4, .sel = 0}, + { .arm = 1, .ahb = 3, .sel = 1}, + { .arm = 2, .ahb = 2, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 4, .ahb = 1, .sel = 0}, + { .arm = 1, .ahb = 5, .sel = 0}, + { .arm = 1, .ahb = 8, .sel = 0}, + { .arm = 1, .ahb = 6, .sel = 1}, + { .arm = 2, .ahb = 4, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, + { .arm = 4, .ahb = 2, .sel = 0}, + { .arm = 0, .ahb = 0, .sel = 0}, +}; + +static unsigned long get_rate_arm(void) +{ + unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0); + struct arm_ahb_div *aad; + unsigned long fref = get_rate_mpll(); + + aad = &clk_consumer[(pdr0 >> 16) & 0xf]; + if (aad->sel) + fref = fref * 3 / 4; + + return fref / aad->arm; +} + +static unsigned long get_rate_ahb(struct clk *clk) +{ + unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0); + struct arm_ahb_div *aad; + unsigned long fref = get_rate_arm(); + + aad = &clk_consumer[(pdr0 >> 16) & 0xf]; + + return fref / aad->ahb; +} + +static unsigned long get_rate_ipg(struct clk *clk) +{ + return get_rate_ahb(NULL) >> 1; +} + +static unsigned long get_rate_uart(struct clk *clk) +{ + unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3); + unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4); + unsigned long div = ((pdr4 >> 10) & 0x3f) + 1; + + if (pdr3 & (1 << 14)) + return get_rate_arm() / div; + else + return get_rate_ppll() / div; +} + +static unsigned long get_rate_sdhc(struct clk *clk) +{ + unsigned long pdr3 = __raw_readl(CCM_BASE + CCM_PDR3); + unsigned long div, rate; + + if (pdr3 & (1 << 6)) + rate = get_rate_arm(); + else + rate = get_rate_ppll(); + + switch (clk->id) { + default: + case 0: + div = pdr3 & 0x3f; + break; + case 1: + div = (pdr3 >> 8) & 0x3f; + break; + case 2: + div = (pdr3 >> 16) & 0x3f; + break; + } + + return rate / (div + 1); +} + +static unsigned long get_rate_mshc(struct clk *clk) +{ + unsigned long pdr1 = __raw_readl(CCM_BASE + CCM_PDR1); + unsigned long div1, div2, rate; + + if (pdr1 & (1 << 7)) + rate = get_rate_arm(); + else + rate = get_rate_ppll(); + + div1 = (pdr1 >> 29) & 0x7; + div2 = (pdr1 >> 22) & 0x3f; + + return rate / ((div1 + 1) * (div2 + 1)); +} + +static unsigned long get_rate_ssi(struct clk *clk) +{ + unsigned long pdr2 = __raw_readl(CCM_BASE + CCM_PDR2); + unsigned long div1, div2, rate; + + if (pdr2 & (1 << 6)) + rate = get_rate_arm(); + else + rate = get_rate_ppll(); + + switch (clk->id) { + default: + case 0: + div1 = pdr2 & 0x3f; + div2 = (pdr2 >> 24) & 0x7; + break; + case 1: + div1 = (pdr2 >> 8) & 0x3f; + div2 = (pdr2 >> 27) & 0x7; + break; + } + + return rate / ((div1 + 1) * (div2 + 1)); +} + +static unsigned long get_rate_csi(struct clk *clk) +{ + unsigned long pdr2 = __raw_readl(CCM_BASE + CCM_PDR2); + unsigned long rate; + + if (pdr2 & (1 << 7)) + rate = get_rate_arm(); + else + rate = get_rate_ppll(); + + return rate / (((pdr2 >> 16) & 0x3f) + 1); +} + +static unsigned long get_rate_otg(struct clk *clk) +{ + unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4); + unsigned long rate; + + if (pdr4 & (1 << 9)) + rate = get_rate_arm(); + else + rate = get_rate_ppll(); + + return rate / (((pdr4 >> 22) & 0x3f) + 1); +} + +static unsigned long get_rate_ipg_per(struct clk *clk) +{ + unsigned long pdr0 = __raw_readl(CCM_BASE + CCM_PDR0); + unsigned long pdr4 = __raw_readl(CCM_BASE + CCM_PDR4); + unsigned long div; + + if (pdr0 & (1 << 26)) { + div = (pdr4 >> 16) & 0x3f; + return get_rate_arm() / (div + 1); + } else { + div = (pdr0 >> 12) & 0x7; + return get_rate_ahb(NULL) / (div + 1); + } +} + +static unsigned long get_rate_hsp(struct clk *clk) +{ + unsigned long hsp_podf = (__raw_readl(CCM_BASE + CCM_PDR0) >> 20) & 0x03; + unsigned long fref = get_rate_mpll(); + + if (fref > 400 * 1000 * 1000) { + switch (hsp_podf) { + case 0: + return fref >> 2; + case 1: + return fref >> 3; + case 2: + return fref / 3; + } + } else { + switch (hsp_podf) { + case 0: + case 2: + return fref / 3; + case 1: + return fref / 6; + } + } + + return 0; +} + +static int clk_cgr_enable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg |= 3 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void clk_cgr_disable(struct clk *clk) +{ + u32 reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(3 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +#define DEFINE_CLOCK(name, i, er, es, gr, sr) \ + static struct clk name = { \ + .id = i, \ + .enable_reg = CCM_BASE + er, \ + .enable_shift = es, \ + .get_rate = gr, \ + .set_rate = sr, \ + .enable = clk_cgr_enable, \ + .disable = clk_cgr_disable, \ + } + +DEFINE_CLOCK(asrc_clk, 0, CCM_CGR0, 0, NULL, NULL); +DEFINE_CLOCK(ata_clk, 0, CCM_CGR0, 2, get_rate_ipg, NULL); +/* DEFINE_CLOCK(audmux_clk, 0, CCM_CGR0, 4, NULL, NULL); */ +DEFINE_CLOCK(can1_clk, 0, CCM_CGR0, 6, get_rate_ipg, NULL); +DEFINE_CLOCK(can2_clk, 1, CCM_CGR0, 8, get_rate_ipg, NULL); +DEFINE_CLOCK(cspi1_clk, 0, CCM_CGR0, 10, get_rate_ipg, NULL); +DEFINE_CLOCK(cspi2_clk, 1, CCM_CGR0, 12, get_rate_ipg, NULL); +DEFINE_CLOCK(ect_clk, 0, CCM_CGR0, 14, get_rate_ipg, NULL); +DEFINE_CLOCK(edio_clk, 0, CCM_CGR0, 16, NULL, NULL); +DEFINE_CLOCK(emi_clk, 0, CCM_CGR0, 18, get_rate_ipg, NULL); +DEFINE_CLOCK(epit1_clk, 0, CCM_CGR0, 20, get_rate_ipg, NULL); +DEFINE_CLOCK(epit2_clk, 1, CCM_CGR0, 22, get_rate_ipg, NULL); +DEFINE_CLOCK(esai_clk, 0, CCM_CGR0, 24, NULL, NULL); +DEFINE_CLOCK(esdhc1_clk, 0, CCM_CGR0, 26, get_rate_sdhc, NULL); +DEFINE_CLOCK(esdhc2_clk, 1, CCM_CGR0, 28, get_rate_sdhc, NULL); +DEFINE_CLOCK(esdhc3_clk, 2, CCM_CGR0, 30, get_rate_sdhc, NULL); + +DEFINE_CLOCK(fec_clk, 0, CCM_CGR1, 0, get_rate_ipg, NULL); +DEFINE_CLOCK(gpio1_clk, 0, CCM_CGR1, 2, NULL, NULL); +DEFINE_CLOCK(gpio2_clk, 1, CCM_CGR1, 4, NULL, NULL); +DEFINE_CLOCK(gpio3_clk, 2, CCM_CGR1, 6, NULL, NULL); +DEFINE_CLOCK(gpt_clk, 0, CCM_CGR1, 8, get_rate_ipg, NULL); +DEFINE_CLOCK(i2c1_clk, 0, CCM_CGR1, 10, get_rate_ipg_per, NULL); +DEFINE_CLOCK(i2c2_clk, 1, CCM_CGR1, 12, get_rate_ipg_per, NULL); +DEFINE_CLOCK(i2c3_clk, 2, CCM_CGR1, 14, get_rate_ipg_per, NULL); +DEFINE_CLOCK(iomuxc_clk, 0, CCM_CGR1, 16, NULL, NULL); +DEFINE_CLOCK(ipu_clk, 0, CCM_CGR1, 18, get_rate_hsp, NULL); +DEFINE_CLOCK(kpp_clk, 0, CCM_CGR1, 20, get_rate_ipg, NULL); +DEFINE_CLOCK(mlb_clk, 0, CCM_CGR1, 22, get_rate_ahb, NULL); +DEFINE_CLOCK(mshc_clk, 0, CCM_CGR1, 24, get_rate_mshc, NULL); +DEFINE_CLOCK(owire_clk, 0, CCM_CGR1, 26, get_rate_ipg_per, NULL); +DEFINE_CLOCK(pwm_clk, 0, CCM_CGR1, 28, get_rate_ipg_per, NULL); +DEFINE_CLOCK(rngc_clk, 0, CCM_CGR1, 30, get_rate_ipg, NULL); + +DEFINE_CLOCK(rtc_clk, 0, CCM_CGR2, 0, get_rate_ipg, NULL); +DEFINE_CLOCK(rtic_clk, 0, CCM_CGR2, 2, get_rate_ahb, NULL); +DEFINE_CLOCK(scc_clk, 0, CCM_CGR2, 4, get_rate_ipg, NULL); +DEFINE_CLOCK(sdma_clk, 0, CCM_CGR2, 6, NULL, NULL); +DEFINE_CLOCK(spba_clk, 0, CCM_CGR2, 8, get_rate_ipg, NULL); +DEFINE_CLOCK(spdif_clk, 0, CCM_CGR2, 10, NULL, NULL); +DEFINE_CLOCK(ssi1_clk, 0, CCM_CGR2, 12, get_rate_ssi, NULL); +DEFINE_CLOCK(ssi2_clk, 1, CCM_CGR2, 14, get_rate_ssi, NULL); +DEFINE_CLOCK(uart1_clk, 0, CCM_CGR2, 16, get_rate_uart, NULL); +DEFINE_CLOCK(uart2_clk, 1, CCM_CGR2, 18, get_rate_uart, NULL); +DEFINE_CLOCK(uart3_clk, 2, CCM_CGR2, 20, get_rate_uart, NULL); +DEFINE_CLOCK(usbotg_clk, 0, CCM_CGR2, 22, get_rate_otg, NULL); +DEFINE_CLOCK(wdog_clk, 0, CCM_CGR2, 24, NULL, NULL); +DEFINE_CLOCK(max_clk, 0, CCM_CGR2, 26, NULL, NULL); +DEFINE_CLOCK(audmux_clk, 0, CCM_CGR2, 30, NULL, NULL); + +DEFINE_CLOCK(csi_clk, 0, CCM_CGR3, 0, get_rate_csi, NULL); +DEFINE_CLOCK(iim_clk, 0, CCM_CGR3, 2, NULL, NULL); +DEFINE_CLOCK(gpu2d_clk, 0, CCM_CGR3, 4, NULL, NULL); + +DEFINE_CLOCK(usbahb_clk, 0, 0, 0, get_rate_ahb, NULL); + +static int clk_dummy_enable(struct clk *clk) +{ + return 0; +} + +static void clk_dummy_disable(struct clk *clk) +{ +} + +static unsigned long get_rate_nfc(struct clk *clk) +{ + unsigned long div1; + + div1 = (__raw_readl(CCM_BASE + CCM_PDR4) >> 28) + 1; + + return get_rate_ahb(NULL) / div1; +} + +/* NAND Controller: It seems it can't be disabled */ +static struct clk nfc_clk = { + .id = 0, + .enable_reg = 0, + .enable_shift = 0, + .get_rate = get_rate_nfc, + .set_rate = NULL, /* set_rate_nfc, */ + .enable = clk_dummy_enable, + .disable = clk_dummy_disable +}; + +#define _REGISTER_CLOCK(d, n, c) \ + { \ + .dev_id = d, \ + .con_id = n, \ + .clk = &c, \ + }, + +static struct clk_lookup lookups[] = { + _REGISTER_CLOCK(NULL, "asrc", asrc_clk) + _REGISTER_CLOCK(NULL, "ata", ata_clk) + _REGISTER_CLOCK("flexcan.0", NULL, can1_clk) + _REGISTER_CLOCK("flexcan.1", NULL, can2_clk) + _REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk) + _REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk) + _REGISTER_CLOCK(NULL, "ect", ect_clk) + _REGISTER_CLOCK(NULL, "edio", edio_clk) + _REGISTER_CLOCK(NULL, "emi", emi_clk) + _REGISTER_CLOCK("imx-epit.0", NULL, epit1_clk) + _REGISTER_CLOCK("imx-epit.1", NULL, epit2_clk) + _REGISTER_CLOCK(NULL, "esai", esai_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk) + _REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk) + _REGISTER_CLOCK("fec.0", NULL, fec_clk) + _REGISTER_CLOCK(NULL, "gpio", gpio1_clk) + _REGISTER_CLOCK(NULL, "gpio", gpio2_clk) + _REGISTER_CLOCK(NULL, "gpio", gpio3_clk) + _REGISTER_CLOCK("gpt.0", NULL, gpt_clk) + _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk) + _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) + _REGISTER_CLOCK("imx-i2c.2", NULL, i2c3_clk) + _REGISTER_CLOCK(NULL, "iomuxc", iomuxc_clk) + _REGISTER_CLOCK("ipu-core", NULL, ipu_clk) + _REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk) + _REGISTER_CLOCK(NULL, "kpp", kpp_clk) + _REGISTER_CLOCK(NULL, "mlb", mlb_clk) + _REGISTER_CLOCK(NULL, "mshc", mshc_clk) + _REGISTER_CLOCK("mxc_w1", NULL, owire_clk) + _REGISTER_CLOCK(NULL, "pwm", pwm_clk) + _REGISTER_CLOCK(NULL, "rngc", rngc_clk) + _REGISTER_CLOCK(NULL, "rtc", rtc_clk) + _REGISTER_CLOCK(NULL, "rtic", rtic_clk) + _REGISTER_CLOCK(NULL, "scc", scc_clk) + _REGISTER_CLOCK("imx-sdma", NULL, sdma_clk) + _REGISTER_CLOCK(NULL, "spba", spba_clk) + _REGISTER_CLOCK(NULL, "spdif", spdif_clk) + _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk) + _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk) + _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk) + _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk) + _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb", usbotg_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb", usbotg_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk) + _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usbahb_clk) + _REGISTER_CLOCK("imx2-wdt.0", NULL, wdog_clk) + _REGISTER_CLOCK(NULL, "max", max_clk) + _REGISTER_CLOCK(NULL, "audmux", audmux_clk) + _REGISTER_CLOCK(NULL, "csi", csi_clk) + _REGISTER_CLOCK(NULL, "iim", iim_clk) + _REGISTER_CLOCK(NULL, "gpu2d", gpu2d_clk) + _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk) +}; + +int __init mx35_clocks_init() +{ + unsigned int cgr2 = 3 << 26, cgr3 = 0; + +#if defined(CONFIG_DEBUG_LL) && !defined(CONFIG_DEBUG_ICEDCC) + cgr2 |= 3 << 16; +#endif + + clkdev_add_table(lookups, ARRAY_SIZE(lookups)); + + /* Turn off all clocks except the ones we need to survive, namely: + * EMI, GPIO1/2/3, GPT, IOMUX, MAX and eventually uart + */ + __raw_writel((3 << 18), CCM_BASE + CCM_CGR0); + __raw_writel((3 << 2) | (3 << 4) | (3 << 6) | (3 << 8) | (3 << 16), + CCM_BASE + CCM_CGR1); + + /* + * Check if we came up in internal boot mode. If yes, we need some + * extra clocks turned on, otherwise the MX35 boot ROM code will + * hang after a watchdog reset. + */ + if (!(__raw_readl(CCM_BASE + CCM_RCSR) & (3 << 10))) { + /* Additionally turn on UART1, SCC, and IIM clocks */ + cgr2 |= 3 << 16 | 3 << 4; + cgr3 |= 3 << 2; + } + + __raw_writel(cgr2, CCM_BASE + CCM_CGR2); + __raw_writel(cgr3, CCM_BASE + CCM_CGR3); + + clk_enable(&iim_clk); + mx35_read_cpu_rev(); + +#ifdef CONFIG_MXC_USE_EPIT + epit_timer_init(&epit1_clk, + MX35_IO_ADDRESS(MX35_EPIT1_BASE_ADDR), MX35_INT_EPIT1); +#else + mxc_timer_init(&gpt_clk, + MX35_IO_ADDRESS(MX35_GPT1_BASE_ADDR), MX35_INT_GPT); +#endif + + return 0; +} diff --git a/arch/arm/mach-imx/cpu-imx27.c b/arch/arm/mach-imx/cpu-imx27.c new file mode 100644 index 00000000..3b117be3 --- /dev/null +++ b/arch/arm/mach-imx/cpu-imx27.c @@ -0,0 +1,76 @@ +/* + * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Juergen Beisert, kernel@pengutronix.de + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +/* + * i.MX27 specific CPU detection code + */ + +#include <linux/io.h> +#include <linux/module.h> + +#include <mach/hardware.h> + +static int cpu_silicon_rev = -1; +static int cpu_partnumber; + +#define SYS_CHIP_ID 0x00 /* The offset of CHIP ID register */ + +static void query_silicon_parameter(void) +{ + u32 val; + /* + * now we have access to the IO registers. As we need + * the silicon revision very early we read it here to + * avoid any further hooks + */ + val = __raw_readl(MX27_IO_ADDRESS(MX27_SYSCTRL_BASE_ADDR + + SYS_CHIP_ID)); + + switch (val >> 28) { + case 0: + cpu_silicon_rev = IMX_CHIP_REVISION_1_0; + break; + case 1: + cpu_silicon_rev = IMX_CHIP_REVISION_2_0; + break; + case 2: + cpu_silicon_rev = IMX_CHIP_REVISION_2_1; + break; + default: + cpu_silicon_rev = IMX_CHIP_REVISION_UNKNOWN; + } + cpu_partnumber = (int)((val >> 12) & 0xFFFF); +} + +/* + * Returns: + * the silicon revision of the cpu + * -EINVAL - not a mx27 + */ +int mx27_revision(void) +{ + if (cpu_silicon_rev == -1) + query_silicon_parameter(); + + if (cpu_partnumber != 0x8821) + return -EINVAL; + + return cpu_silicon_rev; +} +EXPORT_SYMBOL(mx27_revision); diff --git a/arch/arm/mach-imx/cpu-imx31.c b/arch/arm/mach-imx/cpu-imx31.c new file mode 100644 index 00000000..a3780700 --- /dev/null +++ b/arch/arm/mach-imx/cpu-imx31.c @@ -0,0 +1,57 @@ +/* + * MX31 CPU type detection + * + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <mach/iim.h> + +unsigned int mx31_cpu_rev; +EXPORT_SYMBOL(mx31_cpu_rev); + +static struct { + u8 srev; + const char *name; + const char *v; + unsigned int rev; +} mx31_cpu_type[] __initdata = { + { .srev = 0x00, .name = "i.MX31(L)", .v = "1.0", .rev = IMX_CHIP_REVISION_1_0 }, + { .srev = 0x10, .name = "i.MX31", .v = "1.1", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x11, .name = "i.MX31L", .v = "1.1", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x12, .name = "i.MX31", .v = "1.15", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x13, .name = "i.MX31L", .v = "1.15", .rev = IMX_CHIP_REVISION_1_1 }, + { .srev = 0x14, .name = "i.MX31", .v = "1.2", .rev = IMX_CHIP_REVISION_1_2 }, + { .srev = 0x15, .name = "i.MX31L", .v = "1.2", .rev = IMX_CHIP_REVISION_1_2 }, + { .srev = 0x28, .name = "i.MX31", .v = "2.0", .rev = IMX_CHIP_REVISION_2_0 }, + { .srev = 0x29, .name = "i.MX31L", .v = "2.0", .rev = IMX_CHIP_REVISION_2_0 }, +}; + +void __init mx31_read_cpu_rev(void) +{ + u32 i, srev; + + /* read SREV register from IIM module */ + srev = __raw_readl(MX31_IO_ADDRESS(MX31_IIM_BASE_ADDR + MXC_IIMSREV)); + + for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++) + if (srev == mx31_cpu_type[i].srev) { + printk(KERN_INFO + "CPU identified as %s, silicon rev %s\n", + mx31_cpu_type[i].name, mx31_cpu_type[i].v); + + mx31_cpu_rev = mx31_cpu_type[i].rev; + return; + } + + mx31_cpu_rev = IMX_CHIP_REVISION_UNKNOWN; + + printk(KERN_WARNING "Unknown CPU identifier. srev = %02x\n", srev); +} diff --git a/arch/arm/mach-imx/cpu-imx35.c b/arch/arm/mach-imx/cpu-imx35.c new file mode 100644 index 00000000..6637cd81 --- /dev/null +++ b/arch/arm/mach-imx/cpu-imx35.c @@ -0,0 +1,44 @@ +/* + * MX35 CPU type detection + * + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#include <linux/module.h> +#include <linux/io.h> +#include <mach/hardware.h> +#include <mach/iim.h> + +unsigned int mx35_cpu_rev; +EXPORT_SYMBOL(mx35_cpu_rev); + +void __init mx35_read_cpu_rev(void) +{ + u32 rev; + char *srev; + + rev = __raw_readl(MX35_IO_ADDRESS(MX35_IIM_BASE_ADDR + MXC_IIMSREV)); + switch (rev) { + case 0x00: + mx35_cpu_rev = IMX_CHIP_REVISION_1_0; + srev = "1.0"; + break; + case 0x10: + mx35_cpu_rev = IMX_CHIP_REVISION_2_0; + srev = "2.0"; + break; + case 0x11: + mx35_cpu_rev = IMX_CHIP_REVISION_2_1; + srev = "2.1"; + break; + default: + mx35_cpu_rev = IMX_CHIP_REVISION_UNKNOWN; + srev = "unknown"; + } + + printk(KERN_INFO "CPU identified as i.MX35, silicon rev %s\n", srev); +} diff --git a/arch/arm/mach-imx/crmregs-imx31.h b/arch/arm/mach-imx/crmregs-imx31.h new file mode 100644 index 00000000..37a8a07b --- /dev/null +++ b/arch/arm/mach-imx/crmregs-imx31.h @@ -0,0 +1,248 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __ARCH_ARM_MACH_MX3_CRM_REGS_H__ +#define __ARCH_ARM_MACH_MX3_CRM_REGS_H__ + +#define CKIH_CLK_FREQ 26000000 +#define CKIH_CLK_FREQ_27MHZ 27000000 +#define CKIL_CLK_FREQ 32768 + +#define MXC_CCM_BASE MX31_IO_ADDRESS(MX31_CCM_BASE_ADDR) + +/* Register addresses */ +#define MXC_CCM_CCMR (MXC_CCM_BASE + 0x00) +#define MXC_CCM_PDR0 (MXC_CCM_BASE + 0x04) +#define MXC_CCM_PDR1 (MXC_CCM_BASE + 0x08) +#define MXC_CCM_RCSR (MXC_CCM_BASE + 0x0C) +#define MXC_CCM_MPCTL (MXC_CCM_BASE + 0x10) +#define MXC_CCM_UPCTL (MXC_CCM_BASE + 0x14) +#define MXC_CCM_SRPCTL (MXC_CCM_BASE + 0x18) +#define MXC_CCM_COSR (MXC_CCM_BASE + 0x1C) +#define MXC_CCM_CGR0 (MXC_CCM_BASE + 0x20) +#define MXC_CCM_CGR1 (MXC_CCM_BASE + 0x24) +#define MXC_CCM_CGR2 (MXC_CCM_BASE + 0x28) +#define MXC_CCM_WIMR (MXC_CCM_BASE + 0x2C) +#define MXC_CCM_LDC (MXC_CCM_BASE + 0x30) +#define MXC_CCM_DCVR0 (MXC_CCM_BASE + 0x34) +#define MXC_CCM_DCVR1 (MXC_CCM_BASE + 0x38) +#define MXC_CCM_DCVR2 (MXC_CCM_BASE + 0x3C) +#define MXC_CCM_DCVR3 (MXC_CCM_BASE + 0x40) +#define MXC_CCM_LTR0 (MXC_CCM_BASE + 0x44) +#define MXC_CCM_LTR1 (MXC_CCM_BASE + 0x48) +#define MXC_CCM_LTR2 (MXC_CCM_BASE + 0x4C) +#define MXC_CCM_LTR3 (MXC_CCM_BASE + 0x50) +#define MXC_CCM_LTBR0 (MXC_CCM_BASE + 0x54) +#define MXC_CCM_LTBR1 (MXC_CCM_BASE + 0x58) +#define MXC_CCM_PMCR0 (MXC_CCM_BASE + 0x5C) +#define MXC_CCM_PMCR1 (MXC_CCM_BASE + 0x60) +#define MXC_CCM_PDR2 (MXC_CCM_BASE + 0x64) + +/* Register bit definitions */ +#define MXC_CCM_CCMR_WBEN (1 << 27) +#define MXC_CCM_CCMR_CSCS (1 << 25) +#define MXC_CCM_CCMR_PERCS (1 << 24) +#define MXC_CCM_CCMR_SSI1S_OFFSET 18 +#define MXC_CCM_CCMR_SSI1S_MASK (0x3 << 18) +#define MXC_CCM_CCMR_SSI2S_OFFSET 21 +#define MXC_CCM_CCMR_SSI2S_MASK (0x3 << 21) +#define MXC_CCM_CCMR_LPM_OFFSET 14 +#define MXC_CCM_CCMR_LPM_MASK (0x3 << 14) +#define MXC_CCM_CCMR_FIRS_OFFSET 11 +#define MXC_CCM_CCMR_FIRS_MASK (0x3 << 11) +#define MXC_CCM_CCMR_UPE (1 << 9) +#define MXC_CCM_CCMR_SPE (1 << 8) +#define MXC_CCM_CCMR_MDS (1 << 7) +#define MXC_CCM_CCMR_SBYCS (1 << 4) +#define MXC_CCM_CCMR_MPE (1 << 3) +#define MXC_CCM_CCMR_PRCS_OFFSET 1 +#define MXC_CCM_CCMR_PRCS_MASK (0x3 << 1) + +#define MXC_CCM_PDR0_CSI_PODF_OFFSET 26 +#define MXC_CCM_PDR0_CSI_PODF_MASK (0x3F << 26) +#define MXC_CCM_PDR0_CSI_PRDF_OFFSET 23 +#define MXC_CCM_PDR0_CSI_PRDF_MASK (0x7 << 23) +#define MXC_CCM_PDR0_PER_PODF_OFFSET 16 +#define MXC_CCM_PDR0_PER_PODF_MASK (0x1F << 16) +#define MXC_CCM_PDR0_HSP_PODF_OFFSET 11 +#define MXC_CCM_PDR0_HSP_PODF_MASK (0x7 << 11) +#define MXC_CCM_PDR0_NFC_PODF_OFFSET 8 +#define MXC_CCM_PDR0_NFC_PODF_MASK (0x7 << 8) +#define MXC_CCM_PDR0_IPG_PODF_OFFSET 6 +#define MXC_CCM_PDR0_IPG_PODF_MASK (0x3 << 6) +#define MXC_CCM_PDR0_MAX_PODF_OFFSET 3 +#define MXC_CCM_PDR0_MAX_PODF_MASK (0x7 << 3) +#define MXC_CCM_PDR0_MCU_PODF_OFFSET 0 +#define MXC_CCM_PDR0_MCU_PODF_MASK 0x7 + +#define MXC_CCM_PDR1_USB_PRDF_OFFSET 30 +#define MXC_CCM_PDR1_USB_PRDF_MASK (0x3 << 30) +#define MXC_CCM_PDR1_USB_PODF_OFFSET 27 +#define MXC_CCM_PDR1_USB_PODF_MASK (0x7 << 27) +#define MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET 24 +#define MXC_CCM_PDR1_FIRI_PRE_PODF_MASK (0x7 << 24) +#define MXC_CCM_PDR1_FIRI_PODF_OFFSET 18 +#define MXC_CCM_PDR1_FIRI_PODF_MASK (0x3F << 18) +#define MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET 15 +#define MXC_CCM_PDR1_SSI2_PRE_PODF_MASK (0x7 << 15) +#define MXC_CCM_PDR1_SSI2_PODF_OFFSET 9 +#define MXC_CCM_PDR1_SSI2_PODF_MASK (0x3F << 9) +#define MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET 6 +#define MXC_CCM_PDR1_SSI1_PRE_PODF_MASK (0x7 << 6) +#define MXC_CCM_PDR1_SSI1_PODF_OFFSET 0 +#define MXC_CCM_PDR1_SSI1_PODF_MASK 0x3F + +/* Bit definitions for RCSR */ +#define MXC_CCM_RCSR_NF16B 0x80000000 + +/* + * LTR0 register offsets + */ +#define MXC_CCM_LTR0_DIV3CK_OFFSET 1 +#define MXC_CCM_LTR0_DIV3CK_MASK (0x3 << 1) +#define MXC_CCM_LTR0_DNTHR_OFFSET 16 +#define MXC_CCM_LTR0_DNTHR_MASK (0x3F << 16) +#define MXC_CCM_LTR0_UPTHR_OFFSET 22 +#define MXC_CCM_LTR0_UPTHR_MASK (0x3F << 22) + +/* + * LTR1 register offsets + */ +#define MXC_CCM_LTR1_PNCTHR_OFFSET 0 +#define MXC_CCM_LTR1_PNCTHR_MASK 0x3F +#define MXC_CCM_LTR1_UPCNT_OFFSET 6 +#define MXC_CCM_LTR1_UPCNT_MASK (0xFF << 6) +#define MXC_CCM_LTR1_DNCNT_OFFSET 14 +#define MXC_CCM_LTR1_DNCNT_MASK (0xFF << 14) +#define MXC_CCM_LTR1_LTBRSR_MASK 0x400000 +#define MXC_CCM_LTR1_LTBRSR_OFFSET 22 +#define MXC_CCM_LTR1_LTBRSR 0x400000 +#define MXC_CCM_LTR1_LTBRSH 0x800000 + +/* + * LTR2 bit definitions. x ranges from 0 for WSW9 to 6 for WSW15 + */ +#define MXC_CCM_LTR2_WSW_OFFSET(x) (11 + (x) * 3) +#define MXC_CCM_LTR2_WSW_MASK(x) (0x7 << \ + MXC_CCM_LTR2_WSW_OFFSET((x))) +#define MXC_CCM_LTR2_EMAC_OFFSET 0 +#define MXC_CCM_LTR2_EMAC_MASK 0x1FF + +/* + * LTR3 bit definitions. x ranges from 0 for WSW0 to 8 for WSW8 + */ +#define MXC_CCM_LTR3_WSW_OFFSET(x) (5 + (x) * 3) +#define MXC_CCM_LTR3_WSW_MASK(x) (0x7 << \ + MXC_CCM_LTR3_WSW_OFFSET((x))) + +#define MXC_CCM_PMCR0_DFSUP1 0x80000000 +#define MXC_CCM_PMCR0_DFSUP1_SPLL (0 << 31) +#define MXC_CCM_PMCR0_DFSUP1_MPLL (1 << 31) +#define MXC_CCM_PMCR0_DFSUP0 0x40000000 +#define MXC_CCM_PMCR0_DFSUP0_PLL (0 << 30) +#define MXC_CCM_PMCR0_DFSUP0_PDR (1 << 30) +#define MXC_CCM_PMCR0_DFSUP_MASK (0x3 << 30) + +#define DVSUP_TURBO 0 +#define DVSUP_HIGH 1 +#define DVSUP_MEDIUM 2 +#define DVSUP_LOW 3 +#define MXC_CCM_PMCR0_DVSUP_TURBO (DVSUP_TURBO << 28) +#define MXC_CCM_PMCR0_DVSUP_HIGH (DVSUP_HIGH << 28) +#define MXC_CCM_PMCR0_DVSUP_MEDIUM (DVSUP_MEDIUM << 28) +#define MXC_CCM_PMCR0_DVSUP_LOW (DVSUP_LOW << 28) +#define MXC_CCM_PMCR0_DVSUP_OFFSET 28 +#define MXC_CCM_PMCR0_DVSUP_MASK (0x3 << 28) +#define MXC_CCM_PMCR0_UDSC 0x08000000 +#define MXC_CCM_PMCR0_UDSC_MASK (1 << 27) +#define MXC_CCM_PMCR0_UDSC_UP (1 << 27) +#define MXC_CCM_PMCR0_UDSC_DOWN (0 << 27) + +#define MXC_CCM_PMCR0_VSCNT_1 (0x0 << 24) +#define MXC_CCM_PMCR0_VSCNT_2 (0x1 << 24) +#define MXC_CCM_PMCR0_VSCNT_3 (0x2 << 24) +#define MXC_CCM_PMCR0_VSCNT_4 (0x3 << 24) +#define MXC_CCM_PMCR0_VSCNT_5 (0x4 << 24) +#define MXC_CCM_PMCR0_VSCNT_6 (0x5 << 24) +#define MXC_CCM_PMCR0_VSCNT_7 (0x6 << 24) +#define MXC_CCM_PMCR0_VSCNT_8 (0x7 << 24) +#define MXC_CCM_PMCR0_VSCNT_OFFSET 24 +#define MXC_CCM_PMCR0_VSCNT_MASK (0x7 << 24) +#define MXC_CCM_PMCR0_DVFEV 0x00800000 +#define MXC_CCM_PMCR0_DVFIS 0x00400000 +#define MXC_CCM_PMCR0_LBMI 0x00200000 +#define MXC_CCM_PMCR0_LBFL 0x00100000 +#define MXC_CCM_PMCR0_LBCF_4 (0x0 << 18) +#define MXC_CCM_PMCR0_LBCF_8 (0x1 << 18) +#define MXC_CCM_PMCR0_LBCF_12 (0x2 << 18) +#define MXC_CCM_PMCR0_LBCF_16 (0x3 << 18) +#define MXC_CCM_PMCR0_LBCF_OFFSET 18 +#define MXC_CCM_PMCR0_LBCF_MASK (0x3 << 18) +#define MXC_CCM_PMCR0_PTVIS 0x00020000 +#define MXC_CCM_PMCR0_UPDTEN 0x00010000 +#define MXC_CCM_PMCR0_UPDTEN_MASK (0x1 << 16) +#define MXC_CCM_PMCR0_FSVAIM 0x00008000 +#define MXC_CCM_PMCR0_FSVAI_OFFSET 13 +#define MXC_CCM_PMCR0_FSVAI_MASK (0x3 << 13) +#define MXC_CCM_PMCR0_DPVCR 0x00001000 +#define MXC_CCM_PMCR0_DPVV 0x00000800 +#define MXC_CCM_PMCR0_WFIM 0x00000400 +#define MXC_CCM_PMCR0_DRCE3 0x00000200 +#define MXC_CCM_PMCR0_DRCE2 0x00000100 +#define MXC_CCM_PMCR0_DRCE1 0x00000080 +#define MXC_CCM_PMCR0_DRCE0 0x00000040 +#define MXC_CCM_PMCR0_DCR 0x00000020 +#define MXC_CCM_PMCR0_DVFEN 0x00000010 +#define MXC_CCM_PMCR0_PTVAIM 0x00000008 +#define MXC_CCM_PMCR0_PTVAI_OFFSET 1 +#define MXC_CCM_PMCR0_PTVAI_MASK (0x3 << 1) +#define MXC_CCM_PMCR0_DPTEN 0x00000001 + +#define MXC_CCM_PMCR1_DVGP_OFFSET 0 +#define MXC_CCM_PMCR1_DVGP_MASK (0xF) + +#define MXC_CCM_PMCR1_PLLRDIS (0x1 << 7) +#define MXC_CCM_PMCR1_EMIRQ_EN (0x1 << 8) + +#define MXC_CCM_DCVR_ULV_MASK (0x3FF << 22) +#define MXC_CCM_DCVR_ULV_OFFSET 22 +#define MXC_CCM_DCVR_LLV_MASK (0x3FF << 12) +#define MXC_CCM_DCVR_LLV_OFFSET 12 +#define MXC_CCM_DCVR_ELV_MASK (0x3FF << 2) +#define MXC_CCM_DCVR_ELV_OFFSET 2 + +#define MXC_CCM_PDR2_MST2_PDF_MASK (0x3F << 7) +#define MXC_CCM_PDR2_MST2_PDF_OFFSET 7 +#define MXC_CCM_PDR2_MST1_PDF_MASK 0x3F +#define MXC_CCM_PDR2_MST1_PDF_OFFSET 0 + +#define MXC_CCM_COSR_CLKOSEL_MASK 0x0F +#define MXC_CCM_COSR_CLKOSEL_OFFSET 0 +#define MXC_CCM_COSR_CLKOUTDIV_MASK (0x07 << 6) +#define MXC_CCM_COSR_CLKOUTDIV_OFFSET 6 +#define MXC_CCM_COSR_CLKOEN (1 << 9) + +/* + * PMCR0 register offsets + */ +#define MXC_CCM_PMCR0_LBFL_OFFSET 20 +#define MXC_CCM_PMCR0_DFSUP0_OFFSET 30 +#define MXC_CCM_PMCR0_DFSUP1_OFFSET 31 + +#endif /* __ARCH_ARM_MACH_MX3_CRM_REGS_H__ */ diff --git a/arch/arm/mach-imx/devices-imx1.h b/arch/arm/mach-imx/devices-imx1.h new file mode 100644 index 00000000..3aad1e70 --- /dev/null +++ b/arch/arm/mach-imx/devices-imx1.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <mach/mx1.h> +#include <mach/devices-common.h> + +extern const struct imx_imx_fb_data imx1_imx_fb_data; +#define imx1_add_imx_fb(pdata) \ + imx_add_imx_fb(&imx1_imx_fb_data, pdata) + +extern const struct imx_imx_i2c_data imx1_imx_i2c_data; +#define imx1_add_imx_i2c(pdata) \ + imx_add_imx_i2c(&imx1_imx_i2c_data, pdata) + +extern const struct imx_imx_uart_3irq_data imx1_imx_uart_data[]; +#define imx1_add_imx_uart(id, pdata) \ + imx_add_imx_uart_3irq(&imx1_imx_uart_data[id], pdata) +#define imx1_add_imx_uart0(pdata) imx1_add_imx_uart(0, pdata) +#define imx1_add_imx_uart1(pdata) imx1_add_imx_uart(1, pdata) + +extern const struct imx_spi_imx_data imx1_cspi_data[]; +#define imx1_add_cspi(id, pdata) \ + imx_add_spi_imx(&imx1_cspi_data[id], pdata) + +#define imx1_add_spi_imx0(pdata) imx1_add_cspi(0, pdata) +#define imx1_add_spi_imx1(pdata) imx1_add_cspi(1, pdata) diff --git a/arch/arm/mach-imx/devices-imx21.h b/arch/arm/mach-imx/devices-imx21.h new file mode 100644 index 00000000..2628e0c4 --- /dev/null +++ b/arch/arm/mach-imx/devices-imx21.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <mach/mx21.h> +#include <mach/devices-common.h> + +extern const struct imx_imx21_hcd_data imx21_imx21_hcd_data; +#define imx21_add_imx21_hcd(pdata) \ + imx_add_imx21_hcd(&imx21_imx21_hcd_data, pdata) + +extern const struct imx_imx2_wdt_data imx21_imx2_wdt_data; +#define imx21_add_imx2_wdt(pdata) \ + imx_add_imx2_wdt(&imx21_imx2_wdt_data) + +extern const struct imx_imx_fb_data imx21_imx_fb_data; +#define imx21_add_imx_fb(pdata) \ + imx_add_imx_fb(&imx21_imx_fb_data, pdata) + +extern const struct imx_imx_i2c_data imx21_imx_i2c_data; +#define imx21_add_imx_i2c(pdata) \ + imx_add_imx_i2c(&imx21_imx_i2c_data, pdata) + +extern const struct imx_imx_keypad_data imx21_imx_keypad_data; +#define imx21_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx21_imx_keypad_data, pdata) + +extern const struct imx_imx_ssi_data imx21_imx_ssi_data[]; +#define imx21_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx21_imx_ssi_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx21_imx_uart_data[]; +#define imx21_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx21_imx_uart_data[id], pdata) +#define imx21_add_imx_uart0(pdata) imx21_add_imx_uart(0, pdata) +#define imx21_add_imx_uart1(pdata) imx21_add_imx_uart(1, pdata) +#define imx21_add_imx_uart2(pdata) imx21_add_imx_uart(2, pdata) +#define imx21_add_imx_uart3(pdata) imx21_add_imx_uart(3, pdata) + +extern const struct imx_mxc_mmc_data imx21_mxc_mmc_data[]; +#define imx21_add_mxc_mmc(id, pdata) \ + imx_add_mxc_mmc(&imx21_mxc_mmc_data[id], pdata) + +extern const struct imx_mxc_nand_data imx21_mxc_nand_data; +#define imx21_add_mxc_nand(pdata) \ + imx_add_mxc_nand(&imx21_mxc_nand_data, pdata) + +extern const struct imx_mxc_w1_data imx21_mxc_w1_data; +#define imx21_add_mxc_w1(pdata) \ + imx_add_mxc_w1(&imx21_mxc_w1_data) + +extern const struct imx_spi_imx_data imx21_cspi_data[]; +#define imx21_add_cspi(id, pdata) \ + imx_add_spi_imx(&imx21_cspi_data[id], pdata) +#define imx21_add_spi_imx0(pdata) imx21_add_cspi(0, pdata) +#define imx21_add_spi_imx1(pdata) imx21_add_cspi(1, pdata) diff --git a/arch/arm/mach-imx/devices-imx25.h b/arch/arm/mach-imx/devices-imx25.h new file mode 100644 index 00000000..efa0761c --- /dev/null +++ b/arch/arm/mach-imx/devices-imx25.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <mach/mx25.h> +#include <mach/devices-common.h> + +extern const struct imx_fec_data imx25_fec_data; +#define imx25_add_fec(pdata) \ + imx_add_fec(&imx25_fec_data, pdata) + +extern const struct imx_flexcan_data imx25_flexcan_data[]; +#define imx25_add_flexcan(id, pdata) \ + imx_add_flexcan(&imx25_flexcan_data[id], pdata) +#define imx25_add_flexcan0(pdata) imx25_add_flexcan(0, pdata) +#define imx25_add_flexcan1(pdata) imx25_add_flexcan(1, pdata) + +extern const struct imx_fsl_usb2_udc_data imx25_fsl_usb2_udc_data; +#define imx25_add_fsl_usb2_udc(pdata) \ + imx_add_fsl_usb2_udc(&imx25_fsl_usb2_udc_data, pdata) + +extern struct imx_imxdi_rtc_data imx25_imxdi_rtc_data; +#define imx25_add_imxdi_rtc(pdata) \ + imx_add_imxdi_rtc(&imx25_imxdi_rtc_data) + +extern const struct imx_imx2_wdt_data imx25_imx2_wdt_data; +#define imx25_add_imx2_wdt(pdata) \ + imx_add_imx2_wdt(&imx25_imx2_wdt_data) + +extern const struct imx_imx_fb_data imx25_imx_fb_data; +#define imx25_add_imx_fb(pdata) \ + imx_add_imx_fb(&imx25_imx_fb_data, pdata) + +extern const struct imx_imx_i2c_data imx25_imx_i2c_data[]; +#define imx25_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx25_imx_i2c_data[id], pdata) +#define imx25_add_imx_i2c0(pdata) imx25_add_imx_i2c(0, pdata) +#define imx25_add_imx_i2c1(pdata) imx25_add_imx_i2c(1, pdata) +#define imx25_add_imx_i2c2(pdata) imx25_add_imx_i2c(2, pdata) + +extern const struct imx_imx_keypad_data imx25_imx_keypad_data; +#define imx25_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx25_imx_keypad_data, pdata) + +extern const struct imx_imx_ssi_data imx25_imx_ssi_data[]; +#define imx25_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx25_imx_ssi_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx25_imx_uart_data[]; +#define imx25_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx25_imx_uart_data[id], pdata) +#define imx25_add_imx_uart0(pdata) imx25_add_imx_uart(0, pdata) +#define imx25_add_imx_uart1(pdata) imx25_add_imx_uart(1, pdata) +#define imx25_add_imx_uart2(pdata) imx25_add_imx_uart(2, pdata) +#define imx25_add_imx_uart3(pdata) imx25_add_imx_uart(3, pdata) +#define imx25_add_imx_uart4(pdata) imx25_add_imx_uart(4, pdata) + +extern const struct imx_mx2_camera_data imx25_mx2_camera_data; +#define imx25_add_mx2_camera(pdata) \ + imx_add_mx2_camera(&imx25_mx2_camera_data, pdata) + +extern const struct imx_mxc_ehci_data imx25_mxc_ehci_otg_data; +#define imx25_add_mxc_ehci_otg(pdata) \ + imx_add_mxc_ehci(&imx25_mxc_ehci_otg_data, pdata) +extern const struct imx_mxc_ehci_data imx25_mxc_ehci_hs_data; +#define imx25_add_mxc_ehci_hs(pdata) \ + imx_add_mxc_ehci(&imx25_mxc_ehci_hs_data, pdata) + +extern const struct imx_mxc_nand_data imx25_mxc_nand_data; +#define imx25_add_mxc_nand(pdata) \ + imx_add_mxc_nand(&imx25_mxc_nand_data, pdata) + +extern const struct imx_sdhci_esdhc_imx_data imx25_sdhci_esdhc_imx_data[]; +#define imx25_add_sdhci_esdhc_imx(id, pdata) \ + imx_add_sdhci_esdhc_imx(&imx25_sdhci_esdhc_imx_data[id], pdata) + +extern const struct imx_spi_imx_data imx25_cspi_data[]; +#define imx25_add_spi_imx(id, pdata) \ + imx_add_spi_imx(&imx25_cspi_data[id], pdata) +#define imx25_add_spi_imx0(pdata) imx25_add_spi_imx(0, pdata) +#define imx25_add_spi_imx1(pdata) imx25_add_spi_imx(1, pdata) +#define imx25_add_spi_imx2(pdata) imx25_add_spi_imx(2, pdata) + +extern struct imx_mxc_pwm_data imx25_mxc_pwm_data[]; +#define imx25_add_mxc_pwm(id) \ + imx_add_mxc_pwm(&imx25_mxc_pwm_data[id]) diff --git a/arch/arm/mach-imx/devices-imx27.h b/arch/arm/mach-imx/devices-imx27.h new file mode 100644 index 00000000..7f97a3cd --- /dev/null +++ b/arch/arm/mach-imx/devices-imx27.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <mach/mx27.h> +#include <mach/devices-common.h> + +extern const struct imx_fec_data imx27_fec_data; +#define imx27_add_fec(pdata) \ + imx_add_fec(&imx27_fec_data, pdata) + +extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data; +#define imx27_add_fsl_usb2_udc(pdata) \ + imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata) + +extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data; +#define imx27_add_imx2_wdt(pdata) \ + imx_add_imx2_wdt(&imx27_imx2_wdt_data) + +extern const struct imx_imx_fb_data imx27_imx_fb_data; +#define imx27_add_imx_fb(pdata) \ + imx_add_imx_fb(&imx27_imx_fb_data, pdata) + +extern const struct imx_imx_i2c_data imx27_imx_i2c_data[]; +#define imx27_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx27_imx_i2c_data[id], pdata) + +extern const struct imx_imx_keypad_data imx27_imx_keypad_data; +#define imx27_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx27_imx_keypad_data, pdata) + +extern const struct imx_imx_ssi_data imx27_imx_ssi_data[]; +#define imx27_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx27_imx_ssi_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx27_imx_uart_data[]; +#define imx27_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx27_imx_uart_data[id], pdata) +#define imx27_add_imx_uart0(pdata) imx27_add_imx_uart(0, pdata) +#define imx27_add_imx_uart1(pdata) imx27_add_imx_uart(1, pdata) +#define imx27_add_imx_uart2(pdata) imx27_add_imx_uart(2, pdata) +#define imx27_add_imx_uart3(pdata) imx27_add_imx_uart(3, pdata) +#define imx27_add_imx_uart4(pdata) imx27_add_imx_uart(4, pdata) +#define imx27_add_imx_uart5(pdata) imx27_add_imx_uart(5, pdata) + +extern const struct imx_mx2_camera_data imx27_mx2_camera_data; +#define imx27_add_mx2_camera(pdata) \ + imx_add_mx2_camera(&imx27_mx2_camera_data, pdata) + +extern const struct imx_mxc_ehci_data imx27_mxc_ehci_otg_data; +#define imx27_add_mxc_ehci_otg(pdata) \ + imx_add_mxc_ehci(&imx27_mxc_ehci_otg_data, pdata) +extern const struct imx_mxc_ehci_data imx27_mxc_ehci_hs_data[]; +#define imx27_add_mxc_ehci_hs(id, pdata) \ + imx_add_mxc_ehci(&imx27_mxc_ehci_hs_data[id - 1], pdata) + +extern const struct imx_mxc_mmc_data imx27_mxc_mmc_data[]; +#define imx27_add_mxc_mmc(id, pdata) \ + imx_add_mxc_mmc(&imx27_mxc_mmc_data[id], pdata) + +extern const struct imx_mxc_nand_data imx27_mxc_nand_data; +#define imx27_add_mxc_nand(pdata) \ + imx_add_mxc_nand(&imx27_mxc_nand_data, pdata) + +extern const struct imx_mxc_w1_data imx27_mxc_w1_data; +#define imx27_add_mxc_w1(pdata) \ + imx_add_mxc_w1(&imx27_mxc_w1_data) + +extern const struct imx_spi_imx_data imx27_cspi_data[]; +#define imx27_add_cspi(id, pdata) \ + imx_add_spi_imx(&imx27_cspi_data[id], pdata) +#define imx27_add_spi_imx0(pdata) imx27_add_cspi(0, pdata) +#define imx27_add_spi_imx1(pdata) imx27_add_cspi(1, pdata) +#define imx27_add_spi_imx2(pdata) imx27_add_cspi(2, pdata) diff --git a/arch/arm/mach-imx/devices-imx31.h b/arch/arm/mach-imx/devices-imx31.h new file mode 100644 index 00000000..dbe940d9 --- /dev/null +++ b/arch/arm/mach-imx/devices-imx31.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <mach/mx31.h> +#include <mach/devices-common.h> + +extern const struct imx_fsl_usb2_udc_data imx31_fsl_usb2_udc_data; +#define imx31_add_fsl_usb2_udc(pdata) \ + imx_add_fsl_usb2_udc(&imx31_fsl_usb2_udc_data, pdata) + +extern const struct imx_imx2_wdt_data imx31_imx2_wdt_data; +#define imx31_add_imx2_wdt(pdata) \ + imx_add_imx2_wdt(&imx31_imx2_wdt_data) + +extern const struct imx_imx_i2c_data imx31_imx_i2c_data[]; +#define imx31_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx31_imx_i2c_data[id], pdata) +#define imx31_add_imx_i2c0(pdata) imx31_add_imx_i2c(0, pdata) +#define imx31_add_imx_i2c1(pdata) imx31_add_imx_i2c(1, pdata) +#define imx31_add_imx_i2c2(pdata) imx31_add_imx_i2c(2, pdata) + +extern const struct imx_imx_keypad_data imx31_imx_keypad_data; +#define imx31_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx31_imx_keypad_data, pdata) + +extern const struct imx_imx_ssi_data imx31_imx_ssi_data[]; +#define imx31_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx31_imx_ssi_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx31_imx_uart_data[]; +#define imx31_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx31_imx_uart_data[id], pdata) +#define imx31_add_imx_uart0(pdata) imx31_add_imx_uart(0, pdata) +#define imx31_add_imx_uart1(pdata) imx31_add_imx_uart(1, pdata) +#define imx31_add_imx_uart2(pdata) imx31_add_imx_uart(2, pdata) +#define imx31_add_imx_uart3(pdata) imx31_add_imx_uart(3, pdata) +#define imx31_add_imx_uart4(pdata) imx31_add_imx_uart(4, pdata) + +extern const struct imx_ipu_core_data imx31_ipu_core_data; +#define imx31_add_ipu_core(pdata) \ + imx_add_ipu_core(&imx31_ipu_core_data, pdata) +#define imx31_alloc_mx3_camera(pdata) \ + imx_alloc_mx3_camera(&imx31_ipu_core_data, pdata) +#define imx31_add_mx3_sdc_fb(pdata) \ + imx_add_mx3_sdc_fb(&imx31_ipu_core_data, pdata) + +extern const struct imx_mxc_ehci_data imx31_mxc_ehci_otg_data; +#define imx31_add_mxc_ehci_otg(pdata) \ + imx_add_mxc_ehci(&imx31_mxc_ehci_otg_data, pdata) +extern const struct imx_mxc_ehci_data imx31_mxc_ehci_hs_data[]; +#define imx31_add_mxc_ehci_hs(id, pdata) \ + imx_add_mxc_ehci(&imx31_mxc_ehci_hs_data[id - 1], pdata) + +extern const struct imx_mxc_mmc_data imx31_mxc_mmc_data[]; +#define imx31_add_mxc_mmc(id, pdata) \ + imx_add_mxc_mmc(&imx31_mxc_mmc_data[id], pdata) + +extern const struct imx_mxc_nand_data imx31_mxc_nand_data; +#define imx31_add_mxc_nand(pdata) \ + imx_add_mxc_nand(&imx31_mxc_nand_data, pdata) + +extern const struct imx_mxc_rtc_data imx31_mxc_rtc_data; +#define imx31_add_mxc_rtc(pdata) \ + imx_add_mxc_rtc(&imx31_mxc_rtc_data) + +extern const struct imx_mxc_w1_data imx31_mxc_w1_data; +#define imx31_add_mxc_w1(pdata) \ + imx_add_mxc_w1(&imx31_mxc_w1_data) + +extern const struct imx_spi_imx_data imx31_cspi_data[]; +#define imx31_add_cspi(id, pdata) \ + imx_add_spi_imx(&imx31_cspi_data[id], pdata) +#define imx31_add_spi_imx0(pdata) imx31_add_cspi(0, pdata) +#define imx31_add_spi_imx1(pdata) imx31_add_cspi(1, pdata) +#define imx31_add_spi_imx2(pdata) imx31_add_cspi(2, pdata) diff --git a/arch/arm/mach-imx/devices-imx35.h b/arch/arm/mach-imx/devices-imx35.h new file mode 100644 index 00000000..234cbd3c --- /dev/null +++ b/arch/arm/mach-imx/devices-imx35.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 Pengutronix + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de> + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <mach/mx35.h> +#include <mach/devices-common.h> + +extern const struct imx_fec_data imx35_fec_data; +#define imx35_add_fec(pdata) \ + imx_add_fec(&imx35_fec_data, pdata) + +extern const struct imx_fsl_usb2_udc_data imx35_fsl_usb2_udc_data; +#define imx35_add_fsl_usb2_udc(pdata) \ + imx_add_fsl_usb2_udc(&imx35_fsl_usb2_udc_data, pdata) + +extern const struct imx_flexcan_data imx35_flexcan_data[]; +#define imx35_add_flexcan(id, pdata) \ + imx_add_flexcan(&imx35_flexcan_data[id], pdata) +#define imx35_add_flexcan0(pdata) imx35_add_flexcan(0, pdata) +#define imx35_add_flexcan1(pdata) imx35_add_flexcan(1, pdata) + +extern const struct imx_imx2_wdt_data imx35_imx2_wdt_data; +#define imx35_add_imx2_wdt(pdata) \ + imx_add_imx2_wdt(&imx35_imx2_wdt_data) + +extern const struct imx_imx_i2c_data imx35_imx_i2c_data[]; +#define imx35_add_imx_i2c(id, pdata) \ + imx_add_imx_i2c(&imx35_imx_i2c_data[id], pdata) +#define imx35_add_imx_i2c0(pdata) imx35_add_imx_i2c(0, pdata) +#define imx35_add_imx_i2c1(pdata) imx35_add_imx_i2c(1, pdata) +#define imx35_add_imx_i2c2(pdata) imx35_add_imx_i2c(2, pdata) + +extern const struct imx_imx_keypad_data imx35_imx_keypad_data; +#define imx35_add_imx_keypad(pdata) \ + imx_add_imx_keypad(&imx35_imx_keypad_data, pdata) + +extern const struct imx_imx_ssi_data imx35_imx_ssi_data[]; +#define imx35_add_imx_ssi(id, pdata) \ + imx_add_imx_ssi(&imx35_imx_ssi_data[id], pdata) + +extern const struct imx_imx_uart_1irq_data imx35_imx_uart_data[]; +#define imx35_add_imx_uart(id, pdata) \ + imx_add_imx_uart_1irq(&imx35_imx_uart_data[id], pdata) +#define imx35_add_imx_uart0(pdata) imx35_add_imx_uart(0, pdata) +#define imx35_add_imx_uart1(pdata) imx35_add_imx_uart(1, pdata) +#define imx35_add_imx_uart2(pdata) imx35_add_imx_uart(2, pdata) + +extern const struct imx_ipu_core_data imx35_ipu_core_data; +#define imx35_add_ipu_core(pdata) \ + imx_add_ipu_core(&imx35_ipu_core_data, pdata) +#define imx35_alloc_mx3_camera(pdata) \ + imx_alloc_mx3_camera(&imx35_ipu_core_data, pdata) +#define imx35_add_mx3_sdc_fb(pdata) \ + imx_add_mx3_sdc_fb(&imx35_ipu_core_data, pdata) + +extern const struct imx_mxc_ehci_data imx35_mxc_ehci_otg_data; +#define imx35_add_mxc_ehci_otg(pdata) \ + imx_add_mxc_ehci(&imx35_mxc_ehci_otg_data, pdata) +extern const struct imx_mxc_ehci_data imx35_mxc_ehci_hs_data; +#define imx35_add_mxc_ehci_hs(pdata) \ + imx_add_mxc_ehci(&imx35_mxc_ehci_hs_data, pdata) + +extern const struct imx_mxc_nand_data imx35_mxc_nand_data; +#define imx35_add_mxc_nand(pdata) \ + imx_add_mxc_nand(&imx35_mxc_nand_data, pdata) + +extern const struct imx_mxc_w1_data imx35_mxc_w1_data; +#define imx35_add_mxc_w1(pdata) \ + imx_add_mxc_w1(&imx35_mxc_w1_data) + +extern const struct imx_sdhci_esdhc_imx_data imx35_sdhci_esdhc_imx_data[]; +#define imx35_add_sdhci_esdhc_imx(id, pdata) \ + imx_add_sdhci_esdhc_imx(&imx35_sdhci_esdhc_imx_data[id], pdata) + +extern const struct imx_spi_imx_data imx35_cspi_data[]; +#define imx35_add_cspi(id, pdata) \ + imx_add_spi_imx(&imx35_cspi_data[id], pdata) +#define imx35_add_spi_imx0(pdata) imx35_add_cspi(0, pdata) +#define imx35_add_spi_imx1(pdata) imx35_add_cspi(1, pdata) diff --git a/arch/arm/mach-imx/dma-v1.c b/arch/arm/mach-imx/dma-v1.c new file mode 100644 index 00000000..f8aa5be0 --- /dev/null +++ b/arch/arm/mach-imx/dma-v1.c @@ -0,0 +1,865 @@ +/* + * linux/arch/arm/plat-mxc/dma-v1.c + * + * i.MX DMA registration and IRQ dispatching + * + * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de> + * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/err.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/scatterlist.h> +#include <linux/io.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <mach/hardware.h> +#include <mach/dma-v1.h> + +#define DMA_DCR 0x00 /* Control Register */ +#define DMA_DISR 0x04 /* Interrupt status Register */ +#define DMA_DIMR 0x08 /* Interrupt mask Register */ +#define DMA_DBTOSR 0x0c /* Burst timeout status Register */ +#define DMA_DRTOSR 0x10 /* Request timeout Register */ +#define DMA_DSESR 0x14 /* Transfer Error Status Register */ +#define DMA_DBOSR 0x18 /* Buffer overflow status Register */ +#define DMA_DBTOCR 0x1c /* Burst timeout control Register */ +#define DMA_WSRA 0x40 /* W-Size Register A */ +#define DMA_XSRA 0x44 /* X-Size Register A */ +#define DMA_YSRA 0x48 /* Y-Size Register A */ +#define DMA_WSRB 0x4c /* W-Size Register B */ +#define DMA_XSRB 0x50 /* X-Size Register B */ +#define DMA_YSRB 0x54 /* Y-Size Register B */ +#define DMA_SAR(x) (0x80 + ((x) << 6)) /* Source Address Registers */ +#define DMA_DAR(x) (0x84 + ((x) << 6)) /* Destination Address Registers */ +#define DMA_CNTR(x) (0x88 + ((x) << 6)) /* Count Registers */ +#define DMA_CCR(x) (0x8c + ((x) << 6)) /* Control Registers */ +#define DMA_RSSR(x) (0x90 + ((x) << 6)) /* Request source select Registers */ +#define DMA_BLR(x) (0x94 + ((x) << 6)) /* Burst length Registers */ +#define DMA_RTOR(x) (0x98 + ((x) << 6)) /* Request timeout Registers */ +#define DMA_BUCR(x) (0x98 + ((x) << 6)) /* Bus Utilization Registers */ +#define DMA_CCNR(x) (0x9C + ((x) << 6)) /* Channel counter Registers */ + +#define DCR_DRST (1<<1) +#define DCR_DEN (1<<0) +#define DBTOCR_EN (1<<15) +#define DBTOCR_CNT(x) ((x) & 0x7fff) +#define CNTR_CNT(x) ((x) & 0xffffff) +#define CCR_ACRPT (1<<14) +#define CCR_DMOD_LINEAR (0x0 << 12) +#define CCR_DMOD_2D (0x1 << 12) +#define CCR_DMOD_FIFO (0x2 << 12) +#define CCR_DMOD_EOBFIFO (0x3 << 12) +#define CCR_SMOD_LINEAR (0x0 << 10) +#define CCR_SMOD_2D (0x1 << 10) +#define CCR_SMOD_FIFO (0x2 << 10) +#define CCR_SMOD_EOBFIFO (0x3 << 10) +#define CCR_MDIR_DEC (1<<9) +#define CCR_MSEL_B (1<<8) +#define CCR_DSIZ_32 (0x0 << 6) +#define CCR_DSIZ_8 (0x1 << 6) +#define CCR_DSIZ_16 (0x2 << 6) +#define CCR_SSIZ_32 (0x0 << 4) +#define CCR_SSIZ_8 (0x1 << 4) +#define CCR_SSIZ_16 (0x2 << 4) +#define CCR_REN (1<<3) +#define CCR_RPT (1<<2) +#define CCR_FRC (1<<1) +#define CCR_CEN (1<<0) +#define RTOR_EN (1<<15) +#define RTOR_CLK (1<<14) +#define RTOR_PSC (1<<13) + +/* + * struct imx_dma_channel - i.MX specific DMA extension + * @name: name specified by DMA client + * @irq_handler: client callback for end of transfer + * @err_handler: client callback for error condition + * @data: clients context data for callbacks + * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE + * @sg: pointer to the actual read/written chunk for scatter-gather emulation + * @resbytes: total residual number of bytes to transfer + * (it can be lower or same as sum of SG mapped chunk sizes) + * @sgcount: number of chunks to be read/written + * + * Structure is used for IMX DMA processing. It would be probably good + * @struct dma_struct in the future for external interfacing and use + * @struct imx_dma_channel only as extension to it. + */ + +struct imx_dma_channel { + const char *name; + void (*irq_handler) (int, void *); + void (*err_handler) (int, void *, int errcode); + void (*prog_handler) (int, void *, struct scatterlist *); + void *data; + unsigned int dma_mode; + struct scatterlist *sg; + unsigned int resbytes; + int dma_num; + + int in_use; + + u32 ccr_from_device; + u32 ccr_to_device; + + struct timer_list watchdog; + + int hw_chaining; +}; + +static void __iomem *imx_dmav1_baseaddr; + +static void imx_dmav1_writel(unsigned val, unsigned offset) +{ + __raw_writel(val, imx_dmav1_baseaddr + offset); +} + +static unsigned imx_dmav1_readl(unsigned offset) +{ + return __raw_readl(imx_dmav1_baseaddr + offset); +} + +static struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; + +static struct clk *dma_clk; + +static int imx_dma_hw_chain(struct imx_dma_channel *imxdma) +{ + if (cpu_is_mx27()) + return imxdma->hw_chaining; + else + return 0; +} + +/* + * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation + */ +static inline int imx_dma_sg_next(int channel, struct scatterlist *sg) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long now; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return 0; + } + + now = min(imxdma->resbytes, sg->length); + if (imxdma->resbytes != IMX_DMA_LENGTH_LOOP) + imxdma->resbytes -= now; + + if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) + imx_dmav1_writel(sg->dma_address, DMA_DAR(channel)); + else + imx_dmav1_writel(sg->dma_address, DMA_SAR(channel)); + + imx_dmav1_writel(now, DMA_CNTR(channel)); + + pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, " + "size 0x%08x\n", channel, + imx_dmav1_readl(DMA_DAR(channel)), + imx_dmav1_readl(DMA_SAR(channel)), + imx_dmav1_readl(DMA_CNTR(channel))); + + return now; +} + +/** + * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from + * device transfer + * + * @channel: i.MX DMA channel number + * @dma_address: the DMA/physical memory address of the linear data block + * to transfer + * @dma_length: length of the data block in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_single(int channel, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + unsigned int dmamode) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + imxdma->sg = NULL; + imxdma->dma_mode = dmamode; + + if (!dma_address) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", + channel); + return -EINVAL; + } + + if (!dma_length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", + channel); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d " + "dev_addr=0x%08x for read\n", + channel, __func__, (unsigned int)dma_address, + dma_length, dev_addr); + + imx_dmav1_writel(dev_addr, DMA_SAR(channel)); + imx_dmav1_writel(dma_address, DMA_DAR(channel)); + imx_dmav1_writel(imxdma->ccr_from_device, DMA_CCR(channel)); + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: %s dma_addressg=0x%08x dma_length=%d " + "dev_addr=0x%08x for write\n", + channel, __func__, (unsigned int)dma_address, + dma_length, dev_addr); + + imx_dmav1_writel(dma_address, DMA_SAR(channel)); + imx_dmav1_writel(dev_addr, DMA_DAR(channel)); + imx_dmav1_writel(imxdma->ccr_to_device, + DMA_CCR(channel)); + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n", + channel); + return -EINVAL; + } + + imx_dmav1_writel(dma_length, DMA_CNTR(channel)); + + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_single); + +/** + * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer + * @channel: i.MX DMA channel number + * @sg: pointer to the scatter-gather list/vector + * @sgcount: scatter-gather list hungs count + * @dma_length: total length of the transfer request in bytes + * @dev_addr: physical device port address + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory + * or %DMA_MODE_WRITE from memory to the device + * + * The function sets up DMA channel state and registers to be ready for + * transfer specified by provided parameters. The scatter-gather emulation + * is set up according to the parameters. + * + * The full preparation of the transfer requires setup of more register + * by the caller before imx_dma_enable() can be called. + * + * %BLR(channel) holds transfer burst length in bytes, 0 means 64 bytes + * + * %RSSR(channel) has to be set to the DMA request line source %DMA_REQ_xxx + * + * %CCR(channel) has to specify transfer parameters, the next settings is + * typical for linear or simple scatter-gather transfers if %DMA_MODE_READ is + * specified + * + * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x + * + * The typical setup for %DMA_MODE_WRITE is specified by next options + * combination + * + * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x + * + * Be careful here and do not mistakenly mix source and target device + * port sizes constants, they are really different: + * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32, + * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32 + * + * Return value: if incorrect parameters are provided -%EINVAL. + * Zero indicates success. + */ +int +imx_dma_setup_sg(int channel, + struct scatterlist *sg, unsigned int sgcount, + unsigned int dma_length, unsigned int dev_addr, + unsigned int dmamode) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + if (imxdma->in_use) + return -EBUSY; + + imxdma->sg = sg; + imxdma->dma_mode = dmamode; + imxdma->resbytes = dma_length; + + if (!sg || !sgcount) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg empty sg list\n", + channel); + return -EINVAL; + } + + if (!sg->length) { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n", + channel); + return -EINVAL; + } + + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { + pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d " + "dev_addr=0x%08x for read\n", + channel, __func__, sg, sgcount, dma_length, dev_addr); + + imx_dmav1_writel(dev_addr, DMA_SAR(channel)); + imx_dmav1_writel(imxdma->ccr_from_device, DMA_CCR(channel)); + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { + pr_debug("imxdma%d: %s sg=%p sgcount=%d total length=%d " + "dev_addr=0x%08x for write\n", + channel, __func__, sg, sgcount, dma_length, dev_addr); + + imx_dmav1_writel(dev_addr, DMA_DAR(channel)); + imx_dmav1_writel(imxdma->ccr_to_device, DMA_CCR(channel)); + } else { + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n", + channel); + return -EINVAL; + } + + imx_dma_sg_next(channel, sg); + + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_sg); + +int +imx_dma_config_channel(int channel, unsigned int config_port, + unsigned int config_mem, unsigned int dmareq, int hw_chaining) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + u32 dreq = 0; + + imxdma->hw_chaining = 0; + + if (hw_chaining) { + imxdma->hw_chaining = 1; + if (!imx_dma_hw_chain(imxdma)) + return -EINVAL; + } + + if (dmareq) + dreq = CCR_REN; + + imxdma->ccr_from_device = config_port | (config_mem << 2) | dreq; + imxdma->ccr_to_device = config_mem | (config_port << 2) | dreq; + + imx_dmav1_writel(dmareq, DMA_RSSR(channel)); + + return 0; +} +EXPORT_SYMBOL(imx_dma_config_channel); + +void imx_dma_config_burstlen(int channel, unsigned int burstlen) +{ + imx_dmav1_writel(burstlen, DMA_BLR(channel)); +} +EXPORT_SYMBOL(imx_dma_config_burstlen); + +/** + * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification + * handlers + * @channel: i.MX DMA channel number + * @irq_handler: the pointer to the function called if the transfer + * ends successfully + * @err_handler: the pointer to the function called if the premature + * end caused by error occurs + * @data: user specified value to be passed to the handlers + */ +int +imx_dma_setup_handlers(int channel, + void (*irq_handler) (int, void *), + void (*err_handler) (int, void *, int), + void *data) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return -ENODEV; + } + + local_irq_save(flags); + imx_dmav1_writel(1 << channel, DMA_DISR); + imxdma->irq_handler = irq_handler; + imxdma->err_handler = err_handler; + imxdma->data = data; + local_irq_restore(flags); + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_handlers); + +/** + * imx_dma_setup_progression_handler - setup i.MX DMA channel progression + * handlers + * @channel: i.MX DMA channel number + * @prog_handler: the pointer to the function called if the transfer progresses + */ +int +imx_dma_setup_progression_handler(int channel, + void (*prog_handler) (int, void*, struct scatterlist*)) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return -ENODEV; + } + + local_irq_save(flags); + imxdma->prog_handler = prog_handler; + local_irq_restore(flags); + return 0; +} +EXPORT_SYMBOL(imx_dma_setup_progression_handler); + +/** + * imx_dma_enable - function to start i.MX DMA channel operation + * @channel: i.MX DMA channel number + * + * The channel has to be allocated by driver through imx_dma_request() + * or imx_dma_request_by_prio() function. + * The transfer parameters has to be set to the channel registers through + * call of the imx_dma_setup_single() or imx_dma_setup_sg() function + * and registers %BLR(channel), %RSSR(channel) and %CCR(channel) has to + * be set prior this function call by the channel user. + */ +void imx_dma_enable(int channel) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_enable\n", channel); + + if (!imxdma->name) { + printk(KERN_CRIT "%s: called for not allocated channel %d\n", + __func__, channel); + return; + } + + if (imxdma->in_use) + return; + + local_irq_save(flags); + + imx_dmav1_writel(1 << channel, DMA_DISR); + imx_dmav1_writel(imx_dmav1_readl(DMA_DIMR) & ~(1 << channel), DMA_DIMR); + imx_dmav1_writel(imx_dmav1_readl(DMA_CCR(channel)) | CCR_CEN | + CCR_ACRPT, DMA_CCR(channel)); + +#ifdef CONFIG_ARCH_MX2 + if ((cpu_is_mx21() || cpu_is_mx27()) && + imxdma->sg && imx_dma_hw_chain(imxdma)) { + imxdma->sg = sg_next(imxdma->sg); + if (imxdma->sg) { + u32 tmp; + imx_dma_sg_next(channel, imxdma->sg); + tmp = imx_dmav1_readl(DMA_CCR(channel)); + imx_dmav1_writel(tmp | CCR_RPT | CCR_ACRPT, + DMA_CCR(channel)); + } + } +#endif + imxdma->in_use = 1; + + local_irq_restore(flags); +} +EXPORT_SYMBOL(imx_dma_enable); + +/** + * imx_dma_disable - stop, finish i.MX DMA channel operatin + * @channel: i.MX DMA channel number + */ +void imx_dma_disable(int channel) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + + pr_debug("imxdma%d: imx_dma_disable\n", channel); + + if (imx_dma_hw_chain(imxdma)) + del_timer(&imxdma->watchdog); + + local_irq_save(flags); + imx_dmav1_writel(imx_dmav1_readl(DMA_DIMR) | (1 << channel), DMA_DIMR); + imx_dmav1_writel(imx_dmav1_readl(DMA_CCR(channel)) & ~CCR_CEN, + DMA_CCR(channel)); + imx_dmav1_writel(1 << channel, DMA_DISR); + imxdma->in_use = 0; + local_irq_restore(flags); +} +EXPORT_SYMBOL(imx_dma_disable); + +#ifdef CONFIG_ARCH_MX2 +static void imx_dma_watchdog(unsigned long chno) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[chno]; + + imx_dmav1_writel(0, DMA_CCR(chno)); + imxdma->in_use = 0; + imxdma->sg = NULL; + + if (imxdma->err_handler) + imxdma->err_handler(chno, imxdma->data, IMX_DMA_ERR_TIMEOUT); +} +#endif + +static irqreturn_t dma_err_handler(int irq, void *dev_id) +{ + int i, disr; + struct imx_dma_channel *imxdma; + unsigned int err_mask; + int errcode; + + disr = imx_dmav1_readl(DMA_DISR); + + err_mask = imx_dmav1_readl(DMA_DBTOSR) | + imx_dmav1_readl(DMA_DRTOSR) | + imx_dmav1_readl(DMA_DSESR) | + imx_dmav1_readl(DMA_DBOSR); + + if (!err_mask) + return IRQ_HANDLED; + + imx_dmav1_writel(disr & err_mask, DMA_DISR); + + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + if (!(err_mask & (1 << i))) + continue; + imxdma = &imx_dma_channels[i]; + errcode = 0; + + if (imx_dmav1_readl(DMA_DBTOSR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DBTOSR); + errcode |= IMX_DMA_ERR_BURST; + } + if (imx_dmav1_readl(DMA_DRTOSR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DRTOSR); + errcode |= IMX_DMA_ERR_REQUEST; + } + if (imx_dmav1_readl(DMA_DSESR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DSESR); + errcode |= IMX_DMA_ERR_TRANSFER; + } + if (imx_dmav1_readl(DMA_DBOSR) & (1 << i)) { + imx_dmav1_writel(1 << i, DMA_DBOSR); + errcode |= IMX_DMA_ERR_BUFFER; + } + if (imxdma->name && imxdma->err_handler) { + imxdma->err_handler(i, imxdma->data, errcode); + continue; + } + + imx_dma_channels[i].sg = NULL; + + printk(KERN_WARNING + "DMA timeout on channel %d (%s) -%s%s%s%s\n", + i, imxdma->name, + errcode & IMX_DMA_ERR_BURST ? " burst" : "", + errcode & IMX_DMA_ERR_REQUEST ? " request" : "", + errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "", + errcode & IMX_DMA_ERR_BUFFER ? " buffer" : ""); + } + return IRQ_HANDLED; +} + +static void dma_irq_handle_channel(int chno) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[chno]; + + if (!imxdma->name) { + /* + * IRQ for an unregistered DMA channel: + * let's clear the interrupts and disable it. + */ + printk(KERN_WARNING + "spurious IRQ for DMA channel %d\n", chno); + return; + } + + if (imxdma->sg) { + u32 tmp; + struct scatterlist *current_sg = imxdma->sg; + imxdma->sg = sg_next(imxdma->sg); + + if (imxdma->sg) { + imx_dma_sg_next(chno, imxdma->sg); + + tmp = imx_dmav1_readl(DMA_CCR(chno)); + + if (imx_dma_hw_chain(imxdma)) { + /* FIXME: The timeout should probably be + * configurable + */ + mod_timer(&imxdma->watchdog, + jiffies + msecs_to_jiffies(500)); + + tmp |= CCR_CEN | CCR_RPT | CCR_ACRPT; + imx_dmav1_writel(tmp, DMA_CCR(chno)); + } else { + imx_dmav1_writel(tmp & ~CCR_CEN, DMA_CCR(chno)); + tmp |= CCR_CEN; + } + + imx_dmav1_writel(tmp, DMA_CCR(chno)); + + if (imxdma->prog_handler) + imxdma->prog_handler(chno, imxdma->data, + current_sg); + + return; + } + + if (imx_dma_hw_chain(imxdma)) { + del_timer(&imxdma->watchdog); + return; + } + } + + imx_dmav1_writel(0, DMA_CCR(chno)); + imxdma->in_use = 0; + if (imxdma->irq_handler) + imxdma->irq_handler(chno, imxdma->data); +} + +static irqreturn_t dma_irq_handler(int irq, void *dev_id) +{ + int i, disr; + +#ifdef CONFIG_ARCH_MX2 + if (cpu_is_mx21() || cpu_is_mx27()) + dma_err_handler(irq, dev_id); +#endif + + disr = imx_dmav1_readl(DMA_DISR); + + pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", + disr); + + imx_dmav1_writel(disr, DMA_DISR); + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + if (disr & (1 << i)) + dma_irq_handle_channel(i); + } + + return IRQ_HANDLED; +} + +/** + * imx_dma_request - request/allocate specified channel number + * @channel: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + */ +int imx_dma_request(int channel, const char *name) +{ + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + unsigned long flags; + int ret = 0; + + /* basic sanity checks */ + if (!name) + return -EINVAL; + + if (channel >= IMX_DMA_CHANNELS) { + printk(KERN_CRIT "%s: called for non-existed channel %d\n", + __func__, channel); + return -EINVAL; + } + + local_irq_save(flags); + if (imxdma->name) { + local_irq_restore(flags); + return -EBUSY; + } + memset(imxdma, 0, sizeof(*imxdma)); + imxdma->name = name; + local_irq_restore(flags); /* request_irq() can block */ + +#ifdef CONFIG_ARCH_MX2 + if (cpu_is_mx21() || cpu_is_mx27()) { + ret = request_irq(MX2x_INT_DMACH0 + channel, + dma_irq_handler, 0, "DMA", NULL); + if (ret) { + imxdma->name = NULL; + pr_crit("Can't register IRQ %d for DMA channel %d\n", + MX2x_INT_DMACH0 + channel, channel); + return ret; + } + init_timer(&imxdma->watchdog); + imxdma->watchdog.function = &imx_dma_watchdog; + imxdma->watchdog.data = channel; + } +#endif + + return ret; +} +EXPORT_SYMBOL(imx_dma_request); + +/** + * imx_dma_free - release previously acquired channel + * @channel: i.MX DMA channel number + */ +void imx_dma_free(int channel) +{ + unsigned long flags; + struct imx_dma_channel *imxdma = &imx_dma_channels[channel]; + + if (!imxdma->name) { + printk(KERN_CRIT + "%s: trying to free free channel %d\n", + __func__, channel); + return; + } + + local_irq_save(flags); + /* Disable interrupts */ + imx_dma_disable(channel); + imxdma->name = NULL; + +#ifdef CONFIG_ARCH_MX2 + if (cpu_is_mx21() || cpu_is_mx27()) + free_irq(MX2x_INT_DMACH0 + channel, NULL); +#endif + + local_irq_restore(flags); +} +EXPORT_SYMBOL(imx_dma_free); + +/** + * imx_dma_request_by_prio - find and request some of free channels best + * suiting requested priority + * @channel: i.MX DMA channel number + * @name: the driver/caller own non-%NULL identification + * + * This function tries to find a free channel in the specified priority group + * if the priority cannot be achieved it tries to look for free channel + * in the higher and then even lower priority groups. + * + * Return value: If there is no free channel to allocate, -%ENODEV is returned. + * On successful allocation channel is returned. + */ +int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio) +{ + int i; + int best; + + switch (prio) { + case (DMA_PRIO_HIGH): + best = 8; + break; + case (DMA_PRIO_MEDIUM): + best = 4; + break; + case (DMA_PRIO_LOW): + default: + best = 0; + break; + } + + for (i = best; i < IMX_DMA_CHANNELS; i++) + if (!imx_dma_request(i, name)) + return i; + + for (i = best - 1; i >= 0; i--) + if (!imx_dma_request(i, name)) + return i; + + printk(KERN_ERR "%s: no free DMA channel found\n", __func__); + + return -ENODEV; +} +EXPORT_SYMBOL(imx_dma_request_by_prio); + +static int __init imx_dma_init(void) +{ + int ret = 0; + int i; + +#ifdef CONFIG_ARCH_MX1 + if (cpu_is_mx1()) + imx_dmav1_baseaddr = MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR); + else +#endif +#ifdef CONFIG_MACH_MX21 + if (cpu_is_mx21()) + imx_dmav1_baseaddr = MX21_IO_ADDRESS(MX21_DMA_BASE_ADDR); + else +#endif +#ifdef CONFIG_MACH_MX27 + if (cpu_is_mx27()) + imx_dmav1_baseaddr = MX27_IO_ADDRESS(MX27_DMA_BASE_ADDR); + else +#endif + return 0; + + dma_clk = clk_get(NULL, "dma"); + if (IS_ERR(dma_clk)) + return PTR_ERR(dma_clk); + clk_enable(dma_clk); + + /* reset DMA module */ + imx_dmav1_writel(DCR_DRST, DMA_DCR); + +#ifdef CONFIG_ARCH_MX1 + if (cpu_is_mx1()) { + ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", NULL); + if (ret) { + pr_crit("Wow! Can't register IRQ for DMA\n"); + return ret; + } + + ret = request_irq(MX1_DMA_ERR, dma_err_handler, 0, "DMA", NULL); + if (ret) { + pr_crit("Wow! Can't register ERRIRQ for DMA\n"); + free_irq(MX1_DMA_INT, NULL); + return ret; + } + } +#endif + /* enable DMA module */ + imx_dmav1_writel(DCR_DEN, DMA_DCR); + + /* clear all interrupts */ + imx_dmav1_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_DISR); + + /* disable interrupts */ + imx_dmav1_writel((1 << IMX_DMA_CHANNELS) - 1, DMA_DIMR); + + for (i = 0; i < IMX_DMA_CHANNELS; i++) { + imx_dma_channels[i].sg = NULL; + imx_dma_channels[i].dma_num = i; + } + + return ret; +} + +arch_initcall(imx_dma_init); diff --git a/arch/arm/mach-imx/ehci-imx25.c b/arch/arm/mach-imx/ehci-imx25.c new file mode 100644 index 00000000..865daf0b --- /dev/null +++ b/arch/arm/mach-imx/ehci-imx25.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/mxc_ehci.h> + +#define USBCTRL_OTGBASE_OFFSET 0x600 + +#define MX25_OTG_SIC_SHIFT 29 +#define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT) +#define MX25_OTG_PM_BIT (1 << 24) + +#define MX25_H1_SIC_SHIFT 21 +#define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT) +#define MX25_H1_PM_BIT (1 << 8) +#define MX25_H1_IPPUE_UP_BIT (1 << 7) +#define MX25_H1_IPPUE_DOWN_BIT (1 << 6) +#define MX25_H1_TLL_BIT (1 << 5) +#define MX25_H1_USBTE_BIT (1 << 4) + +int mx25_initialize_usb_hw(int port, unsigned int flags) +{ + unsigned int v; + + v = readl(MX25_IO_ADDRESS(MX25_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + switch (port) { + case 0: /* OTG port */ + v &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PM_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX25_OTG_PM_BIT; + + break; + case 1: /* H1 port */ + v &= ~(MX25_H1_SIC_MASK | MX25_H1_PM_BIT | MX25_H1_TLL_BIT | + MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT | MX25_H1_IPPUE_UP_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX25_H1_PM_BIT; + + if (!(flags & MXC_EHCI_TTL_ENABLED)) + v |= MX25_H1_TLL_BIT; + + if (flags & MXC_EHCI_INTERNAL_PHY) + v |= MX25_H1_USBTE_BIT; + + if (flags & MXC_EHCI_IPPUE_DOWN) + v |= MX25_H1_IPPUE_DOWN_BIT; + + if (flags & MXC_EHCI_IPPUE_UP) + v |= MX25_H1_IPPUE_UP_BIT; + + break; + default: + return -EINVAL; + } + + writel(v, MX25_IO_ADDRESS(MX25_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + return 0; +} + diff --git a/arch/arm/mach-imx/ehci-imx27.c b/arch/arm/mach-imx/ehci-imx27.c new file mode 100644 index 00000000..fa69419e --- /dev/null +++ b/arch/arm/mach-imx/ehci-imx27.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/mxc_ehci.h> + +#define USBCTRL_OTGBASE_OFFSET 0x600 + +#define MX27_OTG_SIC_SHIFT 29 +#define MX27_OTG_SIC_MASK (0x3 << MX27_OTG_SIC_SHIFT) +#define MX27_OTG_PM_BIT (1 << 24) + +#define MX27_H2_SIC_SHIFT 21 +#define MX27_H2_SIC_MASK (0x3 << MX27_H2_SIC_SHIFT) +#define MX27_H2_PM_BIT (1 << 16) +#define MX27_H2_DT_BIT (1 << 5) + +#define MX27_H1_SIC_SHIFT 13 +#define MX27_H1_SIC_MASK (0x3 << MX27_H1_SIC_SHIFT) +#define MX27_H1_PM_BIT (1 << 8) +#define MX27_H1_DT_BIT (1 << 4) + +int mx27_initialize_usb_hw(int port, unsigned int flags) +{ + unsigned int v; + + v = readl(MX27_IO_ADDRESS(MX27_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + switch (port) { + case 0: /* OTG port */ + v &= ~(MX27_OTG_SIC_MASK | MX27_OTG_PM_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX27_OTG_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX27_OTG_PM_BIT; + break; + case 1: /* H1 port */ + v &= ~(MX27_H1_SIC_MASK | MX27_H1_PM_BIT | MX27_H1_DT_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX27_H1_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX27_H1_PM_BIT; + + if (!(flags & MXC_EHCI_TTL_ENABLED)) + v |= MX27_H1_DT_BIT; + + break; + case 2: /* H2 port */ + v &= ~(MX27_H2_SIC_MASK | MX27_H2_PM_BIT | MX27_H2_DT_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX27_H2_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX27_H2_PM_BIT; + + if (!(flags & MXC_EHCI_TTL_ENABLED)) + v |= MX27_H2_DT_BIT; + + break; + default: + return -EINVAL; + } + + writel(v, MX27_IO_ADDRESS(MX27_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + return 0; +} + diff --git a/arch/arm/mach-imx/ehci-imx31.c b/arch/arm/mach-imx/ehci-imx31.c new file mode 100644 index 00000000..faad0f15 --- /dev/null +++ b/arch/arm/mach-imx/ehci-imx31.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/mxc_ehci.h> + +#define USBCTRL_OTGBASE_OFFSET 0x600 + +#define MX31_OTG_SIC_SHIFT 29 +#define MX31_OTG_SIC_MASK (0x3 << MX31_OTG_SIC_SHIFT) +#define MX31_OTG_PM_BIT (1 << 24) + +#define MX31_H2_SIC_SHIFT 21 +#define MX31_H2_SIC_MASK (0x3 << MX31_H2_SIC_SHIFT) +#define MX31_H2_PM_BIT (1 << 16) +#define MX31_H2_DT_BIT (1 << 5) + +#define MX31_H1_SIC_SHIFT 13 +#define MX31_H1_SIC_MASK (0x3 << MX31_H1_SIC_SHIFT) +#define MX31_H1_PM_BIT (1 << 8) +#define MX31_H1_DT_BIT (1 << 4) + +int mx31_initialize_usb_hw(int port, unsigned int flags) +{ + unsigned int v; + + v = readl(MX31_IO_ADDRESS(MX31_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + switch (port) { + case 0: /* OTG port */ + v &= ~(MX31_OTG_SIC_MASK | MX31_OTG_PM_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_OTG_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX31_OTG_PM_BIT; + + break; + case 1: /* H1 port */ + v &= ~(MX31_H1_SIC_MASK | MX31_H1_PM_BIT | MX31_H1_DT_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_H1_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX31_H1_PM_BIT; + + if (!(flags & MXC_EHCI_TTL_ENABLED)) + v |= MX31_H1_DT_BIT; + + break; + case 2: /* H2 port */ + v &= ~(MX31_H2_SIC_MASK | MX31_H2_PM_BIT | MX31_H2_DT_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX31_H2_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX31_H2_PM_BIT; + + if (!(flags & MXC_EHCI_TTL_ENABLED)) + v |= MX31_H2_DT_BIT; + + break; + default: + return -EINVAL; + } + + writel(v, MX31_IO_ADDRESS(MX31_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + return 0; +} diff --git a/arch/arm/mach-imx/ehci-imx35.c b/arch/arm/mach-imx/ehci-imx35.c new file mode 100644 index 00000000..001ec397 --- /dev/null +++ b/arch/arm/mach-imx/ehci-imx35.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/mxc_ehci.h> + +#define USBCTRL_OTGBASE_OFFSET 0x600 + +#define MX35_OTG_SIC_SHIFT 29 +#define MX35_OTG_SIC_MASK (0x3 << MX35_OTG_SIC_SHIFT) +#define MX35_OTG_PM_BIT (1 << 24) + +#define MX35_H1_SIC_SHIFT 21 +#define MX35_H1_SIC_MASK (0x3 << MX35_H1_SIC_SHIFT) +#define MX35_H1_PM_BIT (1 << 8) +#define MX35_H1_IPPUE_UP_BIT (1 << 7) +#define MX35_H1_IPPUE_DOWN_BIT (1 << 6) +#define MX35_H1_TLL_BIT (1 << 5) +#define MX35_H1_USBTE_BIT (1 << 4) + +int mx35_initialize_usb_hw(int port, unsigned int flags) +{ + unsigned int v; + + v = readl(MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + switch (port) { + case 0: /* OTG port */ + v &= ~(MX35_OTG_SIC_MASK | MX35_OTG_PM_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_OTG_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX35_OTG_PM_BIT; + + break; + case 1: /* H1 port */ + v &= ~(MX35_H1_SIC_MASK | MX35_H1_PM_BIT | MX35_H1_TLL_BIT | + MX35_H1_USBTE_BIT | MX35_H1_IPPUE_DOWN_BIT | MX35_H1_IPPUE_UP_BIT); + v |= (flags & MXC_EHCI_INTERFACE_MASK) << MX35_H1_SIC_SHIFT; + + if (!(flags & MXC_EHCI_POWER_PINS_ENABLED)) + v |= MX35_H1_PM_BIT; + + if (!(flags & MXC_EHCI_TTL_ENABLED)) + v |= MX35_H1_TLL_BIT; + + if (flags & MXC_EHCI_INTERNAL_PHY) + v |= MX35_H1_USBTE_BIT; + + if (flags & MXC_EHCI_IPPUE_DOWN) + v |= MX35_H1_IPPUE_DOWN_BIT; + + if (flags & MXC_EHCI_IPPUE_UP) + v |= MX35_H1_IPPUE_UP_BIT; + + break; + default: + return -EINVAL; + } + + writel(v, MX35_IO_ADDRESS(MX35_USB_BASE_ADDR + USBCTRL_OTGBASE_OFFSET)); + + return 0; +} diff --git a/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c new file mode 100644 index 00000000..5911281d --- /dev/null +++ b/arch/arm/mach-imx/eukrea_mbimx27-baseboard.c @@ -0,0 +1,381 @@ +/* + * Copyright (C) 2009-2010 Eric Benard - eric@eukrea.com + * + * Based on pcm970-baseboard.c which is : + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/backlight.h> +#include <video/platform_lcd.h> + +#include <asm/mach/arch.h> + +#include <mach/common.h> +#include <mach/iomux-mx27.h> +#include <mach/hardware.h> +#include <mach/audmux.h> + +#include "devices-imx27.h" + +static const int eukrea_mbimx27_pins[] __initconst = { + /* UART2 */ + PE3_PF_UART2_CTS, + PE4_PF_UART2_RTS, + PE6_PF_UART2_TXD, + PE7_PF_UART2_RXD, + /* UART3 */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + PE10_PF_UART3_CTS, + PE11_PF_UART3_RTS, + /* UART4 */ +#if !defined(MACH_EUKREA_CPUIMX27_USEUART4) + PB26_AF_UART4_RTS, + PB28_AF_UART4_TXD, + PB29_AF_UART4_CTS, + PB31_AF_UART4_RXD, +#endif + /* SDHC1*/ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + /* display */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* SPI1 */ + PD29_PF_CSPI1_SCLK, + PD30_PF_CSPI1_MISO, + PD31_PF_CSPI1_MOSI, + /* SSI4 */ +#if defined(CONFIG_SND_SOC_EUKREA_TLV320) \ + || defined(CONFIG_SND_SOC_EUKREA_TLV320_MODULE) + PC16_PF_SSI4_FS, + PC17_PF_SSI4_RXD | GPIO_PUEN, + PC18_PF_SSI4_TXD | GPIO_PUEN, + PC19_PF_SSI4_CLK, +#endif +}; + +static const uint32_t eukrea_mbimx27_keymap[] = { + KEY(0, 0, KEY_UP), + KEY(0, 1, KEY_DOWN), + KEY(1, 0, KEY_RIGHT), + KEY(1, 1, KEY_LEFT), +}; + +static const struct matrix_keymap_data +eukrea_mbimx27_keymap_data __initconst = { + .keymap = eukrea_mbimx27_keymap, + .keymap_size = ARRAY_SIZE(eukrea_mbimx27_keymap), +}; + +static struct gpio_led gpio_leds[] = { + { + .name = "led1", + .default_trigger = "heartbeat", + .active_low = 1, + .gpio = GPIO_PORTF | 16, + }, + { + .name = "led2", + .default_trigger = "none", + .active_low = 1, + .gpio = GPIO_PORTF | 19, + }, +}; + +static struct gpio_led_platform_data gpio_led_info = { + .leds = gpio_leds, + .num_leds = ARRAY_SIZE(gpio_leds), +}; + +static struct platform_device leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &gpio_led_info, + }, +}; + +static struct imx_fb_videomode eukrea_mbimx27_modes[] = { + { + .mode = { + .name = "CMO-QVGA", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = 156000, + .hsync_len = 30, + .left_margin = 38, + .right_margin = 20, + .vsync_len = 3, + .upper_margin = 15, + .lower_margin = 4, + }, + .pcr = 0xFAD08B80, + .bpp = 16, + }, { + .mode = { + .name = "DVI-VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 32000, + .hsync_len = 1, + .left_margin = 35, + .right_margin = 0, + .vsync_len = 1, + .upper_margin = 7, + .lower_margin = 0, + }, + .pcr = 0xFA208B80, + .bpp = 16, + }, { + .mode = { + .name = "DVI-SVGA", + .refresh = 60, + .xres = 800, + .yres = 600, + .pixclock = 25000, + .hsync_len = 1, + .left_margin = 35, + .right_margin = 0, + .vsync_len = 1, + .upper_margin = 7, + .lower_margin = 0, + }, + .pcr = 0xFA208B80, + .bpp = 16, + }, +}; + +static const struct imx_fb_platform_data eukrea_mbimx27_fb_data __initconst = { + .mode = eukrea_mbimx27_modes, + .num_modes = ARRAY_SIZE(eukrea_mbimx27_modes), + + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00040060, +}; + +static void eukrea_mbimx27_bl_set_intensity(int intensity) +{ + if (intensity) + gpio_direction_output(GPIO_PORTE | 5, 1); + else + gpio_direction_output(GPIO_PORTE | 5, 0); +} + +static struct generic_bl_info eukrea_mbimx27_bl_info = { + .name = "eukrea_mbimx27-bl", + .max_intensity = 0xff, + .default_intensity = 0xff, + .set_bl_intensity = eukrea_mbimx27_bl_set_intensity, +}; + +static struct platform_device eukrea_mbimx27_bl_dev = { + .name = "generic-bl", + .id = 1, + .dev = { + .platform_data = &eukrea_mbimx27_bl_info, + }, +}; + +static void eukrea_mbimx27_lcd_power_set(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) + gpio_direction_output(GPIO_PORTA | 25, 1); + else + gpio_direction_output(GPIO_PORTA | 25, 0); +} + +static struct plat_lcd_data eukrea_mbimx27_lcd_power_data = { + .set_power = eukrea_mbimx27_lcd_power_set, +}; + +static struct platform_device eukrea_mbimx27_lcd_powerdev = { + .name = "platform-lcd", + .dev.platform_data = &eukrea_mbimx27_lcd_power_data, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +#define ADS7846_PENDOWN (GPIO_PORTD | 25) + +static void __maybe_unused ads7846_dev_init(void) +{ + if (gpio_request(ADS7846_PENDOWN, "ADS7846 pendown") < 0) { + printk(KERN_ERR "can't get ads746 pen down GPIO\n"); + return; + } + gpio_direction_input(ADS7846_PENDOWN); +} + +static int ads7846_get_pendown_state(void) +{ + return !gpio_get_value(ADS7846_PENDOWN); +} + +static struct ads7846_platform_data ads7846_config __initdata = { + .get_pendown_state = ads7846_get_pendown_state, + .keep_vref_on = 1, +}; + +static struct spi_board_info __maybe_unused + eukrea_mbimx27_spi_board_info[] __initdata = { + [0] = { + .modalias = "ads7846", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 1500000, + .irq = IRQ_GPIOD(25), + .platform_data = &ads7846_config, + .mode = SPI_MODE_2, + }, +}; + +static int eukrea_mbimx27_spi_cs[] = {GPIO_PORTD | 28}; + +static const struct spi_imx_master eukrea_mbimx27_spi0_data __initconst = { + .chipselect = eukrea_mbimx27_spi_cs, + .num_chipselect = ARRAY_SIZE(eukrea_mbimx27_spi_cs), +}; + +static struct i2c_board_info eukrea_mbimx27_i2c_devices[] = { + { + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +static struct platform_device *platform_devices[] __initdata = { + &leds_gpio, +}; + +static const struct imxmmc_platform_data sdhc_pdata __initconst = { + .dat3_card_detect = 1, +}; + +static const +struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata __initconst = { + .flags = IMX_SSI_DMA | IMX_SSI_USE_I2S_SLAVE, +}; + +/* + * system init for baseboard usage. Will be called by cpuimx27 init. + * + * Add platform devices present on this baseboard and init + * them from CPU side as far as required to use them later on + */ +void __init eukrea_mbimx27_baseboard_init(void) +{ + mxc_gpio_setup_multiple_pins(eukrea_mbimx27_pins, + ARRAY_SIZE(eukrea_mbimx27_pins), "MBIMX27"); + +#if defined(CONFIG_SND_SOC_EUKREA_TLV320) \ + || defined(CONFIG_SND_SOC_EUKREA_TLV320_MODULE) + /* SSI unit master I2S codec connected to SSI_PINS_4*/ + mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, + MXC_AUDMUX_V1_PCR_SYN | + MXC_AUDMUX_V1_PCR_TFSDIR | + MXC_AUDMUX_V1_PCR_TCLKDIR | + MXC_AUDMUX_V1_PCR_RFSDIR | + MXC_AUDMUX_V1_PCR_RCLKDIR | + MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | + MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | + MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) + ); + mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4, + MXC_AUDMUX_V1_PCR_SYN | + MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) + ); +#endif + + imx27_add_imx_uart1(&uart_pdata); + imx27_add_imx_uart2(&uart_pdata); +#if !defined(MACH_EUKREA_CPUIMX27_USEUART4) + imx27_add_imx_uart3(&uart_pdata); +#endif + + imx27_add_imx_fb(&eukrea_mbimx27_fb_data); + imx27_add_mxc_mmc(0, &sdhc_pdata); + + i2c_register_board_info(0, eukrea_mbimx27_i2c_devices, + ARRAY_SIZE(eukrea_mbimx27_i2c_devices)); + + imx27_add_imx_ssi(0, &eukrea_mbimx27_ssi_pdata); + +#if defined(CONFIG_TOUCHSCREEN_ADS7846) \ + || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) + /* ADS7846 Touchscreen controller init */ + mxc_gpio_mode(GPIO_PORTD | 25 | GPIO_GPIO | GPIO_IN); + ads7846_dev_init(); +#endif + + /* SPI_CS0 init */ + mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT); + imx27_add_spi_imx0(&eukrea_mbimx27_spi0_data); + spi_register_board_info(eukrea_mbimx27_spi_board_info, + ARRAY_SIZE(eukrea_mbimx27_spi_board_info)); + + /* Leds configuration */ + mxc_gpio_mode(GPIO_PORTF | 16 | GPIO_GPIO | GPIO_OUT); + mxc_gpio_mode(GPIO_PORTF | 19 | GPIO_GPIO | GPIO_OUT); + /* Backlight */ + mxc_gpio_mode(GPIO_PORTE | 5 | GPIO_GPIO | GPIO_OUT); + gpio_request(GPIO_PORTE | 5, "backlight"); + platform_device_register(&eukrea_mbimx27_bl_dev); + /* LCD Reset */ + mxc_gpio_mode(GPIO_PORTA | 25 | GPIO_GPIO | GPIO_OUT); + gpio_request(GPIO_PORTA | 25, "lcd_enable"); + platform_device_register(&eukrea_mbimx27_lcd_powerdev); + + imx27_add_imx_keypad(&eukrea_mbimx27_keymap_data); + + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); +} diff --git a/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c new file mode 100644 index 00000000..f9ef04ac --- /dev/null +++ b/arch/arm/mach-imx/eukrea_mbimxsd25-baseboard.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2010 Eric Benard - eric@eukrea.com + * + * Based on pcm970-baseboard.c which is : + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <video/platform_lcd.h> + +#include <mach/hardware.h> +#include <mach/iomux-mx25.h> +#include <mach/common.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <mach/mx25.h> +#include <mach/audmux.h> + +#include "devices-imx25.h" + +static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = { + /* LCD */ + MX25_PAD_LD0__LD0, + MX25_PAD_LD1__LD1, + MX25_PAD_LD2__LD2, + MX25_PAD_LD3__LD3, + MX25_PAD_LD4__LD4, + MX25_PAD_LD5__LD5, + MX25_PAD_LD6__LD6, + MX25_PAD_LD7__LD7, + MX25_PAD_LD8__LD8, + MX25_PAD_LD9__LD9, + MX25_PAD_LD10__LD10, + MX25_PAD_LD11__LD11, + MX25_PAD_LD12__LD12, + MX25_PAD_LD13__LD13, + MX25_PAD_LD14__LD14, + MX25_PAD_LD15__LD15, + MX25_PAD_GPIO_E__LD16, + MX25_PAD_GPIO_F__LD17, + MX25_PAD_HSYNC__HSYNC, + MX25_PAD_VSYNC__VSYNC, + MX25_PAD_LSCLK__LSCLK, + MX25_PAD_OE_ACD__OE_ACD, + MX25_PAD_CONTRAST__CONTRAST, + /* LCD_PWR */ + MX25_PAD_PWM__GPIO_1_26, + /* LED */ + MX25_PAD_POWER_FAIL__GPIO_3_19, + /* SWITCH */ + MX25_PAD_VSTBY_ACK__GPIO_3_18, + /* UART2 */ + MX25_PAD_UART2_RTS__UART2_RTS, + MX25_PAD_UART2_CTS__UART2_CTS, + MX25_PAD_UART2_TXD__UART2_TXD, + MX25_PAD_UART2_RXD__UART2_RXD, + /* SD1 */ + MX25_PAD_SD1_CMD__SD1_CMD, + MX25_PAD_SD1_CLK__SD1_CLK, + MX25_PAD_SD1_DATA0__SD1_DATA0, + MX25_PAD_SD1_DATA1__SD1_DATA1, + MX25_PAD_SD1_DATA2__SD1_DATA2, + MX25_PAD_SD1_DATA3__SD1_DATA3, + /* SD1 CD */ + MX25_PAD_DE_B__GPIO_2_20, + /* I2S */ + MX25_PAD_KPP_COL3__AUD5_TXFS, + MX25_PAD_KPP_COL2__AUD5_TXC, + MX25_PAD_KPP_COL1__AUD5_RXD, + MX25_PAD_KPP_COL0__AUD5_TXD, + /* CAN */ + MX25_PAD_GPIO_D__CAN2_RX, + MX25_PAD_GPIO_C__CAN2_TX, +}; + +#define GPIO_LED1 83 +#define GPIO_SWITCH1 82 +#define GPIO_SD1CD 52 +#define GPIO_LCDPWR 26 + +static struct imx_fb_videomode eukrea_mximxsd_modes[] = { + { + .mode = { + .name = "CMO-QVGA", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(6500), + .left_margin = 30, + .right_margin = 38, + .upper_margin = 20, + .lower_margin = 3, + .hsync_len = 15, + .vsync_len = 4, + }, + .bpp = 16, + .pcr = 0xCAD08B80, + }, { + .mode = { + .name = "DVI-VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 32000, + .hsync_len = 7, + .left_margin = 100, + .right_margin = 100, + .vsync_len = 7, + .upper_margin = 7, + .lower_margin = 100, + }, + .pcr = 0xFA208B80, + .bpp = 16, + }, { + .mode = { + .name = "DVI-SVGA", + .refresh = 60, + .xres = 800, + .yres = 600, + .pixclock = 25000, + .hsync_len = 7, + .left_margin = 75, + .right_margin = 75, + .vsync_len = 7, + .upper_margin = 7, + .lower_margin = 75, + }, + .pcr = 0xFA208B80, + .bpp = 16, + }, +}; + +static const struct imx_fb_platform_data eukrea_mximxsd_fb_pdata __initconst = { + .mode = eukrea_mximxsd_modes, + .num_modes = ARRAY_SIZE(eukrea_mximxsd_modes), + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00040060, +}; + +static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) + gpio_direction_output(GPIO_LCDPWR, 1); + else + gpio_direction_output(GPIO_LCDPWR, 0); +} + +static struct plat_lcd_data eukrea_mbimxsd_lcd_power_data = { + .set_power = eukrea_mbimxsd_lcd_power_set, +}; + +static struct platform_device eukrea_mbimxsd_lcd_powerdev = { + .name = "platform-lcd", + .dev.platform_data = &eukrea_mbimxsd_lcd_power_data, +}; + +static struct gpio_led eukrea_mbimxsd_leds[] = { + { + .name = "led1", + .default_trigger = "heartbeat", + .active_low = 1, + .gpio = GPIO_LED1, + }, +}; + +static struct gpio_led_platform_data eukrea_mbimxsd_led_info = { + .leds = eukrea_mbimxsd_leds, + .num_leds = ARRAY_SIZE(eukrea_mbimxsd_leds), +}; + +static struct platform_device eukrea_mbimxsd_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &eukrea_mbimxsd_led_info, + }, +}; + +static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = { + { + .gpio = GPIO_SWITCH1, + .code = BTN_0, + .desc = "BP1", + .active_low = 1, + .wakeup = 1, + }, +}; + +static const struct gpio_keys_platform_data + eukrea_mbimxsd_button_data __initconst = { + .buttons = eukrea_mbimxsd_gpio_buttons, + .nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons), +}; + +static struct platform_device *platform_devices[] __initdata = { + &eukrea_mbimxsd_leds_gpio, + &eukrea_mbimxsd_lcd_powerdev, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = { + { + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +static const +struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = { + .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE, +}; + +static struct esdhc_platform_data sd1_pdata = { + .cd_gpio = GPIO_SD1CD, + .wp_gpio = -EINVAL, +}; + +/* + * system init for baseboard usage. Will be called by cpuimx25 init. + * + * Add platform devices present on this baseboard and init + * them from CPU side as far as required to use them later on + */ +void __init eukrea_mbimxsd25_baseboard_init(void) +{ + if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads, + ARRAY_SIZE(eukrea_mbimxsd_pads))) + printk(KERN_ERR "error setting mbimxsd pads !\n"); + +#if defined(CONFIG_SND_SOC_EUKREA_TLV320) + /* SSI unit master I2S codec connected to SSI_AUD5*/ + mxc_audmux_v2_configure_port(0, + MXC_AUDMUX_V2_PTCR_SYN | + MXC_AUDMUX_V2_PTCR_TFSDIR | + MXC_AUDMUX_V2_PTCR_TFSEL(4) | + MXC_AUDMUX_V2_PTCR_TCLKDIR | + MXC_AUDMUX_V2_PTCR_TCSEL(4), + MXC_AUDMUX_V2_PDCR_RXDSEL(4) + ); + mxc_audmux_v2_configure_port(4, + MXC_AUDMUX_V2_PTCR_SYN, + MXC_AUDMUX_V2_PDCR_RXDSEL(0) + ); +#endif + + imx25_add_imx_uart1(&uart_pdata); + imx25_add_imx_fb(&eukrea_mximxsd_fb_pdata); + imx25_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata); + + imx25_add_flexcan1(NULL); + imx25_add_sdhci_esdhc_imx(0, &sd1_pdata); + + gpio_request(GPIO_LED1, "LED1"); + gpio_direction_output(GPIO_LED1, 1); + gpio_free(GPIO_LED1); + + gpio_request(GPIO_SWITCH1, "SWITCH1"); + gpio_direction_input(GPIO_SWITCH1); + gpio_free(GPIO_SWITCH1); + + gpio_request(GPIO_LCDPWR, "LCDPWR"); + gpio_direction_output(GPIO_LCDPWR, 1); + gpio_free(GPIO_SWITCH1); + + i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices, + ARRAY_SIZE(eukrea_mbimxsd_i2c_devices)); + + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx_add_gpio_keys(&eukrea_mbimxsd_button_data); +} diff --git a/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c new file mode 100644 index 00000000..4909ea05 --- /dev/null +++ b/arch/arm/mach-imx/eukrea_mbimxsd35-baseboard.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2010 Eric Benard - eric@eukrea.com + * + * Based on pcm970-baseboard.c which is : + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/types.h> +#include <linux/init.h> + +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/leds.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <video/platform_lcd.h> +#include <linux/i2c.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx35.h> +#include <mach/audmux.h> + +#include "devices-imx35.h" + +static const struct fb_videomode fb_modedb[] = { + { + .name = "CMO-QVGA", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(6500), + .left_margin = 68, + .right_margin = 20, + .upper_margin = 15, + .lower_margin = 4, + .hsync_len = 30, + .vsync_len = 3, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, + { + .name = "DVI-VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 32000, + .left_margin = 100, + .right_margin = 100, + .upper_margin = 7, + .lower_margin = 100, + .hsync_len = 7, + .vsync_len = 7, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, + { + .name = "DVI-SVGA", + .refresh = 60, + .xres = 800, + .yres = 600, + .pixclock = 25000, + .left_margin = 75, + .right_margin = 75, + .upper_margin = 7, + .lower_margin = 75, + .hsync_len = 7, + .vsync_len = 7, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static const struct ipu_platform_data mx3_ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata __initdata = { + .name = "CMO-QVGA", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +static iomux_v3_cfg_t eukrea_mbimxsd_pads[] = { + /* LCD */ + MX35_PAD_LD0__IPU_DISPB_DAT_0, + MX35_PAD_LD1__IPU_DISPB_DAT_1, + MX35_PAD_LD2__IPU_DISPB_DAT_2, + MX35_PAD_LD3__IPU_DISPB_DAT_3, + MX35_PAD_LD4__IPU_DISPB_DAT_4, + MX35_PAD_LD5__IPU_DISPB_DAT_5, + MX35_PAD_LD6__IPU_DISPB_DAT_6, + MX35_PAD_LD7__IPU_DISPB_DAT_7, + MX35_PAD_LD8__IPU_DISPB_DAT_8, + MX35_PAD_LD9__IPU_DISPB_DAT_9, + MX35_PAD_LD10__IPU_DISPB_DAT_10, + MX35_PAD_LD11__IPU_DISPB_DAT_11, + MX35_PAD_LD12__IPU_DISPB_DAT_12, + MX35_PAD_LD13__IPU_DISPB_DAT_13, + MX35_PAD_LD14__IPU_DISPB_DAT_14, + MX35_PAD_LD15__IPU_DISPB_DAT_15, + MX35_PAD_LD16__IPU_DISPB_DAT_16, + MX35_PAD_LD17__IPU_DISPB_DAT_17, + MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC, + MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK, + MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY, + MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC, + /* Backlight */ + MX35_PAD_CONTRAST__IPU_DISPB_CONTR, + /* LCD_PWR */ + MX35_PAD_D3_CLS__GPIO1_4, + /* LED */ + MX35_PAD_LD23__GPIO3_29, + /* SWITCH */ + MX35_PAD_LD19__GPIO3_25, + /* UART2 */ + MX35_PAD_CTS2__UART2_CTS, + MX35_PAD_RTS2__UART2_RTS, + MX35_PAD_TXD2__UART2_TXD_MUX, + MX35_PAD_RXD2__UART2_RXD_MUX, + /* I2S */ + MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS, + MX35_PAD_STXD4__AUDMUX_AUD4_TXD, + MX35_PAD_SRXD4__AUDMUX_AUD4_RXD, + MX35_PAD_SCK4__AUDMUX_AUD4_TXC, + /* CAN2 */ + MX35_PAD_TX5_RX0__CAN2_TXCAN, + MX35_PAD_TX4_RX1__CAN2_RXCAN, + /* SDCARD */ + MX35_PAD_SD1_CMD__ESDHC1_CMD, + MX35_PAD_SD1_CLK__ESDHC1_CLK, + MX35_PAD_SD1_DATA0__ESDHC1_DAT0, + MX35_PAD_SD1_DATA1__ESDHC1_DAT1, + MX35_PAD_SD1_DATA2__ESDHC1_DAT2, + MX35_PAD_SD1_DATA3__ESDHC1_DAT3, + /* SD1 CD */ + MX35_PAD_LD18__GPIO3_24, +}; + +#define GPIO_LED1 IMX_GPIO_NR(3, 29) +#define GPIO_SWITCH1 IMX_GPIO_NR(3, 25) +#define GPIO_LCDPWR IMX_GPIO_NR(1, 4) +#define GPIO_SD1CD IMX_GPIO_NR(3, 24) + +static void eukrea_mbimxsd_lcd_power_set(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) + gpio_direction_output(GPIO_LCDPWR, 1); + else + gpio_direction_output(GPIO_LCDPWR, 0); +} + +static struct plat_lcd_data eukrea_mbimxsd_lcd_power_data = { + .set_power = eukrea_mbimxsd_lcd_power_set, +}; + +static struct platform_device eukrea_mbimxsd_lcd_powerdev = { + .name = "platform-lcd", + .dev.platform_data = &eukrea_mbimxsd_lcd_power_data, +}; + +static struct gpio_led eukrea_mbimxsd_leds[] = { + { + .name = "led1", + .default_trigger = "heartbeat", + .active_low = 1, + .gpio = GPIO_LED1, + }, +}; + +static struct gpio_led_platform_data eukrea_mbimxsd_led_info = { + .leds = eukrea_mbimxsd_leds, + .num_leds = ARRAY_SIZE(eukrea_mbimxsd_leds), +}; + +static struct platform_device eukrea_mbimxsd_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &eukrea_mbimxsd_led_info, + }, +}; + +static struct gpio_keys_button eukrea_mbimxsd_gpio_buttons[] = { + { + .gpio = GPIO_SWITCH1, + .code = BTN_0, + .desc = "BP1", + .active_low = 1, + .wakeup = 1, + }, +}; + +static const struct gpio_keys_platform_data + eukrea_mbimxsd_button_data __initconst = { + .buttons = eukrea_mbimxsd_gpio_buttons, + .nbuttons = ARRAY_SIZE(eukrea_mbimxsd_gpio_buttons), +}; + +static struct platform_device *platform_devices[] __initdata = { + &eukrea_mbimxsd_leds_gpio, + &eukrea_mbimxsd_lcd_powerdev, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct i2c_board_info eukrea_mbimxsd_i2c_devices[] = { + { + I2C_BOARD_INFO("tlv320aic23", 0x1a), + }, +}; + +static const +struct imx_ssi_platform_data eukrea_mbimxsd_ssi_pdata __initconst = { + .flags = IMX_SSI_SYN | IMX_SSI_NET | IMX_SSI_USE_I2S_SLAVE, +}; + +static struct esdhc_platform_data sd1_pdata = { + .cd_gpio = GPIO_SD1CD, + .wp_gpio = -EINVAL, +}; + +/* + * system init for baseboard usage. Will be called by cpuimx35 init. + * + * Add platform devices present on this baseboard and init + * them from CPU side as far as required to use them later on + */ +void __init eukrea_mbimxsd35_baseboard_init(void) +{ + if (mxc_iomux_v3_setup_multiple_pads(eukrea_mbimxsd_pads, + ARRAY_SIZE(eukrea_mbimxsd_pads))) + printk(KERN_ERR "error setting mbimxsd pads !\n"); + +#if defined(CONFIG_SND_SOC_EUKREA_TLV320) + /* SSI unit master I2S codec connected to SSI_AUD4 */ + mxc_audmux_v2_configure_port(0, + MXC_AUDMUX_V2_PTCR_SYN | + MXC_AUDMUX_V2_PTCR_TFSDIR | + MXC_AUDMUX_V2_PTCR_TFSEL(3) | + MXC_AUDMUX_V2_PTCR_TCLKDIR | + MXC_AUDMUX_V2_PTCR_TCSEL(3), + MXC_AUDMUX_V2_PDCR_RXDSEL(3) + ); + mxc_audmux_v2_configure_port(3, + MXC_AUDMUX_V2_PTCR_SYN, + MXC_AUDMUX_V2_PDCR_RXDSEL(0) + ); +#endif + + imx35_add_imx_uart1(&uart_pdata); + imx35_add_ipu_core(&mx3_ipu_data); + imx35_add_mx3_sdc_fb(&mx3fb_pdata); + + imx35_add_imx_ssi(0, &eukrea_mbimxsd_ssi_pdata); + + imx35_add_flexcan1(NULL); + imx35_add_sdhci_esdhc_imx(0, &sd1_pdata); + + gpio_request(GPIO_LED1, "LED1"); + gpio_direction_output(GPIO_LED1, 1); + gpio_free(GPIO_LED1); + + gpio_request(GPIO_SWITCH1, "SWITCH1"); + gpio_direction_input(GPIO_SWITCH1); + gpio_free(GPIO_SWITCH1); + + gpio_request(GPIO_LCDPWR, "LCDPWR"); + gpio_direction_output(GPIO_LCDPWR, 1); + + i2c_register_board_info(0, eukrea_mbimxsd_i2c_devices, + ARRAY_SIZE(eukrea_mbimxsd_i2c_devices)); + + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx_add_gpio_keys(&eukrea_mbimxsd_button_data); +} diff --git a/arch/arm/mach-imx/include/mach/dma-mx1-mx2.h b/arch/arm/mach-imx/include/mach/dma-mx1-mx2.h new file mode 100644 index 00000000..df5f522d --- /dev/null +++ b/arch/arm/mach-imx/include/mach/dma-mx1-mx2.h @@ -0,0 +1,10 @@ +#ifndef __MACH_DMA_MX1_MX2_H__ +#define __MACH_DMA_MX1_MX2_H__ +/* + * Don't use this header in new code, it will go away when all users are + * converted to mach/dma-v1.h + */ + +#include <mach/dma-v1.h> + +#endif /* ifndef __MACH_DMA_MX1_MX2_H__ */ diff --git a/arch/arm/mach-imx/include/mach/dma-v1.h b/arch/arm/mach-imx/include/mach/dma-v1.h new file mode 100644 index 00000000..ac6fd713 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/dma-v1.h @@ -0,0 +1,103 @@ +/* + * linux/arch/arm/mach-imx/include/mach/dma-v1.h + * + * i.MX DMA registration and IRQ dispatching + * + * Copyright 2006 Pavel Pisa <pisa@cmp.felk.cvut.cz> + * Copyright 2008 Juergen Beisert, <kernel@pengutronix.de> + * Copyright 2008 Sascha Hauer, <s.hauer@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#ifndef __MACH_DMA_V1_H__ +#define __MACH_DMA_V1_H__ + +#define imx_has_dma_v1() (cpu_is_mx1() || cpu_is_mx21() || cpu_is_mx27()) + +#include <mach/dma.h> + +#define IMX_DMA_CHANNELS 16 + +#define DMA_MODE_READ 0 +#define DMA_MODE_WRITE 1 +#define DMA_MODE_MASK 1 + +#define MX1_DMA_REG(offset) MX1_IO_ADDRESS(MX1_DMA_BASE_ADDR + (offset)) + +/* DMA Interrupt Mask Register */ +#define MX1_DMA_DIMR MX1_DMA_REG(0x08) + +/* Channel Control Register */ +#define MX1_DMA_CCR(x) MX1_DMA_REG(0x8c + ((x) << 6)) + +#define IMX_DMA_MEMSIZE_32 (0 << 4) +#define IMX_DMA_MEMSIZE_8 (1 << 4) +#define IMX_DMA_MEMSIZE_16 (2 << 4) +#define IMX_DMA_TYPE_LINEAR (0 << 10) +#define IMX_DMA_TYPE_2D (1 << 10) +#define IMX_DMA_TYPE_FIFO (2 << 10) + +#define IMX_DMA_ERR_BURST (1 << 0) +#define IMX_DMA_ERR_REQUEST (1 << 1) +#define IMX_DMA_ERR_TRANSFER (1 << 2) +#define IMX_DMA_ERR_BUFFER (1 << 3) +#define IMX_DMA_ERR_TIMEOUT (1 << 4) + +int +imx_dma_config_channel(int channel, unsigned int config_port, + unsigned int config_mem, unsigned int dmareq, int hw_chaining); + +void +imx_dma_config_burstlen(int channel, unsigned int burstlen); + +int +imx_dma_setup_single(int channel, dma_addr_t dma_address, + unsigned int dma_length, unsigned int dev_addr, + unsigned int dmamode); + + +/* + * Use this flag as the dma_length argument to imx_dma_setup_sg() + * to create an endless running dma loop. The end of the scatterlist + * must be linked to the beginning for this to work. + */ +#define IMX_DMA_LENGTH_LOOP ((unsigned int)-1) + +int +imx_dma_setup_sg(int channel, struct scatterlist *sg, + unsigned int sgcount, unsigned int dma_length, + unsigned int dev_addr, unsigned int dmamode); + +int +imx_dma_setup_handlers(int channel, + void (*irq_handler) (int, void *), + void (*err_handler) (int, void *, int), void *data); + +int +imx_dma_setup_progression_handler(int channel, + void (*prog_handler) (int, void*, struct scatterlist*)); + +void imx_dma_enable(int channel); + +void imx_dma_disable(int channel); + +int imx_dma_request(int channel, const char *name); + +void imx_dma_free(int channel); + +int imx_dma_request_by_prio(const char *name, enum imx_dma_prio prio); + +#endif /* __MACH_DMA_V1_H__ */ diff --git a/arch/arm/mach-imx/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c new file mode 100644 index 00000000..cf8f8099 --- /dev/null +++ b/arch/arm/mach-imx/iomux-imx31.c @@ -0,0 +1,181 @@ +/* + * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * Copyright (C) 2009 by Valentin Longchamp <valentin.longchamp@epfl.ch> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/iomux-mx3.h> + +/* + * IOMUX register (base) addresses + */ +#define IOMUX_BASE MX31_IO_ADDRESS(MX31_IOMUXC_BASE_ADDR) +#define IOMUXINT_OBS1 (IOMUX_BASE + 0x000) +#define IOMUXINT_OBS2 (IOMUX_BASE + 0x004) +#define IOMUXGPR (IOMUX_BASE + 0x008) +#define IOMUXSW_MUX_CTL (IOMUX_BASE + 0x00C) +#define IOMUXSW_PAD_CTL (IOMUX_BASE + 0x154) + +static DEFINE_SPINLOCK(gpio_mux_lock); + +#define IOMUX_REG_MASK (IOMUX_PADNUM_MASK & ~0x3) + +unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG]; +/* + * set the mode for a IOMUX pin. + */ +int mxc_iomux_mode(unsigned int pin_mode) +{ + u32 field, l, mode, ret = 0; + void __iomem *reg; + + reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK); + field = pin_mode & 0x3; + mode = (pin_mode & IOMUX_MODE_MASK) >> IOMUX_MODE_SHIFT; + + spin_lock(&gpio_mux_lock); + + l = __raw_readl(reg); + l &= ~(0xff << (field * 8)); + l |= mode << (field * 8); + __raw_writel(l, reg); + + spin_unlock(&gpio_mux_lock); + + return ret; +} +EXPORT_SYMBOL(mxc_iomux_mode); + +/* + * This function configures the pad value for a IOMUX pin. + */ +void mxc_iomux_set_pad(enum iomux_pins pin, u32 config) +{ + u32 field, l; + void __iomem *reg; + + pin &= IOMUX_PADNUM_MASK; + reg = IOMUXSW_PAD_CTL + (pin + 2) / 3 * 4; + field = (pin + 2) % 3; + + pr_debug("%s: reg offset = 0x%x, field = %d\n", + __func__, (pin + 2) / 3, field); + + spin_lock(&gpio_mux_lock); + + l = __raw_readl(reg); + l &= ~(0x1ff << (field * 10)); + l |= config << (field * 10); + __raw_writel(l, reg); + + spin_unlock(&gpio_mux_lock); +} +EXPORT_SYMBOL(mxc_iomux_set_pad); + +/* + * allocs a single pin: + * - reserves the pin so that it is not claimed by another driver + * - setups the iomux according to the configuration + */ +int mxc_iomux_alloc_pin(unsigned int pin, const char *label) +{ + unsigned pad = pin & IOMUX_PADNUM_MASK; + + if (pad >= (PIN_MAX + 1)) { + printk(KERN_ERR "mxc_iomux: Attempt to request nonexistant pin %u for \"%s\"\n", + pad, label ? label : "?"); + return -EINVAL; + } + + if (test_and_set_bit(pad, mxc_pin_alloc_map)) { + printk(KERN_ERR "mxc_iomux: pin %u already used. Allocation for \"%s\" failed\n", + pad, label ? label : "?"); + return -EBUSY; + } + mxc_iomux_mode(pin); + + return 0; +} +EXPORT_SYMBOL(mxc_iomux_alloc_pin); + +int mxc_iomux_setup_multiple_pins(const unsigned int *pin_list, unsigned count, + const char *label) +{ + const unsigned int *p = pin_list; + int i; + int ret = -EINVAL; + + for (i = 0; i < count; i++) { + ret = mxc_iomux_alloc_pin(*p, label); + if (ret) + goto setup_error; + p++; + } + return 0; + +setup_error: + mxc_iomux_release_multiple_pins(pin_list, i); + return ret; +} +EXPORT_SYMBOL(mxc_iomux_setup_multiple_pins); + +void mxc_iomux_release_pin(unsigned int pin) +{ + unsigned pad = pin & IOMUX_PADNUM_MASK; + + if (pad < (PIN_MAX + 1)) + clear_bit(pad, mxc_pin_alloc_map); +} +EXPORT_SYMBOL(mxc_iomux_release_pin); + +void mxc_iomux_release_multiple_pins(const unsigned int *pin_list, int count) +{ + const unsigned int *p = pin_list; + int i; + + for (i = 0; i < count; i++) { + mxc_iomux_release_pin(*p); + p++; + } +} +EXPORT_SYMBOL(mxc_iomux_release_multiple_pins); + +/* + * This function enables/disables the general purpose function for a particular + * signal. + */ +void mxc_iomux_set_gpr(enum iomux_gp_func gp, bool en) +{ + u32 l; + + spin_lock(&gpio_mux_lock); + l = __raw_readl(IOMUXGPR); + if (en) + l |= gp; + else + l &= ~gp; + + __raw_writel(l, IOMUXGPR); + spin_unlock(&gpio_mux_lock); +} +EXPORT_SYMBOL(mxc_iomux_set_gpr); diff --git a/arch/arm/mach-imx/mach-apf9328.c b/arch/arm/mach-imx/mach-apf9328.c new file mode 100644 index 00000000..15e45c84 --- /dev/null +++ b/arch/arm/mach-imx/mach-apf9328.c @@ -0,0 +1,144 @@ +/* + * linux/arch/arm/mach-imx/mach-apf9328.c + * + * Copyright (c) 2005-2011 ARMadeus systems <support@armadeus.com> + * + * This work is based on mach-scb9328.c which is: + * Copyright (c) 2004 Sascha Hauer <saschahauer@web.de> + * Copyright (c) 2006-2008 Juergen Beisert <jbeisert@netscape.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/dm9000.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/iomux-mx1.h> + +#include "devices-imx1.h" + +static const int apf9328_pins[] __initconst = { + /* UART1 */ + PC9_PF_UART1_CTS, + PC10_PF_UART1_RTS, + PC11_PF_UART1_TXD, + PC12_PF_UART1_RXD, + /* UART2 */ + PB28_PF_UART2_CTS, + PB29_PF_UART2_RTS, + PB30_PF_UART2_TXD, + PB31_PF_UART2_RXD, +}; + +/* + * The APF9328 can have up to 32MB NOR Flash + */ +static struct resource flash_resource = { + .start = MX1_CS0_PHYS, + .end = MX1_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct physmap_flash_data apf9328_flash_data = { + .width = 2, +}; + +static struct platform_device apf9328_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &apf9328_flash_data, + }, + .resource = &flash_resource, + .num_resources = 1, +}; + +/* + * APF9328 has a DM9000 Ethernet controller + */ +static struct dm9000_plat_data dm9000_setup = { + .flags = DM9000_PLATF_16BITONLY +}; + +static struct resource dm9000_resources[] = { + { + .start = MX1_CS4_PHYS + 0x00C00000, + .end = MX1_CS4_PHYS + 0x00C00001, + .flags = IORESOURCE_MEM, + }, { + .start = MX1_CS4_PHYS + 0x00C00002, + .end = MX1_CS4_PHYS + 0x00C00003, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_GPIOB(14), + .end = IRQ_GPIOB(14), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct platform_device dm9000x_device = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(dm9000_resources), + .resource = dm9000_resources, + .dev = { + .platform_data = &dm9000_setup, + } +}; + +/* --- SERIAL RESSOURCE --- */ +static const struct imxuart_platform_data uart0_pdata __initconst = { + .flags = 0, +}; + +static const struct imxuart_platform_data uart1_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *devices[] __initdata = { + &apf9328_flash_device, + &dm9000x_device, +}; + +static void __init apf9328_init(void) +{ + mxc_gpio_setup_multiple_pins(apf9328_pins, + ARRAY_SIZE(apf9328_pins), + "APF9328"); + + imx1_add_imx_uart0(&uart0_pdata); + imx1_add_imx_uart1(&uart1_pdata); + + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init apf9328_timer_init(void) +{ + mx1_clocks_init(32768); +} + +static struct sys_timer apf9328_timer = { + .init = apf9328_timer_init, +}; + +MACHINE_START(APF9328, "Armadeus APF9328") + /* Maintainer: Gwenhael Goavec-Merou, ARMadeus Systems */ + .map_io = mx1_map_io, + .init_early = imx1_init_early, + .init_irq = mx1_init_irq, + .timer = &apf9328_timer, + .init_machine = apf9328_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-armadillo5x0.c b/arch/arm/mach-imx/mach-armadillo5x0.c new file mode 100644 index 00000000..ffb40ff6 --- /dev/null +++ b/arch/arm/mach-imx/mach-armadillo5x0.c @@ -0,0 +1,565 @@ +/* + * armadillo5x0.c + * + * Copyright 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> + * updates in http://alberdroid.blogspot.com/ + * + * Based on Atmark Techno, Inc. armadillo 500 BSP 2008 + * Based on mx31ads.c and pcm037.c Great Work! + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/smsc911x.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/mtd/physmap.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/i2c.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/delay.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/memory.h> +#include <asm/mach/map.h> + +#include <mach/common.h> +#include <mach/iomux-mx3.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" +#include "crmregs-imx31.h" + +static int armadillo5x0_pins[] = { + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + /* UART2 */ + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + /* LAN9118_IRQ */ + IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO), + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + /* Framebuffer */ + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_DRDY0__DRDY0, + IOMUX_MODE(MX31_PIN_LCS1, IOMUX_CONFIG_GPIO), /*ADV7125_PSAVE*/ + /* I2C2 */ + MX31_PIN_CSPI2_MOSI__SCL, + MX31_PIN_CSPI2_MISO__SDA, + /* OTG */ + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, + MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, + MX31_PIN_USBOTG_STP__USBOTG_STP, + /* USB host 2 */ + IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_STXD3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SRXD3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SCK3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SFS3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_STXD6, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SRXD6, IOMUX_CONFIG_FUNC), +}; + +/* USB */ + +#define OTG_RESET IOMUX_TO_GPIO(MX31_PIN_STXD4) +#define USBH2_RESET IOMUX_TO_GPIO(MX31_PIN_SCK6) +#define USBH2_CS IOMUX_TO_GPIO(MX31_PIN_GPIO1_3) + +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +static int usbotg_init(struct platform_device *pdev) +{ + int err; + + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG); + + /* Chip already enabled by hardware */ + /* OTG phy reset*/ + err = gpio_request(OTG_RESET, "USB-OTG-RESET"); + if (err) { + pr_err("Failed to request the usb otg reset gpio\n"); + return err; + } + + err = gpio_direction_output(OTG_RESET, 1/*HIGH*/); + if (err) { + pr_err("Failed to reset the usb otg phy\n"); + goto otg_free_reset; + } + + gpio_set_value(OTG_RESET, 0/*LOW*/); + mdelay(5); + gpio_set_value(OTG_RESET, 1/*HIGH*/); + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_INTERFACE_DIFF_UNI); + +otg_free_reset: + gpio_free(OTG_RESET); + return err; +} + +static int usbh2_init(struct platform_device *pdev) +{ + int err; + + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG); + + mxc_iomux_set_gpr(MUX_PGP_UH2, true); + + + /* Enable the chip */ + err = gpio_request(USBH2_CS, "USB-H2-CS"); + if (err) { + pr_err("Failed to request the usb host 2 CS gpio\n"); + return err; + } + + err = gpio_direction_output(USBH2_CS, 0/*Enabled*/); + if (err) { + pr_err("Failed to drive the usb host 2 CS gpio\n"); + goto h2_free_cs; + } + + /* H2 phy reset*/ + err = gpio_request(USBH2_RESET, "USB-H2-RESET"); + if (err) { + pr_err("Failed to request the usb host 2 reset gpio\n"); + goto h2_free_cs; + } + + err = gpio_direction_output(USBH2_RESET, 1/*HIGH*/); + if (err) { + pr_err("Failed to reset the usb host 2 phy\n"); + goto h2_free_reset; + } + + gpio_set_value(USBH2_RESET, 0/*LOW*/); + mdelay(5); + gpio_set_value(USBH2_RESET, 1/*HIGH*/); + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_INTERFACE_DIFF_UNI); + +h2_free_reset: + gpio_free(USBH2_RESET); +h2_free_cs: + gpio_free(USBH2_CS); + return err; +} + +static struct mxc_usbh_platform_data usbotg_pdata __initdata = { + .init = usbotg_init, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = usbh2_init, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +/* RTC over I2C*/ +#define ARMADILLO5X0_RTC_GPIO IOMUX_TO_GPIO(MX31_PIN_SRXD4) + +static struct i2c_board_info armadillo5x0_i2c_rtc = { + I2C_BOARD_INFO("s35390a", 0x30), +}; + +/* GPIO BUTTONS */ +static struct gpio_keys_button armadillo5x0_buttons[] = { + { + .code = KEY_ENTER, /*28*/ + .gpio = IOMUX_TO_GPIO(MX31_PIN_SCLK0), + .active_low = 1, + .desc = "menu", + .wakeup = 1, + }, { + .code = KEY_BACK, /*158*/ + .gpio = IOMUX_TO_GPIO(MX31_PIN_SRST0), + .active_low = 1, + .desc = "back", + .wakeup = 1, + } +}; + +static const struct gpio_keys_platform_data + armadillo5x0_button_data __initconst = { + .buttons = armadillo5x0_buttons, + .nbuttons = ARRAY_SIZE(armadillo5x0_buttons), +}; + +/* + * NAND Flash + */ +static const struct mxc_nand_platform_data +armadillo5x0_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +/* + * MTD NOR Flash + */ +static struct mtd_partition armadillo5x0_nor_flash_partitions[] = { + { + .name = "nor.bootloader", + .offset = 0x00000000, + .size = 4*32*1024, + }, { + .name = "nor.kernel", + .offset = MTDPART_OFS_APPEND, + .size = 16*128*1024, + }, { + .name = "nor.userland", + .offset = MTDPART_OFS_APPEND, + .size = 110*128*1024, + }, { + .name = "nor.config", + .offset = MTDPART_OFS_APPEND, + .size = 1*128*1024, + }, +}; + +static struct physmap_flash_data armadillo5x0_nor_flash_pdata = { + .width = 2, + .parts = armadillo5x0_nor_flash_partitions, + .nr_parts = ARRAY_SIZE(armadillo5x0_nor_flash_partitions), +}; + +static struct resource armadillo5x0_nor_flash_resource = { + .flags = IORESOURCE_MEM, + .start = MX31_CS0_BASE_ADDR, + .end = MX31_CS0_BASE_ADDR + SZ_64M - 1, +}; + +static struct platform_device armadillo5x0_nor_flash = { + .name = "physmap-flash", + .id = -1, + .num_resources = 1, + .resource = &armadillo5x0_nor_flash_resource, +}; + +/* + * FB support + */ +static const struct fb_videomode fb_modedb[] = { + { /* 640x480 @ 60 Hz */ + .name = "CRT-VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39721, + .left_margin = 35, + .right_margin = 115, + .upper_margin = 43, + .lower_margin = 1, + .hsync_len = 10, + .vsync_len = 1, + .sync = FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, {/* 800x600 @ 56 Hz */ + .name = "CRT-SVGA", + .refresh = 56, + .xres = 800, + .yres = 600, + .pixclock = 30000, + .left_margin = 30, + .right_margin = 108, + .upper_margin = 13, + .lower_margin = 10, + .hsync_len = 10, + .vsync_len = 1, + .sync = FB_SYNC_OE_ACT_HIGH | FB_SYNC_HOR_HIGH_ACT | + FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static const struct ipu_platform_data mx3_ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata __initdata = { + .name = "CRT-VGA", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +/* + * SDHC 1 + * MMC support + */ +static int armadillo5x0_sdhc1_get_ro(struct device *dev) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B)); +} + +static int armadillo5x0_sdhc1_init(struct device *dev, + irq_handler_t detect_irq, void *data) +{ + int ret; + int gpio_det, gpio_wp; + + gpio_det = IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK); + gpio_wp = IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B); + + ret = gpio_request(gpio_det, "sdhc-card-detect"); + if (ret) + return ret; + + gpio_direction_input(gpio_det); + + ret = gpio_request(gpio_wp, "sdhc-write-protect"); + if (ret) + goto err_gpio_free; + + gpio_direction_input(gpio_wp); + + /* When supported the trigger type have to be BOTH */ + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "sdhc-detect", data); + + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(gpio_wp); + +err_gpio_free: + gpio_free(gpio_det); + + return ret; + +} + +static void armadillo5x0_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IOMUX_TO_IRQ(MX31_PIN_ATA_DMACK), data); + gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_DMACK)); + gpio_free(IOMUX_TO_GPIO(MX31_PIN_ATA_RESET_B)); +} + +static const struct imxmmc_platform_data sdhc_pdata __initconst = { + .get_ro = armadillo5x0_sdhc1_get_ro, + .init = armadillo5x0_sdhc1_init, + .exit = armadillo5x0_sdhc1_exit, +}; + +/* + * SMSC 9118 + * Network support + */ +static struct resource armadillo5x0_smc911x_resources[] = { + { + .start = MX31_CS3_BASE_ADDR, + .end = MX31_CS3_BASE_ADDR + SZ_32M - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct smsc911x_platform_config smsc911x_info = { + .flags = SMSC911X_USE_16BIT, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, +}; + +static struct platform_device armadillo5x0_smc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(armadillo5x0_smc911x_resources), + .resource = armadillo5x0_smc911x_resources, + .dev = { + .platform_data = &smsc911x_info, + }, +}; + +/* UART device data */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *devices[] __initdata = { + &armadillo5x0_smc911x_device, +}; + +/* + * Perform board specific initializations + */ +static void __init armadillo5x0_init(void) +{ + mxc_iomux_setup_multiple_pins(armadillo5x0_pins, + ARRAY_SIZE(armadillo5x0_pins), "armadillo5x0"); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + imx_add_gpio_keys(&armadillo5x0_button_data); + imx31_add_imx_i2c1(NULL); + + /* Register UART */ + imx31_add_imx_uart0(&uart_pdata); + imx31_add_imx_uart1(&uart_pdata); + + /* SMSC9118 IRQ pin */ + gpio_direction_input(MX31_PIN_GPIO1_0); + + /* Register SDHC */ + imx31_add_mxc_mmc(0, &sdhc_pdata); + + /* Register FB */ + imx31_add_ipu_core(&mx3_ipu_data); + imx31_add_mx3_sdc_fb(&mx3fb_pdata); + + /* Register NOR Flash */ + mxc_register_device(&armadillo5x0_nor_flash, + &armadillo5x0_nor_flash_pdata); + + /* Register NAND Flash */ + imx31_add_mxc_nand(&armadillo5x0_nand_board_info); + + /* set NAND page size to 2k if not configured via boot mode pins */ + __raw_writel(__raw_readl(MXC_CCM_RCSR) | (1 << 30), MXC_CCM_RCSR); + + /* RTC */ + /* Get RTC IRQ and register the chip */ + if (gpio_request(ARMADILLO5X0_RTC_GPIO, "rtc") == 0) { + if (gpio_direction_input(ARMADILLO5X0_RTC_GPIO) == 0) + armadillo5x0_i2c_rtc.irq = gpio_to_irq(ARMADILLO5X0_RTC_GPIO); + else + gpio_free(ARMADILLO5X0_RTC_GPIO); + } + if (armadillo5x0_i2c_rtc.irq == 0) + pr_warning("armadillo5x0_init: failed to get RTC IRQ\n"); + i2c_register_board_info(1, &armadillo5x0_i2c_rtc, 1); + + /* USB */ + + usbotg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbotg_pdata.otg) + imx31_add_mxc_ehci_otg(&usbotg_pdata); + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbh2_pdata.otg) + imx31_add_mxc_ehci_hs(2, &usbh2_pdata); +} + +static void __init armadillo5x0_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer armadillo5x0_timer = { + .init = armadillo5x0_timer_init, +}; + +MACHINE_START(ARMADILLO5X0, "Armadillo-500") + /* Maintainer: Alberto Panizzo */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &armadillo5x0_timer, + .init_machine = armadillo5x0_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-bug.c b/arch/arm/mach-imx/mach-bug.c new file mode 100644 index 00000000..42e4f078 --- /dev/null +++ b/arch/arm/mach-imx/mach-bug.c @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2011 Denis 'GNUtoo' Carikli <GNUtoo@no-log.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> + +#include <mach/iomux-mx3.h> +#include <mach/hardware.h> +#include <mach/common.h> + +#include <asm/mach/time.h> +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include "devices-imx31.h" + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const unsigned int bug_pins[] __initconst = { + MX31_PIN_PC_RST__CTS5, + MX31_PIN_PC_VS2__RTS5, + MX31_PIN_PC_BVD2__TXD5, + MX31_PIN_PC_BVD1__RXD5, +}; + +static void __init bug_board_init(void) +{ + mxc_iomux_setup_multiple_pins(bug_pins, + ARRAY_SIZE(bug_pins), "uart-4"); + imx31_add_imx_uart4(&uart_pdata); +} + +static void __init bug_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer bug_timer = { + .init = bug_timer_init, +}; + +MACHINE_START(BUG, "BugLabs BUGBase") + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &bug_timer, + .init_machine = bug_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c new file mode 100644 index 00000000..46a2e41d --- /dev/null +++ b/arch/arm/mach-imx/mach-cpuimx27.c @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2009 Eric Benard - eric@eukrea.com + * + * Based on pcm038.c which is : + * Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/mtd/plat-ram.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/eukrea-baseboards.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx27.h> +#include <mach/ulpi.h> + +#include "devices-imx27.h" + +static const int eukrea_cpuimx27_pins[] __initconst = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* UART4 */ +#if defined(MACH_EUKREA_CPUIMX27_USEUART4) + PB26_AF_UART4_RTS, + PB28_AF_UART4_TXD, + PB29_AF_UART4_CTS, + PB31_AF_UART4_RXD, +#endif + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* I2C1 */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, + /* SDHC2 */ +#if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2) + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, +#endif +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + /* Quad UART's IRQ */ + GPIO_PORTB | 22 | GPIO_GPIO | GPIO_IN, + GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN, + GPIO_PORTB | 27 | GPIO_GPIO | GPIO_IN, + GPIO_PORTB | 30 | GPIO_GPIO | GPIO_IN, +#endif + /* OTG */ + PC7_PF_USBOTG_DATA5, + PC8_PF_USBOTG_DATA6, + PC9_PF_USBOTG_DATA0, + PC10_PF_USBOTG_DATA2, + PC11_PF_USBOTG_DATA1, + PC12_PF_USBOTG_DATA4, + PC13_PF_USBOTG_DATA3, + PE0_PF_USBOTG_NXT, + PE1_PF_USBOTG_STP, + PE2_PF_USBOTG_DIR, + PE24_PF_USBOTG_CLK, + PE25_PF_USBOTG_DATA7, + /* USBH2 */ + PA0_PF_USBH2_CLK, + PA1_PF_USBH2_DIR, + PA2_PF_USBH2_DATA7, + PA3_PF_USBH2_NXT, + PA4_PF_USBH2_STP, + PD19_AF_USBH2_DATA4, + PD20_AF_USBH2_DATA3, + PD21_AF_USBH2_DATA6, + PD22_AF_USBH2_DATA0, + PD23_AF_USBH2_DATA2, + PD24_AF_USBH2_DATA1, + PD26_AF_USBH2_DATA5, +}; + +static struct physmap_flash_data eukrea_cpuimx27_flash_data = { + .width = 2, +}; + +static struct resource eukrea_cpuimx27_flash_resource = { + .start = 0xc0000000, + .end = 0xc3ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device eukrea_cpuimx27_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &eukrea_cpuimx27_flash_data, + }, + .num_resources = 1, + .resource = &eukrea_cpuimx27_flash_resource, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct mxc_nand_platform_data +cpuimx27_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static struct platform_device *platform_devices[] __initdata = { + &eukrea_cpuimx27_nor_mtd_device, +}; + +static const struct imxi2c_platform_data cpuimx27_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info eukrea_cpuimx27_i2c_devices[] = { + { + I2C_BOARD_INFO("pcf8563", 0x51), + }, +}; + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) +static struct plat_serial8250_port serial_platform_data[] = { + { + .mapbase = (unsigned long)(MX27_CS3_BASE_ADDR + 0x200000), + .irq = IRQ_GPIOB(23), + .uartclk = 14745600, + .regshift = 1, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + .mapbase = (unsigned long)(MX27_CS3_BASE_ADDR + 0x400000), + .irq = IRQ_GPIOB(22), + .uartclk = 14745600, + .regshift = 1, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + .mapbase = (unsigned long)(MX27_CS3_BASE_ADDR + 0x800000), + .irq = IRQ_GPIOB(27), + .uartclk = 14745600, + .regshift = 1, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + .mapbase = (unsigned long)(MX27_CS3_BASE_ADDR + 0x1000000), + .irq = IRQ_GPIOB(30), + .uartclk = 14745600, + .regshift = 1, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP, + }, { + } +}; + +static struct platform_device serial_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = serial_platform_data, + }, +}; +#endif + +static int eukrea_cpuimx27_otg_init(struct platform_device *pdev) +{ + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = eukrea_cpuimx27_otg_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static int eukrea_cpuimx27_usbh2_init(struct platform_device *pdev) +{ + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = eukrea_cpuimx27_usbh2_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +static int otg_mode_host; + +static int __init eukrea_cpuimx27_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", eukrea_cpuimx27_otg_mode); + +static void __init eukrea_cpuimx27_init(void) +{ + mxc_gpio_setup_multiple_pins(eukrea_cpuimx27_pins, + ARRAY_SIZE(eukrea_cpuimx27_pins), "CPUIMX27"); + + imx27_add_imx_uart0(&uart_pdata); + + imx27_add_mxc_nand(&cpuimx27_nand_board_info); + + i2c_register_board_info(0, eukrea_cpuimx27_i2c_devices, + ARRAY_SIZE(eukrea_cpuimx27_i2c_devices)); + + imx27_add_imx_i2c(0, &cpuimx27_i2c1_data); + + imx27_add_fec(NULL); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx27_add_imx2_wdt(NULL); + imx27_add_mxc_w1(NULL); + +#if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2) + /* SDHC2 can be used for Wifi */ + imx27_add_mxc_mmc(1, NULL); +#endif +#if defined(MACH_EUKREA_CPUIMX27_USEUART4) + /* in which case UART4 is also used for Bluetooth */ + imx27_add_imx_uart3(&uart_pdata); +#endif + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) + platform_device_register(&serial_device); +#endif + + if (otg_mode_host) { + otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (otg_pdata.otg) + imx27_add_mxc_ehci_otg(&otg_pdata); + } else { + imx27_add_fsl_usb2_udc(&otg_device_pdata); + } + + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbh2_pdata.otg) + imx27_add_mxc_ehci_hs(2, &usbh2_pdata); + +#ifdef CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD + eukrea_mbimx27_baseboard_init(); +#endif +} + +static void __init eukrea_cpuimx27_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer eukrea_cpuimx27_timer = { + .init = eukrea_cpuimx27_timer_init, +}; + +MACHINE_START(CPUIMX27, "EUKREA CPUIMX27") + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &eukrea_cpuimx27_timer, + .init_machine = eukrea_cpuimx27_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c new file mode 100644 index 00000000..3f8ef825 --- /dev/null +++ b/arch/arm/mach-imx/mach-cpuimx35.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2010 Eric Benard - eric@eukrea.com + * Copyright (C) 2009 Sascha Hauer, Pengutronix + * + * 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/types.h> +#include <linux/init.h> + +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/memory.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/i2c/tsc2007.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/i2c-gpio.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/eukrea-baseboards.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx35.h> + +#include "devices-imx35.h" + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxi2c_platform_data + eukrea_cpuimx35_i2c0_data __initconst = { + .bitrate = 100000, +}; + +static struct tsc2007_platform_data tsc2007_info = { + .model = 2007, + .x_plate_ohms = 180, +}; + +#define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2) +static struct i2c_board_info eukrea_cpuimx35_i2c_devices[] = { + { + I2C_BOARD_INFO("pcf8563", 0x51), + }, { + I2C_BOARD_INFO("tsc2007", 0x48), + .type = "tsc2007", + .platform_data = &tsc2007_info, + .irq = gpio_to_irq(TSC2007_IRQGPIO), + }, +}; + +static iomux_v3_cfg_t eukrea_cpuimx35_pads[] = { + /* UART1 */ + MX35_PAD_CTS1__UART1_CTS, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RXD1__UART1_RXD_MUX, + /* FEC */ + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + /* I2C1 */ + MX35_PAD_I2C1_CLK__I2C1_SCL, + MX35_PAD_I2C1_DAT__I2C1_SDA, + /* TSC2007 IRQ */ + MX35_PAD_ATA_DA2__GPIO3_2, +}; + +static const struct mxc_nand_platform_data + eukrea_cpuimx35_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static int eukrea_cpuimx35_otg_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static const struct mxc_usbh_platform_data otg_pdata __initconst = { + .init = eukrea_cpuimx35_otg_init, + .portsc = MXC_EHCI_MODE_UTMI, +}; + +static int eukrea_cpuimx35_usbh1_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI | + MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN); +} + +static const struct mxc_usbh_platform_data usbh1_pdata __initconst = { + .init = eukrea_cpuimx35_usbh1_init, + .portsc = MXC_EHCI_MODE_SERIAL, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI, + .workaround = FLS_USB2_WORKAROUND_ENGCM09152, +}; + +static int otg_mode_host; + +static int __init eukrea_cpuimx35_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", eukrea_cpuimx35_otg_mode); + +/* + * Board specific initialization. + */ +static void __init eukrea_cpuimx35_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads, + ARRAY_SIZE(eukrea_cpuimx35_pads)); + + imx35_add_fec(NULL); + imx35_add_imx2_wdt(NULL); + + imx35_add_imx_uart0(&uart_pdata); + imx35_add_mxc_nand(&eukrea_cpuimx35_nand_board_info); + + i2c_register_board_info(0, eukrea_cpuimx35_i2c_devices, + ARRAY_SIZE(eukrea_cpuimx35_i2c_devices)); + imx35_add_imx_i2c0(&eukrea_cpuimx35_i2c0_data); + + if (otg_mode_host) + imx35_add_mxc_ehci_otg(&otg_pdata); + else + imx35_add_fsl_usb2_udc(&otg_device_pdata); + + imx35_add_mxc_ehci_hs(&usbh1_pdata); + +#ifdef CONFIG_MACH_EUKREA_MBIMXSD35_BASEBOARD + eukrea_mbimxsd35_baseboard_init(); +#endif +} + +static void __init eukrea_cpuimx35_timer_init(void) +{ + mx35_clocks_init(); +} + +struct sys_timer eukrea_cpuimx35_timer = { + .init = eukrea_cpuimx35_timer_init, +}; + +MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35") + /* Maintainer: Eukrea Electromatique */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx35_map_io, + .init_early = imx35_init_early, + .init_irq = mx35_init_irq, + .timer = &eukrea_cpuimx35_timer, + .init_machine = eukrea_cpuimx35_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c new file mode 100644 index 00000000..148cff28 --- /dev/null +++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c @@ -0,0 +1,170 @@ +/* + * Copyright 2009 Sascha Hauer, <kernel@pengutronix.de> + * Copyright 2010 Eric Bénard - Eukréa Electromatique, <eric@eukrea.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <mach/eukrea-baseboards.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/memory.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <mach/mx25.h> +#include <mach/iomux-mx25.h> + +#include "devices-imx25.h" + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static iomux_v3_cfg_t eukrea_cpuimx25_pads[] = { + /* FEC - RMII */ + MX25_PAD_FEC_MDC__FEC_MDC, + MX25_PAD_FEC_MDIO__FEC_MDIO, + MX25_PAD_FEC_TDATA0__FEC_TDATA0, + MX25_PAD_FEC_TDATA1__FEC_TDATA1, + MX25_PAD_FEC_TX_EN__FEC_TX_EN, + MX25_PAD_FEC_RDATA0__FEC_RDATA0, + MX25_PAD_FEC_RDATA1__FEC_RDATA1, + MX25_PAD_FEC_RX_DV__FEC_RX_DV, + MX25_PAD_FEC_TX_CLK__FEC_TX_CLK, + /* I2C1 */ + MX25_PAD_I2C1_CLK__I2C1_CLK, + MX25_PAD_I2C1_DAT__I2C1_DAT, +}; + +static const struct fec_platform_data mx25_fec_pdata __initconst = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +static const struct mxc_nand_platform_data +eukrea_cpuimx25_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static const struct imxi2c_platform_data +eukrea_cpuimx25_i2c0_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info eukrea_cpuimx25_i2c_devices[] = { + { + I2C_BOARD_INFO("pcf8563", 0x51), + }, +}; + +static int eukrea_cpuimx25_otg_init(struct platform_device *pdev) +{ + return mx25_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static const struct mxc_usbh_platform_data otg_pdata __initconst = { + .init = eukrea_cpuimx25_otg_init, + .portsc = MXC_EHCI_MODE_UTMI, +}; + +static int eukrea_cpuimx25_usbh2_init(struct platform_device *pdev) +{ + return mx25_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI | + MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN); +} + +static const struct mxc_usbh_platform_data usbh2_pdata __initconst = { + .init = eukrea_cpuimx25_usbh2_init, + .portsc = MXC_EHCI_MODE_SERIAL, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI, +}; + +static int otg_mode_host; + +static int __init eukrea_cpuimx25_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", eukrea_cpuimx25_otg_mode); + +static void __init eukrea_cpuimx25_init(void) +{ + if (mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx25_pads, + ARRAY_SIZE(eukrea_cpuimx25_pads))) + printk(KERN_ERR "error setting cpuimx25 pads !\n"); + + imx25_add_imx_uart0(&uart_pdata); + imx25_add_mxc_nand(&eukrea_cpuimx25_nand_board_info); + imx25_add_imxdi_rtc(NULL); + imx25_add_fec(&mx25_fec_pdata); + + i2c_register_board_info(0, eukrea_cpuimx25_i2c_devices, + ARRAY_SIZE(eukrea_cpuimx25_i2c_devices)); + imx25_add_imx_i2c0(&eukrea_cpuimx25_i2c0_data); + + if (otg_mode_host) + imx25_add_mxc_ehci_otg(&otg_pdata); + else + imx25_add_fsl_usb2_udc(&otg_device_pdata); + + imx25_add_mxc_ehci_hs(&usbh2_pdata); + +#ifdef CONFIG_MACH_EUKREA_MBIMXSD25_BASEBOARD + eukrea_mbimxsd25_baseboard_init(); +#endif +} + +static void __init eukrea_cpuimx25_timer_init(void) +{ + mx25_clocks_init(); +} + +static struct sys_timer eukrea_cpuimx25_timer = { + .init = eukrea_cpuimx25_timer_init, +}; + +MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25") + /* Maintainer: Eukrea Electromatique */ + .boot_params = MX25_PHYS_OFFSET + 0x100, + .map_io = mx25_map_io, + .init_early = imx25_init_early, + .init_irq = mx25_init_irq, + .timer = &eukrea_cpuimx25_timer, + .init_machine = eukrea_cpuimx25_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx27_visstrim_m10.c b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c new file mode 100644 index 00000000..7ae43b1e --- /dev/null +++ b/arch/arm/mach-imx/mach-imx27_visstrim_m10.c @@ -0,0 +1,269 @@ +/* + * mach-imx27_visstrim_m10.c + * + * Copyright 2010 Javier Martin <javier.martin@vista-silicon.com> + * + * Based on mach-pcm038.c, mach-pca100.c, mach-mx27ads.c and others. + * + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> +#include <linux/input.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/common.h> +#include <mach/iomux.h> + +#include "devices-imx27.h" + +#define OTG_PHY_CS_GPIO (GPIO_PORTF + 17) +#define SDHC1_IRQ IRQ_GPIOB(25) + +static const int visstrim_m10_pins[] __initconst = { + /* UART1 (console) */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* SSI1 */ + PC20_PF_SSI1_FS, + PC21_PF_SSI1_RXD, + PC22_PF_SSI1_TXD, + PC23_PF_SSI1_CLK, + /* SDHC1 */ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + /* Both I2Cs */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* USB OTG */ + OTG_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT, + PC9_PF_USBOTG_DATA0, + PC11_PF_USBOTG_DATA1, + PC10_PF_USBOTG_DATA2, + PC13_PF_USBOTG_DATA3, + PC12_PF_USBOTG_DATA4, + PC7_PF_USBOTG_DATA5, + PC8_PF_USBOTG_DATA6, + PE25_PF_USBOTG_DATA7, + PE24_PF_USBOTG_CLK, + PE2_PF_USBOTG_DIR, + PE0_PF_USBOTG_NXT, + PE1_PF_USBOTG_STP, + PB23_PF_USB_PWR, + PB24_PF_USB_OC, +}; + +/* GPIOs used as events for applications */ +static struct gpio_keys_button visstrim_gpio_keys[] = { + { + .type = EV_KEY, + .code = KEY_RESTART, + .gpio = (GPIO_PORTC + 15), + .desc = "Default config", + .active_low = 0, + .wakeup = 1, + }, + { + .type = EV_KEY, + .code = KEY_RECORD, + .gpio = (GPIO_PORTF + 14), + .desc = "Record", + .active_low = 0, + .wakeup = 1, + }, + { + .type = EV_KEY, + .code = KEY_STOP, + .gpio = (GPIO_PORTF + 13), + .desc = "Stop", + .active_low = 0, + .wakeup = 1, + } +}; + +static const struct gpio_keys_platform_data + visstrim_gpio_keys_platform_data __initconst = { + .buttons = visstrim_gpio_keys, + .nbuttons = ARRAY_SIZE(visstrim_gpio_keys), +}; + +/* Visstrim_SM10 has a microSD slot connected to sdhc1 */ +static int visstrim_m10_sdhc1_init(struct device *dev, + irq_handler_t detect_irq, void *data) +{ + int ret; + + ret = request_irq(SDHC1_IRQ, detect_irq, IRQF_TRIGGER_FALLING, + "mmc-detect", data); + return ret; +} + +static void visstrim_m10_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(SDHC1_IRQ, data); +} + +static const struct imxmmc_platform_data visstrim_m10_sdhc_pdata __initconst = { + .init = visstrim_m10_sdhc1_init, + .exit = visstrim_m10_sdhc1_exit, +}; + +/* Visstrim_SM10 NOR flash */ +static struct physmap_flash_data visstrim_m10_flash_data = { + .width = 2, +}; + +static struct resource visstrim_m10_flash_resource = { + .start = 0xc0000000, + .end = 0xc0000000 + SZ_64M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device visstrim_m10_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &visstrim_m10_flash_data, + }, + .num_resources = 1, + .resource = &visstrim_m10_flash_resource, +}; + +static struct platform_device *platform_devices[] __initdata = { + &visstrim_m10_nor_mtd_device, +}; + +/* Visstrim_M10 uses UART0 as console */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* I2C */ +static const struct imxi2c_platform_data visstrim_m10_i2c_data __initconst = { + .bitrate = 100000, +}; + +static struct pca953x_platform_data visstrim_m10_pca9555_pdata = { + .gpio_base = 240, /* After MX27 internal GPIOs */ + .invert = 0, +}; + +static struct i2c_board_info visstrim_m10_i2c_devices[] = { + { + I2C_BOARD_INFO("pca9555", 0x20), + .platform_data = &visstrim_m10_pca9555_pdata, + }, + { + I2C_BOARD_INFO("tlv320aic32x4", 0x18), + } +}; + +/* USB OTG */ +static int otg_phy_init(struct platform_device *pdev) +{ + gpio_set_value(OTG_PHY_CS_GPIO, 0); + + mdelay(10); + + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); +} + +static const struct mxc_usbh_platform_data +visstrim_m10_usbotg_pdata __initconst = { + .init = otg_phy_init, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +/* SSI */ +static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = { + .flags = IMX_SSI_DMA | IMX_SSI_SYN, +}; + +static void __init visstrim_m10_board_init(void) +{ + int ret; + + ret = mxc_gpio_setup_multiple_pins(visstrim_m10_pins, + ARRAY_SIZE(visstrim_m10_pins), "VISSTRIM_M10"); + if (ret) + pr_err("Failed to setup pins (%d)\n", ret); + + imx27_add_imx_ssi(0, &visstrim_m10_ssi_pdata); + imx27_add_imx_uart0(&uart_pdata); + + i2c_register_board_info(0, visstrim_m10_i2c_devices, + ARRAY_SIZE(visstrim_m10_i2c_devices)); + imx27_add_imx_i2c(0, &visstrim_m10_i2c_data); + imx27_add_imx_i2c(1, &visstrim_m10_i2c_data); + imx27_add_mxc_mmc(0, &visstrim_m10_sdhc_pdata); + imx27_add_mxc_ehci_otg(&visstrim_m10_usbotg_pdata); + imx27_add_fec(NULL); + imx_add_gpio_keys(&visstrim_gpio_keys_platform_data); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); +} + +static void __init visstrim_m10_timer_init(void) +{ + mx27_clocks_init((unsigned long)25000000); +} + +static struct sys_timer visstrim_m10_timer = { + .init = visstrim_m10_timer_init, +}; + +MACHINE_START(IMX27_VISSTRIM_M10, "Vista Silicon Visstrim_M10") + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &visstrim_m10_timer, + .init_machine = visstrim_m10_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx27ipcam.c b/arch/arm/mach-imx/mach-imx27ipcam.c new file mode 100644 index 00000000..9be6cd6f --- /dev/null +++ b/arch/arm/mach-imx/mach-imx27ipcam.c @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Author: Fabio Estevam <fabio.estevam@freescale.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx27.h> + +#include "devices-imx27.h" + +static const int mx27ipcam_pins[] __initconst = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, +}; + +static void __init mx27ipcam_init(void) +{ + mxc_gpio_setup_multiple_pins(mx27ipcam_pins, ARRAY_SIZE(mx27ipcam_pins), + "mx27ipcam"); + + imx27_add_imx_uart0(NULL); + imx27_add_fec(NULL); + imx27_add_imx2_wdt(NULL); +} + +static void __init mx27ipcam_timer_init(void) +{ + mx27_clocks_init(25000000); +} + +static struct sys_timer mx27ipcam_timer = { + .init = mx27ipcam_timer_init, +}; + +MACHINE_START(IMX27IPCAM, "Freescale IMX27IPCAM") + /* maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &mx27ipcam_timer, + .init_machine = mx27ipcam_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-imx27lite.c b/arch/arm/mach-imx/mach-imx27lite.c new file mode 100644 index 00000000..84114051 --- /dev/null +++ b/arch/arm/mach-imx/mach-imx27lite.c @@ -0,0 +1,84 @@ +/* + * Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * Copyright 2009 Daniel Schaeffer (daniel.schaeffer@timesys.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx27.h> + +#include "devices-imx27.h" + +static const int mx27lite_pins[] __initconst = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static void __init mx27lite_init(void) +{ + mxc_gpio_setup_multiple_pins(mx27lite_pins, ARRAY_SIZE(mx27lite_pins), + "imx27lite"); + imx27_add_imx_uart0(&uart_pdata); + imx27_add_fec(NULL); +} + +static void __init mx27lite_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer mx27lite_timer = { + .init = mx27lite_timer_init, +}; + +MACHINE_START(IMX27LITE, "LogicPD i.MX27LITE") + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &mx27lite_timer, + .init_machine = mx27lite_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-kzm_arm11_01.c b/arch/arm/mach-imx/mach-kzm_arm11_01.c new file mode 100644 index 00000000..1ecae20c --- /dev/null +++ b/arch/arm/mach-imx/mach-kzm_arm11_01.c @@ -0,0 +1,278 @@ +/* + * KZM-ARM11-01 support + * Copyright (C) 2009 Yoichi Yuasa <yuasa@linux-mips.org> + * + * based on code for MX31ADS, + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 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. + */ + +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_8250.h> +#include <linux/smsc911x.h> +#include <linux/types.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/memory.h> +#include <asm/setup.h> +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> +#include <asm/mach/time.h> + +#include <mach/clock.h> +#include <mach/common.h> +#include <mach/iomux-mx3.h> + +#include "devices-imx31.h" + +#define KZM_ARM11_IO_ADDRESS(x) (IOMEM( \ + IMX_IO_P2V_MODULE(x, MX31_CS4) ?: \ + IMX_IO_P2V_MODULE(x, MX31_CS5)) ?: \ + MX31_IO_ADDRESS(x)) + +/* + * KZM-ARM11-01 Board Control Registers on FPGA + */ +#define KZM_ARM11_CTL1 (MX31_CS4_BASE_ADDR + 0x1000) +#define KZM_ARM11_CTL2 (MX31_CS4_BASE_ADDR + 0x1001) +#define KZM_ARM11_RSW1 (MX31_CS4_BASE_ADDR + 0x1002) +#define KZM_ARM11_BACK_LIGHT (MX31_CS4_BASE_ADDR + 0x1004) +#define KZM_ARM11_FPGA_REV (MX31_CS4_BASE_ADDR + 0x1008) +#define KZM_ARM11_7SEG_LED (MX31_CS4_BASE_ADDR + 0x1010) +#define KZM_ARM11_LEDS (MX31_CS4_BASE_ADDR + 0x1020) +#define KZM_ARM11_DIPSW2 (MX31_CS4_BASE_ADDR + 0x1003) + +/* + * External UART for touch panel on FPGA + */ +#define KZM_ARM11_16550 (MX31_CS4_BASE_ADDR + 0x1050) + +#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE) +/* + * KZM-ARM11-01 has an external UART on FPGA + */ +static struct plat_serial8250_port serial_platform_data[] = { + { + .membase = KZM_ARM11_IO_ADDRESS(KZM_ARM11_16550), + .mapbase = KZM_ARM11_16550, + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), + .irqflags = IRQ_TYPE_EDGE_RISING, + .uartclk = 14745600, + .regshift = 0, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | + UPF_BUGGY_UART, + }, + {}, +}; + +static struct resource serial8250_resources[] = { + { + .start = KZM_ARM11_16550, + .end = KZM_ARM11_16550 + 0x10, + .flags = IORESOURCE_MEM, + }, + { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, + .num_resources = ARRAY_SIZE(serial8250_resources), + .resource = serial8250_resources, +}; + +static int __init kzm_init_ext_uart(void) +{ + u8 tmp; + + /* + * GPIO 1-1: external UART interrupt line + */ + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO)); + gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1), "ext-uart-int"); + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_1)); + + /* + * Unmask UART interrupt + */ + tmp = __raw_readb(KZM_ARM11_IO_ADDRESS(KZM_ARM11_CTL1)); + tmp |= 0x2; + __raw_writeb(tmp, KZM_ARM11_IO_ADDRESS(KZM_ARM11_CTL1)); + + return platform_device_register(&serial_device); +} +#else +static inline int kzm_init_ext_uart(void) +{ + return 0; +} +#endif + +/* + * SMSC LAN9118 + */ +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +static struct smsc911x_platform_config kzm_smsc9118_config = { + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, +}; + +static struct resource kzm_smsc9118_resources[] = { + { + .start = MX31_CS5_BASE_ADDR, + .end = MX31_CS5_BASE_ADDR + SZ_128K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO1_2), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO1_2), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, + }, +}; + +static struct platform_device kzm_smsc9118_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(kzm_smsc9118_resources), + .resource = kzm_smsc9118_resources, + .dev = { + .platform_data = &kzm_smsc9118_config, + }, +}; + +static int __init kzm_init_smsc9118(void) +{ + /* + * GPIO 1-2: SMSC9118 interrupt line + */ + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_GPIO1_2, IOMUX_CONFIG_GPIO)); + gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_2), "smsc9118-int"); + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_2)); + + return platform_device_register(&kzm_smsc9118_device); +} +#else +static inline int kzm_init_smsc9118(void) +{ + return 0; +} +#endif + +#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE) +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static void __init kzm_init_imx_uart(void) +{ + imx31_add_imx_uart0(&uart_pdata); + imx31_add_imx_uart1(&uart_pdata); +} +#else +static inline void kzm_init_imx_uart(void) +{ +} +#endif + +static int kzm_pins[] __initdata = { + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + MX31_PIN_DCD_DCE1__DCD_DCE1, + MX31_PIN_RI_DCE1__RI_DCE1, + MX31_PIN_DSR_DCE1__DSR_DCE1, + MX31_PIN_DTR_DCE1__DTR_DCE1, + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + MX31_PIN_DCD_DTE1__DCD_DTE2, + MX31_PIN_RI_DTE1__RI_DTE2, + MX31_PIN_DSR_DTE1__DSR_DTE2, + MX31_PIN_DTR_DTE1__DTR_DTE2, +}; + +/* + * Board specific initialization. + */ +static void __init kzm_board_init(void) +{ + mxc_iomux_setup_multiple_pins(kzm_pins, + ARRAY_SIZE(kzm_pins), "kzm"); + kzm_init_ext_uart(); + kzm_init_smsc9118(); + kzm_init_imx_uart(); + + pr_info("Clock input source is 26MHz\n"); +} + +/* + * This structure defines static mappings for the kzm-arm11-01 board. + */ +static struct map_desc kzm_io_desc[] __initdata = { + { + .virtual = MX31_CS4_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(MX31_CS4_BASE_ADDR), + .length = MX31_CS4_SIZE, + .type = MT_DEVICE + }, + { + .virtual = MX31_CS5_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(MX31_CS5_BASE_ADDR), + .length = MX31_CS5_SIZE, + .type = MT_DEVICE + }, +}; + +/* + * Set up static virtual mappings. + */ +static void __init kzm_map_io(void) +{ + mx31_map_io(); + iotable_init(kzm_io_desc, ARRAY_SIZE(kzm_io_desc)); +} + +static void __init kzm_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer kzm_timer = { + .init = kzm_timer_init, +}; + +MACHINE_START(KZM_ARM11_01, "Kyoto Microcomputer Co., Ltd. KZM-ARM11-01") + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = kzm_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &kzm_timer, + .init_machine = kzm_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx1ads.c b/arch/arm/mach-imx/mach-mx1ads.c new file mode 100644 index 00000000..38ec5cbb --- /dev/null +++ b/arch/arm/mach-imx/mach-mx1ads.c @@ -0,0 +1,161 @@ +/* + * arch/arm/mach-imx/mach-mx1ads.c + * + * Initially based on: + * linux-2.6.7-imx/arch/arm/mach-imx/scb9328.c + * Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de> + * + * 2004 (c) MontaVista Software, Inc. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/i2c.h> +#include <linux/i2c/pcf857x.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx1.h> +#include <mach/irqs.h> + +#include "devices-imx1.h" + +static const int mx1ads_pins[] __initconst = { + /* UART1 */ + PC9_PF_UART1_CTS, + PC10_PF_UART1_RTS, + PC11_PF_UART1_TXD, + PC12_PF_UART1_RXD, + /* UART2 */ + PB28_PF_UART2_CTS, + PB29_PF_UART2_RTS, + PB30_PF_UART2_TXD, + PB31_PF_UART2_RXD, + /* I2C */ + PA15_PF_I2C_SDA, + PA16_PF_I2C_SCL, + /* SPI */ + PC13_PF_SPI1_SPI_RDY, + PC14_PF_SPI1_SCLK, + PC15_PF_SPI1_SS, + PC16_PF_SPI1_MISO, + PC17_PF_SPI1_MOSI, +}; + +/* + * UARTs platform data + */ + +static const struct imxuart_platform_data uart0_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxuart_platform_data uart1_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* + * Physmap flash + */ + +static struct physmap_flash_data mx1ads_flash_data = { + .width = 4, /* bankwidth in bytes */ +}; + +static struct resource flash_resource = { + .start = MX1_CS0_PHYS, + .end = MX1_CS0_PHYS + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device flash_device = { + .name = "physmap-flash", + .id = 0, + .resource = &flash_resource, + .num_resources = 1, +}; + +/* + * I2C + */ +static struct pcf857x_platform_data pcf857x_data[] = { + { + .gpio_base = 4 * 32, + }, { + .gpio_base = 4 * 32 + 16, + } +}; + +static const struct imxi2c_platform_data mx1ads_i2c_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info mx1ads_i2c_devices[] = { + { + I2C_BOARD_INFO("pcf8575", 0x22), + .platform_data = &pcf857x_data[0], + }, { + I2C_BOARD_INFO("pcf8575", 0x24), + .platform_data = &pcf857x_data[1], + }, +}; + +/* + * Board init + */ +static void __init mx1ads_init(void) +{ + mxc_gpio_setup_multiple_pins(mx1ads_pins, + ARRAY_SIZE(mx1ads_pins), "mx1ads"); + + /* UART */ + imx1_add_imx_uart0(&uart0_pdata); + imx1_add_imx_uart1(&uart1_pdata); + + /* Physmap flash */ + mxc_register_device(&flash_device, &mx1ads_flash_data); + + /* I2C */ + i2c_register_board_info(0, mx1ads_i2c_devices, + ARRAY_SIZE(mx1ads_i2c_devices)); + + imx1_add_imx_i2c(&mx1ads_i2c_data); +} + +static void __init mx1ads_timer_init(void) +{ + mx1_clocks_init(32000); +} + +struct sys_timer mx1ads_timer = { + .init = mx1ads_timer_init, +}; + +MACHINE_START(MX1ADS, "Freescale MX1ADS") + /* Maintainer: Sascha Hauer, Pengutronix */ + .boot_params = MX1_PHYS_OFFSET + 0x100, + .map_io = mx1_map_io, + .init_early = imx1_init_early, + .init_irq = mx1_init_irq, + .timer = &mx1ads_timer, + .init_machine = mx1ads_init, +MACHINE_END + +MACHINE_START(MXLADS, "Freescale MXLADS") + .boot_params = MX1_PHYS_OFFSET + 0x100, + .map_io = mx1_map_io, + .init_early = imx1_init_early, + .init_irq = mx1_init_irq, + .timer = &mx1ads_timer, + .init_machine = mx1ads_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx21ads.c b/arch/arm/mach-imx/mach-mx21ads.c new file mode 100644 index 00000000..a37fe021 --- /dev/null +++ b/arch/arm/mach-imx/mach-mx21ads.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2006-2007 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. + */ + +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/physmap.h> +#include <linux/gpio.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <mach/iomux-mx21.h> + +#include "devices-imx21.h" + +/* + * Memory-mapped I/O on MX21ADS base board + */ +#define MX21ADS_MMIO_BASE_ADDR 0xf5000000 +#define MX21ADS_MMIO_SIZE 0xc00000 + +#define MX21ADS_REG_ADDR(offset) (void __force __iomem *) \ + (MX21ADS_MMIO_BASE_ADDR + (offset)) + +#define MX21ADS_CS8900A_IRQ IRQ_GPIOE(11) +#define MX21ADS_CS8900A_IOBASE_REG MX21ADS_REG_ADDR(0x000000) +#define MX21ADS_ST16C255_IOBASE_REG MX21ADS_REG_ADDR(0x200000) +#define MX21ADS_VERSION_REG MX21ADS_REG_ADDR(0x400000) +#define MX21ADS_IO_REG MX21ADS_REG_ADDR(0x800000) + +/* MX21ADS_IO_REG bit definitions */ +#define MX21ADS_IO_SD_WP 0x0001 /* read */ +#define MX21ADS_IO_TP6 0x0001 /* write */ +#define MX21ADS_IO_SW_SEL 0x0002 /* read */ +#define MX21ADS_IO_TP7 0x0002 /* write */ +#define MX21ADS_IO_RESET_E_UART 0x0004 +#define MX21ADS_IO_RESET_BASE 0x0008 +#define MX21ADS_IO_CSI_CTL2 0x0010 +#define MX21ADS_IO_CSI_CTL1 0x0020 +#define MX21ADS_IO_CSI_CTL0 0x0040 +#define MX21ADS_IO_UART1_EN 0x0080 +#define MX21ADS_IO_UART4_EN 0x0100 +#define MX21ADS_IO_LCDON 0x0200 +#define MX21ADS_IO_IRDA_EN 0x0400 +#define MX21ADS_IO_IRDA_FIR_SEL 0x0800 +#define MX21ADS_IO_IRDA_MD0_B 0x1000 +#define MX21ADS_IO_IRDA_MD1 0x2000 +#define MX21ADS_IO_LED4_ON 0x4000 +#define MX21ADS_IO_LED3_ON 0x8000 + +static const int mx21ads_pins[] __initconst = { + + /* CS8900A */ + (GPIO_PORTE | GPIO_GPIO | GPIO_IN | 11), + + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + + /* UART3 (IrDA) - only TXD and RXD */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + + /* UART4 */ + PB26_AF_UART4_RTS, + PB28_AF_UART4_TXD, + PB29_AF_UART4_CTS, + PB31_AF_UART4_RXD, + + /* LCDC */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA24_PF_REV, /* Sharp panel dedicated signal */ + PA25_PF_CLS, /* Sharp panel dedicated signal */ + PA26_PF_PS, /* Sharp panel dedicated signal */ + PA27_PF_SPL_SPR, /* Sharp panel dedicated signal */ + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + + /* MMC/SDHC */ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + + /* NFC */ + PF0_PF_NRFB, + PF1_PF_NFCE, + PF2_PF_NFWP, + PF3_PF_NFCLE, + PF4_PF_NFALE, + PF5_PF_NFRE, + PF6_PF_NFWE, + PF7_PF_NFIO0, + PF8_PF_NFIO1, + PF9_PF_NFIO2, + PF10_PF_NFIO3, + PF11_PF_NFIO4, + PF12_PF_NFIO5, + PF13_PF_NFIO6, + PF14_PF_NFIO7, +}; + +/* ADS's NOR flash: 2x AM29BDS128HE9VKI on 32-bit bus */ +static struct physmap_flash_data mx21ads_flash_data = { + .width = 4, +}; + +static struct resource mx21ads_flash_resource = { + .start = MX21_CS0_BASE_ADDR, + .end = MX21_CS0_BASE_ADDR + 0x02000000 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device mx21ads_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &mx21ads_flash_data, + }, + .num_resources = 1, + .resource = &mx21ads_flash_resource, +}; + +static const struct imxuart_platform_data uart_pdata_rts __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxuart_platform_data uart_pdata_norts __initconst = { +}; + +static int mx21ads_fb_init(struct platform_device *pdev) +{ + u16 tmp; + + tmp = __raw_readw(MX21ADS_IO_REG); + tmp |= MX21ADS_IO_LCDON; + __raw_writew(tmp, MX21ADS_IO_REG); + return 0; +} + +static void mx21ads_fb_exit(struct platform_device *pdev) +{ + u16 tmp; + + tmp = __raw_readw(MX21ADS_IO_REG); + tmp &= ~MX21ADS_IO_LCDON; + __raw_writew(tmp, MX21ADS_IO_REG); +} + +/* + * Connected is a portrait Sharp-QVGA display + * of type: LQ035Q7DB02 + */ +static struct imx_fb_videomode mx21ads_modes[] = { + { + .mode = { + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 188679, /* in ps (5.3MHz) */ + .hsync_len = 2, + .left_margin = 6, + .right_margin = 16, + .vsync_len = 1, + .upper_margin = 8, + .lower_margin = 10, + }, + .pcr = 0xfb108bc7, + .bpp = 16, + }, +}; + +static const struct imx_fb_platform_data mx21ads_fb_data __initconst = { + .mode = mx21ads_modes, + .num_modes = ARRAY_SIZE(mx21ads_modes), + + .pwmr = 0x00a903ff, + .lscr1 = 0x00120300, + .dmacr = 0x00020008, + + .init = mx21ads_fb_init, + .exit = mx21ads_fb_exit, +}; + +static int mx21ads_sdhc_get_ro(struct device *dev) +{ + return (__raw_readw(MX21ADS_IO_REG) & MX21ADS_IO_SD_WP) ? 1 : 0; +} + +static int mx21ads_sdhc_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + return request_irq(IRQ_GPIOD(25), detect_irq, + IRQF_TRIGGER_FALLING, "mmc-detect", data); +} + +static void mx21ads_sdhc_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOD(25), data); +} + +static const struct imxmmc_platform_data mx21ads_sdhc_pdata __initconst = { + .ocr_avail = MMC_VDD_29_30 | MMC_VDD_30_31, /* 3.0V */ + .get_ro = mx21ads_sdhc_get_ro, + .init = mx21ads_sdhc_init, + .exit = mx21ads_sdhc_exit, +}; + +static const struct mxc_nand_platform_data +mx21ads_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static struct map_desc mx21ads_io_desc[] __initdata = { + /* + * Memory-mapped I/O on MX21ADS Base board: + * - CS8900A Ethernet controller + * - ST16C2552CJ UART + * - CPU and Base board version + * - Base board I/O register + */ + { + .virtual = MX21ADS_MMIO_BASE_ADDR, + .pfn = __phys_to_pfn(MX21_CS1_BASE_ADDR), + .length = MX21ADS_MMIO_SIZE, + .type = MT_DEVICE, + }, +}; + +static void __init mx21ads_map_io(void) +{ + mx21_map_io(); + iotable_init(mx21ads_io_desc, ARRAY_SIZE(mx21ads_io_desc)); +} + +static struct platform_device *platform_devices[] __initdata = { + &mx21ads_nor_mtd_device, +}; + +static void __init mx21ads_board_init(void) +{ + mxc_gpio_setup_multiple_pins(mx21ads_pins, ARRAY_SIZE(mx21ads_pins), + "mx21ads"); + + imx21_add_imx_uart0(&uart_pdata_rts); + imx21_add_imx_uart2(&uart_pdata_norts); + imx21_add_imx_uart3(&uart_pdata_rts); + imx21_add_imx_fb(&mx21ads_fb_data); + imx21_add_mxc_mmc(0, &mx21ads_sdhc_pdata); + imx21_add_mxc_nand(&mx21ads_nand_board_info); + + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); +} + +static void __init mx21ads_timer_init(void) +{ + mx21_clocks_init(32768, 26000000); +} + +static struct sys_timer mx21ads_timer = { + .init = mx21ads_timer_init, +}; + +MACHINE_START(MX21ADS, "Freescale i.MX21ADS") + /* maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX21_PHYS_OFFSET + 0x100, + .map_io = mx21ads_map_io, + .init_early = imx21_init_early, + .init_irq = mx21_init_irq, + .timer = &mx21ads_timer, + .init_machine = mx21ads_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx25_3ds.c b/arch/arm/mach-imx/mach-mx25_3ds.c new file mode 100644 index 00000000..58ea3fdf --- /dev/null +++ b/arch/arm/mach-imx/mach-mx25_3ds.c @@ -0,0 +1,258 @@ +/* + * Copyright 2009 Sascha Hauer, <kernel@pengutronix.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* + * This machine is known as: + * - i.MX25 3-Stack Development System + * - i.MX25 Platform Development Kit (i.MX25 PDK) + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/usb/otg.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/memory.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <mach/mx25.h> +#include <mach/iomux-mx25.h> + +#include "devices-imx25.h" + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static iomux_v3_cfg_t mx25pdk_pads[] = { + MX25_PAD_FEC_MDC__FEC_MDC, + MX25_PAD_FEC_MDIO__FEC_MDIO, + MX25_PAD_FEC_TDATA0__FEC_TDATA0, + MX25_PAD_FEC_TDATA1__FEC_TDATA1, + MX25_PAD_FEC_TX_EN__FEC_TX_EN, + MX25_PAD_FEC_RDATA0__FEC_RDATA0, + MX25_PAD_FEC_RDATA1__FEC_RDATA1, + MX25_PAD_FEC_RX_DV__FEC_RX_DV, + MX25_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX25_PAD_A17__GPIO_2_3, /* FEC_EN, GPIO 35 */ + MX25_PAD_D12__GPIO_4_8, /* FEC_RESET_B, GPIO 104 */ + + /* LCD */ + MX25_PAD_LD0__LD0, + MX25_PAD_LD1__LD1, + MX25_PAD_LD2__LD2, + MX25_PAD_LD3__LD3, + MX25_PAD_LD4__LD4, + MX25_PAD_LD5__LD5, + MX25_PAD_LD6__LD6, + MX25_PAD_LD7__LD7, + MX25_PAD_LD8__LD8, + MX25_PAD_LD9__LD9, + MX25_PAD_LD10__LD10, + MX25_PAD_LD11__LD11, + MX25_PAD_LD12__LD12, + MX25_PAD_LD13__LD13, + MX25_PAD_LD14__LD14, + MX25_PAD_LD15__LD15, + MX25_PAD_GPIO_E__LD16, + MX25_PAD_GPIO_F__LD17, + MX25_PAD_HSYNC__HSYNC, + MX25_PAD_VSYNC__VSYNC, + MX25_PAD_LSCLK__LSCLK, + MX25_PAD_OE_ACD__OE_ACD, + MX25_PAD_CONTRAST__CONTRAST, + + /* Keypad */ + MX25_PAD_KPP_ROW0__KPP_ROW0, + MX25_PAD_KPP_ROW1__KPP_ROW1, + MX25_PAD_KPP_ROW2__KPP_ROW2, + MX25_PAD_KPP_ROW3__KPP_ROW3, + MX25_PAD_KPP_COL0__KPP_COL0, + MX25_PAD_KPP_COL1__KPP_COL1, + MX25_PAD_KPP_COL2__KPP_COL2, + MX25_PAD_KPP_COL3__KPP_COL3, + + /* SD1 */ + MX25_PAD_SD1_CMD__SD1_CMD, + MX25_PAD_SD1_CLK__SD1_CLK, + MX25_PAD_SD1_DATA0__SD1_DATA0, + MX25_PAD_SD1_DATA1__SD1_DATA1, + MX25_PAD_SD1_DATA2__SD1_DATA2, + MX25_PAD_SD1_DATA3__SD1_DATA3, + MX25_PAD_A14__GPIO_2_0, /* WriteProtect */ + MX25_PAD_A15__GPIO_2_1, /* CardDetect */ + + /* I2C1 */ + MX25_PAD_I2C1_CLK__I2C1_CLK, + MX25_PAD_I2C1_DAT__I2C1_DAT, +}; + +static const struct fec_platform_data mx25_fec_pdata __initconst = { + .phy = PHY_INTERFACE_MODE_RMII, +}; + +#define FEC_ENABLE_GPIO IMX_GPIO_NR(2, 3) +#define FEC_RESET_B_GPIO IMX_GPIO_NR(4, 8) + +static void __init mx25pdk_fec_reset(void) +{ + gpio_request(FEC_ENABLE_GPIO, "FEC PHY enable"); + gpio_request(FEC_RESET_B_GPIO, "FEC PHY reset"); + + gpio_direction_output(FEC_ENABLE_GPIO, 0); /* drop PHY power */ + gpio_direction_output(FEC_RESET_B_GPIO, 0); /* assert reset */ + udelay(2); + + /* turn on PHY power and lift reset */ + gpio_set_value(FEC_ENABLE_GPIO, 1); + gpio_set_value(FEC_RESET_B_GPIO, 1); +} + +static const struct mxc_nand_platform_data +mx25pdk_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct imx_fb_videomode mx25pdk_modes[] = { + { + .mode = { + .name = "CRT-VGA", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39683, + .left_margin = 45, + .right_margin = 114, + .upper_margin = 33, + .lower_margin = 11, + .hsync_len = 1, + .vsync_len = 1, + }, + .bpp = 16, + .pcr = 0xFA208B80, + }, +}; + +static const struct imx_fb_platform_data mx25pdk_fb_pdata __initconst = { + .mode = mx25pdk_modes, + .num_modes = ARRAY_SIZE(mx25pdk_modes), + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, +}; + +static const uint32_t mx25pdk_keymap[] = { + KEY(0, 0, KEY_UP), + KEY(0, 1, KEY_DOWN), + KEY(0, 2, KEY_VOLUMEDOWN), + KEY(0, 3, KEY_HOME), + KEY(1, 0, KEY_RIGHT), + KEY(1, 1, KEY_LEFT), + KEY(1, 2, KEY_ENTER), + KEY(1, 3, KEY_VOLUMEUP), + KEY(2, 0, KEY_F6), + KEY(2, 1, KEY_F8), + KEY(2, 2, KEY_F9), + KEY(2, 3, KEY_F10), + KEY(3, 0, KEY_F1), + KEY(3, 1, KEY_F2), + KEY(3, 2, KEY_F3), + KEY(3, 3, KEY_POWER), +}; + +static const struct matrix_keymap_data mx25pdk_keymap_data __initconst = { + .keymap = mx25pdk_keymap, + .keymap_size = ARRAY_SIZE(mx25pdk_keymap), +}; + +static int mx25pdk_usbh2_init(struct platform_device *pdev) +{ + return mx25_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY); +} + +static const struct mxc_usbh_platform_data usbh2_pdata __initconst = { + .init = mx25pdk_usbh2_init, + .portsc = MXC_EHCI_MODE_SERIAL, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI, +}; + +static const struct imxi2c_platform_data mx25_3ds_i2c0_data __initconst = { + .bitrate = 100000, +}; + +#define SD1_GPIO_WP IMX_GPIO_NR(2, 0) +#define SD1_GPIO_CD IMX_GPIO_NR(2, 1) + +static const struct esdhc_platform_data mx25pdk_esdhc_pdata __initconst = { + .wp_gpio = SD1_GPIO_WP, + .cd_gpio = SD1_GPIO_CD, +}; + +static void __init mx25pdk_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads, + ARRAY_SIZE(mx25pdk_pads)); + + imx25_add_imx_uart0(&uart_pdata); + imx25_add_fsl_usb2_udc(&otg_device_pdata); + imx25_add_mxc_ehci_hs(&usbh2_pdata); + imx25_add_mxc_nand(&mx25pdk_nand_board_info); + imx25_add_imxdi_rtc(NULL); + imx25_add_imx_fb(&mx25pdk_fb_pdata); + imx25_add_imx2_wdt(NULL); + + mx25pdk_fec_reset(); + imx25_add_fec(&mx25_fec_pdata); + imx25_add_imx_keypad(&mx25pdk_keymap_data); + + imx25_add_sdhci_esdhc_imx(0, &mx25pdk_esdhc_pdata); + imx25_add_imx_i2c0(&mx25_3ds_i2c0_data); +} + +static void __init mx25pdk_timer_init(void) +{ + mx25_clocks_init(); +} + +static struct sys_timer mx25pdk_timer = { + .init = mx25pdk_timer_init, +}; + +MACHINE_START(MX25_3DS, "Freescale MX25PDK (3DS)") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX25_PHYS_OFFSET + 0x100, + .map_io = mx25_map_io, + .init_early = imx25_init_early, + .init_irq = mx25_init_irq, + .timer = &mx25pdk_timer, + .init_machine = mx25pdk_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx27_3ds.c b/arch/arm/mach-imx/mach-mx27_3ds.c new file mode 100644 index 00000000..6e1accf9 --- /dev/null +++ b/arch/arm/mach-imx/mach-mx27_3ds.c @@ -0,0 +1,317 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + * Author: Fabio Estevam <fabio.estevam@freescale.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * This machine is known as: + * - i.MX27 3-Stack Development System + * - i.MX27 Platform Development Kit (i.MX27 PDK) + */ + +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/delay.h> +#include <linux/mfd/mc13783.h> +#include <linux/spi/spi.h> +#include <linux/regulator/machine.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx27.h> +#include <mach/ulpi.h> +#include <mach/irqs.h> +#include <mach/3ds_debugboard.h> + +#include "devices-imx27.h" + +#define SD1_EN_GPIO (GPIO_PORTB + 25) +#define OTG_PHY_RESET_GPIO (GPIO_PORTB + 23) +#define SPI2_SS0 (GPIO_PORTD + 21) +#define EXPIO_PARENT_INT (MXC_INTERNAL_IRQS + GPIO_PORTC + 28) + +static const int mx27pdk_pins[] __initconst = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* SDHC1 */ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + SD1_EN_GPIO | GPIO_GPIO | GPIO_OUT, + /* OTG */ + OTG_PHY_RESET_GPIO | GPIO_GPIO | GPIO_OUT, + PC7_PF_USBOTG_DATA5, + PC8_PF_USBOTG_DATA6, + PC9_PF_USBOTG_DATA0, + PC10_PF_USBOTG_DATA2, + PC11_PF_USBOTG_DATA1, + PC12_PF_USBOTG_DATA4, + PC13_PF_USBOTG_DATA3, + PE0_PF_USBOTG_NXT, + PE1_PF_USBOTG_STP, + PE2_PF_USBOTG_DIR, + PE24_PF_USBOTG_CLK, + PE25_PF_USBOTG_DATA7, + /* CSPI2 */ + PD22_PF_CSPI2_SCLK, + PD23_PF_CSPI2_MISO, + PD24_PF_CSPI2_MOSI, + /* I2C1 */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* + * Matrix keyboard + */ + +static const uint32_t mx27_3ds_keymap[] = { + KEY(0, 0, KEY_UP), + KEY(0, 1, KEY_DOWN), + KEY(1, 0, KEY_RIGHT), + KEY(1, 1, KEY_LEFT), + KEY(1, 2, KEY_ENTER), + KEY(2, 0, KEY_F6), + KEY(2, 1, KEY_F8), + KEY(2, 2, KEY_F9), + KEY(2, 3, KEY_F10), +}; + +static const struct matrix_keymap_data mx27_3ds_keymap_data __initconst = { + .keymap = mx27_3ds_keymap, + .keymap_size = ARRAY_SIZE(mx27_3ds_keymap), +}; + +static int mx27_3ds_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + return request_irq(IRQ_GPIOB(26), detect_irq, IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, "sdhc1-card-detect", data); +} + +static void mx27_3ds_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOB(26), data); +} + +static const struct imxmmc_platform_data sdhc1_pdata __initconst = { + .init = mx27_3ds_sdhc1_init, + .exit = mx27_3ds_sdhc1_exit, +}; + +static void mx27_3ds_sdhc1_enable_level_translator(void) +{ + /* Turn on TXB0108 OE pin */ + gpio_request(SD1_EN_GPIO, "sd1_enable"); + gpio_direction_output(SD1_EN_GPIO, 1); +} + + +static int otg_phy_init(void) +{ + gpio_request(OTG_PHY_RESET_GPIO, "usb-otg-reset"); + gpio_direction_output(OTG_PHY_RESET_GPIO, 0); + mdelay(1); + gpio_set_value(OTG_PHY_RESET_GPIO, 1); + return 0; +} + +static int mx27_3ds_otg_init(struct platform_device *pdev) +{ + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = mx27_3ds_otg_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +static int otg_mode_host; + +static int __init mx27_3ds_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", mx27_3ds_otg_mode); + +/* Regulators */ +static struct regulator_consumer_supply vmmc1_consumers[] = { + REGULATOR_SUPPLY("lcd_2v8", NULL), +}; + +static struct regulator_init_data vmmc1_init = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(vmmc1_consumers), + .consumer_supplies = vmmc1_consumers, +}; + +static struct regulator_consumer_supply vgen_consumers[] = { + REGULATOR_SUPPLY("vdd_lcdio", NULL), +}; + +static struct regulator_init_data vgen_init = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen_consumers), + .consumer_supplies = vgen_consumers, +}; + +static struct mc13xxx_regulator_init_data mx27_3ds_regulators[] = { + { + .id = MC13783_REG_VMMC1, + .init_data = &vmmc1_init, + }, { + .id = MC13783_REG_VGEN, + .init_data = &vgen_init, + }, +}; + +/* MC13783 */ +static struct mc13xxx_platform_data mc13783_pdata = { + .regulators = { + .regulators = mx27_3ds_regulators, + .num_regulators = ARRAY_SIZE(mx27_3ds_regulators), + + }, + .flags = MC13783_USE_REGULATOR, +}; + +/* SPI */ +static int spi2_internal_chipselect[] = {SPI2_SS0}; + +static const struct spi_imx_master spi2_pdata __initconst = { + .chipselect = spi2_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi2_internal_chipselect), +}; + +static struct spi_board_info mx27_3ds_spi_devs[] __initdata = { + { + .modalias = "mc13783", + .max_speed_hz = 1000000, + .bus_num = 1, + .chip_select = 0, /* SS0 */ + .platform_data = &mc13783_pdata, + .irq = IRQ_GPIOC(14), + .mode = SPI_CS_HIGH, + }, +}; + +static const struct imxi2c_platform_data mx27_3ds_i2c0_data __initconst = { + .bitrate = 100000, +}; + +static void __init mx27pdk_init(void) +{ + mxc_gpio_setup_multiple_pins(mx27pdk_pins, ARRAY_SIZE(mx27pdk_pins), + "mx27pdk"); + mx27_3ds_sdhc1_enable_level_translator(); + imx27_add_imx_uart0(&uart_pdata); + imx27_add_fec(NULL); + imx27_add_imx_keypad(&mx27_3ds_keymap_data); + imx27_add_mxc_mmc(0, &sdhc1_pdata); + imx27_add_imx2_wdt(NULL); + otg_phy_init(); + + if (otg_mode_host) { + otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + + if (otg_pdata.otg) + imx27_add_mxc_ehci_otg(&otg_pdata); + } + + if (!otg_mode_host) + imx27_add_fsl_usb2_udc(&otg_device_pdata); + + imx27_add_spi_imx1(&spi2_pdata); + spi_register_board_info(mx27_3ds_spi_devs, + ARRAY_SIZE(mx27_3ds_spi_devs)); + + if (mxc_expio_init(MX27_CS5_BASE_ADDR, EXPIO_PARENT_INT)) + pr_warn("Init of the debugboard failed, all devices on the debugboard are unusable.\n"); + imx27_add_imx_i2c(0, &mx27_3ds_i2c0_data); +} + +static void __init mx27pdk_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer mx27pdk_timer = { + .init = mx27pdk_timer_init, +}; + +MACHINE_START(MX27_3DS, "Freescale MX27PDK") + /* maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &mx27pdk_timer, + .init_machine = mx27pdk_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx27ads.c b/arch/arm/mach-imx/mach-mx27ads.c new file mode 100644 index 00000000..1db79506 --- /dev/null +++ b/arch/arm/mach-imx/mach-mx27ads.c @@ -0,0 +1,352 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2006-2007 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. + */ + +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <mach/gpio.h> +#include <mach/iomux-mx27.h> + +#include "devices-imx27.h" + +/* + * Base address of PBC controller, CS4 + */ +#define PBC_BASE_ADDRESS 0xf4300000 +#define PBC_REG_ADDR(offset) (void __force __iomem *) \ + (PBC_BASE_ADDRESS + (offset)) + +/* When the PBC address connection is fixed in h/w, defined as 1 */ +#define PBC_ADDR_SH 0 + +/* Offsets for the PBC Controller register */ +/* + * PBC Board version register offset + */ +#define PBC_VERSION_REG PBC_REG_ADDR(0x00000 >> PBC_ADDR_SH) +/* + * PBC Board control register 1 set address. + */ +#define PBC_BCTRL1_SET_REG PBC_REG_ADDR(0x00008 >> PBC_ADDR_SH) +/* + * PBC Board control register 1 clear address. + */ +#define PBC_BCTRL1_CLEAR_REG PBC_REG_ADDR(0x0000C >> PBC_ADDR_SH) + +/* PBC Board Control Register 1 bit definitions */ +#define PBC_BCTRL1_LCDON 0x0800 /* Enable the LCD */ + +/* to determine the correct external crystal reference */ +#define CKIH_27MHZ_BIT_SET (1 << 3) + +static const int mx27ads_pins[] __initconst = { + /* UART0 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* UART1 */ + PE3_PF_UART2_CTS, + PE4_PF_UART2_RTS, + PE6_PF_UART2_TXD, + PE7_PF_UART2_RXD, + /* UART2 */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + PE10_PF_UART3_CTS, + PE11_PF_UART3_RTS, + /* UART3 */ + PB26_AF_UART4_RTS, + PB28_AF_UART4_TXD, + PB29_AF_UART4_CTS, + PB31_AF_UART4_RXD, + /* UART4 */ + PB18_AF_UART5_TXD, + PB19_AF_UART5_RXD, + PB20_AF_UART5_CTS, + PB21_AF_UART5_RTS, + /* UART5 */ + PB10_AF_UART6_TXD, + PB12_AF_UART6_CTS, + PB11_AF_UART6_RXD, + PB13_AF_UART6_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* I2C2 */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* FB */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA24_PF_REV, + PA25_PF_CLS, + PA26_PF_PS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* OWIRE */ + PE16_AF_OWIRE, + /* SDHC1*/ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + /* SDHC2*/ + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, +}; + +static const struct mxc_nand_platform_data +mx27ads_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +/* ADS's NOR flash */ +static struct physmap_flash_data mx27ads_flash_data = { + .width = 2, +}; + +static struct resource mx27ads_flash_resource = { + .start = 0xc0000000, + .end = 0xc0000000 + 0x02000000 - 1, + .flags = IORESOURCE_MEM, + +}; + +static struct platform_device mx27ads_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &mx27ads_flash_data, + }, + .num_resources = 1, + .resource = &mx27ads_flash_resource, +}; + +static const struct imxi2c_platform_data mx27ads_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info mx27ads_i2c_devices[] = { +}; + +void lcd_power(int on) +{ + if (on) + __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_SET_REG); + else + __raw_writew(PBC_BCTRL1_LCDON, PBC_BCTRL1_CLEAR_REG); +} + +static struct imx_fb_videomode mx27ads_modes[] = { + { + .mode = { + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 188679, /* in ps (5.3MHz) */ + .hsync_len = 1, + .left_margin = 9, + .right_margin = 16, + .vsync_len = 1, + .upper_margin = 7, + .lower_margin = 9, + }, + .bpp = 16, + .pcr = 0xFB008BC0, + }, +}; + +static const struct imx_fb_platform_data mx27ads_fb_data __initconst = { + .mode = mx27ads_modes, + .num_modes = ARRAY_SIZE(mx27ads_modes), + + /* + * - HSYNC active high + * - VSYNC active high + * - clk notenabled while idle + * - clock inverted + * - data not inverted + * - data enable low active + * - enable sharp mode + */ + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, + + .lcd_power = lcd_power, +}; + +static int mx27ads_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + return request_irq(IRQ_GPIOE(21), detect_irq, IRQF_TRIGGER_RISING, + "sdhc1-card-detect", data); +} + +static int mx27ads_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + return request_irq(IRQ_GPIOB(7), detect_irq, IRQF_TRIGGER_RISING, + "sdhc2-card-detect", data); +} + +static void mx27ads_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOE(21), data); +} + +static void mx27ads_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOB(7), data); +} + +static const struct imxmmc_platform_data sdhc1_pdata __initconst = { + .init = mx27ads_sdhc1_init, + .exit = mx27ads_sdhc1_exit, +}; + +static const struct imxmmc_platform_data sdhc2_pdata __initconst = { + .init = mx27ads_sdhc2_init, + .exit = mx27ads_sdhc2_exit, +}; + +static struct platform_device *platform_devices[] __initdata = { + &mx27ads_nor_mtd_device, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static void __init mx27ads_board_init(void) +{ + mxc_gpio_setup_multiple_pins(mx27ads_pins, ARRAY_SIZE(mx27ads_pins), + "mx27ads"); + + imx27_add_imx_uart0(&uart_pdata); + imx27_add_imx_uart1(&uart_pdata); + imx27_add_imx_uart2(&uart_pdata); + imx27_add_imx_uart3(&uart_pdata); + imx27_add_imx_uart4(&uart_pdata); + imx27_add_imx_uart5(&uart_pdata); + imx27_add_mxc_nand(&mx27ads_nand_board_info); + + /* only the i2c master 1 is used on this CPU card */ + i2c_register_board_info(1, mx27ads_i2c_devices, + ARRAY_SIZE(mx27ads_i2c_devices)); + imx27_add_imx_i2c(1, &mx27ads_i2c1_data); + imx27_add_imx_fb(&mx27ads_fb_data); + imx27_add_mxc_mmc(0, &sdhc1_pdata); + imx27_add_mxc_mmc(1, &sdhc2_pdata); + + imx27_add_fec(NULL); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx27_add_mxc_w1(NULL); +} + +static void __init mx27ads_timer_init(void) +{ + unsigned long fref = 26000000; + + if ((__raw_readw(PBC_VERSION_REG) & CKIH_27MHZ_BIT_SET) == 0) + fref = 27000000; + + mx27_clocks_init(fref); +} + +static struct sys_timer mx27ads_timer = { + .init = mx27ads_timer_init, +}; + +static struct map_desc mx27ads_io_desc[] __initdata = { + { + .virtual = PBC_BASE_ADDRESS, + .pfn = __phys_to_pfn(MX27_CS4_BASE_ADDR), + .length = SZ_1M, + .type = MT_DEVICE, + }, +}; + +static void __init mx27ads_map_io(void) +{ + mx27_map_io(); + iotable_init(mx27ads_io_desc, ARRAY_SIZE(mx27ads_io_desc)); +} + +MACHINE_START(MX27ADS, "Freescale i.MX27ADS") + /* maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27ads_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &mx27ads_timer, + .init_machine = mx27ads_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31_3ds.c b/arch/arm/mach-imx/mach-mx31_3ds.c new file mode 100644 index 00000000..b5ecc26d --- /dev/null +++ b/arch/arm/mach-imx/mach-mx31_3ds.c @@ -0,0 +1,772 @@ +/* + * Copyright 2008 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. + */ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/mfd/mc13783.h> +#include <linux/spi/spi.h> +#include <linux/spi/l4f00242t03.h> +#include <linux/regulator/machine.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/memblock.h> + +#include <media/soc_camera.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/memory.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <mach/iomux-mx3.h> +#include <mach/3ds_debugboard.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" + +/* CPLD IRQ line for external uart, external ethernet etc */ +#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_1) + +static int mx31_3ds_pins[] = { + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO), + /*SPI0*/ + MX31_PIN_CSPI1_SCLK__SCLK, + MX31_PIN_CSPI1_MOSI__MOSI, + MX31_PIN_CSPI1_MISO__MISO, + MX31_PIN_CSPI1_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI1_SS2__SS2, /* CS for LCD */ + /* SPI 1 */ + MX31_PIN_CSPI2_SCLK__SCLK, + MX31_PIN_CSPI2_MOSI__MOSI, + MX31_PIN_CSPI2_MISO__MISO, + MX31_PIN_CSPI2_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI2_SS0__SS0, + MX31_PIN_CSPI2_SS2__SS2, /*CS for MC13783 */ + /* MC13783 IRQ */ + IOMUX_MODE(MX31_PIN_GPIO1_3, IOMUX_CONFIG_GPIO), + /* USB OTG reset */ + IOMUX_MODE(MX31_PIN_USB_PWR, IOMUX_CONFIG_GPIO), + /* USB OTG */ + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, + MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, + MX31_PIN_USBOTG_STP__USBOTG_STP, + /*Keyboard*/ + MX31_PIN_KEY_ROW0_KEY_ROW0, + MX31_PIN_KEY_ROW1_KEY_ROW1, + MX31_PIN_KEY_ROW2_KEY_ROW2, + MX31_PIN_KEY_COL0_KEY_COL0, + MX31_PIN_KEY_COL1_KEY_COL1, + MX31_PIN_KEY_COL2_KEY_COL2, + MX31_PIN_KEY_COL3_KEY_COL3, + /* USB Host 2 */ + IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_PC_VS2, IOMUX_CONFIG_ALT1), + IOMUX_MODE(MX31_PIN_PC_BVD1, IOMUX_CONFIG_ALT1), + IOMUX_MODE(MX31_PIN_PC_BVD2, IOMUX_CONFIG_ALT1), + IOMUX_MODE(MX31_PIN_PC_RST, IOMUX_CONFIG_ALT1), + IOMUX_MODE(MX31_PIN_IOIS16, IOMUX_CONFIG_ALT1), + IOMUX_MODE(MX31_PIN_PC_RW_B, IOMUX_CONFIG_ALT1), + /* USB Host2 reset */ + IOMUX_MODE(MX31_PIN_USB_BYP, IOMUX_CONFIG_GPIO), + /* I2C1 */ + MX31_PIN_I2C_CLK__I2C1_SCL, + MX31_PIN_I2C_DAT__I2C1_SDA, + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + MX31_PIN_GPIO3_1__GPIO3_1, /* Card detect */ + MX31_PIN_GPIO3_0__GPIO3_0, /* OE */ + /* Framebuffer */ + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_CONTRAST__CONTRAST, + /* CSI */ + MX31_PIN_CSI_D6__CSI_D6, + MX31_PIN_CSI_D7__CSI_D7, + MX31_PIN_CSI_D8__CSI_D8, + MX31_PIN_CSI_D9__CSI_D9, + MX31_PIN_CSI_D10__CSI_D10, + MX31_PIN_CSI_D11__CSI_D11, + MX31_PIN_CSI_D12__CSI_D12, + MX31_PIN_CSI_D13__CSI_D13, + MX31_PIN_CSI_D14__CSI_D14, + MX31_PIN_CSI_D15__CSI_D15, + MX31_PIN_CSI_HSYNC__CSI_HSYNC, + MX31_PIN_CSI_MCLK__CSI_MCLK, + MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, + MX31_PIN_CSI_VSYNC__CSI_VSYNC, + MX31_PIN_CSI_D5__GPIO3_5, /* CMOS PWDN */ + IOMUX_MODE(MX31_PIN_RI_DTE1, IOMUX_CONFIG_GPIO), /* CMOS reset */ +}; + +/* + * Camera support + */ +static phys_addr_t mx3_camera_base __initdata; +#define MX31_3DS_CAMERA_BUF_SIZE SZ_8M + +#define MX31_3DS_GPIO_CAMERA_PW IOMUX_TO_GPIO(MX31_PIN_CSI_D5) +#define MX31_3DS_GPIO_CAMERA_RST IOMUX_TO_GPIO(MX31_PIN_RI_DTE1) + +static struct gpio mx31_3ds_camera_gpios[] = { + { MX31_3DS_GPIO_CAMERA_PW, GPIOF_OUT_INIT_HIGH, "camera-power" }, + { MX31_3DS_GPIO_CAMERA_RST, GPIOF_OUT_INIT_HIGH, "camera-reset" }, +}; + +static const struct mx3_camera_pdata mx31_3ds_camera_pdata __initconst = { + .flags = MX3_CAMERA_DATAWIDTH_10, + .mclk_10khz = 2600, +}; + +static int __init mx31_3ds_init_camera(void) +{ + int dma, ret = -ENOMEM; + struct platform_device *pdev = + imx31_alloc_mx3_camera(&mx31_3ds_camera_pdata); + + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + if (!mx3_camera_base) + goto err; + + dma = dma_declare_coherent_memory(&pdev->dev, + mx3_camera_base, mx3_camera_base, + MX31_3DS_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + + if (!(dma & DMA_MEMORY_MAP)) + goto err; + + ret = platform_device_add(pdev); + if (ret) +err: + platform_device_put(pdev); + + return ret; +} + +static int mx31_3ds_camera_power(struct device *dev, int on) +{ + /* enable or disable the camera */ + pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE"); + gpio_set_value(MX31_3DS_GPIO_CAMERA_PW, on ? 0 : 1); + + if (!on) + goto out; + + /* If enabled, give a reset impulse */ + gpio_set_value(MX31_3DS_GPIO_CAMERA_RST, 0); + msleep(20); + gpio_set_value(MX31_3DS_GPIO_CAMERA_RST, 1); + msleep(100); + +out: + return 0; +} + +static struct i2c_board_info mx31_3ds_i2c_camera = { + I2C_BOARD_INFO("ov2640", 0x30), +}; + +static struct regulator_bulk_data mx31_3ds_camera_regs[] = { + { .supply = "cmos_vcore" }, + { .supply = "cmos_2v8" }, +}; + +static struct soc_camera_link iclink_ov2640 = { + .bus_id = 0, + .board_info = &mx31_3ds_i2c_camera, + .i2c_adapter_id = 0, + .power = mx31_3ds_camera_power, + .regulators = mx31_3ds_camera_regs, + .num_regulators = ARRAY_SIZE(mx31_3ds_camera_regs), +}; + +static struct platform_device mx31_3ds_ov2640 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_ov2640, + }, +}; + +/* + * FB support + */ +static const struct fb_videomode fb_modedb[] = { + { /* 480x640 @ 60 Hz */ + .name = "Epson-VGA", + .refresh = 60, + .xres = 480, + .yres = 640, + .pixclock = 41701, + .left_margin = 20, + .right_margin = 41, + .upper_margin = 10, + .lower_margin = 5, + .hsync_len = 20, + .vsync_len = 10, + .sync = FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static struct ipu_platform_data mx3_ipu_data = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata __initdata = { + .name = "Epson-VGA", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +/* LCD */ +static struct l4f00242t03_pdata mx31_3ds_l4f00242t03_pdata = { + .reset_gpio = IOMUX_TO_GPIO(MX31_PIN_LCS1), + .data_enable_gpio = IOMUX_TO_GPIO(MX31_PIN_SER_RS), + .core_supply = "lcd_2v8", + .io_supply = "vdd_lcdio", +}; + +/* + * Support for SD card slot in personality board + */ +#define MX31_3DS_GPIO_SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_GPIO3_1) +#define MX31_3DS_GPIO_SDHC1_BE IOMUX_TO_GPIO(MX31_PIN_GPIO3_0) + +static struct gpio mx31_3ds_sdhc1_gpios[] = { + { MX31_3DS_GPIO_SDHC1_CD, GPIOF_IN, "sdhc1-card-detect" }, + { MX31_3DS_GPIO_SDHC1_BE, GPIOF_OUT_INIT_LOW, "sdhc1-bus-en" }, +}; + +static int mx31_3ds_sdhc1_init(struct device *dev, + irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request_array(mx31_3ds_sdhc1_gpios, + ARRAY_SIZE(mx31_3ds_sdhc1_gpios)); + if (ret) { + pr_warning("Unable to request the SD/MMC GPIOs.\n"); + return ret; + } + + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO3_1), + detect_irq, IRQF_DISABLED | + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "sdhc1-detect", data); + if (ret) { + pr_warning("Unable to request the SD/MMC card-detect IRQ.\n"); + goto gpio_free; + } + + return 0; + +gpio_free: + gpio_free_array(mx31_3ds_sdhc1_gpios, + ARRAY_SIZE(mx31_3ds_sdhc1_gpios)); + return ret; +} + +static void mx31_3ds_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO3_1), data); + gpio_free_array(mx31_3ds_sdhc1_gpios, + ARRAY_SIZE(mx31_3ds_sdhc1_gpios)); +} + +static void mx31_3ds_sdhc1_setpower(struct device *dev, unsigned int vdd) +{ + /* + * While the voltage stuff is done by the driver, activate the + * Buffer Enable Pin only if there is a card in slot to fix the card + * voltage issue caused by bi-directional chip TXB0108 on 3Stack. + * Done here because at this stage we have for sure a debounced value + * of the presence of the card, showed by the value of vdd. + * 7 == ilog2(MMC_VDD_165_195) + */ + if (vdd > 7) + gpio_set_value(MX31_3DS_GPIO_SDHC1_BE, 1); + else + gpio_set_value(MX31_3DS_GPIO_SDHC1_BE, 0); +} + +static struct imxmmc_platform_data sdhc1_pdata = { + .init = mx31_3ds_sdhc1_init, + .exit = mx31_3ds_sdhc1_exit, + .setpower = mx31_3ds_sdhc1_setpower, +}; + +/* + * Matrix keyboard + */ + +static const uint32_t mx31_3ds_keymap[] = { + KEY(0, 0, KEY_UP), + KEY(0, 1, KEY_DOWN), + KEY(1, 0, KEY_RIGHT), + KEY(1, 1, KEY_LEFT), + KEY(1, 2, KEY_ENTER), + KEY(2, 0, KEY_F6), + KEY(2, 1, KEY_F8), + KEY(2, 2, KEY_F9), + KEY(2, 3, KEY_F10), +}; + +static const struct matrix_keymap_data mx31_3ds_keymap_data __initconst = { + .keymap = mx31_3ds_keymap, + .keymap_size = ARRAY_SIZE(mx31_3ds_keymap), +}; + +/* Regulators */ +static struct regulator_init_data pwgtx_init = { + .constraints = { + .boot_on = 1, + .always_on = 1, + }, +}; + +static struct regulator_init_data gpo_init = { + .constraints = { + .boot_on = 1, + .always_on = 1, + } +}; + +static struct regulator_consumer_supply vmmc2_consumers[] = { + REGULATOR_SUPPLY("vmmc", "mxc-mmc.0"), +}; + +static struct regulator_init_data vmmc2_init = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vmmc2_consumers), + .consumer_supplies = vmmc2_consumers, +}; + +static struct regulator_consumer_supply vmmc1_consumers[] = { + REGULATOR_SUPPLY("lcd_2v8", NULL), + REGULATOR_SUPPLY("cmos_2v8", "soc-camera-pdrv.0"), +}; + +static struct regulator_init_data vmmc1_init = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vmmc1_consumers), + .consumer_supplies = vmmc1_consumers, +}; + +static struct regulator_consumer_supply vgen_consumers[] = { + REGULATOR_SUPPLY("vdd_lcdio", NULL), +}; + +static struct regulator_init_data vgen_init = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vgen_consumers), + .consumer_supplies = vgen_consumers, +}; + +static struct regulator_consumer_supply vvib_consumers[] = { + REGULATOR_SUPPLY("cmos_vcore", "soc-camera-pdrv.0"), +}; + +static struct regulator_init_data vvib_init = { + .constraints = { + .min_uV = 1300000, + .max_uV = 1300000, + .apply_uV = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(vvib_consumers), + .consumer_supplies = vvib_consumers, +}; + +static struct mc13xxx_regulator_init_data mx31_3ds_regulators[] = { + { + .id = MC13783_REG_PWGT1SPI, /* Power Gate for ARM core. */ + .init_data = &pwgtx_init, + }, { + .id = MC13783_REG_PWGT2SPI, /* Power Gate for L2 Cache. */ + .init_data = &pwgtx_init, + }, { + + .id = MC13783_REG_GPO1, /* Turn on 1.8V */ + .init_data = &gpo_init, + }, { + .id = MC13783_REG_GPO3, /* Turn on 3.3V */ + .init_data = &gpo_init, + }, { + .id = MC13783_REG_VMMC2, /* Power MMC/SD, WiFi/Bluetooth. */ + .init_data = &vmmc2_init, + }, { + .id = MC13783_REG_VMMC1, /* Power LCD, CMOS, FM, GPS, Accel. */ + .init_data = &vmmc1_init, + }, { + .id = MC13783_REG_VGEN, /* Power LCD */ + .init_data = &vgen_init, + }, { + .id = MC13783_REG_VVIB, /* Power CMOS */ + .init_data = &vvib_init, + }, +}; + +/* MC13783 */ +static struct mc13xxx_platform_data mc13783_pdata = { + .regulators = { + .regulators = mx31_3ds_regulators, + .num_regulators = ARRAY_SIZE(mx31_3ds_regulators), + }, + .flags = MC13783_USE_REGULATOR | MC13783_USE_TOUCHSCREEN, +}; + +/* SPI */ +static int spi0_internal_chipselect[] = { + MXC_SPI_CS(2), +}; + +static const struct spi_imx_master spi0_pdata __initconst = { + .chipselect = spi0_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi0_internal_chipselect), +}; + +static int spi1_internal_chipselect[] = { + MXC_SPI_CS(0), + MXC_SPI_CS(2), +}; + +static const struct spi_imx_master spi1_pdata __initconst = { + .chipselect = spi1_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi1_internal_chipselect), +}; + +static struct spi_board_info mx31_3ds_spi_devs[] __initdata = { + { + .modalias = "mc13783", + .max_speed_hz = 1000000, + .bus_num = 1, + .chip_select = 1, /* SS2 */ + .platform_data = &mc13783_pdata, + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3), + .mode = SPI_CS_HIGH, + }, { + .modalias = "l4f00242t03", + .max_speed_hz = 5000000, + .bus_num = 0, + .chip_select = 0, /* SS2 */ + .platform_data = &mx31_3ds_l4f00242t03_pdata, + }, +}; + +/* + * NAND Flash + */ +static const struct mxc_nand_platform_data +mx31_3ds_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +#ifdef MACH_MX31_3DS_MXC_NAND_USE_BBT + .flash_bbt = 1, +#endif +}; + +/* + * USB OTG + */ + +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +#define USBOTG_RST_B IOMUX_TO_GPIO(MX31_PIN_USB_PWR) +#define USBH2_RST_B IOMUX_TO_GPIO(MX31_PIN_USB_BYP) + +static int mx31_3ds_usbotg_init(void) +{ + int err; + + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG); + + err = gpio_request(USBOTG_RST_B, "otgusb-reset"); + if (err) { + pr_err("Failed to request the USB OTG reset gpio\n"); + return err; + } + + err = gpio_direction_output(USBOTG_RST_B, 0); + if (err) { + pr_err("Failed to drive the USB OTG reset gpio\n"); + goto usbotg_free_reset; + } + + mdelay(1); + gpio_set_value(USBOTG_RST_B, 1); + return 0; + +usbotg_free_reset: + gpio_free(USBOTG_RST_B); + return err; +} + +static int mx31_3ds_otg_init(struct platform_device *pdev) +{ + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); +} + +static int mx31_3ds_host2_init(struct platform_device *pdev) +{ + int err; + + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_PC_VS2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_PC_BVD1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_PC_BVD2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_PC_RST, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_IOIS16, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_PC_RW_B, USB_PAD_CFG); + + err = gpio_request(USBH2_RST_B, "usbh2-reset"); + if (err) { + pr_err("Failed to request the USB Host 2 reset gpio\n"); + return err; + } + + err = gpio_direction_output(USBH2_RST_B, 0); + if (err) { + pr_err("Failed to drive the USB Host 2 reset gpio\n"); + goto usbotg_free_reset; + } + + mdelay(1); + gpio_set_value(USBH2_RST_B, 1); + + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); + +usbotg_free_reset: + gpio_free(USBH2_RST_B); + return err; +} + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = mx31_3ds_otg_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = mx31_3ds_host2_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static const struct fsl_usb2_platform_data usbotg_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +static int otg_mode_host; + +static int __init mx31_3ds_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", mx31_3ds_otg_mode); + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxi2c_platform_data mx31_3ds_i2c0_data __initconst = { + .bitrate = 100000, +}; + +static struct platform_device *devices[] __initdata = { + &mx31_3ds_ov2640, +}; + +static void __init mx31_3ds_init(void) +{ + int ret; + + mxc_iomux_setup_multiple_pins(mx31_3ds_pins, ARRAY_SIZE(mx31_3ds_pins), + "mx31_3ds"); + + imx31_add_imx_uart0(&uart_pdata); + imx31_add_mxc_nand(&mx31_3ds_nand_board_info); + + imx31_add_spi_imx1(&spi1_pdata); + spi_register_board_info(mx31_3ds_spi_devs, + ARRAY_SIZE(mx31_3ds_spi_devs)); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + imx31_add_imx_keypad(&mx31_3ds_keymap_data); + + mx31_3ds_usbotg_init(); + if (otg_mode_host) { + otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (otg_pdata.otg) + imx31_add_mxc_ehci_otg(&otg_pdata); + } + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbh2_pdata.otg) + imx31_add_mxc_ehci_hs(2, &usbh2_pdata); + + if (!otg_mode_host) + imx31_add_fsl_usb2_udc(&usbotg_pdata); + + if (mxc_expio_init(MX31_CS5_BASE_ADDR, EXPIO_PARENT_INT)) + printk(KERN_WARNING "Init of the debug board failed, all " + "devices on the debug board are unusable.\n"); + imx31_add_imx2_wdt(NULL); + imx31_add_imx_i2c0(&mx31_3ds_i2c0_data); + imx31_add_mxc_mmc(0, &sdhc1_pdata); + + imx31_add_spi_imx0(&spi0_pdata); + imx31_add_ipu_core(&mx3_ipu_data); + imx31_add_mx3_sdc_fb(&mx3fb_pdata); + + /* CSI */ + /* Camera power: default - off */ + ret = gpio_request_array(mx31_3ds_camera_gpios, + ARRAY_SIZE(mx31_3ds_camera_gpios)); + if (ret) { + pr_err("Failed to request camera gpios"); + iclink_ov2640.power = NULL; + } + + mx31_3ds_init_camera(); +} + +static void __init mx31_3ds_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer mx31_3ds_timer = { + .init = mx31_3ds_timer_init, +}; + +static void __init mx31_3ds_reserve(void) +{ + /* reserve MX31_3DS_CAMERA_BUF_SIZE bytes for mx3-camera */ + mx3_camera_base = memblock_alloc(MX31_3DS_CAMERA_BUF_SIZE, + MX31_3DS_CAMERA_BUF_SIZE); + memblock_free(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE); + memblock_remove(mx3_camera_base, MX31_3DS_CAMERA_BUF_SIZE); +} + +MACHINE_START(MX31_3DS, "Freescale MX31PDK (3DS)") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &mx31_3ds_timer, + .init_machine = mx31_3ds_init, + .reserve = mx31_3ds_reserve, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31ads.c b/arch/arm/mach-imx/mach-mx31ads.c new file mode 100644 index 00000000..f4dee025 --- /dev/null +++ b/arch/arm/mach-imx/mach-mx31ads.c @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 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. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/serial_8250.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/irq.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/memory.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <mach/board-mx31ads.h> +#include <mach/iomux-mx3.h> + +#ifdef CONFIG_MACH_MX31ADS_WM1133_EV1 +#include <linux/mfd/wm8350/audio.h> +#include <linux/mfd/wm8350/core.h> +#include <linux/mfd/wm8350/pmic.h> +#endif + +#include "devices-imx31.h" + +/* PBC Board interrupt status register */ +#define PBC_INTSTATUS 0x000016 + +/* PBC Board interrupt current status register */ +#define PBC_INTCURR_STATUS 0x000018 + +/* PBC Interrupt mask register set address */ +#define PBC_INTMASK_SET 0x00001A + +/* PBC Interrupt mask register clear address */ +#define PBC_INTMASK_CLEAR 0x00001C + +/* External UART A */ +#define PBC_SC16C652_UARTA 0x010000 + +/* External UART B */ +#define PBC_SC16C652_UARTB 0x010010 + +#define PBC_INTSTATUS_REG (PBC_INTSTATUS + PBC_BASE_ADDRESS) +#define PBC_INTMASK_SET_REG (PBC_INTMASK_SET + PBC_BASE_ADDRESS) +#define PBC_INTMASK_CLEAR_REG (PBC_INTMASK_CLEAR + PBC_BASE_ADDRESS) +#define EXPIO_PARENT_INT IOMUX_TO_IRQ(MX31_PIN_GPIO1_4) + +#define MXC_IRQ_TO_EXPIO(irq) ((irq) - MXC_EXP_IO_BASE) + +#define EXPIO_INT_XUART_INTA (MXC_EXP_IO_BASE + 10) +#define EXPIO_INT_XUART_INTB (MXC_EXP_IO_BASE + 11) + +#define MXC_MAX_EXP_IO_LINES 16 + +/* + * The serial port definition structure. + */ +static struct plat_serial8250_port serial_platform_data[] = { + { + .membase = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTA), + .mapbase = (unsigned long)(MX31_CS4_BASE_ADDR + PBC_SC16C652_UARTA), + .irq = EXPIO_INT_XUART_INTA, + .uartclk = 14745600, + .regshift = 0, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ, + }, { + .membase = (void *)(PBC_BASE_ADDRESS + PBC_SC16C652_UARTB), + .mapbase = (unsigned long)(MX31_CS4_BASE_ADDR + PBC_SC16C652_UARTB), + .irq = EXPIO_INT_XUART_INTB, + .uartclk = 14745600, + .regshift = 0, + .iotype = UPIO_MEM, + .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ, + }, + {}, +}; + +static struct platform_device serial_device = { + .name = "serial8250", + .id = 0, + .dev = { + .platform_data = serial_platform_data, + }, +}; + +static int __init mxc_init_extuart(void) +{ + return platform_device_register(&serial_device); +} + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static unsigned int uart_pins[] = { + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1 +}; + +static inline void mxc_init_imx_uart(void) +{ + mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), "uart-0"); + imx31_add_imx_uart0(&uart_pdata); +} + +static void mx31ads_expio_irq_handler(u32 irq, struct irq_desc *desc) +{ + u32 imr_val; + u32 int_valid; + u32 expio_irq; + + imr_val = __raw_readw(PBC_INTMASK_SET_REG); + int_valid = __raw_readw(PBC_INTSTATUS_REG) & imr_val; + + expio_irq = MXC_EXP_IO_BASE; + for (; int_valid != 0; int_valid >>= 1, expio_irq++) { + if ((int_valid & 1) == 0) + continue; + + generic_handle_irq(expio_irq); + } +} + +/* + * Disable an expio pin's interrupt by setting the bit in the imr. + * @param d an expio virtual irq description + */ +static void expio_mask_irq(struct irq_data *d) +{ + u32 expio = MXC_IRQ_TO_EXPIO(d->irq); + /* mask the interrupt */ + __raw_writew(1 << expio, PBC_INTMASK_CLEAR_REG); + __raw_readw(PBC_INTMASK_CLEAR_REG); +} + +/* + * Acknowledge an expanded io pin's interrupt by clearing the bit in the isr. + * @param d an expio virtual irq description + */ +static void expio_ack_irq(struct irq_data *d) +{ + u32 expio = MXC_IRQ_TO_EXPIO(d->irq); + /* clear the interrupt status */ + __raw_writew(1 << expio, PBC_INTSTATUS_REG); +} + +/* + * Enable a expio pin's interrupt by clearing the bit in the imr. + * @param d an expio virtual irq description + */ +static void expio_unmask_irq(struct irq_data *d) +{ + u32 expio = MXC_IRQ_TO_EXPIO(d->irq); + /* unmask the interrupt */ + __raw_writew(1 << expio, PBC_INTMASK_SET_REG); +} + +static struct irq_chip expio_irq_chip = { + .name = "EXPIO(CPLD)", + .irq_ack = expio_ack_irq, + .irq_mask = expio_mask_irq, + .irq_unmask = expio_unmask_irq, +}; + +static void __init mx31ads_init_expio(void) +{ + int i; + + printk(KERN_INFO "MX31ADS EXPIO(CPLD) hardware\n"); + + /* + * Configure INT line as GPIO input + */ + mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_GPIO1_4, IOMUX_CONFIG_GPIO), "expio"); + + /* disable the interrupt and clear the status */ + __raw_writew(0xFFFF, PBC_INTMASK_CLEAR_REG); + __raw_writew(0xFFFF, PBC_INTSTATUS_REG); + for (i = MXC_EXP_IO_BASE; i < (MXC_EXP_IO_BASE + MXC_MAX_EXP_IO_LINES); + i++) { + irq_set_chip_and_handler(i, &expio_irq_chip, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + } + irq_set_irq_type(EXPIO_PARENT_INT, IRQ_TYPE_LEVEL_HIGH); + irq_set_chained_handler(EXPIO_PARENT_INT, mx31ads_expio_irq_handler); +} + +#ifdef CONFIG_MACH_MX31ADS_WM1133_EV1 +/* This section defines setup for the Wolfson Microelectronics + * 1133-EV1 PMU/audio board. When other PMU boards are supported the + * regulator definitions may be shared with them, but for now they can + * only be used with this board so would generate warnings about + * unused statics and some of the configuration is specific to this + * module. + */ + +/* CPU */ +static struct regulator_consumer_supply sw1a_consumers[] = { + { + .supply = "cpu_vcc", + } +}; + +static struct regulator_init_data sw1a_data = { + .constraints = { + .name = "SW1A", + .min_uV = 1275000, + .max_uV = 1600000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .state_mem = { + .uV = 1400000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .initial_state = PM_SUSPEND_MEM, + .always_on = 1, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sw1a_consumers), + .consumer_supplies = sw1a_consumers, +}; + +/* System IO - High */ +static struct regulator_init_data viohi_data = { + .constraints = { + .name = "VIOHO", + .min_uV = 2800000, + .max_uV = 2800000, + .state_mem = { + .uV = 2800000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .initial_state = PM_SUSPEND_MEM, + .always_on = 1, + .boot_on = 1, + }, +}; + +/* System IO - Low */ +static struct regulator_init_data violo_data = { + .constraints = { + .name = "VIOLO", + .min_uV = 1800000, + .max_uV = 1800000, + .state_mem = { + .uV = 1800000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .initial_state = PM_SUSPEND_MEM, + .always_on = 1, + .boot_on = 1, + }, +}; + +/* DDR RAM */ +static struct regulator_init_data sw2a_data = { + .constraints = { + .name = "SW2A", + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .state_mem = { + .uV = 1800000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .state_disk = { + .mode = REGULATOR_MODE_NORMAL, + .enabled = 0, + }, + .always_on = 1, + .boot_on = 1, + .initial_state = PM_SUSPEND_MEM, + }, +}; + +static struct regulator_init_data ldo1_data = { + .constraints = { + .name = "VCAM/VMMC1/VMMC2", + .min_uV = 2800000, + .max_uV = 2800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, +}; + +static struct regulator_consumer_supply ldo2_consumers[] = { + { .supply = "AVDD", .dev_name = "1-001a" }, + { .supply = "HPVDD", .dev_name = "1-001a" }, +}; + +/* CODEC and SIM */ +static struct regulator_init_data ldo2_data = { + .constraints = { + .name = "VESIM/VSIM/AVDD", + .min_uV = 3300000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(ldo2_consumers), + .consumer_supplies = ldo2_consumers, +}; + +/* General */ +static struct regulator_init_data vdig_data = { + .constraints = { + .name = "VDIG", + .min_uV = 1500000, + .max_uV = 1500000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + .boot_on = 1, + }, +}; + +/* Tranceivers */ +static struct regulator_init_data ldo4_data = { + .constraints = { + .name = "VRF1/CVDD_2.775", + .min_uV = 2500000, + .max_uV = 2500000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + .boot_on = 1, + }, +}; + +static struct wm8350_led_platform_data wm8350_led_data = { + .name = "wm8350:white", + .default_trigger = "heartbeat", + .max_uA = 27899, +}; + +static struct wm8350_audio_platform_data imx32ads_wm8350_setup = { + .vmid_discharge_msecs = 1000, + .drain_msecs = 30, + .cap_discharge_msecs = 700, + .vmid_charge_msecs = 700, + .vmid_s_curve = WM8350_S_CURVE_SLOW, + .dis_out4 = WM8350_DISCHARGE_SLOW, + .dis_out3 = WM8350_DISCHARGE_SLOW, + .dis_out2 = WM8350_DISCHARGE_SLOW, + .dis_out1 = WM8350_DISCHARGE_SLOW, + .vroi_out4 = WM8350_TIE_OFF_500R, + .vroi_out3 = WM8350_TIE_OFF_500R, + .vroi_out2 = WM8350_TIE_OFF_500R, + .vroi_out1 = WM8350_TIE_OFF_500R, + .vroi_enable = 0, + .codec_current_on = WM8350_CODEC_ISEL_1_0, + .codec_current_standby = WM8350_CODEC_ISEL_0_5, + .codec_current_charge = WM8350_CODEC_ISEL_1_5, +}; + +static int mx31_wm8350_init(struct wm8350 *wm8350) +{ + wm8350_gpio_config(wm8350, 0, WM8350_GPIO_DIR_IN, + WM8350_GPIO0_PWR_ON_IN, WM8350_GPIO_ACTIVE_LOW, + WM8350_GPIO_PULL_UP, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_ON); + + wm8350_gpio_config(wm8350, 3, WM8350_GPIO_DIR_IN, + WM8350_GPIO3_PWR_OFF_IN, WM8350_GPIO_ACTIVE_HIGH, + WM8350_GPIO_PULL_DOWN, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_ON); + + wm8350_gpio_config(wm8350, 4, WM8350_GPIO_DIR_IN, + WM8350_GPIO4_MR_IN, WM8350_GPIO_ACTIVE_HIGH, + WM8350_GPIO_PULL_DOWN, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF); + + wm8350_gpio_config(wm8350, 7, WM8350_GPIO_DIR_IN, + WM8350_GPIO7_HIBERNATE_IN, WM8350_GPIO_ACTIVE_HIGH, + WM8350_GPIO_PULL_DOWN, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF); + + wm8350_gpio_config(wm8350, 6, WM8350_GPIO_DIR_OUT, + WM8350_GPIO6_SDOUT_OUT, WM8350_GPIO_ACTIVE_HIGH, + WM8350_GPIO_PULL_NONE, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF); + + wm8350_gpio_config(wm8350, 8, WM8350_GPIO_DIR_OUT, + WM8350_GPIO8_VCC_FAULT_OUT, WM8350_GPIO_ACTIVE_LOW, + WM8350_GPIO_PULL_NONE, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF); + + wm8350_gpio_config(wm8350, 9, WM8350_GPIO_DIR_OUT, + WM8350_GPIO9_BATT_FAULT_OUT, WM8350_GPIO_ACTIVE_LOW, + WM8350_GPIO_PULL_NONE, WM8350_GPIO_INVERT_OFF, + WM8350_GPIO_DEBOUNCE_OFF); + + wm8350_register_regulator(wm8350, WM8350_DCDC_1, &sw1a_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_3, &viohi_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_4, &violo_data); + wm8350_register_regulator(wm8350, WM8350_DCDC_6, &sw2a_data); + wm8350_register_regulator(wm8350, WM8350_LDO_1, &ldo1_data); + wm8350_register_regulator(wm8350, WM8350_LDO_2, &ldo2_data); + wm8350_register_regulator(wm8350, WM8350_LDO_3, &vdig_data); + wm8350_register_regulator(wm8350, WM8350_LDO_4, &ldo4_data); + + /* LEDs */ + wm8350_dcdc_set_slot(wm8350, WM8350_DCDC_5, 1, 1, + WM8350_DC5_ERRACT_SHUTDOWN_CONV); + wm8350_isink_set_flash(wm8350, WM8350_ISINK_A, + WM8350_ISINK_FLASH_DISABLE, + WM8350_ISINK_FLASH_TRIG_BIT, + WM8350_ISINK_FLASH_DUR_32MS, + WM8350_ISINK_FLASH_ON_INSTANT, + WM8350_ISINK_FLASH_OFF_INSTANT, + WM8350_ISINK_FLASH_MODE_EN); + wm8350_dcdc25_set_mode(wm8350, WM8350_DCDC_5, + WM8350_ISINK_MODE_BOOST, + WM8350_ISINK_ILIM_NORMAL, + WM8350_DC5_RMP_20V, + WM8350_DC5_FBSRC_ISINKA); + wm8350_register_led(wm8350, 0, WM8350_DCDC_5, WM8350_ISINK_A, + &wm8350_led_data); + + wm8350->codec.platform_data = &imx32ads_wm8350_setup; + + regulator_has_full_constraints(); + + return 0; +} + +static struct wm8350_platform_data __initdata mx31_wm8350_pdata = { + .init = mx31_wm8350_init, + .irq_base = MXC_BOARD_IRQ_START + MXC_MAX_EXP_IO_LINES, +}; +#endif + +static struct i2c_board_info __initdata mx31ads_i2c1_devices[] = { +#ifdef CONFIG_MACH_MX31ADS_WM1133_EV1 + { + I2C_BOARD_INFO("wm8350", 0x1a), + .platform_data = &mx31_wm8350_pdata, + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3), + }, +#endif +}; + +static void mxc_init_i2c(void) +{ + i2c_register_board_info(1, mx31ads_i2c1_devices, + ARRAY_SIZE(mx31ads_i2c1_devices)); + + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_CSPI2_MOSI, IOMUX_CONFIG_ALT1)); + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_CSPI2_MISO, IOMUX_CONFIG_ALT1)); + + imx31_add_imx_i2c1(NULL); +} + +static unsigned int ssi_pins[] = { + MX31_PIN_SFS5__SFS5, + MX31_PIN_SCK5__SCK5, + MX31_PIN_SRXD5__SRXD5, + MX31_PIN_STXD5__STXD5, +}; + +static void mxc_init_audio(void) +{ + imx31_add_imx_ssi(0, NULL); + mxc_iomux_setup_multiple_pins(ssi_pins, ARRAY_SIZE(ssi_pins), "ssi"); +} + +/* static mappings */ +static struct map_desc mx31ads_io_desc[] __initdata = { + { + .virtual = MX31_CS4_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(MX31_CS4_BASE_ADDR), + .length = MX31_CS4_SIZE / 2, + .type = MT_DEVICE + }, +}; + +static void __init mx31ads_map_io(void) +{ + mx31_map_io(); + iotable_init(mx31ads_io_desc, ARRAY_SIZE(mx31ads_io_desc)); +} + +static void __init mx31ads_init_irq(void) +{ + mx31_init_irq(); + mx31ads_init_expio(); +} + +static void __init mx31ads_init(void) +{ + mxc_init_extuart(); + mxc_init_imx_uart(); + mxc_init_i2c(); + mxc_init_audio(); +} + +static void __init mx31ads_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer mx31ads_timer = { + .init = mx31ads_timer_init, +}; + +MACHINE_START(MX31ADS, "Freescale MX31ADS") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx31ads_map_io, + .init_early = imx31_init_early, + .init_irq = mx31ads_init_irq, + .timer = &mx31ads_timer, + .init_machine = mx31ads_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31lilly.c b/arch/arm/mach-imx/mach-mx31lilly.c new file mode 100644 index 00000000..410e676a --- /dev/null +++ b/arch/arm/mach-imx/mach-mx31lilly.c @@ -0,0 +1,302 @@ +/* + * LILLY-1131 module support + * + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * + * based on code for other MX31 boards, + * + * Copyright 2005-2007 Freescale Semiconductor + * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/smsc911x.h> +#include <linux/mtd/physmap.h> +#include <linux/spi/spi.h> +#include <linux/mfd/mc13783.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx3.h> +#include <mach/board-mx31lilly.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" + +/* + * This file contains module-specific initialization routines for LILLY-1131. + * Initialization of peripherals found on the baseboard is implemented in the + * appropriate baseboard support code. + */ + +/* SMSC ethernet support */ + +static struct resource smsc91x_resources[] = { + { + .start = MX31_CS4_BASE_ADDR, + .end = MX31_CS4_BASE_ADDR + 0xffff, + .flags = IORESOURCE_MEM, + }, + { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO1_0), + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_FALLING, + } +}; + +static struct smsc911x_platform_config smsc911x_config = { + .phy_interface = PHY_INTERFACE_MODE_MII, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .flags = SMSC911X_USE_32BIT | + SMSC911X_SAVE_MAC_ADDRESS | + SMSC911X_FORCE_INTERNAL_PHY, +}; + +static struct platform_device smsc91x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc91x_resources), + .resource = smsc91x_resources, + .dev = { + .platform_data = &smsc911x_config, + } +}; + +/* NOR flash */ +static struct physmap_flash_data nor_flash_data = { + .width = 2, +}; + +static struct resource nor_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +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, +}; + +/* USB */ + +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +static int usbh1_init(struct platform_device *pdev) +{ + int pins[] = { + MX31_PIN_CSPI1_MOSI__USBH1_RXDM, + MX31_PIN_CSPI1_MISO__USBH1_RXDP, + MX31_PIN_CSPI1_SS0__USBH1_TXDM, + MX31_PIN_CSPI1_SS1__USBH1_TXDP, + MX31_PIN_CSPI1_SS2__USBH1_RCV, + MX31_PIN_CSPI1_SCLK__USBH1_OEB, + MX31_PIN_CSPI1_SPI_RDY__USBH1_FS, + }; + + mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB H1"); + + mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG); + + mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true); + + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_INTERFACE_SINGLE_UNI); +} + +static int usbh2_init(struct platform_device *pdev) +{ + int pins[] = { + MX31_PIN_USBH2_DATA0__USBH2_DATA0, + MX31_PIN_USBH2_DATA1__USBH2_DATA1, + MX31_PIN_USBH2_CLK__USBH2_CLK, + MX31_PIN_USBH2_DIR__USBH2_DIR, + MX31_PIN_USBH2_NXT__USBH2_NXT, + MX31_PIN_USBH2_STP__USBH2_STP, + }; + + mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB H2"); + + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG); + + mxc_iomux_set_gpr(MUX_PGP_UH2, true); + + /* chip select */ + mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_GPIO), + "USBH2_CS"); + gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), "USBH2 CS"); + gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), 0); + + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); +} + +static const struct mxc_usbh_platform_data usbh1_pdata __initconst = { + .init = usbh1_init, + .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL, +}; + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = usbh2_init, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +static void lilly1131_usb_init(void) +{ + imx31_add_mxc_ehci_hs(1, &usbh1_pdata); + + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbh2_pdata.otg) + imx31_add_mxc_ehci_hs(2, &usbh2_pdata); +} + +/* SPI */ + +static int spi_internal_chipselect[] = { + MXC_SPI_CS(0), + MXC_SPI_CS(1), + MXC_SPI_CS(2), +}; + +static const struct spi_imx_master spi0_pdata __initconst = { + .chipselect = spi_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi_internal_chipselect), +}; + +static const struct spi_imx_master spi1_pdata __initconst = { + .chipselect = spi_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi_internal_chipselect), +}; + +static struct mc13xxx_platform_data mc13783_pdata __initdata = { + .flags = MC13XXX_USE_RTC | MC13XXX_USE_TOUCHSCREEN, +}; + +static struct spi_board_info mc13783_dev __initdata = { + .modalias = "mc13783", + .max_speed_hz = 1000000, + .bus_num = 1, + .chip_select = 0, + .platform_data = &mc13783_pdata, + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3), +}; + +static struct platform_device *devices[] __initdata = { + &smsc91x_device, + &physmap_flash_device, +}; + +static int mx31lilly_baseboard; +core_param(mx31lilly_baseboard, mx31lilly_baseboard, int, 0444); + +static void __init mx31lilly_board_init(void) +{ + switch (mx31lilly_baseboard) { + case MX31LILLY_NOBOARD: + break; + case MX31LILLY_DB: + mx31lilly_db_init(); + break; + default: + printk(KERN_ERR "Illegal mx31lilly_baseboard type %d\n", + mx31lilly_baseboard); + } + + mxc_iomux_alloc_pin(MX31_PIN_CS4__CS4, "Ethernet CS"); + + /* SPI */ + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SCLK__SCLK, "SPI1_CLK"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_MOSI__MOSI, "SPI1_TX"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_MISO__MISO, "SPI1_RX"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SPI_RDY__SPI_RDY, "SPI1_RDY"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SS0__SS0, "SPI1_SS0"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SS1__SS1, "SPI1_SS1"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI1_SS2__SS2, "SPI1_SS2"); + + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SCLK__SCLK, "SPI2_CLK"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MOSI__MOSI, "SPI2_TX"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_MISO__MISO, "SPI2_RX"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SPI_RDY__SPI_RDY, "SPI2_RDY"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS0__SS0, "SPI2_SS0"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS1__SS1, "SPI2_SS1"); + mxc_iomux_alloc_pin(MX31_PIN_CSPI2_SS2__SS2, "SPI2_SS2"); + + imx31_add_spi_imx0(&spi0_pdata); + imx31_add_spi_imx1(&spi1_pdata); + spi_register_board_info(&mc13783_dev, 1); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + /* USB */ + lilly1131_usb_init(); +} + +static void __init mx31lilly_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer mx31lilly_timer = { + .init = mx31lilly_timer_init, +}; + +MACHINE_START(LILLY1131, "INCO startec LILLY-1131") + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &mx31lilly_timer, + .init_machine = mx31lilly_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31lite.c b/arch/arm/mach-imx/mach-mx31lite.c new file mode 100644 index 00000000..ac9b4cad --- /dev/null +++ b/arch/arm/mach-imx/mach-mx31lite.c @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/memory.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/smsc911x.h> +#include <linux/mfd/mc13783.h> +#include <linux/spi/spi.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/mtd/physmap.h> +#include <linux/delay.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <asm/page.h> +#include <asm/setup.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/board-mx31lite.h> +#include <mach/iomux-mx3.h> +#include <mach/irqs.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" + +/* + * This file contains the module-specific initialization routines. + */ + +static unsigned int mx31lite_pins[] = { + /* LAN9117 IRQ pin */ + IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO), + /* SPI 1 */ + MX31_PIN_CSPI2_SCLK__SCLK, + MX31_PIN_CSPI2_MOSI__MOSI, + MX31_PIN_CSPI2_MISO__MISO, + MX31_PIN_CSPI2_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI2_SS0__SS0, + MX31_PIN_CSPI2_SS1__SS1, + MX31_PIN_CSPI2_SS2__SS2, +}; + +static const struct mxc_nand_platform_data +mx31lite_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static struct smsc911x_platform_config smsc911x_config = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL, + .flags = SMSC911X_USE_16BIT, +}; + +static struct resource smsc911x_resources[] = { + { + .start = MX31_CS4_BASE_ADDR, + .end = MX31_CS4_BASE_ADDR + 0x100, + .flags = IORESOURCE_MEM, + }, { + .start = IOMUX_TO_IRQ(MX31_PIN_SFS6), + .end = IOMUX_TO_IRQ(MX31_PIN_SFS6), + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device smsc911x_device = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_config, + }, +}; + +/* + * SPI + * + * The MC13783 is the only hard-wired SPI device on the module. + */ + +static int spi_internal_chipselect[] = { + MXC_SPI_CS(0), +}; + +static const struct spi_imx_master spi1_pdata __initconst = { + .chipselect = spi_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi_internal_chipselect), +}; + +static struct mc13xxx_platform_data mc13783_pdata __initdata = { + .flags = MC13XXX_USE_RTC | + MC13XXX_USE_REGULATOR, +}; + +static struct spi_board_info mc13783_spi_dev __initdata = { + .modalias = "mc13783", + .max_speed_hz = 1000000, + .bus_num = 1, + .chip_select = 0, + .platform_data = &mc13783_pdata, + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3), +}; + +/* + * USB + */ + +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +static int usbh2_init(struct platform_device *pdev) +{ + int pins[] = { + MX31_PIN_USBH2_DATA0__USBH2_DATA0, + MX31_PIN_USBH2_DATA1__USBH2_DATA1, + MX31_PIN_USBH2_CLK__USBH2_CLK, + MX31_PIN_USBH2_DIR__USBH2_DIR, + MX31_PIN_USBH2_NXT__USBH2_NXT, + MX31_PIN_USBH2_STP__USBH2_STP, + }; + + mxc_iomux_setup_multiple_pins(pins, ARRAY_SIZE(pins), "USB H2"); + + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG); + + mxc_iomux_set_gpr(MUX_PGP_UH2, true); + + /* chip select */ + mxc_iomux_alloc_pin(IOMUX_MODE(MX31_PIN_DTR_DCE1, IOMUX_CONFIG_GPIO), + "USBH2_CS"); + gpio_request(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), "USBH2 CS"); + gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1), 0); + + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); +} + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = usbh2_init, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +/* + * NOR flash + */ + +static struct physmap_flash_data nor_flash_data = { + .width = 2, +}; + +static struct resource nor_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +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, +}; + + + +/* + * This structure defines the MX31 memory map. + */ +static struct map_desc mx31lite_io_desc[] __initdata = { + { + .virtual = MX31_CS4_BASE_ADDR_VIRT, + .pfn = __phys_to_pfn(MX31_CS4_BASE_ADDR), + .length = MX31_CS4_SIZE, + .type = MT_DEVICE + } +}; + +/* + * Set up static virtual mappings. + */ +void __init mx31lite_map_io(void) +{ + mx31_map_io(); + iotable_init(mx31lite_io_desc, ARRAY_SIZE(mx31lite_io_desc)); +} + +static int mx31lite_baseboard; +core_param(mx31lite_baseboard, mx31lite_baseboard, int, 0444); + +static void __init mx31lite_init(void) +{ + int ret; + + switch (mx31lite_baseboard) { + case MX31LITE_NOBOARD: + break; + case MX31LITE_DB: + mx31lite_db_init(); + break; + default: + printk(KERN_ERR "Illegal mx31lite_baseboard type %d\n", + mx31lite_baseboard); + } + + mxc_iomux_setup_multiple_pins(mx31lite_pins, ARRAY_SIZE(mx31lite_pins), + "mx31lite"); + + /* NOR and NAND flash */ + platform_device_register(&physmap_flash_device); + imx31_add_mxc_nand(&mx31lite_nand_board_info); + + imx31_add_spi_imx1(&spi1_pdata); + spi_register_board_info(&mc13783_spi_dev, 1); + + /* USB */ + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbh2_pdata.otg) + imx31_add_mxc_ehci_hs(2, &usbh2_pdata); + + /* SMSC9117 IRQ pin */ + ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_SFS6), "sms9117-irq"); + if (ret) + pr_warning("could not get LAN irq gpio\n"); + else { + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_SFS6)); + platform_device_register(&smsc911x_device); + } +} + +static void __init mx31lite_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +struct sys_timer mx31lite_timer = { + .init = mx31lite_timer_init, +}; + +MACHINE_START(MX31LITE, "LogicPD i.MX31 SOM") + /* Maintainer: Freescale Semiconductor, Inc. */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx31lite_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &mx31lite_timer, + .init_machine = mx31lite_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c new file mode 100644 index 00000000..eaa51e49 --- /dev/null +++ b/arch/arm/mach-imx/mach-mx31moboard.c @@ -0,0 +1,583 @@ +/* + * Copyright (C) 2008 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/gfp.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/leds.h> +#include <linux/memory.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13783.h> +#include <linux/spi/spi.h> +#include <linux/types.h> +#include <linux/memblock.h> + +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <mach/board-mx31moboard.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx3.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" + +static unsigned int moboard_pins[] = { + /* UART0 */ + MX31_PIN_TXD1__TXD1, MX31_PIN_RXD1__RXD1, + MX31_PIN_CTS1__GPIO2_7, + /* UART4 */ + MX31_PIN_PC_RST__CTS5, MX31_PIN_PC_VS2__RTS5, + MX31_PIN_PC_BVD2__TXD5, MX31_PIN_PC_BVD1__RXD5, + /* I2C0 */ + MX31_PIN_I2C_DAT__I2C1_SDA, MX31_PIN_I2C_CLK__I2C1_SCL, + /* I2C1 */ + MX31_PIN_DCD_DTE1__I2C2_SDA, MX31_PIN_RI_DTE1__I2C2_SCL, + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, MX31_PIN_SD1_CMD__SD1_CMD, + MX31_PIN_ATA_CS0__GPIO3_26, MX31_PIN_ATA_CS1__GPIO3_27, + /* USB reset */ + MX31_PIN_GPIO1_0__GPIO1_0, + /* USB OTG */ + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, MX31_PIN_USBOTG_STP__USBOTG_STP, + MX31_PIN_USB_OC__GPIO1_30, + /* USB H2 */ + MX31_PIN_USBH2_DATA0__USBH2_DATA0, + MX31_PIN_USBH2_DATA1__USBH2_DATA1, + MX31_PIN_STXD3__USBH2_DATA2, MX31_PIN_SRXD3__USBH2_DATA3, + MX31_PIN_SCK3__USBH2_DATA4, MX31_PIN_SFS3__USBH2_DATA5, + MX31_PIN_STXD6__USBH2_DATA6, MX31_PIN_SRXD6__USBH2_DATA7, + MX31_PIN_USBH2_CLK__USBH2_CLK, MX31_PIN_USBH2_DIR__USBH2_DIR, + MX31_PIN_USBH2_NXT__USBH2_NXT, MX31_PIN_USBH2_STP__USBH2_STP, + MX31_PIN_SCK6__GPIO1_25, + /* LEDs */ + MX31_PIN_SVEN0__GPIO2_0, MX31_PIN_STX0__GPIO2_1, + MX31_PIN_SRX0__GPIO2_2, MX31_PIN_SIMPD0__GPIO2_3, + /* SPI1 */ + MX31_PIN_CSPI2_MOSI__MOSI, MX31_PIN_CSPI2_MISO__MISO, + MX31_PIN_CSPI2_SCLK__SCLK, MX31_PIN_CSPI2_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI2_SS0__SS0, MX31_PIN_CSPI2_SS2__SS2, + /* Atlas IRQ */ + MX31_PIN_GPIO1_3__GPIO1_3, + /* SPI2 */ + MX31_PIN_CSPI3_MOSI__MOSI, MX31_PIN_CSPI3_MISO__MISO, + MX31_PIN_CSPI3_SCLK__SCLK, MX31_PIN_CSPI3_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI2_SS1__CSPI3_SS1, +}; + +static struct physmap_flash_data mx31moboard_flash_data = { + .width = 2, +}; + +static struct resource mx31moboard_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device mx31moboard_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &mx31moboard_flash_data, + }, + .resource = &mx31moboard_flash_resource, + .num_resources = 1, +}; + +static int moboard_uart0_init(struct platform_device *pdev) +{ + int ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CTS1), "uart0-cts-hack"); + if (ret) + return ret; + + ret = gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CTS1), 0); + if (ret) + gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); + + return ret; +} + +static void moboard_uart0_exit(struct platform_device *pdev) +{ + gpio_free(IOMUX_TO_GPIO(MX31_PIN_CTS1)); +} + +static const struct imxuart_platform_data uart0_pdata __initconst = { + .init = moboard_uart0_init, + .exit = moboard_uart0_exit, +}; + +static const struct imxuart_platform_data uart4_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxi2c_platform_data moboard_i2c0_data __initconst = { + .bitrate = 400000, +}; + +static const struct imxi2c_platform_data moboard_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static int moboard_spi1_cs[] = { + MXC_SPI_CS(0), + MXC_SPI_CS(2), +}; + +static const struct spi_imx_master moboard_spi1_pdata __initconst = { + .chipselect = moboard_spi1_cs, + .num_chipselect = ARRAY_SIZE(moboard_spi1_cs), +}; + +static struct regulator_consumer_supply sdhc_consumers[] = { + { + .dev_name = "mxc-mmc.0", + .supply = "sdhc0_vcc", + }, + { + .dev_name = "mxc-mmc.1", + .supply = "sdhc1_vcc", + }, +}; + +static struct regulator_init_data sdhc_vreg_data = { + .constraints = { + .min_uV = 2700000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .always_on = 0, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sdhc_consumers), + .consumer_supplies = sdhc_consumers, +}; + +static struct regulator_consumer_supply cam_consumers[] = { + { + .dev_name = "mx3_camera.0", + .supply = "cam_vcc", + }, +}; + +static struct regulator_init_data cam_vreg_data = { + .constraints = { + .min_uV = 2700000, + .max_uV = 3000000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .always_on = 0, + .boot_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(cam_consumers), + .consumer_supplies = cam_consumers, +}; + +static struct mc13xxx_regulator_init_data moboard_regulators[] = { + { + .id = MC13783_REG_VMMC1, + .init_data = &sdhc_vreg_data, + }, + { + .id = MC13783_REG_VCAM, + .init_data = &cam_vreg_data, + }, +}; + +static struct mc13783_led_platform_data moboard_led[] = { + { + .id = MC13783_LED_R1, + .name = "coreboard-led-4:red", + .max_current = 2, + }, + { + .id = MC13783_LED_G1, + .name = "coreboard-led-4:green", + .max_current = 2, + }, + { + .id = MC13783_LED_B1, + .name = "coreboard-led-4:blue", + .max_current = 2, + }, + { + .id = MC13783_LED_R2, + .name = "coreboard-led-5:red", + .max_current = 3, + }, + { + .id = MC13783_LED_G2, + .name = "coreboard-led-5:green", + .max_current = 3, + }, + { + .id = MC13783_LED_B2, + .name = "coreboard-led-5:blue", + .max_current = 3, + }, +}; + +static struct mc13783_leds_platform_data moboard_leds = { + .num_leds = ARRAY_SIZE(moboard_led), + .led = moboard_led, + .flags = MC13783_LED_SLEWLIMTC, + .abmode = MC13783_LED_AB_DISABLED, + .tc1_period = MC13783_LED_PERIOD_10MS, + .tc2_period = MC13783_LED_PERIOD_10MS, +}; + +static struct mc13xxx_platform_data moboard_pmic = { + .regulators = { + .regulators = moboard_regulators, + .num_regulators = ARRAY_SIZE(moboard_regulators), + }, + .leds = &moboard_leds, + .flags = MC13XXX_USE_REGULATOR | MC13XXX_USE_RTC | + MC13XXX_USE_ADC | MC13XXX_USE_LED, +}; + +static struct spi_board_info moboard_spi_board_info[] __initdata = { + { + .modalias = "mc13783", + .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3), + .max_speed_hz = 300000, + .bus_num = 1, + .chip_select = 0, + .platform_data = &moboard_pmic, + .mode = SPI_CS_HIGH, + }, +}; + +static int moboard_spi2_cs[] = { + MXC_SPI_CS(1), +}; + +static const struct spi_imx_master moboard_spi2_pdata __initconst = { + .chipselect = moboard_spi2_cs, + .num_chipselect = ARRAY_SIZE(moboard_spi2_cs), +}; + +#define SDHC1_CD IOMUX_TO_GPIO(MX31_PIN_ATA_CS0) +#define SDHC1_WP IOMUX_TO_GPIO(MX31_PIN_ATA_CS1) + +static int moboard_sdhc1_get_ro(struct device *dev) +{ + return !gpio_get_value(SDHC1_WP); +} + +static int moboard_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC1_CD, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC1_CD); + + ret = gpio_request(SDHC1_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC1_WP); + + ret = request_irq(gpio_to_irq(SDHC1_CD), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "sdhc1-card-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(SDHC1_WP); +err_gpio_free: + gpio_free(SDHC1_CD); + + return ret; +} + +static void moboard_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(SDHC1_CD), data); + gpio_free(SDHC1_WP); + gpio_free(SDHC1_CD); +} + +static const struct imxmmc_platform_data sdhc1_pdata __initconst = { + .get_ro = moboard_sdhc1_get_ro, + .init = moboard_sdhc1_init, + .exit = moboard_sdhc1_exit, +}; + +/* + * this pin is dedicated for all mx31moboard systems, so we do it here + */ +#define USB_RESET_B IOMUX_TO_GPIO(MX31_PIN_GPIO1_0) +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS) + +#define OTG_EN_B IOMUX_TO_GPIO(MX31_PIN_USB_OC) +#define USBH2_EN_B IOMUX_TO_GPIO(MX31_PIN_SCK6) + +static void usb_xcvr_reset(void) +{ + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA0, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA1, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA2, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA3, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA4, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA5, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA6, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DATA7, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBOTG_CLK, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBOTG_DIR, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBOTG_NXT, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBOTG_STP, USB_PAD_CFG | PAD_CTL_100K_PU); + + mxc_iomux_set_gpr(MUX_PGP_UH2, true); + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, USB_PAD_CFG | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_SRXD6, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_STXD6, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_SFS3, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_SCK3, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_SRXD3, USB_PAD_CFG | PAD_CTL_100K_PD); + mxc_iomux_set_pad(MX31_PIN_STXD3, USB_PAD_CFG | PAD_CTL_100K_PD); + + gpio_request(OTG_EN_B, "usb-udc-en"); + gpio_direction_output(OTG_EN_B, 0); + gpio_request(USBH2_EN_B, "usbh2-en"); + gpio_direction_output(USBH2_EN_B, 0); + + gpio_request(USB_RESET_B, "usb-reset"); + gpio_direction_output(USB_RESET_B, 0); + mdelay(1); + gpio_set_value(USB_RESET_B, 1); + mdelay(1); +} + +static int moboard_usbh2_init_hw(struct platform_device *pdev) +{ + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); +} + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = moboard_usbh2_init_hw, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +static int __init moboard_usbh2_init(void) +{ + struct platform_device *pdev; + + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (!usbh2_pdata.otg) + return -ENODEV; + + pdev = imx31_add_mxc_ehci_hs(2, &usbh2_pdata); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} + +static struct gpio_led mx31moboard_leds[] = { + { + .name = "coreboard-led-0:red:running", + .default_trigger = "heartbeat", + .gpio = IOMUX_TO_GPIO(MX31_PIN_SVEN0), + }, { + .name = "coreboard-led-1:red", + .gpio = IOMUX_TO_GPIO(MX31_PIN_STX0), + }, { + .name = "coreboard-led-2:red", + .gpio = IOMUX_TO_GPIO(MX31_PIN_SRX0), + }, { + .name = "coreboard-led-3:red", + .gpio = IOMUX_TO_GPIO(MX31_PIN_SIMPD0), + }, +}; + +static struct gpio_led_platform_data mx31moboard_led_pdata = { + .num_leds = ARRAY_SIZE(mx31moboard_leds), + .leds = mx31moboard_leds, +}; + +static struct platform_device mx31moboard_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &mx31moboard_led_pdata, + }, +}; + +static const struct ipu_platform_data mx3_ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct platform_device *devices[] __initdata = { + &mx31moboard_flash, + &mx31moboard_leds_device, +}; + +static struct mx3_camera_pdata camera_pdata __initdata = { + .flags = MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10, + .mclk_10khz = 4800, +}; + +static phys_addr_t mx3_camera_base __initdata; +#define MX3_CAMERA_BUF_SIZE SZ_4M + +static int __init mx31moboard_init_cam(void) +{ + int dma, ret = -ENOMEM; + struct platform_device *pdev; + + imx31_add_ipu_core(&mx3_ipu_data); + + pdev = imx31_alloc_mx3_camera(&camera_pdata); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + dma = dma_declare_coherent_memory(&pdev->dev, + mx3_camera_base, mx3_camera_base, + MX3_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + if (!(dma & DMA_MEMORY_MAP)) + goto err; + + ret = platform_device_add(pdev); + if (ret) +err: + platform_device_put(pdev); + + return ret; + +} + +static int mx31moboard_baseboard; +core_param(mx31moboard_baseboard, mx31moboard_baseboard, int, 0444); + +/* + * Board specific initialization. + */ +static void __init mx31moboard_init(void) +{ + mxc_iomux_setup_multiple_pins(moboard_pins, ARRAY_SIZE(moboard_pins), + "moboard"); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + imx31_add_imx_uart0(&uart0_pdata); + imx31_add_imx_uart4(&uart4_pdata); + + imx31_add_imx_i2c0(&moboard_i2c0_data); + imx31_add_imx_i2c1(&moboard_i2c1_data); + + imx31_add_spi_imx1(&moboard_spi1_pdata); + imx31_add_spi_imx2(&moboard_spi2_pdata); + + gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3), "pmic-irq"); + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO1_3)); + spi_register_board_info(moboard_spi_board_info, + ARRAY_SIZE(moboard_spi_board_info)); + + imx31_add_mxc_mmc(0, &sdhc1_pdata); + + mx31moboard_init_cam(); + + usb_xcvr_reset(); + + moboard_usbh2_init(); + + switch (mx31moboard_baseboard) { + case MX31NOBOARD: + break; + case MX31DEVBOARD: + mx31moboard_devboard_init(); + break; + case MX31MARXBOT: + mx31moboard_marxbot_init(); + break; + case MX31SMARTBOT: + case MX31EYEBOT: + mx31moboard_smartbot_init(mx31moboard_baseboard); + break; + default: + printk(KERN_ERR "Illegal mx31moboard_baseboard type %d\n", + mx31moboard_baseboard); + } +} + +static void __init mx31moboard_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +struct sys_timer mx31moboard_timer = { + .init = mx31moboard_timer_init, +}; + +static void __init mx31moboard_reserve(void) +{ + /* reserve 4 MiB for mx3-camera */ + mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE, + MX3_CAMERA_BUF_SIZE); + memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE); + memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE); +} + +MACHINE_START(MX31MOBOARD, "EPFL Mobots mx31moboard") + /* Maintainer: Valentin Longchamp, EPFL Mobots group */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .reserve = mx31moboard_reserve, + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &mx31moboard_timer, + .init_machine = mx31moboard_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mx35_3ds.c b/arch/arm/mach-imx/mach-mx35_3ds.c new file mode 100644 index 00000000..882880ac --- /dev/null +++ b/arch/arm/mach-imx/mach-mx35_3ds.c @@ -0,0 +1,224 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009 Marc Kleine-Budde, Pengutronix + * + * Author: Fabio Estevam <fabio.estevam@freescale.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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. + */ + +/* + * This machine is known as: + * - i.MX35 3-Stack Development System + * - i.MX35 Platform Development Kit (i.MX35 PDK) + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/memory.h> +#include <linux/gpio.h> +#include <linux/usb/otg.h> + +#include <linux/mtd/physmap.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx35.h> +#include <mach/irqs.h> +#include <mach/3ds_debugboard.h> + +#include "devices-imx35.h" + +#define EXPIO_PARENT_INT (MXC_INTERNAL_IRQS + GPIO_PORTA + 1) + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct physmap_flash_data mx35pdk_flash_data = { + .width = 2, +}; + +static struct resource mx35pdk_flash_resource = { + .start = MX35_CS0_BASE_ADDR, + .end = MX35_CS0_BASE_ADDR + SZ_64M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device mx35pdk_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &mx35pdk_flash_data, + }, + .resource = &mx35pdk_flash_resource, + .num_resources = 1, +}; + +static const struct mxc_nand_platform_data mx35pdk_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct platform_device *devices[] __initdata = { + &mx35pdk_flash, +}; + +static iomux_v3_cfg_t mx35pdk_pads[] = { + /* UART1 */ + MX35_PAD_CTS1__UART1_CTS, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RXD1__UART1_RXD_MUX, + /* FEC */ + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + /* USBOTG */ + MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR, + MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC, + /* USBH1 */ + MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR, + MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC, + /* SDCARD */ + MX35_PAD_SD1_CMD__ESDHC1_CMD, + MX35_PAD_SD1_CLK__ESDHC1_CLK, + MX35_PAD_SD1_DATA0__ESDHC1_DAT0, + MX35_PAD_SD1_DATA1__ESDHC1_DAT1, + MX35_PAD_SD1_DATA2__ESDHC1_DAT2, + MX35_PAD_SD1_DATA3__ESDHC1_DAT3, + /* I2C1 */ + MX35_PAD_I2C1_CLK__I2C1_SCL, + MX35_PAD_I2C1_DAT__I2C1_SDA, +}; + +static int mx35_3ds_otg_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERNAL_PHY); +} + +/* OTG config */ +static const struct fsl_usb2_platform_data usb_otg_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI_WIDE, + .workaround = FLS_USB2_WORKAROUND_ENGCM09152, +/* + * ENGCM09152 also requires a hardware change. + * Please check the MX35 Chip Errata document for details. + */ +}; + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = mx35_3ds_otg_init, + .portsc = MXC_EHCI_MODE_UTMI, +}; + +static int mx35_3ds_usbh_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI | + MXC_EHCI_INTERNAL_PHY); +} + +/* USB HOST config */ +static const struct mxc_usbh_platform_data usb_host_pdata __initconst = { + .init = mx35_3ds_usbh_init, + .portsc = MXC_EHCI_MODE_SERIAL, +}; + +static int otg_mode_host; + +static int __init mx35_3ds_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", mx35_3ds_otg_mode); + +static const struct imxi2c_platform_data mx35_3ds_i2c0_data __initconst = { + .bitrate = 100000, +}; + +/* + * Board specific initialization. + */ +static void __init mx35_3ds_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(mx35pdk_pads, ARRAY_SIZE(mx35pdk_pads)); + + imx35_add_fec(NULL); + imx35_add_imx2_wdt(NULL); + platform_add_devices(devices, ARRAY_SIZE(devices)); + + imx35_add_imx_uart0(&uart_pdata); + + if (otg_mode_host) + imx35_add_mxc_ehci_otg(&otg_pdata); + + imx35_add_mxc_ehci_hs(&usb_host_pdata); + + if (!otg_mode_host) + imx35_add_fsl_usb2_udc(&usb_otg_pdata); + + imx35_add_mxc_nand(&mx35pdk_nand_board_info); + imx35_add_sdhci_esdhc_imx(0, NULL); + + if (mxc_expio_init(MX35_CS5_BASE_ADDR, EXPIO_PARENT_INT)) + pr_warn("Init of the debugboard failed, all " + "devices on the debugboard are unusable.\n"); + imx35_add_imx_i2c0(&mx35_3ds_i2c0_data); +} + +static void __init mx35pdk_timer_init(void) +{ + mx35_clocks_init(); +} + +struct sys_timer mx35pdk_timer = { + .init = mx35pdk_timer_init, +}; + +MACHINE_START(MX35_3DS, "Freescale MX35PDK") + /* Maintainer: Freescale Semiconductor, Inc */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx35_map_io, + .init_early = imx35_init_early, + .init_irq = mx35_init_irq, + .timer = &mx35pdk_timer, + .init_machine = mx35_3ds_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-mxt_td60.c b/arch/arm/mach-imx/mach-mxt_td60.c new file mode 100644 index 00000000..27745415 --- /dev/null +++ b/arch/arm/mach-imx/mach-mxt_td60.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2006-2007 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. + */ + +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <linux/gpio.h> +#include <mach/iomux-mx27.h> +#include <linux/i2c/pca953x.h> + +#include "devices-imx27.h" + +static const int mxt_td60_pins[] __initconst = { + /* UART0 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* UART1 */ + PE3_PF_UART2_CTS, + PE4_PF_UART2_RTS, + PE6_PF_UART2_TXD, + PE7_PF_UART2_RXD, + /* UART2 */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + PE10_PF_UART3_CTS, + PE11_PF_UART3_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* I2C1 */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, + /* I2C2 */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* FB */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA25_PF_CLS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* OWIRE */ + PE16_AF_OWIRE, + /* SDHC1*/ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + PF8_AF_ATA_IORDY, + /* SDHC2*/ + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, +}; + +static const struct mxc_nand_platform_data +mxt_td60_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static const struct imxi2c_platform_data mxt_td60_i2c0_data __initconst = { + .bitrate = 100000, +}; + +/* PCA9557 */ +static int mxt_td60_pca9557_setup(struct i2c_client *client, + unsigned gpio_base, unsigned ngpio, + void *context) +{ + static int mxt_td60_gpio_value[] = { + -1, -1, -1, -1, -1, -1, -1, 1 + }; + int n; + + for (n = 0; n < ARRAY_SIZE(mxt_td60_gpio_value); ++n) { + gpio_request(gpio_base + n, "MXT_TD60 GPIO Exp"); + if (mxt_td60_gpio_value[n] < 0) + gpio_direction_input(gpio_base + n); + else + gpio_direction_output(gpio_base + n, + mxt_td60_gpio_value[n]); + gpio_export(gpio_base + n, 0); + } + + return 0; +} + +static struct pca953x_platform_data mxt_td60_pca9557_pdata = { + .gpio_base = 240, /* place PCA9557 after all MX27 gpio pins */ + .invert = 0, /* Do not invert */ + .setup = mxt_td60_pca9557_setup, +}; + +static struct i2c_board_info mxt_td60_i2c_devices[] = { + { + I2C_BOARD_INFO("pca9557", 0x18), + .platform_data = &mxt_td60_pca9557_pdata, + }, +}; + +static const struct imxi2c_platform_data mxt_td60_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static struct i2c_board_info mxt_td60_i2c2_devices[] = { +}; + +static struct imx_fb_videomode mxt_td60_modes[] = { + { + .mode = { + .name = "Chimei LW700AT9003", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = 30303, + .hsync_len = 64, + .left_margin = 0x67, + .right_margin = 0x68, + .vsync_len = 16, + .upper_margin = 0x0f, + .lower_margin = 0x0f, + }, + .bpp = 16, + .pcr = 0xFA208B83, + }, +}; + +static const struct imx_fb_platform_data mxt_td60_fb_data __initconst = { + .mode = mxt_td60_modes, + .num_modes = ARRAY_SIZE(mxt_td60_modes), + + /* + * - HSYNC active high + * - VSYNC active high + * - clk notenabled while idle + * - clock inverted + * - data not inverted + * - data enable low active + * - enable sharp mode + */ + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, +}; + +static int mxt_td60_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + return request_irq(IRQ_GPIOF(8), detect_irq, IRQF_TRIGGER_FALLING, + "sdhc1-card-detect", data); +} + +static void mxt_td60_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOF(8), data); +} + +static const struct imxmmc_platform_data sdhc1_pdata __initconst = { + .init = mxt_td60_sdhc1_init, + .exit = mxt_td60_sdhc1_exit, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static void __init mxt_td60_board_init(void) +{ + mxc_gpio_setup_multiple_pins(mxt_td60_pins, ARRAY_SIZE(mxt_td60_pins), + "MXT_TD60"); + + imx27_add_imx_uart0(&uart_pdata); + imx27_add_imx_uart1(&uart_pdata); + imx27_add_imx_uart2(&uart_pdata); + imx27_add_mxc_nand(&mxt_td60_nand_board_info); + + i2c_register_board_info(0, mxt_td60_i2c_devices, + ARRAY_SIZE(mxt_td60_i2c_devices)); + + i2c_register_board_info(1, mxt_td60_i2c2_devices, + ARRAY_SIZE(mxt_td60_i2c2_devices)); + + imx27_add_imx_i2c(0, &mxt_td60_i2c0_data); + imx27_add_imx_i2c(1, &mxt_td60_i2c1_data); + imx27_add_imx_fb(&mxt_td60_fb_data); + imx27_add_mxc_mmc(0, &sdhc1_pdata); + imx27_add_fec(NULL); +} + +static void __init mxt_td60_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer mxt_td60_timer = { + .init = mxt_td60_timer_init, +}; + +MACHINE_START(MXT_TD60, "Maxtrack i-MXT TD60") + /* maintainer: Maxtrack Industrial */ + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &mxt_td60_timer, + .init_machine = mxt_td60_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-pca100.c b/arch/arm/mach-imx/mach-pca100.c new file mode 100644 index 00000000..bbddc5a1 --- /dev/null +++ b/arch/arm/mach-imx/mach-pca100.c @@ -0,0 +1,442 @@ +/* + * Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix + * Copyright (C) 2009 Sascha Hauer (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/i2c/at24.h> +#include <linux/dma-mapping.h> +#include <linux/spi/spi.h> +#include <linux/spi/eeprom.h> +#include <linux/irq.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx27.h> +#include <asm/mach/time.h> +#include <mach/audmux.h> +#include <mach/irqs.h> +#include <mach/ulpi.h> + +#include "devices-imx27.h" + +#define OTG_PHY_CS_GPIO (GPIO_PORTB + 23) +#define USBH2_PHY_CS_GPIO (GPIO_PORTB + 24) +#define SPI1_SS0 (GPIO_PORTD + 28) +#define SPI1_SS1 (GPIO_PORTD + 27) +#define SD2_CD (GPIO_PORTC + 29) + +static const int pca100_pins[] __initconst = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* SDHC */ + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, + SD2_CD | GPIO_GPIO | GPIO_IN, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* SSI1 */ + PC20_PF_SSI1_FS, + PC21_PF_SSI1_RXD, + PC22_PF_SSI1_TXD, + PC23_PF_SSI1_CLK, + /* onboard I2C */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* external I2C */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, + /* SPI1 */ + PD25_PF_CSPI1_RDY, + PD29_PF_CSPI1_SCLK, + PD30_PF_CSPI1_MISO, + PD31_PF_CSPI1_MOSI, + /* OTG */ + OTG_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT, + PC7_PF_USBOTG_DATA5, + PC8_PF_USBOTG_DATA6, + PC9_PF_USBOTG_DATA0, + PC10_PF_USBOTG_DATA2, + PC11_PF_USBOTG_DATA1, + PC12_PF_USBOTG_DATA4, + PC13_PF_USBOTG_DATA3, + PE0_PF_USBOTG_NXT, + PE1_PF_USBOTG_STP, + PE2_PF_USBOTG_DIR, + PE24_PF_USBOTG_CLK, + PE25_PF_USBOTG_DATA7, + /* USBH2 */ + USBH2_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT, + PA0_PF_USBH2_CLK, + PA1_PF_USBH2_DIR, + PA2_PF_USBH2_DATA7, + PA3_PF_USBH2_NXT, + PA4_PF_USBH2_STP, + PD19_AF_USBH2_DATA4, + PD20_AF_USBH2_DATA3, + PD21_AF_USBH2_DATA6, + PD22_AF_USBH2_DATA0, + PD23_AF_USBH2_DATA2, + PD24_AF_USBH2_DATA1, + PD26_AF_USBH2_DATA5, + /* display */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA26_PF_PS, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA31_PF_OE_ACD, + /* free GPIO */ + GPIO_PORTC | 31 | GPIO_GPIO | GPIO_IN, /* GPIO0_IRQ */ + GPIO_PORTC | 25 | GPIO_GPIO | GPIO_IN, /* GPIO1_IRQ */ + GPIO_PORTE | 5 | GPIO_GPIO | GPIO_IN, /* GPIO2_IRQ */ +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct mxc_nand_platform_data +pca100_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static const struct imxi2c_platform_data pca100_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static struct at24_platform_data board_eeprom = { + .byte_len = 4096, + .page_size = 32, + .flags = AT24_FLAG_ADDR16, +}; + +static struct i2c_board_info pca100_i2c_devices[] = { + { + I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */ + .platform_data = &board_eeprom, + }, { + I2C_BOARD_INFO("pcf8563", 0x51), + }, { + I2C_BOARD_INFO("lm75", 0x4a), + } +}; + +static struct spi_eeprom at25320 = { + .name = "at25320an", + .byte_len = 4096, + .page_size = 32, + .flags = EE_ADDR2, +}; + +static struct spi_board_info pca100_spi_board_info[] __initdata = { + { + .modalias = "at25", + .max_speed_hz = 30000, + .bus_num = 0, + .chip_select = 1, + .platform_data = &at25320, + }, +}; + +static int pca100_spi_cs[] = {SPI1_SS0, SPI1_SS1}; + +static const struct spi_imx_master pca100_spi0_data __initconst = { + .chipselect = pca100_spi_cs, + .num_chipselect = ARRAY_SIZE(pca100_spi_cs), +}; + +static void pca100_ac97_warm_reset(struct snd_ac97 *ac97) +{ + mxc_gpio_mode(GPIO_PORTC | 20 | GPIO_GPIO | GPIO_OUT); + gpio_set_value(GPIO_PORTC + 20, 1); + udelay(2); + gpio_set_value(GPIO_PORTC + 20, 0); + mxc_gpio_mode(PC20_PF_SSI1_FS); + msleep(2); +} + +static void pca100_ac97_cold_reset(struct snd_ac97 *ac97) +{ + mxc_gpio_mode(GPIO_PORTC | 20 | GPIO_GPIO | GPIO_OUT); /* FS */ + gpio_set_value(GPIO_PORTC + 20, 0); + mxc_gpio_mode(GPIO_PORTC | 22 | GPIO_GPIO | GPIO_OUT); /* TX */ + gpio_set_value(GPIO_PORTC + 22, 0); + mxc_gpio_mode(GPIO_PORTC | 28 | GPIO_GPIO | GPIO_OUT); /* reset */ + gpio_set_value(GPIO_PORTC + 28, 0); + udelay(10); + gpio_set_value(GPIO_PORTC + 28, 1); + mxc_gpio_mode(PC20_PF_SSI1_FS); + mxc_gpio_mode(PC22_PF_SSI1_TXD); + msleep(2); +} + +static const struct imx_ssi_platform_data pca100_ssi_pdata __initconst = { + .ac97_reset = pca100_ac97_cold_reset, + .ac97_warm_reset = pca100_ac97_warm_reset, + .flags = IMX_SSI_USE_AC97, +}; + +static int pca100_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = request_irq(IRQ_GPIOC(29), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "imx-mmc-detect", data); + if (ret) + printk(KERN_ERR + "pca100: Failed to reuest irq for sd/mmc detection\n"); + + return ret; +} + +static void pca100_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOC(29), data); +} + +static const struct imxmmc_platform_data sdhc_pdata __initconst = { + .init = pca100_sdhc2_init, + .exit = pca100_sdhc2_exit, +}; + +static int otg_phy_init(struct platform_device *pdev) +{ + gpio_set_value(OTG_PHY_CS_GPIO, 0); + + mdelay(10); + + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = otg_phy_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static int usbh2_phy_init(struct platform_device *pdev) +{ + gpio_set_value(USBH2_PHY_CS_GPIO, 0); + + mdelay(10); + + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = usbh2_phy_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +static int otg_mode_host; + +static int __init pca100_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", pca100_otg_mode); + +/* framebuffer info */ +static struct imx_fb_videomode pca100_fb_modes[] = { + { + .mode = { + .name = "EMERGING-ETV570G0DHU", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 39722, /* in ps (25.175 MHz) */ + .hsync_len = 30, + .left_margin = 114, + .right_margin = 16, + .vsync_len = 3, + .upper_margin = 32, + .lower_margin = 0, + }, + /* + * TFT + * Pixel pol active high + * HSYNC active low + * VSYNC active low + * use HSYNC for ACD count + * line clock disable while idle + * always enable line clock even if no data + */ + .pcr = 0xf0c08080, + .bpp = 16, + }, +}; + +static const struct imx_fb_platform_data pca100_fb_data __initconst = { + .mode = pca100_fb_modes, + .num_modes = ARRAY_SIZE(pca100_fb_modes), + + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, +}; + +static void __init pca100_init(void) +{ + int ret; + + /* SSI unit */ + mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, + MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */ + MXC_AUDMUX_V1_PCR_TFCSEL(3) | + MXC_AUDMUX_V1_PCR_TCLKDIR | /* clock is output */ + MXC_AUDMUX_V1_PCR_RXDSEL(3)); + mxc_audmux_v1_configure_port(3, + MXC_AUDMUX_V1_PCR_SYN | /* 4wire mode */ + MXC_AUDMUX_V1_PCR_TFCSEL(0) | + MXC_AUDMUX_V1_PCR_TFSDIR | + MXC_AUDMUX_V1_PCR_RXDSEL(0)); + + ret = mxc_gpio_setup_multiple_pins(pca100_pins, + ARRAY_SIZE(pca100_pins), "PCA100"); + if (ret) + printk(KERN_ERR "pca100: Failed to setup pins (%d)\n", ret); + + imx27_add_imx_ssi(0, &pca100_ssi_pdata); + + imx27_add_imx_uart0(&uart_pdata); + + imx27_add_mxc_mmc(1, &sdhc_pdata); + + imx27_add_mxc_nand(&pca100_nand_board_info); + + /* only the i2c master 1 is used on this CPU card */ + i2c_register_board_info(1, pca100_i2c_devices, + ARRAY_SIZE(pca100_i2c_devices)); + + imx27_add_imx_i2c(1, &pca100_i2c1_data); + + mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_IN); + mxc_gpio_mode(GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN); + spi_register_board_info(pca100_spi_board_info, + ARRAY_SIZE(pca100_spi_board_info)); + imx27_add_spi_imx0(&pca100_spi0_data); + + gpio_request(OTG_PHY_CS_GPIO, "usb-otg-cs"); + gpio_direction_output(OTG_PHY_CS_GPIO, 1); + gpio_request(USBH2_PHY_CS_GPIO, "usb-host2-cs"); + gpio_direction_output(USBH2_PHY_CS_GPIO, 1); + + if (otg_mode_host) { + otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + + if (otg_pdata.otg) + imx27_add_mxc_ehci_otg(&otg_pdata); + } else { + gpio_set_value(OTG_PHY_CS_GPIO, 0); + imx27_add_fsl_usb2_udc(&otg_device_pdata); + } + + usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, + ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT); + + if (usbh2_pdata.otg) + imx27_add_mxc_ehci_hs(2, &usbh2_pdata); + + imx27_add_imx_fb(&pca100_fb_data); + + imx27_add_fec(NULL); + imx27_add_imx2_wdt(NULL); + imx27_add_mxc_w1(NULL); +} + +static void __init pca100_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer pca100_timer = { + .init = pca100_timer_init, +}; + +MACHINE_START(PCA100, "phyCARD-i.MX27") + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .init_machine = pca100_init, + .timer = &pca100_timer, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm037.c b/arch/arm/mach-imx/mach-pcm037.c new file mode 100644 index 00000000..89c213b8 --- /dev/null +++ b/arch/arm/mach-imx/mach-pcm037.c @@ -0,0 +1,696 @@ +/* + * Copyright (C) 2008 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/plat-ram.h> +#include <linux/memory.h> +#include <linux/gpio.h> +#include <linux/smsc911x.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/i2c/at24.h> +#include <linux/delay.h> +#include <linux/spi/spi.h> +#include <linux/irq.h> +#include <linux/can/platform/sja1000.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> +#include <linux/gfp.h> +#include <linux/memblock.h> + +#include <media/soc_camera.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx3.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" +#include "pcm037.h" + +static enum pcm037_board_variant pcm037_instance = PCM037_PCM970; + +static int __init pcm037_variant_setup(char *str) +{ + if (!strcmp("eet", str)) + pcm037_instance = PCM037_EET; + else if (strcmp("pcm970", str)) + pr_warning("Unknown pcm037 baseboard variant %s\n", str); + + return 1; +} + +/* Supported values: "pcm970" (default) and "eet" */ +__setup("pcm037_variant=", pcm037_variant_setup); + +enum pcm037_board_variant pcm037_variant(void) +{ + return pcm037_instance; +} + +/* UART1 with RTS/CTS handshake signals */ +static unsigned int pcm037_uart1_handshake_pins[] = { + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, +}; + +/* UART1 without RTS/CTS handshake signals */ +static unsigned int pcm037_uart1_pins[] = { + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, +}; + +static unsigned int pcm037_pins[] = { + /* I2C */ + MX31_PIN_CSPI2_MOSI__SCL, + MX31_PIN_CSPI2_MISO__SDA, + MX31_PIN_CSPI2_SS2__I2C3_SDA, + MX31_PIN_CSPI2_SCLK__I2C3_SCL, + /* SDHC1 */ + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + IOMUX_MODE(MX31_PIN_SCK6, IOMUX_CONFIG_GPIO), /* card detect */ + IOMUX_MODE(MX31_PIN_SFS6, IOMUX_CONFIG_GPIO), /* write protect */ + /* SPI1 */ + MX31_PIN_CSPI1_MOSI__MOSI, + MX31_PIN_CSPI1_MISO__MISO, + MX31_PIN_CSPI1_SCLK__SCLK, + MX31_PIN_CSPI1_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI1_SS0__SS0, + MX31_PIN_CSPI1_SS1__SS1, + MX31_PIN_CSPI1_SS2__SS2, + /* UART2 */ + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + /* UART3 */ + MX31_PIN_CSPI3_MOSI__RXD3, + MX31_PIN_CSPI3_MISO__TXD3, + MX31_PIN_CSPI3_SCLK__RTS3, + MX31_PIN_CSPI3_SPI_RDY__CTS3, + /* LAN9217 irq pin */ + IOMUX_MODE(MX31_PIN_GPIO3_1, IOMUX_CONFIG_GPIO), + /* Onewire */ + MX31_PIN_BATT_LINE__OWIRE, + /* Framebuffer */ + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_DRDY0__DRDY0, + MX31_PIN_D3_REV__D3_REV, + MX31_PIN_CONTRAST__CONTRAST, + MX31_PIN_D3_SPL__D3_SPL, + MX31_PIN_D3_CLS__D3_CLS, + MX31_PIN_LCS0__GPI03_23, + /* CSI */ + IOMUX_MODE(MX31_PIN_CSI_D5, IOMUX_CONFIG_GPIO), + MX31_PIN_CSI_D6__CSI_D6, + MX31_PIN_CSI_D7__CSI_D7, + MX31_PIN_CSI_D8__CSI_D8, + MX31_PIN_CSI_D9__CSI_D9, + MX31_PIN_CSI_D10__CSI_D10, + MX31_PIN_CSI_D11__CSI_D11, + MX31_PIN_CSI_D12__CSI_D12, + MX31_PIN_CSI_D13__CSI_D13, + MX31_PIN_CSI_D14__CSI_D14, + MX31_PIN_CSI_D15__CSI_D15, + MX31_PIN_CSI_HSYNC__CSI_HSYNC, + MX31_PIN_CSI_MCLK__CSI_MCLK, + MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, + MX31_PIN_CSI_VSYNC__CSI_VSYNC, + /* GPIO */ + IOMUX_MODE(MX31_PIN_ATA_DMACK, IOMUX_CONFIG_GPIO), + /* OTG */ + MX31_PIN_USBOTG_DATA0__USBOTG_DATA0, + MX31_PIN_USBOTG_DATA1__USBOTG_DATA1, + MX31_PIN_USBOTG_DATA2__USBOTG_DATA2, + MX31_PIN_USBOTG_DATA3__USBOTG_DATA3, + MX31_PIN_USBOTG_DATA4__USBOTG_DATA4, + MX31_PIN_USBOTG_DATA5__USBOTG_DATA5, + MX31_PIN_USBOTG_DATA6__USBOTG_DATA6, + MX31_PIN_USBOTG_DATA7__USBOTG_DATA7, + MX31_PIN_USBOTG_CLK__USBOTG_CLK, + MX31_PIN_USBOTG_DIR__USBOTG_DIR, + MX31_PIN_USBOTG_NXT__USBOTG_NXT, + MX31_PIN_USBOTG_STP__USBOTG_STP, + /* USB host 2 */ + IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_STXD3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SRXD3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SCK3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SFS3, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_STXD6, IOMUX_CONFIG_FUNC), + IOMUX_MODE(MX31_PIN_SRXD6, IOMUX_CONFIG_FUNC), +}; + +static struct physmap_flash_data pcm037_flash_data = { + .width = 2, +}; + +static struct resource pcm037_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm037_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &pcm037_flash_data, + }, + .resource = &pcm037_flash_resource, + .num_resources = 1, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct resource smsc911x_resources[] = { + { + .start = MX31_CS1_BASE_ADDR + 0x300, + .end = MX31_CS1_BASE_ADDR + 0x300 + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IOMUX_TO_IRQ(MX31_PIN_GPIO3_1), + .end = IOMUX_TO_IRQ(MX31_PIN_GPIO3_1), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct smsc911x_platform_config smsc911x_info = { + .flags = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY | + SMSC911X_SAVE_MAC_ADDRESS, + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + +static struct platform_device pcm037_eth = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smsc911x_resources), + .resource = smsc911x_resources, + .dev = { + .platform_data = &smsc911x_info, + }, +}; + +static struct platdata_mtd_ram pcm038_sram_data = { + .bankwidth = 2, +}; + +static struct resource pcm038_sram_resource = { + .start = MX31_CS4_BASE_ADDR, + .end = MX31_CS4_BASE_ADDR + 512 * 1024 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm037_sram_device = { + .name = "mtd-ram", + .id = 0, + .dev = { + .platform_data = &pcm038_sram_data, + }, + .num_resources = 1, + .resource = &pcm038_sram_resource, +}; + +static const struct mxc_nand_platform_data +pcm037_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static const struct imxi2c_platform_data pcm037_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static const struct imxi2c_platform_data pcm037_i2c2_data __initconst = { + .bitrate = 20000, +}; + +static struct at24_platform_data board_eeprom = { + .byte_len = 4096, + .page_size = 32, + .flags = AT24_FLAG_ADDR16, +}; + +static int pcm037_camera_power(struct device *dev, int on) +{ + /* disable or enable the camera in X7 or X8 PCM970 connector */ + gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), !on); + return 0; +} + +static struct i2c_board_info pcm037_i2c_camera[] = { + { + I2C_BOARD_INFO("mt9t031", 0x5d), + }, { + I2C_BOARD_INFO("mt9v022", 0x48), + }, +}; + +static struct soc_camera_link iclink_mt9v022 = { + .bus_id = 0, /* Must match with the camera ID */ + .board_info = &pcm037_i2c_camera[1], + .i2c_adapter_id = 2, +}; + +static struct soc_camera_link iclink_mt9t031 = { + .bus_id = 0, /* Must match with the camera ID */ + .power = pcm037_camera_power, + .board_info = &pcm037_i2c_camera[0], + .i2c_adapter_id = 2, +}; + +static struct i2c_board_info pcm037_i2c_devices[] = { + { + I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */ + .platform_data = &board_eeprom, + }, { + I2C_BOARD_INFO("pcf8563", 0x51), + } +}; + +static struct platform_device pcm037_mt9t031 = { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &iclink_mt9t031, + }, +}; + +static struct platform_device pcm037_mt9v022 = { + .name = "soc-camera-pdrv", + .id = 1, + .dev = { + .platform_data = &iclink_mt9v022, + }, +}; + +/* Not connected by default */ +#ifdef PCM970_SDHC_RW_SWITCH +static int pcm970_sdhc1_get_ro(struct device *dev) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_SFS6)); +} +#endif + +#define SDHC1_GPIO_WP IOMUX_TO_GPIO(MX31_PIN_SFS6) +#define SDHC1_GPIO_DET IOMUX_TO_GPIO(MX31_PIN_SCK6) + +static int pcm970_sdhc1_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC1_GPIO_DET, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC1_GPIO_DET); + +#ifdef PCM970_SDHC_RW_SWITCH + ret = gpio_request(SDHC1_GPIO_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC1_GPIO_WP); +#endif + + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "sdhc-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: +#ifdef PCM970_SDHC_RW_SWITCH + gpio_free(SDHC1_GPIO_WP); +err_gpio_free: +#endif + gpio_free(SDHC1_GPIO_DET); + + return ret; +} + +static void pcm970_sdhc1_exit(struct device *dev, void *data) +{ + free_irq(IOMUX_TO_IRQ(MX31_PIN_SCK6), data); + gpio_free(SDHC1_GPIO_DET); + gpio_free(SDHC1_GPIO_WP); +} + +static const struct imxmmc_platform_data sdhc_pdata __initconst = { +#ifdef PCM970_SDHC_RW_SWITCH + .get_ro = pcm970_sdhc1_get_ro, +#endif + .init = pcm970_sdhc1_init, + .exit = pcm970_sdhc1_exit, +}; + +struct mx3_camera_pdata camera_pdata __initdata = { + .flags = MX3_CAMERA_DATAWIDTH_8 | MX3_CAMERA_DATAWIDTH_10, + .mclk_10khz = 2000, +}; + +static phys_addr_t mx3_camera_base __initdata; +#define MX3_CAMERA_BUF_SIZE SZ_4M + +static int __init pcm037_init_camera(void) +{ + int dma, ret = -ENOMEM; + struct platform_device *pdev = imx31_alloc_mx3_camera(&camera_pdata); + + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + dma = dma_declare_coherent_memory(&pdev->dev, + mx3_camera_base, mx3_camera_base, + MX3_CAMERA_BUF_SIZE, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE); + if (!(dma & DMA_MEMORY_MAP)) + goto err; + + ret = platform_device_add(pdev); + if (ret) +err: + platform_device_put(pdev); + + return ret; +} + +static struct platform_device *devices[] __initdata = { + &pcm037_flash, + &pcm037_sram_device, + &pcm037_mt9t031, + &pcm037_mt9v022, +}; + +static const struct ipu_platform_data mx3_ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static const struct fb_videomode fb_modedb[] = { + { + /* 240x320 @ 60 Hz Sharp */ + .name = "Sharp-LQ035Q7DH06-QVGA", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 185925, + .left_margin = 9, + .right_margin = 16, + .upper_margin = 7, + .lower_margin = 9, + .hsync_len = 1, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | + FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, { + /* 240x320 @ 60 Hz */ + .name = "TX090", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 38255, + .left_margin = 144, + .right_margin = 0, + .upper_margin = 7, + .lower_margin = 40, + .hsync_len = 96, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, { + /* 240x320 @ 60 Hz */ + .name = "CMEL-OLED", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 185925, + .left_margin = 9, + .right_margin = 16, + .upper_margin = 7, + .lower_margin = 9, + .hsync_len = 1, + .vsync_len = 1, + .sync = FB_SYNC_OE_ACT_HIGH | FB_SYNC_CLK_INVERT, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static struct mx3fb_platform_data mx3fb_pdata = { + .name = "Sharp-LQ035Q7DH06-QVGA", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +static struct resource pcm970_sja1000_resources[] = { + { + .start = MX31_CS5_BASE_ADDR, + .end = MX31_CS5_BASE_ADDR + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IOMUX_TO_IRQ(IOMUX_PIN(48, 105)), + .end = IOMUX_TO_IRQ(IOMUX_PIN(48, 105)), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, + }, +}; + +struct sja1000_platform_data pcm970_sja1000_platform_data = { + .osc_freq = 16000000, + .ocr = OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL, + .cdr = CDR_CBP, +}; + +static struct platform_device pcm970_sja1000 = { + .name = "sja1000_platform", + .dev = { + .platform_data = &pcm970_sja1000_platform_data, + }, + .resource = pcm970_sja1000_resources, + .num_resources = ARRAY_SIZE(pcm970_sja1000_resources), +}; + +static int pcm037_otg_init(struct platform_device *pdev) +{ + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = pcm037_otg_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static int pcm037_usbh2_init(struct platform_device *pdev) +{ + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data usbh2_pdata __initdata = { + .init = pcm037_usbh2_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +static int otg_mode_host; + +static int __init pcm037_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", pcm037_otg_mode); + +/* + * Board specific initialization. + */ +static void __init pcm037_init(void) +{ + int ret; + + mxc_iomux_set_gpr(MUX_PGP_UH2, 1); + + mxc_iomux_setup_multiple_pins(pcm037_pins, ARRAY_SIZE(pcm037_pins), + "pcm037"); + +#define H2_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS \ + | PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + + mxc_iomux_set_pad(MX31_PIN_USBH2_CLK, H2_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DIR, H2_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_NXT, H2_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_STP, H2_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA0, H2_PAD_CFG); /* USBH2_DATA0 */ + mxc_iomux_set_pad(MX31_PIN_USBH2_DATA1, H2_PAD_CFG); /* USBH2_DATA1 */ + mxc_iomux_set_pad(MX31_PIN_SRXD6, H2_PAD_CFG); /* USBH2_DATA2 */ + mxc_iomux_set_pad(MX31_PIN_STXD6, H2_PAD_CFG); /* USBH2_DATA3 */ + mxc_iomux_set_pad(MX31_PIN_SFS3, H2_PAD_CFG); /* USBH2_DATA4 */ + mxc_iomux_set_pad(MX31_PIN_SCK3, H2_PAD_CFG); /* USBH2_DATA5 */ + mxc_iomux_set_pad(MX31_PIN_SRXD3, H2_PAD_CFG); /* USBH2_DATA6 */ + mxc_iomux_set_pad(MX31_PIN_STXD3, H2_PAD_CFG); /* USBH2_DATA7 */ + + if (pcm037_variant() == PCM037_EET) + mxc_iomux_setup_multiple_pins(pcm037_uart1_pins, + ARRAY_SIZE(pcm037_uart1_pins), "pcm037_uart1"); + else + mxc_iomux_setup_multiple_pins(pcm037_uart1_handshake_pins, + ARRAY_SIZE(pcm037_uart1_handshake_pins), + "pcm037_uart1"); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + imx31_add_imx2_wdt(NULL); + imx31_add_imx_uart0(&uart_pdata); + /* XXX: should't this have .flags = 0 (i.e. no RTSCTS) on PCM037_EET? */ + imx31_add_imx_uart1(&uart_pdata); + imx31_add_imx_uart2(&uart_pdata); + + imx31_add_mxc_w1(NULL); + + /* LAN9217 IRQ pin */ + ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1), "lan9217-irq"); + if (ret) + pr_warning("could not get LAN irq gpio\n"); + else { + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_GPIO3_1)); + platform_device_register(&pcm037_eth); + } + + + /* I2C adapters and devices */ + i2c_register_board_info(1, pcm037_i2c_devices, + ARRAY_SIZE(pcm037_i2c_devices)); + + imx31_add_imx_i2c1(&pcm037_i2c1_data); + imx31_add_imx_i2c2(&pcm037_i2c2_data); + + imx31_add_mxc_nand(&pcm037_nand_board_info); + imx31_add_mxc_mmc(0, &sdhc_pdata); + imx31_add_ipu_core(&mx3_ipu_data); + imx31_add_mx3_sdc_fb(&mx3fb_pdata); + + /* CSI */ + /* Camera power: default - off */ + ret = gpio_request(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), "mt9t031-power"); + if (!ret) + gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_CSI_D5), 1); + else + iclink_mt9t031.power = NULL; + + pcm037_init_camera(); + + platform_device_register(&pcm970_sja1000); + + if (otg_mode_host) { + otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (otg_pdata.otg) + imx31_add_mxc_ehci_otg(&otg_pdata); + } + + usbh2_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (usbh2_pdata.otg) + imx31_add_mxc_ehci_hs(2, &usbh2_pdata); + + if (!otg_mode_host) + imx31_add_fsl_usb2_udc(&otg_device_pdata); + +} + +static void __init pcm037_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +struct sys_timer pcm037_timer = { + .init = pcm037_timer_init, +}; + +static void __init pcm037_reserve(void) +{ + /* reserve 4 MiB for mx3-camera */ + mx3_camera_base = memblock_alloc(MX3_CAMERA_BUF_SIZE, + MX3_CAMERA_BUF_SIZE); + memblock_free(mx3_camera_base, MX3_CAMERA_BUF_SIZE); + memblock_remove(mx3_camera_base, MX3_CAMERA_BUF_SIZE); +} + +MACHINE_START(PCM037, "Phytec Phycore pcm037") + /* Maintainer: Pengutronix */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .reserve = pcm037_reserve, + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &pcm037_timer, + .init_machine = pcm037_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm037_eet.c b/arch/arm/mach-imx/mach-pcm037_eet.c new file mode 100644 index 00000000..1b7606be --- /dev/null +++ b/arch/arm/mach-imx/mach-pcm037_eet.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2009 + * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> + +#include <mach/common.h> +#include <mach/iomux-mx3.h> + +#include <asm/mach-types.h> + +#include "pcm037.h" +#include "devices-imx31.h" + +static unsigned int pcm037_eet_pins[] = { + /* Reserve and hardwire GPIO 57 high - S6E63D6 chipselect */ + IOMUX_MODE(MX31_PIN_KEY_COL7, IOMUX_CONFIG_GPIO), + /* GPIO keys */ + IOMUX_MODE(MX31_PIN_GPIO1_0, IOMUX_CONFIG_GPIO), /* 0 */ + IOMUX_MODE(MX31_PIN_GPIO1_1, IOMUX_CONFIG_GPIO), /* 1 */ + IOMUX_MODE(MX31_PIN_GPIO1_2, IOMUX_CONFIG_GPIO), /* 2 */ + IOMUX_MODE(MX31_PIN_GPIO1_3, IOMUX_CONFIG_GPIO), /* 3 */ + IOMUX_MODE(MX31_PIN_SVEN0, IOMUX_CONFIG_GPIO), /* 32 */ + IOMUX_MODE(MX31_PIN_STX0, IOMUX_CONFIG_GPIO), /* 33 */ + IOMUX_MODE(MX31_PIN_SRX0, IOMUX_CONFIG_GPIO), /* 34 */ + IOMUX_MODE(MX31_PIN_SIMPD0, IOMUX_CONFIG_GPIO), /* 35 */ + IOMUX_MODE(MX31_PIN_RTS1, IOMUX_CONFIG_GPIO), /* 38 */ + IOMUX_MODE(MX31_PIN_CTS1, IOMUX_CONFIG_GPIO), /* 39 */ + IOMUX_MODE(MX31_PIN_KEY_ROW4, IOMUX_CONFIG_GPIO), /* 50 */ + IOMUX_MODE(MX31_PIN_KEY_ROW5, IOMUX_CONFIG_GPIO), /* 51 */ + IOMUX_MODE(MX31_PIN_KEY_ROW6, IOMUX_CONFIG_GPIO), /* 52 */ + IOMUX_MODE(MX31_PIN_KEY_ROW7, IOMUX_CONFIG_GPIO), /* 53 */ + + /* LEDs */ + IOMUX_MODE(MX31_PIN_DTR_DTE1, IOMUX_CONFIG_GPIO), /* 44 */ + IOMUX_MODE(MX31_PIN_DSR_DTE1, IOMUX_CONFIG_GPIO), /* 45 */ + IOMUX_MODE(MX31_PIN_KEY_COL5, IOMUX_CONFIG_GPIO), /* 55 */ + IOMUX_MODE(MX31_PIN_KEY_COL6, IOMUX_CONFIG_GPIO), /* 56 */ +}; + +/* SPI */ +static struct spi_board_info pcm037_spi_dev[] = { + { + .modalias = "dac124s085", + .max_speed_hz = 400000, + .bus_num = 0, + .chip_select = 0, /* Index in pcm037_spi1_cs[] */ + .mode = SPI_CPHA, + }, +}; + +/* Platform Data for MXC CSPI */ +static int pcm037_spi1_cs[] = {MXC_SPI_CS(1), IOMUX_TO_GPIO(MX31_PIN_KEY_COL7)}; + +static const struct spi_imx_master pcm037_spi1_pdata __initconst = { + .chipselect = pcm037_spi1_cs, + .num_chipselect = ARRAY_SIZE(pcm037_spi1_cs), +}; + +/* GPIO-keys input device */ +static struct gpio_keys_button pcm037_gpio_keys[] = { + { + .type = EV_KEY, + .code = KEY_L, + .gpio = 0, + .desc = "Wheel Manual", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_A, + .gpio = 1, + .desc = "Wheel AF", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_V, + .gpio = 2, + .desc = "Wheel View", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_M, + .gpio = 3, + .desc = "Wheel Menu", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_UP, + .gpio = 32, + .desc = "Nav Pad Up", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_RIGHT, + .gpio = 33, + .desc = "Nav Pad Right", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_DOWN, + .gpio = 34, + .desc = "Nav Pad Down", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_LEFT, + .gpio = 35, + .desc = "Nav Pad Left", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_ENTER, + .gpio = 38, + .desc = "Nav Pad Ok", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = KEY_O, + .gpio = 39, + .desc = "Wheel Off", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = BTN_FORWARD, + .gpio = 50, + .desc = "Focus Forward", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = BTN_BACK, + .gpio = 51, + .desc = "Focus Backward", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = BTN_MIDDLE, + .gpio = 52, + .desc = "Release Half", + .wakeup = 0, + }, { + .type = EV_KEY, + .code = BTN_EXTRA, + .gpio = 53, + .desc = "Release Full", + .wakeup = 0, + }, +}; + +static const struct gpio_keys_platform_data + pcm037_gpio_keys_platform_data __initconst = { + .buttons = pcm037_gpio_keys, + .nbuttons = ARRAY_SIZE(pcm037_gpio_keys), + .rep = 0, /* No auto-repeat */ +}; + +static int __init eet_init_devices(void) +{ + if (!machine_is_pcm037() || pcm037_variant() != PCM037_EET) + return 0; + + mxc_iomux_setup_multiple_pins(pcm037_eet_pins, + ARRAY_SIZE(pcm037_eet_pins), "pcm037_eet"); + + /* SPI */ + spi_register_board_info(pcm037_spi_dev, ARRAY_SIZE(pcm037_spi_dev)); + imx31_add_spi_imx0(&pcm037_spi1_pdata); + + imx_add_gpio_keys(&pcm037_gpio_keys_platform_data); + + return 0; +} +late_initcall(eet_init_devices); diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c new file mode 100644 index 00000000..853bb871 --- /dev/null +++ b/arch/arm/mach-imx/mach-pcm038.c @@ -0,0 +1,356 @@ +/* + * Copyright 2007 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/i2c.h> +#include <linux/i2c/at24.h> +#include <linux/io.h> +#include <linux/mtd/plat-ram.h> +#include <linux/mtd/physmap.h> +#include <linux/platform_device.h> +#include <linux/regulator/machine.h> +#include <linux/mfd/mc13783.h> +#include <linux/spi/spi.h> +#include <linux/irq.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/board-pcm038.h> +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx27.h> +#include <mach/ulpi.h> + +#include "devices-imx27.h" + +static const int pcm038_pins[] __initconst = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* UART2 */ + PE3_PF_UART2_CTS, + PE4_PF_UART2_RTS, + PE6_PF_UART2_TXD, + PE7_PF_UART2_RXD, + /* UART3 */ + PE8_PF_UART3_TXD, + PE9_PF_UART3_RXD, + PE10_PF_UART3_CTS, + PE11_PF_UART3_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + /* I2C2 */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + /* SPI1 */ + PD25_PF_CSPI1_RDY, + PD29_PF_CSPI1_SCLK, + PD30_PF_CSPI1_MISO, + PD31_PF_CSPI1_MOSI, + /* SSI1 */ + PC20_PF_SSI1_FS, + PC21_PF_SSI1_RXD, + PC22_PF_SSI1_TXD, + PC23_PF_SSI1_CLK, + /* SSI4 */ + PC16_PF_SSI4_FS, + PC17_PF_SSI4_RXD, + PC18_PF_SSI4_TXD, + PC19_PF_SSI4_CLK, + /* USB host */ + PA0_PF_USBH2_CLK, + PA1_PF_USBH2_DIR, + PA2_PF_USBH2_DATA7, + PA3_PF_USBH2_NXT, + PA4_PF_USBH2_STP, + PD19_AF_USBH2_DATA4, + PD20_AF_USBH2_DATA3, + PD21_AF_USBH2_DATA6, + PD22_AF_USBH2_DATA0, + PD23_AF_USBH2_DATA2, + PD24_AF_USBH2_DATA1, + PD26_AF_USBH2_DATA5, +}; + +/* + * Phytec's PCM038 comes with 2MiB battery buffered SRAM, + * 16 bit width + */ + +static struct platdata_mtd_ram pcm038_sram_data = { + .bankwidth = 2, +}; + +static struct resource pcm038_sram_resource = { + .start = MX27_CS1_BASE_ADDR, + .end = MX27_CS1_BASE_ADDR + 512 * 1024 - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm038_sram_mtd_device = { + .name = "mtd-ram", + .id = 0, + .dev = { + .platform_data = &pcm038_sram_data, + }, + .num_resources = 1, + .resource = &pcm038_sram_resource, +}; + +/* + * Phytec's phyCORE-i.MX27 comes with 32MiB flash, + * 16 bit width + */ +static struct physmap_flash_data pcm038_flash_data = { + .width = 2, +}; + +static struct resource pcm038_flash_resource = { + .start = 0xc0000000, + .end = 0xc1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm038_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &pcm038_flash_data, + }, + .num_resources = 1, + .resource = &pcm038_flash_resource, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct mxc_nand_platform_data +pcm038_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static struct platform_device *platform_devices[] __initdata = { + &pcm038_nor_mtd_device, + &pcm038_sram_mtd_device, +}; + +/* On pcm038 there's a sram attached to CS1, we enable the chipselect here and + * setup other stuffs to access the sram. */ +static void __init pcm038_init_sram(void) +{ + mx27_setup_weimcs(1, 0x0000d843, 0x22252521, 0x22220a00); +} + +static const struct imxi2c_platform_data pcm038_i2c1_data __initconst = { + .bitrate = 100000, +}; + +static struct at24_platform_data board_eeprom = { + .byte_len = 4096, + .page_size = 32, + .flags = AT24_FLAG_ADDR16, +}; + +static struct i2c_board_info pcm038_i2c_devices[] = { + { + I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */ + .platform_data = &board_eeprom, + }, { + I2C_BOARD_INFO("pcf8563", 0x51), + }, { + I2C_BOARD_INFO("lm75", 0x4a), + } +}; + +static int pcm038_spi_cs[] = {GPIO_PORTD + 28}; + +static const struct spi_imx_master pcm038_spi0_data __initconst = { + .chipselect = pcm038_spi_cs, + .num_chipselect = ARRAY_SIZE(pcm038_spi_cs), +}; + +static struct regulator_consumer_supply sdhc1_consumers[] = { + { + .dev_name = "mxc-mmc.1", + .supply = "sdhc_vcc", + }, +}; + +static struct regulator_init_data sdhc1_data = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3400000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(sdhc1_consumers), + .consumer_supplies = sdhc1_consumers, +}; + +static struct regulator_consumer_supply cam_consumers[] = { + { + .dev = NULL, + .supply = "imx_cam_vcc", + }, +}; + +static struct regulator_init_data cam_data = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3400000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + .valid_modes_mask = REGULATOR_MODE_NORMAL | + REGULATOR_MODE_FAST, + .always_on = 0, + .boot_on = 0, + }, + .num_consumer_supplies = ARRAY_SIZE(cam_consumers), + .consumer_supplies = cam_consumers, +}; + +static struct mc13xxx_regulator_init_data pcm038_regulators[] = { + { + .id = MC13783_REG_VCAM, + .init_data = &cam_data, + }, { + .id = MC13783_REG_VMMC1, + .init_data = &sdhc1_data, + }, +}; + +static struct mc13xxx_platform_data pcm038_pmic = { + .regulators = { + .regulators = pcm038_regulators, + .num_regulators = ARRAY_SIZE(pcm038_regulators), + }, + .flags = MC13783_USE_ADC | MC13783_USE_REGULATOR | + MC13783_USE_TOUCHSCREEN, +}; + +static struct spi_board_info pcm038_spi_board_info[] __initdata = { + { + .modalias = "mc13783", + .irq = IRQ_GPIOB(23), + .max_speed_hz = 300000, + .bus_num = 0, + .chip_select = 0, + .platform_data = &pcm038_pmic, + .mode = SPI_CS_HIGH, + } +}; + +static int pcm038_usbh2_init(struct platform_device *pdev) +{ + return mx27_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static const struct mxc_usbh_platform_data usbh2_pdata __initconst = { + .init = pcm038_usbh2_init, + .portsc = MXC_EHCI_MODE_ULPI, +}; + +static void __init pcm038_init(void) +{ + mxc_gpio_setup_multiple_pins(pcm038_pins, ARRAY_SIZE(pcm038_pins), + "PCM038"); + + pcm038_init_sram(); + + imx27_add_imx_uart0(&uart_pdata); + imx27_add_imx_uart1(&uart_pdata); + imx27_add_imx_uart2(&uart_pdata); + + mxc_gpio_mode(PE16_AF_OWIRE); + imx27_add_mxc_nand(&pcm038_nand_board_info); + + /* only the i2c master 1 is used on this CPU card */ + i2c_register_board_info(1, pcm038_i2c_devices, + ARRAY_SIZE(pcm038_i2c_devices)); + + imx27_add_imx_i2c(1, &pcm038_i2c1_data); + + /* PE18 for user-LED D40 */ + mxc_gpio_mode(GPIO_PORTE | 18 | GPIO_GPIO | GPIO_OUT); + + mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT); + + /* MC13783 IRQ */ + mxc_gpio_mode(GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN); + + imx27_add_spi_imx0(&pcm038_spi0_data); + spi_register_board_info(pcm038_spi_board_info, + ARRAY_SIZE(pcm038_spi_board_info)); + + imx27_add_mxc_ehci_hs(2, &usbh2_pdata); + + imx27_add_fec(NULL); + platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices)); + imx27_add_imx2_wdt(NULL); + imx27_add_mxc_w1(NULL); + +#ifdef CONFIG_MACH_PCM970_BASEBOARD + pcm970_baseboard_init(); +#endif +} + +static void __init pcm038_timer_init(void) +{ + mx27_clocks_init(26000000); +} + +static struct sys_timer pcm038_timer = { + .init = pcm038_timer_init, +}; + +MACHINE_START(PCM038, "phyCORE-i.MX27") + .boot_params = MX27_PHYS_OFFSET + 0x100, + .map_io = mx27_map_io, + .init_early = imx27_init_early, + .init_irq = mx27_init_irq, + .timer = &pcm038_timer, + .init_machine = pcm038_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-pcm043.c b/arch/arm/mach-imx/mach-pcm043.c new file mode 100644 index 00000000..02644162 --- /dev/null +++ b/arch/arm/mach-imx/mach-pcm043.c @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2009 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/init.h> + +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/plat-ram.h> +#include <linux/memory.h> +#include <linux/gpio.h> +#include <linux/smc911x.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/i2c/at24.h> +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx35.h> +#include <mach/ulpi.h> +#include <mach/audmux.h> + +#include "devices-imx35.h" + +static const struct fb_videomode fb_modedb[] = { + { + /* 240x320 @ 60 Hz */ + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 185925, + .left_margin = 9, + .right_margin = 16, + .upper_margin = 7, + .lower_margin = 9, + .hsync_len = 1, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, { + /* 240x320 @ 60 Hz */ + .name = "TX090", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 38255, + .left_margin = 144, + .right_margin = 0, + .upper_margin = 7, + .lower_margin = 40, + .hsync_len = 96, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, +}; + +static const struct ipu_platform_data mx3_ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata __initdata = { + .name = "Sharp-LQ035Q7", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +static struct physmap_flash_data pcm043_flash_data = { + .width = 2, +}; + +static struct resource pcm043_flash_resource = { + .start = 0xa0000000, + .end = 0xa1ffffff, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device pcm043_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &pcm043_flash_data, + }, + .resource = &pcm043_flash_resource, + .num_resources = 1, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static const struct imxi2c_platform_data pcm043_i2c0_data __initconst = { + .bitrate = 50000, +}; + +static struct at24_platform_data board_eeprom = { + .byte_len = 4096, + .page_size = 32, + .flags = AT24_FLAG_ADDR16, +}; + +static struct i2c_board_info pcm043_i2c_devices[] = { + { + I2C_BOARD_INFO("at24", 0x52), /* E0=0, E1=1, E2=0 */ + .platform_data = &board_eeprom, + }, { + I2C_BOARD_INFO("pcf8563", 0x51), + }, +}; + +static struct platform_device *devices[] __initdata = { + &pcm043_flash, +}; + +static iomux_v3_cfg_t pcm043_pads[] = { + /* UART1 */ + MX35_PAD_CTS1__UART1_CTS, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RXD1__UART1_RXD_MUX, + /* UART2 */ + MX35_PAD_CTS2__UART2_CTS, + MX35_PAD_RTS2__UART2_RTS, + MX35_PAD_TXD2__UART2_TXD_MUX, + MX35_PAD_RXD2__UART2_RXD_MUX, + /* FEC */ + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + /* I2C1 */ + MX35_PAD_I2C1_CLK__I2C1_SCL, + MX35_PAD_I2C1_DAT__I2C1_SDA, + /* Display */ + MX35_PAD_LD0__IPU_DISPB_DAT_0, + MX35_PAD_LD1__IPU_DISPB_DAT_1, + MX35_PAD_LD2__IPU_DISPB_DAT_2, + MX35_PAD_LD3__IPU_DISPB_DAT_3, + MX35_PAD_LD4__IPU_DISPB_DAT_4, + MX35_PAD_LD5__IPU_DISPB_DAT_5, + MX35_PAD_LD6__IPU_DISPB_DAT_6, + MX35_PAD_LD7__IPU_DISPB_DAT_7, + MX35_PAD_LD8__IPU_DISPB_DAT_8, + MX35_PAD_LD9__IPU_DISPB_DAT_9, + MX35_PAD_LD10__IPU_DISPB_DAT_10, + MX35_PAD_LD11__IPU_DISPB_DAT_11, + MX35_PAD_LD12__IPU_DISPB_DAT_12, + MX35_PAD_LD13__IPU_DISPB_DAT_13, + MX35_PAD_LD14__IPU_DISPB_DAT_14, + MX35_PAD_LD15__IPU_DISPB_DAT_15, + MX35_PAD_LD16__IPU_DISPB_DAT_16, + MX35_PAD_LD17__IPU_DISPB_DAT_17, + MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC, + MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK, + MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY, + MX35_PAD_CONTRAST__IPU_DISPB_CONTR, + MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC, + MX35_PAD_D3_REV__IPU_DISPB_D3_REV, + MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS, + /* gpio */ + MX35_PAD_ATA_CS0__GPIO2_6, + /* USB host */ + MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR, + MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC, + /* SSI */ + MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS, + MX35_PAD_STXD4__AUDMUX_AUD4_TXD, + MX35_PAD_SRXD4__AUDMUX_AUD4_RXD, + MX35_PAD_SCK4__AUDMUX_AUD4_TXC, + /* CAN2 */ + MX35_PAD_TX5_RX0__CAN2_TXCAN, + MX35_PAD_TX4_RX1__CAN2_RXCAN, + /* esdhc */ + MX35_PAD_SD1_CMD__ESDHC1_CMD, + MX35_PAD_SD1_CLK__ESDHC1_CLK, + MX35_PAD_SD1_DATA0__ESDHC1_DAT0, + MX35_PAD_SD1_DATA1__ESDHC1_DAT1, + MX35_PAD_SD1_DATA2__ESDHC1_DAT2, + MX35_PAD_SD1_DATA3__ESDHC1_DAT3, + MX35_PAD_ATA_DATA10__GPIO2_23, /* WriteProtect */ + MX35_PAD_ATA_DATA11__GPIO2_24, /* CardDetect */ +}; + +#define AC97_GPIO_TXFS IMX_GPIO_NR(2, 31) +#define AC97_GPIO_TXD IMX_GPIO_NR(2, 28) +#define AC97_GPIO_RESET IMX_GPIO_NR(2, 0) +#define SD1_GPIO_WP IMX_GPIO_NR(2, 23) +#define SD1_GPIO_CD IMX_GPIO_NR(2, 24) + +static void pcm043_ac97_warm_reset(struct snd_ac97 *ac97) +{ + iomux_v3_cfg_t txfs_gpio = MX35_PAD_STXFS4__GPIO2_31; + iomux_v3_cfg_t txfs = MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS; + int ret; + + ret = gpio_request(AC97_GPIO_TXFS, "SSI"); + if (ret) { + printk("failed to get GPIO_TXFS: %d\n", ret); + return; + } + + mxc_iomux_v3_setup_pad(txfs_gpio); + + /* warm reset */ + gpio_direction_output(AC97_GPIO_TXFS, 1); + udelay(2); + gpio_set_value(AC97_GPIO_TXFS, 0); + + gpio_free(AC97_GPIO_TXFS); + mxc_iomux_v3_setup_pad(txfs); +} + +static void pcm043_ac97_cold_reset(struct snd_ac97 *ac97) +{ + iomux_v3_cfg_t txfs_gpio = MX35_PAD_STXFS4__GPIO2_31; + iomux_v3_cfg_t txfs = MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS; + iomux_v3_cfg_t txd_gpio = MX35_PAD_STXD4__GPIO2_28; + iomux_v3_cfg_t txd = MX35_PAD_STXD4__AUDMUX_AUD4_TXD; + iomux_v3_cfg_t reset_gpio = MX35_PAD_SD2_CMD__GPIO2_0; + int ret; + + ret = gpio_request(AC97_GPIO_TXFS, "SSI"); + if (ret) + goto err1; + + ret = gpio_request(AC97_GPIO_TXD, "SSI"); + if (ret) + goto err2; + + ret = gpio_request(AC97_GPIO_RESET, "SSI"); + if (ret) + goto err3; + + mxc_iomux_v3_setup_pad(txfs_gpio); + mxc_iomux_v3_setup_pad(txd_gpio); + mxc_iomux_v3_setup_pad(reset_gpio); + + gpio_direction_output(AC97_GPIO_TXFS, 0); + gpio_direction_output(AC97_GPIO_TXD, 0); + + /* cold reset */ + gpio_direction_output(AC97_GPIO_RESET, 0); + udelay(10); + gpio_direction_output(AC97_GPIO_RESET, 1); + + mxc_iomux_v3_setup_pad(txd); + mxc_iomux_v3_setup_pad(txfs); + + gpio_free(AC97_GPIO_RESET); +err3: + gpio_free(AC97_GPIO_TXD); +err2: + gpio_free(AC97_GPIO_TXFS); +err1: + if (ret) + printk("%s failed with %d\n", __func__, ret); + mdelay(1); +} + +static const struct imx_ssi_platform_data pcm043_ssi_pdata __initconst = { + .ac97_reset = pcm043_ac97_cold_reset, + .ac97_warm_reset = pcm043_ac97_warm_reset, + .flags = IMX_SSI_USE_AC97, +}; + +static const struct mxc_nand_platform_data +pcm037_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, +}; + +static int pcm043_otg_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_DIFF_UNI); +} + +static struct mxc_usbh_platform_data otg_pdata __initdata = { + .init = pcm043_otg_init, + .portsc = MXC_EHCI_MODE_UTMI, +}; + +static int pcm043_usbh1_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, MXC_EHCI_INTERFACE_SINGLE_UNI | + MXC_EHCI_INTERNAL_PHY | MXC_EHCI_IPPUE_DOWN); +} + +static const struct mxc_usbh_platform_data usbh1_pdata __initconst = { + .init = pcm043_usbh1_init, + .portsc = MXC_EHCI_MODE_SERIAL, +}; + +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI, +}; + +static int otg_mode_host; + +static int __init pcm043_otg_mode(char *options) +{ + if (!strcmp(options, "host")) + otg_mode_host = 1; + else if (!strcmp(options, "device")) + otg_mode_host = 0; + else + pr_info("otg_mode neither \"host\" nor \"device\". " + "Defaulting to device\n"); + return 0; +} +__setup("otg_mode=", pcm043_otg_mode); + +static struct esdhc_platform_data sd1_pdata = { + .wp_gpio = SD1_GPIO_WP, + .cd_gpio = SD1_GPIO_CD, +}; + +/* + * Board specific initialization. + */ +static void __init pcm043_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads)); + + mxc_audmux_v2_configure_port(3, + MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ + MXC_AUDMUX_V2_PTCR_TFSEL(0) | + MXC_AUDMUX_V2_PTCR_TFSDIR, + MXC_AUDMUX_V2_PDCR_RXDSEL(0)); + + mxc_audmux_v2_configure_port(0, + MXC_AUDMUX_V2_PTCR_SYN | /* 4wire mode */ + MXC_AUDMUX_V2_PTCR_TCSEL(3) | + MXC_AUDMUX_V2_PTCR_TCLKDIR, /* clock is output */ + MXC_AUDMUX_V2_PDCR_RXDSEL(3)); + + imx35_add_fec(NULL); + platform_add_devices(devices, ARRAY_SIZE(devices)); + imx35_add_imx2_wdt(NULL); + + imx35_add_imx_uart0(&uart_pdata); + imx35_add_mxc_nand(&pcm037_nand_board_info); + imx35_add_imx_ssi(0, &pcm043_ssi_pdata); + + imx35_add_imx_uart1(&uart_pdata); + + i2c_register_board_info(0, pcm043_i2c_devices, + ARRAY_SIZE(pcm043_i2c_devices)); + + imx35_add_imx_i2c0(&pcm043_i2c0_data); + + imx35_add_ipu_core(&mx3_ipu_data); + imx35_add_mx3_sdc_fb(&mx3fb_pdata); + + if (otg_mode_host) { + otg_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (otg_pdata.otg) + imx35_add_mxc_ehci_otg(&otg_pdata); + } + imx35_add_mxc_ehci_hs(&usbh1_pdata); + + if (!otg_mode_host) + imx35_add_fsl_usb2_udc(&otg_device_pdata); + + imx35_add_flexcan1(NULL); + imx35_add_sdhci_esdhc_imx(0, &sd1_pdata); +} + +static void __init pcm043_timer_init(void) +{ + mx35_clocks_init(); +} + +struct sys_timer pcm043_timer = { + .init = pcm043_timer_init, +}; + +MACHINE_START(PCM043, "Phytec Phycore pcm043") + /* Maintainer: Pengutronix */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx35_map_io, + .init_early = imx35_init_early, + .init_irq = mx35_init_irq, + .timer = &pcm043_timer, + .init_machine = pcm043_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-qong.c b/arch/arm/mach-imx/mach-qong.c new file mode 100644 index 00000000..c1632871 --- /dev/null +++ b/arch/arm/mach-imx/mach-qong.c @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/memory.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/nand.h> +#include <linux/gpio.h> + +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> +#include <asm/mach/map.h> +#include <mach/common.h> +#include <asm/page.h> +#include <asm/setup.h> +#include <mach/iomux-mx3.h> + +#include "devices-imx31.h" + +/* FPGA defines */ +#define QONG_FPGA_VERSION(major, minor, rev) \ + (((major & 0xF) << 12) | ((minor & 0xF) << 8) | (rev & 0xFF)) + +#define QONG_FPGA_BASEADDR MX31_CS1_BASE_ADDR +#define QONG_FPGA_PERIPH_SIZE (1 << 24) + +#define QONG_FPGA_CTRL_BASEADDR QONG_FPGA_BASEADDR +#define QONG_FPGA_CTRL_SIZE 0x10 +/* FPGA control registers */ +#define QONG_FPGA_CTRL_VERSION 0x00 + +#define QONG_DNET_ID 1 +#define QONG_DNET_BASEADDR \ + (QONG_FPGA_BASEADDR + QONG_DNET_ID * QONG_FPGA_PERIPH_SIZE) +#define QONG_DNET_SIZE 0x00001000 + +#define QONG_FPGA_IRQ IOMUX_TO_IRQ(MX31_PIN_DTR_DCE1) + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +static int uart_pins[] = { + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1 +}; + +static inline void __init mxc_init_imx_uart(void) +{ + mxc_iomux_setup_multiple_pins(uart_pins, ARRAY_SIZE(uart_pins), + "uart-0"); + imx31_add_imx_uart0(&uart_pdata); +} + +static struct resource dnet_resources[] = { + { + .name = "dnet-memory", + .start = QONG_DNET_BASEADDR, + .end = QONG_DNET_BASEADDR + QONG_DNET_SIZE - 1, + .flags = IORESOURCE_MEM, + }, { + .start = QONG_FPGA_IRQ, + .end = QONG_FPGA_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device dnet_device = { + .name = "dnet", + .id = -1, + .num_resources = ARRAY_SIZE(dnet_resources), + .resource = dnet_resources, +}; + +static int __init qong_init_dnet(void) +{ + int ret; + + ret = platform_device_register(&dnet_device); + return ret; +} + +/* MTD NOR flash */ + +static struct physmap_flash_data qong_flash_data = { + .width = 2, +}; + +static struct resource qong_flash_resource = { + .start = MX31_CS0_BASE_ADDR, + .end = MX31_CS0_BASE_ADDR + SZ_128M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device qong_nor_mtd_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &qong_flash_data, + }, + .resource = &qong_flash_resource, + .num_resources = 1, +}; + +static void qong_init_nor_mtd(void) +{ + (void)platform_device_register(&qong_nor_mtd_device); +} + +/* + * Hardware specific access to control-lines + */ +static void qong_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd, nand_chip->IO_ADDR_W + (1 << 24)); + else + writeb(cmd, nand_chip->IO_ADDR_W + (1 << 23)); +} + +/* + * Read the Device Ready pin. + */ +static int qong_nand_device_ready(struct mtd_info *mtd) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_NFRB)); +} + +static void qong_nand_select_chip(struct mtd_info *mtd, int chip) +{ + if (chip >= 0) + gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 0); + else + gpio_set_value(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 1); +} + +static struct platform_nand_data qong_nand_data = { + .chip = { + .nr_chips = 1, + .chip_delay = 20, + .options = 0, + }, + .ctrl = { + .cmd_ctrl = qong_nand_cmd_ctrl, + .dev_ready = qong_nand_device_ready, + .select_chip = qong_nand_select_chip, + } +}; + +static struct resource qong_nand_resource = { + .start = MX31_CS3_BASE_ADDR, + .end = MX31_CS3_BASE_ADDR + SZ_32M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device qong_nand_device = { + .name = "gen_nand", + .id = -1, + .dev = { + .platform_data = &qong_nand_data, + }, + .num_resources = 1, + .resource = &qong_nand_resource, +}; + +static void __init qong_init_nand_mtd(void) +{ + /* init CS */ + mx31_setup_weimcs(3, 0x00004f00, 0x20013b31, 0x00020800); + mxc_iomux_set_gpr(MUX_SDCTL_CSD1_SEL, true); + + /* enable pin */ + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_NFCE_B, IOMUX_CONFIG_GPIO)); + if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), "nand_enable")) + gpio_direction_output(IOMUX_TO_GPIO(MX31_PIN_NFCE_B), 0); + + /* ready/busy pin */ + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_NFRB, IOMUX_CONFIG_GPIO)); + if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_NFRB), "nand_rdy")) + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_NFRB)); + + /* write protect pin */ + mxc_iomux_mode(IOMUX_MODE(MX31_PIN_NFWP_B, IOMUX_CONFIG_GPIO)); + if (!gpio_request(IOMUX_TO_GPIO(MX31_PIN_NFWP_B), "nand_wp")) + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_NFWP_B)); + + platform_device_register(&qong_nand_device); +} + +static void __init qong_init_fpga(void) +{ + void __iomem *regs; + u32 fpga_ver; + + regs = ioremap(QONG_FPGA_CTRL_BASEADDR, QONG_FPGA_CTRL_SIZE); + if (!regs) { + printk(KERN_ERR "%s: failed to map registers, aborting.\n", + __func__); + return; + } + + fpga_ver = readl(regs + QONG_FPGA_CTRL_VERSION); + iounmap(regs); + printk(KERN_INFO "Qong FPGA version %d.%d.%d\n", + (fpga_ver & 0xF000) >> 12, + (fpga_ver & 0x0F00) >> 8, fpga_ver & 0x00FF); + if (fpga_ver < QONG_FPGA_VERSION(0, 8, 7)) { + printk(KERN_ERR "qong: Unexpected FPGA version, FPGA-based " + "devices won't be registered!\n"); + return; + } + + /* register FPGA-based devices */ + qong_init_nand_mtd(); + qong_init_dnet(); +} + +/* + * Board specific initialization. + */ +static void __init qong_init(void) +{ + mxc_init_imx_uart(); + qong_init_nor_mtd(); + qong_init_fpga(); +} + +static void __init qong_timer_init(void) +{ + mx31_clocks_init(26000000); +} + +static struct sys_timer qong_timer = { + .init = qong_timer_init, +}; + +MACHINE_START(QONG, "Dave/DENX QongEVB-LITE") + /* Maintainer: DENX Software Engineering GmbH */ + .boot_params = MX3x_PHYS_OFFSET + 0x100, + .map_io = mx31_map_io, + .init_early = imx31_init_early, + .init_irq = mx31_init_irq, + .timer = &qong_timer, + .init_machine = qong_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-scb9328.c b/arch/arm/mach-imx/mach-scb9328.c new file mode 100644 index 00000000..dcaee043 --- /dev/null +++ b/arch/arm/mach-imx/mach-scb9328.c @@ -0,0 +1,155 @@ +/* + * linux/arch/arm/mach-mx1/mach-scb9328.c + * + * Copyright (c) 2004 Sascha Hauer <saschahauer@web.de> + * Copyright (c) 2006-2008 Juergen Beisert <jbeisert@netscape.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/interrupt.h> +#include <linux/dm9000.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/irqs.h> +#include <mach/iomux-mx1.h> + +#include "devices-imx1.h" + +/* + * This scb9328 has a 32MiB flash + */ +static struct resource flash_resource = { + .start = MX1_CS0_PHYS, + .end = MX1_CS0_PHYS + (32 * 1024 * 1024) - 1, + .flags = IORESOURCE_MEM, +}; + +static struct physmap_flash_data scb_flash_data = { + .width = 2, +}; + +static struct platform_device scb_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &scb_flash_data, + }, + .resource = &flash_resource, + .num_resources = 1, +}; + +/* + * scb9328 has a DM9000 network controller + * connected to CS5, with 16 bit data path + * and interrupt connected to GPIO 3 + */ + +/* + * internal datapath is fixed 16 bit + */ +static struct dm9000_plat_data dm9000_platdata = { + .flags = DM9000_PLATF_16BITONLY, +}; + +/* + * the DM9000 drivers wants two defined address spaces + * to gain access to address latch registers and the data path. + */ +static struct resource dm9000x_resources[] = { + { + .name = "address area", + .start = MX1_CS5_PHYS, + .end = MX1_CS5_PHYS + 1, + .flags = IORESOURCE_MEM, /* address access */ + }, { + .name = "data area", + .start = MX1_CS5_PHYS + 4, + .end = MX1_CS5_PHYS + 5, + .flags = IORESOURCE_MEM, /* data access */ + }, { + .start = IRQ_GPIOC(3), + .end = IRQ_GPIOC(3), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct platform_device dm9000x_device = { + .name = "dm9000", + .id = 0, + .num_resources = ARRAY_SIZE(dm9000x_resources), + .resource = dm9000x_resources, + .dev = { + .platform_data = &dm9000_platdata, + } +}; + +static const int mxc_uart1_pins[] = { + PC9_PF_UART1_CTS, + PC10_PF_UART1_RTS, + PC11_PF_UART1_TXD, + PC12_PF_UART1_RXD, +}; + +static int uart1_mxc_init(struct platform_device *pdev) +{ + return mxc_gpio_setup_multiple_pins(mxc_uart1_pins, + ARRAY_SIZE(mxc_uart1_pins), "UART1"); +} + +static void uart1_mxc_exit(struct platform_device *pdev) +{ + mxc_gpio_release_multiple_pins(mxc_uart1_pins, + ARRAY_SIZE(mxc_uart1_pins)); +} + +static const struct imxuart_platform_data uart_pdata __initconst = { + .init = uart1_mxc_init, + .exit = uart1_mxc_exit, + .flags = IMXUART_HAVE_RTSCTS, +}; + +static struct platform_device *devices[] __initdata = { + &scb_flash_device, + &dm9000x_device, +}; + +/* + * scb9328_init - Init the CPU card itself + */ +static void __init scb9328_init(void) +{ + imx1_add_imx_uart0(&uart_pdata); + + printk(KERN_INFO"Scb9328: Adding devices\n"); + platform_add_devices(devices, ARRAY_SIZE(devices)); +} + +static void __init scb9328_timer_init(void) +{ + mx1_clocks_init(32000); +} + +static struct sys_timer scb9328_timer = { + .init = scb9328_timer_init, +}; + +MACHINE_START(SCB9328, "Synertronixx scb9328") + /* Sascha Hauer */ + .boot_params = 0x08000100, + .map_io = mx1_map_io, + .init_early = imx1_init_early, + .init_irq = mx1_init_irq, + .timer = &scb9328_timer, + .init_machine = scb9328_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mach-vpr200.c b/arch/arm/mach-imx/mach-vpr200.c new file mode 100644 index 00000000..d74e3473 --- /dev/null +++ b/arch/arm/mach-imx/mach-vpr200.c @@ -0,0 +1,322 @@ +/* + * Copyright 2009 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2009 Marc Kleine-Budde, Pengutronix + * Copyright 2010 Creative Product Design + * + * Derived from mx35 3stack. + * Original author: Fabio Estevam <fabio.estevam@freescale.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/types.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/memory.h> +#include <linux/gpio.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/time.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx35.h> +#include <mach/irqs.h> + +#include <linux/i2c.h> +#include <linux/i2c/at24.h> +#include <linux/mfd/mc13xxx.h> + +#include "devices-imx35.h" + +#define GPIO_LCDPWR IMX_GPIO_NR(1, 2) +#define GPIO_PMIC_INT IMX_GPIO_NR(2, 0) + +#define GPIO_BUTTON1 IMX_GPIO_NR(1, 4) +#define GPIO_BUTTON2 IMX_GPIO_NR(1, 5) +#define GPIO_BUTTON3 IMX_GPIO_NR(1, 7) +#define GPIO_BUTTON4 IMX_GPIO_NR(1, 8) +#define GPIO_BUTTON5 IMX_GPIO_NR(1, 9) +#define GPIO_BUTTON6 IMX_GPIO_NR(1, 10) +#define GPIO_BUTTON7 IMX_GPIO_NR(1, 11) +#define GPIO_BUTTON8 IMX_GPIO_NR(1, 12) + +static const struct fb_videomode fb_modedb[] = { + { + /* 800x480 @ 60 Hz */ + .name = "PT0708048", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = KHZ2PICOS(33260), + .left_margin = 50, + .right_margin = 156, + .upper_margin = 10, + .lower_margin = 10, + .hsync_len = 1, /* note: DE only display */ + .vsync_len = 1, /* note: DE only display */ + .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, { + /* 800x480 @ 60 Hz */ + .name = "CTP-CLAA070LC0ACW", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = KHZ2PICOS(27000), + .left_margin = 50, + .right_margin = 50, /* whole line should have 900 clocks */ + .upper_margin = 10, + .lower_margin = 10, /* whole frame should have 500 lines */ + .hsync_len = 1, /* note: DE only display */ + .vsync_len = 1, /* note: DE only display */ + .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + } +}; + +static const struct ipu_platform_data mx3_ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static struct mx3fb_platform_data mx3fb_pdata __initdata = { + .name = "PT0708048", + .mode = fb_modedb, + .num_modes = ARRAY_SIZE(fb_modedb), +}; + +static struct physmap_flash_data vpr200_flash_data = { + .width = 2, +}; + +static struct resource vpr200_flash_resource = { + .start = MX35_CS0_BASE_ADDR, + .end = MX35_CS0_BASE_ADDR + SZ_64M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device vpr200_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &vpr200_flash_data, + }, + .resource = &vpr200_flash_resource, + .num_resources = 1, +}; + +static const struct mxc_nand_platform_data + vpr200_nand_board_info __initconst = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +#define VPR_KEY_DEBOUNCE 500 +static struct gpio_keys_button vpr200_gpio_keys_table[] = { + {KEY_F2, GPIO_BUTTON1, 1, "vpr-keys: F2", 0, VPR_KEY_DEBOUNCE}, + {KEY_F3, GPIO_BUTTON2, 1, "vpr-keys: F3", 0, VPR_KEY_DEBOUNCE}, + {KEY_F4, GPIO_BUTTON3, 1, "vpr-keys: F4", 0, VPR_KEY_DEBOUNCE}, + {KEY_F5, GPIO_BUTTON4, 1, "vpr-keys: F5", 0, VPR_KEY_DEBOUNCE}, + {KEY_F6, GPIO_BUTTON5, 1, "vpr-keys: F6", 0, VPR_KEY_DEBOUNCE}, + {KEY_F7, GPIO_BUTTON6, 1, "vpr-keys: F7", 0, VPR_KEY_DEBOUNCE}, + {KEY_F8, GPIO_BUTTON7, 1, "vpr-keys: F8", 1, VPR_KEY_DEBOUNCE}, + {KEY_F9, GPIO_BUTTON8, 1, "vpr-keys: F9", 1, VPR_KEY_DEBOUNCE}, +}; + +static const struct gpio_keys_platform_data + vpr200_gpio_keys_data __initconst = { + .buttons = vpr200_gpio_keys_table, + .nbuttons = ARRAY_SIZE(vpr200_gpio_keys_table), +}; + +static struct mc13xxx_platform_data vpr200_pmic = { + .flags = MC13XXX_USE_ADC | MC13XXX_USE_TOUCHSCREEN, +}; + +static const struct imxi2c_platform_data vpr200_i2c0_data __initconst = { + .bitrate = 50000, +}; + +static struct at24_platform_data vpr200_eeprom = { + .byte_len = 2048 / 8, + .page_size = 1, +}; + +static struct i2c_board_info vpr200_i2c_devices[] = { + { + I2C_BOARD_INFO("at24", 0x50), /* E0=0, E1=0, E2=0 */ + .platform_data = &vpr200_eeprom, + }, { + I2C_BOARD_INFO("mc13892", 0x08), + .platform_data = &vpr200_pmic, + .irq = gpio_to_irq(GPIO_PMIC_INT), + } +}; + +static iomux_v3_cfg_t vpr200_pads[] = { + /* UART1 */ + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RXD1__UART1_RXD_MUX, + /* UART3 */ + MX35_PAD_ATA_DATA10__UART3_RXD_MUX, + MX35_PAD_ATA_DATA11__UART3_TXD_MUX, + /* FEC */ + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + /* Display */ + MX35_PAD_LD0__IPU_DISPB_DAT_0, + MX35_PAD_LD1__IPU_DISPB_DAT_1, + MX35_PAD_LD2__IPU_DISPB_DAT_2, + MX35_PAD_LD3__IPU_DISPB_DAT_3, + MX35_PAD_LD4__IPU_DISPB_DAT_4, + MX35_PAD_LD5__IPU_DISPB_DAT_5, + MX35_PAD_LD6__IPU_DISPB_DAT_6, + MX35_PAD_LD7__IPU_DISPB_DAT_7, + MX35_PAD_LD8__IPU_DISPB_DAT_8, + MX35_PAD_LD9__IPU_DISPB_DAT_9, + MX35_PAD_LD10__IPU_DISPB_DAT_10, + MX35_PAD_LD11__IPU_DISPB_DAT_11, + MX35_PAD_LD12__IPU_DISPB_DAT_12, + MX35_PAD_LD13__IPU_DISPB_DAT_13, + MX35_PAD_LD14__IPU_DISPB_DAT_14, + MX35_PAD_LD15__IPU_DISPB_DAT_15, + MX35_PAD_LD16__IPU_DISPB_DAT_16, + MX35_PAD_LD17__IPU_DISPB_DAT_17, + MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK, + MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY, + MX35_PAD_CONTRAST__IPU_DISPB_CONTR, + /* LCD Enable */ + MX35_PAD_D3_VSYNC__GPIO1_2, + /* USBOTG */ + MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR, + MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC, + /* SDCARD */ + MX35_PAD_SD1_CMD__ESDHC1_CMD, + MX35_PAD_SD1_CLK__ESDHC1_CLK, + MX35_PAD_SD1_DATA0__ESDHC1_DAT0, + MX35_PAD_SD1_DATA1__ESDHC1_DAT1, + MX35_PAD_SD1_DATA2__ESDHC1_DAT2, + MX35_PAD_SD1_DATA3__ESDHC1_DAT3, + /* PMIC */ + MX35_PAD_GPIO2_0__GPIO2_0, + /* GPIO keys */ + MX35_PAD_SCKR__GPIO1_4, + MX35_PAD_COMPARE__GPIO1_5, + MX35_PAD_SCKT__GPIO1_7, + MX35_PAD_FST__GPIO1_8, + MX35_PAD_HCKT__GPIO1_9, + MX35_PAD_TX5_RX0__GPIO1_10, + MX35_PAD_TX4_RX1__GPIO1_11, + MX35_PAD_TX3_RX2__GPIO1_12, +}; + +/* USB Device config */ +static const struct fsl_usb2_platform_data otg_device_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_UTMI, + .workaround = FLS_USB2_WORKAROUND_ENGCM09152, +}; + +static int vpr200_usbh_init(struct platform_device *pdev) +{ + return mx35_initialize_usb_hw(pdev->id, + MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY); +} + +/* USB HOST config */ +static const struct mxc_usbh_platform_data usb_host_pdata __initconst = { + .init = vpr200_usbh_init, + .portsc = MXC_EHCI_MODE_SERIAL, +}; + +static struct platform_device *devices[] __initdata = { + &vpr200_flash, +}; + +/* + * Board specific initialization. + */ +static void __init vpr200_board_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(vpr200_pads, ARRAY_SIZE(vpr200_pads)); + + imx35_add_fec(NULL); + imx35_add_imx2_wdt(NULL); + imx_add_gpio_keys(&vpr200_gpio_keys_data); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + + if (0 != gpio_request(GPIO_LCDPWR, "LCDPWR")) + printk(KERN_WARNING "vpr200: Couldn't get LCDPWR gpio\n"); + else + gpio_direction_output(GPIO_LCDPWR, 0); + + if (0 != gpio_request(GPIO_PMIC_INT, "PMIC_INT")) + printk(KERN_WARNING "vpr200: Couldn't get PMIC_INT gpio\n"); + else + gpio_direction_input(GPIO_PMIC_INT); + + imx35_add_imx_uart0(NULL); + imx35_add_imx_uart2(NULL); + + imx35_add_ipu_core(&mx3_ipu_data); + imx35_add_mx3_sdc_fb(&mx3fb_pdata); + + imx35_add_fsl_usb2_udc(&otg_device_pdata); + imx35_add_mxc_ehci_hs(&usb_host_pdata); + + imx35_add_mxc_nand(&vpr200_nand_board_info); + imx35_add_sdhci_esdhc_imx(0, NULL); + + i2c_register_board_info(0, vpr200_i2c_devices, + ARRAY_SIZE(vpr200_i2c_devices)); + + imx35_add_imx_i2c0(&vpr200_i2c0_data); +} + +static void __init vpr200_timer_init(void) +{ + mx35_clocks_init(); +} + +struct sys_timer vpr200_timer = { + .init = vpr200_timer_init, +}; + +MACHINE_START(VPR200, "VPR200") + /* Maintainer: Creative Product Design */ + .map_io = mx35_map_io, + .init_early = imx35_init_early, + .init_irq = mx35_init_irq, + .timer = &vpr200_timer, + .init_machine = vpr200_board_init, +MACHINE_END diff --git a/arch/arm/mach-imx/mm-imx1.c b/arch/arm/mach-imx/mm-imx1.c new file mode 100644 index 00000000..2e482ba5 --- /dev/null +++ b/arch/arm/mach-imx/mm-imx1.c @@ -0,0 +1,58 @@ +/* + * author: Sascha Hauer + * Created: april 20th, 2004 + * Copyright: Synertronixx GmbH + * + * Common code for i.MX1 machines + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include <asm/mach/map.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/irqs.h> +#include <mach/iomux-v1.h> + +static struct map_desc imx_io_desc[] __initdata = { + imx_map_entry(MX1, IO, MT_DEVICE), +}; + +void __init mx1_map_io(void) +{ + iotable_init(imx_io_desc, ARRAY_SIZE(imx_io_desc)); +} + +void __init imx1_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX1); + mxc_arch_reset_init(MX1_IO_ADDRESS(MX1_WDT_BASE_ADDR)); + imx_iomuxv1_init(MX1_IO_ADDRESS(MX1_GPIO_BASE_ADDR), + MX1_NUM_GPIO_PORT); +} + +static struct mxc_gpio_port imx1_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ(MX1, 0, 1, MX1_GPIO_INT_PORTA), + DEFINE_IMX_GPIO_PORT_IRQ(MX1, 1, 2, MX1_GPIO_INT_PORTB), + DEFINE_IMX_GPIO_PORT_IRQ(MX1, 2, 3, MX1_GPIO_INT_PORTC), + DEFINE_IMX_GPIO_PORT_IRQ(MX1, 3, 4, MX1_GPIO_INT_PORTD), +}; + +void __init mx1_init_irq(void) +{ + mxc_init_irq(MX1_IO_ADDRESS(MX1_AVIC_BASE_ADDR)); + mxc_gpio_init(imx1_gpio_ports, ARRAY_SIZE(imx1_gpio_ports)); +} diff --git a/arch/arm/mach-imx/mm-imx21.c b/arch/arm/mach-imx/mm-imx21.c new file mode 100644 index 00000000..7a0c500a --- /dev/null +++ b/arch/arm/mach-imx/mm-imx21.c @@ -0,0 +1,86 @@ +/* + * arch/arm/mach-imx/mm-imx21.c + * + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <asm/pgtable.h> +#include <asm/mach/map.h> +#include <mach/gpio.h> +#include <mach/irqs.h> +#include <mach/iomux-v1.h> + +/* MX21 memory map definition */ +static struct map_desc imx21_io_desc[] __initdata = { + /* + * this fixed mapping covers: + * - AIPI1 + * - AIPI2 + * - AITC + * - ROM Patch + * - and some reserved space + */ + imx_map_entry(MX21, AIPI, MT_DEVICE), + /* + * this fixed mapping covers: + * - CSI + * - ATA + */ + imx_map_entry(MX21, SAHB1, MT_DEVICE), + /* + * this fixed mapping covers: + * - EMI + */ + imx_map_entry(MX21, X_MEMC, MT_DEVICE), +}; + +/* + * Initialize the memory map. It is called during the + * system startup to create static physical to virtual + * memory map for the IO modules. + */ +void __init mx21_map_io(void) +{ + iotable_init(imx21_io_desc, ARRAY_SIZE(imx21_io_desc)); +} + +void __init imx21_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX21); + mxc_arch_reset_init(MX21_IO_ADDRESS(MX21_WDOG_BASE_ADDR)); + imx_iomuxv1_init(MX21_IO_ADDRESS(MX21_GPIO_BASE_ADDR), + MX21_NUM_GPIO_PORT); +} + +static struct mxc_gpio_port imx21_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ(MX21, 0, 1, MX21_INT_GPIO), + DEFINE_IMX_GPIO_PORT(MX21, 1, 2), + DEFINE_IMX_GPIO_PORT(MX21, 2, 3), + DEFINE_IMX_GPIO_PORT(MX21, 3, 4), + DEFINE_IMX_GPIO_PORT(MX21, 4, 5), + DEFINE_IMX_GPIO_PORT(MX21, 5, 6), +}; + +void __init mx21_init_irq(void) +{ + mxc_init_irq(MX21_IO_ADDRESS(MX21_AVIC_BASE_ADDR)); + mxc_gpio_init(imx21_gpio_ports, ARRAY_SIZE(imx21_gpio_ports)); +} diff --git a/arch/arm/mach-imx/mm-imx25.c b/arch/arm/mach-imx/mm-imx25.c new file mode 100644 index 00000000..02f7b5c7 --- /dev/null +++ b/arch/arm/mach-imx/mm-imx25.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 1999,2000 Arm Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * - add MX31 specific definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/err.h> + +#include <asm/pgtable.h> +#include <asm/mach/map.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/mx25.h> +#include <mach/iomux-v3.h> +#include <mach/gpio.h> +#include <mach/irqs.h> + +/* + * This table defines static virtual address mappings for I/O regions. + * These are the mappings common across all MX25 boards. + */ +static struct map_desc mx25_io_desc[] __initdata = { + imx_map_entry(MX25, AVIC, MT_DEVICE_NONSHARED), + imx_map_entry(MX25, AIPS1, MT_DEVICE_NONSHARED), + imx_map_entry(MX25, AIPS2, MT_DEVICE_NONSHARED), +}; + +/* + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory mappings + * for the IO modules. + */ +void __init mx25_map_io(void) +{ + iotable_init(mx25_io_desc, ARRAY_SIZE(mx25_io_desc)); +} + +void __init imx25_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX25); + mxc_iomux_v3_init(MX25_IO_ADDRESS(MX25_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(MX25_IO_ADDRESS(MX25_WDOG_BASE_ADDR)); +} + +static struct mxc_gpio_port imx25_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ(MX25, 0, 1, MX25_INT_GPIO1), + DEFINE_IMX_GPIO_PORT_IRQ(MX25, 1, 2, MX25_INT_GPIO2), + DEFINE_IMX_GPIO_PORT_IRQ(MX25, 2, 3, MX25_INT_GPIO3), + DEFINE_IMX_GPIO_PORT_IRQ(MX25, 3, 4, MX25_INT_GPIO4), +}; + +void __init mx25_init_irq(void) +{ + mxc_init_irq(MX25_IO_ADDRESS(MX25_AVIC_BASE_ADDR)); + mxc_gpio_init(imx25_gpio_ports, ARRAY_SIZE(imx25_gpio_ports)); +} + diff --git a/arch/arm/mach-imx/mm-imx27.c b/arch/arm/mach-imx/mm-imx27.c new file mode 100644 index 00000000..a6761a39 --- /dev/null +++ b/arch/arm/mach-imx/mm-imx27.c @@ -0,0 +1,86 @@ +/* + * arch/arm/mach-imx/mm-imx27.c + * + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <mach/hardware.h> +#include <mach/common.h> +#include <asm/pgtable.h> +#include <asm/mach/map.h> +#include <mach/gpio.h> +#include <mach/irqs.h> +#include <mach/iomux-v1.h> + +/* MX27 memory map definition */ +static struct map_desc imx27_io_desc[] __initdata = { + /* + * this fixed mapping covers: + * - AIPI1 + * - AIPI2 + * - AITC + * - ROM Patch + * - and some reserved space + */ + imx_map_entry(MX27, AIPI, MT_DEVICE), + /* + * this fixed mapping covers: + * - CSI + * - ATA + */ + imx_map_entry(MX27, SAHB1, MT_DEVICE), + /* + * this fixed mapping covers: + * - EMI + */ + imx_map_entry(MX27, X_MEMC, MT_DEVICE), +}; + +/* + * Initialize the memory map. It is called during the + * system startup to create static physical to virtual + * memory map for the IO modules. + */ +void __init mx27_map_io(void) +{ + iotable_init(imx27_io_desc, ARRAY_SIZE(imx27_io_desc)); +} + +void __init imx27_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX27); + mxc_arch_reset_init(MX27_IO_ADDRESS(MX27_WDOG_BASE_ADDR)); + imx_iomuxv1_init(MX27_IO_ADDRESS(MX27_GPIO_BASE_ADDR), + MX27_NUM_GPIO_PORT); +} + +static struct mxc_gpio_port imx27_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ(MX27, 0, 1, MX27_INT_GPIO), + DEFINE_IMX_GPIO_PORT(MX27, 1, 2), + DEFINE_IMX_GPIO_PORT(MX27, 2, 3), + DEFINE_IMX_GPIO_PORT(MX27, 3, 4), + DEFINE_IMX_GPIO_PORT(MX27, 4, 5), + DEFINE_IMX_GPIO_PORT(MX27, 5, 6), +}; + +void __init mx27_init_irq(void) +{ + mxc_init_irq(MX27_IO_ADDRESS(MX27_AVIC_BASE_ADDR)); + mxc_gpio_init(imx27_gpio_ports, ARRAY_SIZE(imx27_gpio_ports)); +} diff --git a/arch/arm/mach-imx/mm-imx31.c b/arch/arm/mach-imx/mm-imx31.c new file mode 100644 index 00000000..86b9b458 --- /dev/null +++ b/arch/arm/mach-imx/mm-imx31.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 1999,2000 Arm Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * - add MX31 specific definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/err.h> + +#include <asm/pgtable.h> +#include <asm/mach/map.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-v3.h> +#include <mach/gpio.h> +#include <mach/irqs.h> + +static struct map_desc mx31_io_desc[] __initdata = { + imx_map_entry(MX31, X_MEMC, MT_DEVICE), + imx_map_entry(MX31, AVIC, MT_DEVICE_NONSHARED), + imx_map_entry(MX31, AIPS1, MT_DEVICE_NONSHARED), + imx_map_entry(MX31, AIPS2, MT_DEVICE_NONSHARED), + imx_map_entry(MX31, SPBA0, MT_DEVICE_NONSHARED), +}; + +/* + * This function initializes the memory map. It is called during the + * system startup to create static physical to virtual memory mappings + * for the IO modules. + */ +void __init mx31_map_io(void) +{ + iotable_init(mx31_io_desc, ARRAY_SIZE(mx31_io_desc)); +} + +void __init imx31_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX31); + mxc_arch_reset_init(MX31_IO_ADDRESS(MX31_WDOG_BASE_ADDR)); +} + +static struct mxc_gpio_port imx31_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ(MX31, 0, 1, MX31_INT_GPIO1), + DEFINE_IMX_GPIO_PORT_IRQ(MX31, 1, 2, MX31_INT_GPIO2), + DEFINE_IMX_GPIO_PORT_IRQ(MX31, 2, 3, MX31_INT_GPIO3), +}; + +void __init mx31_init_irq(void) +{ + mxc_init_irq(MX31_IO_ADDRESS(MX31_AVIC_BASE_ADDR)); + mxc_gpio_init(imx31_gpio_ports, ARRAY_SIZE(imx31_gpio_ports)); +} diff --git a/arch/arm/mach-imx/mm-imx35.c b/arch/arm/mach-imx/mm-imx35.c new file mode 100644 index 00000000..c880e6d1 --- /dev/null +++ b/arch/arm/mach-imx/mm-imx35.c @@ -0,0 +1,63 @@ +/* + * Copyright (C) 1999,2000 Arm Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd + * Copyright (C) 2002 Shane Nay (shane@minirl.com) + * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * - add MX31 specific definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/err.h> + +#include <asm/pgtable.h> +#include <asm/mach/map.h> +#include <asm/hardware/cache-l2x0.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-v3.h> +#include <mach/gpio.h> +#include <mach/irqs.h> + +static struct map_desc mx35_io_desc[] __initdata = { + imx_map_entry(MX35, X_MEMC, MT_DEVICE), + imx_map_entry(MX35, AVIC, MT_DEVICE_NONSHARED), + imx_map_entry(MX35, AIPS1, MT_DEVICE_NONSHARED), + imx_map_entry(MX35, AIPS2, MT_DEVICE_NONSHARED), + imx_map_entry(MX35, SPBA0, MT_DEVICE_NONSHARED), +}; + +void __init mx35_map_io(void) +{ + iotable_init(mx35_io_desc, ARRAY_SIZE(mx35_io_desc)); +} + +void __init imx35_init_early(void) +{ + mxc_set_cpu_type(MXC_CPU_MX35); + mxc_iomux_v3_init(MX35_IO_ADDRESS(MX35_IOMUXC_BASE_ADDR)); + mxc_arch_reset_init(MX35_IO_ADDRESS(MX35_WDOG_BASE_ADDR)); +} + +static struct mxc_gpio_port imx35_gpio_ports[] = { + DEFINE_IMX_GPIO_PORT_IRQ(MX35, 0, 1, MX35_INT_GPIO1), + DEFINE_IMX_GPIO_PORT_IRQ(MX35, 1, 2, MX35_INT_GPIO2), + DEFINE_IMX_GPIO_PORT_IRQ(MX35, 2, 3, MX35_INT_GPIO3), +}; + +void __init mx35_init_irq(void) +{ + mxc_init_irq(MX35_IO_ADDRESS(MX35_AVIC_BASE_ADDR)); + mxc_gpio_init(imx35_gpio_ports, ARRAY_SIZE(imx35_gpio_ports)); +} diff --git a/arch/arm/mach-imx/mx1-camera-fiq-ksym.c b/arch/arm/mach-imx/mx1-camera-fiq-ksym.c new file mode 100644 index 00000000..b09ee12a --- /dev/null +++ b/arch/arm/mach-imx/mx1-camera-fiq-ksym.c @@ -0,0 +1,18 @@ +/* + * Exported ksyms of ARCH_MX1 + * + * Copyright (C) 2008, Darius Augulis <augulis.darius@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> + +#include <mach/mx1_camera.h> + +/* IMX camera FIQ handler */ +EXPORT_SYMBOL(mx1_camera_sof_fiq_start); +EXPORT_SYMBOL(mx1_camera_sof_fiq_end); diff --git a/arch/arm/mach-imx/mx1-camera-fiq.S b/arch/arm/mach-imx/mx1-camera-fiq.S new file mode 100644 index 00000000..9c69aa65 --- /dev/null +++ b/arch/arm/mach-imx/mx1-camera-fiq.S @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2008 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> + * + * Based on linux/arch/arm/lib/floppydma.S + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + .global mx1_camera_sof_fiq_end + .global mx1_camera_sof_fiq_start +mx1_camera_sof_fiq_start: + @ enable dma + ldr r12, [r9] + orr r12, r12, #0x00000001 + str r12, [r9] + @ unmask DMA interrupt + ldr r12, [r8] + bic r12, r12, r13 + str r12, [r8] + @ disable SOF interrupt + ldr r12, [r10] + bic r12, r12, #0x00010000 + str r12, [r10] + @ clear SOF flag + mov r12, #0x00010000 + str r12, [r11] + @ return from FIQ + subs pc, lr, #4 +mx1_camera_sof_fiq_end: diff --git a/arch/arm/mach-imx/mx31lilly-db.c b/arch/arm/mach-imx/mx31lilly-db.c new file mode 100644 index 00000000..7d26f766 --- /dev/null +++ b/arch/arm/mach-imx/mx31lilly-db.c @@ -0,0 +1,216 @@ +/* + * LILLY-1131 development board support + * + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * + * based on code for other MX31 boards, + * + * Copyright 2005-2007 Freescale Semiconductor + * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx3.h> +#include <mach/board-mx31lilly.h> + +#include "devices-imx31.h" + +/* + * This file contains board-specific initialization routines for the + * LILLY-1131 development board. If you design an own baseboard for the + * module, use this file as base for support code. + */ + +static unsigned int lilly_db_board_pins[] __initdata = { + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + MX31_PIN_CTS2__CTS2, + MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, + MX31_PIN_RXD2__RXD2, + MX31_PIN_CSPI3_MOSI__RXD3, + MX31_PIN_CSPI3_MISO__TXD3, + MX31_PIN_CSPI3_SCLK__RTS3, + MX31_PIN_CSPI3_SPI_RDY__CTS3, + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, + MX31_PIN_LD0__LD0, + MX31_PIN_LD1__LD1, + MX31_PIN_LD2__LD2, + MX31_PIN_LD3__LD3, + MX31_PIN_LD4__LD4, + MX31_PIN_LD5__LD5, + MX31_PIN_LD6__LD6, + MX31_PIN_LD7__LD7, + MX31_PIN_LD8__LD8, + MX31_PIN_LD9__LD9, + MX31_PIN_LD10__LD10, + MX31_PIN_LD11__LD11, + MX31_PIN_LD12__LD12, + MX31_PIN_LD13__LD13, + MX31_PIN_LD14__LD14, + MX31_PIN_LD15__LD15, + MX31_PIN_LD16__LD16, + MX31_PIN_LD17__LD17, + MX31_PIN_VSYNC3__VSYNC3, + MX31_PIN_HSYNC__HSYNC, + MX31_PIN_FPSHIFT__FPSHIFT, + MX31_PIN_DRDY0__DRDY0, + MX31_PIN_CONTRAST__CONTRAST, +}; + +/* UART */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* MMC support */ + +static int mxc_mmc1_get_ro(struct device *dev) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_LCS0)); +} + +static int gpio_det, gpio_wp; + +#define MMC_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +static int mxc_mmc1_init(struct device *dev, + irq_handler_t detect_irq, void *data) +{ + int ret; + + gpio_det = IOMUX_TO_GPIO(MX31_PIN_GPIO1_1); + gpio_wp = IOMUX_TO_GPIO(MX31_PIN_LCS0); + + mxc_iomux_set_pad(MX31_PIN_SD1_DATA0, MMC_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SD1_DATA1, MMC_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SD1_DATA2, MMC_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SD1_DATA3, MMC_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SD1_CLK, MMC_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SD1_CMD, MMC_PAD_CFG); + + ret = gpio_request(gpio_det, "MMC detect"); + if (ret) + return ret; + + ret = gpio_request(gpio_wp, "MMC w/p"); + if (ret) + goto exit_free_det; + + gpio_direction_input(gpio_det); + gpio_direction_input(gpio_wp); + + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), detect_irq, + IRQF_DISABLED | IRQF_TRIGGER_FALLING, + "MMC detect", data); + if (ret) + goto exit_free_wp; + + return 0; + +exit_free_wp: + gpio_free(gpio_wp); + +exit_free_det: + gpio_free(gpio_det); + + return ret; +} + +static void mxc_mmc1_exit(struct device *dev, void *data) +{ + gpio_free(gpio_det); + gpio_free(gpio_wp); + free_irq(IOMUX_TO_IRQ(MX31_PIN_GPIO1_1), data); +} + +static const struct imxmmc_platform_data mmc_pdata __initconst = { + .get_ro = mxc_mmc1_get_ro, + .init = mxc_mmc1_init, + .exit = mxc_mmc1_exit, +}; + +/* Framebuffer support */ +static const struct ipu_platform_data ipu_data __initconst = { + .irq_base = MXC_IPU_IRQ_START, +}; + +static const struct fb_videomode fb_modedb = { + /* 640x480 TFT panel (IPS-056T) */ + .name = "CRT-VGA", + .refresh = 64, + .xres = 640, + .yres = 480, + .pixclock = 30000, + .left_margin = 200, + .right_margin = 2, + .upper_margin = 2, + .lower_margin = 2, + .hsync_len = 3, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct mx3fb_platform_data fb_pdata __initdata = { + .name = "CRT-VGA", + .mode = &fb_modedb, + .num_modes = 1, +}; + +#define LCD_VCC_EN_GPIO (7) + +static void __init mx31lilly_init_fb(void) +{ + if (gpio_request(LCD_VCC_EN_GPIO, "LCD enable") != 0) { + printk(KERN_WARNING "unable to request LCD_VCC_EN pin.\n"); + return; + } + + imx31_add_ipu_core(&ipu_data); + imx31_add_mx3_sdc_fb(&fb_pdata); + gpio_direction_output(LCD_VCC_EN_GPIO, 1); +} + +void __init mx31lilly_db_init(void) +{ + mxc_iomux_setup_multiple_pins(lilly_db_board_pins, + ARRAY_SIZE(lilly_db_board_pins), + "development board pins"); + imx31_add_imx_uart0(&uart_pdata); + imx31_add_imx_uart1(&uart_pdata); + imx31_add_imx_uart2(&uart_pdata); + imx31_add_mxc_mmc(0, &mmc_pdata); + mx31lilly_init_fb(); +} diff --git a/arch/arm/mach-imx/mx31lite-db.c b/arch/arm/mach-imx/mx31lite-db.c new file mode 100644 index 00000000..5aa053ed --- /dev/null +++ b/arch/arm/mach-imx/mx31lite-db.c @@ -0,0 +1,203 @@ +/* + * LogicPD i.MX31 SOM-LV development board support + * + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * + * based on code for other MX31 boards, + * + * Copyright 2005-2007 Freescale Semiconductor + * Copyright (c) 2009 Alberto Panizzo <maramaopercheseimorto@gmail.com> + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/common.h> +#include <mach/iomux-mx3.h> +#include <mach/board-mx31lite.h> + +#include "devices-imx31.h" + +/* + * This file contains board-specific initialization routines for the + * LogicPD i.MX31 SOM-LV development board, aka 'LiteKit'. + * If you design an own baseboard for the module, use this file as base + * for support code. + */ + +static unsigned int litekit_db_board_pins[] __initdata = { + /* UART1 */ + MX31_PIN_CTS1__CTS1, + MX31_PIN_RTS1__RTS1, + MX31_PIN_TXD1__TXD1, + MX31_PIN_RXD1__RXD1, + /* SPI 0 */ + MX31_PIN_CSPI1_SCLK__SCLK, + MX31_PIN_CSPI1_MOSI__MOSI, + MX31_PIN_CSPI1_MISO__MISO, + MX31_PIN_CSPI1_SPI_RDY__SPI_RDY, + MX31_PIN_CSPI1_SS0__SS0, + MX31_PIN_CSPI1_SS1__SS1, + MX31_PIN_CSPI1_SS2__SS2, + /* SDHC1 */ + MX31_PIN_SD1_DATA0__SD1_DATA0, + MX31_PIN_SD1_DATA1__SD1_DATA1, + MX31_PIN_SD1_DATA2__SD1_DATA2, + MX31_PIN_SD1_DATA3__SD1_DATA3, + MX31_PIN_SD1_CLK__SD1_CLK, + MX31_PIN_SD1_CMD__SD1_CMD, +}; + +/* UART */ +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +/* MMC */ + +static int gpio_det, gpio_wp; + +#define MMC_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS) + +static int mxc_mmc1_get_ro(struct device *dev) +{ + return gpio_get_value(IOMUX_TO_GPIO(MX31_PIN_GPIO1_6)); +} + +static int mxc_mmc1_init(struct device *dev, + irq_handler_t detect_irq, void *data) +{ + int ret; + + gpio_det = IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1); + gpio_wp = IOMUX_TO_GPIO(MX31_PIN_GPIO1_6); + + mxc_iomux_set_pad(MX31_PIN_SD1_DATA0, + MMC_PAD_CFG | PAD_CTL_PUE_PUD | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_SD1_DATA1, + MMC_PAD_CFG | PAD_CTL_PUE_PUD | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_SD1_DATA2, + MMC_PAD_CFG | PAD_CTL_PUE_PUD | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_SD1_DATA3, + MMC_PAD_CFG | PAD_CTL_PUE_PUD | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_SD1_CMD, + MMC_PAD_CFG | PAD_CTL_PUE_PUD | PAD_CTL_100K_PU); + mxc_iomux_set_pad(MX31_PIN_SD1_CLK, MMC_PAD_CFG); + + ret = gpio_request(gpio_det, "MMC detect"); + if (ret) + return ret; + + ret = gpio_request(gpio_wp, "MMC w/p"); + if (ret) + goto exit_free_det; + + gpio_direction_input(gpio_det); + gpio_direction_input(gpio_wp); + + ret = request_irq(IOMUX_TO_IRQ(MX31_PIN_DCD_DCE1), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "MMC detect", data); + if (ret) + goto exit_free_wp; + + return 0; + +exit_free_wp: + gpio_free(gpio_wp); + +exit_free_det: + gpio_free(gpio_det); + + return ret; +} + +static void mxc_mmc1_exit(struct device *dev, void *data) +{ + gpio_free(gpio_det); + gpio_free(gpio_wp); + free_irq(IOMUX_TO_IRQ(MX31_PIN_DCD_DCE1), data); +} + +static const struct imxmmc_platform_data mmc_pdata __initconst = { + .get_ro = mxc_mmc1_get_ro, + .init = mxc_mmc1_init, + .exit = mxc_mmc1_exit, +}; + +/* SPI */ + +static int spi_internal_chipselect[] = { + MXC_SPI_CS(0), + MXC_SPI_CS(1), + MXC_SPI_CS(2), +}; + +static const struct spi_imx_master spi0_pdata __initconst = { + .chipselect = spi_internal_chipselect, + .num_chipselect = ARRAY_SIZE(spi_internal_chipselect), +}; + +/* GPIO LEDs */ + +static struct gpio_led litekit_leds[] = { + { + .name = "GPIO0", + .gpio = IOMUX_TO_GPIO(MX31_PIN_COMPARE), + .active_low = 1, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + }, + { + .name = "GPIO1", + .gpio = IOMUX_TO_GPIO(MX31_PIN_CAPTURE), + .active_low = 1, + .default_state = LEDS_GPIO_DEFSTATE_OFF, + } +}; + +static struct gpio_led_platform_data litekit_led_platform_data = { + .leds = litekit_leds, + .num_leds = ARRAY_SIZE(litekit_leds), +}; + +static struct platform_device litekit_led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &litekit_led_platform_data, + }, +}; + +void __init mx31lite_db_init(void) +{ + mxc_iomux_setup_multiple_pins(litekit_db_board_pins, + ARRAY_SIZE(litekit_db_board_pins), + "development board pins"); + imx31_add_imx_uart0(&uart_pdata); + imx31_add_mxc_mmc(0, &mmc_pdata); + imx31_add_spi_imx0(&spi0_pdata); + platform_device_register(&litekit_led_device); + imx31_add_imx2_wdt(NULL); + imx31_add_mxc_rtc(NULL); +} diff --git a/arch/arm/mach-imx/mx31moboard-devboard.c b/arch/arm/mach-imx/mx31moboard-devboard.c new file mode 100644 index 00000000..0aa25364 --- /dev/null +++ b/arch/arm/mach-imx/mx31moboard-devboard.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <linux/usb/otg.h> + +#include <mach/common.h> +#include <mach/iomux-mx3.h> +#include <mach/hardware.h> +#include <mach/ulpi.h> + +#include "devices-imx31.h" + +static unsigned int devboard_pins[] = { + /* UART1 */ + MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2, + /* SDHC2 */ + MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2, + MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0, + MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD, + MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29, + /* USB H1 */ + MX31_PIN_CSPI1_MISO__USBH1_RXDP, MX31_PIN_CSPI1_MOSI__USBH1_RXDM, + MX31_PIN_CSPI1_SS0__USBH1_TXDM, MX31_PIN_CSPI1_SS1__USBH1_TXDP, + MX31_PIN_CSPI1_SS2__USBH1_RCV, MX31_PIN_CSPI1_SCLK__USBH1_OEB, + MX31_PIN_CSPI1_SPI_RDY__USBH1_FS, MX31_PIN_SFS6__USBH1_SUSPEND, + MX31_PIN_NFRE_B__GPIO1_11, MX31_PIN_NFALE__GPIO1_12, + /* SEL */ + MX31_PIN_DTR_DCE1__GPIO2_8, MX31_PIN_DSR_DCE1__GPIO2_9, + MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR) +#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW) + +static int devboard_sdhc2_get_ro(struct device *dev) +{ + return !gpio_get_value(SDHC2_WP); +} + +static int devboard_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC2_CD, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC2_CD); + + ret = gpio_request(SDHC2_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC2_WP); + + ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "sdhc2-card-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(SDHC2_WP); +err_gpio_free: + gpio_free(SDHC2_CD); + + return ret; +} + +static void devboard_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(SDHC2_CD), data); + gpio_free(SDHC2_WP); + gpio_free(SDHC2_CD); +} + +static const struct imxmmc_platform_data sdhc2_pdata __initconst = { + .get_ro = devboard_sdhc2_get_ro, + .init = devboard_sdhc2_init, + .exit = devboard_sdhc2_exit, +}; + +#define SEL0 IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1) +#define SEL1 IOMUX_TO_GPIO(MX31_PIN_DSR_DCE1) +#define SEL2 IOMUX_TO_GPIO(MX31_PIN_RI_DCE1) +#define SEL3 IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1) + +static void devboard_init_sel_gpios(void) +{ + if (!gpio_request(SEL0, "sel0")) { + gpio_direction_input(SEL0); + gpio_export(SEL0, true); + } + + if (!gpio_request(SEL1, "sel1")) { + gpio_direction_input(SEL1); + gpio_export(SEL1, true); + } + + if (!gpio_request(SEL2, "sel2")) { + gpio_direction_input(SEL2); + gpio_export(SEL2, true); + } + + if (!gpio_request(SEL3, "sel3")) { + gpio_direction_input(SEL3); + gpio_export(SEL3, true); + } +} +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +static int devboard_usbh1_hw_init(struct platform_device *pdev) +{ + mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true); + + mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG); + + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_INTERFACE_SINGLE_UNI); +} + +#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B) +#define USBH1_MODE IOMUX_TO_GPIO(MX31_PIN_NFALE) + +static int devboard_isp1105_init(struct otg_transceiver *otg) +{ + int ret = gpio_request(USBH1_MODE, "usbh1-mode"); + if (ret) + return ret; + /* single ended */ + gpio_direction_output(USBH1_MODE, 0); + + ret = gpio_request(USBH1_VBUSEN_B, "usbh1-vbusen"); + if (ret) { + gpio_free(USBH1_MODE); + return ret; + } + gpio_direction_output(USBH1_VBUSEN_B, 1); + + return 0; +} + + +static int devboard_isp1105_set_vbus(struct otg_transceiver *otg, bool on) +{ + if (on) + gpio_set_value(USBH1_VBUSEN_B, 0); + else + gpio_set_value(USBH1_VBUSEN_B, 1); + + return 0; +} + +static struct mxc_usbh_platform_data usbh1_pdata __initdata = { + .init = devboard_usbh1_hw_init, + .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL, +}; + +static int __init devboard_usbh1_init(void) +{ + struct otg_transceiver *otg; + struct platform_device *pdev; + + otg = kzalloc(sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + otg->label = "ISP1105"; + otg->init = devboard_isp1105_init; + otg->set_vbus = devboard_isp1105_set_vbus; + + usbh1_pdata.otg = otg; + + pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} + + +static const struct fsl_usb2_platform_data usb_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +/* + * system init for baseboard usage. Will be called by mx31moboard init. + */ +void __init mx31moboard_devboard_init(void) +{ + printk(KERN_INFO "Initializing mx31devboard peripherals\n"); + + mxc_iomux_setup_multiple_pins(devboard_pins, ARRAY_SIZE(devboard_pins), + "devboard"); + + imx31_add_imx_uart1(&uart_pdata); + + imx31_add_mxc_mmc(1, &sdhc2_pdata); + + devboard_init_sel_gpios(); + + imx31_add_fsl_usb2_udc(&usb_pdata); + + devboard_usbh1_init(); +} diff --git a/arch/arm/mach-imx/mx31moboard-marxbot.c b/arch/arm/mach-imx/mx31moboard-marxbot.c new file mode 100644 index 00000000..bb639cbd --- /dev/null +++ b/arch/arm/mach-imx/mx31moboard-marxbot.c @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#include <linux/usb/otg.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx3.h> +#include <mach/ulpi.h> + +#include <media/soc_camera.h> + +#include "devices-imx31.h" + +static unsigned int marxbot_pins[] = { + /* SDHC2 */ + MX31_PIN_PC_PWRON__SD2_DATA3, MX31_PIN_PC_VS1__SD2_DATA2, + MX31_PIN_PC_READY__SD2_DATA1, MX31_PIN_PC_WAIT_B__SD2_DATA0, + MX31_PIN_PC_CD2_B__SD2_CLK, MX31_PIN_PC_CD1_B__SD2_CMD, + MX31_PIN_ATA_DIOR__GPIO3_28, MX31_PIN_ATA_DIOW__GPIO3_29, + /* CSI */ + MX31_PIN_CSI_D6__CSI_D6, MX31_PIN_CSI_D7__CSI_D7, + MX31_PIN_CSI_D8__CSI_D8, MX31_PIN_CSI_D9__CSI_D9, + MX31_PIN_CSI_D10__CSI_D10, MX31_PIN_CSI_D11__CSI_D11, + MX31_PIN_CSI_D12__CSI_D12, MX31_PIN_CSI_D13__CSI_D13, + MX31_PIN_CSI_D14__CSI_D14, MX31_PIN_CSI_D15__CSI_D15, + MX31_PIN_CSI_HSYNC__CSI_HSYNC, MX31_PIN_CSI_MCLK__CSI_MCLK, + MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, MX31_PIN_CSI_VSYNC__CSI_VSYNC, + MX31_PIN_CSI_D4__GPIO3_4, MX31_PIN_CSI_D5__GPIO3_5, + MX31_PIN_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1, + MX31_PIN_TXD2__GPIO1_28, + /* dsPIC resets */ + MX31_PIN_STXD5__GPIO1_21, MX31_PIN_SRXD5__GPIO1_22, + /*battery detection */ + MX31_PIN_LCS0__GPIO3_23, + /* USB H1 */ + MX31_PIN_CSPI1_MISO__USBH1_RXDP, MX31_PIN_CSPI1_MOSI__USBH1_RXDM, + MX31_PIN_CSPI1_SS0__USBH1_TXDM, MX31_PIN_CSPI1_SS1__USBH1_TXDP, + MX31_PIN_CSPI1_SS2__USBH1_RCV, MX31_PIN_CSPI1_SCLK__USBH1_OEB, + MX31_PIN_CSPI1_SPI_RDY__USBH1_FS, MX31_PIN_SFS6__USBH1_SUSPEND, + MX31_PIN_NFRE_B__GPIO1_11, MX31_PIN_NFALE__GPIO1_12, + /* SEL */ + MX31_PIN_DTR_DCE1__GPIO2_8, MX31_PIN_DSR_DCE1__GPIO2_9, + MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11, +}; + +#define SDHC2_CD IOMUX_TO_GPIO(MX31_PIN_ATA_DIOR) +#define SDHC2_WP IOMUX_TO_GPIO(MX31_PIN_ATA_DIOW) + +static int marxbot_sdhc2_get_ro(struct device *dev) +{ + return !gpio_get_value(SDHC2_WP); +} + +static int marxbot_sdhc2_init(struct device *dev, irq_handler_t detect_irq, + void *data) +{ + int ret; + + ret = gpio_request(SDHC2_CD, "sdhc-detect"); + if (ret) + return ret; + + gpio_direction_input(SDHC2_CD); + + ret = gpio_request(SDHC2_WP, "sdhc-wp"); + if (ret) + goto err_gpio_free; + gpio_direction_input(SDHC2_WP); + + ret = request_irq(gpio_to_irq(SDHC2_CD), detect_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "sdhc2-card-detect", data); + if (ret) + goto err_gpio_free_2; + + return 0; + +err_gpio_free_2: + gpio_free(SDHC2_WP); +err_gpio_free: + gpio_free(SDHC2_CD); + + return ret; +} + +static void marxbot_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(gpio_to_irq(SDHC2_CD), data); + gpio_free(SDHC2_WP); + gpio_free(SDHC2_CD); +} + +static const struct imxmmc_platform_data sdhc2_pdata __initconst = { + .get_ro = marxbot_sdhc2_get_ro, + .init = marxbot_sdhc2_init, + .exit = marxbot_sdhc2_exit, +}; + +#define TRSLAT_RST_B IOMUX_TO_GPIO(MX31_PIN_STXD5) +#define DSPICS_RST_B IOMUX_TO_GPIO(MX31_PIN_SRXD5) + +static void dspics_resets_init(void) +{ + if (!gpio_request(TRSLAT_RST_B, "translator-rst")) { + gpio_direction_output(TRSLAT_RST_B, 0); + gpio_export(TRSLAT_RST_B, false); + } + + if (!gpio_request(DSPICS_RST_B, "dspics-rst")) { + gpio_direction_output(DSPICS_RST_B, 0); + gpio_export(DSPICS_RST_B, false); + } +} + +static struct spi_board_info marxbot_spi_board_info[] __initdata = { + { + .modalias = "spidev", + .max_speed_hz = 300000, + .bus_num = 1, + .chip_select = 1, /* according spi1_cs[] ! */ + }, +}; + +#define TURRETCAM_POWER IOMUX_TO_GPIO(MX31_PIN_GPIO3_1) +#define BASECAM_POWER IOMUX_TO_GPIO(MX31_PIN_CSI_D5) +#define TURRETCAM_RST_B IOMUX_TO_GPIO(MX31_PIN_GPIO3_0) +#define BASECAM_RST_B IOMUX_TO_GPIO(MX31_PIN_CSI_D4) +#define CAM_CHOICE IOMUX_TO_GPIO(MX31_PIN_TXD2) + +static int marxbot_basecam_power(struct device *dev, int on) +{ + gpio_set_value(BASECAM_POWER, !on); + return 0; +} + +static int marxbot_basecam_reset(struct device *dev) +{ + gpio_set_value(BASECAM_RST_B, 0); + udelay(100); + gpio_set_value(BASECAM_RST_B, 1); + return 0; +} + +static struct i2c_board_info marxbot_i2c_devices[] = { + { + I2C_BOARD_INFO("mt9t031", 0x5d), + }, +}; + +static struct soc_camera_link base_iclink = { + .bus_id = 0, /* Must match with the camera ID */ + .power = marxbot_basecam_power, + .reset = marxbot_basecam_reset, + .board_info = &marxbot_i2c_devices[0], + .i2c_adapter_id = 0, +}; + +static struct platform_device marxbot_camera[] = { + { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &base_iclink, + }, + }, +}; + +static struct platform_device *marxbot_cameras[] __initdata = { + &marxbot_camera[0], +}; + +static int __init marxbot_cam_init(void) +{ + int ret = gpio_request(CAM_CHOICE, "cam-choice"); + if (ret) + return ret; + gpio_direction_output(CAM_CHOICE, 0); + + ret = gpio_request(BASECAM_RST_B, "basecam-reset"); + if (ret) + return ret; + gpio_direction_output(BASECAM_RST_B, 1); + ret = gpio_request(BASECAM_POWER, "basecam-standby"); + if (ret) + return ret; + gpio_direction_output(BASECAM_POWER, 0); + + ret = gpio_request(TURRETCAM_RST_B, "turretcam-reset"); + if (ret) + return ret; + gpio_direction_output(TURRETCAM_RST_B, 1); + ret = gpio_request(TURRETCAM_POWER, "turretcam-standby"); + if (ret) + return ret; + gpio_direction_output(TURRETCAM_POWER, 0); + + return 0; +} + +#define SEL0 IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1) +#define SEL1 IOMUX_TO_GPIO(MX31_PIN_DSR_DCE1) +#define SEL2 IOMUX_TO_GPIO(MX31_PIN_RI_DCE1) +#define SEL3 IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1) + +static void marxbot_init_sel_gpios(void) +{ + if (!gpio_request(SEL0, "sel0")) { + gpio_direction_input(SEL0); + gpio_export(SEL0, true); + } + + if (!gpio_request(SEL1, "sel1")) { + gpio_direction_input(SEL1); + gpio_export(SEL1, true); + } + + if (!gpio_request(SEL2, "sel2")) { + gpio_direction_input(SEL2); + gpio_export(SEL2, true); + } + + if (!gpio_request(SEL3, "sel3")) { + gpio_direction_input(SEL3); + gpio_export(SEL3, true); + } +} + +#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \ + PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + +static int marxbot_usbh1_hw_init(struct platform_device *pdev) +{ + mxc_iomux_set_gpr(MUX_PGP_USB_SUSPEND, true); + + mxc_iomux_set_pad(MX31_PIN_CSPI1_MISO, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_MOSI, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS0, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS1, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SS2, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SCLK, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_CSPI1_SPI_RDY, USB_PAD_CFG); + mxc_iomux_set_pad(MX31_PIN_SFS6, USB_PAD_CFG); + + mdelay(10); + + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED | + MXC_EHCI_INTERFACE_SINGLE_UNI); +} + +#define USBH1_VBUSEN_B IOMUX_TO_GPIO(MX31_PIN_NFRE_B) +#define USBH1_MODE IOMUX_TO_GPIO(MX31_PIN_NFALE) + +static int marxbot_isp1105_init(struct otg_transceiver *otg) +{ + int ret = gpio_request(USBH1_MODE, "usbh1-mode"); + if (ret) + return ret; + /* single ended */ + gpio_direction_output(USBH1_MODE, 0); + + ret = gpio_request(USBH1_VBUSEN_B, "usbh1-vbusen"); + if (ret) { + gpio_free(USBH1_MODE); + return ret; + } + gpio_direction_output(USBH1_VBUSEN_B, 1); + + return 0; +} + + +static int marxbot_isp1105_set_vbus(struct otg_transceiver *otg, bool on) +{ + if (on) + gpio_set_value(USBH1_VBUSEN_B, 0); + else + gpio_set_value(USBH1_VBUSEN_B, 1); + + return 0; +} + +static struct mxc_usbh_platform_data usbh1_pdata __initdata = { + .init = marxbot_usbh1_hw_init, + .portsc = MXC_EHCI_MODE_UTMI | MXC_EHCI_SERIAL, +}; + +static int __init marxbot_usbh1_init(void) +{ + struct otg_transceiver *otg; + struct platform_device *pdev; + + otg = kzalloc(sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + otg->label = "ISP1105"; + otg->init = marxbot_isp1105_init; + otg->set_vbus = marxbot_isp1105_set_vbus; + + usbh1_pdata.otg = otg; + + pdev = imx31_add_mxc_ehci_hs(1, &usbh1_pdata); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} + +static const struct fsl_usb2_platform_data usb_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +/* + * system init for baseboard usage. Will be called by mx31moboard init. + */ +void __init mx31moboard_marxbot_init(void) +{ + printk(KERN_INFO "Initializing mx31marxbot peripherals\n"); + + mxc_iomux_setup_multiple_pins(marxbot_pins, ARRAY_SIZE(marxbot_pins), + "marxbot"); + + marxbot_init_sel_gpios(); + + dspics_resets_init(); + + imx31_add_mxc_mmc(1, &sdhc2_pdata); + + spi_register_board_info(marxbot_spi_board_info, + ARRAY_SIZE(marxbot_spi_board_info)); + + marxbot_cam_init(); + platform_add_devices(marxbot_cameras, ARRAY_SIZE(marxbot_cameras)); + + /* battery present pin */ + gpio_request(IOMUX_TO_GPIO(MX31_PIN_LCS0), "bat-present"); + gpio_direction_input(IOMUX_TO_GPIO(MX31_PIN_LCS0)); + gpio_export(IOMUX_TO_GPIO(MX31_PIN_LCS0), false); + + imx31_add_fsl_usb2_udc(&usb_pdata); + + marxbot_usbh1_init(); +} diff --git a/arch/arm/mach-imx/mx31moboard-smartbot.c b/arch/arm/mach-imx/mx31moboard-smartbot.c new file mode 100644 index 00000000..fabb801e --- /dev/null +++ b/arch/arm/mach-imx/mx31moboard-smartbot.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2009 Valentin Longchamp, EPFL Mobots group + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#include <linux/usb/otg.h> +#include <linux/usb/ulpi.h> + +#include <mach/common.h> +#include <mach/hardware.h> +#include <mach/iomux-mx3.h> +#include <mach/board-mx31moboard.h> +#include <mach/ulpi.h> + +#include <media/soc_camera.h> + +#include "devices-imx31.h" + +static unsigned int smartbot_pins[] = { + /* UART1 */ + MX31_PIN_CTS2__CTS2, MX31_PIN_RTS2__RTS2, + MX31_PIN_TXD2__TXD2, MX31_PIN_RXD2__RXD2, + /* CSI */ + MX31_PIN_CSI_D4__CSI_D4, MX31_PIN_CSI_D5__CSI_D5, + MX31_PIN_CSI_D6__CSI_D6, MX31_PIN_CSI_D7__CSI_D7, + MX31_PIN_CSI_D8__CSI_D8, MX31_PIN_CSI_D9__CSI_D9, + MX31_PIN_CSI_D10__CSI_D10, MX31_PIN_CSI_D11__CSI_D11, + MX31_PIN_CSI_D12__CSI_D12, MX31_PIN_CSI_D13__CSI_D13, + MX31_PIN_CSI_D14__CSI_D14, MX31_PIN_CSI_D15__CSI_D15, + MX31_PIN_CSI_HSYNC__CSI_HSYNC, MX31_PIN_CSI_MCLK__CSI_MCLK, + MX31_PIN_CSI_PIXCLK__CSI_PIXCLK, MX31_PIN_CSI_VSYNC__CSI_VSYNC, + MX31_PIN_GPIO3_0__GPIO3_0, MX31_PIN_GPIO3_1__GPIO3_1, + /* ENABLES */ + MX31_PIN_DTR_DCE1__GPIO2_8, MX31_PIN_DSR_DCE1__GPIO2_9, + MX31_PIN_RI_DCE1__GPIO2_10, MX31_PIN_DCD_DCE1__GPIO2_11, +}; + +static const struct imxuart_platform_data uart_pdata __initconst = { + .flags = IMXUART_HAVE_RTSCTS, +}; + +#define CAM_POWER IOMUX_TO_GPIO(MX31_PIN_GPIO3_1) +#define CAM_RST_B IOMUX_TO_GPIO(MX31_PIN_GPIO3_0) + +static int smartbot_cam_power(struct device *dev, int on) +{ + gpio_set_value(CAM_POWER, !on); + return 0; +} + +static int smartbot_cam_reset(struct device *dev) +{ + gpio_set_value(CAM_RST_B, 0); + udelay(100); + gpio_set_value(CAM_RST_B, 1); + return 0; +} + +static struct i2c_board_info smartbot_i2c_devices[] = { + { + I2C_BOARD_INFO("mt9t031", 0x5d), + }, +}; + +static struct soc_camera_link base_iclink = { + .bus_id = 0, /* Must match with the camera ID */ + .power = smartbot_cam_power, + .reset = smartbot_cam_reset, + .board_info = &smartbot_i2c_devices[0], + .i2c_adapter_id = 0, +}; + +static struct platform_device smartbot_camera[] = { + { + .name = "soc-camera-pdrv", + .id = 0, + .dev = { + .platform_data = &base_iclink, + }, + }, +}; + +static struct platform_device *smartbot_cameras[] __initdata = { + &smartbot_camera[0], +}; + +static int __init smartbot_cam_init(void) +{ + int ret = gpio_request(CAM_RST_B, "cam-reset"); + if (ret) + return ret; + gpio_direction_output(CAM_RST_B, 1); + ret = gpio_request(CAM_POWER, "cam-standby"); + if (ret) + return ret; + gpio_direction_output(CAM_POWER, 0); + + return 0; +} + +static const struct fsl_usb2_platform_data usb_pdata __initconst = { + .operating_mode = FSL_USB2_DR_DEVICE, + .phy_mode = FSL_USB2_PHY_ULPI, +}; + +#if defined(CONFIG_USB_ULPI) + +static int smartbot_otg_init(struct platform_device *pdev) +{ + return mx31_initialize_usb_hw(pdev->id, MXC_EHCI_POWER_PINS_ENABLED); +} + +static struct mxc_usbh_platform_data otg_host_pdata __initdata = { + .init = smartbot_otg_init, + .portsc = MXC_EHCI_MODE_ULPI | MXC_EHCI_UTMI_8BIT, +}; + +static int __init smartbot_otg_host_init(void) +{ + struct platform_device *pdev; + + otg_host_pdata.otg = imx_otg_ulpi_create(ULPI_OTG_DRVVBUS | + ULPI_OTG_DRVVBUS_EXT); + if (!otg_host_pdata.otg) + return -ENODEV; + + pdev = imx31_add_mxc_ehci_otg(&otg_host_pdata); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} +#else +static inline int smartbot_otg_host_init(void) { return 0; } +#endif + +#define POWER_EN IOMUX_TO_GPIO(MX31_PIN_DTR_DCE1) +#define DSPIC_RST_B IOMUX_TO_GPIO(MX31_PIN_DSR_DCE1) +#define TRSLAT_RST_B IOMUX_TO_GPIO(MX31_PIN_RI_DCE1) +#define TRSLAT_SRC_CHOICE IOMUX_TO_GPIO(MX31_PIN_DCD_DCE1) + +static void smartbot_resets_init(void) +{ + if (!gpio_request(POWER_EN, "power-enable")) { + gpio_direction_output(POWER_EN, 0); + gpio_export(POWER_EN, false); + } + + if (!gpio_request(DSPIC_RST_B, "dspic-rst")) { + gpio_direction_output(DSPIC_RST_B, 0); + gpio_export(DSPIC_RST_B, false); + } + + if (!gpio_request(TRSLAT_RST_B, "translator-rst")) { + gpio_direction_output(TRSLAT_RST_B, 0); + gpio_export(TRSLAT_RST_B, false); + } + + if (!gpio_request(TRSLAT_SRC_CHOICE, "translator-src-choice")) { + gpio_direction_output(TRSLAT_SRC_CHOICE, 0); + gpio_export(TRSLAT_SRC_CHOICE, false); + } +} +/* + * system init for baseboard usage. Will be called by mx31moboard init. + */ +void __init mx31moboard_smartbot_init(int board) +{ + printk(KERN_INFO "Initializing mx31smartbot peripherals\n"); + + mxc_iomux_setup_multiple_pins(smartbot_pins, ARRAY_SIZE(smartbot_pins), + "smartbot"); + + imx31_add_imx_uart1(&uart_pdata); + + switch (board) { + case MX31SMARTBOT: + imx31_add_fsl_usb2_udc(&usb_pdata); + break; + case MX31EYEBOT: + smartbot_otg_host_init(); + break; + default: + printk(KERN_WARNING "Unknown board %d, USB OTG not initialized", + board); + } + + smartbot_resets_init(); + + smartbot_cam_init(); + platform_add_devices(smartbot_cameras, ARRAY_SIZE(smartbot_cameras)); +} diff --git a/arch/arm/mach-imx/pcm037.h b/arch/arm/mach-imx/pcm037.h new file mode 100644 index 00000000..d6929721 --- /dev/null +++ b/arch/arm/mach-imx/pcm037.h @@ -0,0 +1,11 @@ +#ifndef __PCM037_H__ +#define __PCM037_H__ + +enum pcm037_board_variant { + PCM037_PCM970, + PCM037_EET, +}; + +extern enum pcm037_board_variant pcm037_variant(void); + +#endif diff --git a/arch/arm/mach-imx/pcm970-baseboard.c b/arch/arm/mach-imx/pcm970-baseboard.c new file mode 100644 index 00000000..99afbc3f --- /dev/null +++ b/arch/arm/mach-imx/pcm970-baseboard.c @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/gpio.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/can/platform/sja1000.h> + +#include <asm/mach/arch.h> + +#include <mach/common.h> +#include <mach/iomux-mx27.h> +#include <mach/hardware.h> + +#include "devices-imx27.h" + +static const int pcm970_pins[] __initconst = { + /* SDHC */ + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, + /* display */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA24_PF_REV, + PA25_PF_CLS, + PA26_PF_PS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* + * it seems the data line misses a pullup, so we must enable + * the internal pullup as a local workaround + */ + PD17_PF_I2C_DATA | GPIO_PUEN, + PD18_PF_I2C_CLK, + /* Camera */ + PB10_PF_CSI_D0, + PB11_PF_CSI_D1, + PB12_PF_CSI_D2, + PB13_PF_CSI_D3, + PB14_PF_CSI_D4, + PB15_PF_CSI_MCLK, + PB16_PF_CSI_PIXCLK, + PB17_PF_CSI_D5, + PB18_PF_CSI_D6, + PB19_PF_CSI_D7, + PB20_PF_CSI_VSYNC, + PB21_PF_CSI_HSYNC, +}; + +static int pcm970_sdhc2_get_ro(struct device *dev) +{ + return gpio_get_value(GPIO_PORTC + 28); +} + +static int pcm970_sdhc2_init(struct device *dev, irq_handler_t detect_irq, void *data) +{ + int ret; + + ret = request_irq(IRQ_GPIOC(29), detect_irq, IRQF_TRIGGER_FALLING, + "imx-mmc-detect", data); + if (ret) + return ret; + + ret = gpio_request(GPIO_PORTC + 28, "imx-mmc-ro"); + if (ret) { + free_irq(IRQ_GPIOC(29), data); + return ret; + } + + gpio_direction_input(GPIO_PORTC + 28); + + return 0; +} + +static void pcm970_sdhc2_exit(struct device *dev, void *data) +{ + free_irq(IRQ_GPIOC(29), data); + gpio_free(GPIO_PORTC + 28); +} + +static const struct imxmmc_platform_data sdhc_pdata __initconst = { + .get_ro = pcm970_sdhc2_get_ro, + .init = pcm970_sdhc2_init, + .exit = pcm970_sdhc2_exit, +}; + +static struct imx_fb_videomode pcm970_modes[] = { + { + .mode = { + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 188679, /* in ps (5.3MHz) */ + .hsync_len = 7, + .left_margin = 5, + .right_margin = 16, + .vsync_len = 1, + .upper_margin = 7, + .lower_margin = 9, + }, + /* + * - HSYNC active high + * - VSYNC active high + * - clk notenabled while idle + * - clock not inverted + * - data not inverted + * - data enable low active + * - enable sharp mode + */ + .pcr = 0xF00080C0, + .bpp = 16, + }, { + .mode = { + .name = "TX090", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 38255, + .left_margin = 144, + .right_margin = 0, + .upper_margin = 7, + .lower_margin = 40, + .hsync_len = 96, + .vsync_len = 1, + }, + /* + * - HSYNC active low (1 << 22) + * - VSYNC active low (1 << 23) + * - clk notenabled while idle + * - clock not inverted + * - data not inverted + * - data enable low active + * - enable sharp mode + */ + .pcr = 0xF0008080 | (1<<22) | (1<<23) | (1<<19), + .bpp = 32, + }, +}; + +static const struct imx_fb_platform_data pcm038_fb_data __initconst = { + .mode = pcm970_modes, + .num_modes = ARRAY_SIZE(pcm970_modes), + + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, +}; + +static struct resource pcm970_sja1000_resources[] = { + { + .start = MX27_CS4_BASE_ADDR, + .end = MX27_CS4_BASE_ADDR + 0x100 - 1, + .flags = IORESOURCE_MEM, + }, { + .start = IRQ_GPIOE(19), + .end = IRQ_GPIOE(19), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWEDGE, + }, +}; + +static struct sja1000_platform_data pcm970_sja1000_platform_data = { + .osc_freq = 16000000, + .ocr = OCR_TX1_PULLDOWN | OCR_TX0_PUSHPULL, + .cdr = CDR_CBP, +}; + +static struct platform_device pcm970_sja1000 = { + .name = "sja1000_platform", + .dev = { + .platform_data = &pcm970_sja1000_platform_data, + }, + .resource = pcm970_sja1000_resources, + .num_resources = ARRAY_SIZE(pcm970_sja1000_resources), +}; + +/* + * system init for baseboard usage. Will be called by pcm038 init. + * + * Add platform devices present on this baseboard and init + * them from CPU side as far as required to use them later on + */ +void __init pcm970_baseboard_init(void) +{ + mxc_gpio_setup_multiple_pins(pcm970_pins, ARRAY_SIZE(pcm970_pins), + "PCM970"); + + imx27_add_imx_fb(&pcm038_fb_data); + mxc_gpio_mode(GPIO_PORTC | 28 | GPIO_GPIO | GPIO_IN); + imx27_add_mxc_mmc(1, &sdhc_pdata); + platform_device_register(&pcm970_sja1000); +} diff --git a/arch/arm/mach-imx/pm-imx27.c b/arch/arm/mach-imx/pm-imx27.c new file mode 100644 index 00000000..acf17691 --- /dev/null +++ b/arch/arm/mach-imx/pm-imx27.c @@ -0,0 +1,49 @@ +/* + * i.MX27 Power Management Routines + * + * Based on Freescale's BSP + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License. + */ + +#include <linux/kernel.h> +#include <linux/suspend.h> +#include <linux/io.h> +#include <mach/system.h> +#include <mach/mx27.h> + +static int mx27_suspend_enter(suspend_state_t state) +{ + u32 cscr; + switch (state) { + case PM_SUSPEND_MEM: + /* Clear MPEN and SPEN to disable MPLL/SPLL */ + cscr = __raw_readl(MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR)); + cscr &= 0xFFFFFFFC; + __raw_writel(cscr, MX27_IO_ADDRESS(MX27_CCM_BASE_ADDR)); + /* Executes WFI */ + arch_idle(); + break; + + default: + return -EINVAL; + } + return 0; +} + +static const struct platform_suspend_ops mx27_suspend_ops = { + .enter = mx27_suspend_enter, + .valid = suspend_valid_only_mem, +}; + +static int __init mx27_pm_init(void) +{ + if (!cpu_is_mx27()) + return 0; + + suspend_set_ops(&mx27_suspend_ops); + return 0; +} + +device_initcall(mx27_pm_init); |