diff options
Diffstat (limited to 'arch/arm/mach-omap2')
261 files changed, 99077 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig new file mode 100644 index 00000000000..e20c8ab80b0 --- /dev/null +++ b/arch/arm/mach-omap2/Kconfig @@ -0,0 +1,389 @@ +if ARCH_OMAP2PLUS + +menu "TI OMAP2/3/4 Specific Features" + +config ARCH_OMAP2PLUS_TYPICAL + bool "Typical OMAP configuration" + default y + select AEABI + select REGULATOR + select PM_RUNTIME + select VFP + select NEON if ARCH_OMAP3 || ARCH_OMAP4 + select SERIAL_OMAP + select SERIAL_OMAP_CONSOLE + select I2C + select I2C_OMAP + select MENELAUS if ARCH_OMAP2 + select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4 + select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4 + help + Compile a kernel suitable for booting most boards + +config ARCH_OMAP2 + bool "TI OMAP2" + depends on ARCH_OMAP2PLUS + default y + select CPU_V6 + select MULTI_IRQ_HANDLER + +config ARCH_OMAP3 + bool "TI OMAP3" + depends on ARCH_OMAP2PLUS + default y + select CPU_V7 + select USB_ARCH_HAS_EHCI + select ARCH_HAS_OPP + select PM_OPP if PM + select ARM_CPU_SUSPEND if PM + select MULTI_IRQ_HANDLER + +config ARCH_OMAP4 + bool "TI OMAP4" + default y + depends on ARCH_OMAP2PLUS + select CACHE_L2X0 + select CPU_V7 + select ARM_GIC + select HAVE_SMP + select LOCAL_TIMERS if SMP + select PL310_ERRATA_588369 + select PL310_ERRATA_727915 + select ARM_ERRATA_720789 + select ARCH_HAS_OPP + select PM_OPP if PM + select USB_ARCH_HAS_EHCI + select ARM_CPU_SUSPEND if PM + +comment "OMAP Core Type" + depends on ARCH_OMAP2 + +config SOC_OMAP2420 + bool "OMAP2420 support" + depends on ARCH_OMAP2 + default y + select OMAP_DM_TIMER + select ARCH_OMAP_OTG + +config SOC_OMAP2430 + bool "OMAP2430 support" + depends on ARCH_OMAP2 + default y + select ARCH_OMAP_OTG + +config SOC_OMAP3430 + bool "OMAP3430 support" + depends on ARCH_OMAP3 + default y + select ARCH_OMAP_OTG + +config SOC_OMAPTI81XX + bool "TI81XX support" + depends on ARCH_OMAP3 + default y + +config SOC_OMAPAM33XX + bool "AM33XX support" + depends on ARCH_OMAP3 + default y + +config OMAP_PACKAGE_ZAF + bool + +config OMAP_PACKAGE_ZAC + bool + +config OMAP_PACKAGE_CBC + bool + +config OMAP_PACKAGE_CBB + bool + +config OMAP_PACKAGE_CUS + bool + +config OMAP_PACKAGE_CBP + bool + +config OMAP_PACKAGE_CBL + bool + +config OMAP_PACKAGE_CBS + bool + +comment "OMAP Board Type" + depends on ARCH_OMAP2PLUS + +config MACH_OMAP_GENERIC + bool "Generic OMAP2+ board" + depends on ARCH_OMAP2PLUS + select USE_OF + default y + help + Support for generic TI OMAP2+ boards using Flattened Device Tree. + More information at Documentation/devicetree + +config MACH_OMAP2_TUSB6010 + bool + depends on ARCH_OMAP2 && SOC_OMAP2420 + default y if MACH_NOKIA_N8X0 + +config MACH_OMAP_H4 + bool "OMAP 2420 H4 board" + depends on SOC_OMAP2420 + default y + select OMAP_PACKAGE_ZAF + select OMAP_DEBUG_DEVICES + +config MACH_OMAP_APOLLON + bool "OMAP 2420 Apollon board" + depends on SOC_OMAP2420 + default y + select OMAP_PACKAGE_ZAC + +config MACH_OMAP_2430SDP + bool "OMAP 2430 SDP board" + depends on SOC_OMAP2430 + default y + select OMAP_PACKAGE_ZAC + +config MACH_OMAP3_BEAGLE + bool "OMAP3 BEAGLE board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_DEVKIT8000 + bool "DEVKIT8000 board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CUS + +config MACH_OMAP_LDP + bool "OMAP3 LDP board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_OMAP3530_LV_SOM + bool "OMAP3 Logic 3530 LV SOM board" + depends on ARCH_OMAP3 + select OMAP_PACKAGE_CBB + default y + help + Support for the LogicPD OMAP3530 SOM Development kit + for full description please see the products webpage at + http://www.logicpd.com/products/development-kits/texas-instruments-zoom%E2%84%A2-omap35x-development-kit + +config MACH_OMAP3_TORPEDO + bool "OMAP3 Logic 35x Torpedo board" + depends on ARCH_OMAP3 + select OMAP_PACKAGE_CBB + default y + help + Support for the LogicPD OMAP35x Torpedo Development kit + for full description please see the products webpage at + http://www.logicpd.com/products/development-kits/zoom-omap35x-torpedo-development-kit + +config MACH_OVERO + bool "Gumstix Overo board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_OMAP3EVM + bool "OMAP 3530 EVM board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_OMAP3517EVM + bool "OMAP3517/ AM3517 EVM board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_CRANEBOARD + bool "AM3517/05 CRANE board" + depends on ARCH_OMAP3 + select OMAP_PACKAGE_CBB + +config MACH_OMAP3_PANDORA + bool "OMAP3 Pandora" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + select REGULATOR_FIXED_VOLTAGE if REGULATOR + +config MACH_OMAP3_TOUCHBOOK + bool "OMAP3 Touch Book" + depends on ARCH_OMAP3 + default y + +config MACH_OMAP_3430SDP + bool "OMAP 3430 SDP board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_NOKIA_N800 + bool + +config MACH_NOKIA_N810 + bool + +config MACH_NOKIA_N810_WIMAX + bool + +config MACH_NOKIA_N8X0 + bool "Nokia N800/N810" + depends on SOC_OMAP2420 + default y + select OMAP_PACKAGE_ZAC + select MACH_NOKIA_N800 + select MACH_NOKIA_N810 + select MACH_NOKIA_N810_WIMAX + +config MACH_NOKIA_RM680 + bool "Nokia RM-680 board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_NOKIA_RX51 + bool "Nokia RX-51 board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_OMAP_ZOOM2 + bool "OMAP3 Zoom2 board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + select SERIAL_8250 + select SERIAL_CORE_CONSOLE + select SERIAL_8250_CONSOLE + select REGULATOR_FIXED_VOLTAGE if REGULATOR + +config MACH_OMAP_ZOOM3 + bool "OMAP3630 Zoom3 board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBP + select SERIAL_8250 + select SERIAL_CORE_CONSOLE + select SERIAL_8250_CONSOLE + select REGULATOR_FIXED_VOLTAGE if REGULATOR + +config MACH_CM_T35 + bool "CompuLab CM-T35/CM-T3730 modules" + depends on ARCH_OMAP3 + default y + select MACH_CM_T3730 + select OMAP_PACKAGE_CUS + +config MACH_CM_T3517 + bool "CompuLab CM-T3517 module" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_CM_T3730 + bool + +config MACH_IGEP0020 + bool "IGEP v2 board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + +config MACH_IGEP0030 + bool "IGEP OMAP3 module" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBB + select MACH_IGEP0020 + +config MACH_SBC3530 + bool "OMAP3 SBC STALKER board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CUS + +config MACH_OMAP_3630SDP + bool "OMAP3630 SDP board" + depends on ARCH_OMAP3 + default y + select OMAP_PACKAGE_CBP + +config MACH_TI8168EVM + bool "TI8168 Evaluation Module" + depends on SOC_OMAPTI81XX + default y + +config MACH_TI8148EVM + bool "TI8148 Evaluation Module" + depends on SOC_OMAPTI81XX + default y + +config MACH_OMAP_4430SDP + bool "OMAP 4430 SDP board" + default y + depends on ARCH_OMAP4 + select OMAP_PACKAGE_CBL + select OMAP_PACKAGE_CBS + select REGULATOR_FIXED_VOLTAGE if REGULATOR + +config MACH_OMAP4_PANDA + bool "OMAP4 Panda Board" + default y + depends on ARCH_OMAP4 + select OMAP_PACKAGE_CBL + select OMAP_PACKAGE_CBS + select REGULATOR_FIXED_VOLTAGE if REGULATOR + +config OMAP3_EMU + bool "OMAP3 debugging peripherals" + depends on ARCH_OMAP3 + select ARM_AMBA + select OC_ETM + help + Say Y here to enable debugging hardware of omap3 + +config OMAP3_SDRC_AC_TIMING + bool "Enable SDRC AC timing register changes" + depends on ARCH_OMAP3 + default n + help + If you know that none of your system initiators will attempt to + access SDRAM during CORE DVFS, select Y here. This should boost + SDRAM performance at lower CORE OPPs. There are relatively few + users who will wish to say yes at this point - almost everyone will + wish to say no. Selecting yes without understanding what is + going on could result in system crashes; + +config OMAP4_ERRATA_I688 + bool "OMAP4 errata: Async Bridge Corruption" + depends on ARCH_OMAP4 + select ARCH_HAS_BARRIERS + help + If a data is stalled inside asynchronous bridge because of back + pressure, it may be accepted multiple times, creating pointer + misalignment that will corrupt next transfers on that data path + until next reset of the system (No recovery procedure once the + issue is hit, the path remains consistently broken). Async bridge + can be found on path between MPU to EMIF and MPU to L3 interconnect. + This situation can happen only when the idle is initiated by a + Master Request Disconnection (which is trigged by software when + executing WFI on CPU). + The work-around for this errata needs all the initiators connected + through async bridge must ensure that data path is properly drained + before issuing WFI. This condition will be met if one Strongly ordered + access is performed to the target right before executing the WFI. + In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained. + IO barrier ensure that there is no synchronisation loss on initiators + operating on both interconnect port simultaneously. +endmenu + +endif diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile new file mode 100644 index 00000000000..bd76394ccaf --- /dev/null +++ b/arch/arm/mach-omap2/Makefile @@ -0,0 +1,273 @@ +# +# Makefile for the linux kernel. +# + +# Common support +obj-y := id.o io.o control.o mux.o devices.o serial.o gpmc.o timer.o pm.o \ + common.o gpio.o dma.o wd_timer.o display.o + +omap-2-3-common = irq.o sdrc.o +hwmod-common = omap_hwmod.o \ + omap_hwmod_common_data.o +clock-common = clock.o clock_common_data.o \ + clkt_dpll.o clkt_clksel.o +secure-common = omap-smc.o omap-secure.o + +obj-$(CONFIG_ARCH_OMAP2) += $(omap-2-3-common) $(hwmod-common) +obj-$(CONFIG_ARCH_OMAP3) += $(omap-2-3-common) $(hwmod-common) $(secure-common) +obj-$(CONFIG_ARCH_OMAP4) += prm44xx.o $(hwmod-common) $(secure-common) + +obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o + +obj-$(CONFIG_TWL4030_CORE) += omap_twl.o + +# SMP support ONLY available for OMAP4 +obj-$(CONFIG_SMP) += omap-smp.o omap-headsmp.o +obj-$(CONFIG_LOCAL_TIMERS) += timer-mpu.o +obj-$(CONFIG_HOTPLUG_CPU) += omap-hotplug.o +obj-$(CONFIG_ARCH_OMAP4) += omap4-common.o omap-wakeupgen.o \ + sleep44xx.o + +plus_sec := $(call as-instr,.arch_extension sec,+sec) +AFLAGS_omap-headsmp.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_omap-smc.o :=-Wa,-march=armv7-a$(plus_sec) +AFLAGS_sleep44xx.o :=-Wa,-march=armv7-a$(plus_sec) + +# Functions loaded to SRAM +obj-$(CONFIG_SOC_OMAP2420) += sram242x.o +obj-$(CONFIG_SOC_OMAP2430) += sram243x.o +obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o + +AFLAGS_sram242x.o :=-Wa,-march=armv6 +AFLAGS_sram243x.o :=-Wa,-march=armv6 +AFLAGS_sram34xx.o :=-Wa,-march=armv7-a + +# Pin multiplexing +obj-$(CONFIG_SOC_OMAP2420) += mux2420.o +obj-$(CONFIG_SOC_OMAP2430) += mux2430.o +obj-$(CONFIG_ARCH_OMAP3) += mux34xx.o +obj-$(CONFIG_ARCH_OMAP4) += mux44xx.o + +# SMS/SDRC +obj-$(CONFIG_ARCH_OMAP2) += sdrc2xxx.o +# obj-$(CONFIG_ARCH_OMAP3) += sdrc3xxx.o + +# OPP table initialization +ifeq ($(CONFIG_PM_OPP),y) +obj-y += opp.o +obj-$(CONFIG_ARCH_OMAP3) += opp3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o +endif + +# Power Management +ifeq ($(CONFIG_PM),y) +obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o +obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o +obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o \ + cpuidle34xx.o +obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o omap-mpuss-lowpower.o \ + cpuidle44xx.o +obj-$(CONFIG_PM_DEBUG) += pm-debug.o +obj-$(CONFIG_OMAP_SMARTREFLEX) += sr_device.o smartreflex.o +obj-$(CONFIG_OMAP_SMARTREFLEX_CLASS3) += smartreflex-class3.o + +AFLAGS_sleep24xx.o :=-Wa,-march=armv6 +AFLAGS_sleep34xx.o :=-Wa,-march=armv7-a$(plus_sec) + +ifeq ($(CONFIG_PM_VERBOSE),y) +CFLAGS_pm_bus.o += -DDEBUG +endif + +endif + +# PRCM +obj-y += prm_common.o +obj-$(CONFIG_ARCH_OMAP2) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o +obj-$(CONFIG_ARCH_OMAP3) += prcm.o cm2xxx_3xxx.o prm2xxx_3xxx.o \ + vc3xxx_data.o vp3xxx_data.o +# XXX The presence of cm2xxx_3xxx.o on the line below is temporary and +# will be removed once the OMAP4 part of the codebase is converted to +# use OMAP4-specific PRCM functions. +obj-$(CONFIG_ARCH_OMAP4) += prcm.o cm2xxx_3xxx.o cminst44xx.o \ + cm44xx.o prcm_mpu44xx.o \ + prminst44xx.o vc44xx_data.o \ + vp44xx_data.o prm44xx.o + +# OMAP voltage domains +voltagedomain-common := voltage.o vc.o vp.o +obj-$(CONFIG_ARCH_OMAP2) += $(voltagedomain-common) \ + voltagedomains2xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += $(voltagedomain-common) \ + voltagedomains3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(voltagedomain-common) \ + voltagedomains44xx_data.o + +# OMAP powerdomain framework +powerdomain-common += powerdomain.o powerdomain-common.o +obj-$(CONFIG_ARCH_OMAP2) += $(powerdomain-common) \ + powerdomain2xxx_3xxx.o \ + powerdomains2xxx_data.o \ + powerdomains2xxx_3xxx_data.o +obj-$(CONFIG_ARCH_OMAP3) += $(powerdomain-common) \ + powerdomain2xxx_3xxx.o \ + powerdomains3xxx_data.o \ + powerdomains2xxx_3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += $(powerdomain-common) \ + powerdomain44xx.o \ + powerdomains44xx_data.o + +# PRCM clockdomain control +obj-$(CONFIG_ARCH_OMAP2) += clockdomain.o \ + clockdomain2xxx_3xxx.o \ + clockdomains2xxx_3xxx_data.o +obj-$(CONFIG_SOC_OMAP2420) += clockdomains2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += clockdomains2430_data.o +obj-$(CONFIG_ARCH_OMAP3) += clockdomain.o \ + clockdomain2xxx_3xxx.o \ + clockdomains2xxx_3xxx_data.o \ + clockdomains3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += clockdomain.o \ + clockdomain44xx.o \ + clockdomains44xx_data.o + +# Clock framework +obj-$(CONFIG_ARCH_OMAP2) += $(clock-common) clock2xxx.o \ + clkt2xxx_sys.o \ + clkt2xxx_dpllcore.o \ + clkt2xxx_virt_prcm_set.o \ + clkt2xxx_apll.o clkt2xxx_osc.o \ + clkt2xxx_dpll.o clkt_iclk.o +obj-$(CONFIG_SOC_OMAP2420) += clock2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += clock2430.o clock2430_data.o +obj-$(CONFIG_ARCH_OMAP3) += $(clock-common) clock3xxx.o \ + clock34xx.o clkt34xx_dpll3m2.o \ + clock3517.o clock36xx.o \ + dpll3xxx.o clock3xxx_data.o \ + clkt_iclk.o +obj-$(CONFIG_ARCH_OMAP4) += $(clock-common) clock44xx_data.o \ + dpll3xxx.o dpll44xx.o + +# OMAP2 clock rate set data (old "OPP" data) +obj-$(CONFIG_SOC_OMAP2420) += opp2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += opp2430_data.o + +# hwmod data +obj-$(CONFIG_SOC_OMAP2420) += omap_hwmod_2xxx_ipblock_data.o \ + omap_hwmod_2xxx_3xxx_ipblock_data.o \ + omap_hwmod_2xxx_interconnect_data.o \ + omap_hwmod_2xxx_3xxx_interconnect_data.o \ + omap_hwmod_2420_data.o +obj-$(CONFIG_SOC_OMAP2430) += omap_hwmod_2xxx_ipblock_data.o \ + omap_hwmod_2xxx_3xxx_ipblock_data.o \ + omap_hwmod_2xxx_interconnect_data.o \ + omap_hwmod_2xxx_3xxx_interconnect_data.o \ + omap_hwmod_2430_data.o +obj-$(CONFIG_ARCH_OMAP3) += omap_hwmod_2xxx_3xxx_ipblock_data.o \ + omap_hwmod_2xxx_3xxx_interconnect_data.o \ + omap_hwmod_3xxx_data.o +obj-$(CONFIG_ARCH_OMAP4) += omap_hwmod_44xx_data.o + +# EMU peripherals +obj-$(CONFIG_OMAP3_EMU) += emu.o + +# L3 interconnect +obj-$(CONFIG_ARCH_OMAP3) += omap_l3_smx.o +obj-$(CONFIG_ARCH_OMAP4) += omap_l3_noc.o + +obj-$(CONFIG_OMAP_MBOX_FWK) += mailbox_mach.o +mailbox_mach-objs := mailbox.o + +obj-$(CONFIG_OMAP_IOMMU) += iommu2.o + +iommu-$(CONFIG_OMAP_IOMMU) := omap-iommu.o +obj-y += $(iommu-m) $(iommu-y) + +i2c-omap-$(CONFIG_I2C_OMAP) := i2c.o +obj-y += $(i2c-omap-m) $(i2c-omap-y) + +ifneq ($(CONFIG_TIDSPBRIDGE),) +obj-y += dsp.o +endif + +# Specific board support +obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o +obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o +obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o +obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o +obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o +obj-$(CONFIG_MACH_DEVKIT8000) += board-devkit8000.o +obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o +obj-$(CONFIG_MACH_OMAP3530_LV_SOM) += board-omap3logic.o +obj-$(CONFIG_MACH_OMAP3_TORPEDO) += board-omap3logic.o +obj-$(CONFIG_MACH_ENCORE) += board-omap3encore.o +obj-$(CONFIG_MACH_OVERO) += board-overo.o +obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o +obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o +obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o +obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o +obj-$(CONFIG_MACH_NOKIA_RM680) += board-rm680.o \ + sdram-nokia.o +obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o \ + sdram-nokia.o \ + board-rx51-peripherals.o \ + board-rx51-video.o +obj-$(CONFIG_MACH_OMAP_ZOOM2) += board-zoom.o \ + board-zoom-peripherals.o \ + board-zoom-display.o \ + board-zoom-debugboard.o +obj-$(CONFIG_MACH_OMAP_ZOOM3) += board-zoom.o \ + board-zoom-peripherals.o \ + board-zoom-display.o \ + board-zoom-debugboard.o +obj-$(CONFIG_MACH_OMAP_3630SDP) += board-3630sdp.o \ + board-zoom-peripherals.o \ + board-zoom-display.o +obj-$(CONFIG_MACH_CM_T35) += board-cm-t35.o +obj-$(CONFIG_MACH_CM_T3517) += board-cm-t3517.o +obj-$(CONFIG_MACH_IGEP0020) += board-igep0020.o +obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o +obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o +obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o + +obj-$(CONFIG_MACH_PCM049) += board-omap4pcm049.o + +obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o + +obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o + +obj-$(CONFIG_MACH_SBC3530) += board-omap3stalker.o +obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o +obj-$(CONFIG_MACH_TI8148EVM) += board-ti8168evm.o + +# Platform specific device init code + +omap-flash-$(CONFIG_MTD_NAND_OMAP2) := board-flash.o +omap-flash-$(CONFIG_MTD_ONENAND_OMAP2) := board-flash.o +obj-y += $(omap-flash-y) $(omap-flash-m) + +omap-hsmmc-$(CONFIG_MMC_OMAP_HS) := hsmmc.o +obj-y += $(omap-hsmmc-m) $(omap-hsmmc-y) + + +usbfs-$(CONFIG_ARCH_OMAP_OTG) := usb-fs.o +obj-y += $(usbfs-m) $(usbfs-y) +obj-y += usb-musb.o +obj-y += omap_phy_internal.o + +obj-$(CONFIG_MACH_OMAP2_TUSB6010) += usb-tusb6010.o +obj-y += usb-host.o + +onenand-$(CONFIG_MTD_ONENAND_OMAP2) := gpmc-onenand.o +obj-y += $(onenand-m) $(onenand-y) + +nand-$(CONFIG_MTD_NAND_OMAP2) := gpmc-nand.o +obj-y += $(nand-m) $(nand-y) + +smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o +obj-y += $(smc91x-m) $(smc91x-y) + +smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o +obj-y += $(smsc911x-m) $(smsc911x-y) +obj-$(CONFIG_ARCH_OMAP4) += hwspinlock.o + +obj-y += common-board-devices.o twl-common.o diff --git a/arch/arm/mach-omap2/Makefile.boot b/arch/arm/mach-omap2/Makefile.boot new file mode 100644 index 00000000000..b03e562acc6 --- /dev/null +++ b/arch/arm/mach-omap2/Makefile.boot @@ -0,0 +1,3 @@ + zreladdr-y += 0x80008000 +params_phys-y := 0x80000100 +initrd_phys-y := 0x80800000 diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c new file mode 100644 index 00000000000..7370983f809 --- /dev/null +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -0,0 +1,308 @@ +/* + * linux/arch/arm/mach-omap2/board-2430sdp.c + * + * Copyright (C) 2006 Texas Instruments + * + * Modified from mach-omap2/board-generic.c + * + * Initial Code : Based on a patch from Komal Shah and Richard Woodruff + * Updated the Code for 2430 SDP : Syed Mohammed Khasim + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/mmc/host.h> +#include <linux/delay.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> +#include <plat/usb.h> +#include <plat/gpmc-smc91x.h> + +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> + +#include "mux.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define SDP2430_CS0_BASE 0x04000000 +#define SECONDARY_LCD_GPIO 147 + +static struct mtd_partition sdp2430_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "bootloader", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, + /* file system */ + { + .name = "filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct physmap_flash_data sdp2430_flash_data = { + .width = 2, + .parts = sdp2430_partitions, + .nr_parts = ARRAY_SIZE(sdp2430_partitions), +}; + +static struct resource sdp2430_flash_resource = { + .start = SDP2430_CS0_BASE, + .end = SDP2430_CS0_BASE + SZ_64M - 1, + .flags = IORESOURCE_MEM, +}; + +static struct platform_device sdp2430_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &sdp2430_flash_data, + }, + .num_resources = 1, + .resource = &sdp2430_flash_resource, +}; + +static struct platform_device *sdp2430_devices[] __initdata = { + &sdp2430_flash_device, +}; + +/* LCD */ +#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91 +#define SDP2430_LCD_PANEL_ENABLE_GPIO 154 + +static int sdp2430_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + gpio_direction_output(SDP2430_LCD_PANEL_ENABLE_GPIO, 1); + gpio_direction_output(SDP2430_LCD_PANEL_BACKLIGHT_GPIO, 1); + + return 0; +} + +static void sdp2430_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + gpio_direction_output(SDP2430_LCD_PANEL_ENABLE_GPIO, 0); + gpio_direction_output(SDP2430_LCD_PANEL_BACKLIGHT_GPIO, 0); +} + +static struct panel_generic_dpi_data sdp2430_panel_data = { + .name = "nec_nl2432dr22-11b", + .platform_enable = sdp2430_panel_enable_lcd, + .platform_disable = sdp2430_panel_disable_lcd, +}; + +static struct omap_dss_device sdp2430_lcd_device = { + .name = "lcd", + .driver_name = "generic_dpi_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 16, + .data = &sdp2430_panel_data, +}; + +static struct omap_dss_device *sdp2430_dss_devices[] = { + &sdp2430_lcd_device, +}; + +static struct omap_dss_board_info sdp2430_dss_data = { + .num_devices = ARRAY_SIZE(sdp2430_dss_devices), + .devices = sdp2430_dss_devices, + .default_device = &sdp2430_lcd_device, +}; + +static void __init sdp2430_display_init(void) +{ + int r; + + static struct gpio gpios[] __initdata = { + { SDP2430_LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW, + "LCD reset" }, + { SDP2430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW, + "LCD Backlight" }, + }; + + r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (r) { + pr_err("Cannot request LCD GPIOs, error %d\n", r); + return; + } + + omap_display_init(&sdp2430_dss_data); +} + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91x_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 5, + .gpio_irq = 149, + .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 | + IORESOURCE_IRQ_LOWLEVEL, + +}; + +static void __init board_smc91x_init(void) +{ + omap_mux_init_gpio(149, OMAP_PIN_INPUT); + gpmc_smc91x_init(&board_smc91x_data); +} + +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif + +static struct regulator_consumer_supply sdp2430_vmmc1_supplies[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */ +static struct regulator_init_data sdp2430_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp2430_vmmc1_supplies), + .consumer_supplies = &sdp2430_vmmc1_supplies[0], +}; + +static struct twl4030_gpio_platform_data sdp2430_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, +}; + +static struct twl4030_platform_data sdp2430_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .gpio = &sdp2430_gpio_data, + .vmmc1 = &sdp2430_vmmc1, +}; + +static struct i2c_board_info __initdata sdp2430_i2c1_boardinfo[] = { + { + I2C_BOARD_INFO("isp1301_omap", 0x2D), + .flags = I2C_CLIENT_WAKE, + .irq = OMAP_GPIO_IRQ(78), + }, +}; + +static int __init omap2430_i2c_init(void) +{ + omap_register_i2c_bus(1, 100, sdp2430_i2c1_boardinfo, + ARRAY_SIZE(sdp2430_i2c1_boardinfo)); + omap_pmic_init(2, 100, "twl4030", INT_24XX_SYS_NIRQ, + &sdp2430_twldata); + return 0; +} + +static struct omap2_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .ext_clock = 1, + }, + {} /* Terminator */ +}; + +static struct omap_usb_config sdp2430_usb_config __initdata = { + .otg = 1, +#ifdef CONFIG_USB_GADGET_OMAP + .hmc_mode = 0x0, +#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) + .hmc_mode = 0x1, +#endif + .pins[0] = 3, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init omap_2430sdp_init(void) +{ + omap2430_mux_init(board_mux, OMAP_PACKAGE_ZAC); + + omap2430_i2c_init(); + + platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices)); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + omap2_hsmmc_init(mmc); + omap2_usbfs_init(&sdp2430_usb_config); + + omap_mux_init_signal("usb0hs_stp", OMAP_PULL_ENA | OMAP_PULL_UP); + usb_musb_init(NULL); + + board_smc91x_init(); + + /* Turn off secondary LCD backlight */ + gpio_request_one(SECONDARY_LCD_GPIO, GPIOF_OUT_INIT_LOW, + "Secondary LCD backlight"); + + sdp2430_display_init(); +} + +MACHINE_START(OMAP_2430SDP, "OMAP2430 sdp2430 board") + /* Maintainer: Syed Khasim - Texas Instruments Inc */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap243x_map_io, + .init_early = omap2430_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = omap_2430sdp_init, + .timer = &omap2_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c new file mode 100644 index 00000000000..383717ba63b --- /dev/null +++ b/arch/arm/mach-omap2/board-3430sdp.c @@ -0,0 +1,637 @@ +/* + * linux/arch/arm/mach-omap2/board-3430sdp.c + * + * Copyright (C) 2007 Texas Instruments + * + * Modified from mach-omap2/board-generic.c + * + * Initial code: Syed Mohammed Khasim + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/spi/spi.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/mmc/host.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/mcspi.h> +#include <plat/board.h> +#include <plat/usb.h> +#include "common.h" +#include <plat/dma.h> +#include <plat/gpmc.h> +#include <video/omapdss.h> +#include <video/omap-panel-dvi.h> + +#include <plat/gpmc-smc91x.h> + +#include "board-flash.h" +#include "mux.h" +#include "sdram-qimonda-hyb18m512160af-6.h" +#include "hsmmc.h" +#include "pm.h" +#include "control.h" +#include "common-board-devices.h" + +#define CONFIG_DISABLE_HFCLK 1 + +#define SDP3430_TS_GPIO_IRQ_SDPV1 3 +#define SDP3430_TS_GPIO_IRQ_SDPV2 2 + +#define ENABLE_VAUX3_DEDICATED 0x03 +#define ENABLE_VAUX3_DEV_GRP 0x20 + +#define TWL4030_MSECURE_GPIO 22 + +static uint32_t board_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_A), + KEY(0, 3, KEY_B), + KEY(0, 4, KEY_C), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_E), + KEY(1, 3, KEY_F), + KEY(1, 4, KEY_G), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_I), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_K), + KEY(2, 4, KEY_3), + KEY(3, 0, KEY_M), + KEY(3, 1, KEY_N), + KEY(3, 2, KEY_O), + KEY(3, 3, KEY_P), + KEY(3, 4, KEY_Q), + KEY(4, 0, KEY_R), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_T), + KEY(4, 3, KEY_U), + KEY(4, 4, KEY_D), + KEY(5, 0, KEY_V), + KEY(5, 1, KEY_W), + KEY(5, 2, KEY_L), + KEY(5, 3, KEY_S), + KEY(5, 4, KEY_H), + 0 +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data sdp3430_kp_data = { + .keymap_data = &board_map_data, + .rows = 5, + .cols = 6, + .rep = 1, +}; + +#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8 +#define SDP3430_LCD_PANEL_ENABLE_GPIO 5 + +static struct gpio sdp3430_dss_gpios[] __initdata = { + {SDP3430_LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW, "LCD reset" }, + {SDP3430_LCD_PANEL_BACKLIGHT_GPIO, GPIOF_OUT_INIT_LOW, "LCD Backlight"}, +}; + +static int lcd_enabled; +static int dvi_enabled; + +static void __init sdp3430_display_init(void) +{ + int r; + + r = gpio_request_array(sdp3430_dss_gpios, + ARRAY_SIZE(sdp3430_dss_gpios)); + if (r) + printk(KERN_ERR "failed to get LCD control GPIOs\n"); + +} + +static int sdp3430_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + + gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 1); + gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 1); + + lcd_enabled = 1; + + return 0; +} + +static void sdp3430_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + lcd_enabled = 0; + + gpio_direction_output(SDP3430_LCD_PANEL_ENABLE_GPIO, 0); + gpio_direction_output(SDP3430_LCD_PANEL_BACKLIGHT_GPIO, 0); +} + +static int sdp3430_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + + dvi_enabled = 1; + + return 0; +} + +static void sdp3430_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + dvi_enabled = 0; +} + +static int sdp3430_panel_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void sdp3430_panel_disable_tv(struct omap_dss_device *dssdev) +{ +} + + +static struct omap_dss_device sdp3430_lcd_device = { + .name = "lcd", + .driver_name = "sharp_ls_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 16, + .platform_enable = sdp3430_panel_enable_lcd, + .platform_disable = sdp3430_panel_disable_lcd, +}; + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = sdp3430_panel_enable_dvi, + .platform_disable = sdp3430_panel_disable_dvi, +}; + +static struct omap_dss_device sdp3430_dvi_device = { + .name = "dvi", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device sdp3430_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = sdp3430_panel_enable_tv, + .platform_disable = sdp3430_panel_disable_tv, +}; + + +static struct omap_dss_device *sdp3430_dss_devices[] = { + &sdp3430_lcd_device, + &sdp3430_dvi_device, + &sdp3430_tv_device, +}; + +static struct omap_dss_board_info sdp3430_dss_data = { + .num_devices = ARRAY_SIZE(sdp3430_dss_devices), + .devices = sdp3430_dss_devices, + .default_device = &sdp3430_lcd_device, +}; + +static struct omap_board_config_kernel sdp3430_config[] __initdata = { +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + /* 8 bits (default) requires S6.3 == ON, + * so the SIM card isn't used; else 4 bits. + */ + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_wp = 4, + }, + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_wp = 7, + }, + {} /* Terminator */ +}; + +static int sdp3430_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + /* gpio + 0 is "mmc0_cd" (input/IRQ), + * gpio + 1 is "mmc1_cd" (input/IRQ) + */ + mmc[0].gpio_cd = gpio + 0; + mmc[1].gpio_cd = gpio + 1; + omap2_hsmmc_init(mmc); + + /* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */ + gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl"); + + /* gpio + 15 is "sub_lcd_nRST" (output) */ + gpio_request_one(gpio + 15, GPIOF_OUT_INIT_LOW, "sub_lcd_nRST"); + + return 0; +} + +static struct twl4030_gpio_platform_data sdp3430_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .pulldowns = BIT(2) | BIT(6) | BIT(8) | BIT(13) + | BIT(16) | BIT(17), + .setup = sdp3430_twl_gpio_setup, +}; + +/* regulator consumer mappings */ + +/* ads7846 on SPI */ +static struct regulator_consumer_supply sdp3430_vaux3_supplies[] = { + REGULATOR_SUPPLY("vcc", "spi1.0"), +}; + +static struct regulator_consumer_supply sdp3430_vmmc1_supplies[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply sdp3430_vsim_supplies[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply sdp3430_vmmc2_supplies[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +/* + * Apply all the fixed voltages since most versions of U-Boot + * don't bother with that initialization. + */ + +/* VAUX1 for mainboard (irda and sub-lcd) */ +static struct regulator_init_data sdp3430_vaux1 = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +/* VAUX2 for camera module */ +static struct regulator_init_data sdp3430_vaux2 = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +/* VAUX3 for LCD board */ +static struct regulator_init_data sdp3430_vaux3 = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp3430_vaux3_supplies), + .consumer_supplies = sdp3430_vaux3_supplies, +}; + +/* VAUX4 for OMAP VDD_CSI2 (camera) */ +static struct regulator_init_data sdp3430_vaux4 = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */ +static struct regulator_init_data sdp3430_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp3430_vmmc1_supplies), + .consumer_supplies = sdp3430_vmmc1_supplies, +}; + +/* VMMC2 for MMC2 card */ +static struct regulator_init_data sdp3430_vmmc2 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 1850000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp3430_vmmc2_supplies), + .consumer_supplies = sdp3430_vmmc2_supplies, +}; + +/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */ +static struct regulator_init_data sdp3430_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp3430_vsim_supplies), + .consumer_supplies = sdp3430_vsim_supplies, +}; + +static struct twl4030_platform_data sdp3430_twldata = { + /* platform_data for children goes here */ + .gpio = &sdp3430_gpio_data, + .keypad = &sdp3430_kp_data, + + .vaux1 = &sdp3430_vaux1, + .vaux2 = &sdp3430_vaux2, + .vaux3 = &sdp3430_vaux3, + .vaux4 = &sdp3430_vaux4, + .vmmc1 = &sdp3430_vmmc1, + .vmmc2 = &sdp3430_vmmc2, + .vsim = &sdp3430_vsim, +}; + +static int __init omap3430_i2c_init(void) +{ + /* i2c1 for PMIC only */ + omap3_pmic_get_config(&sdp3430_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_BCI | + TWL_COMMON_PDATA_MADC | TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + sdp3430_twldata.vdac->constraints.apply_uV = true; + sdp3430_twldata.vpll2->constraints.apply_uV = true; + sdp3430_twldata.vpll2->constraints.name = "VDVI"; + + omap3_pmic_init("twl4030", &sdp3430_twldata); + + /* i2c2 on camera connector (for sensor control) and optional isp1301 */ + omap_register_i2c_bus(2, 400, NULL, 0); + /* i2c3 on display connector (for DVI, tfp410) */ + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 3, + .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 | + IORESOURCE_IRQ_LOWLEVEL, +}; + +static void __init board_smc91x_init(void) +{ + if (omap_rev() > OMAP3430_REV_ES1_0) + board_smc91x_data.gpio_irq = 6; + else + board_smc91x_data.gpio_irq = 29; + + gpmc_smc91x_init(&board_smc91x_data); +} + +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif + +static void enable_board_wakeup_source(void) +{ + /* T2 interrupt line (keypad) */ + omap_mux_init_signal("sys_nirq", + OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); +} + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = 57, + .reset_gpio_port[1] = 61, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#else +#define board_mux NULL +#endif + +/* + * SDP3430 V2 Board CS organization + * Different from SDP3430 V1. Now 4 switches used to specify CS + * + * See also the Switch S8 settings in the comments. + */ +static char chip_sel_3430[][GPMC_CS_NUM] = { + {PDC_NOR, PDC_NAND, PDC_ONENAND, DBG_MPDB, 0, 0, 0, 0}, /* S8:1111 */ + {PDC_ONENAND, PDC_NAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1110 */ + {PDC_NAND, PDC_ONENAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1101 */ +}; + +static struct mtd_partition sdp_nor_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "Bootloader-NOR", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "Params-NOR", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "Kernel-NOR", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, + /* file system */ + { + .name = "Filesystem-NOR", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct mtd_partition sdp_onenand_partitions[] = { + { + .name = "X-Loader-OneNAND", + .offset = 0, + .size = 4 * (64 * 2048), + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "U-Boot-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 2 * (64 * 2048), + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "U-Boot Environment-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 1 * (64 * 2048), + }, + { + .name = "Kernel-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 16 * (64 * 2048), + }, + { + .name = "File System-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct mtd_partition sdp_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader-NAND", + .offset = 0, + .size = 4 * (64 * 2048), + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 10 * (64 * 2048), + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "Boot Env-NAND", + + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */ + .size = 6 * (64 * 2048), + }, + { + .name = "Kernel-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 40 * (64 * 2048), + }, + { + .name = "File System - NAND", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, /* Offset = 0x780000 */ + }, +}; + +static struct flash_partitions sdp_flash_partitions[] = { + { + .parts = sdp_nor_partitions, + .nr_parts = ARRAY_SIZE(sdp_nor_partitions), + }, + { + .parts = sdp_onenand_partitions, + .nr_parts = ARRAY_SIZE(sdp_onenand_partitions), + }, + { + .parts = sdp_nand_partitions, + .nr_parts = ARRAY_SIZE(sdp_nand_partitions), + }, +}; + +static void __init omap_3430sdp_init(void) +{ + int gpio_pendown; + + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap_board_config = sdp3430_config; + omap_board_config_size = ARRAY_SIZE(sdp3430_config); + omap3430_i2c_init(); + omap_display_init(&sdp3430_dss_data); + if (omap_rev() > OMAP3430_REV_ES1_0) + gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV2; + else + gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV1; + omap_ads7846_init(1, gpio_pendown, 310, NULL); + omap_serial_init(); + omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL); + usb_musb_init(NULL); + board_smc91x_init(); + board_flash_init(sdp_flash_partitions, chip_sel_3430, 0); + sdp3430_display_init(); + enable_board_wakeup_source(); + usbhs_init(&usbhs_bdata); +} + +MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board") + /* Maintainer: Syed Khasim - Texas Instruments Inc */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3430_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap_3430sdp_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c new file mode 100644 index 00000000000..6ef350d1ae4 --- /dev/null +++ b/arch/arm/mach-omap2/board-3630sdp.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc. + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/gpio.h> +#include <linux/mtd/nand.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "common.h" +#include <plat/board.h> +#include <plat/gpmc-smc91x.h> +#include <plat/usb.h> + +#include <mach/board-zoom.h> + +#include "board-flash.h" +#include "mux.h" +#include "sdram-hynix-h8mbx00u0mer-0em.h" + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 3, + .flags = GPMC_MUX_ADD_DATA | IORESOURCE_IRQ_LOWLEVEL, +}; + +static void __init board_smc91x_init(void) +{ + board_smc91x_data.gpio_irq = 158; + gpmc_smc91x_init(&board_smc91x_data); +} + +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif /* defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) */ + +static void enable_board_wakeup_source(void) +{ + /* T2 interrupt line (keypad) */ + omap_mux_init_signal("sys_nirq", + OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); +} + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = 126, + .reset_gpio_port[1] = 61, + .reset_gpio_port[2] = -EINVAL +}; + +static struct omap_board_config_kernel sdp_config[] __initdata = { +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +/* + * SDP3630 CS organization + * See also the Switch S8 settings in the comments. + */ +static char chip_sel_sdp[][GPMC_CS_NUM] = { + {PDC_NOR, PDC_NAND, PDC_ONENAND, DBG_MPDB, 0, 0, 0, 0}, /* S8:1111 */ + {PDC_ONENAND, PDC_NAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1110 */ + {PDC_NAND, PDC_ONENAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1101 */ +}; + +static struct mtd_partition sdp_nor_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "Bootloader-NOR", + .offset = 0, + .size = SZ_256K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "Params-NOR", + .offset = MTDPART_OFS_APPEND, + .size = SZ_256K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "Kernel-NOR", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, + /* file system */ + { + .name = "Filesystem-NOR", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct mtd_partition sdp_onenand_partitions[] = { + { + .name = "X-Loader-OneNAND", + .offset = 0, + .size = 4 * (64 * 2048), + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "U-Boot-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 2 * (64 * 2048), + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "U-Boot Environment-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 1 * (64 * 2048), + }, + { + .name = "Kernel-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = 16 * (64 * 2048), + }, + { + .name = "File System-OneNAND", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct mtd_partition sdp_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader-NAND", + .offset = 0, + .size = 4 * (64 * 2048), + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 10 * (64 * 2048), + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "Boot Env-NAND", + + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */ + .size = 6 * (64 * 2048), + }, + { + .name = "Kernel-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 40 * (64 * 2048), + }, + { + .name = "File System - NAND", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, /* Offset = 0x780000 */ + }, +}; + +static struct flash_partitions sdp_flash_partitions[] = { + { + .parts = sdp_nor_partitions, + .nr_parts = ARRAY_SIZE(sdp_nor_partitions), + }, + { + .parts = sdp_onenand_partitions, + .nr_parts = ARRAY_SIZE(sdp_onenand_partitions), + }, + { + .parts = sdp_nand_partitions, + .nr_parts = ARRAY_SIZE(sdp_nand_partitions), + }, +}; + +static void __init omap_sdp_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBP); + omap_board_config = sdp_config; + omap_board_config_size = ARRAY_SIZE(sdp_config); + zoom_peripherals_init(); + omap_sdrc_init(h8mbx00u0mer0em_sdrc_params, + h8mbx00u0mer0em_sdrc_params); + zoom_display_init(); + board_smc91x_init(); + board_flash_init(sdp_flash_partitions, chip_sel_sdp, NAND_BUSWIDTH_16); + enable_board_wakeup_source(); + usbhs_init(&usbhs_bdata); +} + +MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3630_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap_sdp_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c new file mode 100644 index 00000000000..4e9071589bf --- /dev/null +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -0,0 +1,940 @@ +/* + * Board support file for OMAP4430 SDP. + * + * Copyright (C) 2009 Texas Instruments + * + * Author: Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * Based on mach-omap2/board-3430sdp.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/usb/otg.h> +#include <linux/spi/spi.h> +#include <linux/i2c/twl.h> +#include <linux/gpio_keys.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/leds.h> +#include <linux/leds_pwm.h> + +#include <mach/hardware.h> +#include <asm/hardware/gic.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/usb.h> +#include <plat/mmc.h> +#include <plat/omap4-keypad.h> +#include <video/omapdss.h> +#include <video/omap-panel-nokia-dsi.h> +#include <video/omap-panel-picodlp.h> +#include <linux/wl12xx.h> + +#include "mux.h" +#include "hsmmc.h" +#include "control.h" +#include "common-board-devices.h" + +#define ETH_KS8851_IRQ 34 +#define ETH_KS8851_POWER_ON 48 +#define ETH_KS8851_QUART 138 +#define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 +#define OMAP4_SFH7741_ENABLE_GPIO 188 +#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ +#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define HDMI_GPIO_HPD 63 /* Hotplug detect */ +#define DISPLAY_SEL_GPIO 59 /* LCD2/PicoDLP switch */ +#define DLP_POWER_ON_GPIO 40 + +#define GPIO_WIFI_PMENA 54 +#define GPIO_WIFI_IRQ 53 + +static const int sdp4430_keymap[] = { + KEY(0, 0, KEY_E), + KEY(0, 1, KEY_R), + KEY(0, 2, KEY_T), + KEY(0, 3, KEY_HOME), + KEY(0, 4, KEY_F5), + KEY(0, 5, KEY_UNKNOWN), + KEY(0, 6, KEY_I), + KEY(0, 7, KEY_LEFTSHIFT), + + KEY(1, 0, KEY_D), + KEY(1, 1, KEY_F), + KEY(1, 2, KEY_G), + KEY(1, 3, KEY_SEND), + KEY(1, 4, KEY_F6), + KEY(1, 5, KEY_UNKNOWN), + KEY(1, 6, KEY_K), + KEY(1, 7, KEY_ENTER), + + KEY(2, 0, KEY_X), + KEY(2, 1, KEY_C), + KEY(2, 2, KEY_V), + KEY(2, 3, KEY_END), + KEY(2, 4, KEY_F7), + KEY(2, 5, KEY_UNKNOWN), + KEY(2, 6, KEY_DOT), + KEY(2, 7, KEY_CAPSLOCK), + + KEY(3, 0, KEY_Z), + KEY(3, 1, KEY_KPPLUS), + KEY(3, 2, KEY_B), + KEY(3, 3, KEY_F1), + KEY(3, 4, KEY_F8), + KEY(3, 5, KEY_UNKNOWN), + KEY(3, 6, KEY_O), + KEY(3, 7, KEY_SPACE), + + KEY(4, 0, KEY_W), + KEY(4, 1, KEY_Y), + KEY(4, 2, KEY_U), + KEY(4, 3, KEY_F2), + KEY(4, 4, KEY_VOLUMEUP), + KEY(4, 5, KEY_UNKNOWN), + KEY(4, 6, KEY_L), + KEY(4, 7, KEY_LEFT), + + KEY(5, 0, KEY_S), + KEY(5, 1, KEY_H), + KEY(5, 2, KEY_J), + KEY(5, 3, KEY_F3), + KEY(5, 4, KEY_F9), + KEY(5, 5, KEY_VOLUMEDOWN), + KEY(5, 6, KEY_M), + KEY(5, 7, KEY_RIGHT), + + KEY(6, 0, KEY_Q), + KEY(6, 1, KEY_A), + KEY(6, 2, KEY_N), + KEY(6, 3, KEY_BACK), + KEY(6, 4, KEY_BACKSPACE), + KEY(6, 5, KEY_UNKNOWN), + KEY(6, 6, KEY_P), + KEY(6, 7, KEY_UP), + + KEY(7, 0, KEY_PROG1), + KEY(7, 1, KEY_PROG2), + KEY(7, 2, KEY_PROG3), + KEY(7, 3, KEY_PROG4), + KEY(7, 4, KEY_F4), + KEY(7, 5, KEY_UNKNOWN), + KEY(7, 6, KEY_OK), + KEY(7, 7, KEY_DOWN), +}; +static struct omap_device_pad keypad_pads[] = { + { .name = "kpd_col1.kpd_col1", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "kpd_col1.kpd_col1", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "kpd_col2.kpd_col2", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "kpd_col3.kpd_col3", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "kpd_col4.kpd_col4", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "kpd_col5.kpd_col5", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "gpmc_a23.kpd_col7", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "gpmc_a22.kpd_col6", + .enable = OMAP_WAKEUP_EN | OMAP_MUX_MODE1, + }, + { .name = "kpd_row0.kpd_row0", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "kpd_row1.kpd_row1", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "kpd_row2.kpd_row2", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "kpd_row3.kpd_row3", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "kpd_row4.kpd_row4", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "kpd_row5.kpd_row5", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "gpmc_a18.kpd_row6", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, + { .name = "gpmc_a19.kpd_row7", + .enable = OMAP_PULL_ENA | OMAP_PULL_UP | OMAP_WAKEUP_EN | + OMAP_MUX_MODE1 | OMAP_INPUT_EN, + }, +}; + +static struct matrix_keymap_data sdp4430_keymap_data = { + .keymap = sdp4430_keymap, + .keymap_size = ARRAY_SIZE(sdp4430_keymap), +}; + +static struct omap4_keypad_platform_data sdp4430_keypad_data = { + .keymap_data = &sdp4430_keymap_data, + .rows = 8, + .cols = 8, +}; + +static struct omap_board_data keypad_data = { + .id = 1, + .pads = keypad_pads, + .pads_cnt = ARRAY_SIZE(keypad_pads), +}; + +static struct gpio_led sdp4430_gpio_leds[] = { + { + .name = "omap4:green:debug0", + .gpio = 61, + }, + { + .name = "omap4:green:debug1", + .gpio = 30, + }, + { + .name = "omap4:green:debug2", + .gpio = 7, + }, + { + .name = "omap4:green:debug3", + .gpio = 8, + }, + { + .name = "omap4:green:debug4", + .gpio = 50, + }, + { + .name = "omap4:blue:user", + .gpio = 169, + }, + { + .name = "omap4:red:user", + .gpio = 170, + }, + { + .name = "omap4:green:user", + .gpio = 139, + }, + +}; + +static struct gpio_keys_button sdp4430_gpio_keys[] = { + { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = OMAP4_SFH7741_SENSOR_OUTPUT_GPIO, + .active_low = 0, + } +}; + +static struct gpio_led_platform_data sdp4430_led_data = { + .leds = sdp4430_gpio_leds, + .num_leds = ARRAY_SIZE(sdp4430_gpio_leds), +}; + +static struct led_pwm sdp4430_pwm_leds[] = { + { + .name = "omap4:green:chrg", + .pwm_id = 1, + .max_brightness = 255, + .pwm_period_ns = 7812500, + }, +}; + +static struct led_pwm_platform_data sdp4430_pwm_data = { + .num_leds = ARRAY_SIZE(sdp4430_pwm_leds), + .leds = sdp4430_pwm_leds, +}; + +static struct platform_device sdp4430_leds_pwm = { + .name = "leds_pwm", + .id = -1, + .dev = { + .platform_data = &sdp4430_pwm_data, + }, +}; + +static int omap_prox_activate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 1); + return 0; +} + +static void omap_prox_deactivate(struct device *dev) +{ + gpio_set_value(OMAP4_SFH7741_ENABLE_GPIO , 0); +} + +static struct gpio_keys_platform_data sdp4430_gpio_keys_data = { + .buttons = sdp4430_gpio_keys, + .nbuttons = ARRAY_SIZE(sdp4430_gpio_keys), + .enable = omap_prox_activate, + .disable = omap_prox_deactivate, +}; + +static struct platform_device sdp4430_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &sdp4430_gpio_keys_data, + }, +}; + +static struct platform_device sdp4430_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &sdp4430_led_data, + }, +}; +static struct spi_board_info sdp4430_spi_board_info[] __initdata = { + { + .modalias = "ks8851", + .bus_num = 1, + .chip_select = 0, + .max_speed_hz = 24000000, + .irq = ETH_KS8851_IRQ, + }, +}; + +static struct gpio sdp4430_eth_gpios[] __initdata = { + { ETH_KS8851_POWER_ON, GPIOF_OUT_INIT_HIGH, "eth_power" }, + { ETH_KS8851_QUART, GPIOF_OUT_INIT_HIGH, "quart" }, + { ETH_KS8851_IRQ, GPIOF_IN, "eth_irq" }, +}; + +static int __init omap_ethernet_init(void) +{ + int status; + + /* Request of GPIO lines */ + status = gpio_request_array(sdp4430_eth_gpios, + ARRAY_SIZE(sdp4430_eth_gpios)); + if (status) + pr_err("Cannot request ETH GPIOs\n"); + + return status; +} + +static struct regulator_consumer_supply sdp4430_vbat_supply[] = { + REGULATOR_SUPPLY("vddvibl", "twl6040-vibra"), + REGULATOR_SUPPLY("vddvibr", "twl6040-vibra"), +}; + +static struct regulator_init_data sdp4430_vbat_data = { + .constraints = { + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp4430_vbat_supply), + .consumer_supplies = sdp4430_vbat_supply, +}; + +static struct fixed_voltage_config sdp4430_vbat_pdata = { + .supply_name = "VBAT", + .microvolts = 3750000, + .init_data = &sdp4430_vbat_data, + .gpio = -EINVAL, +}; + +static struct platform_device sdp4430_vbat = { + .name = "reg-fixed-voltage", + .id = -1, + .dev = { + .platform_data = &sdp4430_vbat_pdata, + }, +}; + +static struct platform_device sdp4430_dmic_codec = { + .name = "dmic-codec", + .id = -1, +}; + +static struct platform_device *sdp4430_devices[] __initdata = { + &sdp4430_gpio_keys_device, + &sdp4430_leds_gpio, + &sdp4430_leds_pwm, + &sdp4430_vbat, + &sdp4430_dmic_codec, +}; + +static struct omap_musb_board_data musb_board_data = { + .interface_type = MUSB_INTERFACE_UTMI, + .mode = MUSB_OTG, + .power = 100, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .nonremovable = true, + .ocr_mask = MMC_VDD_29_30, + .no_off_init = true, + }, + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + { + .mmc = 5, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD, + .pm_caps = MMC_PM_KEEP_POWER, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .ocr_mask = MMC_VDD_165_195, + .nonremovable = true, + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply sdp4430_vaux_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +static struct regulator_consumer_supply omap4_sdp4430_vmmc5_supply = { + .supply = "vmmc", + .dev_name = "omap_hsmmc.4", +}; + +static struct regulator_init_data sdp4430_vmmc5 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = 1, + .consumer_supplies = &omap4_sdp4430_vmmc5_supply, +}; + +static struct fixed_voltage_config sdp4430_vwlan = { + .supply_name = "vwl1271", + .microvolts = 1800000, /* 1.8V */ + .gpio = GPIO_WIFI_PMENA, + .startup_delay = 70000, /* 70msec */ + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &sdp4430_vmmc5, +}; + +static struct platform_device omap_vwlan_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &sdp4430_vwlan, + }, +}; + +static int omap4_twl6030_hsmmc_late_init(struct device *dev) +{ + int ret = 0; + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct omap_mmc_platform_data *pdata = dev->platform_data; + + /* Setting MMC1 Card detect Irq */ + if (pdev->id == 0) { + ret = twl6030_mmc_card_detect_config(); + if (ret) + pr_err("Failed configuring MMC1 card detect\n"); + pdata->slots[0].card_detect_irq = TWL6030_IRQ_BASE + + MMCDETECT_INTR_OFFSET; + pdata->slots[0].card_detect = twl6030_mmc_card_detect; + } + return ret; +} + +static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev) +{ + struct omap_mmc_platform_data *pdata; + + /* dev can be null if CONFIG_MMC_OMAP_HS is not set */ + if (!dev) { + pr_err("Failed %s\n", __func__); + return; + } + pdata = dev->platform_data; + pdata->init = omap4_twl6030_hsmmc_late_init; +} + +static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers) +{ + struct omap2_hsmmc_info *c; + + omap2_hsmmc_init(controllers); + for (c = controllers; c->mmc; c++) + omap4_twl6030_hsmmc_set_late_init(c->dev); + + return 0; +} + +static struct regulator_init_data sdp4430_vaux1 = { + .constraints = { + .min_uV = 1000000, + .max_uV = 3000000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(sdp4430_vaux_supply), + .consumer_supplies = sdp4430_vaux_supply, +}; + +static struct regulator_init_data sdp4430_vusim = { + .constraints = { + .min_uV = 1200000, + .max_uV = 2900000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +static struct twl4030_codec_data twl6040_codec = { + /* single-step ramp for headset and handsfree */ + .hs_left_step = 0x0f, + .hs_right_step = 0x0f, + .hf_left_step = 0x1d, + .hf_right_step = 0x1d, +}; + +static struct twl4030_vibra_data twl6040_vibra = { + .vibldrv_res = 8, + .vibrdrv_res = 3, + .viblmotor_res = 10, + .vibrmotor_res = 10, + .vddvibl_uV = 0, /* fixed volt supply - VBAT */ + .vddvibr_uV = 0, /* fixed volt supply - VBAT */ +}; + +static struct twl4030_audio_data twl6040_audio = { + .codec = &twl6040_codec, + .vibra = &twl6040_vibra, + .audpwron_gpio = 127, + .naudint_irq = OMAP44XX_IRQ_SYS_2N, + .irq_base = TWL6040_CODEC_IRQ_BASE, +}; + +static struct twl4030_platform_data sdp4430_twldata = { + .audio = &twl6040_audio, + /* Regulators */ + .vusim = &sdp4430_vusim, + .vaux1 = &sdp4430_vaux1, +}; + +static struct i2c_board_info __initdata sdp4430_i2c_3_boardinfo[] = { + { + I2C_BOARD_INFO("tmp105", 0x48), + }, + { + I2C_BOARD_INFO("bh1780", 0x29), + }, +}; +static struct i2c_board_info __initdata sdp4430_i2c_4_boardinfo[] = { + { + I2C_BOARD_INFO("hmc5843", 0x1e), + }, +}; +static int __init omap4_i2c_init(void) +{ + omap4_pmic_get_config(&sdp4430_twldata, TWL_COMMON_PDATA_USB, + TWL_COMMON_REGULATOR_VDAC | + TWL_COMMON_REGULATOR_VAUX2 | + TWL_COMMON_REGULATOR_VAUX3 | + TWL_COMMON_REGULATOR_VMMC | + TWL_COMMON_REGULATOR_VPP | + TWL_COMMON_REGULATOR_VANA | + TWL_COMMON_REGULATOR_VCXIO | + TWL_COMMON_REGULATOR_VUSB | + TWL_COMMON_REGULATOR_CLK32KG); + omap4_pmic_init("twl6030", &sdp4430_twldata); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, sdp4430_i2c_3_boardinfo, + ARRAY_SIZE(sdp4430_i2c_3_boardinfo)); + omap_register_i2c_bus(4, 400, sdp4430_i2c_4_boardinfo, + ARRAY_SIZE(sdp4430_i2c_4_boardinfo)); + return 0; +} + +static void __init omap_sfh7741prox_init(void) +{ + int error; + + error = gpio_request_one(OMAP4_SFH7741_ENABLE_GPIO, + GPIOF_OUT_INIT_LOW, "sfh7741"); + if (error < 0) + pr_err("%s:failed to request GPIO %d, error %d\n", + __func__, OMAP4_SFH7741_ENABLE_GPIO, error); +} + +static struct gpio sdp4430_hdmi_gpios[] = { + { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, + { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, +}; + +static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) +{ + int status; + + status = gpio_request_array(sdp4430_hdmi_gpios, + ARRAY_SIZE(sdp4430_hdmi_gpios)); + if (status) + pr_err("%s: Cannot request HDMI GPIOs\n", __func__); + + return status; +} + +static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) +{ + gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); +} + +static struct nokia_dsi_panel_data dsi1_panel = { + .name = "taal", + .reset_gpio = 102, + .use_ext_te = false, + .ext_te_gpio = 101, + .esd_interval = 0, +}; + +static struct omap_dss_device sdp4430_lcd_device = { + .name = "lcd", + .driver_name = "taal", + .type = OMAP_DISPLAY_TYPE_DSI, + .data = &dsi1_panel, + .phy.dsi = { + .clk_lane = 1, + .clk_pol = 0, + .data1_lane = 2, + .data1_pol = 0, + .data2_lane = 3, + .data2_pol = 0, + + .module = 0, + }, + + .clocks = { + .dispc = { + .channel = { + /* Logic Clock = 172.8 MHz */ + .lck_div = 1, + /* Pixel Clock = 34.56 MHz */ + .pck_div = 5, + .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC, + }, + .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, + }, + + .dsi = { + .regn = 16, /* Fint = 2.4 MHz */ + .regm = 180, /* DDR Clock = 216 MHz */ + .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ + .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ + + .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ + .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI, + }, + }, + .channel = OMAP_DSS_CHANNEL_LCD, +}; + +static struct nokia_dsi_panel_data dsi2_panel = { + .name = "taal", + .reset_gpio = 104, + .use_ext_te = false, + .ext_te_gpio = 103, + .esd_interval = 0, +}; + +static struct omap_dss_device sdp4430_lcd2_device = { + .name = "lcd2", + .driver_name = "taal", + .type = OMAP_DISPLAY_TYPE_DSI, + .data = &dsi2_panel, + .phy.dsi = { + .clk_lane = 1, + .clk_pol = 0, + .data1_lane = 2, + .data1_pol = 0, + .data2_lane = 3, + .data2_pol = 0, + + .module = 1, + }, + + .clocks = { + .dispc = { + .channel = { + /* Logic Clock = 172.8 MHz */ + .lck_div = 1, + /* Pixel Clock = 34.56 MHz */ + .pck_div = 5, + .lcd_clk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC, + }, + .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, + }, + + .dsi = { + .regn = 16, /* Fint = 2.4 MHz */ + .regm = 180, /* DDR Clock = 216 MHz */ + .regm_dispc = 5, /* PLL1_CLK1 = 172.8 MHz */ + .regm_dsi = 5, /* PLL1_CLK2 = 172.8 MHz */ + + .lp_clk_div = 10, /* LP Clock = 8.64 MHz */ + .dsi_fclk_src = OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI, + }, + }, + .channel = OMAP_DSS_CHANNEL_LCD2, +}; + +static void sdp4430_lcd_init(void) +{ + int r; + + r = gpio_request_one(dsi1_panel.reset_gpio, GPIOF_DIR_OUT, + "lcd1_reset_gpio"); + if (r) + pr_err("%s: Could not get lcd1_reset_gpio\n", __func__); + + r = gpio_request_one(dsi2_panel.reset_gpio, GPIOF_DIR_OUT, + "lcd2_reset_gpio"); + if (r) + pr_err("%s: Could not get lcd2_reset_gpio\n", __func__); +} + +static struct omap_dss_hdmi_data sdp4430_hdmi_data = { + .hpd_gpio = HDMI_GPIO_HPD, +}; + +static struct omap_dss_device sdp4430_hdmi_device = { + .name = "hdmi", + .driver_name = "hdmi_panel", + .type = OMAP_DISPLAY_TYPE_HDMI, + .platform_enable = sdp4430_panel_enable_hdmi, + .platform_disable = sdp4430_panel_disable_hdmi, + .channel = OMAP_DSS_CHANNEL_DIGIT, + .data = &sdp4430_hdmi_data, +}; + +static struct picodlp_panel_data sdp4430_picodlp_pdata = { + .picodlp_adapter_id = 2, + .emu_done_gpio = 44, + .pwrgood_gpio = 45, +}; + +static void sdp4430_picodlp_init(void) +{ + int r; + const struct gpio picodlp_gpios[] = { + {DLP_POWER_ON_GPIO, GPIOF_OUT_INIT_LOW, + "DLP POWER ON"}, + {sdp4430_picodlp_pdata.emu_done_gpio, GPIOF_IN, + "DLP EMU DONE"}, + {sdp4430_picodlp_pdata.pwrgood_gpio, GPIOF_OUT_INIT_LOW, + "DLP PWRGOOD"}, + }; + + r = gpio_request_array(picodlp_gpios, ARRAY_SIZE(picodlp_gpios)); + if (r) + pr_err("Cannot request PicoDLP GPIOs, error %d\n", r); +} + +static int sdp4430_panel_enable_picodlp(struct omap_dss_device *dssdev) +{ + gpio_set_value(DISPLAY_SEL_GPIO, 0); + gpio_set_value(DLP_POWER_ON_GPIO, 1); + + return 0; +} + +static void sdp4430_panel_disable_picodlp(struct omap_dss_device *dssdev) +{ + gpio_set_value(DLP_POWER_ON_GPIO, 0); + gpio_set_value(DISPLAY_SEL_GPIO, 1); +} + +static struct omap_dss_device sdp4430_picodlp_device = { + .name = "picodlp", + .driver_name = "picodlp_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 24, + .channel = OMAP_DSS_CHANNEL_LCD2, + .platform_enable = sdp4430_panel_enable_picodlp, + .platform_disable = sdp4430_panel_disable_picodlp, + .data = &sdp4430_picodlp_pdata, +}; + +static struct omap_dss_device *sdp4430_dss_devices[] = { + &sdp4430_lcd_device, + &sdp4430_lcd2_device, + &sdp4430_hdmi_device, + &sdp4430_picodlp_device, +}; + +static struct omap_dss_board_info sdp4430_dss_data = { + .num_devices = ARRAY_SIZE(sdp4430_dss_devices), + .devices = sdp4430_dss_devices, + .default_device = &sdp4430_lcd_device, +}; + +static void __init omap_4430sdp_display_init(void) +{ + int r; + + /* Enable LCD2 by default (instead of Pico DLP) */ + r = gpio_request_one(DISPLAY_SEL_GPIO, GPIOF_OUT_INIT_HIGH, + "display_sel"); + if (r) + pr_err("%s: Could not get display_sel GPIO\n", __func__); + + sdp4430_lcd_init(); + sdp4430_picodlp_init(); + omap_display_init(&sdp4430_dss_data); + /* + * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and + * later have external pull up on the HDMI I2C lines + */ + if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2) + omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); + else + omap_hdmi_init(0); + + omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + OMAP4_MUX(USBB2_ULPITLL_CLK, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +#else +#define board_mux NULL + #endif + +static void __init omap4_sdp4430_wifi_mux_init(void) +{ + omap_mux_init_gpio(GPIO_WIFI_IRQ, OMAP_PIN_INPUT | + OMAP_PIN_OFF_WAKEUPENABLE); + omap_mux_init_gpio(GPIO_WIFI_PMENA, OMAP_PIN_OUTPUT); + + omap_mux_init_signal("sdmmc5_cmd.sdmmc5_cmd", + OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_clk.sdmmc5_clk", + OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat0.sdmmc5_dat0", + OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat1.sdmmc5_dat1", + OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat2.sdmmc5_dat2", + OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP); + omap_mux_init_signal("sdmmc5_dat3.sdmmc5_dat3", + OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP); + +} + +static struct wl12xx_platform_data omap4_sdp4430_wlan_data __initdata = { + .irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ), + .board_ref_clock = WL12XX_REFCLOCK_26, + .board_tcxo_clock = WL12XX_TCXOCLOCK_26, +}; + +static void __init omap4_sdp4430_wifi_init(void) +{ + int ret; + + omap4_sdp4430_wifi_mux_init(); + ret = wl12xx_set_platform_data(&omap4_sdp4430_wlan_data); + if (ret) + pr_err("Error setting wl12xx data: %d\n", ret); + ret = platform_device_register(&omap_vwlan_device); + if (ret) + pr_err("Error registering wl12xx device: %d\n", ret); +} + +static void __init omap_4430sdp_init(void) +{ + int status; + int package = OMAP_PACKAGE_CBS; + + if (omap_rev() == OMAP4430_REV_ES1_0) + package = OMAP_PACKAGE_CBL; + omap4_mux_init(board_mux, NULL, package); + + omap4_i2c_init(); + omap_sfh7741prox_init(); + platform_add_devices(sdp4430_devices, ARRAY_SIZE(sdp4430_devices)); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + omap4_sdp4430_wifi_init(); + omap4_twl6030_hsmmc_init(mmc); + + usb_musb_init(&musb_board_data); + + status = omap_ethernet_init(); + if (status) { + pr_err("Ethernet initialization failed: %d\n", status); + } else { + sdp4430_spi_board_info[0].irq = gpio_to_irq(ETH_KS8851_IRQ); + spi_register_board_info(sdp4430_spi_board_info, + ARRAY_SIZE(sdp4430_spi_board_info)); + } + + status = omap4_keyboard_init(&sdp4430_keypad_data, &keypad_data); + if (status) + pr_err("Keypad initialization failed: %d\n", status); + + omap_4430sdp_display_init(); +} + +MACHINE_START(OMAP_4430SDP, "OMAP4430 4430SDP board") + /* Maintainer: Santosh Shilimkar - Texas Instruments Inc */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap4_map_io, + .init_early = omap4430_init_early, + .init_irq = gic_init_irq, + .handle_irq = gic_handle_irq, + .init_machine = omap_4430sdp_init, + .timer = &omap4_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c new file mode 100644 index 00000000000..c3851e8de28 --- /dev/null +++ b/arch/arm/mach-omap2/board-am3517crane.c @@ -0,0 +1,105 @@ +/* + * Support for AM3517/05 Craneboard + * http://www.mistralsolutions.com/products/craneboard.php + * + * Copyright (C) 2010 Mistral Solutions Pvt Ltd. <www.mistralsolutions.com> + * Author: R.Srinath <srinath@mistralsolutions.com> + * + * Based on mach-omap2/board-am3517evm.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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/gpio.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/usb.h> + +#include "mux.h" +#include "control.h" + +#define GPIO_USB_POWER 35 +#define GPIO_USB_NRESET 38 + + +/* Board initialization */ +static struct omap_board_config_kernel am3517_crane_config[] __initdata = { +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static struct usbhs_omap_board_data usbhs_bdata __initdata = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = GPIO_USB_NRESET, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +static void __init am3517_crane_init(void) +{ + int ret; + + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + + omap_board_config = am3517_crane_config; + omap_board_config_size = ARRAY_SIZE(am3517_crane_config); + + /* Configure GPIO for EHCI port */ + if (omap_mux_init_gpio(GPIO_USB_NRESET, OMAP_PIN_OUTPUT)) { + pr_err("Can not configure mux for GPIO_USB_NRESET %d\n", + GPIO_USB_NRESET); + return; + } + + if (omap_mux_init_gpio(GPIO_USB_POWER, OMAP_PIN_OUTPUT)) { + pr_err("Can not configure mux for GPIO_USB_POWER %d\n", + GPIO_USB_POWER); + return; + } + + ret = gpio_request_one(GPIO_USB_POWER, GPIOF_OUT_INIT_HIGH, + "usb_ehci_enable"); + if (ret < 0) { + pr_err("Can not request GPIO %d\n", GPIO_USB_POWER); + return; + } + + usbhs_init(&usbhs_bdata); +} + +MACHINE_START(CRANEBOARD, "AM3517/05 CRANEBOARD") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = am35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = am3517_crane_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-am3517evm.c b/arch/arm/mach-omap2/board-am3517evm.c new file mode 100644 index 00000000000..4b1cfe32e6b --- /dev/null +++ b/arch/arm/mach-omap2/board-am3517evm.c @@ -0,0 +1,520 @@ +/* + * linux/arch/arm/mach-omap2/board-am3517evm.c + * + * Copyright (C) 2009 Texas Instruments Incorporated + * Author: Ranjith Lohithakshan <ranjithl@ti.com> + * + * Based on mach-omap2/board-omap3evm.c + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; 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/clk.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/i2c/pca953x.h> +#include <linux/can/platform/ti_hecc.h> +#include <linux/davinci_emac.h> +#include <linux/mmc/host.h> + +#include <mach/hardware.h> +#include <mach/am35xx.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/usb.h> +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-dvi.h> + +#include "mux.h" +#include "control.h" +#include "hsmmc.h" + +#define AM35XX_EVM_MDIO_FREQUENCY (1000000) + +static struct mdio_platform_data am3517_evm_mdio_pdata = { + .bus_freq = AM35XX_EVM_MDIO_FREQUENCY, +}; + +static struct resource am3517_mdio_resources[] = { + { + .start = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET, + .end = AM35XX_IPSS_EMAC_BASE + AM35XX_EMAC_MDIO_OFFSET + + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device am3517_mdio_device = { + .name = "davinci_mdio", + .id = 0, + .num_resources = ARRAY_SIZE(am3517_mdio_resources), + .resource = am3517_mdio_resources, + .dev.platform_data = &am3517_evm_mdio_pdata, +}; + +static struct emac_platform_data am3517_evm_emac_pdata = { + .rmii_en = 1, +}; + +static struct resource am3517_emac_resources[] = { + { + .start = AM35XX_IPSS_EMAC_BASE, + .end = AM35XX_IPSS_EMAC_BASE + 0x2FFFF, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_35XX_EMAC_C0_RXTHRESH_IRQ, + .end = INT_35XX_EMAC_C0_RXTHRESH_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .start = INT_35XX_EMAC_C0_RX_PULSE_IRQ, + .end = INT_35XX_EMAC_C0_RX_PULSE_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .start = INT_35XX_EMAC_C0_TX_PULSE_IRQ, + .end = INT_35XX_EMAC_C0_TX_PULSE_IRQ, + .flags = IORESOURCE_IRQ, + }, + { + .start = INT_35XX_EMAC_C0_MISC_PULSE_IRQ, + .end = INT_35XX_EMAC_C0_MISC_PULSE_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device am3517_emac_device = { + .name = "davinci_emac", + .id = -1, + .num_resources = ARRAY_SIZE(am3517_emac_resources), + .resource = am3517_emac_resources, +}; + +static void am3517_enable_ethernet_int(void) +{ + u32 regval; + + regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); + regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR | + AM35XX_CPGMAC_C0_TX_PULSE_CLR | + AM35XX_CPGMAC_C0_MISC_PULSE_CLR | + AM35XX_CPGMAC_C0_RX_THRESH_CLR); + omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR); + regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); +} + +static void am3517_disable_ethernet_int(void) +{ + u32 regval; + + regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); + regval = (regval | AM35XX_CPGMAC_C0_RX_PULSE_CLR | + AM35XX_CPGMAC_C0_TX_PULSE_CLR); + omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR); + regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR); +} + +static void am3517_evm_ethernet_init(struct emac_platform_data *pdata) +{ + unsigned int regval; + + pdata->ctrl_reg_offset = AM35XX_EMAC_CNTRL_OFFSET; + pdata->ctrl_mod_reg_offset = AM35XX_EMAC_CNTRL_MOD_OFFSET; + pdata->ctrl_ram_offset = AM35XX_EMAC_CNTRL_RAM_OFFSET; + pdata->ctrl_ram_size = AM35XX_EMAC_CNTRL_RAM_SIZE; + pdata->version = EMAC_VERSION_2; + pdata->hw_ram_addr = AM35XX_EMAC_HW_RAM_ADDR; + pdata->interrupt_enable = am3517_enable_ethernet_int; + pdata->interrupt_disable = am3517_disable_ethernet_int; + am3517_emac_device.dev.platform_data = pdata; + platform_device_register(&am3517_emac_device); + platform_device_register(&am3517_mdio_device); + clk_add_alias(NULL, dev_name(&am3517_mdio_device.dev), + NULL, &am3517_emac_device.dev); + + regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); + regval = regval & (~(AM35XX_CPGMACSS_SW_RST)); + omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET); + regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET); + + return ; +} + + + +#define LCD_PANEL_PWR 176 +#define LCD_PANEL_BKLIGHT_PWR 182 +#define LCD_PANEL_PWM 181 + +static struct i2c_board_info __initdata am3517evm_i2c1_boardinfo[] = { + { + I2C_BOARD_INFO("s35390a", 0x30), + }, +}; + +/* + * RTC - S35390A + */ +#define GPIO_RTCS35390A_IRQ 55 + +static void __init am3517_evm_rtc_init(void) +{ + int r; + + omap_mux_init_gpio(GPIO_RTCS35390A_IRQ, OMAP_PIN_INPUT_PULLUP); + + r = gpio_request_one(GPIO_RTCS35390A_IRQ, GPIOF_IN, "rtcs35390a-irq"); + if (r < 0) { + printk(KERN_WARNING "failed to request GPIO#%d\n", + GPIO_RTCS35390A_IRQ); + return; + } + + am3517evm_i2c1_boardinfo[0].irq = gpio_to_irq(GPIO_RTCS35390A_IRQ); +} + +/* + * I2C GPIO Expander - TCA6416 + */ + +/* Mounted on Base-Board */ +static struct pca953x_platform_data am3517evm_gpio_expander_info_0 = { + .gpio_base = OMAP_MAX_GPIO_LINES, +}; +static struct i2c_board_info __initdata am3517evm_i2c2_boardinfo[] = { + { + I2C_BOARD_INFO("tlv320aic23", 0x1A), + }, + { + I2C_BOARD_INFO("tca6416", 0x21), + .platform_data = &am3517evm_gpio_expander_info_0, + }, +}; + +/* Mounted on UI Card */ +static struct pca953x_platform_data am3517evm_ui_gpio_expander_info_1 = { + .gpio_base = OMAP_MAX_GPIO_LINES + 16, +}; +static struct pca953x_platform_data am3517evm_ui_gpio_expander_info_2 = { + .gpio_base = OMAP_MAX_GPIO_LINES + 32, +}; +static struct i2c_board_info __initdata am3517evm_i2c3_boardinfo[] = { + { + I2C_BOARD_INFO("tca6416", 0x20), + .platform_data = &am3517evm_ui_gpio_expander_info_1, + }, + { + I2C_BOARD_INFO("tca6416", 0x21), + .platform_data = &am3517evm_ui_gpio_expander_info_2, + }, +}; + +static int __init am3517_evm_i2c_init(void) +{ + omap_register_i2c_bus(1, 400, NULL, 0); + omap_register_i2c_bus(2, 400, am3517evm_i2c2_boardinfo, + ARRAY_SIZE(am3517evm_i2c2_boardinfo)); + omap_register_i2c_bus(3, 400, am3517evm_i2c3_boardinfo, + ARRAY_SIZE(am3517evm_i2c3_boardinfo)); + + return 0; +} + +static int lcd_enabled; +static int dvi_enabled; + +#if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \ + defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE) +static struct gpio am3517_evm_dss_gpios[] __initdata = { + /* GPIO 182 = LCD Backlight Power */ + { LCD_PANEL_BKLIGHT_PWR, GPIOF_OUT_INIT_HIGH, "lcd_backlight_pwr" }, + /* GPIO 181 = LCD Panel PWM */ + { LCD_PANEL_PWM, GPIOF_OUT_INIT_HIGH, "lcd bl enable" }, + /* GPIO 176 = LCD Panel Power enable pin */ + { LCD_PANEL_PWR, GPIOF_OUT_INIT_HIGH, "dvi enable" }, +}; + +static void __init am3517_evm_display_init(void) +{ + int r; + + omap_mux_init_gpio(LCD_PANEL_PWR, OMAP_PIN_INPUT_PULLUP); + omap_mux_init_gpio(LCD_PANEL_BKLIGHT_PWR, OMAP_PIN_INPUT_PULLDOWN); + omap_mux_init_gpio(LCD_PANEL_PWM, OMAP_PIN_INPUT_PULLDOWN); + + r = gpio_request_array(am3517_evm_dss_gpios, + ARRAY_SIZE(am3517_evm_dss_gpios)); + if (r) { + printk(KERN_ERR "failed to get DSS panel control GPIOs\n"); + return; + } + + printk(KERN_INFO "Display initialized successfully\n"); +} +#else +static void __init am3517_evm_display_init(void) {} +#endif + +static int am3517_evm_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + gpio_set_value(LCD_PANEL_PWR, 1); + lcd_enabled = 1; + + return 0; +} + +static void am3517_evm_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + gpio_set_value(LCD_PANEL_PWR, 0); + lcd_enabled = 0; +} + +static struct panel_generic_dpi_data lcd_panel = { + .name = "sharp_lq", + .platform_enable = am3517_evm_panel_enable_lcd, + .platform_disable = am3517_evm_panel_disable_lcd, +}; + +static struct omap_dss_device am3517_evm_lcd_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "lcd", + .driver_name = "generic_dpi_panel", + .data = &lcd_panel, + .phy.dpi.data_lines = 16, +}; + +static int am3517_evm_panel_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void am3517_evm_panel_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct omap_dss_device am3517_evm_tv_device = { + .type = OMAP_DISPLAY_TYPE_VENC, + .name = "tv", + .driver_name = "venc", + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = am3517_evm_panel_enable_tv, + .platform_disable = am3517_evm_panel_disable_tv, +}; + +static int am3517_evm_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + dvi_enabled = 1; + + return 0; +} + +static void am3517_evm_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + dvi_enabled = 0; +} + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = am3517_evm_panel_enable_dvi, + .platform_disable = am3517_evm_panel_disable_dvi, +}; + +static struct omap_dss_device am3517_evm_dvi_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "dvi", + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device *am3517_evm_dss_devices[] = { + &am3517_evm_lcd_device, + &am3517_evm_tv_device, + &am3517_evm_dvi_device, +}; + +static struct omap_dss_board_info am3517_evm_dss_data = { + .num_devices = ARRAY_SIZE(am3517_evm_dss_devices), + .devices = am3517_evm_dss_devices, + .default_device = &am3517_evm_lcd_device, +}; + +/* + * Board initialization + */ + +static struct omap_musb_board_data musb_board_data = { + .interface_type = MUSB_INTERFACE_ULPI, + .mode = MUSB_OTG, + .power = 500, + .set_phy_power = am35x_musb_phy_power, + .clear_irq = am35x_musb_clear_irq, + .set_mode = am35x_set_mode, + .reset = am35x_musb_reset, +}; + +static __init void am3517_evm_musb_init(void) +{ + u32 devconf2; + + /* + * Set up USB clock/mode in the DEVCONF2 register. + */ + devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2); + + /* USB2.0 PHY reference clock is 13 MHz */ + devconf2 &= ~(CONF2_REFFREQ | CONF2_OTGMODE | CONF2_PHY_GPIOMODE); + devconf2 |= CONF2_REFFREQ_13MHZ | CONF2_SESENDEN | CONF2_VBDTCTEN + | CONF2_DATPOL; + + omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2); + + usb_musb_init(&musb_board_data); +} + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, +#if defined(CONFIG_PANEL_SHARP_LQ043T1DG01) || \ + defined(CONFIG_PANEL_SHARP_LQ043T1DG01_MODULE) + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, +#else + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, +#endif + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = 57, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* USB OTG DRVVBUS offset = 0x212 */ + OMAP3_MUX(SAD2D_MCAD23, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + + +static struct resource am3517_hecc_resources[] = { + { + .start = AM35XX_IPSS_HECC_BASE, + .end = AM35XX_IPSS_HECC_BASE + 0x3FFF, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_35XX_HECC0_IRQ, + .end = INT_35XX_HECC0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device am3517_hecc_device = { + .name = "ti_hecc", + .id = -1, + .num_resources = ARRAY_SIZE(am3517_hecc_resources), + .resource = am3517_hecc_resources, +}; + +static struct ti_hecc_platform_data am3517_evm_hecc_pdata = { + .scc_hecc_offset = AM35XX_HECC_SCC_HECC_OFFSET, + .scc_ram_offset = AM35XX_HECC_SCC_RAM_OFFSET, + .hecc_ram_offset = AM35XX_HECC_RAM_OFFSET, + .mbx_offset = AM35XX_HECC_MBOX_OFFSET, + .int_line = AM35XX_HECC_INT_LINE, + .version = AM35XX_HECC_VERSION, +}; + +static void am3517_evm_hecc_init(struct ti_hecc_platform_data *pdata) +{ + am3517_hecc_device.dev.platform_data = pdata; + platform_device_register(&am3517_hecc_device); +} + +static struct omap_board_config_kernel am3517_evm_config[] __initdata = { +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = 127, + .gpio_wp = 126, + }, + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = 128, + .gpio_wp = 129, + }, + {} /* Terminator */ +}; + + +static void __init am3517_evm_init(void) +{ + omap_board_config = am3517_evm_config; + omap_board_config_size = ARRAY_SIZE(am3517_evm_config); + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + + am3517_evm_i2c_init(); + omap_display_init(&am3517_evm_dss_data); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + + /* Configure GPIO for EHCI port */ + omap_mux_init_gpio(57, OMAP_PIN_OUTPUT); + usbhs_init(&usbhs_bdata); + am3517_evm_hecc_init(&am3517_evm_hecc_pdata); + /* DSS */ + am3517_evm_display_init(); + + /* RTC - S35390A */ + am3517_evm_rtc_init(); + + i2c_register_board_info(1, am3517evm_i2c1_boardinfo, + ARRAY_SIZE(am3517evm_i2c1_boardinfo)); + /*Ethernet*/ + am3517_evm_ethernet_init(&am3517_evm_emac_pdata); + + /* MUSB */ + am3517_evm_musb_init(); + + /* MMC init function */ + omap2_hsmmc_init(mmc); +} + +MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = am35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = am3517_evm_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c new file mode 100644 index 00000000000..ac773829941 --- /dev/null +++ b/arch/arm/mach-omap2/board-apollon.c @@ -0,0 +1,361 @@ +/* + * linux/arch/arm/mach-omap2/board-apollon.c + * + * Copyright (C) 2005,2006 Samsung Electronics + * Author: Kyungmin Park <kyungmin.park@samsung.com> + * + * Modified from mach-omap/omap2/board-h4.c + * + * Code for apollon OMAP2 board. Should work on many OMAP2 systems where + * the bootloader passes the board-specific data to the kernel. + * Do not put any board specific code to this file; create a new machine + * type if you need custom low-level initializations. + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/onenand.h> +#include <linux/delay.h> +#include <linux/leds.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/smc91x.h> +#include <linux/gpio.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> + +#include <plat/led.h> +#include <plat/usb.h> +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> + +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> + +#include "mux.h" +#include "control.h" + +/* LED & Switch macros */ +#define LED0_GPIO13 13 +#define LED1_GPIO14 14 +#define LED2_GPIO15 15 +#define SW_ENTER_GPIO16 16 +#define SW_UP_GPIO17 17 +#define SW_DOWN_GPIO58 58 + +#define APOLLON_FLASH_CS 0 +#define APOLLON_ETH_CS 1 +#define APOLLON_ETHR_GPIO_IRQ 74 + +static struct mtd_partition apollon_partitions[] = { + { + .name = "X-Loader + U-Boot", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, + }, + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = SZ_16M, + }, + { + .name = "filesystem00", + .offset = MTDPART_OFS_APPEND, + .size = SZ_32M, + }, + { + .name = "filesystem01", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct onenand_platform_data apollon_flash_data = { + .parts = apollon_partitions, + .nr_parts = ARRAY_SIZE(apollon_partitions), +}; + +static struct resource apollon_flash_resource[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device apollon_onenand_device = { + .name = "onenand-flash", + .id = -1, + .dev = { + .platform_data = &apollon_flash_data, + }, + .num_resources = ARRAY_SIZE(apollon_flash_resource), + .resource = apollon_flash_resource, +}; + +static void __init apollon_flash_init(void) +{ + unsigned long base; + + if (gpmc_cs_request(APOLLON_FLASH_CS, SZ_128K, &base) < 0) { + printk(KERN_ERR "Cannot request OneNAND GPMC CS\n"); + return; + } + apollon_flash_resource[0].start = base; + apollon_flash_resource[0].end = base + SZ_128K - 1; +} + +static struct smc91x_platdata appolon_smc91x_info = { + .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT, + .leda = RPC_LED_100_10, + .ledb = RPC_LED_TX_RX, +}; + +static struct resource apollon_smc91x_resources[] = { + [0] = { + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ), + .end = OMAP_GPIO_IRQ(APOLLON_ETHR_GPIO_IRQ), + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE, + }, +}; + +static struct platform_device apollon_smc91x_device = { + .name = "smc91x", + .id = -1, + .dev = { + .platform_data = &appolon_smc91x_info, + }, + .num_resources = ARRAY_SIZE(apollon_smc91x_resources), + .resource = apollon_smc91x_resources, +}; + +static struct omap_led_config apollon_led_config[] = { + { + .cdev = { + .name = "apollon:led0", + }, + .gpio = LED0_GPIO13, + }, + { + .cdev = { + .name = "apollon:led1", + }, + .gpio = LED1_GPIO14, + }, + { + .cdev = { + .name = "apollon:led2", + }, + .gpio = LED2_GPIO15, + }, +}; + +static struct omap_led_platform_data apollon_led_data = { + .nr_leds = ARRAY_SIZE(apollon_led_config), + .leds = apollon_led_config, +}; + +static struct platform_device apollon_led_device = { + .name = "omap-led", + .id = -1, + .dev = { + .platform_data = &apollon_led_data, + }, +}; + +static struct platform_device *apollon_devices[] __initdata = { + &apollon_onenand_device, + &apollon_smc91x_device, + &apollon_led_device, +}; + +static inline void __init apollon_init_smc91x(void) +{ + unsigned long base; + + unsigned int rate; + struct clk *gpmc_fck; + int eth_cs; + int err; + + gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */ + if (IS_ERR(gpmc_fck)) { + WARN_ON(1); + return; + } + + clk_enable(gpmc_fck); + rate = clk_get_rate(gpmc_fck); + + eth_cs = APOLLON_ETH_CS; + + /* Make sure CS1 timings are correct */ + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200); + + if (rate >= 160000000) { + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4); + } else if (rate >= 130000000) { + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4); + } else {/* rate = 100000000 */ + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2); + } + + if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) { + printk(KERN_ERR "Failed to request GPMC CS for smc91x\n"); + goto out; + } + apollon_smc91x_resources[0].start = base + 0x300; + apollon_smc91x_resources[0].end = base + 0x30f; + udelay(100); + + omap_mux_init_gpio(APOLLON_ETHR_GPIO_IRQ, 0); + err = gpio_request_one(APOLLON_ETHR_GPIO_IRQ, GPIOF_IN, "SMC91x irq"); + if (err) { + printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", + APOLLON_ETHR_GPIO_IRQ); + gpmc_cs_free(APOLLON_ETH_CS); + } +out: + clk_disable(gpmc_fck); + clk_put(gpmc_fck); +} + +static struct omap_usb_config apollon_usb_config __initdata = { + .register_dev = 1, + .hmc_mode = 0x14, /* 0:dev 1:host1 2:disable */ + + .pins[0] = 6, +}; + +static struct panel_generic_dpi_data apollon_panel_data = { + .name = "apollon", +}; + +static struct omap_dss_device apollon_lcd_device = { + .name = "lcd", + .driver_name = "generic_dpi_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 18, + .data = &apollon_panel_data, +}; + +static struct omap_dss_device *apollon_dss_devices[] = { + &apollon_lcd_device, +}; + +static struct omap_dss_board_info apollon_dss_data = { + .num_devices = ARRAY_SIZE(apollon_dss_devices), + .devices = apollon_dss_devices, + .default_device = &apollon_lcd_device, +}; + +static struct gpio apollon_gpio_leds[] __initdata = { + { LED0_GPIO13, GPIOF_OUT_INIT_LOW, "LED0" }, /* LED0 - AA10 */ + { LED1_GPIO14, GPIOF_OUT_INIT_LOW, "LED1" }, /* LED1 - AA6 */ + { LED2_GPIO15, GPIOF_OUT_INIT_LOW, "LED2" }, /* LED2 - AA4 */ +}; + +static void __init apollon_led_init(void) +{ + omap_mux_init_signal("vlynq_clk.gpio_13", 0); + omap_mux_init_signal("vlynq_rx1.gpio_14", 0); + omap_mux_init_signal("vlynq_rx0.gpio_15", 0); + + gpio_request_array(apollon_gpio_leds, ARRAY_SIZE(apollon_gpio_leds)); +} + +static void __init apollon_usb_init(void) +{ + /* USB device */ + /* DEVICE_SUSPEND */ + omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0); + gpio_request_one(12, GPIOF_OUT_INIT_LOW, "USB suspend"); + omap2_usbfs_init(&apollon_usb_config); +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init omap_apollon_init(void) +{ + u32 v; + + omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC); + + apollon_init_smc91x(); + apollon_led_init(); + apollon_flash_init(); + apollon_usb_init(); + + /* REVISIT: where's the correct place */ + omap_mux_init_signal("sys_nirq", OMAP_PULL_ENA | OMAP_PULL_UP); + + /* LCD PWR_EN */ + omap_mux_init_signal("mcbsp2_dr.gpio_11", OMAP_PULL_ENA | OMAP_PULL_UP); + + /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */ + v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); + v |= (1 << 24); + omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0); + + /* + * Make sure the serial ports are muxed on at this point. + * You have to mux them off in device drivers later on + * if not needed. + */ + platform_add_devices(apollon_devices, ARRAY_SIZE(apollon_devices)); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + omap_display_init(&apollon_dss_data); +} + +MACHINE_START(OMAP_APOLLON, "OMAP24xx Apollon") + /* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap242x_map_io, + .init_early = omap2420_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = omap_apollon_init, + .timer = &omap2_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c new file mode 100644 index 00000000000..d73316ed420 --- /dev/null +++ b/arch/arm/mach-omap2/board-cm-t35.c @@ -0,0 +1,687 @@ +/* + * CompuLab CM-T35/CM-T3730 modules support + * + * Copyright (C) 2009-2011 CompuLab, Ltd. + * Authors: Mike Rapoport <mike@compulab.co.il> + * Igor Grinberg <grinberg@compulab.co.il> + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/delay.h> +#include <linux/gpio.h> + +#include <linux/i2c/at24.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/mmc/host.h> + +#include <linux/spi/spi.h> +#include <linux/spi/tdo24m.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/nand.h> +#include <plat/gpmc.h> +#include <plat/usb.h> +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-dvi.h> +#include <plat/mcspi.h> + +#include <mach/hardware.h> + +#include "mux.h" +#include "sdram-micron-mt46h32m32lf-6.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define CM_T35_GPIO_PENDOWN 57 +#define SB_T35_USB_HUB_RESET_GPIO 167 + +#define CM_T35_SMSC911X_CS 5 +#define CM_T35_SMSC911X_GPIO 163 +#define SB_T35_SMSC911X_CS 4 +#define SB_T35_SMSC911X_GPIO 65 + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +#include <linux/smsc911x.h> +#include <plat/gpmc-smsc911x.h> + +static struct omap_smsc911x_platform_data cm_t35_smsc911x_cfg = { + .id = 0, + .cs = CM_T35_SMSC911X_CS, + .gpio_irq = CM_T35_SMSC911X_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, +}; + +static struct omap_smsc911x_platform_data sb_t35_smsc911x_cfg = { + .id = 1, + .cs = SB_T35_SMSC911X_CS, + .gpio_irq = SB_T35_SMSC911X_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, +}; + +static void __init cm_t35_init_ethernet(void) +{ + gpmc_smsc911x_init(&cm_t35_smsc911x_cfg); + gpmc_smsc911x_init(&sb_t35_smsc911x_cfg); +} +#else +static inline void __init cm_t35_init_ethernet(void) { return; } +#endif + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +#include <linux/leds.h> + +static struct gpio_led cm_t35_leds[] = { + [0] = { + .gpio = 186, + .name = "cm-t35:green", + .default_trigger = "heartbeat", + .active_low = 0, + }, +}; + +static struct gpio_led_platform_data cm_t35_led_pdata = { + .num_leds = ARRAY_SIZE(cm_t35_leds), + .leds = cm_t35_leds, +}; + +static struct platform_device cm_t35_led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &cm_t35_led_pdata, + }, +}; + +static void __init cm_t35_init_led(void) +{ + platform_device_register(&cm_t35_led_device); +} +#else +static inline void cm_t35_init_led(void) {} +#endif + +#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE) +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> + +static struct mtd_partition cm_t35_nand_partitions[] = { + { + .name = "xloader", + .offset = 0, /* Offset = 0x00000 */ + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE + }, + { + .name = "uboot", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 15 * NAND_BLOCK_SIZE, + }, + { + .name = "uboot environment", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */ + .size = 2 * NAND_BLOCK_SIZE, + }, + { + .name = "linux", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x2A0000 */ + .size = 32 * NAND_BLOCK_SIZE, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x6A0000 */ + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_nand_platform_data cm_t35_nand_data = { + .parts = cm_t35_nand_partitions, + .nr_parts = ARRAY_SIZE(cm_t35_nand_partitions), + .cs = 0, +}; + +static void __init cm_t35_init_nand(void) +{ + if (gpmc_nand_init(&cm_t35_nand_data) < 0) + pr_err("CM-T35: Unable to register NAND device\n"); +} +#else +static inline void cm_t35_init_nand(void) {} +#endif + +#define CM_T35_LCD_EN_GPIO 157 +#define CM_T35_LCD_BL_GPIO 58 +#define CM_T35_DVI_EN_GPIO 54 + +static int lcd_enabled; +static int dvi_enabled; + +static int cm_t35_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + + gpio_set_value(CM_T35_LCD_EN_GPIO, 1); + gpio_set_value(CM_T35_LCD_BL_GPIO, 1); + + lcd_enabled = 1; + + return 0; +} + +static void cm_t35_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + lcd_enabled = 0; + + gpio_set_value(CM_T35_LCD_BL_GPIO, 0); + gpio_set_value(CM_T35_LCD_EN_GPIO, 0); +} + +static int cm_t35_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + + gpio_set_value(CM_T35_DVI_EN_GPIO, 0); + dvi_enabled = 1; + + return 0; +} + +static void cm_t35_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(CM_T35_DVI_EN_GPIO, 1); + dvi_enabled = 0; +} + +static int cm_t35_panel_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void cm_t35_panel_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct panel_generic_dpi_data lcd_panel = { + .name = "toppoly_tdo35s", + .platform_enable = cm_t35_panel_enable_lcd, + .platform_disable = cm_t35_panel_disable_lcd, +}; + +static struct omap_dss_device cm_t35_lcd_device = { + .name = "lcd", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "generic_dpi_panel", + .data = &lcd_panel, + .phy.dpi.data_lines = 18, +}; + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = cm_t35_panel_enable_dvi, + .platform_disable = cm_t35_panel_disable_dvi, +}; + +static struct omap_dss_device cm_t35_dvi_device = { + .name = "dvi", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device cm_t35_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = cm_t35_panel_enable_tv, + .platform_disable = cm_t35_panel_disable_tv, +}; + +static struct omap_dss_device *cm_t35_dss_devices[] = { + &cm_t35_lcd_device, + &cm_t35_dvi_device, + &cm_t35_tv_device, +}; + +static struct omap_dss_board_info cm_t35_dss_data = { + .num_devices = ARRAY_SIZE(cm_t35_dss_devices), + .devices = cm_t35_dss_devices, + .default_device = &cm_t35_dvi_device, +}; + +static struct omap2_mcspi_device_config tdo24m_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +static struct tdo24m_platform_data tdo24m_config = { + .model = TDO35S, +}; + +static struct spi_board_info cm_t35_lcd_spi_board_info[] __initdata = { + { + .modalias = "tdo24m", + .bus_num = 4, + .chip_select = 0, + .max_speed_hz = 1000000, + .controller_data = &tdo24m_mcspi_config, + .platform_data = &tdo24m_config, + }, +}; + +static struct gpio cm_t35_dss_gpios[] __initdata = { + { CM_T35_LCD_EN_GPIO, GPIOF_OUT_INIT_LOW, "lcd enable" }, + { CM_T35_LCD_BL_GPIO, GPIOF_OUT_INIT_LOW, "lcd bl enable" }, + { CM_T35_DVI_EN_GPIO, GPIOF_OUT_INIT_HIGH, "dvi enable" }, +}; + +static void __init cm_t35_init_display(void) +{ + int err; + + spi_register_board_info(cm_t35_lcd_spi_board_info, + ARRAY_SIZE(cm_t35_lcd_spi_board_info)); + + err = gpio_request_array(cm_t35_dss_gpios, + ARRAY_SIZE(cm_t35_dss_gpios)); + if (err) { + pr_err("CM-T35: failed to request DSS control GPIOs\n"); + return; + } + + gpio_export(CM_T35_LCD_EN_GPIO, 0); + gpio_export(CM_T35_LCD_BL_GPIO, 0); + gpio_export(CM_T35_DVI_EN_GPIO, 0); + + msleep(50); + gpio_set_value(CM_T35_LCD_EN_GPIO, 1); + + err = omap_display_init(&cm_t35_dss_data); + if (err) { + pr_err("CM-T35: failed to register DSS device\n"); + gpio_free_array(cm_t35_dss_gpios, ARRAY_SIZE(cm_t35_dss_gpios)); + } +} + +static struct regulator_consumer_supply cm_t35_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply cm_t35_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply cm_t35_vio_supplies[] = { + REGULATOR_SUPPLY("vcc", "spi1.0"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data cm_t35_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(cm_t35_vmmc1_supply), + .consumer_supplies = cm_t35_vmmc1_supply, +}; + +/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */ +static struct regulator_init_data cm_t35_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(cm_t35_vsim_supply), + .consumer_supplies = cm_t35_vsim_supply, +}; + +static struct regulator_init_data cm_t35_vio = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE, + }, + .num_consumer_supplies = ARRAY_SIZE(cm_t35_vio_supplies), + .consumer_supplies = cm_t35_vio_supplies, +}; + +static uint32_t cm_t35_keymap[] = { + KEY(0, 0, KEY_A), KEY(0, 1, KEY_B), KEY(0, 2, KEY_LEFT), + KEY(1, 0, KEY_UP), KEY(1, 1, KEY_ENTER), KEY(1, 2, KEY_DOWN), + KEY(2, 0, KEY_RIGHT), KEY(2, 1, KEY_C), KEY(2, 2, KEY_D), +}; + +static struct matrix_keymap_data cm_t35_keymap_data = { + .keymap = cm_t35_keymap, + .keymap_size = ARRAY_SIZE(cm_t35_keymap), +}; + +static struct twl4030_keypad_data cm_t35_kp_data = { + .keymap_data = &cm_t35_keymap_data, + .rows = 3, + .cols = 3, + .rep = 1, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + + }, + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA, + .transceiver = 1, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .ocr_mask = 0x00100000, /* 3.3V */ + }, + {} /* Terminator */ +}; + +static struct usbhs_omap_board_data usbhs_bdata __initdata = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = OMAP_MAX_GPIO_LINES + 6, + .reset_gpio_port[1] = OMAP_MAX_GPIO_LINES + 7, + .reset_gpio_port[2] = -EINVAL +}; + +static void __init cm_t35_init_usbh(void) +{ + int err; + + err = gpio_request_one(SB_T35_USB_HUB_RESET_GPIO, + GPIOF_OUT_INIT_LOW, "usb hub rst"); + if (err) { + pr_err("SB-T35: usb hub rst gpio request failed: %d\n", err); + } else { + udelay(10); + gpio_set_value(SB_T35_USB_HUB_RESET_GPIO, 1); + msleep(1); + } + + usbhs_init(&usbhs_bdata); +} + +static int cm_t35_twl_gpio_setup(struct device *dev, unsigned gpio, + unsigned ngpio) +{ + int wlan_rst = gpio + 2; + + if (gpio_request_one(wlan_rst, GPIOF_OUT_INIT_HIGH, "WLAN RST") == 0) { + gpio_export(wlan_rst, 0); + udelay(10); + gpio_set_value_cansleep(wlan_rst, 0); + udelay(10); + gpio_set_value_cansleep(wlan_rst, 1); + } else { + pr_err("CM-T35: could not obtain gpio for WiFi reset\n"); + } + + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + return 0; +} + +static struct twl4030_gpio_platform_data cm_t35_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .setup = cm_t35_twl_gpio_setup, +}; + +static struct twl4030_platform_data cm_t35_twldata = { + /* platform_data for children goes here */ + .keypad = &cm_t35_kp_data, + .gpio = &cm_t35_gpio_data, + .vmmc1 = &cm_t35_vmmc1, + .vsim = &cm_t35_vsim, + .vio = &cm_t35_vio, +}; + +static void __init cm_t35_init_i2c(void) +{ + omap3_pmic_get_config(&cm_t35_twldata, TWL_COMMON_PDATA_USB, + TWL_COMMON_REGULATOR_VDAC | + TWL_COMMON_PDATA_AUDIO); + + omap3_pmic_init("tps65930", &cm_t35_twldata); +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* nCS and IRQ for CM-T35 ethernet */ + OMAP3_MUX(GPMC_NCS5, OMAP_MUX_MODE0), + OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP), + + /* nCS and IRQ for SB-T35 ethernet */ + OMAP3_MUX(GPMC_NCS4, OMAP_MUX_MODE0), + OMAP3_MUX(GPMC_WAIT3, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP), + + /* PENDOWN GPIO */ + OMAP3_MUX(GPMC_NCS6, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + + /* mUSB */ + OMAP3_MUX(HSUSB0_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_STP, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(HSUSB0_DIR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_NXT, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* MMC 2 */ + OMAP3_MUX(SDMMC2_DAT4, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(SDMMC2_DAT5, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(SDMMC2_DAT6, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(SDMMC2_DAT7, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + + /* McSPI 1 */ + OMAP3_MUX(MCSPI1_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI1_SIMO, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI1_SOMI, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI1_CS0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + + /* McSPI 4 */ + OMAP3_MUX(MCBSP1_CLKR, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP1_DX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP1_DR, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP1_FSX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT_PULLUP), + + /* McBSP 2 */ + OMAP3_MUX(MCBSP2_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP2_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP2_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP2_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + + /* serial ports */ + OMAP3_MUX(MCBSP3_CLKX, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(MCBSP3_FSX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(UART1_TX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(UART1_RX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* common DSS */ + OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA9, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA10, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA11, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA12, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA13, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA14, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + + /* display controls */ + OMAP3_MUX(MCBSP1_FSR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(GPMC_NCS7, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + /* TPS IRQ */ + OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_WAKEUP_EN | \ + OMAP_PIN_INPUT_PULLUP), + + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +static void __init cm_t3x_common_dss_mux_init(int mux_mode) +{ + omap_mux_init_signal("dss_data18", mux_mode); + omap_mux_init_signal("dss_data19", mux_mode); + omap_mux_init_signal("dss_data20", mux_mode); + omap_mux_init_signal("dss_data21", mux_mode); + omap_mux_init_signal("dss_data22", mux_mode); + omap_mux_init_signal("dss_data23", mux_mode); +} + +static void __init cm_t35_init_mux(void) +{ + int mux_mode = OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT; + + omap_mux_init_signal("dss_data0.dss_data0", mux_mode); + omap_mux_init_signal("dss_data1.dss_data1", mux_mode); + omap_mux_init_signal("dss_data2.dss_data2", mux_mode); + omap_mux_init_signal("dss_data3.dss_data3", mux_mode); + omap_mux_init_signal("dss_data4.dss_data4", mux_mode); + omap_mux_init_signal("dss_data5.dss_data5", mux_mode); + cm_t3x_common_dss_mux_init(mux_mode); +} + +static void __init cm_t3730_init_mux(void) +{ + int mux_mode = OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT; + + omap_mux_init_signal("sys_boot0", mux_mode); + omap_mux_init_signal("sys_boot1", mux_mode); + omap_mux_init_signal("sys_boot3", mux_mode); + omap_mux_init_signal("sys_boot4", mux_mode); + omap_mux_init_signal("sys_boot5", mux_mode); + omap_mux_init_signal("sys_boot6", mux_mode); + cm_t3x_common_dss_mux_init(mux_mode); +} +#else +static inline void cm_t35_init_mux(void) {} +static inline void cm_t3730_init_mux(void) {} +#endif + +static struct omap_board_config_kernel cm_t35_config[] __initdata = { +}; + +static void __init cm_t3x_common_init(void) +{ + omap_board_config = cm_t35_config; + omap_board_config_size = ARRAY_SIZE(cm_t35_config); + omap3_mux_init(board_mux, OMAP_PACKAGE_CUS); + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + cm_t35_init_i2c(); + omap_ads7846_init(1, CM_T35_GPIO_PENDOWN, 0, NULL); + cm_t35_init_ethernet(); + cm_t35_init_led(); + cm_t35_init_display(); + + usb_musb_init(NULL); + cm_t35_init_usbh(); +} + +static void __init cm_t35_init(void) +{ + cm_t3x_common_init(); + cm_t35_init_mux(); + cm_t35_init_nand(); +} + +static void __init cm_t3730_init(void) +{ + cm_t3x_common_init(); + cm_t3730_init_mux(); +} + +MACHINE_START(CM_T35, "Compulab CM-T35") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = cm_t35_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(CM_T3730, "Compulab CM-T3730") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3630_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = cm_t3730_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c new file mode 100644 index 00000000000..f36d694d215 --- /dev/null +++ b/arch/arm/mach-omap2/board-cm-t3517.c @@ -0,0 +1,306 @@ +/* + * linux/arch/arm/mach-omap2/board-cm-t3517.c + * + * Support for the CompuLab CM-T3517 modules + * + * Copyright (C) 2010 CompuLab, Ltd. + * Author: Igor Grinberg <grinberg@compulab.co.il> + * + * 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/platform_device.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include <linux/rtc-v3020.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/can/platform/ti_hecc.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/usb.h> +#include <plat/nand.h> +#include <plat/gpmc.h> + +#include <mach/am35xx.h> + +#include "mux.h" +#include "control.h" +#include "common-board-devices.h" + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +static struct gpio_led cm_t3517_leds[] = { + [0] = { + .gpio = 186, + .name = "cm-t3517:green", + .default_trigger = "heartbeat", + .active_low = 0, + }, +}; + +static struct gpio_led_platform_data cm_t3517_led_pdata = { + .num_leds = ARRAY_SIZE(cm_t3517_leds), + .leds = cm_t3517_leds, +}; + +static struct platform_device cm_t3517_led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &cm_t3517_led_pdata, + }, +}; + +static void __init cm_t3517_init_leds(void) +{ + platform_device_register(&cm_t3517_led_device); +} +#else +static inline void cm_t3517_init_leds(void) {} +#endif + +#if defined(CONFIG_CAN_TI_HECC) || defined(CONFIG_CAN_TI_HECC_MODULE) +static struct resource cm_t3517_hecc_resources[] = { + { + .start = AM35XX_IPSS_HECC_BASE, + .end = AM35XX_IPSS_HECC_BASE + SZ_16K - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = INT_35XX_HECC0_IRQ, + .end = INT_35XX_HECC0_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct ti_hecc_platform_data cm_t3517_hecc_pdata = { + .scc_hecc_offset = AM35XX_HECC_SCC_HECC_OFFSET, + .scc_ram_offset = AM35XX_HECC_SCC_RAM_OFFSET, + .hecc_ram_offset = AM35XX_HECC_RAM_OFFSET, + .mbx_offset = AM35XX_HECC_MBOX_OFFSET, + .int_line = AM35XX_HECC_INT_LINE, + .version = AM35XX_HECC_VERSION, +}; + +static struct platform_device cm_t3517_hecc_device = { + .name = "ti_hecc", + .id = 1, + .num_resources = ARRAY_SIZE(cm_t3517_hecc_resources), + .resource = cm_t3517_hecc_resources, + .dev = { + .platform_data = &cm_t3517_hecc_pdata, + }, +}; + +static void cm_t3517_init_hecc(void) +{ + platform_device_register(&cm_t3517_hecc_device); +} +#else +static inline void cm_t3517_init_hecc(void) {} +#endif + +#if defined(CONFIG_RTC_DRV_V3020) || defined(CONFIG_RTC_DRV_V3020_MODULE) +#define RTC_IO_GPIO (153) +#define RTC_WR_GPIO (154) +#define RTC_RD_GPIO (53) +#define RTC_CS_GPIO (163) +#define RTC_CS_EN_GPIO (160) + +struct v3020_platform_data cm_t3517_v3020_pdata = { + .use_gpio = 1, + .gpio_cs = RTC_CS_GPIO, + .gpio_wr = RTC_WR_GPIO, + .gpio_rd = RTC_RD_GPIO, + .gpio_io = RTC_IO_GPIO, +}; + +static struct platform_device cm_t3517_rtc_device = { + .name = "v3020", + .id = -1, + .dev = { + .platform_data = &cm_t3517_v3020_pdata, + } +}; + +static void __init cm_t3517_init_rtc(void) +{ + int err; + + err = gpio_request_one(RTC_CS_EN_GPIO, GPIOF_OUT_INIT_HIGH, + "rtc cs en"); + if (err) { + pr_err("CM-T3517: rtc cs en gpio request failed: %d\n", err); + return; + } + + platform_device_register(&cm_t3517_rtc_device); +} +#else +static inline void cm_t3517_init_rtc(void) {} +#endif + +#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE) +#define HSUSB1_RESET_GPIO (146) +#define HSUSB2_RESET_GPIO (147) +#define USB_HUB_RESET_GPIO (152) + +static struct usbhs_omap_board_data cm_t3517_ehci_pdata __initdata = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = HSUSB1_RESET_GPIO, + .reset_gpio_port[1] = HSUSB2_RESET_GPIO, + .reset_gpio_port[2] = -EINVAL, +}; + +static int __init cm_t3517_init_usbh(void) +{ + int err; + + err = gpio_request_one(USB_HUB_RESET_GPIO, GPIOF_OUT_INIT_LOW, + "usb hub rst"); + if (err) { + pr_err("CM-T3517: usb hub rst gpio request failed: %d\n", err); + } else { + udelay(10); + gpio_set_value(USB_HUB_RESET_GPIO, 1); + msleep(1); + } + + usbhs_init(&cm_t3517_ehci_pdata); + + return 0; +} +#else +static inline int cm_t3517_init_usbh(void) +{ + return 0; +} +#endif + +#if defined(CONFIG_MTD_NAND_OMAP2) || defined(CONFIG_MTD_NAND_OMAP2_MODULE) +static struct mtd_partition cm_t3517_nand_partitions[] = { + { + .name = "xloader", + .offset = 0, /* Offset = 0x00000 */ + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE + }, + { + .name = "uboot", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 15 * NAND_BLOCK_SIZE, + }, + { + .name = "uboot environment", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */ + .size = 2 * NAND_BLOCK_SIZE, + }, + { + .name = "linux", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x2A0000 */ + .size = 32 * NAND_BLOCK_SIZE, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x6A0000 */ + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_nand_platform_data cm_t3517_nand_data = { + .parts = cm_t3517_nand_partitions, + .nr_parts = ARRAY_SIZE(cm_t3517_nand_partitions), + .cs = 0, +}; + +static void __init cm_t3517_init_nand(void) +{ + if (gpmc_nand_init(&cm_t3517_nand_data) < 0) + pr_err("CM-T3517: NAND initialization failed\n"); +} +#else +static inline void cm_t3517_init_nand(void) {} +#endif + +static struct omap_board_config_kernel cm_t3517_config[] __initdata = { +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* GPIO186 - Green LED */ + OMAP3_MUX(SYS_CLKOUT2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + /* RTC GPIOs: */ + /* IO - GPIO153 */ + OMAP3_MUX(MCBSP4_DR, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + /* WR# - GPIO154 */ + OMAP3_MUX(MCBSP4_DX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + /* RD# - GPIO53 */ + OMAP3_MUX(GPMC_NCS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + /* CS# - GPIO163 */ + OMAP3_MUX(UART3_CTS_RCTX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + /* CS EN - GPIO160 */ + OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + + /* HSUSB1 RESET */ + OMAP3_MUX(UART2_TX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + /* HSUSB2 RESET */ + OMAP3_MUX(UART2_RX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + /* CM-T3517 USB HUB nRESET */ + OMAP3_MUX(MCBSP4_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init cm_t3517_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + omap_board_config = cm_t3517_config; + omap_board_config_size = ARRAY_SIZE(cm_t3517_config); + cm_t3517_init_leds(); + cm_t3517_init_nand(); + cm_t3517_init_rtc(); + cm_t3517_init_usbh(); + cm_t3517_init_hecc(); +} + +MACHINE_START(CM_T3517, "Compulab CM-T3517") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = am35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = cm_t3517_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-devkit8000.c b/arch/arm/mach-omap2/board-devkit8000.c new file mode 100644 index 00000000000..e873063f4fd --- /dev/null +++ b/arch/arm/mach-omap2/board-devkit8000.c @@ -0,0 +1,667 @@ +/* + * board-devkit8000.c - TimLL Devkit8000 + * + * Copyright (C) 2009 Kim Botherway + * Copyright (C) 2010 Thomas Weber + * + * Modified from mach-omap2/board-omap3beagle.c + * + * Initial code: Syed Mohammed Khasim + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> +#include <linux/mmc/host.h> + +#include <linux/regulator/machine.h> +#include <linux/i2c/twl.h> + +#include <mach/hardware.h> +#include <mach/id.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> +#include <plat/nand.h> +#include <plat/usb.h> +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-dvi.h> + +#include <plat/mcspi.h> +#include <linux/input/matrix_keypad.h> +#include <linux/spi/spi.h> +#include <linux/dm9000.h> +#include <linux/interrupt.h> + +#include "sdram-micron-mt46h32m32lf-6.h" + +#include "mux.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define OMAP_DM9000_GPIO_IRQ 25 +#define OMAP3_DEVKIT_TS_GPIO 27 + +static struct mtd_partition devkit8000_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader", + .offset = 0, + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 15 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot Env", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */ + .size = 1 * NAND_BLOCK_SIZE, + }, + { + .name = "Kernel", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 32 * NAND_BLOCK_SIZE, + }, + { + .name = "File System", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */ + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_wp = 29, + }, + {} /* Terminator */ +}; + +static int devkit8000_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(dssdev->reset_gpio)) + gpio_set_value_cansleep(dssdev->reset_gpio, 1); + return 0; +} + +static void devkit8000_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(dssdev->reset_gpio)) + gpio_set_value_cansleep(dssdev->reset_gpio, 0); +} + +static int devkit8000_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(dssdev->reset_gpio)) + gpio_set_value_cansleep(dssdev->reset_gpio, 1); + return 0; +} + +static void devkit8000_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(dssdev->reset_gpio)) + gpio_set_value_cansleep(dssdev->reset_gpio, 0); +} + +static struct regulator_consumer_supply devkit8000_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +/* ads7846 on SPI */ +static struct regulator_consumer_supply devkit8000_vio_supply[] = { + REGULATOR_SUPPLY("vcc", "spi2.0"), +}; + +static struct panel_generic_dpi_data lcd_panel = { + .name = "innolux_at070tn83", + .platform_enable = devkit8000_panel_enable_lcd, + .platform_disable = devkit8000_panel_disable_lcd, +}; + +static struct omap_dss_device devkit8000_lcd_device = { + .name = "lcd", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "generic_dpi_panel", + .data = &lcd_panel, + .phy.dpi.data_lines = 24, +}; + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = devkit8000_panel_enable_dvi, + .platform_disable = devkit8000_panel_disable_dvi, +}; + +static struct omap_dss_device devkit8000_dvi_device = { + .name = "dvi", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device devkit8000_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, +}; + + +static struct omap_dss_device *devkit8000_dss_devices[] = { + &devkit8000_lcd_device, + &devkit8000_dvi_device, + &devkit8000_tv_device, +}; + +static struct omap_dss_board_info devkit8000_dss_data = { + .num_devices = ARRAY_SIZE(devkit8000_dss_devices), + .devices = devkit8000_dss_devices, + .default_device = &devkit8000_lcd_device, +}; + +static uint32_t board_keymap[] = { + KEY(0, 0, KEY_1), + KEY(1, 0, KEY_2), + KEY(2, 0, KEY_3), + KEY(0, 1, KEY_4), + KEY(1, 1, KEY_5), + KEY(2, 1, KEY_6), + KEY(3, 1, KEY_F5), + KEY(0, 2, KEY_7), + KEY(1, 2, KEY_8), + KEY(2, 2, KEY_9), + KEY(3, 2, KEY_F6), + KEY(0, 3, KEY_F7), + KEY(1, 3, KEY_0), + KEY(2, 3, KEY_F8), + PERSISTENT_KEY(4, 5), + KEY(4, 4, KEY_VOLUMEUP), + KEY(5, 5, KEY_VOLUMEDOWN), + 0 +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data devkit8000_kp_data = { + .keymap_data = &board_map_data, + .rows = 6, + .cols = 6, + .rep = 1, +}; + +static struct gpio_led gpio_leds[]; + +static int devkit8000_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + int ret; + + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + + /* TWL4030_GPIO_MAX + 0 is "LCD_PWREN" (out, active high) */ + devkit8000_lcd_device.reset_gpio = gpio + TWL4030_GPIO_MAX + 0; + ret = gpio_request_one(devkit8000_lcd_device.reset_gpio, + GPIOF_OUT_INIT_LOW, "LCD_PWREN"); + if (ret < 0) { + devkit8000_lcd_device.reset_gpio = -EINVAL; + printk(KERN_ERR "Failed to request GPIO for LCD_PWRN\n"); + } + + /* gpio + 7 is "DVI_PD" (out, active low) */ + devkit8000_dvi_device.reset_gpio = gpio + 7; + ret = gpio_request_one(devkit8000_dvi_device.reset_gpio, + GPIOF_OUT_INIT_LOW, "DVI PowerDown"); + if (ret < 0) { + devkit8000_dvi_device.reset_gpio = -EINVAL; + printk(KERN_ERR "Failed to request GPIO for DVI PowerDown\n"); + } + + return 0; +} + +static struct twl4030_gpio_platform_data devkit8000_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .pulldowns = BIT(1) | BIT(2) | BIT(6) | BIT(8) | BIT(13) + | BIT(15) | BIT(16) | BIT(17), + .setup = devkit8000_twl_gpio_setup, +}; + +static struct regulator_consumer_supply devkit8000_vpll1_supplies[] = { + REGULATOR_SUPPLY("vdds_dsi", "omapdss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data devkit8000_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(devkit8000_vmmc1_supply), + .consumer_supplies = devkit8000_vmmc1_supply, +}; + +/* VPLL1 for digital video outputs */ +static struct regulator_init_data devkit8000_vpll1 = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(devkit8000_vpll1_supplies), + .consumer_supplies = devkit8000_vpll1_supplies, +}; + +/* VAUX4 for ads7846 and nubs */ +static struct regulator_init_data devkit8000_vio = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(devkit8000_vio_supply), + .consumer_supplies = devkit8000_vio_supply, +}; + +static struct twl4030_platform_data devkit8000_twldata = { + /* platform_data for children goes here */ + .gpio = &devkit8000_gpio_data, + .vmmc1 = &devkit8000_vmmc1, + .vpll1 = &devkit8000_vpll1, + .vio = &devkit8000_vio, + .keypad = &devkit8000_kp_data, +}; + +static int __init devkit8000_i2c_init(void) +{ + omap3_pmic_get_config(&devkit8000_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC); + omap3_pmic_init("tps65930", &devkit8000_twldata); + /* Bus 3 is attached to the DVI port where devices like the pico DLP + * projector don't work reliably with 400kHz */ + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static struct gpio_led gpio_leds[] = { + { + .name = "led1", + .default_trigger = "heartbeat", + .gpio = 186, + .active_low = true, + }, + { + .name = "led2", + .default_trigger = "mmc0", + .gpio = 163, + .active_low = true, + }, + { + .name = "ledB", + .default_trigger = "none", + .gpio = 153, + .active_low = true, + }, + { + .name = "led3", + .default_trigger = "none", + .gpio = 164, + .active_low = true, + }, +}; + +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 gpio_keys_button gpio_buttons[] = { + { + .code = BTN_EXTRA, + .gpio = 26, + .desc = "user", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + +#define OMAP_DM9000_BASE 0x2c000000 + +static struct resource omap_dm9000_resources[] = { + [0] = { + .start = OMAP_DM9000_BASE, + .end = (OMAP_DM9000_BASE + 0x4 - 1), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = (OMAP_DM9000_BASE + 0x400), + .end = (OMAP_DM9000_BASE + 0x400 + 0x4 - 1), + .flags = IORESOURCE_MEM, + }, + [2] = { + .start = OMAP_GPIO_IRQ(OMAP_DM9000_GPIO_IRQ), + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW, + }, +}; + +static struct dm9000_plat_data omap_dm9000_platdata = { + .flags = DM9000_PLATF_16BITONLY, +}; + +static struct platform_device omap_dm9000_dev = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(omap_dm9000_resources), + .resource = omap_dm9000_resources, + .dev = { + .platform_data = &omap_dm9000_platdata, + }, +}; + +static void __init omap_dm9000_init(void) +{ + unsigned char *eth_addr = omap_dm9000_platdata.dev_addr; + struct omap_die_id odi; + int ret; + + ret = gpio_request_one(OMAP_DM9000_GPIO_IRQ, GPIOF_IN, "dm9000 irq"); + if (ret < 0) { + printk(KERN_ERR "Failed to request GPIO%d for dm9000 IRQ\n", + OMAP_DM9000_GPIO_IRQ); + return; + } + + /* init the mac address using DIE id */ + omap_get_die_id(&odi); + + eth_addr[0] = 0x02; /* locally administered */ + eth_addr[1] = odi.id_1 & 0xff; + eth_addr[2] = (odi.id_0 & 0xff000000) >> 24; + eth_addr[3] = (odi.id_0 & 0x00ff0000) >> 16; + eth_addr[4] = (odi.id_0 & 0x0000ff00) >> 8; + eth_addr[5] = (odi.id_0 & 0x000000ff); +} + +static struct platform_device *devkit8000_devices[] __initdata = { + &leds_gpio, + &keys_gpio, + &omap_dm9000_dev, +}; + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* nCS and IRQ for Devkit8000 ethernet */ + OMAP3_MUX(GPMC_NCS6, OMAP_MUX_MODE0), + OMAP3_MUX(ETK_D11, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP), + + /* McSPI 2*/ + OMAP3_MUX(MCSPI2_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI2_SIMO, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(MCSPI2_SOMI, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI2_CS0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(MCSPI2_CS1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + + /* PENDOWN GPIO */ + OMAP3_MUX(ETK_D13, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + + /* mUSB */ + OMAP3_MUX(HSUSB0_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_STP, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(HSUSB0_DIR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_NXT, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(HSUSB0_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* USB 1 */ + OMAP3_MUX(ETK_CTL, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_CLK, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT), + OMAP3_MUX(ETK_D8, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D9, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D0, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D1, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D2, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D4, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D5, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D6, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + OMAP3_MUX(ETK_D7, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + + /* MMC 1 */ + OMAP3_MUX(SDMMC1_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT4, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT5, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT6, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(SDMMC1_DAT7, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* McBSP 2 */ + OMAP3_MUX(MCBSP2_FSX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP2_CLKX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP2_DR, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP2_DX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + + /* I2C 1 */ + OMAP3_MUX(I2C1_SCL, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(I2C1_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* I2C 2 */ + OMAP3_MUX(I2C2_SCL, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(I2C2_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* I2C 3 */ + OMAP3_MUX(I2C3_SCL, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(I2C3_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* I2C 4 */ + OMAP3_MUX(I2C4_SCL, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(I2C4_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* serial ports */ + OMAP3_MUX(MCBSP3_CLKX, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(MCBSP3_FSX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(UART1_TX, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(UART1_RX, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* DSS */ + OMAP3_MUX(DSS_PCLK, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_HSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_VSYNC, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_ACBIAS, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA0, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA1, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA2, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA3, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA4, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA5, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA6, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA7, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA8, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA9, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA10, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA11, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA12, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA13, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA14, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA15, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA16, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA17, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA20, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE0 | OMAP_PIN_OUTPUT), + + /* expansion port */ + /* McSPI 1 */ + OMAP3_MUX(MCSPI1_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI1_SIMO, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI1_SOMI, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(MCSPI1_CS0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + OMAP3_MUX(MCSPI1_CS3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLDOWN), + + /* HDQ */ + OMAP3_MUX(HDQ_SIO, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + /* McSPI4 */ + OMAP3_MUX(MCBSP1_CLKR, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP1_DX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP1_DR, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP3_MUX(MCBSP1_FSX, OMAP_MUX_MODE1 | OMAP_PIN_INPUT_PULLUP), + + /* MMC 2 */ + OMAP3_MUX(SDMMC2_DAT4, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(SDMMC2_DAT5, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(SDMMC2_DAT6, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + OMAP3_MUX(SDMMC2_DAT7, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + + /* I2C3 */ + OMAP3_MUX(I2C3_SCL, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + OMAP3_MUX(I2C3_SDA, OMAP_MUX_MODE0 | OMAP_PIN_INPUT), + + OMAP3_MUX(MCBSP1_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(MCBSP_CLKS, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(MCBSP1_FSR, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + OMAP3_MUX(GPMC_NCS7, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + OMAP3_MUX(GPMC_NCS3, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + /* TPS IRQ */ + OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_WAKEUP_EN | \ + OMAP_PIN_INPUT_PULLUP), + + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init devkit8000_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CUS); + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + + omap_dm9000_init(); + + devkit8000_i2c_init(); + platform_add_devices(devkit8000_devices, + ARRAY_SIZE(devkit8000_devices)); + + omap_display_init(&devkit8000_dss_data); + + omap_ads7846_init(2, OMAP3_DEVKIT_TS_GPIO, 0, NULL); + + usb_musb_init(NULL); + usbhs_init(&usbhs_bdata); + omap_nand_flash_init(NAND_BUSWIDTH_16, devkit8000_nand_partitions, + ARRAY_SIZE(devkit8000_nand_partitions)); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); +} + +MACHINE_START(DEVKIT8000, "OMAP3 Devkit8000") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = devkit8000_init, + .timer = &omap3_secure_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c new file mode 100644 index 00000000000..30a6f527510 --- /dev/null +++ b/arch/arm/mach-omap2/board-flash.c @@ -0,0 +1,247 @@ +/* + * board-flash.c + * Modified from mach-omap2/board-3430sdp-flash.c + * + * Copyright (C) 2009 Nokia Corporation + * Copyright (C) 2009 Texas Instruments + * + * Vimal Singh <vimalsingh@ti.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/kernel.h> +#include <linux/platform_device.h> +#include <linux/mtd/physmap.h> +#include <linux/io.h> +#include <plat/irqs.h> + +#include <plat/gpmc.h> +#include <plat/nand.h> +#include <plat/onenand.h> +#include <plat/tc.h> + +#include "board-flash.h" + +#define REG_FPGA_REV 0x10 +#define REG_FPGA_DIP_SWITCH_INPUT2 0x60 +#define MAX_SUPPORTED_GPMC_CONFIG 3 + +#define DEBUG_BASE 0x08000000 /* debug board */ + +/* various memory sizes */ +#define FLASH_SIZE_SDPV1 SZ_64M /* NOR flash (64 Meg aligned) */ +#define FLASH_SIZE_SDPV2 SZ_128M /* NOR flash (256 Meg aligned) */ + +static struct physmap_flash_data board_nor_data = { + .width = 2, +}; + +static struct resource board_nor_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device board_nor_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &board_nor_data, + }, + .num_resources = 1, + .resource = &board_nor_resource, +}; + +static void +__init board_nor_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs) +{ + int err; + + board_nor_data.parts = nor_parts; + board_nor_data.nr_parts = nr_parts; + + /* Configure start address and size of NOR device */ + if (omap_rev() >= OMAP3430_REV_ES1_0) { + err = gpmc_cs_request(cs, FLASH_SIZE_SDPV2 - 1, + (unsigned long *)&board_nor_resource.start); + board_nor_resource.end = board_nor_resource.start + + FLASH_SIZE_SDPV2 - 1; + } else { + err = gpmc_cs_request(cs, FLASH_SIZE_SDPV1 - 1, + (unsigned long *)&board_nor_resource.start); + board_nor_resource.end = board_nor_resource.start + + FLASH_SIZE_SDPV1 - 1; + } + if (err < 0) { + pr_err("NOR: Can't request GPMC CS\n"); + return; + } + if (platform_device_register(&board_nor_device) < 0) + pr_err("Unable to register NOR device\n"); +} + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) +static struct omap_onenand_platform_data board_onenand_data = { + .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */ +}; + +static void +__init board_onenand_init(struct mtd_partition *onenand_parts, + u8 nr_parts, u8 cs) +{ + board_onenand_data.cs = cs; + board_onenand_data.parts = onenand_parts; + board_onenand_data.nr_parts = nr_parts; + + gpmc_onenand_init(&board_onenand_data); +} +#else +static void +__init board_onenand_init(struct mtd_partition *nor_parts, u8 nr_parts, u8 cs) +{ +} +#endif /* CONFIG_MTD_ONENAND_OMAP2 || CONFIG_MTD_ONENAND_OMAP2_MODULE */ + +#if defined(CONFIG_MTD_NAND_OMAP2) || \ + defined(CONFIG_MTD_NAND_OMAP2_MODULE) + +/* Note that all values in this struct are in nanoseconds */ +static struct gpmc_timings nand_timings = { + + .sync_clk = 0, + + .cs_on = 0, + .cs_rd_off = 36, + .cs_wr_off = 36, + + .adv_on = 6, + .adv_rd_off = 24, + .adv_wr_off = 36, + + .we_off = 30, + .oe_off = 48, + + .access = 54, + .rd_cycle = 72, + .wr_cycle = 72, + + .wr_access = 30, + .wr_data_mux_bus = 0, +}; + +static struct omap_nand_platform_data board_nand_data = { + .gpmc_t = &nand_timings, +}; + +void +__init board_nand_init(struct mtd_partition *nand_parts, + u8 nr_parts, u8 cs, int nand_type) +{ + board_nand_data.cs = cs; + board_nand_data.parts = nand_parts; + board_nand_data.nr_parts = nr_parts; + board_nand_data.devsize = nand_type; + + board_nand_data.ecc_opt = OMAP_ECC_HAMMING_CODE_DEFAULT; + board_nand_data.gpmc_irq = OMAP_GPMC_IRQ_BASE + cs; + gpmc_nand_init(&board_nand_data); +} +#endif /* CONFIG_MTD_NAND_OMAP2 || CONFIG_MTD_NAND_OMAP2_MODULE */ + +/** + * get_gpmc0_type - Reads the FPGA DIP_SWITCH_INPUT_REGISTER2 to get + * the various cs values. + */ +static u8 get_gpmc0_type(void) +{ + u8 cs = 0; + void __iomem *fpga_map_addr; + + fpga_map_addr = ioremap(DEBUG_BASE, 4096); + if (!fpga_map_addr) + return -ENOMEM; + + if (!(__raw_readw(fpga_map_addr + REG_FPGA_REV))) + /* we dont have an DEBUG FPGA??? */ + /* Depend on #defines!! default to strata boot return param */ + goto unmap; + + /* S8-DIP-OFF = 1, S8-DIP-ON = 0 */ + cs = __raw_readw(fpga_map_addr + REG_FPGA_DIP_SWITCH_INPUT2) & 0xf; + + /* ES2.0 SDP's onwards 4 dip switches are provided for CS */ + if (omap_rev() >= OMAP3430_REV_ES1_0) + /* change (S8-1:4=DS-2:0) to (S8-4:1=DS-2:0) */ + cs = ((cs & 8) >> 3) | ((cs & 4) >> 1) | + ((cs & 2) << 1) | ((cs & 1) << 3); + else + /* change (S8-1:3=DS-2:0) to (S8-3:1=DS-2:0) */ + cs = ((cs & 4) >> 2) | (cs & 2) | ((cs & 1) << 2); +unmap: + iounmap(fpga_map_addr); + return cs; +} + +/** + * board_flash_init - Identify devices connected to GPMC and register. + * + * @return - void. + */ +void board_flash_init(struct flash_partitions partition_info[], + char chip_sel_board[][GPMC_CS_NUM], int nand_type) +{ + u8 cs = 0; + u8 norcs = GPMC_CS_NUM + 1; + u8 nandcs = GPMC_CS_NUM + 1; + u8 onenandcs = GPMC_CS_NUM + 1; + u8 idx; + unsigned char *config_sel = NULL; + + /* REVISIT: Is this return correct idx for 2430 SDP? + * for which cs configuration matches for 2430 SDP? + */ + idx = get_gpmc0_type(); + if (idx >= MAX_SUPPORTED_GPMC_CONFIG) { + pr_err("%s: Invalid chip select: %d\n", __func__, cs); + return; + } + config_sel = (unsigned char *)(chip_sel_board[idx]); + + while (cs < GPMC_CS_NUM) { + switch (config_sel[cs]) { + case PDC_NOR: + if (norcs > GPMC_CS_NUM) + norcs = cs; + break; + case PDC_NAND: + if (nandcs > GPMC_CS_NUM) + nandcs = cs; + break; + case PDC_ONENAND: + if (onenandcs > GPMC_CS_NUM) + onenandcs = cs; + break; + }; + cs++; + } + + if (norcs > GPMC_CS_NUM) + pr_err("NOR: Unable to find configuration in GPMC\n"); + else + board_nor_init(partition_info[0].parts, + partition_info[0].nr_parts, norcs); + + if (onenandcs > GPMC_CS_NUM) + pr_err("OneNAND: Unable to find configuration in GPMC\n"); + else + board_onenand_init(partition_info[1].parts, + partition_info[1].nr_parts, onenandcs); + + if (nandcs > GPMC_CS_NUM) + pr_err("NAND: Unable to find configuration in GPMC\n"); + else + board_nand_init(partition_info[2].parts, + partition_info[2].nr_parts, nandcs, nand_type); +} diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h new file mode 100644 index 00000000000..d25503a9841 --- /dev/null +++ b/arch/arm/mach-omap2/board-flash.h @@ -0,0 +1,49 @@ +/* + * board-sdp.h + * + * Information structures for SDP-specific board config data + * + * Copyright (C) 2009 Nokia Corporation + * Copyright (C) 2009 Texas Instruments + * + * 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/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <plat/gpmc.h> + +#define PDC_NOR 1 +#define PDC_NAND 2 +#define PDC_ONENAND 3 +#define DBG_MPDB 4 + +struct flash_partitions { + struct mtd_partition *parts; + int nr_parts; +}; + +#if defined(CONFIG_MTD_NAND_OMAP2) || \ + defined(CONFIG_MTD_NAND_OMAP2_MODULE) || \ + defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) +extern void board_flash_init(struct flash_partitions [], + char chip_sel[][GPMC_CS_NUM], int nand_type); +#else +static inline void board_flash_init(struct flash_partitions part[], + char chip_sel[][GPMC_CS_NUM], int nand_type) +{ +} +#endif + +#if defined(CONFIG_MTD_NAND_OMAP2) || \ + defined(CONFIG_MTD_NAND_OMAP2_MODULE) +extern void board_nand_init(struct mtd_partition *nand_parts, + u8 nr_parts, u8 cs, int nand_type); +#else +static inline void board_nand_init(struct mtd_partition *nand_parts, + u8 nr_parts, u8 cs, int nand_type) +{ +} +#endif diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c new file mode 100644 index 00000000000..ad497620539 --- /dev/null +++ b/arch/arm/mach-omap2/board-generic.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2005 Nokia Corporation + * Author: Paul Mundt <paul.mundt@nokia.com> + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ + * + * Modified from the original mach-omap/omap2/board-generic.c did by Paul + * to support the OMAP2+ device tree boards with an unique board file. + * + * 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/io.h> +#include <linux/of_platform.h> +#include <linux/irqdomain.h> +#include <linux/i2c/twl.h> + +#include <mach/hardware.h> +#include <asm/hardware/gic.h> +#include <asm/mach/arch.h> + +#include <plat/board.h> +#include "common.h" +#include "common-board-devices.h" + +/* + * XXX: Still needed to boot until the i2c & twl driver is adapted to + * device-tree + */ +#ifdef CONFIG_ARCH_OMAP4 +static struct twl4030_platform_data sdp4430_twldata = { + .irq_base = TWL6030_IRQ_BASE, + .irq_end = TWL6030_IRQ_END, +}; + +static void __init omap4_i2c_init(void) +{ + omap4_pmic_init("twl6030", &sdp4430_twldata); +} +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static struct twl4030_platform_data beagle_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, +}; + +static void __init omap3_i2c_init(void) +{ + omap3_pmic_init("twl4030", &beagle_twldata); +} +#endif + +static struct of_device_id omap_dt_match_table[] __initdata = { + { .compatible = "simple-bus", }, + { .compatible = "ti,omap-infra", }, + { } +}; + +static struct of_device_id intc_match[] __initdata = { + { .compatible = "ti,omap3-intc", }, + { .compatible = "arm,cortex-a9-gic", }, + { } +}; + +static void __init omap_generic_init(void) +{ + struct device_node *node = of_find_matching_node(NULL, intc_match); + if (node) + irq_domain_add_simple(node, 0); + + omap_sdrc_init(NULL, NULL); + + of_platform_populate(NULL, omap_dt_match_table, NULL, NULL); +} + +#ifdef CONFIG_ARCH_OMAP4 +static void __init omap4_init(void) +{ + omap4_i2c_init(); + omap_generic_init(); +} +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static void __init omap3_init(void) +{ + omap3_i2c_init(); + omap_generic_init(); +} +#endif + +#if defined(CONFIG_SOC_OMAP2420) +static const char *omap242x_boards_compat[] __initdata = { + "ti,omap2420", + NULL, +}; + +DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap242x_map_io, + .init_early = omap2420_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = omap_generic_init, + .timer = &omap2_timer, + .dt_compat = omap242x_boards_compat, + .restart = omap_prcm_restart, +MACHINE_END +#endif + +#if defined(CONFIG_SOC_OMAP2430) +static const char *omap243x_boards_compat[] __initdata = { + "ti,omap2430", + NULL, +}; + +DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap243x_map_io, + .init_early = omap2430_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = omap_generic_init, + .timer = &omap2_timer, + .dt_compat = omap243x_boards_compat, + .restart = omap_prcm_restart, +MACHINE_END +#endif + +#if defined(CONFIG_ARCH_OMAP3) +static const char *omap3_boards_compat[] __initdata = { + "ti,omap3", + NULL, +}; + +DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3430_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3_init, + .timer = &omap3_timer, + .dt_compat = omap3_boards_compat, + .restart = omap_prcm_restart, +MACHINE_END +#endif + +#if defined(CONFIG_ARCH_OMAP4) +static const char *omap4_boards_compat[] __initdata = { + "ti,omap4", + NULL, +}; + +DT_MACHINE_START(OMAP4_DT, "Generic OMAP4 (Flattened Device Tree)") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap4_map_io, + .init_early = omap4430_init_early, + .init_irq = gic_init_irq, + .handle_irq = gic_handle_irq, + .init_machine = omap4_init, + .timer = &omap4_timer, + .dt_compat = omap4_boards_compat, + .restart = omap_prcm_restart, +MACHINE_END +#endif diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c new file mode 100644 index 00000000000..54af800d143 --- /dev/null +++ b/arch/arm/mach-omap2/board-h4.c @@ -0,0 +1,403 @@ +/* + * linux/arch/arm/mach-omap2/board-h4.c + * + * Copyright (C) 2005 Nokia Corporation + * Author: Paul Mundt <paul.mundt@nokia.com> + * + * Modified from mach-omap/omap1/board-generic.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> +#include <linux/delay.h> +#include <linux/workqueue.h> +#include <linux/i2c.h> +#include <linux/i2c/at24.h> +#include <linux/input.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/input/matrix_keypad.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/usb.h> +#include <plat/board.h> +#include "common.h" +#include <plat/menelaus.h> +#include <plat/dma.h> +#include <plat/gpmc.h> + +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> + +#include "mux.h" +#include "control.h" + +#define H4_FLASH_CS 0 +#define H4_SMC91X_CS 1 + +#define H4_ETHR_GPIO_IRQ 92 + +#if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE) +static const uint32_t board_matrix_keys[] = { + KEY(0, 0, KEY_LEFT), + KEY(1, 0, KEY_RIGHT), + KEY(2, 0, KEY_A), + KEY(3, 0, KEY_B), + KEY(4, 0, KEY_C), + KEY(0, 1, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(2, 1, KEY_E), + KEY(3, 1, KEY_F), + KEY(4, 1, KEY_G), + KEY(0, 2, KEY_ENTER), + KEY(1, 2, KEY_I), + KEY(2, 2, KEY_J), + KEY(3, 2, KEY_K), + KEY(4, 2, KEY_3), + KEY(0, 3, KEY_M), + KEY(1, 3, KEY_N), + KEY(2, 3, KEY_O), + KEY(3, 3, KEY_P), + KEY(4, 3, KEY_Q), + KEY(0, 4, KEY_R), + KEY(1, 4, KEY_4), + KEY(2, 4, KEY_T), + KEY(3, 4, KEY_U), + KEY(4, 4, KEY_ENTER), + KEY(0, 5, KEY_V), + KEY(1, 5, KEY_W), + KEY(2, 5, KEY_L), + KEY(3, 5, KEY_S), + KEY(4, 5, KEY_ENTER), +}; + +static const struct matrix_keymap_data board_keymap_data = { + .keymap = board_matrix_keys, + .keymap_size = ARRAY_SIZE(board_matrix_keys), +}; + +static unsigned int board_keypad_row_gpios[] = { + 88, 89, 124, 11, 6, 96 +}; + +static unsigned int board_keypad_col_gpios[] = { + 90, 91, 100, 36, 12, 97, 98 +}; + +static struct matrix_keypad_platform_data board_keypad_platform_data = { + .keymap_data = &board_keymap_data, + .row_gpios = board_keypad_row_gpios, + .num_row_gpios = ARRAY_SIZE(board_keypad_row_gpios), + .col_gpios = board_keypad_col_gpios, + .num_col_gpios = ARRAY_SIZE(board_keypad_col_gpios), + .active_low = 1, + + .debounce_ms = 20, + .col_scan_delay_us = 5, +}; + +static struct platform_device board_keyboard = { + .name = "matrix-keypad", + .id = -1, + .dev = { + .platform_data = &board_keypad_platform_data, + }, +}; +static void __init board_mkp_init(void) +{ + omap_mux_init_gpio(88, OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_gpio(89, OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_gpio(124, OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_signal("mcbsp2_dr.gpio_11", OMAP_PULL_ENA | OMAP_PULL_UP); + if (omap_has_menelaus()) { + omap_mux_init_signal("sdrc_a14.gpio0", + OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_signal("vlynq_rx0.gpio_15", 0); + omap_mux_init_signal("gpio_98", 0); + board_keypad_row_gpios[5] = 0; + board_keypad_col_gpios[2] = 15; + board_keypad_col_gpios[6] = 18; + } else { + omap_mux_init_signal("gpio_96", OMAP_PULL_ENA | OMAP_PULL_UP); + omap_mux_init_signal("gpio_100", 0); + omap_mux_init_signal("gpio_98", 0); + } + omap_mux_init_signal("gpio_90", 0); + omap_mux_init_signal("gpio_91", 0); + omap_mux_init_signal("gpio_36", 0); + omap_mux_init_signal("mcbsp2_clkx.gpio_12", 0); + omap_mux_init_signal("gpio_97", 0); + + platform_device_register(&board_keyboard); +} +#else +static inline void board_mkp_init(void) +{ +} +#endif + +static struct mtd_partition h4_partitions[] = { + /* bootloader (U-Boot, etc) in first sector */ + { + .name = "bootloader", + .offset = 0, + .size = SZ_128K, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + /* bootloader params in the next sector */ + { + .name = "params", + .offset = MTDPART_OFS_APPEND, + .size = SZ_128K, + .mask_flags = 0, + }, + /* kernel */ + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = SZ_2M, + .mask_flags = 0 + }, + /* file system */ + { + .name = "filesystem", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + .mask_flags = 0 + } +}; + +static struct physmap_flash_data h4_flash_data = { + .width = 2, + .parts = h4_partitions, + .nr_parts = ARRAY_SIZE(h4_partitions), +}; + +static struct resource h4_flash_resource = { + .flags = IORESOURCE_MEM, +}; + +static struct platform_device h4_flash_device = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = &h4_flash_data, + }, + .num_resources = 1, + .resource = &h4_flash_resource, +}; + +static struct platform_device *h4_devices[] __initdata = { + &h4_flash_device, +}; + +static struct panel_generic_dpi_data h4_panel_data = { + .name = "h4", +}; + +static struct omap_dss_device h4_lcd_device = { + .name = "lcd", + .driver_name = "generic_dpi_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 16, + .data = &h4_panel_data, +}; + +static struct omap_dss_device *h4_dss_devices[] = { + &h4_lcd_device, +}; + +static struct omap_dss_board_info h4_dss_data = { + .num_devices = ARRAY_SIZE(h4_dss_devices), + .devices = h4_dss_devices, + .default_device = &h4_lcd_device, +}; + +/* 2420 Sysboot setup (2430 is different) */ +static u32 get_sysboot_value(void) +{ + return (omap_ctrl_readl(OMAP24XX_CONTROL_STATUS) & + (OMAP2_SYSBOOT_5_MASK | OMAP2_SYSBOOT_4_MASK | + OMAP2_SYSBOOT_3_MASK | OMAP2_SYSBOOT_2_MASK | + OMAP2_SYSBOOT_1_MASK | OMAP2_SYSBOOT_0_MASK)); +} + +/* H4-2420's always used muxed mode, H4-2422's always use non-muxed + * + * Note: OMAP-GIT doesn't correctly do is_cpu_omap2422 and is_cpu_omap2423 + * correctly. The macro needs to look at production_id not just hawkeye. + */ +static u32 is_gpmc_muxed(void) +{ + u32 mux; + mux = get_sysboot_value(); + if ((mux & 0xF) == 0xd) + return 1; /* NAND config (could be either) */ + if (mux & 0x2) /* if mux'ed */ + return 1; + else + return 0; +} + +static inline void __init h4_init_debug(void) +{ + int eth_cs; + unsigned long cs_mem_base; + unsigned int muxed, rate; + struct clk *gpmc_fck; + + eth_cs = H4_SMC91X_CS; + + gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */ + if (IS_ERR(gpmc_fck)) { + WARN_ON(1); + return; + } + + clk_enable(gpmc_fck); + rate = clk_get_rate(gpmc_fck); + clk_disable(gpmc_fck); + clk_put(gpmc_fck); + + if (is_gpmc_muxed()) + muxed = 0x200; + else + muxed = 0; + + /* Make sure CS1 timings are correct */ + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, + 0x00011000 | muxed); + + if (rate >= 160000000) { + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4); + } else if (rate >= 130000000) { + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4); + } else {/* rate = 100000000 */ + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F); + gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2); + } + + if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) { + printk(KERN_ERR "Failed to request GPMC mem for smc91x\n"); + goto out; + } + + udelay(100); + + omap_mux_init_gpio(92, 0); + if (debug_card_init(cs_mem_base, H4_ETHR_GPIO_IRQ) < 0) + gpmc_cs_free(eth_cs); + +out: + clk_disable(gpmc_fck); + clk_put(gpmc_fck); +} + +static void __init h4_init_flash(void) +{ + unsigned long base; + + if (gpmc_cs_request(H4_FLASH_CS, SZ_64M, &base) < 0) { + printk("Can't request GPMC CS for flash\n"); + return; + } + h4_flash_resource.start = base; + h4_flash_resource.end = base + SZ_64M - 1; +} + +static struct omap_usb_config h4_usb_config __initdata = { + /* S1.10 OFF -- usb "download port" + * usb0 switched to Mini-B port and isp1105 transceiver; + * S2.POS3 = ON, S2.POS4 = OFF ... to enable battery charging + */ + .register_dev = 1, + .pins[0] = 3, +/* .hmc_mode = 0x14,*/ /* 0:dev 1:host 2:disable */ + .hmc_mode = 0x00, /* 0:dev|otg 1:disable 2:disable */ +}; + +static struct at24_platform_data m24c01 = { + .byte_len = SZ_1K / 8, + .page_size = 16, +}; + +static struct i2c_board_info __initdata h4_i2c_board_info[] = { + { + I2C_BOARD_INFO("isp1301_omap", 0x2d), + .irq = OMAP_GPIO_IRQ(125), + }, + { /* EEPROM on mainboard */ + I2C_BOARD_INFO("24c01", 0x52), + .platform_data = &m24c01, + }, + { /* EEPROM on cpu card */ + I2C_BOARD_INFO("24c01", 0x57), + .platform_data = &m24c01, + }, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init omap_h4_init(void) +{ + omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAF); + + /* + * Make sure the serial ports are muxed on at this point. + * You have to mux them off in device drivers later on + * if not needed. + */ + + board_mkp_init(); + i2c_register_board_info(1, h4_i2c_board_info, + ARRAY_SIZE(h4_i2c_board_info)); + + platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices)); + omap2_usbfs_init(&h4_usb_config); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + h4_init_flash(); + + omap_display_init(&h4_dss_data); +} + +MACHINE_START(OMAP_H4, "OMAP2420 H4 board") + /* Maintainer: Paul Mundt <paul.mundt@nokia.com> */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap242x_map_io, + .init_early = omap2420_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = omap_h4_init, + .timer = &omap2_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-igep0020.c b/arch/arm/mach-omap2/board-igep0020.c new file mode 100644 index 00000000000..a59ace0ed56 --- /dev/null +++ b/arch/arm/mach-omap2/board-igep0020.c @@ -0,0 +1,691 @@ +/* + * Copyright (C) 2009 Integration Software and Electronic Engineering. + * + * Modified from mach-omap2/board-generic.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/input.h> + +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/i2c/twl.h> +#include <linux/mmc/host.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> +#include <plat/usb.h> +#include <video/omapdss.h> +#include <video/omap-panel-dvi.h> +#include <plat/onenand.h> + +#include "mux.h" +#include "hsmmc.h" +#include "sdram-numonyx-m65kxxxxam.h" +#include "common-board-devices.h" + +#define IGEP2_SMSC911X_CS 5 +#define IGEP2_SMSC911X_GPIO 176 +#define IGEP2_GPIO_USBH_NRESET 24 +#define IGEP2_GPIO_LED0_GREEN 26 +#define IGEP2_GPIO_LED0_RED 27 +#define IGEP2_GPIO_LED1_RED 28 +#define IGEP2_GPIO_DVI_PUP 170 + +#define IGEP2_RB_GPIO_WIFI_NPD 94 +#define IGEP2_RB_GPIO_WIFI_NRESET 95 +#define IGEP2_RB_GPIO_BT_NRESET 137 +#define IGEP2_RC_GPIO_WIFI_NPD 138 +#define IGEP2_RC_GPIO_WIFI_NRESET 139 +#define IGEP2_RC_GPIO_BT_NRESET 137 + +#define IGEP3_GPIO_LED0_GREEN 54 +#define IGEP3_GPIO_LED0_RED 53 +#define IGEP3_GPIO_LED1_RED 16 +#define IGEP3_GPIO_USBH_NRESET 183 + +/* + * IGEP2 Hardware Revision Table + * + * -------------------------------------------------------------------------- + * | Id. | Hw Rev. | HW0 (28) | WIFI_NPD | WIFI_NRESET | BT_NRESET | + * -------------------------------------------------------------------------- + * | 0 | B | high | gpio94 | gpio95 | - | + * | 0 | B/C (B-compatible) | high | gpio94 | gpio95 | gpio137 | + * | 1 | C | low | gpio138 | gpio139 | gpio137 | + * -------------------------------------------------------------------------- + */ + +#define IGEP2_BOARD_HWREV_B 0 +#define IGEP2_BOARD_HWREV_C 1 +#define IGEP3_BOARD_HWREV 2 + +static u8 hwrev; + +static void __init igep2_get_revision(void) +{ + u8 ret; + + if (machine_is_igep0030()) { + hwrev = IGEP3_BOARD_HWREV; + return; + } + + omap_mux_init_gpio(IGEP2_GPIO_LED1_RED, OMAP_PIN_INPUT); + + if (gpio_request_one(IGEP2_GPIO_LED1_RED, GPIOF_IN, "GPIO_HW0_REV")) { + pr_warning("IGEP2: Could not obtain gpio GPIO_HW0_REV\n"); + pr_err("IGEP2: Unknown Hardware Revision\n"); + return; + } + + ret = gpio_get_value(IGEP2_GPIO_LED1_RED); + if (ret == 0) { + pr_info("IGEP2: Hardware Revision C (B-NON compatible)\n"); + hwrev = IGEP2_BOARD_HWREV_C; + } else if (ret == 1) { + pr_info("IGEP2: Hardware Revision B/C (B compatible)\n"); + hwrev = IGEP2_BOARD_HWREV_B; + } else { + pr_err("IGEP2: Unknown Hardware Revision\n"); + hwrev = -1; + } + + gpio_free(IGEP2_GPIO_LED1_RED); +} + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) + +#define ONENAND_MAP 0x20000000 + +/* NAND04GR4E1A ( x2 Flash built-in COMBO POP MEMORY ) + * Since the device is equipped with two DataRAMs, and two-plane NAND + * Flash memory array, these two component enables simultaneous program + * of 4KiB. Plane1 has only even blocks such as block0, block2, block4 + * while Plane2 has only odd blocks such as block1, block3, block5. + * So MTD regards it as 4KiB page size and 256KiB block size 64*(2*2048) + */ + +static struct mtd_partition igep_onenand_partitions[] = { + { + .name = "X-Loader", + .offset = 0, + .size = 2 * (64*(2*2048)) + }, + { + .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, + .size = 6 * (64*(2*2048)), + }, + { + .name = "Environment", + .offset = MTDPART_OFS_APPEND, + .size = 2 * (64*(2*2048)), + }, + { + .name = "Kernel", + .offset = MTDPART_OFS_APPEND, + .size = 12 * (64*(2*2048)), + }, + { + .name = "File System", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_onenand_platform_data igep_onenand_data = { + .parts = igep_onenand_partitions, + .nr_parts = ARRAY_SIZE(igep_onenand_partitions), + .dma_channel = -1, /* disable DMA in OMAP OneNAND driver */ +}; + +static struct platform_device igep_onenand_device = { + .name = "omap2-onenand", + .id = -1, + .dev = { + .platform_data = &igep_onenand_data, + }, +}; + +static void __init igep_flash_init(void) +{ + u8 cs = 0; + u8 onenandcs = GPMC_CS_NUM + 1; + + for (cs = 0; cs < GPMC_CS_NUM; cs++) { + u32 ret; + ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); + + /* Check if NAND/oneNAND is configured */ + if ((ret & 0xC00) == 0x800) + /* NAND found */ + pr_err("IGEP: Unsupported NAND found\n"); + else { + ret = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7); + if ((ret & 0x3F) == (ONENAND_MAP >> 24)) + /* ONENAND found */ + onenandcs = cs; + } + } + + if (onenandcs > GPMC_CS_NUM) { + pr_err("IGEP: Unable to find configuration in GPMC\n"); + return; + } + + igep_onenand_data.cs = onenandcs; + + if (platform_device_register(&igep_onenand_device) < 0) + pr_err("IGEP: Unable to register OneNAND device\n"); +} + +#else +static void __init igep_flash_init(void) {} +#endif + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) + +#include <linux/smsc911x.h> +#include <plat/gpmc-smsc911x.h> + +static struct omap_smsc911x_platform_data smsc911x_cfg = { + .cs = IGEP2_SMSC911X_CS, + .gpio_irq = IGEP2_SMSC911X_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, +}; + +static inline void __init igep2_init_smsc911x(void) +{ + gpmc_smsc911x_init(&smsc911x_cfg); +} + +#else +static inline void __init igep2_init_smsc911x(void) { } +#endif + +static struct regulator_consumer_supply igep_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */ +static struct regulator_init_data igep_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(igep_vmmc1_supply), + .consumer_supplies = igep_vmmc1_supply, +}; + +static struct regulator_consumer_supply igep_vio_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1"), +}; + +static struct regulator_init_data igep_vio = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = 1, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(igep_vio_supply), + .consumer_supplies = igep_vio_supply, +}; + +static struct regulator_consumer_supply igep_vmmc2_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +static struct regulator_init_data igep_vmmc2 = { + .constraints = { + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(igep_vmmc2_supply), + .consumer_supplies = igep_vmmc2_supply, +}; + +static struct fixed_voltage_config igep_vwlan = { + .supply_name = "vwlan", + .microvolts = 3300000, + .gpio = -EINVAL, + .enabled_at_boot = 1, + .init_data = &igep_vmmc2, +}; + +static struct platform_device igep_vwlan_device = { + .name = "reg-fixed-voltage", + .id = 0, + .dev = { + .platform_data = &igep_vwlan, + }, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, +#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE) + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, +#endif + {} /* Terminator */ +}; + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +#include <linux/leds.h> + +static struct gpio_led igep_gpio_leds[] = { + [0] = { + .name = "gpio-led:red:d0", + .default_trigger = "default-off" + }, + [1] = { + .name = "gpio-led:green:d0", + .default_trigger = "default-off", + }, + [2] = { + .name = "gpio-led:red:d1", + .default_trigger = "default-off", + }, + [3] = { + .name = "gpio-led:green:d1", + .default_trigger = "heartbeat", + .gpio = -EINVAL, /* gets replaced */ + .active_low = 1, + }, +}; + +static struct gpio_led_platform_data igep_led_pdata = { + .leds = igep_gpio_leds, + .num_leds = ARRAY_SIZE(igep_gpio_leds), +}; + +static struct platform_device igep_led_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &igep_led_pdata, + }, +}; + +static void __init igep_leds_init(void) +{ + if (machine_is_igep0020()) { + igep_gpio_leds[0].gpio = IGEP2_GPIO_LED0_RED; + igep_gpio_leds[1].gpio = IGEP2_GPIO_LED0_GREEN; + igep_gpio_leds[2].gpio = IGEP2_GPIO_LED1_RED; + } else { + igep_gpio_leds[0].gpio = IGEP3_GPIO_LED0_RED; + igep_gpio_leds[1].gpio = IGEP3_GPIO_LED0_GREEN; + igep_gpio_leds[2].gpio = IGEP3_GPIO_LED1_RED; + } + + platform_device_register(&igep_led_device); +} + +#else +static struct gpio igep_gpio_leds[] __initdata = { + { -EINVAL, GPIOF_OUT_INIT_LOW, "gpio-led:red:d0" }, + { -EINVAL, GPIOF_OUT_INIT_LOW, "gpio-led:green:d0" }, + { -EINVAL, GPIOF_OUT_INIT_LOW, "gpio-led:red:d1" }, +}; + +static inline void igep_leds_init(void) +{ + int i; + + if (machine_is_igep0020()) { + igep_gpio_leds[0].gpio = IGEP2_GPIO_LED0_RED; + igep_gpio_leds[1].gpio = IGEP2_GPIO_LED0_GREEN; + igep_gpio_leds[2].gpio = IGEP2_GPIO_LED1_RED; + } else { + igep_gpio_leds[0].gpio = IGEP3_GPIO_LED0_RED; + igep_gpio_leds[1].gpio = IGEP3_GPIO_LED0_GREEN; + igep_gpio_leds[2].gpio = IGEP3_GPIO_LED1_RED; + } + + if (gpio_request_array(igep_gpio_leds, ARRAY_SIZE(igep_gpio_leds))) { + pr_warning("IGEP v2: Could not obtain leds gpios\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(igep_gpio_leds); i++) + gpio_export(igep_gpio_leds[i].gpio, 0); +} +#endif + +static struct gpio igep2_twl_gpios[] = { + { -EINVAL, GPIOF_IN, "GPIO_EHCI_NOC" }, + { -EINVAL, GPIOF_OUT_INIT_LOW, "GPIO_USBH_CPEN" }, +}; + +static int igep_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + int ret; + + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */ +#if !defined(CONFIG_LEDS_GPIO) && !defined(CONFIG_LEDS_GPIO_MODULE) + ret = gpio_request_one(gpio + TWL4030_GPIO_MAX + 1, GPIOF_OUT_INIT_HIGH, + "gpio-led:green:d1"); + if (ret == 0) + gpio_export(gpio + TWL4030_GPIO_MAX + 1, 0); + else + pr_warning("IGEP: Could not obtain gpio GPIO_LED1_GREEN\n"); +#else + igep_gpio_leds[3].gpio = gpio + TWL4030_GPIO_MAX + 1; +#endif + + if (machine_is_igep0030()) + return 0; + + /* + * REVISIT: need ehci-omap hooks for external VBUS + * power switch and overcurrent detect + */ + igep2_twl_gpios[0].gpio = gpio + 1; + + /* TWL4030_GPIO_MAX + 0 == ledA, GPIO_USBH_CPEN (out, active low) */ + igep2_twl_gpios[1].gpio = gpio + TWL4030_GPIO_MAX; + + ret = gpio_request_array(igep2_twl_gpios, ARRAY_SIZE(igep2_twl_gpios)); + if (ret < 0) + pr_err("IGEP2: Could not obtain gpio for USBH_CPEN"); + + return 0; +}; + +static struct twl4030_gpio_platform_data igep_twl4030_gpio_pdata = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .setup = igep_twl_gpio_setup, +}; + +static int igep2_enable_dvi(struct omap_dss_device *dssdev) +{ + gpio_direction_output(IGEP2_GPIO_DVI_PUP, 1); + + return 0; +} + +static void igep2_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_direction_output(IGEP2_GPIO_DVI_PUP, 0); +} + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = igep2_enable_dvi, + .platform_disable = igep2_disable_dvi, + .i2c_bus_num = 3, +}; + +static struct omap_dss_device igep2_dvi_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "dvi", + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device *igep2_dss_devices[] = { + &igep2_dvi_device +}; + +static struct omap_dss_board_info igep2_dss_data = { + .num_devices = ARRAY_SIZE(igep2_dss_devices), + .devices = igep2_dss_devices, + .default_device = &igep2_dvi_device, +}; + +static void __init igep2_display_init(void) +{ + int err = gpio_request_one(IGEP2_GPIO_DVI_PUP, GPIOF_OUT_INIT_HIGH, + "GPIO_DVI_PUP"); + if (err) + pr_err("IGEP v2: Could not obtain gpio GPIO_DVI_PUP\n"); +} + +static struct platform_device *igep_devices[] __initdata = { + &igep_vwlan_device, +}; + +static int igep2_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_RIGHT), + KEY(0, 2, KEY_A), + KEY(0, 3, KEY_B), + KEY(1, 0, KEY_DOWN), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_E), + KEY(1, 3, KEY_F), + KEY(2, 0, KEY_ENTER), + KEY(2, 1, KEY_I), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_K), + KEY(3, 0, KEY_M), + KEY(3, 1, KEY_N), + KEY(3, 2, KEY_O), + KEY(3, 3, KEY_P) +}; + +static struct matrix_keymap_data igep2_keymap_data = { + .keymap = igep2_keymap, + .keymap_size = ARRAY_SIZE(igep2_keymap), +}; + +static struct twl4030_keypad_data igep2_keypad_pdata = { + .keymap_data = &igep2_keymap_data, + .rows = 4, + .cols = 4, + .rep = 1, +}; + +static struct twl4030_platform_data igep_twldata = { + /* platform_data for children goes here */ + .gpio = &igep_twl4030_gpio_pdata, + .vmmc1 = &igep_vmmc1, + .vio = &igep_vio, +}; + +static struct i2c_board_info __initdata igep2_i2c3_boardinfo[] = { + { + I2C_BOARD_INFO("eeprom", 0x50), + }, +}; + +static void __init igep_i2c_init(void) +{ + int ret; + + omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_USB, 0); + + if (machine_is_igep0020()) { + /* + * Bus 3 is attached to the DVI port where devices like the + * pico DLP projector don't work reliably with 400kHz + */ + ret = omap_register_i2c_bus(3, 100, igep2_i2c3_boardinfo, + ARRAY_SIZE(igep2_i2c3_boardinfo)); + if (ret) + pr_warning("IGEP2: Could not register I2C3 bus (%d)\n", ret); + + igep_twldata.keypad = &igep2_keypad_pdata; + /* Get common pmic data */ + omap3_pmic_get_config(&igep_twldata, TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VPLL2); + igep_twldata.vpll2->constraints.apply_uV = true; + igep_twldata.vpll2->constraints.name = "VDVI"; + } + + omap3_pmic_init("twl4030", &igep_twldata); +} + +static const struct usbhs_omap_board_data igep2_usbhs_bdata __initconst = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = IGEP2_GPIO_USBH_NRESET, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL, +}; + +static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = { + .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = IGEP3_GPIO_USBH_NRESET, + .reset_gpio_port[2] = -EINVAL, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +#if defined(CONFIG_LIBERTAS_SDIO) || defined(CONFIG_LIBERTAS_SDIO_MODULE) +static struct gpio igep_wlan_bt_gpios[] __initdata = { + { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_NPD" }, + { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_WIFI_NRESET" }, + { -EINVAL, GPIOF_OUT_INIT_HIGH, "GPIO_BT_NRESET" }, +}; + +static void __init igep_wlan_bt_init(void) +{ + int err; + + /* GPIO's for WLAN-BT combo depends on hardware revision */ + if (hwrev == IGEP2_BOARD_HWREV_B) { + igep_wlan_bt_gpios[0].gpio = IGEP2_RB_GPIO_WIFI_NPD; + igep_wlan_bt_gpios[1].gpio = IGEP2_RB_GPIO_WIFI_NRESET; + igep_wlan_bt_gpios[2].gpio = IGEP2_RB_GPIO_BT_NRESET; + } else if (hwrev == IGEP2_BOARD_HWREV_C || machine_is_igep0030()) { + igep_wlan_bt_gpios[0].gpio = IGEP2_RC_GPIO_WIFI_NPD; + igep_wlan_bt_gpios[1].gpio = IGEP2_RC_GPIO_WIFI_NRESET; + igep_wlan_bt_gpios[2].gpio = IGEP2_RC_GPIO_BT_NRESET; + } else + return; + + err = gpio_request_array(igep_wlan_bt_gpios, + ARRAY_SIZE(igep_wlan_bt_gpios)); + if (err) { + pr_warning("IGEP2: Could not obtain WIFI/BT gpios\n"); + return; + } + + gpio_export(igep_wlan_bt_gpios[0].gpio, 0); + gpio_export(igep_wlan_bt_gpios[1].gpio, 0); + gpio_export(igep_wlan_bt_gpios[2].gpio, 0); + + gpio_set_value(igep_wlan_bt_gpios[1].gpio, 0); + udelay(10); + gpio_set_value(igep_wlan_bt_gpios[1].gpio, 1); + +} +#else +static inline void __init igep_wlan_bt_init(void) { } +#endif + +static void __init igep_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + + /* Get IGEP2 hardware revision */ + igep2_get_revision(); + /* Register I2C busses and drivers */ + igep_i2c_init(); + platform_add_devices(igep_devices, ARRAY_SIZE(igep_devices)); + omap_serial_init(); + omap_sdrc_init(m65kxxxxam_sdrc_params, + m65kxxxxam_sdrc_params); + usb_musb_init(NULL); + + igep_flash_init(); + igep_leds_init(); + + /* + * WLAN-BT combo module from MuRata which has a Marvell WLAN + * (88W8686) + CSR Bluetooth chipset. Uses SDIO interface. + */ + igep_wlan_bt_init(); + + if (machine_is_igep0020()) { + omap_display_init(&igep2_dss_data); + igep2_display_init(); + igep2_init_smsc911x(); + usbhs_init(&igep2_usbhs_bdata); + } else { + usbhs_init(&igep3_usbhs_bdata); + } +} + +MACHINE_START(IGEP0020, "IGEP v2 board") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = igep_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(IGEP0030, "IGEP OMAP3 module") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = igep_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c new file mode 100644 index 00000000000..2d2a61f7dcb --- /dev/null +++ b/arch/arm/mach-omap2/board-ldp.c @@ -0,0 +1,441 @@ +/* + * linux/arch/arm/mach-omap2/board-ldp.c + * + * Copyright (C) 2008 Texas Instruments Inc. + * Nishant Kamat <nskamat@ti.com> + * + * Modified from mach-omap2/board-3430sdp.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/gpio_keys.h> +#include <linux/workqueue.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/spi/spi.h> +#include <linux/regulator/machine.h> +#include <linux/i2c/twl.h> +#include <linux/io.h> +#include <linux/smsc911x.h> +#include <linux/mmc/host.h> +#include <linux/gpio.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/mcspi.h> +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> +#include <mach/board-zoom.h> + +#include <asm/delay.h> +#include <plat/usb.h> +#include <plat/gpmc-smsc911x.h> + +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> + +#include "board-flash.h" +#include "mux.h" +#include "hsmmc.h" +#include "control.h" +#include "common-board-devices.h" + +#define LDP_SMSC911X_CS 1 +#define LDP_SMSC911X_GPIO 152 +#define DEBUG_BASE 0x08000000 +#define LDP_ETHR_START DEBUG_BASE + +static uint32_t board_keymap[] = { + KEY(0, 0, KEY_1), + KEY(1, 0, KEY_2), + KEY(2, 0, KEY_3), + KEY(0, 1, KEY_4), + KEY(1, 1, KEY_5), + KEY(2, 1, KEY_6), + KEY(3, 1, KEY_F5), + KEY(0, 2, KEY_7), + KEY(1, 2, KEY_8), + KEY(2, 2, KEY_9), + KEY(3, 2, KEY_F6), + KEY(0, 3, KEY_F7), + KEY(1, 3, KEY_0), + KEY(2, 3, KEY_F8), + PERSISTENT_KEY(4, 5), + KEY(4, 4, KEY_VOLUMEUP), + KEY(5, 5, KEY_VOLUMEDOWN), + 0 +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data ldp_kp_twl4030_data = { + .keymap_data = &board_map_data, + .rows = 6, + .cols = 6, + .rep = 1, +}; + +static struct gpio_keys_button ldp_gpio_keys_buttons[] = { + [0] = { + .code = KEY_ENTER, + .gpio = 101, + .desc = "enter sw", + .active_low = 1, + .debounce_interval = 30, + }, + [1] = { + .code = KEY_F1, + .gpio = 102, + .desc = "func 1", + .active_low = 1, + .debounce_interval = 30, + }, + [2] = { + .code = KEY_F2, + .gpio = 103, + .desc = "func 2", + .active_low = 1, + .debounce_interval = 30, + }, + [3] = { + .code = KEY_F3, + .gpio = 104, + .desc = "func 3", + .active_low = 1, + .debounce_interval = 30, + }, + [4] = { + .code = KEY_F4, + .gpio = 105, + .desc = "func 4", + .active_low = 1, + .debounce_interval = 30, + }, + [5] = { + .code = KEY_LEFT, + .gpio = 106, + .desc = "left sw", + .active_low = 1, + .debounce_interval = 30, + }, + [6] = { + .code = KEY_RIGHT, + .gpio = 107, + .desc = "right sw", + .active_low = 1, + .debounce_interval = 30, + }, + [7] = { + .code = KEY_UP, + .gpio = 108, + .desc = "up sw", + .active_low = 1, + .debounce_interval = 30, + }, + [8] = { + .code = KEY_DOWN, + .gpio = 109, + .desc = "down sw", + .active_low = 1, + .debounce_interval = 30, + }, +}; + +static struct gpio_keys_platform_data ldp_gpio_keys = { + .buttons = ldp_gpio_keys_buttons, + .nbuttons = ARRAY_SIZE(ldp_gpio_keys_buttons), + .rep = 1, +}; + +static struct platform_device ldp_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &ldp_gpio_keys, + }, +}; + +static struct omap_smsc911x_platform_data smsc911x_cfg = { + .cs = LDP_SMSC911X_CS, + .gpio_irq = LDP_SMSC911X_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT, +}; + +static inline void __init ldp_init_smsc911x(void) +{ + gpmc_smsc911x_init(&smsc911x_cfg); +} + +/* LCD */ + +static int ldp_backlight_gpio; +static int ldp_lcd_enable_gpio; + +#define LCD_PANEL_RESET_GPIO 55 +#define LCD_PANEL_QVGA_GPIO 56 + +static int ldp_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(ldp_lcd_enable_gpio)) + gpio_direction_output(ldp_lcd_enable_gpio, 1); + if (gpio_is_valid(ldp_backlight_gpio)) + gpio_direction_output(ldp_backlight_gpio, 1); + + return 0; +} + +static void ldp_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(ldp_lcd_enable_gpio)) + gpio_direction_output(ldp_lcd_enable_gpio, 0); + if (gpio_is_valid(ldp_backlight_gpio)) + gpio_direction_output(ldp_backlight_gpio, 0); +} + +static struct panel_generic_dpi_data ldp_panel_data = { + .name = "nec_nl2432dr22-11b", + .platform_enable = ldp_panel_enable_lcd, + .platform_disable = ldp_panel_disable_lcd, +}; + +static struct omap_dss_device ldp_lcd_device = { + .name = "lcd", + .driver_name = "generic_dpi_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 18, + .data = &ldp_panel_data, +}; + +static struct omap_dss_device *ldp_dss_devices[] = { + &ldp_lcd_device, +}; + +static struct omap_dss_board_info ldp_dss_data = { + .num_devices = ARRAY_SIZE(ldp_dss_devices), + .devices = ldp_dss_devices, + .default_device = &ldp_lcd_device, +}; + +static void __init ldp_display_init(void) +{ + int r; + + static struct gpio gpios[] __initdata = { + {LCD_PANEL_RESET_GPIO, GPIOF_OUT_INIT_HIGH, "LCD RESET"}, + {LCD_PANEL_QVGA_GPIO, GPIOF_OUT_INIT_HIGH, "LCD QVGA"}, + }; + + r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (r) { + pr_err("Cannot request LCD GPIOs, error %d\n", r); + return; + } + + omap_display_init(&ldp_dss_data); +} + +static int ldp_twl_gpio_setup(struct device *dev, unsigned gpio, unsigned ngpio) +{ + int r; + + struct gpio gpios[] = { + {gpio + 7 , GPIOF_OUT_INIT_LOW, "LCD ENABLE"}, + {gpio + 15, GPIOF_OUT_INIT_LOW, "LCD BACKLIGHT"}, + }; + + r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); + if (r) { + pr_err("Cannot request LCD GPIOs, error %d\n", r); + ldp_backlight_gpio = -EINVAL; + ldp_lcd_enable_gpio = -EINVAL; + return r; + } + + ldp_backlight_gpio = gpio + 15; + ldp_lcd_enable_gpio = gpio + 7; + + return 0; +} + +static struct twl4030_gpio_platform_data ldp_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .setup = ldp_twl_gpio_setup, +}; + +static struct regulator_consumer_supply ldp_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data ldp_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ldp_vmmc1_supply), + .consumer_supplies = ldp_vmmc1_supply, +}; + +/* ads7846 on SPI */ +static struct regulator_consumer_supply ldp_vaux1_supplies[] = { + REGULATOR_SUPPLY("vcc", "spi1.0"), +}; + +/* VAUX1 */ +static struct regulator_init_data ldp_vaux1 = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ldp_vaux1_supplies), + .consumer_supplies = ldp_vaux1_supplies, +}; + +static struct regulator_consumer_supply ldp_vpll2_supplies[] = { + REGULATOR_SUPPLY("vdds_dsi", "omapdss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi1"), +}; + +static struct regulator_init_data ldp_vpll2 = { + .constraints = { + .name = "VDVI", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ldp_vpll2_supplies), + .consumer_supplies = ldp_vpll2_supplies, +}; + +static struct twl4030_platform_data ldp_twldata = { + /* platform_data for children goes here */ + .vmmc1 = &ldp_vmmc1, + .vaux1 = &ldp_vaux1, + .vpll2 = &ldp_vpll2, + .gpio = &ldp_gpio_data, + .keypad = &ldp_kp_twl4030_data, +}; + +static int __init omap_i2c_init(void) +{ + omap3_pmic_get_config(&ldp_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC, 0); + omap3_pmic_init("twl4030", &ldp_twldata); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static struct omap2_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + +static struct platform_device *ldp_devices[] __initdata = { + &ldp_gpio_keys_device, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static struct mtd_partition ldp_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader-NAND", + .offset = 0, + .size = 4 * (64 * 2048), /* 512KB, 0x80000 */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 10 * (64 * 2048), /* 1.25MB, 0x140000 */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "Boot Env-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */ + .size = 2 * (64 * 2048), /* 256KB, 0x40000 */ + }, + { + .name = "Kernel-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x0200000*/ + .size = 240 * (64 * 2048), /* 30M, 0x1E00000 */ + }, + { + .name = "File System - NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x2000000 */ + .size = MTDPART_SIZ_FULL, /* 96MB, 0x6000000 */ + }, + +}; + +static void __init omap_ldp_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + ldp_init_smsc911x(); + omap_i2c_init(); + platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices)); + omap_ads7846_init(1, 54, 310, NULL); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + usb_musb_init(NULL); + board_nand_init(ldp_nand_partitions, + ARRAY_SIZE(ldp_nand_partitions), ZOOM_NAND_CS, 0); + + omap2_hsmmc_init(mmc); + ldp_display_init(); +} + +MACHINE_START(OMAP_LDP, "OMAP LDP board") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3430_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap_ldp_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c new file mode 100644 index 00000000000..67226271760 --- /dev/null +++ b/arch/arm/mach-omap2/board-n8x0.c @@ -0,0 +1,724 @@ +/* + * linux/arch/arm/mach-omap2/board-n8x0.c + * + * Copyright (C) 2005-2009 Nokia Corporation + * Author: Juha Yrjola <juha.yrjola@nokia.com> + * + * Modified from mach-omap2/board-generic.c + * + * 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/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/stddef.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/usb/musb.h> +#include <sound/tlv320aic3x.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/menelaus.h> +#include <mach/irqs.h> +#include <plat/mcspi.h> +#include <plat/onenand.h> +#include <plat/mmc.h> +#include <plat/serial.h> + +#include "mux.h" + +static int slot1_cover_open; +static int slot2_cover_open; +static struct device *mmc_device; + +#define TUSB6010_ASYNC_CS 1 +#define TUSB6010_SYNC_CS 4 +#define TUSB6010_GPIO_INT 58 +#define TUSB6010_GPIO_ENABLE 0 +#define TUSB6010_DMACHAN 0x3f + +#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE) +/* + * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and + * 1.5 V voltage regulators of PM companion chip. Companion chip will then + * provide then PGOOD signal to TUSB6010 which will release it from reset. + */ +static int tusb_set_power(int state) +{ + int i, retval = 0; + + if (state) { + gpio_set_value(TUSB6010_GPIO_ENABLE, 1); + msleep(1); + + /* Wait until TUSB6010 pulls INT pin down */ + i = 100; + while (i && gpio_get_value(TUSB6010_GPIO_INT)) { + msleep(1); + i--; + } + + if (!i) { + printk(KERN_ERR "tusb: powerup failed\n"); + retval = -ENODEV; + } + } else { + gpio_set_value(TUSB6010_GPIO_ENABLE, 0); + msleep(10); + } + + return retval; +} + +static struct musb_hdrc_config musb_config = { + .multipoint = 1, + .dyn_fifo = 1, + .num_eps = 16, + .ram_bits = 12, +}; + +static struct musb_hdrc_platform_data tusb_data = { +#if defined(CONFIG_USB_MUSB_OTG) + .mode = MUSB_OTG, +#elif defined(CONFIG_USB_MUSB_PERIPHERAL) + .mode = MUSB_PERIPHERAL, +#else /* defined(CONFIG_USB_MUSB_HOST) */ + .mode = MUSB_HOST, +#endif + .set_power = tusb_set_power, + .min_power = 25, /* x2 = 50 mA drawn from VBUS as peripheral */ + .power = 100, /* Max 100 mA VBUS for host mode */ + .config = &musb_config, +}; + +static void __init n8x0_usb_init(void) +{ + int ret = 0; + static char announce[] __initdata = KERN_INFO "TUSB 6010\n"; + + /* PM companion chip power control pin */ + ret = gpio_request_one(TUSB6010_GPIO_ENABLE, GPIOF_OUT_INIT_LOW, + "TUSB6010 enable"); + if (ret != 0) { + printk(KERN_ERR "Could not get TUSB power GPIO%i\n", + TUSB6010_GPIO_ENABLE); + return; + } + tusb_set_power(0); + + ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2, + TUSB6010_ASYNC_CS, TUSB6010_SYNC_CS, + TUSB6010_GPIO_INT, TUSB6010_DMACHAN); + if (ret != 0) + goto err; + + printk(announce); + + return; + +err: + gpio_free(TUSB6010_GPIO_ENABLE); +} +#else + +static void __init n8x0_usb_init(void) {} + +#endif /*CONFIG_USB_MUSB_TUSB6010 */ + + +static struct omap2_mcspi_device_config p54spi_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct spi_board_info n800_spi_board_info[] __initdata = { + { + .modalias = "p54spi", + .bus_num = 2, + .chip_select = 0, + .max_speed_hz = 48000000, + .controller_data = &p54spi_mcspi_config, + }, +}; + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) + +static struct mtd_partition onenand_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x20000, + .mask_flags = MTD_WRITEABLE, /* Force read-only */ + }, + { + .name = "config", + .offset = MTDPART_OFS_APPEND, + .size = 0x60000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 0x200000, + }, + { + .name = "initfs", + .offset = MTDPART_OFS_APPEND, + .size = 0x400000, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_onenand_platform_data board_onenand_data[] = { + { + .cs = 0, + .gpio_irq = 26, + .parts = onenand_partitions, + .nr_parts = ARRAY_SIZE(onenand_partitions), + .flags = ONENAND_SYNC_READ, + } +}; +#endif + +#if defined(CONFIG_MENELAUS) && \ + (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)) + +/* + * On both N800 and N810, only the first of the two MMC controllers is in use. + * The two MMC slots are multiplexed via Menelaus companion chip over I2C. + * On N800, both slots are powered via Menelaus. On N810, only one of the + * slots is powered via Menelaus. The N810 EMMC is powered via GPIO. + * + * VMMC slot 1 on both N800 and N810 + * VDCDC3_APE and VMCS2_APE slot 2 on N800 + * GPIO23 and GPIO9 slot 2 EMMC on N810 + * + */ +#define N8X0_SLOT_SWITCH_GPIO 96 +#define N810_EMMC_VSD_GPIO 23 +#define N810_EMMC_VIO_GPIO 9 + +static int n8x0_mmc_switch_slot(struct device *dev, int slot) +{ +#ifdef CONFIG_MMC_DEBUG + dev_dbg(dev, "Choose slot %d\n", slot + 1); +#endif + gpio_set_value(N8X0_SLOT_SWITCH_GPIO, slot); + return 0; +} + +static int n8x0_mmc_set_power_menelaus(struct device *dev, int slot, + int power_on, int vdd) +{ + int mV; + +#ifdef CONFIG_MMC_DEBUG + dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1, + power_on ? "on" : "off", vdd); +#endif + if (slot == 0) { + if (!power_on) + return menelaus_set_vmmc(0); + switch (1 << vdd) { + case MMC_VDD_33_34: + case MMC_VDD_32_33: + case MMC_VDD_31_32: + mV = 3100; + break; + case MMC_VDD_30_31: + mV = 3000; + break; + case MMC_VDD_28_29: + mV = 2800; + break; + case MMC_VDD_165_195: + mV = 1850; + break; + default: + BUG(); + } + return menelaus_set_vmmc(mV); + } else { + if (!power_on) + return menelaus_set_vdcdc(3, 0); + switch (1 << vdd) { + case MMC_VDD_33_34: + case MMC_VDD_32_33: + mV = 3300; + break; + case MMC_VDD_30_31: + case MMC_VDD_29_30: + mV = 3000; + break; + case MMC_VDD_28_29: + case MMC_VDD_27_28: + mV = 2800; + break; + case MMC_VDD_24_25: + case MMC_VDD_23_24: + mV = 2400; + break; + case MMC_VDD_22_23: + case MMC_VDD_21_22: + mV = 2200; + break; + case MMC_VDD_20_21: + mV = 2000; + break; + case MMC_VDD_165_195: + mV = 1800; + break; + default: + BUG(); + } + return menelaus_set_vdcdc(3, mV); + } + return 0; +} + +static void n810_set_power_emmc(struct device *dev, + int power_on) +{ + dev_dbg(dev, "Set EMMC power %s\n", power_on ? "on" : "off"); + + if (power_on) { + gpio_set_value(N810_EMMC_VSD_GPIO, 1); + msleep(1); + gpio_set_value(N810_EMMC_VIO_GPIO, 1); + msleep(1); + } else { + gpio_set_value(N810_EMMC_VIO_GPIO, 0); + msleep(50); + gpio_set_value(N810_EMMC_VSD_GPIO, 0); + msleep(50); + } +} + +static int n8x0_mmc_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + if (machine_is_nokia_n800() || slot == 0) + return n8x0_mmc_set_power_menelaus(dev, slot, power_on, vdd); + + n810_set_power_emmc(dev, power_on); + + return 0; +} + +static int n8x0_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode) +{ + int r; + + dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1, + bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull"); + BUG_ON(slot != 0 && slot != 1); + slot++; + switch (bus_mode) { + case MMC_BUSMODE_OPENDRAIN: + r = menelaus_set_mmc_opendrain(slot, 1); + break; + case MMC_BUSMODE_PUSHPULL: + r = menelaus_set_mmc_opendrain(slot, 0); + break; + default: + BUG(); + } + if (r != 0 && printk_ratelimit()) + dev_err(dev, "MMC: unable to set bus mode for slot %d\n", + slot); + return r; +} + +static int n8x0_mmc_get_cover_state(struct device *dev, int slot) +{ + slot++; + BUG_ON(slot != 1 && slot != 2); + if (slot == 1) + return slot1_cover_open; + else + return slot2_cover_open; +} + +static void n8x0_mmc_callback(void *data, u8 card_mask) +{ + int bit, *openp, index; + + if (machine_is_nokia_n800()) { + bit = 1 << 1; + openp = &slot2_cover_open; + index = 1; + } else { + bit = 1; + openp = &slot1_cover_open; + index = 0; + } + + if (card_mask & bit) + *openp = 1; + else + *openp = 0; + +#ifdef CONFIG_MMC_OMAP + omap_mmc_notify_cover_event(mmc_device, index, *openp); +#else + pr_warn("MMC: notify cover event not available\n"); +#endif +} + +static int n8x0_mmc_late_init(struct device *dev) +{ + int r, bit, *openp; + int vs2sel; + + mmc_device = dev; + + r = menelaus_set_slot_sel(1); + if (r < 0) + return r; + + if (machine_is_nokia_n800()) + vs2sel = 0; + else + vs2sel = 2; + + r = menelaus_set_mmc_slot(2, 0, vs2sel, 1); + if (r < 0) + return r; + + n8x0_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */ + n8x0_mmc_set_power(dev, 1, MMC_POWER_ON, 16); + + r = menelaus_set_mmc_slot(1, 1, 0, 1); + if (r < 0) + return r; + r = menelaus_set_mmc_slot(2, 1, vs2sel, 1); + if (r < 0) + return r; + + r = menelaus_get_slot_pin_states(); + if (r < 0) + return r; + + if (machine_is_nokia_n800()) { + bit = 1 << 1; + openp = &slot2_cover_open; + } else { + bit = 1; + openp = &slot1_cover_open; + slot2_cover_open = 0; + } + + /* All slot pin bits seem to be inversed until first switch change */ + if (r == 0xf || r == (0xf & ~bit)) + r = ~r; + + if (r & bit) + *openp = 1; + else + *openp = 0; + + r = menelaus_register_mmc_callback(n8x0_mmc_callback, NULL); + + return r; +} + +static void n8x0_mmc_shutdown(struct device *dev) +{ + int vs2sel; + + if (machine_is_nokia_n800()) + vs2sel = 0; + else + vs2sel = 2; + + menelaus_set_mmc_slot(1, 0, 0, 0); + menelaus_set_mmc_slot(2, 0, vs2sel, 0); +} + +static void n8x0_mmc_cleanup(struct device *dev) +{ + menelaus_unregister_mmc_callback(); + + gpio_free(N8X0_SLOT_SWITCH_GPIO); + + if (machine_is_nokia_n810()) { + gpio_free(N810_EMMC_VSD_GPIO); + gpio_free(N810_EMMC_VIO_GPIO); + } +} + +/* + * MMC controller1 has two slots that are multiplexed via I2C. + * MMC controller2 is not in use. + */ +static struct omap_mmc_platform_data mmc1_data = { + .nr_slots = 2, + .switch_slot = n8x0_mmc_switch_slot, + .init = n8x0_mmc_late_init, + .cleanup = n8x0_mmc_cleanup, + .shutdown = n8x0_mmc_shutdown, + .max_freq = 24000000, + .dma_mask = 0xffffffff, + .slots[0] = { + .wires = 4, + .set_power = n8x0_mmc_set_power, + .set_bus_mode = n8x0_mmc_set_bus_mode, + .get_cover_state = n8x0_mmc_get_cover_state, + .ocr_mask = MMC_VDD_165_195 | MMC_VDD_30_31 | + MMC_VDD_32_33 | MMC_VDD_33_34, + .name = "internal", + }, + .slots[1] = { + .set_power = n8x0_mmc_set_power, + .set_bus_mode = n8x0_mmc_set_bus_mode, + .get_cover_state = n8x0_mmc_get_cover_state, + .ocr_mask = MMC_VDD_165_195 | MMC_VDD_20_21 | + MMC_VDD_21_22 | MMC_VDD_22_23 | + MMC_VDD_23_24 | MMC_VDD_24_25 | + MMC_VDD_27_28 | MMC_VDD_28_29 | + MMC_VDD_29_30 | MMC_VDD_30_31 | + MMC_VDD_32_33 | MMC_VDD_33_34, + .name = "external", + }, +}; + +static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC]; + +static struct gpio n810_emmc_gpios[] __initdata = { + { N810_EMMC_VSD_GPIO, GPIOF_OUT_INIT_LOW, "MMC slot 2 Vddf" }, + { N810_EMMC_VIO_GPIO, GPIOF_OUT_INIT_LOW, "MMC slot 2 Vdd" }, +}; + +static void __init n8x0_mmc_init(void) +{ + int err; + + if (machine_is_nokia_n810()) { + mmc1_data.slots[0].name = "external"; + + /* + * Some Samsung Movinand chips do not like open-ended + * multi-block reads and fall to braind-dead state + * while doing so. Reducing the number of blocks in + * the transfer or delays in clock disable do not help + */ + mmc1_data.slots[1].name = "internal"; + mmc1_data.slots[1].ban_openended = 1; + } + + err = gpio_request_one(N8X0_SLOT_SWITCH_GPIO, GPIOF_OUT_INIT_LOW, + "MMC slot switch"); + if (err) + return; + + if (machine_is_nokia_n810()) { + err = gpio_request_array(n810_emmc_gpios, + ARRAY_SIZE(n810_emmc_gpios)); + if (err) { + gpio_free(N8X0_SLOT_SWITCH_GPIO); + return; + } + } + + mmc_data[0] = &mmc1_data; + omap242x_init_mmc(mmc_data); +} +#else + +void __init n8x0_mmc_init(void) +{ +} +#endif /* CONFIG_MMC_OMAP */ + +#ifdef CONFIG_MENELAUS + +static int n8x0_auto_sleep_regulators(void) +{ + u32 val; + int ret; + + val = EN_VPLL_SLEEP | EN_VMMC_SLEEP \ + | EN_VAUX_SLEEP | EN_VIO_SLEEP \ + | EN_VMEM_SLEEP | EN_DC3_SLEEP \ + | EN_VC_SLEEP | EN_DC2_SLEEP; + + ret = menelaus_set_regulator_sleep(1, val); + if (ret < 0) { + printk(KERN_ERR "Could not set regulators to sleep on " + "menelaus: %u\n", ret); + return ret; + } + return 0; +} + +static int n8x0_auto_voltage_scale(void) +{ + int ret; + + ret = menelaus_set_vcore_hw(1400, 1050); + if (ret < 0) { + printk(KERN_ERR "Could not set VCORE voltage on " + "menelaus: %u\n", ret); + return ret; + } + return 0; +} + +static int n8x0_menelaus_late_init(struct device *dev) +{ + int ret; + + ret = n8x0_auto_voltage_scale(); + if (ret < 0) + return ret; + ret = n8x0_auto_sleep_regulators(); + if (ret < 0) + return ret; + return 0; +} + +#else +static int n8x0_menelaus_late_init(struct device *dev) +{ + return 0; +} +#endif + +static struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = { + .late_init = n8x0_menelaus_late_init, +}; + +static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] __initdata = { + { + I2C_BOARD_INFO("menelaus", 0x72), + .irq = INT_24XX_SYS_NIRQ, + .platform_data = &n8x0_menelaus_platform_data, + }, +}; + +static struct aic3x_pdata n810_aic33_data __initdata = { + .gpio_reset = 118, +}; + +static struct i2c_board_info n810_i2c_board_info_2[] __initdata = { + { + I2C_BOARD_INFO("tlv320aic3x", 0x18), + .platform_data = &n810_aic33_data, + }, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* I2S codec port pins for McBSP block */ + OMAP2420_MUX(EAC_AC_SCLK, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP2420_MUX(EAC_AC_FS, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP2420_MUX(EAC_AC_DIN, OMAP_MUX_MODE1 | OMAP_PIN_INPUT), + OMAP2420_MUX(EAC_AC_DOUT, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +static struct omap_device_pad serial2_pads[] __initdata = { + { + .name = "uart3_rx_irrx.uart3_rx_irrx", + .flags = OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP, + .enable = OMAP_MUX_MODE0, + .idle = OMAP_MUX_MODE3 /* Mux as GPIO for idle */ + }, +}; + +static inline void board_serial_init(void) +{ + struct omap_board_data bdata; + + bdata.flags = 0; + bdata.pads = NULL; + bdata.pads_cnt = 0; + + bdata.id = 0; + omap_serial_init_port(&bdata, NULL); + + bdata.id = 1; + omap_serial_init_port(&bdata, NULL); + + bdata.id = 2; + bdata.pads = serial2_pads; + bdata.pads_cnt = ARRAY_SIZE(serial2_pads); + omap_serial_init_port(&bdata, NULL); +} + +#else + +static inline void board_serial_init(void) +{ + omap_serial_init(); +} + +#endif + +static void __init n8x0_init_machine(void) +{ + omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC); + /* FIXME: add n810 spi devices */ + spi_register_board_info(n800_spi_board_info, + ARRAY_SIZE(n800_spi_board_info)); + omap_register_i2c_bus(1, 400, n8x0_i2c_board_info_1, + ARRAY_SIZE(n8x0_i2c_board_info_1)); + omap_register_i2c_bus(2, 400, NULL, 0); + if (machine_is_nokia_n810()) + i2c_register_board_info(2, n810_i2c_board_info_2, + ARRAY_SIZE(n810_i2c_board_info_2)); + board_serial_init(); + omap_sdrc_init(NULL, NULL); + gpmc_onenand_init(board_onenand_data); + n8x0_mmc_init(); + n8x0_usb_init(); +} + +MACHINE_START(NOKIA_N800, "Nokia N800") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap242x_map_io, + .init_early = omap2420_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = n8x0_init_machine, + .timer = &omap2_timer, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(NOKIA_N810, "Nokia N810") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap242x_map_io, + .init_early = omap2420_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = n8x0_init_machine, + .timer = &omap2_timer, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(NOKIA_N810_WIMAX, "Nokia N810 WiMAX") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap242x_map_io, + .init_early = omap2420_init_early, + .init_irq = omap2_init_irq, + .handle_irq = omap2_intc_handle_irq, + .init_machine = n8x0_init_machine, + .timer = &omap2_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c new file mode 100644 index 00000000000..7ffcd2839e7 --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -0,0 +1,566 @@ +/* + * linux/arch/arm/mach-omap2/board-omap3beagle.c + * + * Copyright (C) 2008 Texas Instruments + * + * Modified from mach-omap2/board-3430sdp.c + * + * Initial code: Syed Mohammed Khasim + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/opp.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> +#include <linux/mmc/host.h> + +#include <linux/regulator/machine.h> +#include <linux/i2c/twl.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> + +#include <plat/board.h> +#include "common.h" +#include <video/omapdss.h> +#include <video/omap-panel-dvi.h> +#include <plat/gpmc.h> +#include <plat/nand.h> +#include <plat/usb.h> +#include <plat/omap_device.h> + +#include "mux.h" +#include "hsmmc.h" +#include "pm.h" +#include "common-board-devices.h" + +/* + * OMAP3 Beagle revision + * Run time detection of Beagle revision is done by reading GPIO. + * GPIO ID - + * AXBX = GPIO173, GPIO172, GPIO171: 1 1 1 + * C1_3 = GPIO173, GPIO172, GPIO171: 1 1 0 + * C4 = GPIO173, GPIO172, GPIO171: 1 0 1 + * XMA/XMB = GPIO173, GPIO172, GPIO171: 0 0 0 + * XMC = GPIO173, GPIO172, GPIO171: 0 1 0 + */ +enum { + OMAP3BEAGLE_BOARD_UNKN = 0, + OMAP3BEAGLE_BOARD_AXBX, + OMAP3BEAGLE_BOARD_C1_3, + OMAP3BEAGLE_BOARD_C4, + OMAP3BEAGLE_BOARD_XM, + OMAP3BEAGLE_BOARD_XMC, +}; + +static u8 omap3_beagle_version; + +/* + * Board-specific configuration + * Defaults to BeagleBoard-xMC + */ +static struct { + int mmc1_gpio_wp; + int usb_pwr_level; + int reset_gpio; + int usr_button_gpio; +} beagle_config = { + .mmc1_gpio_wp = -EINVAL, + .usb_pwr_level = GPIOF_OUT_INIT_LOW, + .reset_gpio = 129, + .usr_button_gpio = 4, +}; + +static struct gpio omap3_beagle_rev_gpios[] __initdata = { + { 171, GPIOF_IN, "rev_id_0" }, + { 172, GPIOF_IN, "rev_id_1" }, + { 173, GPIOF_IN, "rev_id_2" }, +}; + +static void __init omap3_beagle_init_rev(void) +{ + int ret; + u16 beagle_rev = 0; + + omap_mux_init_gpio(171, OMAP_PIN_INPUT_PULLUP); + omap_mux_init_gpio(172, OMAP_PIN_INPUT_PULLUP); + omap_mux_init_gpio(173, OMAP_PIN_INPUT_PULLUP); + + ret = gpio_request_array(omap3_beagle_rev_gpios, + ARRAY_SIZE(omap3_beagle_rev_gpios)); + if (ret < 0) { + printk(KERN_ERR "Unable to get revision detection GPIO pins\n"); + omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN; + return; + } + + beagle_rev = gpio_get_value(171) | (gpio_get_value(172) << 1) + | (gpio_get_value(173) << 2); + + gpio_free_array(omap3_beagle_rev_gpios, + ARRAY_SIZE(omap3_beagle_rev_gpios)); + + switch (beagle_rev) { + case 7: + printk(KERN_INFO "OMAP3 Beagle Rev: Ax/Bx\n"); + omap3_beagle_version = OMAP3BEAGLE_BOARD_AXBX; + beagle_config.mmc1_gpio_wp = 29; + beagle_config.reset_gpio = 170; + beagle_config.usr_button_gpio = 7; + break; + case 6: + printk(KERN_INFO "OMAP3 Beagle Rev: C1/C2/C3\n"); + omap3_beagle_version = OMAP3BEAGLE_BOARD_C1_3; + beagle_config.mmc1_gpio_wp = 23; + beagle_config.reset_gpio = 170; + beagle_config.usr_button_gpio = 7; + break; + case 5: + printk(KERN_INFO "OMAP3 Beagle Rev: C4\n"); + omap3_beagle_version = OMAP3BEAGLE_BOARD_C4; + beagle_config.mmc1_gpio_wp = 23; + beagle_config.reset_gpio = 170; + beagle_config.usr_button_gpio = 7; + break; + case 0: + printk(KERN_INFO "OMAP3 Beagle Rev: xM Ax/Bx\n"); + omap3_beagle_version = OMAP3BEAGLE_BOARD_XM; + beagle_config.usb_pwr_level = GPIOF_OUT_INIT_HIGH; + break; + case 2: + printk(KERN_INFO "OMAP3 Beagle Rev: xM C\n"); + omap3_beagle_version = OMAP3BEAGLE_BOARD_XMC; + break; + default: + printk(KERN_INFO "OMAP3 Beagle Rev: unknown %hd\n", beagle_rev); + omap3_beagle_version = OMAP3BEAGLE_BOARD_UNKN; + } +} + +static struct mtd_partition omap3beagle_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader", + .offset = 0, + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 15 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot Env", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */ + .size = 1 * NAND_BLOCK_SIZE, + }, + { + .name = "Kernel", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 32 * NAND_BLOCK_SIZE, + }, + { + .name = "File System", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */ + .size = MTDPART_SIZ_FULL, + }, +}; + +/* DSS */ + +static int beagle_enable_dvi(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(dssdev->reset_gpio)) + gpio_set_value(dssdev->reset_gpio, 1); + + return 0; +} + +static void beagle_disable_dvi(struct omap_dss_device *dssdev) +{ + if (gpio_is_valid(dssdev->reset_gpio)) + gpio_set_value(dssdev->reset_gpio, 0); +} + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = beagle_enable_dvi, + .platform_disable = beagle_disable_dvi, + .i2c_bus_num = 3, +}; + +static struct omap_dss_device beagle_dvi_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "dvi", + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, + .reset_gpio = -EINVAL, +}; + +static struct omap_dss_device beagle_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, +}; + +static struct omap_dss_device *beagle_dss_devices[] = { + &beagle_dvi_device, + &beagle_tv_device, +}; + +static struct omap_dss_board_info beagle_dss_data = { + .num_devices = ARRAY_SIZE(beagle_dss_devices), + .devices = beagle_dss_devices, + .default_device = &beagle_dvi_device, +}; + +static void __init beagle_display_init(void) +{ + int r; + + r = gpio_request_one(beagle_dvi_device.reset_gpio, GPIOF_OUT_INIT_LOW, + "DVI reset"); + if (r < 0) + printk(KERN_ERR "Unable to get DVI reset GPIO\n"); +} + +#include "sdram-micron-mt46h32m32lf-6.h" + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply beagle_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply beagle_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +static struct gpio_led gpio_leds[]; + +static int beagle_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + int r; + + if (beagle_config.mmc1_gpio_wp != -EINVAL) + omap_mux_init_gpio(beagle_config.mmc1_gpio_wp, OMAP_PIN_INPUT); + mmc[0].gpio_wp = beagle_config.mmc1_gpio_wp; + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + /* + * TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, XM active + * high / others active low) + * DVI reset GPIO is different between beagle revisions + */ + /* Valid for all -xM revisions */ + if (cpu_is_omap3630()) { + /* + * gpio + 1 on Xm controls the TFP410's enable line (active low) + * gpio + 2 control varies depending on the board rev as below: + * P7/P8 revisions(prototype): Camera EN + * A2+ revisions (production): LDO (DVI, serial, led blocks) + */ + r = gpio_request_one(gpio + 1, GPIOF_OUT_INIT_LOW, + "nDVI_PWR_EN"); + if (r) + pr_err("%s: unable to configure nDVI_PWR_EN\n", + __func__); + r = gpio_request_one(gpio + 2, GPIOF_OUT_INIT_HIGH, + "DVI_LDO_EN"); + if (r) + pr_err("%s: unable to configure DVI_LDO_EN\n", + __func__); + } else { + /* + * REVISIT: need ehci-omap hooks for external VBUS + * power switch and overcurrent detect + */ + if (gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC")) + pr_err("%s: unable to configure EHCI_nOC\n", __func__); + } + beagle_dvi_device.reset_gpio = beagle_config.reset_gpio; + + gpio_request_one(gpio + TWL4030_GPIO_MAX, beagle_config.usb_pwr_level, + "nEN_USB_PWR"); + + /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + + return 0; +} + +static struct twl4030_gpio_platform_data beagle_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .pullups = BIT(1), + .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13) + | BIT(15) | BIT(16) | BIT(17), + .setup = beagle_twl_gpio_setup, +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data beagle_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(beagle_vmmc1_supply), + .consumer_supplies = beagle_vmmc1_supply, +}; + +/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */ +static struct regulator_init_data beagle_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(beagle_vsim_supply), + .consumer_supplies = beagle_vsim_supply, +}; + +static struct twl4030_platform_data beagle_twldata = { + /* platform_data for children goes here */ + .gpio = &beagle_gpio_data, + .vmmc1 = &beagle_vmmc1, + .vsim = &beagle_vsim, +}; + +static struct i2c_board_info __initdata beagle_i2c_eeprom[] = { + { + I2C_BOARD_INFO("eeprom", 0x50), + }, +}; + +static int __init omap3_beagle_i2c_init(void) +{ + omap3_pmic_get_config(&beagle_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC | + TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + beagle_twldata.vpll2->constraints.name = "VDVI"; + + omap3_pmic_init("twl4030", &beagle_twldata); + /* Bus 3 is attached to the DVI port where devices like the pico DLP + * projector don't work reliably with 400kHz */ + omap_register_i2c_bus(3, 100, beagle_i2c_eeprom, ARRAY_SIZE(beagle_i2c_eeprom)); + return 0; +} + +static struct gpio_led gpio_leds[] = { + { + .name = "beagleboard::usr0", + .default_trigger = "heartbeat", + .gpio = 150, + }, + { + .name = "beagleboard::usr1", + .default_trigger = "mmc0", + .gpio = 149, + }, + { + .name = "beagleboard::pmu_stat", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + }, +}; + +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 gpio_keys_button gpio_buttons[] = { + { + .code = BTN_EXTRA, + /* Dynamically assigned depending on board */ + .gpio = -EINVAL, + .desc = "user", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + +static struct platform_device madc_hwmon = { + .name = "twl4030_madc_hwmon", + .id = -1, +}; + +static struct platform_device *omap3_beagle_devices[] __initdata = { + &leds_gpio, + &keys_gpio, + &madc_hwmon, +}; + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = 147, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init beagle_opp_init(void) +{ + int r = 0; + + /* Initialize the omap3 opp table */ + if (omap3_opp_init()) { + pr_err("%s: opp default init failed\n", __func__); + return; + } + + /* Custom OPP enabled for all xM versions */ + if (cpu_is_omap3630()) { + struct device *mpu_dev, *iva_dev; + + mpu_dev = omap_device_get_by_hwmod_name("mpu"); + iva_dev = omap_device_get_by_hwmod_name("iva"); + + if (!mpu_dev || !iva_dev) { + pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n", + __func__, mpu_dev, iva_dev); + return; + } + /* Enable MPU 1GHz and lower opps */ + r = opp_enable(mpu_dev, 800000000); + /* TODO: MPU 1GHz needs SR and ABB */ + + /* Enable IVA 800MHz and lower opps */ + r |= opp_enable(iva_dev, 660000000); + /* TODO: DSP 800MHz needs SR and ABB */ + if (r) { + pr_err("%s: failed to enable higher opp %d\n", + __func__, r); + /* + * Cleanup - disable the higher freqs - we dont care + * about the results + */ + opp_disable(mpu_dev, 800000000); + opp_disable(iva_dev, 660000000); + } + } + return; +} + +static void __init omap3_beagle_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap3_beagle_init_rev(); + omap3_beagle_i2c_init(); + + gpio_buttons[0].gpio = beagle_config.usr_button_gpio; + + platform_add_devices(omap3_beagle_devices, + ARRAY_SIZE(omap3_beagle_devices)); + omap_display_init(&beagle_dss_data); + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + + omap_mux_init_gpio(170, OMAP_PIN_INPUT); + /* REVISIT leave DVI powered down until it's needed ... */ + gpio_request_one(170, GPIOF_OUT_INIT_HIGH, "DVI_nPD"); + + usb_musb_init(NULL); + usbhs_init(&usbhs_bdata); + omap_nand_flash_init(NAND_BUSWIDTH_16, omap3beagle_nand_partitions, + ARRAY_SIZE(omap3beagle_nand_partitions)); + + /* Ensure msecure is mux'd to be able to set the RTC. */ + omap_mux_init_signal("sys_drm_msecure", OMAP_PIN_OFF_OUTPUT_HIGH); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); + + beagle_display_init(); + beagle_opp_init(); +} + +MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board") + /* Maintainer: Syed Mohammed Khasim - http://beagleboard.org */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3_beagle_init, + .timer = &omap3_secure_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c new file mode 100644 index 00000000000..c877236a844 --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3evm.c @@ -0,0 +1,697 @@ +/* + * linux/arch/arm/mach-omap2/board-omap3evm.c + * + * Copyright (C) 2008 Texas Instruments + * + * Modified from mach-omap2/board-3430sdp.c + * + * Initial code: Syed Mohammed Khasim + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/leds.h> +#include <linux/interrupt.h> + +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/i2c/twl.h> +#include <linux/usb/otg.h> +#include <linux/smsc911x.h> + +#include <linux/wl12xx.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> +#include <linux/mmc/host.h> +#include <linux/export.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include <plat/usb.h> +#include "common.h" +#include <plat/mcspi.h> +#include <video/omapdss.h> +#include <video/omap-panel-dvi.h> + +#include "mux.h" +#include "sdram-micron-mt46h32m32lf-6.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define OMAP3_EVM_TS_GPIO 175 +#define OMAP3_EVM_EHCI_VBUS 22 +#define OMAP3_EVM_EHCI_SELECT 61 + +#define OMAP3EVM_ETHR_START 0x2c000000 +#define OMAP3EVM_ETHR_SIZE 1024 +#define OMAP3EVM_ETHR_ID_REV 0x50 +#define OMAP3EVM_ETHR_GPIO_IRQ 176 +#define OMAP3EVM_SMSC911X_CS 5 +/* + * Eth Reset signal + * 64 = Generation 1 (<=RevD) + * 7 = Generation 2 (>=RevE) + */ +#define OMAP3EVM_GEN1_ETHR_GPIO_RST 64 +#define OMAP3EVM_GEN2_ETHR_GPIO_RST 7 + +static u8 omap3_evm_version; + +u8 get_omap3_evm_rev(void) +{ + return omap3_evm_version; +} +EXPORT_SYMBOL(get_omap3_evm_rev); + +static void __init omap3_evm_get_revision(void) +{ + void __iomem *ioaddr; + unsigned int smsc_id; + + /* Ethernet PHY ID is stored at ID_REV register */ + ioaddr = ioremap_nocache(OMAP3EVM_ETHR_START, SZ_1K); + if (!ioaddr) + return; + smsc_id = readl(ioaddr + OMAP3EVM_ETHR_ID_REV) & 0xFFFF0000; + iounmap(ioaddr); + + switch (smsc_id) { + /*SMSC9115 chipset*/ + case 0x01150000: + omap3_evm_version = OMAP3EVM_BOARD_GEN_1; + break; + /*SMSC 9220 chipset*/ + case 0x92200000: + default: + omap3_evm_version = OMAP3EVM_BOARD_GEN_2; + } +} + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +#include <plat/gpmc-smsc911x.h> + +static struct omap_smsc911x_platform_data smsc911x_cfg = { + .cs = OMAP3EVM_SMSC911X_CS, + .gpio_irq = OMAP3EVM_ETHR_GPIO_IRQ, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS, +}; + +static inline void __init omap3evm_init_smsc911x(void) +{ + struct clk *l3ck; + unsigned int rate; + + l3ck = clk_get(NULL, "l3_ck"); + if (IS_ERR(l3ck)) + rate = 100000000; + else + rate = clk_get_rate(l3ck); + + /* Configure ethernet controller reset gpio */ + if (cpu_is_omap3430()) { + if (get_omap3_evm_rev() == OMAP3EVM_BOARD_GEN_1) + smsc911x_cfg.gpio_reset = OMAP3EVM_GEN1_ETHR_GPIO_RST; + else + smsc911x_cfg.gpio_reset = OMAP3EVM_GEN2_ETHR_GPIO_RST; + } + + gpmc_smsc911x_init(&smsc911x_cfg); +} + +#else +static inline void __init omap3evm_init_smsc911x(void) { return; } +#endif + +/* + * OMAP3EVM LCD Panel control signals + */ +#define OMAP3EVM_LCD_PANEL_LR 2 +#define OMAP3EVM_LCD_PANEL_UD 3 +#define OMAP3EVM_LCD_PANEL_INI 152 +#define OMAP3EVM_LCD_PANEL_ENVDD 153 +#define OMAP3EVM_LCD_PANEL_QVGA 154 +#define OMAP3EVM_LCD_PANEL_RESB 155 +#define OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO 210 +#define OMAP3EVM_DVI_PANEL_EN_GPIO 199 + +static struct gpio omap3_evm_dss_gpios[] __initdata = { + { OMAP3EVM_LCD_PANEL_RESB, GPIOF_OUT_INIT_HIGH, "lcd_panel_resb" }, + { OMAP3EVM_LCD_PANEL_INI, GPIOF_OUT_INIT_HIGH, "lcd_panel_ini" }, + { OMAP3EVM_LCD_PANEL_QVGA, GPIOF_OUT_INIT_LOW, "lcd_panel_qvga" }, + { OMAP3EVM_LCD_PANEL_LR, GPIOF_OUT_INIT_HIGH, "lcd_panel_lr" }, + { OMAP3EVM_LCD_PANEL_UD, GPIOF_OUT_INIT_HIGH, "lcd_panel_ud" }, + { OMAP3EVM_LCD_PANEL_ENVDD, GPIOF_OUT_INIT_LOW, "lcd_panel_envdd" }, +}; + +static int lcd_enabled; +static int dvi_enabled; + +static void __init omap3_evm_display_init(void) +{ + int r; + + r = gpio_request_array(omap3_evm_dss_gpios, + ARRAY_SIZE(omap3_evm_dss_gpios)); + if (r) + printk(KERN_ERR "failed to get lcd_panel_* gpios\n"); +} + +static int omap3_evm_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 0); + + if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) + gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0); + else + gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1); + + lcd_enabled = 1; + return 0; +} + +static void omap3_evm_disable_lcd(struct omap_dss_device *dssdev) +{ + gpio_set_value(OMAP3EVM_LCD_PANEL_ENVDD, 1); + + if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) + gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 1); + else + gpio_set_value_cansleep(OMAP3EVM_LCD_PANEL_BKLIGHT_GPIO, 0); + + lcd_enabled = 0; +} + +static struct omap_dss_device omap3_evm_lcd_device = { + .name = "lcd", + .driver_name = "sharp_ls_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 18, + .platform_enable = omap3_evm_enable_lcd, + .platform_disable = omap3_evm_disable_lcd, +}; + +static int omap3_evm_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void omap3_evm_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct omap_dss_device omap3_evm_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, + .platform_enable = omap3_evm_enable_tv, + .platform_disable = omap3_evm_disable_tv, +}; + +static int omap3_evm_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + + gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 1); + + dvi_enabled = 1; + return 0; +} + +static void omap3_evm_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value_cansleep(OMAP3EVM_DVI_PANEL_EN_GPIO, 0); + + dvi_enabled = 0; +} + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = omap3_evm_enable_dvi, + .platform_disable = omap3_evm_disable_dvi, +}; + +static struct omap_dss_device omap3_evm_dvi_device = { + .name = "dvi", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device *omap3_evm_dss_devices[] = { + &omap3_evm_lcd_device, + &omap3_evm_tv_device, + &omap3_evm_dvi_device, +}; + +static struct omap_dss_board_info omap3_evm_dss_data = { + .num_devices = ARRAY_SIZE(omap3_evm_dss_devices), + .devices = omap3_evm_dss_devices, + .default_device = &omap3_evm_lcd_device, +}; + +static struct regulator_consumer_supply omap3evm_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply omap3evm_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data omap3evm_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3evm_vmmc1_supply), + .consumer_supplies = omap3evm_vmmc1_supply, +}; + +/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */ +static struct regulator_init_data omap3evm_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3evm_vsim_supply), + .consumer_supplies = omap3evm_vsim_supply, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = 63, + }, +#ifdef CONFIG_WL12XX_PLATFORM_DATA + { + .name = "wl1271", + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD, + .gpio_wp = -EINVAL, + .gpio_cd = -EINVAL, + .nonremovable = true, + }, +#endif + {} /* Terminator */ +}; + +static struct gpio_led gpio_leds[] = { + { + .name = "omap3evm::ledb", + /* normally not visible (board underside) */ + .default_trigger = "default-on", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + }, +}; + +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 int omap3evm_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + int r, lcd_bl_en; + + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + omap_mux_init_gpio(63, OMAP_PIN_INPUT); + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + /* + * Most GPIOs are for USB OTG. Some are mostly sent to + * the P2 connector; notably LEDA for the LCD backlight. + */ + + /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */ + lcd_bl_en = get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2 ? + GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + r = gpio_request_one(gpio + TWL4030_GPIO_MAX, lcd_bl_en, "EN_LCD_BKL"); + if (r) + printk(KERN_ERR "failed to get/set lcd_bkl gpio\n"); + + /* gpio + 7 == DVI Enable */ + gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI"); + + /* TWL4030_GPIO_MAX + 1 == ledB (out, active low LED) */ + gpio_leds[0].gpio = gpio + TWL4030_GPIO_MAX + 1; + + platform_device_register(&leds_gpio); + + return 0; +} + +static struct twl4030_gpio_platform_data omap3evm_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .setup = omap3evm_twl_gpio_setup, +}; + +static uint32_t board_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_DOWN), + KEY(0, 2, KEY_ENTER), + KEY(0, 3, KEY_M), + + KEY(1, 0, KEY_RIGHT), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_I), + KEY(1, 3, KEY_N), + + KEY(2, 0, KEY_A), + KEY(2, 1, KEY_E), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_O), + + KEY(3, 0, KEY_B), + KEY(3, 1, KEY_F), + KEY(3, 2, KEY_K), + KEY(3, 3, KEY_P) +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data omap3evm_kp_data = { + .keymap_data = &board_map_data, + .rows = 4, + .cols = 4, + .rep = 1, +}; + +/* ads7846 on SPI */ +static struct regulator_consumer_supply omap3evm_vio_supply[] = { + REGULATOR_SUPPLY("vcc", "spi1.0"), +}; + +/* VIO for ads7846 */ +static struct regulator_init_data omap3evm_vio = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3evm_vio_supply), + .consumer_supplies = omap3evm_vio_supply, +}; + +#ifdef CONFIG_WL12XX_PLATFORM_DATA + +#define OMAP3EVM_WLAN_PMENA_GPIO (150) +#define OMAP3EVM_WLAN_IRQ_GPIO (149) + +static struct regulator_consumer_supply omap3evm_vmmc2_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +/* VMMC2 for driving the WL12xx module */ +static struct regulator_init_data omap3evm_vmmc2 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3evm_vmmc2_supply), + .consumer_supplies = omap3evm_vmmc2_supply, +}; + +static struct fixed_voltage_config omap3evm_vwlan = { + .supply_name = "vwl1271", + .microvolts = 1800000, /* 1.80V */ + .gpio = OMAP3EVM_WLAN_PMENA_GPIO, + .startup_delay = 70000, /* 70ms */ + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &omap3evm_vmmc2, +}; + +static struct platform_device omap3evm_wlan_regulator = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &omap3evm_vwlan, + }, +}; + +struct wl12xx_platform_data omap3evm_wlan_data __initdata = { + .irq = OMAP_GPIO_IRQ(OMAP3EVM_WLAN_IRQ_GPIO), + .board_ref_clock = WL12XX_REFCLOCK_38, /* 38.4 MHz */ +}; +#endif + +static struct twl4030_platform_data omap3evm_twldata = { + /* platform_data for children goes here */ + .keypad = &omap3evm_kp_data, + .gpio = &omap3evm_gpio_data, + .vio = &omap3evm_vio, + .vmmc1 = &omap3evm_vmmc1, + .vsim = &omap3evm_vsim, +}; + +static int __init omap3_evm_i2c_init(void) +{ + omap3_pmic_get_config(&omap3evm_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC | + TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + omap3evm_twldata.vdac->constraints.apply_uV = true; + omap3evm_twldata.vpll2->constraints.apply_uV = true; + + omap3_pmic_init("twl4030", &omap3evm_twldata); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static struct omap_board_config_kernel omap3_evm_config[] __initdata = { +}; + +static struct usbhs_omap_board_data usbhs_bdata __initdata = { + + .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + /* PHY reset GPIO will be runtime programmed based on EVM version */ + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux omap35x_board_mux[] __initdata = { + OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW | + OMAP_PIN_OFF_WAKEUPENABLE), + OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW | + OMAP_PIN_OFF_WAKEUPENABLE), + OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_NONE), + OMAP3_MUX(GPMC_WAIT2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_NONE), +#ifdef CONFIG_WL12XX_PLATFORM_DATA + /* WLAN IRQ - GPIO 149 */ + OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + + /* WLAN POWER ENABLE - GPIO 150 */ + OMAP3_MUX(UART1_CTS, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + /* MMC2 SDIO pin muxes for WL12xx */ + OMAP3_MUX(SDMMC2_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), +#endif + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +static struct omap_board_mux omap36x_board_mux[] __initdata = { + OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW | + OMAP_PIN_OFF_WAKEUPENABLE), + OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_OUTPUT_LOW | + OMAP_PIN_OFF_WAKEUPENABLE), + /* AM/DM37x EVM: DSS data bus muxed with sys_boot */ + OMAP3_MUX(DSS_DATA18, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(DSS_DATA19, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(DSS_DATA21, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(DSS_DATA22, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(DSS_DATA23, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(SYS_BOOT0, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(SYS_BOOT1, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(SYS_BOOT3, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(SYS_BOOT4, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(SYS_BOOT5, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), + OMAP3_MUX(SYS_BOOT6, OMAP_MUX_MODE3 | OMAP_PIN_OFF_NONE), +#ifdef CONFIG_WL12XX_PLATFORM_DATA + /* WLAN IRQ - GPIO 149 */ + OMAP3_MUX(UART1_RTS, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + + /* WLAN POWER ENABLE - GPIO 150 */ + OMAP3_MUX(UART1_CTS, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + + /* MMC2 SDIO pin muxes for WL12xx */ + OMAP3_MUX(SDMMC2_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(SDMMC2_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), +#endif + + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#else +#define omap35x_board_mux NULL +#define omap36x_board_mux NULL +#endif + +static struct omap_musb_board_data musb_board_data = { + .interface_type = MUSB_INTERFACE_ULPI, + .mode = MUSB_OTG, + .power = 100, +}; + +static struct gpio omap3_evm_ehci_gpios[] __initdata = { + { OMAP3_EVM_EHCI_VBUS, GPIOF_OUT_INIT_HIGH, "enable EHCI VBUS" }, + { OMAP3_EVM_EHCI_SELECT, GPIOF_OUT_INIT_LOW, "select EHCI port" }, +}; + +static void __init omap3_evm_wl12xx_init(void) +{ +#ifdef CONFIG_WL12XX_PLATFORM_DATA + int ret; + + /* WL12xx WLAN Init */ + ret = wl12xx_set_platform_data(&omap3evm_wlan_data); + if (ret) + pr_err("error setting wl12xx data: %d\n", ret); + ret = platform_device_register(&omap3evm_wlan_regulator); + if (ret) + pr_err("error registering wl12xx device: %d\n", ret); +#endif +} + +static void __init omap3_evm_init(void) +{ + omap3_evm_get_revision(); + + if (cpu_is_omap3630()) + omap3_mux_init(omap36x_board_mux, OMAP_PACKAGE_CBB); + else + omap3_mux_init(omap35x_board_mux, OMAP_PACKAGE_CBB); + + omap_board_config = omap3_evm_config; + omap_board_config_size = ARRAY_SIZE(omap3_evm_config); + + omap3_evm_i2c_init(); + + omap_display_init(&omap3_evm_dss_data); + + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL); + + /* OMAP3EVM uses ISP1504 phy and so register nop transceiver */ + usb_nop_xceiv_register(); + + if (get_omap3_evm_rev() >= OMAP3EVM_BOARD_GEN_2) { + /* enable EHCI VBUS using GPIO22 */ + omap_mux_init_gpio(OMAP3_EVM_EHCI_VBUS, OMAP_PIN_INPUT_PULLUP); + /* Select EHCI port on main board */ + omap_mux_init_gpio(OMAP3_EVM_EHCI_SELECT, + OMAP_PIN_INPUT_PULLUP); + gpio_request_array(omap3_evm_ehci_gpios, + ARRAY_SIZE(omap3_evm_ehci_gpios)); + + /* setup EHCI phy reset config */ + omap_mux_init_gpio(21, OMAP_PIN_INPUT_PULLUP); + usbhs_bdata.reset_gpio_port[1] = 21; + + /* EVM REV >= E can supply 500mA with EXTVBUS programming */ + musb_board_data.power = 500; + musb_board_data.extvbus = 1; + } else { + /* setup EHCI phy reset on MDC */ + omap_mux_init_gpio(135, OMAP_PIN_OUTPUT); + usbhs_bdata.reset_gpio_port[1] = 135; + } + usb_musb_init(&musb_board_data); + usbhs_init(&usbhs_bdata); + omap_ads7846_init(1, OMAP3_EVM_TS_GPIO, 310, NULL); + omap3evm_init_smsc911x(); + omap3_evm_display_init(); + omap3_evm_wl12xx_init(); +} + +MACHINE_START(OMAP3EVM, "OMAP3 EVM") + /* Maintainer: Syed Mohammed Khasim - Texas Instruments */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3_evm_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3logic.c b/arch/arm/mach-omap2/board-omap3logic.c new file mode 100644 index 00000000000..4198dd017d8 --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3logic.c @@ -0,0 +1,226 @@ +/* + * linux/arch/arm/mach-omap2/board-omap3logic.c + * + * Copyright (C) 2010 Li-Pro.Net + * Stephan Linz <linz@li-pro.net> + * + * Copyright (C) 2010 Logic Product Development, Inc. + * Peter Barada <peter.barada@logicpd.com> + * + * Modified from Beagle, EVM, and RX51 + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <linux/regulator/machine.h> + +#include <linux/i2c/twl.h> +#include <linux/mmc/host.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include "mux.h" +#include "hsmmc.h" +#include "control.h" +#include "common-board-devices.h" + +#include <plat/mux.h> +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc-smsc911x.h> +#include <plat/gpmc.h> +#include <plat/sdrc.h> + +#define OMAP3LOGIC_SMSC911X_CS 1 + +#define OMAP3530_LV_SOM_MMC_GPIO_CD 110 +#define OMAP3530_LV_SOM_MMC_GPIO_WP 126 +#define OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ 152 + +#define OMAP3_TORPEDO_MMC_GPIO_CD 127 +#define OMAP3_TORPEDO_SMSC911X_GPIO_IRQ 129 + +static struct regulator_consumer_supply omap3logic_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data omap3logic_vmmc1 = { + .constraints = { + .name = "VMMC1", + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3logic_vmmc1_supply), + .consumer_supplies = omap3logic_vmmc1_supply, +}; + +static struct twl4030_gpio_platform_data omap3logic_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .pullups = BIT(1), + .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) + | BIT(13) | BIT(15) | BIT(16) | BIT(17), +}; + +static struct twl4030_platform_data omap3logic_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .gpio = &omap3logic_gpio_data, + .vmmc1 = &omap3logic_vmmc1, +}; + +static int __init omap3logic_i2c_init(void) +{ + omap3_pmic_init("twl4030", &omap3logic_twldata); + return 0; +} + +static struct omap2_hsmmc_info __initdata board_mmc_info[] = { + { + .name = "external", + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + +static void __init board_mmc_init(void) +{ + if (machine_is_omap3530_lv_som()) { + /* OMAP3530 LV SOM board */ + board_mmc_info[0].gpio_cd = OMAP3530_LV_SOM_MMC_GPIO_CD; + board_mmc_info[0].gpio_wp = OMAP3530_LV_SOM_MMC_GPIO_WP; + omap_mux_init_signal("gpio_110", OMAP_PIN_OUTPUT); + omap_mux_init_signal("gpio_126", OMAP_PIN_OUTPUT); + } else if (machine_is_omap3_torpedo()) { + /* OMAP3 Torpedo board */ + board_mmc_info[0].gpio_cd = OMAP3_TORPEDO_MMC_GPIO_CD; + omap_mux_init_signal("gpio_127", OMAP_PIN_OUTPUT); + } else { + /* unsupported board */ + printk(KERN_ERR "%s(): unknown machine type\n", __func__); + return; + } + + omap2_hsmmc_init(board_mmc_info); +} + +static struct omap_smsc911x_platform_data __initdata board_smsc911x_data = { + .cs = OMAP3LOGIC_SMSC911X_CS, + .gpio_irq = -EINVAL, + .gpio_reset = -EINVAL, +}; + +/* TODO/FIXME (comment by Peter Barada, LogicPD): + * Fix the PBIAS voltage for Torpedo MMC1 pins that + * are used for other needs (IRQs, etc). */ +static void omap3torpedo_fix_pbias_voltage(void) +{ + u16 control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; + u32 reg; + + if (machine_is_omap3_torpedo()) + { + /* Set the bias for the pin */ + reg = omap_ctrl_readl(control_pbias_offset); + + reg &= ~OMAP343X_PBIASLITEPWRDNZ1; + omap_ctrl_writel(reg, control_pbias_offset); + + /* 100ms delay required for PBIAS configuration */ + msleep(100); + + reg |= OMAP343X_PBIASLITEVMODE1; + reg |= OMAP343X_PBIASLITEPWRDNZ1; + omap_ctrl_writel(reg | 0x300, control_pbias_offset); + } +} + +static inline void __init board_smsc911x_init(void) +{ + if (machine_is_omap3530_lv_som()) { + /* OMAP3530 LV SOM board */ + board_smsc911x_data.gpio_irq = + OMAP3530_LV_SOM_SMSC911X_GPIO_IRQ; + omap_mux_init_signal("gpio_152", OMAP_PIN_INPUT); + } else if (machine_is_omap3_torpedo()) { + /* OMAP3 Torpedo board */ + board_smsc911x_data.gpio_irq = OMAP3_TORPEDO_SMSC911X_GPIO_IRQ; + omap_mux_init_signal("gpio_129", OMAP_PIN_INPUT); + } else { + /* unsupported board */ + printk(KERN_ERR "%s(): unknown machine type\n", __func__); + return; + } + + gpmc_smsc911x_init(&board_smsc911x_data); +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init omap3logic_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap3torpedo_fix_pbias_voltage(); + omap3logic_i2c_init(); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + board_mmc_init(); + board_smsc911x_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); +} + +MACHINE_START(OMAP3_TORPEDO, "Logic OMAP3 Torpedo board") + .atag_offset = 0x100, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3logic_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(OMAP3530_LV_SOM, "OMAP Logic 3530 LV SOM board") + .atag_offset = 0x100, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3logic_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c new file mode 100644 index 00000000000..1644b73017f --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -0,0 +1,613 @@ +/* + * board-omap3pandora.c (Pandora Handheld Console) + * + * 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/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/spi/spi.h> +#include <linux/regulator/machine.h> +#include <linux/i2c/twl.h> +#include <linux/wl12xx.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> +#include <linux/leds.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> +#include <linux/regulator/fixed.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <mach/hardware.h> +#include <plat/mcspi.h> +#include <plat/usb.h> +#include <video/omapdss.h> +#include <plat/nand.h> + +#include "mux.h" +#include "sdram-micron-mt46h32m32lf-6.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define PANDORA_WIFI_IRQ_GPIO 21 +#define PANDORA_WIFI_NRESET_GPIO 23 +#define OMAP3_PANDORA_TS_GPIO 94 + +static struct mtd_partition omap3pandora_nand_partitions[] = { + { + .name = "xloader", + .offset = 0, + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE + }, { + .name = "uboot", + .offset = MTDPART_OFS_APPEND, + .size = 15 * NAND_BLOCK_SIZE, + }, { + .name = "uboot-env", + .offset = MTDPART_OFS_APPEND, + .size = 1 * NAND_BLOCK_SIZE, + }, { + .name = "boot", + .offset = MTDPART_OFS_APPEND, + .size = 80 * NAND_BLOCK_SIZE, + }, { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_nand_platform_data pandora_nand_data = { + .cs = 0, + .devsize = NAND_BUSWIDTH_16, + .xfer_type = NAND_OMAP_PREFETCH_DMA, + .parts = omap3pandora_nand_partitions, + .nr_parts = ARRAY_SIZE(omap3pandora_nand_partitions), +}; + +static struct gpio_led pandora_gpio_leds[] = { + { + .name = "pandora::sd1", + .default_trigger = "mmc0", + .gpio = 128, + }, { + .name = "pandora::sd2", + .default_trigger = "mmc1", + .gpio = 129, + }, { + .name = "pandora::bluetooth", + .gpio = 158, + }, { + .name = "pandora::wifi", + .gpio = 159, + }, +}; + +static struct gpio_led_platform_data pandora_gpio_led_data = { + .leds = pandora_gpio_leds, + .num_leds = ARRAY_SIZE(pandora_gpio_leds), +}; + +static struct platform_device pandora_leds_gpio = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &pandora_gpio_led_data, + }, +}; + +#define GPIO_BUTTON(gpio_num, ev_type, ev_code, act_low, descr) \ +{ \ + .gpio = gpio_num, \ + .type = ev_type, \ + .code = ev_code, \ + .active_low = act_low, \ + .debounce_interval = 4, \ + .desc = "btn " descr, \ +} + +#define GPIO_BUTTON_LOW(gpio_num, event_code, description) \ + GPIO_BUTTON(gpio_num, EV_KEY, event_code, 1, description) + +static struct gpio_keys_button pandora_gpio_keys[] = { + GPIO_BUTTON_LOW(110, KEY_UP, "up"), + GPIO_BUTTON_LOW(103, KEY_DOWN, "down"), + GPIO_BUTTON_LOW(96, KEY_LEFT, "left"), + GPIO_BUTTON_LOW(98, KEY_RIGHT, "right"), + GPIO_BUTTON_LOW(109, KEY_PAGEUP, "game 1"), + GPIO_BUTTON_LOW(111, KEY_END, "game 2"), + GPIO_BUTTON_LOW(106, KEY_PAGEDOWN, "game 3"), + GPIO_BUTTON_LOW(101, KEY_HOME, "game 4"), + GPIO_BUTTON_LOW(102, KEY_RIGHTSHIFT, "l"), + GPIO_BUTTON_LOW(97, KEY_KPPLUS, "l2"), + GPIO_BUTTON_LOW(105, KEY_RIGHTCTRL, "r"), + GPIO_BUTTON_LOW(107, KEY_KPMINUS, "r2"), + GPIO_BUTTON_LOW(104, KEY_LEFTCTRL, "ctrl"), + GPIO_BUTTON_LOW(99, KEY_MENU, "menu"), + GPIO_BUTTON_LOW(176, KEY_COFFEE, "hold"), + GPIO_BUTTON(100, EV_KEY, KEY_LEFTALT, 0, "alt"), + GPIO_BUTTON(108, EV_SW, SW_LID, 1, "lid"), +}; + +static struct gpio_keys_platform_data pandora_gpio_key_info = { + .buttons = pandora_gpio_keys, + .nbuttons = ARRAY_SIZE(pandora_gpio_keys), +}; + +static struct platform_device pandora_keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &pandora_gpio_key_info, + }, +}; + +static const uint32_t board_keymap[] = { + /* row, col, code */ + KEY(0, 0, KEY_9), + KEY(0, 1, KEY_8), + KEY(0, 2, KEY_I), + KEY(0, 3, KEY_J), + KEY(0, 4, KEY_N), + KEY(0, 5, KEY_M), + KEY(1, 0, KEY_0), + KEY(1, 1, KEY_7), + KEY(1, 2, KEY_U), + KEY(1, 3, KEY_H), + KEY(1, 4, KEY_B), + KEY(1, 5, KEY_SPACE), + KEY(2, 0, KEY_BACKSPACE), + KEY(2, 1, KEY_6), + KEY(2, 2, KEY_Y), + KEY(2, 3, KEY_G), + KEY(2, 4, KEY_V), + KEY(2, 5, KEY_FN), + KEY(3, 0, KEY_O), + KEY(3, 1, KEY_5), + KEY(3, 2, KEY_T), + KEY(3, 3, KEY_F), + KEY(3, 4, KEY_C), + KEY(4, 0, KEY_P), + KEY(4, 1, KEY_4), + KEY(4, 2, KEY_R), + KEY(4, 3, KEY_D), + KEY(4, 4, KEY_X), + KEY(5, 0, KEY_K), + KEY(5, 1, KEY_3), + KEY(5, 2, KEY_E), + KEY(5, 3, KEY_S), + KEY(5, 4, KEY_Z), + KEY(6, 0, KEY_L), + KEY(6, 1, KEY_2), + KEY(6, 2, KEY_W), + KEY(6, 3, KEY_A), + KEY(6, 4, KEY_DOT), + KEY(7, 0, KEY_ENTER), + KEY(7, 1, KEY_1), + KEY(7, 2, KEY_Q), + KEY(7, 3, KEY_LEFTSHIFT), + KEY(7, 4, KEY_COMMA), +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data pandora_kp_data = { + .keymap_data = &board_map_data, + .rows = 8, + .cols = 6, + .rep = 1, +}; + +static struct omap_dss_device pandora_lcd_device = { + .name = "lcd", + .driver_name = "tpo_td043mtea1_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 24, + .reset_gpio = 157, +}; + +static struct omap_dss_device pandora_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, +}; + +static struct omap_dss_device *pandora_dss_devices[] = { + &pandora_lcd_device, + &pandora_tv_device, +}; + +static struct omap_dss_board_info pandora_dss_data = { + .num_devices = ARRAY_SIZE(pandora_dss_devices), + .devices = pandora_dss_devices, + .default_device = &pandora_lcd_device, +}; + +static void pandora_wl1251_init_card(struct mmc_card *card) +{ + /* + * We have TI wl1251 attached to MMC3. Pass this information to + * SDIO core because it can't be probed by normal methods. + */ + card->quirks |= MMC_QUIRK_NONSTD_SDIO; + card->cccr.wide_bus = 1; + card->cis.vendor = 0x104c; + card->cis.device = 0x9066; + card->cis.blksize = 512; + card->cis.max_dtr = 20000000; +} + +static struct omap2_hsmmc_info omap3pandora_mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = 126, + .ext_clock = 0, + }, + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = 127, + .ext_clock = 1, + .transceiver = true, + }, + { + .mmc = 3, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .init_card = pandora_wl1251_init_card, + }, + {} /* Terminator */ +}; + +static int omap3pandora_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + int ret, gpio_32khz; + + /* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */ + omap3pandora_mmc[0].gpio_cd = gpio + 0; + omap3pandora_mmc[1].gpio_cd = gpio + 1; + omap2_hsmmc_init(omap3pandora_mmc); + + /* gpio + 13 drives 32kHz buffer for wifi module */ + gpio_32khz = gpio + 13; + ret = gpio_request_one(gpio_32khz, GPIOF_OUT_INIT_HIGH, "wifi 32kHz"); + if (ret < 0) { + pr_err("Cannot get GPIO line %d, ret=%d\n", gpio_32khz, ret); + return -ENODEV; + } + + return 0; +} + +static struct twl4030_gpio_platform_data omap3pandora_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .setup = omap3pandora_twl_gpio_setup, +}; + +static struct regulator_consumer_supply pandora_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply pandora_vmmc2_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1") +}; + +static struct regulator_consumer_supply pandora_vmmc3_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2"), +}; + +static struct regulator_consumer_supply pandora_vdds_supplies[] = { + REGULATOR_SUPPLY("vdds_sdi", "omapdss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss"), + REGULATOR_SUPPLY("vdds_dsi", "omapdss_dsi.0"), +}; + +static struct regulator_consumer_supply pandora_vcc_lcd_supply[] = { + REGULATOR_SUPPLY("vcc", "display0"), +}; + +static struct regulator_consumer_supply pandora_usb_phy_supply[] = { + REGULATOR_SUPPLY("hsusb0", "ehci-omap.0"), +}; + +/* ads7846 on SPI and 2 nub controllers on I2C */ +static struct regulator_consumer_supply pandora_vaux4_supplies[] = { + REGULATOR_SUPPLY("vcc", "spi1.0"), + REGULATOR_SUPPLY("vcc", "3-0066"), + REGULATOR_SUPPLY("vcc", "3-0067"), +}; + +static struct regulator_consumer_supply pandora_adac_supply[] = { + REGULATOR_SUPPLY("vcc", "soc-audio"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data pandora_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_vmmc1_supply), + .consumer_supplies = pandora_vmmc1_supply, +}; + +/* VMMC2 for MMC2 pins CMD, CLK, DAT0..DAT3 (max 100 mA) */ +static struct regulator_init_data pandora_vmmc2 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_vmmc2_supply), + .consumer_supplies = pandora_vmmc2_supply, +}; + +/* VAUX1 for LCD */ +static struct regulator_init_data pandora_vaux1 = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_vcc_lcd_supply), + .consumer_supplies = pandora_vcc_lcd_supply, +}; + +/* VAUX2 for USB host PHY */ +static struct regulator_init_data pandora_vaux2 = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_usb_phy_supply), + .consumer_supplies = pandora_usb_phy_supply, +}; + +/* VAUX4 for ads7846 and nubs */ +static struct regulator_init_data pandora_vaux4 = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_vaux4_supplies), + .consumer_supplies = pandora_vaux4_supplies, +}; + +/* VSIM for audio DAC */ +static struct regulator_init_data pandora_vsim = { + .constraints = { + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_adac_supply), + .consumer_supplies = pandora_adac_supply, +}; + +/* Fixed regulator internal to Wifi module */ +static struct regulator_init_data pandora_vmmc3 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(pandora_vmmc3_supply), + .consumer_supplies = pandora_vmmc3_supply, +}; + +static struct fixed_voltage_config pandora_vwlan = { + .supply_name = "vwlan", + .microvolts = 1800000, /* 1.8V */ + .gpio = PANDORA_WIFI_NRESET_GPIO, + .startup_delay = 50000, /* 50ms */ + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &pandora_vmmc3, +}; + +static struct platform_device pandora_vwlan_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &pandora_vwlan, + }, +}; + +static struct twl4030_bci_platform_data pandora_bci_data; + +static struct twl4030_platform_data omap3pandora_twldata = { + .gpio = &omap3pandora_gpio_data, + .vmmc1 = &pandora_vmmc1, + .vmmc2 = &pandora_vmmc2, + .vaux1 = &pandora_vaux1, + .vaux2 = &pandora_vaux2, + .vaux4 = &pandora_vaux4, + .vsim = &pandora_vsim, + .keypad = &pandora_kp_data, + .bci = &pandora_bci_data, +}; + +static struct i2c_board_info __initdata omap3pandora_i2c3_boardinfo[] = { + { + I2C_BOARD_INFO("bq27500", 0x55), + .flags = I2C_CLIENT_WAKE, + }, +}; + +static int __init omap3pandora_i2c_init(void) +{ + omap3_pmic_get_config(&omap3pandora_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + omap3pandora_twldata.vdac->constraints.apply_uV = true; + + omap3pandora_twldata.vpll2->constraints.apply_uV = true; + omap3pandora_twldata.vpll2->num_consumer_supplies = + ARRAY_SIZE(pandora_vdds_supplies); + omap3pandora_twldata.vpll2->consumer_supplies = pandora_vdds_supplies; + + omap3_pmic_init("tps65950", &omap3pandora_twldata); + /* i2c2 pins are not connected */ + omap_register_i2c_bus(3, 100, omap3pandora_i2c3_boardinfo, + ARRAY_SIZE(omap3pandora_i2c3_boardinfo)); + return 0; +} + +static struct spi_board_info omap3pandora_spi_board_info[] __initdata = { + { + .modalias = "tpo_td043mtea1_panel_spi", + .bus_num = 1, + .chip_select = 1, + .max_speed_hz = 375000, + .platform_data = &pandora_lcd_device, + } +}; + +static void __init pandora_wl1251_init(void) +{ + struct wl12xx_platform_data pandora_wl1251_pdata; + int ret; + + memset(&pandora_wl1251_pdata, 0, sizeof(pandora_wl1251_pdata)); + + ret = gpio_request_one(PANDORA_WIFI_IRQ_GPIO, GPIOF_IN, "wl1251 irq"); + if (ret < 0) + goto fail; + + pandora_wl1251_pdata.irq = gpio_to_irq(PANDORA_WIFI_IRQ_GPIO); + if (pandora_wl1251_pdata.irq < 0) + goto fail_irq; + + pandora_wl1251_pdata.use_eeprom = true; + ret = wl12xx_set_platform_data(&pandora_wl1251_pdata); + if (ret < 0) + goto fail_irq; + + return; + +fail_irq: + gpio_free(PANDORA_WIFI_IRQ_GPIO); +fail: + printk(KERN_ERR "wl1251 board initialisation failed\n"); +} + +static struct platform_device *omap3pandora_devices[] __initdata = { + &pandora_leds_gpio, + &pandora_keys_gpio, + &pandora_vwlan_device, +}; + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = 16, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init omap3pandora_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap3pandora_i2c_init(); + pandora_wl1251_init(); + platform_add_devices(omap3pandora_devices, + ARRAY_SIZE(omap3pandora_devices)); + omap_display_init(&pandora_dss_data); + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + spi_register_board_info(omap3pandora_spi_board_info, + ARRAY_SIZE(omap3pandora_spi_board_info)); + omap_ads7846_init(1, OMAP3_PANDORA_TS_GPIO, 0, NULL); + usbhs_init(&usbhs_bdata); + usb_musb_init(NULL); + gpmc_nand_init(&pandora_nand_data); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); +} + +MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3pandora_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c new file mode 100644 index 00000000000..cb089a46f62 --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3stalker.c @@ -0,0 +1,461 @@ +/* + * linux/arch/arm/mach-omap2/board-omap3evm.c + * + * Copyright (C) 2008 Guangzhou EMA-Tech + * + * Modified from mach-omap2/board-omap3evm.c + * + * Initial code: Syed Mohammed Khasim + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> + +#include <linux/regulator/machine.h> +#include <linux/i2c/twl.h> +#include <linux/mmc/host.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> +#include <plat/nand.h> +#include <plat/usb.h> +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-dvi.h> + +#include <plat/mcspi.h> +#include <linux/input/matrix_keypad.h> +#include <linux/spi/spi.h> +#include <linux/interrupt.h> +#include <linux/smsc911x.h> +#include <linux/i2c/at24.h> + +#include "sdram-micron-mt46h32m32lf-6.h" +#include "mux.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) +#include <plat/gpmc-smsc911x.h> + +#define OMAP3STALKER_ETHR_START 0x2c000000 +#define OMAP3STALKER_ETHR_SIZE 1024 +#define OMAP3STALKER_ETHR_GPIO_IRQ 19 +#define OMAP3STALKER_SMC911X_CS 5 + +static struct omap_smsc911x_platform_data smsc911x_cfg = { + .cs = OMAP3STALKER_SMC911X_CS, + .gpio_irq = OMAP3STALKER_ETHR_GPIO_IRQ, + .gpio_reset = -EINVAL, + .flags = (SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS), +}; + +static inline void __init omap3stalker_init_eth(void) +{ + struct clk *l3ck; + unsigned int rate; + + l3ck = clk_get(NULL, "l3_ck"); + if (IS_ERR(l3ck)) + rate = 100000000; + else + rate = clk_get_rate(l3ck); + + omap_mux_init_gpio(19, OMAP_PIN_INPUT_PULLUP); + gpmc_smsc911x_init(&smsc911x_cfg); +} + +#else +static inline void __init omap3stalker_init_eth(void) +{ + return; +} +#endif + +/* + * OMAP3 DSS control signals + */ + +#define DSS_ENABLE_GPIO 199 +#define LCD_PANEL_BKLIGHT_GPIO 210 +#define ENABLE_VPLL2_DEV_GRP 0xE0 + +static int lcd_enabled; +static int dvi_enabled; + +static void __init omap3_stalker_display_init(void) +{ + return; +} + +static int omap3_stalker_enable_tv(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void omap3_stalker_disable_tv(struct omap_dss_device *dssdev) +{ +} + +static struct omap_dss_device omap3_stalker_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, +#if defined(CONFIG_OMAP2_VENC_OUT_TYPE_SVIDEO) + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, +#elif defined(CONFIG_OMAP2_VENC_OUT_TYPE_COMPOSITE) + .u.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE, +#endif + .platform_enable = omap3_stalker_enable_tv, + .platform_disable = omap3_stalker_disable_tv, +}; + +static int omap3_stalker_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + gpio_set_value(DSS_ENABLE_GPIO, 1); + dvi_enabled = 1; + return 0; +} + +static void omap3_stalker_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(DSS_ENABLE_GPIO, 0); + dvi_enabled = 0; +} + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = omap3_stalker_enable_dvi, + .platform_disable = omap3_stalker_disable_dvi, +}; + +static struct omap_dss_device omap3_stalker_dvi_device = { + .name = "dvi", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device *omap3_stalker_dss_devices[] = { + &omap3_stalker_tv_device, + &omap3_stalker_dvi_device, +}; + +static struct omap_dss_board_info omap3_stalker_dss_data = { + .num_devices = ARRAY_SIZE(omap3_stalker_dss_devices), + .devices = omap3_stalker_dss_devices, + .default_device = &omap3_stalker_dvi_device, +}; + +static struct regulator_consumer_supply omap3stalker_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply omap3stalker_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data omap3stalker_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3stalker_vmmc1_supply), + .consumer_supplies = omap3stalker_vmmc1_supply, +}; + +/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */ +static struct regulator_init_data omap3stalker_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap3stalker_vsim_supply), + .consumer_supplies = omap3stalker_vsim_supply, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = 23, + }, + {} /* Terminator */ +}; + +static struct gpio_keys_button gpio_buttons[] = { + { + .code = BTN_EXTRA, + .gpio = 18, + .desc = "user", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + +static struct gpio_led gpio_leds[] = { + { + .name = "stalker:D8:usr0", + .default_trigger = "default-on", + .gpio = 126, + }, + { + .name = "stalker:D9:usr1", + .default_trigger = "default-on", + .gpio = 127, + }, + { + .name = "stalker:D3:mmc0", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + .default_trigger = "mmc0", + }, + { + .name = "stalker:D4:heartbeat", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + .default_trigger = "heartbeat", + }, +}; + +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 int +omap3stalker_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + omap_mux_init_gpio(23, OMAP_PIN_INPUT); + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + /* + * Most GPIOs are for USB OTG. Some are mostly sent to + * the P2 connector; notably LEDA for the LCD backlight. + */ + + /* TWL4030_GPIO_MAX + 0 == ledA, LCD Backlight control */ + gpio_request_one(gpio + TWL4030_GPIO_MAX, GPIOF_OUT_INIT_LOW, + "EN_LCD_BKL"); + + /* gpio + 7 == DVI Enable */ + gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "EN_DVI"); + + /* TWL4030_GPIO_MAX + 1 == ledB (out, mmc0) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + /* GPIO + 13 == ledsync (out, heartbeat) */ + gpio_leds[3].gpio = gpio + 13; + + platform_device_register(&leds_gpio); + return 0; +} + +static struct twl4030_gpio_platform_data omap3stalker_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .setup = omap3stalker_twl_gpio_setup, +}; + +static uint32_t board_keymap[] = { + KEY(0, 0, KEY_LEFT), + KEY(0, 1, KEY_DOWN), + KEY(0, 2, KEY_ENTER), + KEY(0, 3, KEY_M), + + KEY(1, 0, KEY_RIGHT), + KEY(1, 1, KEY_UP), + KEY(1, 2, KEY_I), + KEY(1, 3, KEY_N), + + KEY(2, 0, KEY_A), + KEY(2, 1, KEY_E), + KEY(2, 2, KEY_J), + KEY(2, 3, KEY_O), + + KEY(3, 0, KEY_B), + KEY(3, 1, KEY_F), + KEY(3, 2, KEY_K), + KEY(3, 3, KEY_P) +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data omap3stalker_kp_data = { + .keymap_data = &board_map_data, + .rows = 4, + .cols = 4, + .rep = 1, +}; + +static struct twl4030_platform_data omap3stalker_twldata = { + /* platform_data for children goes here */ + .keypad = &omap3stalker_kp_data, + .gpio = &omap3stalker_gpio_data, + .vmmc1 = &omap3stalker_vmmc1, + .vsim = &omap3stalker_vsim, +}; + +static struct at24_platform_data fram_info = { + .byte_len = (64 * 1024) / 8, + .page_size = 8192, + .flags = AT24_FLAG_ADDR16 | AT24_FLAG_IRUGO, +}; + +static struct i2c_board_info __initdata omap3stalker_i2c_boardinfo3[] = { + { + I2C_BOARD_INFO("24c64", 0x50), + .flags = I2C_CLIENT_WAKE, + .platform_data = &fram_info, + }, +}; + +static int __init omap3_stalker_i2c_init(void) +{ + omap3_pmic_get_config(&omap3stalker_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC | + TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + omap3stalker_twldata.vdac->constraints.apply_uV = true; + omap3stalker_twldata.vpll2->constraints.apply_uV = true; + omap3stalker_twldata.vpll2->constraints.name = "VDVI"; + + omap3_pmic_init("twl4030", &omap3stalker_twldata); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, omap3stalker_i2c_boardinfo3, + ARRAY_SIZE(omap3stalker_i2c_boardinfo3)); + return 0; +} + +#define OMAP3_STALKER_TS_GPIO 175 + +static struct omap_board_config_kernel omap3_stalker_config[] __initdata = { +}; + +static struct platform_device *omap3_stalker_devices[] __initdata = { + &keys_gpio, +}; + +static struct usbhs_omap_board_data usbhs_bdata __initconst = { + .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = 21, + .reset_gpio_port[2] = -EINVAL, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + OMAP3_MUX(SYS_NIRQ, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE), + OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP | + OMAP_PIN_OFF_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE), + {.reg_offset = OMAP_MUX_TERMINATOR}, +}; +#endif + +static void __init omap3_stalker_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CUS); + omap_board_config = omap3_stalker_config; + omap_board_config_size = ARRAY_SIZE(omap3_stalker_config); + + omap3_stalker_i2c_init(); + + platform_add_devices(omap3_stalker_devices, + ARRAY_SIZE(omap3_stalker_devices)); + + omap_display_init(&omap3_stalker_dss_data); + + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, NULL); + usb_musb_init(NULL); + usbhs_init(&usbhs_bdata); + omap_ads7846_init(1, OMAP3_STALKER_TS_GPIO, 310, NULL); + + omap_mux_init_gpio(21, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(18, OMAP_PIN_INPUT_PULLUP); + + omap3stalker_init_eth(); + omap3_stalker_display_init(); +/* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdr_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdr_cke1", OMAP_PIN_OUTPUT); +} + +MACHINE_START(SBC3530, "OMAP3 STALKER") + /* Maintainer: Jason Lam -lzg@ema-tech.com */ + .atag_offset = 0x100, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3_stalker_init, + .timer = &omap3_secure_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap3touchbook.c b/arch/arm/mach-omap2/board-omap3touchbook.c new file mode 100644 index 00000000000..a0b851aafcc --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3touchbook.c @@ -0,0 +1,388 @@ +/* + * linux/arch/arm/mach-omap2/board-omap3touchbook.c + * + * Copyright (C) 2009 Always Innovating + * + * Modified from mach-omap2/board-omap3beagleboard.c + * + * Initial code: Grégoire Gentil, Tim Yamin + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand.h> +#include <linux/mmc/host.h> + +#include <plat/mcspi.h> +#include <linux/spi/spi.h> + +#include <linux/spi/ads7846.h> + +#include <linux/regulator/machine.h> +#include <linux/i2c/twl.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/flash.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/gpmc.h> +#include <plat/nand.h> +#include <plat/usb.h> + +#include "mux.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#include <asm/setup.h> + +#define OMAP3_AC_GPIO 136 +#define OMAP3_TS_GPIO 162 +#define TB_BL_PWM_TIMER 9 +#define TB_KILL_POWER_GPIO 168 + +static unsigned long touchbook_revision; + +static struct mtd_partition omap3touchbook_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader", + .offset = 0, + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 15 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot Env", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x260000 */ + .size = 1 * NAND_BLOCK_SIZE, + }, + { + .name = "Kernel", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 32 * NAND_BLOCK_SIZE, + }, + { + .name = "File System", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */ + .size = MTDPART_SIZ_FULL, + }, +}; + +#include "sdram-micron-mt46h32m32lf-6.h" + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_wp = 29, + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply touchbook_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply touchbook_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +static struct gpio_led gpio_leds[]; + +static int touchbook_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + if (system_rev >= 0x20 && system_rev <= 0x34301000) { + omap_mux_init_gpio(23, OMAP_PIN_INPUT); + mmc[0].gpio_wp = 23; + } else { + omap_mux_init_gpio(29, OMAP_PIN_INPUT); + } + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + /* REVISIT: need ehci-omap hooks for external VBUS + * power switch and overcurrent detect + */ + gpio_request_one(gpio + 1, GPIOF_IN, "EHCI_nOC"); + + /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */ + gpio_request_one(gpio + TWL4030_GPIO_MAX, GPIOF_OUT_INIT_LOW, + "nEN_USB_PWR"); + + /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + + return 0; +} + +static struct twl4030_gpio_platform_data touchbook_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .pullups = BIT(1), + .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13) + | BIT(15) | BIT(16) | BIT(17), + .setup = touchbook_twl_gpio_setup, +}; + +static struct regulator_consumer_supply touchbook_vdac_supply[] = { +{ + .supply = "vdac", +}, +}; + +static struct regulator_consumer_supply touchbook_vdvi_supply[] = { +{ + .supply = "vdvi", +}, +}; + +/* VMMC1 for MMC1 pins CMD, CLK, DAT0..DAT3 (20 mA, plus card == max 220 mA) */ +static struct regulator_init_data touchbook_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(touchbook_vmmc1_supply), + .consumer_supplies = touchbook_vmmc1_supply, +}; + +/* VSIM for MMC1 pins DAT4..DAT7 (2 mA, plus card == max 50 mA) */ +static struct regulator_init_data touchbook_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(touchbook_vsim_supply), + .consumer_supplies = touchbook_vsim_supply, +}; + +static struct twl4030_platform_data touchbook_twldata = { + /* platform_data for children goes here */ + .gpio = &touchbook_gpio_data, + .vmmc1 = &touchbook_vmmc1, + .vsim = &touchbook_vsim, +}; + +static struct i2c_board_info __initdata touchBook_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("bq27200", 0x55), + }, +}; + +static int __init omap3_touchbook_i2c_init(void) +{ + /* Standard TouchBook bus */ + omap3_pmic_get_config(&touchbook_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + touchbook_twldata.vdac->num_consumer_supplies = + ARRAY_SIZE(touchbook_vdac_supply); + touchbook_twldata.vdac->consumer_supplies = touchbook_vdac_supply; + + touchbook_twldata.vpll2->constraints.name = "VDVI"; + touchbook_twldata.vpll2->num_consumer_supplies = + ARRAY_SIZE(touchbook_vdvi_supply); + touchbook_twldata.vpll2->consumer_supplies = touchbook_vdvi_supply; + + omap3_pmic_init("twl4030", &touchbook_twldata); + /* Additional TouchBook bus */ + omap_register_i2c_bus(3, 100, touchBook_i2c_boardinfo, + ARRAY_SIZE(touchBook_i2c_boardinfo)); + + return 0; +} + +static struct ads7846_platform_data ads7846_pdata = { + .x_min = 100, + .y_min = 265, + .x_max = 3950, + .y_max = 3750, + .x_plate_ohms = 40, + .pressure_max = 255, + .debounce_max = 10, + .debounce_tol = 5, + .debounce_rep = 1, + .gpio_pendown = OMAP3_TS_GPIO, + .keep_vref_on = 1, +}; + +static struct gpio_led gpio_leds[] = { + { + .name = "touchbook::usr0", + .default_trigger = "heartbeat", + .gpio = 150, + }, + { + .name = "touchbook::usr1", + .default_trigger = "mmc0", + .gpio = 149, + }, + { + .name = "touchbook::pmu_stat", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + }, +}; + +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 gpio_keys_button gpio_buttons[] = { + { + .code = BTN_EXTRA, + .gpio = 7, + .desc = "user", + .wakeup = 1, + }, + { + .code = KEY_POWER, + .gpio = 183, + .desc = "power", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data gpio_key_info = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device keys_gpio = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_key_info, + }, +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static struct platform_device *omap3_touchbook_devices[] __initdata = { + &leds_gpio, + &keys_gpio, +}; + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = 147, + .reset_gpio_port[2] = -EINVAL +}; + +static void omap3_touchbook_poweroff(void) +{ + int pwr_off = TB_KILL_POWER_GPIO; + + if (gpio_request_one(pwr_off, GPIOF_OUT_INIT_LOW, "DVI reset") < 0) + printk(KERN_ERR "Unable to get kill power GPIO\n"); +} + +static int __init early_touchbook_revision(char *p) +{ + if (!p) + return 0; + + return strict_strtoul(p, 10, &touchbook_revision); +} +early_param("tbr", early_touchbook_revision); + +static void __init omap3_touchbook_init(void) +{ + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + + pm_power_off = omap3_touchbook_poweroff; + + omap3_touchbook_i2c_init(); + platform_add_devices(omap3_touchbook_devices, + ARRAY_SIZE(omap3_touchbook_devices)); + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + + omap_mux_init_gpio(170, OMAP_PIN_INPUT); + /* REVISIT leave DVI powered down until it's needed ... */ + gpio_request_one(176, GPIOF_OUT_INIT_HIGH, "DVI_nPD"); + + /* Touchscreen and accelerometer */ + omap_ads7846_init(4, OMAP3_TS_GPIO, 310, &ads7846_pdata); + usb_musb_init(NULL); + usbhs_init(&usbhs_bdata); + omap_nand_flash_init(NAND_BUSWIDTH_16, omap3touchbook_nand_partitions, + ARRAY_SIZE(omap3touchbook_nand_partitions)); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); +} + +MACHINE_START(TOUCHBOOK, "OMAP3 touchbook Board") + /* Maintainer: Gregoire Gentil - http://www.alwaysinnovating.com */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3430_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap3_touchbook_init, + .timer = &omap3_secure_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c new file mode 100644 index 00000000000..28fc271f703 --- /dev/null +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -0,0 +1,523 @@ +/* + * Board support file for OMAP4430 based PandaBoard. + * + * Copyright (C) 2010 Texas Instruments + * + * Author: David Anders <x0132446@ti.com> + * + * Based on mach-omap2/board-4430sdp.c + * + * Author: Santosh Shilimkar <santosh.shilimkar@ti.com> + * + * Based on mach-omap2/board-3430sdp.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/usb/otg.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/wl12xx.h> + +#include <mach/hardware.h> +#include <asm/hardware/gic.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <video/omapdss.h> + +#include <plat/board.h> +#include "common.h" +#include <plat/usb.h> +#include <plat/mmc.h> +#include <video/omap-panel-dvi.h> + +#include "hsmmc.h" +#include "control.h" +#include "mux.h" +#include "common-board-devices.h" + +#define GPIO_HUB_POWER 1 +#define GPIO_HUB_NRESET 62 +#define GPIO_WIFI_PMENA 43 +#define GPIO_WIFI_IRQ 53 +#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ +#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define HDMI_GPIO_HPD 63 /* Hotplug detect */ + +/* wl127x BT, FM, GPS connectivity chip */ +static int wl1271_gpios[] = {46, -1, -1}; +static struct platform_device wl1271_device = { + .name = "kim", + .id = -1, + .dev = { + .platform_data = &wl1271_gpios, + }, +}; + +static struct gpio_led gpio_leds[] = { + { + .name = "pandaboard::status1", + .default_trigger = "heartbeat", + .gpio = 7, + }, + { + .name = "pandaboard::status2", + .default_trigger = "mmc0", + .gpio = 8, + }, +}; + +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 platform_device *panda_devices[] __initdata = { + &leds_gpio, + &wl1271_device, +}; + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[1] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + .phy_reset = false, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = -EINVAL, + .reset_gpio_port[2] = -EINVAL +}; + +static struct gpio panda_ehci_gpios[] __initdata = { + { GPIO_HUB_POWER, GPIOF_OUT_INIT_LOW, "hub_power" }, + { GPIO_HUB_NRESET, GPIOF_OUT_INIT_LOW, "hub_nreset" }, +}; + +static void __init omap4_ehci_init(void) +{ + int ret; + struct clk *phy_ref_clk; + + /* FREF_CLK3 provides the 19.2 MHz reference clock to the PHY */ + phy_ref_clk = clk_get(NULL, "auxclk3_ck"); + if (IS_ERR(phy_ref_clk)) { + pr_err("Cannot request auxclk3\n"); + return; + } + clk_set_rate(phy_ref_clk, 19200000); + clk_enable(phy_ref_clk); + + /* disable the power to the usb hub prior to init and reset phy+hub */ + ret = gpio_request_array(panda_ehci_gpios, + ARRAY_SIZE(panda_ehci_gpios)); + if (ret) { + pr_err("Unable to initialize EHCI power/reset\n"); + return; + } + + gpio_export(GPIO_HUB_POWER, 0); + gpio_export(GPIO_HUB_NRESET, 0); + gpio_set_value(GPIO_HUB_NRESET, 1); + + usbhs_init(&usbhs_bdata); + + /* enable power to hub */ + gpio_set_value(GPIO_HUB_POWER, 1); +} + +static struct omap_musb_board_data musb_board_data = { + .interface_type = MUSB_INTERFACE_UTMI, + .mode = MUSB_OTG, + .power = 100, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_wp = -EINVAL, + .gpio_cd = -EINVAL, + }, + { + .name = "wl1271", + .mmc = 5, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD, + .gpio_wp = -EINVAL, + .gpio_cd = -EINVAL, + .ocr_mask = MMC_VDD_165_195, + .nonremovable = true, + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply omap4_panda_vmmc5_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.4"), +}; + +static struct regulator_init_data panda_vmmc5 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(omap4_panda_vmmc5_supply), + .consumer_supplies = omap4_panda_vmmc5_supply, +}; + +static struct fixed_voltage_config panda_vwlan = { + .supply_name = "vwl1271", + .microvolts = 1800000, /* 1.8V */ + .gpio = GPIO_WIFI_PMENA, + .startup_delay = 70000, /* 70msec */ + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &panda_vmmc5, +}; + +static struct platform_device omap_vwlan_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &panda_vwlan, + }, +}; + +struct wl12xx_platform_data omap_panda_wlan_data __initdata = { + .irq = OMAP_GPIO_IRQ(GPIO_WIFI_IRQ), + /* PANDA ref clock is 38.4 MHz */ + .board_ref_clock = 2, +}; + +static int omap4_twl6030_hsmmc_late_init(struct device *dev) +{ + int ret = 0; + struct platform_device *pdev = container_of(dev, + struct platform_device, dev); + struct omap_mmc_platform_data *pdata = dev->platform_data; + + if (!pdata) { + dev_err(dev, "%s: NULL platform data\n", __func__); + return -EINVAL; + } + /* Setting MMC1 Card detect Irq */ + if (pdev->id == 0) { + ret = twl6030_mmc_card_detect_config(); + if (ret) + dev_err(dev, "%s: Error card detect config(%d)\n", + __func__, ret); + else + pdata->slots[0].card_detect = twl6030_mmc_card_detect; + } + return ret; +} + +static __init void omap4_twl6030_hsmmc_set_late_init(struct device *dev) +{ + struct omap_mmc_platform_data *pdata; + + /* dev can be null if CONFIG_MMC_OMAP_HS is not set */ + if (!dev) { + pr_err("Failed omap4_twl6030_hsmmc_set_late_init\n"); + return; + } + pdata = dev->platform_data; + + pdata->init = omap4_twl6030_hsmmc_late_init; +} + +static int __init omap4_twl6030_hsmmc_init(struct omap2_hsmmc_info *controllers) +{ + struct omap2_hsmmc_info *c; + + omap2_hsmmc_init(controllers); + for (c = controllers; c->mmc; c++) + omap4_twl6030_hsmmc_set_late_init(c->dev); + + return 0; +} + +/* Panda board uses the common PMIC configuration */ +static struct twl4030_platform_data omap4_panda_twldata; + +/* + * Display monitor features are burnt in their EEPROM as EDID data. The EEPROM + * is connected as I2C slave device, and can be accessed at address 0x50 + */ +static struct i2c_board_info __initdata panda_i2c_eeprom[] = { + { + I2C_BOARD_INFO("eeprom", 0x50), + }, +}; + +static int __init omap4_panda_i2c_init(void) +{ + omap4_pmic_get_config(&omap4_panda_twldata, TWL_COMMON_PDATA_USB, + TWL_COMMON_REGULATOR_VDAC | + TWL_COMMON_REGULATOR_VAUX2 | + TWL_COMMON_REGULATOR_VAUX3 | + TWL_COMMON_REGULATOR_VMMC | + TWL_COMMON_REGULATOR_VPP | + TWL_COMMON_REGULATOR_VANA | + TWL_COMMON_REGULATOR_VCXIO | + TWL_COMMON_REGULATOR_VUSB | + TWL_COMMON_REGULATOR_CLK32KG); + omap4_pmic_init("twl6030", &omap4_panda_twldata); + omap_register_i2c_bus(2, 400, NULL, 0); + /* + * Bus 3 is attached to the DVI port where devices like the pico DLP + * projector don't work reliably with 400kHz + */ + omap_register_i2c_bus(3, 100, panda_i2c_eeprom, + ARRAY_SIZE(panda_i2c_eeprom)); + omap_register_i2c_bus(4, 400, NULL, 0); + return 0; +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* WLAN IRQ - GPIO 53 */ + OMAP4_MUX(GPMC_NCS3, OMAP_MUX_MODE3 | OMAP_PIN_INPUT), + /* WLAN POWER ENABLE - GPIO 43 */ + OMAP4_MUX(GPMC_A19, OMAP_MUX_MODE3 | OMAP_PIN_OUTPUT), + /* WLAN SDIO: MMC5 CMD */ + OMAP4_MUX(SDMMC5_CMD, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + /* WLAN SDIO: MMC5 CLK */ + OMAP4_MUX(SDMMC5_CLK, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + /* WLAN SDIO: MMC5 DAT[0-3] */ + OMAP4_MUX(SDMMC5_DAT0, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(SDMMC5_DAT1, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(SDMMC5_DAT2, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + OMAP4_MUX(SDMMC5_DAT3, OMAP_MUX_MODE0 | OMAP_PIN_INPUT_PULLUP), + /* gpio 0 - TFP410 PD */ + OMAP4_MUX(KPD_COL1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE3), + /* dispc2_data23 */ + OMAP4_MUX(USBB2_ULPITLL_STP, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data22 */ + OMAP4_MUX(USBB2_ULPITLL_DIR, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data21 */ + OMAP4_MUX(USBB2_ULPITLL_NXT, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data20 */ + OMAP4_MUX(USBB2_ULPITLL_DAT0, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data19 */ + OMAP4_MUX(USBB2_ULPITLL_DAT1, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data18 */ + OMAP4_MUX(USBB2_ULPITLL_DAT2, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data15 */ + OMAP4_MUX(USBB2_ULPITLL_DAT3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data14 */ + OMAP4_MUX(USBB2_ULPITLL_DAT4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data13 */ + OMAP4_MUX(USBB2_ULPITLL_DAT5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data12 */ + OMAP4_MUX(USBB2_ULPITLL_DAT6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data11 */ + OMAP4_MUX(USBB2_ULPITLL_DAT7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data10 */ + OMAP4_MUX(DPM_EMU3, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data9 */ + OMAP4_MUX(DPM_EMU4, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data16 */ + OMAP4_MUX(DPM_EMU5, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data17 */ + OMAP4_MUX(DPM_EMU6, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_hsync */ + OMAP4_MUX(DPM_EMU7, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_pclk */ + OMAP4_MUX(DPM_EMU8, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_vsync */ + OMAP4_MUX(DPM_EMU9, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_de */ + OMAP4_MUX(DPM_EMU10, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data8 */ + OMAP4_MUX(DPM_EMU11, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data7 */ + OMAP4_MUX(DPM_EMU12, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data6 */ + OMAP4_MUX(DPM_EMU13, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data5 */ + OMAP4_MUX(DPM_EMU14, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data4 */ + OMAP4_MUX(DPM_EMU15, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data3 */ + OMAP4_MUX(DPM_EMU16, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data2 */ + OMAP4_MUX(DPM_EMU17, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data1 */ + OMAP4_MUX(DPM_EMU18, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + /* dispc2_data0 */ + OMAP4_MUX(DPM_EMU19, OMAP_PIN_OUTPUT | OMAP_MUX_MODE5), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +#else +#define board_mux NULL +#endif + +/* Display DVI */ +#define PANDA_DVI_TFP410_POWER_DOWN_GPIO 0 + +static int omap4_panda_enable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(dssdev->reset_gpio, 1); + return 0; +} + +static void omap4_panda_disable_dvi(struct omap_dss_device *dssdev) +{ + gpio_set_value(dssdev->reset_gpio, 0); +} + +/* Using generic display panel */ +static struct panel_dvi_platform_data omap4_dvi_panel = { + .platform_enable = omap4_panda_enable_dvi, + .platform_disable = omap4_panda_disable_dvi, + .i2c_bus_num = 3, +}; + +struct omap_dss_device omap4_panda_dvi_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "dvi", + .driver_name = "dvi", + .data = &omap4_dvi_panel, + .phy.dpi.data_lines = 24, + .reset_gpio = PANDA_DVI_TFP410_POWER_DOWN_GPIO, + .channel = OMAP_DSS_CHANNEL_LCD2, +}; + +int __init omap4_panda_dvi_init(void) +{ + int r; + + /* Requesting TFP410 DVI GPIO and disabling it, at bootup */ + r = gpio_request_one(omap4_panda_dvi_device.reset_gpio, + GPIOF_OUT_INIT_LOW, "DVI PD"); + if (r) + pr_err("Failed to get DVI powerdown GPIO\n"); + + return r; +} + +static struct gpio panda_hdmi_gpios[] = { + { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, + { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, +}; + +static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) +{ + int status; + + status = gpio_request_array(panda_hdmi_gpios, + ARRAY_SIZE(panda_hdmi_gpios)); + if (status) + pr_err("Cannot request HDMI GPIOs\n"); + + return status; +} + +static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev) +{ + gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios)); +} + +static struct omap_dss_hdmi_data omap4_panda_hdmi_data = { + .hpd_gpio = HDMI_GPIO_HPD, +}; + +static struct omap_dss_device omap4_panda_hdmi_device = { + .name = "hdmi", + .driver_name = "hdmi_panel", + .type = OMAP_DISPLAY_TYPE_HDMI, + .platform_enable = omap4_panda_panel_enable_hdmi, + .platform_disable = omap4_panda_panel_disable_hdmi, + .channel = OMAP_DSS_CHANNEL_DIGIT, + .data = &omap4_panda_hdmi_data, +}; + +static struct omap_dss_device *omap4_panda_dss_devices[] = { + &omap4_panda_dvi_device, + &omap4_panda_hdmi_device, +}; + +static struct omap_dss_board_info omap4_panda_dss_data = { + .num_devices = ARRAY_SIZE(omap4_panda_dss_devices), + .devices = omap4_panda_dss_devices, + .default_device = &omap4_panda_dvi_device, +}; + +void omap4_panda_display_init(void) +{ + int r; + + r = omap4_panda_dvi_init(); + if (r) + pr_err("error initializing panda DVI\n"); + + omap_display_init(&omap4_panda_dss_data); + + /* + * OMAP4460SDP/Blaze and OMAP4430 ES2.3 SDP/Blaze boards and + * later have external pull up on the HDMI I2C lines + */ + if (cpu_is_omap446x() || omap_rev() > OMAP4430_REV_ES2_2) + omap_hdmi_init(OMAP_HDMI_SDA_SCL_EXTERNAL_PULLUP); + else + omap_hdmi_init(0); + + omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); +} + +static void __init omap4_panda_init(void) +{ + int package = OMAP_PACKAGE_CBS; + int ret; + + if (omap_rev() == OMAP4430_REV_ES1_0) + package = OMAP_PACKAGE_CBL; + omap4_mux_init(board_mux, NULL, package); + + ret = wl12xx_set_platform_data(&omap_panda_wlan_data); + if (ret) + pr_err("error setting wl12xx data: %d\n", ret); + + omap4_panda_i2c_init(); + platform_add_devices(panda_devices, ARRAY_SIZE(panda_devices)); + platform_device_register(&omap_vwlan_device); + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + omap4_twl6030_hsmmc_init(mmc); + omap4_ehci_init(); + usb_musb_init(&musb_board_data); + omap4_panda_display_init(); +} + +MACHINE_START(OMAP4_PANDA, "OMAP4 Panda board") + /* Maintainer: David Anders - Texas Instruments Inc */ + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap4_map_io, + .init_early = omap4430_init_early, + .init_irq = gic_init_irq, + .handle_irq = gic_handle_irq, + .init_machine = omap4_panda_init, + .timer = &omap4_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c new file mode 100644 index 00000000000..52c0cef7716 --- /dev/null +++ b/arch/arm/mach-omap2/board-overo.c @@ -0,0 +1,569 @@ +/* + * board-overo.c (Gumstix Overo) + * + * Initial code: Steve Sakoman <steve@sakoman.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. + * + * 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/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/spi/spi.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/mmc/host.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/flash.h> +#include <asm/mach/map.h> + +#include <plat/board.h> +#include "common.h" +#include <video/omapdss.h> +#include <video/omap-panel-generic-dpi.h> +#include <video/omap-panel-dvi.h> +#include <plat/gpmc.h> +#include <mach/hardware.h> +#include <plat/nand.h> +#include <plat/mcspi.h> +#include <plat/mux.h> +#include <plat/usb.h> + +#include "mux.h" +#include "sdram-micron-mt46h32m32lf-6.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define OVERO_GPIO_BT_XGATE 15 +#define OVERO_GPIO_W2W_NRESET 16 +#define OVERO_GPIO_PENDOWN 114 +#define OVERO_GPIO_BT_NRESET 164 +#define OVERO_GPIO_USBH_CPEN 168 +#define OVERO_GPIO_USBH_NRESET 183 + +#define OVERO_SMSC911X_CS 5 +#define OVERO_SMSC911X_GPIO 176 +#define OVERO_SMSC911X2_CS 4 +#define OVERO_SMSC911X2_GPIO 65 + +#if defined(CONFIG_TOUCHSCREEN_ADS7846) || \ + defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE) + +/* fixed regulator for ads7846 */ +static struct regulator_consumer_supply ads7846_supply[] = { + REGULATOR_SUPPLY("vcc", "spi1.0"), +}; + +static struct regulator_init_data vads7846_regulator = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(ads7846_supply), + .consumer_supplies = ads7846_supply, +}; + +static struct fixed_voltage_config vads7846 = { + .supply_name = "vads7846", + .microvolts = 3300000, /* 3.3V */ + .gpio = -EINVAL, + .startup_delay = 0, + .init_data = &vads7846_regulator, +}; + +static struct platform_device vads7846_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &vads7846, + }, +}; + +static void __init overo_ads7846_init(void) +{ + omap_ads7846_init(1, OVERO_GPIO_PENDOWN, 0, NULL); + platform_device_register(&vads7846_device); +} + +#else +static inline void __init overo_ads7846_init(void) { return; } +#endif + +#if defined(CONFIG_SMSC911X) || defined(CONFIG_SMSC911X_MODULE) + +#include <linux/smsc911x.h> +#include <plat/gpmc-smsc911x.h> + +static struct omap_smsc911x_platform_data smsc911x_cfg = { + .id = 0, + .cs = OVERO_SMSC911X_CS, + .gpio_irq = OVERO_SMSC911X_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT, +}; + +static struct omap_smsc911x_platform_data smsc911x2_cfg = { + .id = 1, + .cs = OVERO_SMSC911X2_CS, + .gpio_irq = OVERO_SMSC911X2_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT, +}; + +static void __init overo_init_smsc911x(void) +{ + gpmc_smsc911x_init(&smsc911x_cfg); + gpmc_smsc911x_init(&smsc911x2_cfg); +} + +#else +static inline void __init overo_init_smsc911x(void) { return; } +#endif + +/* DSS */ +static int lcd_enabled; +static int dvi_enabled; + +#define OVERO_GPIO_LCD_EN 144 +#define OVERO_GPIO_LCD_BL 145 + +static struct gpio overo_dss_gpios[] __initdata = { + { OVERO_GPIO_LCD_EN, GPIOF_OUT_INIT_HIGH, "OVERO_GPIO_LCD_EN" }, + { OVERO_GPIO_LCD_BL, GPIOF_OUT_INIT_HIGH, "OVERO_GPIO_LCD_BL" }, +}; + +static void __init overo_display_init(void) +{ + if (gpio_request_array(overo_dss_gpios, ARRAY_SIZE(overo_dss_gpios))) { + printk(KERN_ERR "could not obtain DSS control GPIOs\n"); + return; + } + + gpio_export(OVERO_GPIO_LCD_EN, 0); + gpio_export(OVERO_GPIO_LCD_BL, 0); +} + +static int overo_panel_enable_dvi(struct omap_dss_device *dssdev) +{ + if (lcd_enabled) { + printk(KERN_ERR "cannot enable DVI, LCD is enabled\n"); + return -EINVAL; + } + dvi_enabled = 1; + + return 0; +} + +static void overo_panel_disable_dvi(struct omap_dss_device *dssdev) +{ + dvi_enabled = 0; +} + +static struct panel_dvi_platform_data dvi_panel = { + .platform_enable = overo_panel_enable_dvi, + .platform_disable = overo_panel_disable_dvi, + .i2c_bus_num = 3, +}; + +static struct omap_dss_device overo_dvi_device = { + .name = "dvi", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "dvi", + .data = &dvi_panel, + .phy.dpi.data_lines = 24, +}; + +static struct omap_dss_device overo_tv_device = { + .name = "tv", + .driver_name = "venc", + .type = OMAP_DISPLAY_TYPE_VENC, + .phy.venc.type = OMAP_DSS_VENC_TYPE_SVIDEO, +}; + +static int overo_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + if (dvi_enabled) { + printk(KERN_ERR "cannot enable LCD, DVI is enabled\n"); + return -EINVAL; + } + + gpio_set_value(OVERO_GPIO_LCD_EN, 1); + gpio_set_value(OVERO_GPIO_LCD_BL, 1); + lcd_enabled = 1; + return 0; +} + +static void overo_panel_disable_lcd(struct omap_dss_device *dssdev) +{ + gpio_set_value(OVERO_GPIO_LCD_EN, 0); + gpio_set_value(OVERO_GPIO_LCD_BL, 0); + lcd_enabled = 0; +} + +static struct panel_generic_dpi_data lcd43_panel = { + .name = "samsung_lte430wq_f0c", + .platform_enable = overo_panel_enable_lcd, + .platform_disable = overo_panel_disable_lcd, +}; + +static struct omap_dss_device overo_lcd43_device = { + .name = "lcd43", + .type = OMAP_DISPLAY_TYPE_DPI, + .driver_name = "generic_dpi_panel", + .data = &lcd43_panel, + .phy.dpi.data_lines = 24, +}; + +#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \ + defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE) +static struct omap_dss_device overo_lcd35_device = { + .type = OMAP_DISPLAY_TYPE_DPI, + .name = "lcd35", + .driver_name = "lgphilips_lb035q02_panel", + .phy.dpi.data_lines = 24, + .platform_enable = overo_panel_enable_lcd, + .platform_disable = overo_panel_disable_lcd, +}; +#endif + +static struct omap_dss_device *overo_dss_devices[] = { + &overo_dvi_device, + &overo_tv_device, +#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \ + defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE) + &overo_lcd35_device, +#endif + &overo_lcd43_device, +}; + +static struct omap_dss_board_info overo_dss_data = { + .num_devices = ARRAY_SIZE(overo_dss_devices), + .devices = overo_dss_devices, + .default_device = &overo_dvi_device, +}; + +static struct mtd_partition overo_nand_partitions[] = { + { + .name = "xloader", + .offset = 0, /* Offset = 0x00000 */ + .size = 4 * NAND_BLOCK_SIZE, + .mask_flags = MTD_WRITEABLE + }, + { + .name = "uboot", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 14 * NAND_BLOCK_SIZE, + }, + { + .name = "uboot environment", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x240000 */ + .size = 2 * NAND_BLOCK_SIZE, + }, + { + .name = "linux", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */ + .size = 32 * NAND_BLOCK_SIZE, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x680000 */ + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + { + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .transceiver = true, + .ocr_mask = 0x00100000, /* 3.3V */ + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply overo_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) +#include <linux/leds.h> + +static struct gpio_led gpio_leds[] = { + { + .name = "overo:red:gpio21", + .default_trigger = "heartbeat", + .gpio = 21, + .active_low = true, + }, + { + .name = "overo:blue:gpio22", + .default_trigger = "none", + .gpio = 22, + .active_low = true, + }, + { + .name = "overo:blue:COM", + .default_trigger = "mmc0", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + }, +}; + +static struct gpio_led_platform_data gpio_leds_pdata = { + .leds = gpio_leds, + .num_leds = ARRAY_SIZE(gpio_leds), +}; + +static struct platform_device gpio_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &gpio_leds_pdata, + }, +}; + +static void __init overo_init_led(void) +{ + platform_device_register(&gpio_leds_device); +} + +#else +static inline void __init overo_init_led(void) { return; } +#endif + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) +#include <linux/input.h> +#include <linux/gpio_keys.h> + +static struct gpio_keys_button gpio_buttons[] = { + { + .code = BTN_0, + .gpio = 23, + .desc = "button0", + .wakeup = 1, + }, + { + .code = BTN_1, + .gpio = 14, + .desc = "button1", + .wakeup = 1, + }, +}; + +static struct gpio_keys_platform_data gpio_keys_pdata = { + .buttons = gpio_buttons, + .nbuttons = ARRAY_SIZE(gpio_buttons), +}; + +static struct platform_device gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &gpio_keys_pdata, + }, +}; + +static void __init overo_init_keys(void) +{ + platform_device_register(&gpio_keys_device); +} + +#else +static inline void __init overo_init_keys(void) { return; } +#endif + +static int overo_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + omap2_hsmmc_init(mmc); + +#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE) + /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; +#endif + + return 0; +} + +static struct twl4030_gpio_platform_data overo_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .setup = overo_twl_gpio_setup, +}; + +static struct regulator_init_data overo_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(overo_vmmc1_supply), + .consumer_supplies = overo_vmmc1_supply, +}; + +static struct twl4030_platform_data overo_twldata = { + .gpio = &overo_gpio_data, + .vmmc1 = &overo_vmmc1, +}; + +static int __init overo_i2c_init(void) +{ + omap3_pmic_get_config(&overo_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + overo_twldata.vpll2->constraints.name = "VDVI"; + + omap3_pmic_init("tps65950", &overo_twldata); + /* i2c2 pins are used for gpio */ + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static struct spi_board_info overo_spi_board_info[] __initdata = { +#if defined(CONFIG_PANEL_LGPHILIPS_LB035Q02) || \ + defined(CONFIG_PANEL_LGPHILIPS_LB035Q02_MODULE) + { + .modalias = "lgphilips_lb035q02_panel-spi", + .bus_num = 1, + .chip_select = 1, + .max_speed_hz = 500000, + .mode = SPI_MODE_3, + }, +#endif +}; + +static int __init overo_spi_init(void) +{ + overo_ads7846_init(); + spi_register_board_info(overo_spi_board_info, + ARRAY_SIZE(overo_spi_board_info)); + return 0; +} + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = OVERO_GPIO_USBH_NRESET, + .reset_gpio_port[2] = -EINVAL +}; + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static struct gpio overo_bt_gpios[] __initdata = { + { OVERO_GPIO_BT_XGATE, GPIOF_OUT_INIT_LOW, "lcd enable" }, + { OVERO_GPIO_BT_NRESET, GPIOF_OUT_INIT_HIGH, "lcd bl enable" }, +}; + +static void __init overo_init(void) +{ + int ret; + + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + overo_i2c_init(); + omap_display_init(&overo_dss_data); + omap_serial_init(); + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + omap_nand_flash_init(0, overo_nand_partitions, + ARRAY_SIZE(overo_nand_partitions)); + usb_musb_init(NULL); + usbhs_init(&usbhs_bdata); + overo_spi_init(); + overo_init_smsc911x(); + overo_display_init(); + overo_init_led(); + overo_init_keys(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); + + ret = gpio_request_one(OVERO_GPIO_W2W_NRESET, GPIOF_OUT_INIT_HIGH, + "OVERO_GPIO_W2W_NRESET"); + if (ret == 0) { + gpio_export(OVERO_GPIO_W2W_NRESET, 0); + gpio_set_value(OVERO_GPIO_W2W_NRESET, 0); + udelay(10); + gpio_set_value(OVERO_GPIO_W2W_NRESET, 1); + } else { + printk(KERN_ERR "could not obtain gpio for " + "OVERO_GPIO_W2W_NRESET\n"); + } + + ret = gpio_request_array(overo_bt_gpios, ARRAY_SIZE(overo_bt_gpios)); + if (ret) { + pr_err("%s: could not obtain BT gpios\n", __func__); + } else { + gpio_export(OVERO_GPIO_BT_XGATE, 0); + gpio_export(OVERO_GPIO_BT_NRESET, 0); + gpio_set_value(OVERO_GPIO_BT_NRESET, 0); + mdelay(6); + gpio_set_value(OVERO_GPIO_BT_NRESET, 1); + } + + ret = gpio_request_one(OVERO_GPIO_USBH_CPEN, GPIOF_OUT_INIT_HIGH, + "OVERO_GPIO_USBH_CPEN"); + if (ret == 0) + gpio_export(OVERO_GPIO_USBH_CPEN, 0); + else + printk(KERN_ERR "could not obtain gpio for " + "OVERO_GPIO_USBH_CPEN\n"); +} + +MACHINE_START(OVERO, "Gumstix Overo") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap35xx_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = overo_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-rm680.c b/arch/arm/mach-omap2/board-rm680.c new file mode 100644 index 00000000000..8678b386c6a --- /dev/null +++ b/arch/arm/mach-omap2/board-rm680.c @@ -0,0 +1,156 @@ +/* + * Board support file for Nokia RM-680. + * + * Copyright (C) 2010 Nokia + * + * 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/io.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/i2c/twl.h> +#include <linux/platform_device.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/consumer.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <plat/i2c.h> +#include <plat/mmc.h> +#include <plat/usb.h> +#include <plat/gpmc.h> +#include "common.h" +#include <plat/onenand.h> + +#include "mux.h" +#include "hsmmc.h" +#include "sdram-nokia.h" +#include "common-board-devices.h" + +static struct regulator_consumer_supply rm680_vemmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +/* Fixed regulator for internal eMMC */ +static struct regulator_init_data rm680_vemmc = { + .constraints = { + .name = "rm680_vemmc", + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_STATUS + | REGULATOR_CHANGE_MODE, + }, + .num_consumer_supplies = ARRAY_SIZE(rm680_vemmc_consumers), + .consumer_supplies = rm680_vemmc_consumers, +}; + +static struct fixed_voltage_config rm680_vemmc_config = { + .supply_name = "VEMMC", + .microvolts = 2900000, + .gpio = 157, + .startup_delay = 150, + .enable_high = 1, + .init_data = &rm680_vemmc, +}; + +static struct platform_device rm680_vemmc_device = { + .name = "reg-fixed-voltage", + .dev = { + .platform_data = &rm680_vemmc_config, + }, +}; + +static struct platform_device *rm680_peripherals_devices[] __initdata = { + &rm680_vemmc_device, +}; + +/* TWL */ +static struct twl4030_gpio_platform_data rm680_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .pullups = BIT(0), + .pulldowns = BIT(1) | BIT(2) | BIT(8) | BIT(15), +}; + +static struct twl4030_platform_data rm680_twl_data = { + .gpio = &rm680_gpio_data, + /* add rest of the children here */ +}; + +static void __init rm680_i2c_init(void) +{ + omap3_pmic_get_config(&rm680_twl_data, TWL_COMMON_PDATA_USB, 0); + omap_pmic_init(1, 2900, "twl5031", INT_34XX_SYS_NIRQ, &rm680_twl_data); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, NULL, 0); +} + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) +static struct omap_onenand_platform_data board_onenand_data[] = { + { + .gpio_irq = 65, + .flags = ONENAND_SYNC_READWRITE, + } +}; +#endif + +/* eMMC */ +static struct omap2_hsmmc_info mmc[] __initdata = { + { + .name = "internal", + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + { /* Terminator */ } +}; + +static void __init rm680_peripherals_init(void) +{ + platform_add_devices(rm680_peripherals_devices, + ARRAY_SIZE(rm680_peripherals_devices)); + rm680_i2c_init(); + gpmc_onenand_init(board_onenand_data); + omap2_hsmmc_init(mmc); +} + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static void __init rm680_init(void) +{ + struct omap_sdrc_params *sdrc_params; + + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap_serial_init(); + + sdrc_params = nokia_get_sdram_timings(); + omap_sdrc_init(sdrc_params, sdrc_params); + + usb_musb_init(NULL); + rm680_peripherals_init(); +} + +MACHINE_START(NOKIA_RM680, "Nokia RM-680 board") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3630_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = rm680_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c new file mode 100644 index 00000000000..acb4e77b39e --- /dev/null +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -0,0 +1,1152 @@ +/* + * linux/arch/arm/mach-omap2/board-rx51-peripherals.c + * + * Copyright (C) 2008-2009 Nokia + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/spi/spi.h> +#include <linux/wl12xx.h> +#include <linux/spi/tsc2005.h> +#include <linux/i2c.h> +#include <linux/i2c/twl.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/regulator/machine.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/mmc/host.h> +#include <linux/power/isp1704_charger.h> + +#include <plat/mcspi.h> +#include <plat/board.h> +#include "common.h" +#include <plat/dma.h> +#include <plat/gpmc.h> +#include <plat/onenand.h> +#include <plat/gpmc-smc91x.h> + +#include <mach/board-rx51.h> + +#include <sound/tlv320aic3x.h> +#include <sound/tpa6130a2-plat.h> +#include <media/radio-si4713.h> +#include <media/si4713.h> +#include <linux/leds-lp5523.h> + +#include <../drivers/staging/iio/light/tsl2563.h> + +#include "mux.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define SYSTEM_REV_B_USES_VAUX3 0x1699 +#define SYSTEM_REV_S_USES_VAUX3 0x8 + +#define RX51_WL1251_POWER_GPIO 87 +#define RX51_WL1251_IRQ_GPIO 42 +#define RX51_FMTX_RESET_GPIO 163 +#define RX51_FMTX_IRQ 53 +#define RX51_LP5523_CHIP_EN_GPIO 41 + +#define RX51_USB_TRANSCEIVER_RST_GPIO 67 + +#define RX51_TSC2005_RESET_GPIO 104 +#define RX51_TSC2005_IRQ_GPIO 100 + +/* list all spi devices here */ +enum { + RX51_SPI_WL1251, + RX51_SPI_MIPID, /* LCD panel */ + RX51_SPI_TSC2005, /* Touch Controller */ +}; + +static struct wl12xx_platform_data wl1251_pdata; +static struct tsc2005_platform_data tsc2005_pdata; + +#if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE) +static struct tsl2563_platform_data rx51_tsl2563_platform_data = { + .cover_comp_gain = 16, +}; +#endif + +#if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE) +static struct lp5523_led_config rx51_lp5523_led_config[] = { + { + .chan_nr = 0, + .led_current = 50, + }, { + .chan_nr = 1, + .led_current = 50, + }, { + .chan_nr = 2, + .led_current = 50, + }, { + .chan_nr = 3, + .led_current = 50, + }, { + .chan_nr = 4, + .led_current = 50, + }, { + .chan_nr = 5, + .led_current = 50, + }, { + .chan_nr = 6, + .led_current = 50, + }, { + .chan_nr = 7, + .led_current = 50, + }, { + .chan_nr = 8, + .led_current = 50, + } +}; + +static int rx51_lp5523_setup(void) +{ + return gpio_request_one(RX51_LP5523_CHIP_EN_GPIO, GPIOF_DIR_OUT, + "lp5523_enable"); +} + +static void rx51_lp5523_release(void) +{ + gpio_free(RX51_LP5523_CHIP_EN_GPIO); +} + +static void rx51_lp5523_enable(bool state) +{ + gpio_set_value(RX51_LP5523_CHIP_EN_GPIO, !!state); +} + +static struct lp5523_platform_data rx51_lp5523_platform_data = { + .led_config = rx51_lp5523_led_config, + .num_channels = ARRAY_SIZE(rx51_lp5523_led_config), + .clock_mode = LP5523_CLOCK_AUTO, + .setup_resources = rx51_lp5523_setup, + .release_resources = rx51_lp5523_release, + .enable = rx51_lp5523_enable, +}; +#endif + +static struct omap2_mcspi_device_config wl1251_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct omap2_mcspi_device_config mipid_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct omap2_mcspi_device_config tsc2005_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, +}; + +static struct spi_board_info rx51_peripherals_spi_board_info[] __initdata = { + [RX51_SPI_WL1251] = { + .modalias = "wl1251", + .bus_num = 4, + .chip_select = 0, + .max_speed_hz = 48000000, + .mode = SPI_MODE_3, + .controller_data = &wl1251_mcspi_config, + .platform_data = &wl1251_pdata, + }, + [RX51_SPI_MIPID] = { + .modalias = "acx565akm", + .bus_num = 1, + .chip_select = 2, + .max_speed_hz = 6000000, + .controller_data = &mipid_mcspi_config, + }, + [RX51_SPI_TSC2005] = { + .modalias = "tsc2005", + .bus_num = 1, + .chip_select = 0, + .irq = OMAP_GPIO_IRQ(RX51_TSC2005_IRQ_GPIO), + .max_speed_hz = 6000000, + .controller_data = &tsc2005_mcspi_config, + .platform_data = &tsc2005_pdata, + }, +}; + +static void rx51_charger_set_power(bool on) +{ + gpio_set_value(RX51_USB_TRANSCEIVER_RST_GPIO, on); +} + +static struct isp1704_charger_data rx51_charger_data = { + .set_power = rx51_charger_set_power, +}; + +static struct platform_device rx51_charger_device = { + .name = "isp1704_charger", + .dev = { + .platform_data = &rx51_charger_data, + }, +}; + +static void __init rx51_charger_init(void) +{ + WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO, + GPIOF_OUT_INIT_HIGH, "isp1704_reset")); + + platform_device_register(&rx51_charger_device); +} + +#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE) + +#define RX51_GPIO_CAMERA_LENS_COVER 110 +#define RX51_GPIO_CAMERA_FOCUS 68 +#define RX51_GPIO_CAMERA_CAPTURE 69 +#define RX51_GPIO_KEYPAD_SLIDE 71 +#define RX51_GPIO_LOCK_BUTTON 113 +#define RX51_GPIO_PROXIMITY 89 + +#define RX51_GPIO_DEBOUNCE_TIMEOUT 10 + +static struct gpio_keys_button rx51_gpio_keys[] = { + { + .desc = "Camera Lens Cover", + .type = EV_SW, + .code = SW_CAMERA_LENS_COVER, + .gpio = RX51_GPIO_CAMERA_LENS_COVER, + .active_low = 1, + .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, + }, { + .desc = "Camera Focus", + .type = EV_KEY, + .code = KEY_CAMERA_FOCUS, + .gpio = RX51_GPIO_CAMERA_FOCUS, + .active_low = 1, + .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, + }, { + .desc = "Camera Capture", + .type = EV_KEY, + .code = KEY_CAMERA, + .gpio = RX51_GPIO_CAMERA_CAPTURE, + .active_low = 1, + .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, + }, { + .desc = "Lock Button", + .type = EV_KEY, + .code = KEY_SCREENLOCK, + .gpio = RX51_GPIO_LOCK_BUTTON, + .active_low = 1, + .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, + }, { + .desc = "Keypad Slide", + .type = EV_SW, + .code = SW_KEYPAD_SLIDE, + .gpio = RX51_GPIO_KEYPAD_SLIDE, + .active_low = 1, + .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, + }, { + .desc = "Proximity Sensor", + .type = EV_SW, + .code = SW_FRONT_PROXIMITY, + .gpio = RX51_GPIO_PROXIMITY, + .active_low = 0, + .debounce_interval = RX51_GPIO_DEBOUNCE_TIMEOUT, + } +}; + +static struct gpio_keys_platform_data rx51_gpio_keys_data = { + .buttons = rx51_gpio_keys, + .nbuttons = ARRAY_SIZE(rx51_gpio_keys), +}; + +static struct platform_device rx51_gpio_keys_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = &rx51_gpio_keys_data, + }, +}; + +static void __init rx51_add_gpio_keys(void) +{ + platform_device_register(&rx51_gpio_keys_device); +} +#else +static void __init rx51_add_gpio_keys(void) +{ +} +#endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */ + +static uint32_t board_keymap[] = { + /* + * Note that KEY(x, 8, KEY_XXX) entries represent "entrire row + * connected to the ground" matrix state. + */ + KEY(0, 0, KEY_Q), + KEY(0, 1, KEY_O), + KEY(0, 2, KEY_P), + KEY(0, 3, KEY_COMMA), + KEY(0, 4, KEY_BACKSPACE), + KEY(0, 6, KEY_A), + KEY(0, 7, KEY_S), + + KEY(1, 0, KEY_W), + KEY(1, 1, KEY_D), + KEY(1, 2, KEY_F), + KEY(1, 3, KEY_G), + KEY(1, 4, KEY_H), + KEY(1, 5, KEY_J), + KEY(1, 6, KEY_K), + KEY(1, 7, KEY_L), + + KEY(2, 0, KEY_E), + KEY(2, 1, KEY_DOT), + KEY(2, 2, KEY_UP), + KEY(2, 3, KEY_ENTER), + KEY(2, 5, KEY_Z), + KEY(2, 6, KEY_X), + KEY(2, 7, KEY_C), + KEY(2, 8, KEY_F9), + + KEY(3, 0, KEY_R), + KEY(3, 1, KEY_V), + KEY(3, 2, KEY_B), + KEY(3, 3, KEY_N), + KEY(3, 4, KEY_M), + KEY(3, 5, KEY_SPACE), + KEY(3, 6, KEY_SPACE), + KEY(3, 7, KEY_LEFT), + + KEY(4, 0, KEY_T), + KEY(4, 1, KEY_DOWN), + KEY(4, 2, KEY_RIGHT), + KEY(4, 4, KEY_LEFTCTRL), + KEY(4, 5, KEY_RIGHTALT), + KEY(4, 6, KEY_LEFTSHIFT), + KEY(4, 8, KEY_F10), + + KEY(5, 0, KEY_Y), + KEY(5, 8, KEY_F11), + + KEY(6, 0, KEY_U), + + KEY(7, 0, KEY_I), + KEY(7, 1, KEY_F7), + KEY(7, 2, KEY_F8), +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data rx51_kp_data = { + .keymap_data = &board_map_data, + .rows = 8, + .cols = 8, + .rep = 1, +}; + +/* Enable input logic and pull all lines up when eMMC is on. */ +static struct omap_board_mux rx51_mmc2_on_mux[] = { + OMAP3_MUX(SDMMC2_CMD, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT0, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT1, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT2, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT3, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT4, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT5, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT6, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT7, OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE0), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +/* Disable input logic and pull all lines down when eMMC is off. */ +static struct omap_board_mux rx51_mmc2_off_mux[] = { + OMAP3_MUX(SDMMC2_CMD, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT0, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT1, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT2, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT3, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT4, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT5, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT6, OMAP_PULL_ENA | OMAP_MUX_MODE0), + OMAP3_MUX(SDMMC2_DAT7, OMAP_PULL_ENA | OMAP_MUX_MODE0), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; + +static struct omap_mux_partition *partition; + +/* + * Current flows to eMMC when eMMC is off and the data lines are pulled up, + * so pull them down. N.B. we pull 8 lines because we are using 8 lines. + */ +static void rx51_mmc2_remux(struct device *dev, int slot, int power_on) +{ + if (power_on) + omap_mux_write_array(partition, rx51_mmc2_on_mux); + else + omap_mux_write_array(partition, rx51_mmc2_off_mux); +} + +static struct omap2_hsmmc_info mmc[] __initdata = { + { + .name = "external", + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .cover_only = true, + .gpio_cd = 160, + .gpio_wp = -EINVAL, + .power_saving = true, + }, + { + .name = "internal", + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + /* See also rx51_mmc2_remux */ + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .nonremovable = true, + .power_saving = true, + .remux = rx51_mmc2_remux, + }, + {} /* Terminator */ +}; + +static struct regulator_consumer_supply rx51_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply rx51_vaux2_supply[] = { + REGULATOR_SUPPLY("vdds_csib", "omap3isp"), +}; + +static struct regulator_consumer_supply rx51_vaux3_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +static struct regulator_consumer_supply rx51_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.1"), +}; + +static struct regulator_consumer_supply rx51_vmmc2_supplies[] = { + /* tlv320aic3x analog supplies */ + REGULATOR_SUPPLY("AVDD", "2-0018"), + REGULATOR_SUPPLY("DRVDD", "2-0018"), + REGULATOR_SUPPLY("AVDD", "2-0019"), + REGULATOR_SUPPLY("DRVDD", "2-0019"), + /* tpa6130a2 */ + REGULATOR_SUPPLY("Vdd", "2-0060"), + /* Keep vmmc as last item. It is not iterated for newer boards */ + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +static struct regulator_consumer_supply rx51_vio_supplies[] = { + /* tlv320aic3x digital supplies */ + REGULATOR_SUPPLY("IOVDD", "2-0018"), + REGULATOR_SUPPLY("DVDD", "2-0018"), + REGULATOR_SUPPLY("IOVDD", "2-0019"), + REGULATOR_SUPPLY("DVDD", "2-0019"), + /* Si4713 IO supply */ + REGULATOR_SUPPLY("vio", "2-0063"), +}; + +static struct regulator_consumer_supply rx51_vaux1_consumers[] = { + REGULATOR_SUPPLY("vdds_sdi", "omapdss"), + /* Si4713 supply */ + REGULATOR_SUPPLY("vdd", "2-0063"), +}; + +static struct regulator_init_data rx51_vaux1 = { + .constraints = { + .name = "V28", + .min_uV = 2800000, + .max_uV = 2800000, + .always_on = true, /* due battery cover sensor */ + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vaux1_consumers), + .consumer_supplies = rx51_vaux1_consumers, +}; + +static struct regulator_init_data rx51_vaux2 = { + .constraints = { + .name = "VCSI", + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vaux2_supply), + .consumer_supplies = rx51_vaux2_supply, +}; + +/* VAUX3 - adds more power to VIO_18 rail */ +static struct regulator_init_data rx51_vaux3_cam = { + .constraints = { + .name = "VCAM_DIG_18", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +static struct regulator_init_data rx51_vaux3_mmc = { + .constraints = { + .name = "VMMC2_30", + .min_uV = 2800000, + .max_uV = 3000000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vaux3_supply), + .consumer_supplies = rx51_vaux3_supply, +}; + +static struct regulator_init_data rx51_vaux4 = { + .constraints = { + .name = "VCAM_ANA_28", + .min_uV = 2800000, + .max_uV = 2800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, +}; + +static struct regulator_init_data rx51_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vmmc1_supply), + .consumer_supplies = rx51_vmmc1_supply, +}; + +static struct regulator_init_data rx51_vmmc2 = { + .constraints = { + .name = "V28_A", + .min_uV = 2800000, + .max_uV = 3000000, + .always_on = true, /* due VIO leak to AIC34 VDDs */ + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vmmc2_supplies), + .consumer_supplies = rx51_vmmc2_supplies, +}; + +static struct regulator_init_data rx51_vpll1 = { + .constraints = { + .name = "VPLL", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .always_on = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE, + }, +}; + +static struct regulator_init_data rx51_vpll2 = { + .constraints = { + .name = "VSDI_CSI", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .always_on = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE, + }, +}; + +static struct regulator_init_data rx51_vsim = { + .constraints = { + .name = "VMMC2_IO_18", + .min_uV = 1800000, + .max_uV = 1800000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vsim_supply), + .consumer_supplies = rx51_vsim_supply, +}; + +static struct regulator_init_data rx51_vio = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(rx51_vio_supplies), + .consumer_supplies = rx51_vio_supplies, +}; + +static struct regulator_init_data rx51_vintana1 = { + .constraints = { + .name = "VINTANA1", + .min_uV = 1500000, + .max_uV = 1500000, + .always_on = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE, + }, +}; + +static struct regulator_init_data rx51_vintana2 = { + .constraints = { + .name = "VINTANA2", + .min_uV = 2750000, + .max_uV = 2750000, + .apply_uV = true, + .always_on = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE, + }, +}; + +static struct regulator_init_data rx51_vintdig = { + .constraints = { + .name = "VINTDIG", + .min_uV = 1500000, + .max_uV = 1500000, + .always_on = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE, + }, +}; + +static struct si4713_platform_data rx51_si4713_i2c_data __initdata_or_module = { + .gpio_reset = RX51_FMTX_RESET_GPIO, +}; + +static struct i2c_board_info rx51_si4713_board_info __initdata_or_module = { + I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH), + .platform_data = &rx51_si4713_i2c_data, +}; + +static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module = { + .i2c_bus = 2, + .subdev_board_info = &rx51_si4713_board_info, +}; + +static struct platform_device rx51_si4713_dev = { + .name = "radio-si4713", + .id = -1, + .dev = { + .platform_data = &rx51_si4713_data, + }, +}; + +static __init void rx51_init_si4713(void) +{ + int err; + + err = gpio_request_one(RX51_FMTX_IRQ, GPIOF_DIR_IN, "si4713 irq"); + if (err) { + printk(KERN_ERR "Cannot request si4713 irq gpio. %d\n", err); + return; + } + rx51_si4713_board_info.irq = gpio_to_irq(RX51_FMTX_IRQ); + platform_device_register(&rx51_si4713_dev); +} + +static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n) +{ + /* FIXME this gpio setup is just a placeholder for now */ + gpio_request_one(gpio + 6, GPIOF_OUT_INIT_LOW, "backlight_pwm"); + gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "speaker_en"); + + return 0; +} + +static struct twl4030_gpio_platform_data rx51_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .pulldowns = BIT(0) | BIT(1) | BIT(2) | BIT(3) + | BIT(4) | BIT(5) + | BIT(8) | BIT(9) | BIT(10) | BIT(11) + | BIT(12) | BIT(13) | BIT(14) | BIT(15) + | BIT(16) | BIT(17) , + .setup = rx51_twlgpio_setup, +}; + +static struct twl4030_ins sleep_on_seq[] __initdata = { +/* + * Turn off everything + */ + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_SLEEP), 2}, +}; + +static struct twl4030_script sleep_on_script __initdata = { + .script = sleep_on_seq, + .size = ARRAY_SIZE(sleep_on_seq), + .flags = TWL4030_SLEEP_SCRIPT, +}; + +static struct twl4030_ins wakeup_seq[] __initdata = { +/* + * Reenable everything + */ + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2}, +}; + +static struct twl4030_script wakeup_script __initdata = { + .script = wakeup_seq, + .size = ARRAY_SIZE(wakeup_seq), + .flags = TWL4030_WAKEUP12_SCRIPT, +}; + +static struct twl4030_ins wakeup_p3_seq[] __initdata = { +/* + * Reenable everything + */ + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 1, 0, RES_STATE_ACTIVE), 2}, +}; + +static struct twl4030_script wakeup_p3_script __initdata = { + .script = wakeup_p3_seq, + .size = ARRAY_SIZE(wakeup_p3_seq), + .flags = TWL4030_WAKEUP3_SCRIPT, +}; + +static struct twl4030_ins wrst_seq[] __initdata = { +/* + * Reset twl4030. + * Reset VDD1 regulator. + * Reset VDD2 regulator. + * Reset VPLL1 regulator. + * Enable sysclk output. + * Reenable twl4030. + */ + {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_OFF), 2}, + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_ALL, 0, 1, RES_STATE_ACTIVE), + 0x13}, + {MSG_BROADCAST(DEV_GRP_NULL, RES_GRP_PP, 0, 3, RES_STATE_OFF), 0x13}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD1, RES_STATE_WRST), 0x13}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_VDD2, RES_STATE_WRST), 0x13}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_VPLL1, RES_STATE_WRST), 0x35}, + {MSG_SINGULAR(DEV_GRP_P3, RES_HFCLKOUT, RES_STATE_ACTIVE), 2}, + {MSG_SINGULAR(DEV_GRP_NULL, RES_RESET, RES_STATE_ACTIVE), 2}, +}; + +static struct twl4030_script wrst_script __initdata = { + .script = wrst_seq, + .size = ARRAY_SIZE(wrst_seq), + .flags = TWL4030_WRST_SCRIPT, +}; + +static struct twl4030_script *twl4030_scripts[] __initdata = { + /* wakeup12 script should be loaded before sleep script, otherwise a + board might hit retention before loading of wakeup script is + completed. This can cause boot failures depending on timing issues. + */ + &wakeup_script, + &sleep_on_script, + &wakeup_p3_script, + &wrst_script, +}; + +static struct twl4030_resconfig twl4030_rconfig[] __initdata = { + { .resource = RES_VDD1, .devgroup = -1, + .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF, + .remap_sleep = RES_STATE_OFF + }, + { .resource = RES_VDD2, .devgroup = -1, + .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF, + .remap_sleep = RES_STATE_OFF + }, + { .resource = RES_VPLL1, .devgroup = -1, + .type = 1, .type2 = -1, .remap_off = RES_STATE_OFF, + .remap_sleep = RES_STATE_OFF + }, + { .resource = RES_VPLL2, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VAUX1, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VAUX2, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VAUX3, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VAUX4, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VMMC1, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VMMC2, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VDAC, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VSIM, .devgroup = -1, + .type = -1, .type2 = 3, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VINTANA1, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VINTANA2, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VINTDIG, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = -1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_VIO, .devgroup = DEV_GRP_P3, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_CLKEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = 1, .type2 = -1 , .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_REGEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_NRES_PWRON, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_SYSEN, .devgroup = DEV_GRP_P1 | DEV_GRP_P3, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_32KCLKOUT, .devgroup = -1, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_RESET, .devgroup = -1, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { .resource = RES_MAIN_REF, .devgroup = -1, + .type = 1, .type2 = -1, .remap_off = -1, .remap_sleep = -1 + }, + { 0, 0}, +}; + +static struct twl4030_power_data rx51_t2scripts_data __initdata = { + .scripts = twl4030_scripts, + .num = ARRAY_SIZE(twl4030_scripts), + .resource_config = twl4030_rconfig, +}; + +struct twl4030_vibra_data rx51_vibra_data __initdata = { + .coexist = 0, +}; + +struct twl4030_audio_data rx51_audio_data __initdata = { + .audio_mclk = 26000000, + .vibra = &rx51_vibra_data, +}; + +static struct twl4030_platform_data rx51_twldata __initdata = { + /* platform_data for children goes here */ + .gpio = &rx51_gpio_data, + .keypad = &rx51_kp_data, + .power = &rx51_t2scripts_data, + .audio = &rx51_audio_data, + + .vaux1 = &rx51_vaux1, + .vaux2 = &rx51_vaux2, + .vaux4 = &rx51_vaux4, + .vmmc1 = &rx51_vmmc1, + .vpll1 = &rx51_vpll1, + .vpll2 = &rx51_vpll2, + .vsim = &rx51_vsim, + .vintana1 = &rx51_vintana1, + .vintana2 = &rx51_vintana2, + .vintdig = &rx51_vintdig, + .vio = &rx51_vio, +}; + +static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata_or_module = { + .power_gpio = 98, +}; + +/* Audio setup data */ +static struct aic3x_setup_data rx51_aic34_setup = { + .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, + .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, +}; + +static struct aic3x_pdata rx51_aic3x_data = { + .setup = &rx51_aic34_setup, + .gpio_reset = 60, +}; + +static struct aic3x_pdata rx51_aic3x_data2 = { + .gpio_reset = 60, +}; + +static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = { + { + I2C_BOARD_INFO("tlv320aic3x", 0x18), + .platform_data = &rx51_aic3x_data, + }, + { + I2C_BOARD_INFO("tlv320aic3x", 0x19), + .platform_data = &rx51_aic3x_data2, + }, +#if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE) + { + I2C_BOARD_INFO("tsl2563", 0x29), + .platform_data = &rx51_tsl2563_platform_data, + }, +#endif +#if defined(CONFIG_LEDS_LP5523) || defined(CONFIG_LEDS_LP5523_MODULE) + { + I2C_BOARD_INFO("lp5523", 0x32), + .platform_data = &rx51_lp5523_platform_data, + }, +#endif + { + I2C_BOARD_INFO("bq27200", 0x55), + }, + { + I2C_BOARD_INFO("tpa6130a2", 0x60), + .platform_data = &rx51_tpa6130a2_data, + } +}; + +static int __init rx51_i2c_init(void) +{ + if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) || + system_rev >= SYSTEM_REV_B_USES_VAUX3) { + rx51_twldata.vaux3 = &rx51_vaux3_mmc; + /* Only older boards use VMMC2 for internal MMC */ + rx51_vmmc2.num_consumer_supplies--; + } else { + rx51_twldata.vaux3 = &rx51_vaux3_cam; + } + rx51_twldata.vmmc2 = &rx51_vmmc2; + omap3_pmic_get_config(&rx51_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_MADC, + TWL_COMMON_REGULATOR_VDAC); + + rx51_twldata.vdac->constraints.apply_uV = true; + rx51_twldata.vdac->constraints.name = "VDAC"; + + omap_pmic_init(1, 2200, "twl5030", INT_34XX_SYS_NIRQ, &rx51_twldata); + omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2, + ARRAY_SIZE(rx51_peripherals_i2c_board_info_2)); + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +#if defined(CONFIG_MTD_ONENAND_OMAP2) || \ + defined(CONFIG_MTD_ONENAND_OMAP2_MODULE) + +static struct mtd_partition onenand_partitions[] = { + { + .name = "bootloader", + .offset = 0, + .size = 0x20000, + .mask_flags = MTD_WRITEABLE, /* Force read-only */ + }, + { + .name = "config", + .offset = MTDPART_OFS_APPEND, + .size = 0x60000, + }, + { + .name = "log", + .offset = MTDPART_OFS_APPEND, + .size = 0x40000, + }, + { + .name = "kernel", + .offset = MTDPART_OFS_APPEND, + .size = 0x200000, + }, + { + .name = "initfs", + .offset = MTDPART_OFS_APPEND, + .size = 0x200000, + }, + { + .name = "rootfs", + .offset = MTDPART_OFS_APPEND, + .size = MTDPART_SIZ_FULL, + }, +}; + +static struct omap_onenand_platform_data board_onenand_data[] = { + { + .cs = 0, + .gpio_irq = 65, + .parts = onenand_partitions, + .nr_parts = ARRAY_SIZE(onenand_partitions), + .flags = ONENAND_SYNC_READWRITE, + } +}; +#endif + +#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE) + +static struct omap_smc91x_platform_data board_smc91x_data = { + .cs = 1, + .gpio_irq = 54, + .gpio_pwrdwn = 86, + .gpio_reset = 164, + .flags = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL, +}; + +static void __init board_smc91x_init(void) +{ + omap_mux_init_gpio(54, OMAP_PIN_INPUT_PULLDOWN); + omap_mux_init_gpio(86, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(164, OMAP_PIN_OUTPUT); + + gpmc_smc91x_init(&board_smc91x_data); +} + +#else + +static inline void board_smc91x_init(void) +{ +} + +#endif + +static void rx51_wl1251_set_power(bool enable) +{ + gpio_set_value(RX51_WL1251_POWER_GPIO, enable); +} + +static struct gpio rx51_wl1251_gpios[] __initdata = { + { RX51_WL1251_POWER_GPIO, GPIOF_OUT_INIT_LOW, "wl1251 power" }, + { RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" }, +}; + +static void __init rx51_init_wl1251(void) +{ + int irq, ret; + + ret = gpio_request_array(rx51_wl1251_gpios, + ARRAY_SIZE(rx51_wl1251_gpios)); + if (ret < 0) + goto error; + + irq = gpio_to_irq(RX51_WL1251_IRQ_GPIO); + if (irq < 0) + goto err_irq; + + wl1251_pdata.set_power = rx51_wl1251_set_power; + rx51_peripherals_spi_board_info[RX51_SPI_WL1251].irq = irq; + + return; + +err_irq: + gpio_free(RX51_WL1251_IRQ_GPIO); + gpio_free(RX51_WL1251_POWER_GPIO); +error: + printk(KERN_ERR "wl1251 board initialisation failed\n"); + wl1251_pdata.set_power = NULL; + + /* + * Now rx51_peripherals_spi_board_info[1].irq is zero and + * set_power is null, and wl1251_probe() will fail. + */ +} + +static struct tsc2005_platform_data tsc2005_pdata = { + .ts_pressure_max = 2048, + .ts_pressure_fudge = 2, + .ts_x_max = 4096, + .ts_x_fudge = 4, + .ts_y_max = 4096, + .ts_y_fudge = 7, + .ts_x_plate_ohm = 280, + .esd_timeout_ms = 8000, +}; + +static void rx51_tsc2005_set_reset(bool enable) +{ + gpio_set_value(RX51_TSC2005_RESET_GPIO, enable); +} + +static void __init rx51_init_tsc2005(void) +{ + int r; + + r = gpio_request_one(RX51_TSC2005_IRQ_GPIO, GPIOF_IN, "tsc2005 IRQ"); + if (r < 0) { + printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 IRQ"); + rx51_peripherals_spi_board_info[RX51_SPI_TSC2005].irq = 0; + } + + r = gpio_request_one(RX51_TSC2005_RESET_GPIO, GPIOF_OUT_INIT_HIGH, + "tsc2005 reset"); + if (r >= 0) { + tsc2005_pdata.set_reset = rx51_tsc2005_set_reset; + } else { + printk(KERN_ERR "unable to get %s GPIO\n", "tsc2005 reset"); + tsc2005_pdata.esd_timeout_ms = 0; + } +} + +void __init rx51_peripherals_init(void) +{ + rx51_i2c_init(); + regulator_has_full_constraints(); + gpmc_onenand_init(board_onenand_data); + board_smc91x_init(); + rx51_add_gpio_keys(); + rx51_init_wl1251(); + rx51_init_tsc2005(); + rx51_init_si4713(); + spi_register_board_info(rx51_peripherals_spi_board_info, + ARRAY_SIZE(rx51_peripherals_spi_board_info)); + + partition = omap_mux_get("core"); + if (partition) + omap2_hsmmc_init(mmc); + + rx51_charger_init(); +} + diff --git a/arch/arm/mach-omap2/board-rx51-video.c b/arch/arm/mach-omap2/board-rx51-video.c new file mode 100644 index 00000000000..2c1289bd5e6 --- /dev/null +++ b/arch/arm/mach-omap2/board-rx51-video.c @@ -0,0 +1,103 @@ +/* + * linux/arch/arm/mach-omap2/board-rx51-video.c + * + * Copyright (C) 2010 Nokia + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/spi/spi.h> +#include <linux/mm.h> +#include <asm/mach-types.h> +#include <video/omapdss.h> +#include <plat/vram.h> +#include <plat/mcspi.h> + +#include <mach/board-rx51.h> + +#include "mux.h" + +#define RX51_LCD_RESET_GPIO 90 + +#if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) + +static int rx51_lcd_enable(struct omap_dss_device *dssdev) +{ + gpio_set_value(dssdev->reset_gpio, 1); + return 0; +} + +static void rx51_lcd_disable(struct omap_dss_device *dssdev) +{ + gpio_set_value(dssdev->reset_gpio, 0); +} + +static struct omap_dss_device rx51_lcd_device = { + .name = "lcd", + .driver_name = "panel-acx565akm", + .type = OMAP_DISPLAY_TYPE_SDI, + .phy.sdi.datapairs = 2, + .reset_gpio = RX51_LCD_RESET_GPIO, + .platform_enable = rx51_lcd_enable, + .platform_disable = rx51_lcd_disable, +}; + +static struct omap_dss_device rx51_tv_device = { + .name = "tv", + .type = OMAP_DISPLAY_TYPE_VENC, + .driver_name = "venc", + .phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE, +}; + +static struct omap_dss_device *rx51_dss_devices[] = { + &rx51_lcd_device, + &rx51_tv_device, +}; + +static struct omap_dss_board_info rx51_dss_board_info = { + .num_devices = ARRAY_SIZE(rx51_dss_devices), + .devices = rx51_dss_devices, + .default_device = &rx51_lcd_device, +}; + +static int __init rx51_video_init(void) +{ + if (!machine_is_nokia_rx51()) + return 0; + + if (omap_mux_init_gpio(RX51_LCD_RESET_GPIO, OMAP_PIN_OUTPUT)) { + pr_err("%s cannot configure MUX for LCD RESET\n", __func__); + return 0; + } + + if (gpio_request_one(RX51_LCD_RESET_GPIO, GPIOF_OUT_INIT_HIGH, + "LCD ACX565AKM reset")) { + pr_err("%s failed to get LCD Reset GPIO\n", __func__); + return 0; + } + + omap_display_init(&rx51_dss_board_info); + return 0; +} + +subsys_initcall(rx51_video_init); + +void __init rx51_video_mem_init(void) +{ + /* + * GFX 864x480x32bpp + * VID1/2 1280x720x32bpp double buffered + */ + omap_vram_set_sdram_vram(PAGE_ALIGN(864 * 480 * 4) + + 2 * PAGE_ALIGN(1280 * 720 * 4 * 2), 0); +} + +#else +void __init rx51_video_mem_init(void) { } +#endif /* defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE) */ diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c new file mode 100644 index 00000000000..27f01f051df --- /dev/null +++ b/arch/arm/mach-omap2/board-rx51.c @@ -0,0 +1,134 @@ +/* + * linux/arch/arm/mach-omap2/board-rx51.c + * + * Copyright (C) 2007, 2008 Nokia + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/leds.h> + +#include <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/mcspi.h> +#include <plat/board.h> +#include "common.h" +#include <plat/dma.h> +#include <plat/gpmc.h> +#include <plat/usb.h> + +#include "mux.h" +#include "pm.h" +#include "sdram-nokia.h" + +#define RX51_GPIO_SLEEP_IND 162 + +extern void rx51_video_mem_init(void); + +static struct gpio_led gpio_leds[] = { + { + .name = "sleep_ind", + .gpio = RX51_GPIO_SLEEP_IND, + }, +}; + +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, + }, +}; + +/* + * cpuidle C-states definition override from the default values. + * The 'exit_latency' field is the sum of sleep and wake-up latencies. + */ +static struct cpuidle_params rx51_cpuidle_params[] = { + /* C1 */ + {110 + 162, 5 , 1}, + /* C2 */ + {106 + 180, 309, 1}, + /* C3 */ + {107 + 410, 46057, 0}, + /* C4 */ + {121 + 3374, 46057, 0}, + /* C5 */ + {855 + 1146, 46057, 1}, + /* C6 */ + {7580 + 4134, 484329, 0}, + /* C7 */ + {7505 + 15274, 484329, 1}, +}; + +extern void __init rx51_peripherals_init(void); + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static struct omap_musb_board_data musb_board_data = { + .interface_type = MUSB_INTERFACE_ULPI, + .mode = MUSB_PERIPHERAL, + .power = 0, +}; + +static void __init rx51_init(void) +{ + struct omap_sdrc_params *sdrc_params; + + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + omap3_pm_init_cpuidle(rx51_cpuidle_params); + omap_serial_init(); + + sdrc_params = nokia_get_sdram_timings(); + omap_sdrc_init(sdrc_params, sdrc_params); + + usb_musb_init(&musb_board_data); + rx51_peripherals_init(); + + /* Ensure SDRC pins are mux'd for self-refresh */ + omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT); + omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT); + + platform_device_register(&leds_gpio); +} + +static void __init rx51_reserve(void) +{ + rx51_video_mem_init(); + omap_reserve(); +} + +MACHINE_START(NOKIA_RX51, "Nokia RX-51 board") + /* Maintainer: Lauri Leukkunen <lauri.leukkunen@nokia.com> */ + .atag_offset = 0x100, + .reserve = rx51_reserve, + .map_io = omap3_map_io, + .init_early = omap3430_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = rx51_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c new file mode 100644 index 00000000000..ab9a7a9e9d6 --- /dev/null +++ b/arch/arm/mach-omap2/board-ti8168evm.c @@ -0,0 +1,67 @@ +/* + * Code for TI8168/TI8148 EVM. + * + * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; 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 <mach/hardware.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/irqs.h> +#include <plat/board.h> +#include "common.h" +#include <plat/usb.h> + +static struct omap_musb_board_data musb_board_data = { + .set_phy_power = ti81xx_musb_phy_power, + .interface_type = MUSB_INTERFACE_ULPI, + .mode = MUSB_OTG, + .power = 500, +}; + +static struct omap_board_config_kernel ti81xx_evm_config[] __initdata = { +}; + +static void __init ti81xx_evm_init(void) +{ + omap_serial_init(); + omap_sdrc_init(NULL, NULL); + omap_board_config = ti81xx_evm_config; + omap_board_config_size = ARRAY_SIZE(ti81xx_evm_config); + usb_musb_init(&musb_board_data); +} + +MACHINE_START(TI8168EVM, "ti8168evm") + /* Maintainer: Texas Instruments */ + .atag_offset = 0x100, + .map_io = ti81xx_map_io, + .init_early = ti81xx_init_early, + .init_irq = ti81xx_init_irq, + .timer = &omap3_timer, + .init_machine = ti81xx_evm_init, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(TI8148EVM, "ti8148evm") + /* Maintainer: Texas Instruments */ + .atag_offset = 0x100, + .map_io = ti81xx_map_io, + .init_early = ti81xx_init_early, + .init_irq = ti81xx_init_irq, + .timer = &omap3_timer, + .init_machine = ti81xx_evm_init, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-zoom-debugboard.c b/arch/arm/mach-omap2/board-zoom-debugboard.c new file mode 100644 index 00000000000..369c2eb7715 --- /dev/null +++ b/arch/arm/mach-omap2/board-zoom-debugboard.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc. + * Mikkel Christensen <mlc@ti.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/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/serial_8250.h> +#include <linux/smsc911x.h> +#include <linux/interrupt.h> + +#include <plat/gpmc.h> +#include <plat/gpmc-smsc911x.h> + +#include <mach/board-zoom.h> + +#define ZOOM_SMSC911X_CS 7 +#define ZOOM_SMSC911X_GPIO 158 +#define ZOOM_QUADUART_CS 3 +#define ZOOM_QUADUART_GPIO 102 +#define ZOOM_QUADUART_RST_GPIO 152 +#define QUART_CLK 1843200 +#define DEBUG_BASE 0x08000000 +#define ZOOM_ETHR_START DEBUG_BASE + +static struct omap_smsc911x_platform_data zoom_smsc911x_cfg = { + .cs = ZOOM_SMSC911X_CS, + .gpio_irq = ZOOM_SMSC911X_GPIO, + .gpio_reset = -EINVAL, + .flags = SMSC911X_USE_32BIT, +}; + +static inline void __init zoom_init_smsc911x(void) +{ + gpmc_smsc911x_init(&zoom_smsc911x_cfg); +} + +static struct plat_serial8250_port serial_platform_data[] = { + { + .mapbase = ZOOM_UART_BASE, + .irq = OMAP_GPIO_IRQ(102), + .flags = UPF_BOOT_AUTOCONF|UPF_IOREMAP|UPF_SHARE_IRQ, + .irqflags = IRQF_SHARED | IRQF_TRIGGER_RISING, + .iotype = UPIO_MEM, + .regshift = 1, + .uartclk = QUART_CLK, + }, { + .flags = 0 + } +}; + +static struct platform_device zoom_debugboard_serial_device = { + .name = "serial8250", + .id = PLAT8250_DEV_PLATFORM, + .dev = { + .platform_data = serial_platform_data, + }, +}; + +static inline void __init zoom_init_quaduart(void) +{ + int quart_cs; + unsigned long cs_mem_base; + int quart_gpio = 0; + + if (gpio_request_one(ZOOM_QUADUART_RST_GPIO, + GPIOF_OUT_INIT_LOW, + "TL16CP754C GPIO") < 0) { + pr_err("Failed to request GPIO%d for TL16CP754C\n", + ZOOM_QUADUART_RST_GPIO); + return; + } + + quart_cs = ZOOM_QUADUART_CS; + + if (gpmc_cs_request(quart_cs, SZ_1M, &cs_mem_base) < 0) { + printk(KERN_ERR "Failed to request GPMC mem" + "for Quad UART(TL16CP754C)\n"); + return; + } + + quart_gpio = ZOOM_QUADUART_GPIO; + + if (gpio_request_one(quart_gpio, GPIOF_IN, "TL16CP754C GPIO") < 0) + printk(KERN_ERR "Failed to request GPIO%d for TL16CP754C\n", + quart_gpio); +} + +static inline int omap_zoom_debugboard_detect(void) +{ + int debug_board_detect = 0; + int ret = 1; + + debug_board_detect = ZOOM_SMSC911X_GPIO; + + if (gpio_request_one(debug_board_detect, GPIOF_IN, + "Zoom debug board detect") < 0) { + printk(KERN_ERR "Failed to request GPIO%d for Zoom debug" + "board detect\n", debug_board_detect); + return 0; + } + + if (!gpio_get_value(debug_board_detect)) { + ret = 0; + } + gpio_free(debug_board_detect); + return ret; +} + +static struct platform_device *zoom_devices[] __initdata = { + &zoom_debugboard_serial_device, +}; + +int __init zoom_debugboard_init(void) +{ + if (!omap_zoom_debugboard_detect()) + return 0; + + zoom_init_smsc911x(); + zoom_init_quaduart(); + return platform_add_devices(zoom_devices, ARRAY_SIZE(zoom_devices)); +} diff --git a/arch/arm/mach-omap2/board-zoom-display.c b/arch/arm/mach-omap2/board-zoom-display.c new file mode 100644 index 00000000000..d4683ba5f72 --- /dev/null +++ b/arch/arm/mach-omap2/board-zoom-display.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2010 Texas Instruments Inc. + * + * Modified from mach-omap2/board-zoom-peripherals.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/gpio.h> +#include <linux/i2c/twl.h> +#include <linux/spi/spi.h> +#include <plat/mcspi.h> +#include <video/omapdss.h> + +#define LCD_PANEL_RESET_GPIO_PROD 96 +#define LCD_PANEL_RESET_GPIO_PILOT 55 +#define LCD_PANEL_QVGA_GPIO 56 + +static struct gpio zoom_lcd_gpios[] __initdata = { + { -EINVAL, GPIOF_OUT_INIT_HIGH, "lcd reset" }, + { LCD_PANEL_QVGA_GPIO, GPIOF_OUT_INIT_HIGH, "lcd qvga" }, +}; + +static void __init zoom_lcd_panel_init(void) +{ + zoom_lcd_gpios[0].gpio = (omap_rev() > OMAP3430_REV_ES3_0) ? + LCD_PANEL_RESET_GPIO_PROD : + LCD_PANEL_RESET_GPIO_PILOT; + + if (gpio_request_array(zoom_lcd_gpios, ARRAY_SIZE(zoom_lcd_gpios))) + pr_err("%s: Failed to get LCD GPIOs.\n", __func__); +} + +static int zoom_panel_enable_lcd(struct omap_dss_device *dssdev) +{ + return 0; +} + +static void zoom_panel_disable_lcd(struct omap_dss_device *dssdev) +{ +} + +/* + * PWMA/B register offsets (TWL4030_MODULE_PWMA) + */ +#define TWL_INTBR_PMBR1 0xD +#define TWL_INTBR_GPBR1 0xC +#define TWL_LED_PWMON 0x0 +#define TWL_LED_PWMOFF 0x1 + +static int zoom_set_bl_intensity(struct omap_dss_device *dssdev, int level) +{ + unsigned char c; + u8 mux_pwm, enb_pwm; + + if (level > 100) + return -1; + + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &mux_pwm, TWL_INTBR_PMBR1); + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &enb_pwm, TWL_INTBR_GPBR1); + + if (level == 0) { + /* disable pwm1 output and clock */ + enb_pwm = enb_pwm & 0xF5; + /* change pwm1 pin to gpio pin */ + mux_pwm = mux_pwm & 0xCF; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, + enb_pwm, TWL_INTBR_GPBR1); + twl_i2c_write_u8(TWL4030_MODULE_INTBR, + mux_pwm, TWL_INTBR_PMBR1); + return 0; + } + + if (!((enb_pwm & 0xA) && (mux_pwm & 0x30))) { + /* change gpio pin to pwm1 pin */ + mux_pwm = mux_pwm | 0x30; + /* enable pwm1 output and clock*/ + enb_pwm = enb_pwm | 0x0A; + twl_i2c_write_u8(TWL4030_MODULE_INTBR, + mux_pwm, TWL_INTBR_PMBR1); + twl_i2c_write_u8(TWL4030_MODULE_INTBR, + enb_pwm, TWL_INTBR_GPBR1); + } + + c = ((50 * (100 - level)) / 100) + 1; + twl_i2c_write_u8(TWL4030_MODULE_PWM1, 0x7F, TWL_LED_PWMOFF); + twl_i2c_write_u8(TWL4030_MODULE_PWM1, c, TWL_LED_PWMON); + + return 0; +} + +static struct omap_dss_device zoom_lcd_device = { + .name = "lcd", + .driver_name = "NEC_8048_panel", + .type = OMAP_DISPLAY_TYPE_DPI, + .phy.dpi.data_lines = 24, + .platform_enable = zoom_panel_enable_lcd, + .platform_disable = zoom_panel_disable_lcd, + .max_backlight_level = 100, + .set_backlight = zoom_set_bl_intensity, +}; + +static struct omap_dss_device *zoom_dss_devices[] = { + &zoom_lcd_device, +}; + +static struct omap_dss_board_info zoom_dss_data = { + .num_devices = ARRAY_SIZE(zoom_dss_devices), + .devices = zoom_dss_devices, + .default_device = &zoom_lcd_device, +}; + +static struct omap2_mcspi_device_config dss_lcd_mcspi_config = { + .turbo_mode = 1, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +static struct spi_board_info nec_8048_spi_board_info[] __initdata = { + [0] = { + .modalias = "nec_8048_spi", + .bus_num = 1, + .chip_select = 2, + .max_speed_hz = 375000, + .controller_data = &dss_lcd_mcspi_config, + }, +}; + +void __init zoom_display_init(void) +{ + omap_display_init(&zoom_dss_data); + spi_register_board_info(nec_8048_spi_board_info, + ARRAY_SIZE(nec_8048_spi_board_info)); + zoom_lcd_panel_init(); +} + diff --git a/arch/arm/mach-omap2/board-zoom-peripherals.c b/arch/arm/mach-omap2/board-zoom-peripherals.c new file mode 100644 index 00000000000..c126461836a --- /dev/null +++ b/arch/arm/mach-omap2/board-zoom-peripherals.c @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc. + * + * Modified from mach-omap2/board-zoom2.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/gpio.h> +#include <linux/i2c/twl.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/wl12xx.h> +#include <linux/mmc/host.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include "common.h" +#include <plat/usb.h> + +#include <mach/board-zoom.h> + +#include "mux.h" +#include "hsmmc.h" +#include "common-board-devices.h" + +#define OMAP_ZOOM_WLAN_PMENA_GPIO (101) +#define OMAP_ZOOM_WLAN_IRQ_GPIO (162) + +#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES) + +/* Zoom2 has Qwerty keyboard*/ +static uint32_t board_keymap[] = { + KEY(0, 0, KEY_E), + KEY(0, 1, KEY_R), + KEY(0, 2, KEY_T), + KEY(0, 3, KEY_HOME), + KEY(0, 6, KEY_I), + KEY(0, 7, KEY_LEFTSHIFT), + KEY(1, 0, KEY_D), + KEY(1, 1, KEY_F), + KEY(1, 2, KEY_G), + KEY(1, 3, KEY_SEND), + KEY(1, 6, KEY_K), + KEY(1, 7, KEY_ENTER), + KEY(2, 0, KEY_X), + KEY(2, 1, KEY_C), + KEY(2, 2, KEY_V), + KEY(2, 3, KEY_END), + KEY(2, 6, KEY_DOT), + KEY(2, 7, KEY_CAPSLOCK), + KEY(3, 0, KEY_Z), + KEY(3, 1, KEY_KPPLUS), + KEY(3, 2, KEY_B), + KEY(3, 3, KEY_F1), + KEY(3, 6, KEY_O), + KEY(3, 7, KEY_SPACE), + KEY(4, 0, KEY_W), + KEY(4, 1, KEY_Y), + KEY(4, 2, KEY_U), + KEY(4, 3, KEY_F2), + KEY(4, 4, KEY_VOLUMEUP), + KEY(4, 6, KEY_L), + KEY(4, 7, KEY_LEFT), + KEY(5, 0, KEY_S), + KEY(5, 1, KEY_H), + KEY(5, 2, KEY_J), + KEY(5, 3, KEY_F3), + KEY(5, 4, KEY_UNKNOWN), + KEY(5, 5, KEY_VOLUMEDOWN), + KEY(5, 6, KEY_M), + KEY(5, 7, KEY_RIGHT), + KEY(6, 0, KEY_Q), + KEY(6, 1, KEY_A), + KEY(6, 2, KEY_N), + KEY(6, 3, KEY_BACKSPACE), + KEY(6, 6, KEY_P), + KEY(6, 7, KEY_UP), + KEY(7, 0, KEY_PROG1), /*MACRO 1 <User defined> */ + KEY(7, 1, KEY_PROG2), /*MACRO 2 <User defined> */ + KEY(7, 2, KEY_PROG3), /*MACRO 3 <User defined> */ + KEY(7, 3, KEY_PROG4), /*MACRO 4 <User defined> */ + KEY(7, 6, KEY_SELECT), + KEY(7, 7, KEY_DOWN) +}; + +static struct matrix_keymap_data board_map_data = { + .keymap = board_keymap, + .keymap_size = ARRAY_SIZE(board_keymap), +}; + +static struct twl4030_keypad_data zoom_kp_twl4030_data = { + .keymap_data = &board_map_data, + .rows = 8, + .cols = 8, + .rep = 1, +}; + +static struct regulator_consumer_supply zoom_vmmc1_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply zoom_vsim_supply[] = { + REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"), +}; + +static struct regulator_consumer_supply zoom_vmmc2_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"), +}; + +static struct regulator_consumer_supply zoom_vmmc3_supply[] = { + REGULATOR_SUPPLY("vmmc", "omap_hsmmc.2"), +}; + +/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */ +static struct regulator_init_data zoom_vmmc1 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 3150000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(zoom_vmmc1_supply), + .consumer_supplies = zoom_vmmc1_supply, +}; + +/* VMMC2 for MMC2 card */ +static struct regulator_init_data zoom_vmmc2 = { + .constraints = { + .min_uV = 1850000, + .max_uV = 1850000, + .apply_uV = true, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(zoom_vmmc2_supply), + .consumer_supplies = zoom_vmmc2_supply, +}; + +/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */ +static struct regulator_init_data zoom_vsim = { + .constraints = { + .min_uV = 1800000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL + | REGULATOR_MODE_STANDBY, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE + | REGULATOR_CHANGE_MODE + | REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(zoom_vsim_supply), + .consumer_supplies = zoom_vsim_supply, +}; + +static struct regulator_init_data zoom_vmmc3 = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .num_consumer_supplies = ARRAY_SIZE(zoom_vmmc3_supply), + .consumer_supplies = zoom_vmmc3_supply, +}; + +static struct fixed_voltage_config zoom_vwlan = { + .supply_name = "vwl1271", + .microvolts = 1800000, /* 1.8V */ + .gpio = OMAP_ZOOM_WLAN_PMENA_GPIO, + .startup_delay = 70000, /* 70msec */ + .enable_high = 1, + .enabled_at_boot = 0, + .init_data = &zoom_vmmc3, +}; + +static struct platform_device omap_vwlan_device = { + .name = "reg-fixed-voltage", + .id = 1, + .dev = { + .platform_data = &zoom_vwlan, + }, +}; + +static struct wl12xx_platform_data omap_zoom_wlan_data __initdata = { + .irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO), + /* ZOOM ref clock is 26 MHz */ + .board_ref_clock = 1, +}; + +static struct omap2_hsmmc_info mmc[] = { + { + .name = "external", + .mmc = 1, + .caps = MMC_CAP_4_BIT_DATA, + .gpio_wp = -EINVAL, + .power_saving = true, + }, + { + .name = "internal", + .mmc = 2, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .nonremovable = true, + .power_saving = true, + }, + { + .name = "wl1271", + .mmc = 3, + .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_POWER_OFF_CARD, + .gpio_wp = -EINVAL, + .gpio_cd = -EINVAL, + .nonremovable = true, + }, + {} /* Terminator */ +}; + +static int zoom_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + int ret; + + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + mmc[0].gpio_cd = gpio + 0; + omap2_hsmmc_init(mmc); + + ret = gpio_request_one(LCD_PANEL_ENABLE_GPIO, GPIOF_OUT_INIT_LOW, + "lcd enable"); + if (ret) + pr_err("Failed to get LCD_PANEL_ENABLE_GPIO (gpio%d).\n", + LCD_PANEL_ENABLE_GPIO); + + return ret; +} + +/* EXTMUTE callback function */ +static void zoom2_set_hs_extmute(int mute) +{ + gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute); +} + +static struct twl4030_gpio_platform_data zoom_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .setup = zoom_twl_gpio_setup, +}; + +static struct twl4030_platform_data zoom_twldata = { + /* platform_data for children goes here */ + .gpio = &zoom_gpio_data, + .keypad = &zoom_kp_twl4030_data, + .vmmc1 = &zoom_vmmc1, + .vmmc2 = &zoom_vmmc2, + .vsim = &zoom_vsim, +}; + +static int __init omap_i2c_init(void) +{ + omap3_pmic_get_config(&zoom_twldata, + TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_BCI | + TWL_COMMON_PDATA_MADC | TWL_COMMON_PDATA_AUDIO, + TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2); + + if (machine_is_omap_zoom2()) { + struct twl4030_codec_data *codec_data; + codec_data = zoom_twldata.audio->codec; + + codec_data->ramp_delay_value = 3; /* 161 ms */ + codec_data->hs_extmute = 1; + codec_data->set_hs_extmute = zoom2_set_hs_extmute; + } + omap_pmic_init(1, 2400, "twl5030", INT_34XX_SYS_NIRQ, &zoom_twldata); + omap_register_i2c_bus(2, 400, NULL, 0); + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static void enable_board_wakeup_source(void) +{ + /* T2 interrupt line (keypad) */ + omap_mux_init_signal("sys_nirq", + OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP); +} + +void __init zoom_peripherals_init(void) +{ + int ret = wl12xx_set_platform_data(&omap_zoom_wlan_data); + + if (ret) + pr_err("error setting wl12xx data: %d\n", ret); + + omap_i2c_init(); + platform_device_register(&omap_vwlan_device); + usb_musb_init(NULL); + enable_board_wakeup_source(); + omap_serial_init(); +} diff --git a/arch/arm/mach-omap2/board-zoom.c b/arch/arm/mach-omap2/board-zoom.c new file mode 100644 index 00000000000..5c20bcc57f2 --- /dev/null +++ b/arch/arm/mach-omap2/board-zoom.c @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2009-2010 Texas Instruments Inc. + * Mikkel Christensen <mlc@ti.com> + * Felipe Balbi <balbi@ti.com> + * + * Modified from mach-omap2/board-ldp.c + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/gpio.h> +#include <linux/i2c/twl.h> +#include <linux/mtd/nand.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include "common.h" +#include <plat/board.h> +#include <plat/usb.h> + +#include <mach/board-zoom.h> + +#include "board-flash.h" +#include "mux.h" +#include "sdram-micron-mt46h32m32lf-6.h" +#include "sdram-hynix-h8mbx00u0mer-0em.h" + +#define ZOOM3_EHCI_RESET_GPIO 64 + +#ifdef CONFIG_OMAP_MUX +static struct omap_board_mux board_mux[] __initdata = { + /* WLAN IRQ - GPIO 162 */ + OMAP3_MUX(MCBSP1_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT), + /* WLAN POWER ENABLE - GPIO 101 */ + OMAP3_MUX(CAM_D2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT), + /* WLAN SDIO: MMC3 CMD */ + OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLUP), + /* WLAN SDIO: MMC3 CLK */ + OMAP3_MUX(ETK_CLK, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP), + /* WLAN SDIO: MMC3 DAT[0-3] */ + OMAP3_MUX(ETK_D3, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(ETK_D4, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(ETK_D5, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP), + OMAP3_MUX(ETK_D6, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP), + { .reg_offset = OMAP_MUX_TERMINATOR }, +}; +#endif + +static struct mtd_partition zoom_nand_partitions[] = { + /* All the partition sizes are listed in terms of NAND block size */ + { + .name = "X-Loader-NAND", + .offset = 0, + .size = 4 * (64 * 2048), /* 512KB, 0x80000 */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "U-Boot-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */ + .size = 10 * (64 * 2048), /* 1.25MB, 0x140000 */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, + { + .name = "Boot Env-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */ + .size = 2 * (64 * 2048), /* 256KB, 0x40000 */ + }, + { + .name = "Kernel-NAND", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x0200000*/ + .size = 240 * (64 * 2048), /* 30M, 0x1E00000 */ + }, + { + .name = "system", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x2000000 */ + .size = 3328 * (64 * 2048), /* 416M, 0x1A000000 */ + }, + { + .name = "userdata", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1C000000*/ + .size = 256 * (64 * 2048), /* 32M, 0x2000000 */ + }, + { + .name = "cache", + .offset = MTDPART_OFS_APPEND, /* Offset = 0x1E000000*/ + .size = 256 * (64 * 2048), /* 32M, 0x2000000 */ + }, +}; + +static const struct usbhs_omap_board_data usbhs_bdata __initconst = { + .port_mode[0] = OMAP_USBHS_PORT_MODE_UNUSED, + .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY, + .port_mode[2] = OMAP_USBHS_PORT_MODE_UNUSED, + .phy_reset = true, + .reset_gpio_port[0] = -EINVAL, + .reset_gpio_port[1] = ZOOM3_EHCI_RESET_GPIO, + .reset_gpio_port[2] = -EINVAL, +}; + +static void __init omap_zoom_init(void) +{ + if (machine_is_omap_zoom2()) { + omap3_mux_init(board_mux, OMAP_PACKAGE_CBB); + } else if (machine_is_omap_zoom3()) { + omap3_mux_init(board_mux, OMAP_PACKAGE_CBP); + omap_mux_init_gpio(ZOOM3_EHCI_RESET_GPIO, OMAP_PIN_OUTPUT); + usbhs_init(&usbhs_bdata); + } + + board_nand_init(zoom_nand_partitions, ARRAY_SIZE(zoom_nand_partitions), + ZOOM_NAND_CS, NAND_BUSWIDTH_16); + zoom_debugboard_init(); + zoom_peripherals_init(); + + if (machine_is_omap_zoom2()) + omap_sdrc_init(mt46h32m32lf6_sdrc_params, + mt46h32m32lf6_sdrc_params); + else if (machine_is_omap_zoom3()) + omap_sdrc_init(h8mbx00u0mer0em_sdrc_params, + h8mbx00u0mer0em_sdrc_params); + + zoom_display_init(); +} + +MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3430_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap_zoom_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END + +MACHINE_START(OMAP_ZOOM3, "OMAP Zoom3 board") + .atag_offset = 0x100, + .reserve = omap_reserve, + .map_io = omap3_map_io, + .init_early = omap3630_init_early, + .init_irq = omap3_init_irq, + .handle_irq = omap3_intc_handle_irq, + .init_machine = omap_zoom_init, + .timer = &omap3_timer, + .restart = omap_prcm_restart, +MACHINE_END diff --git a/arch/arm/mach-omap2/clkt2xxx_apll.c b/arch/arm/mach-omap2/clkt2xxx_apll.c new file mode 100644 index 00000000000..b19a1f7234a --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_apll.c @@ -0,0 +1,146 @@ +/* + * OMAP2xxx APLL clock control functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> +#include <plat/prcm.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */ +#define EN_APLL_STOPPED 0 +#define EN_APLL_LOCKED 3 + +/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */ +#define APLLS_CLKIN_19_2MHZ 0 +#define APLLS_CLKIN_13MHZ 2 +#define APLLS_CLKIN_12MHZ 3 + +void __iomem *cm_idlest_pll; + +/* Private functions */ + +/* Enable an APLL if off */ +static int omap2_clk_apll_enable(struct clk *clk, u32 status_mask) +{ + u32 cval, apll_mask; + + apll_mask = EN_APLL_LOCKED << clk->enable_bit; + + cval = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); + + if ((cval & apll_mask) == apll_mask) + return 0; /* apll already enabled */ + + cval &= ~apll_mask; + cval |= apll_mask; + omap2_cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); + + omap2_cm_wait_idlest(cm_idlest_pll, status_mask, + OMAP24XX_CM_IDLEST_VAL, clk->name); + + /* + * REVISIT: Should we return an error code if omap2_wait_clock_ready() + * fails? + */ + return 0; +} + +static int omap2_clk_apll96_enable(struct clk *clk) +{ + return omap2_clk_apll_enable(clk, OMAP24XX_ST_96M_APLL_MASK); +} + +static int omap2_clk_apll54_enable(struct clk *clk) +{ + return omap2_clk_apll_enable(clk, OMAP24XX_ST_54M_APLL_MASK); +} + +static void _apll96_allow_idle(struct clk *clk) +{ + omap2xxx_cm_set_apll96_auto_low_power_stop(); +} + +static void _apll96_deny_idle(struct clk *clk) +{ + omap2xxx_cm_set_apll96_disable_autoidle(); +} + +static void _apll54_allow_idle(struct clk *clk) +{ + omap2xxx_cm_set_apll54_auto_low_power_stop(); +} + +static void _apll54_deny_idle(struct clk *clk) +{ + omap2xxx_cm_set_apll54_disable_autoidle(); +} + +/* Stop APLL */ +static void omap2_clk_apll_disable(struct clk *clk) +{ + u32 cval; + + cval = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKEN); + cval &= ~(EN_APLL_LOCKED << clk->enable_bit); + omap2_cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN); +} + +/* Public data */ + +const struct clkops clkops_apll96 = { + .enable = omap2_clk_apll96_enable, + .disable = omap2_clk_apll_disable, + .allow_idle = _apll96_allow_idle, + .deny_idle = _apll96_deny_idle, +}; + +const struct clkops clkops_apll54 = { + .enable = omap2_clk_apll54_enable, + .disable = omap2_clk_apll_disable, + .allow_idle = _apll54_allow_idle, + .deny_idle = _apll54_deny_idle, +}; + +/* Public functions */ + +u32 omap2xxx_get_apll_clkin(void) +{ + u32 aplls, srate = 0; + + aplls = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL1); + aplls &= OMAP24XX_APLLS_CLKIN_MASK; + aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT; + + if (aplls == APLLS_CLKIN_19_2MHZ) + srate = 19200000; + else if (aplls == APLLS_CLKIN_13MHZ) + srate = 13000000; + else if (aplls == APLLS_CLKIN_12MHZ) + srate = 12000000; + + return srate; +} + diff --git a/arch/arm/mach-omap2/clkt2xxx_dpll.c b/arch/arm/mach-omap2/clkt2xxx_dpll.c new file mode 100644 index 00000000000..1502a7bc20b --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_dpll.c @@ -0,0 +1,63 @@ +/* + * OMAP2-specific DPLL control functions + * + * Copyright (C) 2011 Nokia Corporation + * Paul Walmsley + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> + +#include "clock.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +/* Private functions */ + +/** + * _allow_idle - enable DPLL autoidle bits + * @clk: struct clk * of the DPLL to operate on + * + * Enable DPLL automatic idle control. The DPLL will enter low-power + * stop when its downstream clocks are gated. No return value. + * REVISIT: DPLL can optionally enter low-power bypass by writing 0x1 + * instead. Add some mechanism to optionally enter this mode. + */ +static void _allow_idle(struct clk *clk) +{ + if (!clk || !clk->dpll_data) + return; + + omap2xxx_cm_set_dpll_auto_low_power_stop(); +} + +/** + * _deny_idle - prevent DPLL from automatically idling + * @clk: struct clk * of the DPLL to operate on + * + * Disable DPLL automatic idle control. No return value. + */ +static void _deny_idle(struct clk *clk) +{ + if (!clk || !clk->dpll_data) + return; + + omap2xxx_cm_set_dpll_disable_autoidle(); +} + + +/* Public data */ + +const struct clkops clkops_omap2xxx_dpll_ops = { + .allow_idle = _allow_idle, + .deny_idle = _deny_idle, +}; + diff --git a/arch/arm/mach-omap2/clkt2xxx_dpllcore.c b/arch/arm/mach-omap2/clkt2xxx_dpllcore.c new file mode 100644 index 00000000000..4ae43922208 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_dpllcore.c @@ -0,0 +1,173 @@ +/* + * DPLL + CORE_CLK composite clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * 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. + * + * XXX The DPLL and CORE clocks should be split into two separate clock + * types. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> +#include <plat/sram.h> +#include <plat/sdrc.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "opp2xxx.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +/* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */ + +/** + * omap2xxx_clk_get_core_rate - return the CORE_CLK rate + * @clk: pointer to the combined dpll_ck + core_ck (currently "dpll_ck") + * + * Returns the CORE_CLK rate. CORE_CLK can have one of three rate + * sources on OMAP2xxx: the DPLL CLKOUT rate, DPLL CLKOUTX2, or 32KHz + * (the latter is unusual). This currently should be called with + * struct clk *dpll_ck, which is a composite clock of dpll_ck and + * core_ck. + */ +unsigned long omap2xxx_clk_get_core_rate(struct clk *clk) +{ + long long core_clk; + u32 v; + + core_clk = omap2_get_dpll_rate(clk); + + v = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + v &= OMAP24XX_CORE_CLK_SRC_MASK; + + if (v == CORE_CLK_SRC_32K) + core_clk = 32768; + else + core_clk *= v; + + return core_clk; +} + +/* + * Uses the current prcm set to tell if a rate is valid. + * You can go slower, but not faster within a given rate set. + */ +static long omap2_dpllcore_round_rate(unsigned long target_rate) +{ + u32 high, low, core_clk_src; + + core_clk_src = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK; + + if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */ + high = curr_prcm_set->dpll_speed * 2; + low = curr_prcm_set->dpll_speed; + } else { /* DPLL clockout x 2 */ + high = curr_prcm_set->dpll_speed; + low = curr_prcm_set->dpll_speed / 2; + } + +#ifdef DOWN_VARIABLE_DPLL + if (target_rate > high) + return high; + else + return target_rate; +#else + if (target_rate > low) + return high; + else + return low; +#endif + +} + +unsigned long omap2_dpllcore_recalc(struct clk *clk) +{ + return omap2xxx_clk_get_core_rate(clk); +} + +int omap2_reprogram_dpllcore(struct clk *clk, unsigned long rate) +{ + u32 cur_rate, low, mult, div, valid_rate, done_rate; + u32 bypass = 0; + struct prcm_config tmpset; + const struct dpll_data *dd; + + cur_rate = omap2xxx_clk_get_core_rate(dclk); + mult = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + mult &= OMAP24XX_CORE_CLK_SRC_MASK; + + if ((rate == (cur_rate / 2)) && (mult == 2)) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); + } else if ((rate == (cur_rate * 2)) && (mult == 1)) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + } else if (rate != cur_rate) { + valid_rate = omap2_dpllcore_round_rate(rate); + if (valid_rate != rate) + return -EINVAL; + + if (mult == 1) + low = curr_prcm_set->dpll_speed; + else + low = curr_prcm_set->dpll_speed / 2; + + dd = clk->dpll_data; + if (!dd) + return -EINVAL; + + tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg); + tmpset.cm_clksel1_pll &= ~(dd->mult_mask | + dd->div1_mask); + div = ((curr_prcm_set->xtal_speed / 1000000) - 1); + tmpset.cm_clksel2_pll = omap2_cm_read_mod_reg(PLL_MOD, CM_CLKSEL2); + tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK; + if (rate > low) { + tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2; + mult = ((rate / 2) / 1000000); + done_rate = CORE_CLK_SRC_DPLL_X2; + } else { + tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL; + mult = (rate / 1000000); + done_rate = CORE_CLK_SRC_DPLL; + } + tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask)); + tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask)); + + /* Worst case */ + tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS; + + if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */ + bypass = 1; + + /* For omap2xxx_sdrc_init_params() */ + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + + /* Force dll lock mode */ + omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr, + bypass); + + /* Errata: ret dll entry state */ + omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); + omap2xxx_sdrc_reprogram(done_rate, 0); + } + + return 0; +} + diff --git a/arch/arm/mach-omap2/clkt2xxx_osc.c b/arch/arm/mach-omap2/clkt2xxx_osc.c new file mode 100644 index 00000000000..c3460928b5e --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_osc.c @@ -0,0 +1,76 @@ +/* + * OMAP2xxx osc_clk-specific clock code + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * 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. + */ +#undef DEBUG + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "prm2xxx_3xxx.h" +#include "prm-regbits-24xx.h" + +/* + * XXX This does not actually enable the osc_ck, since the osc_ck must + * be running for this function to be called. Instead, this function + * is used to disable an autoidle mode on the osc_ck. The existing + * clk_enable/clk_disable()-based usecounting for osc_ck should be + * replaced with autoidle-based usecounting. + */ +static int omap2_enable_osc_ck(struct clk *clk) +{ + u32 pcc; + + pcc = __raw_readl(prcm_clksrc_ctrl); + + __raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); + + return 0; +} + +/* + * XXX This does not actually disable the osc_ck, since doing so would + * immediately halt the system. Instead, this function is used to + * enable an autoidle mode on the osc_ck. The existing + * clk_enable/clk_disable()-based usecounting for osc_ck should be + * replaced with autoidle-based usecounting. + */ +static void omap2_disable_osc_ck(struct clk *clk) +{ + u32 pcc; + + pcc = __raw_readl(prcm_clksrc_ctrl); + + __raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK, prcm_clksrc_ctrl); +} + +const struct clkops clkops_oscck = { + .enable = omap2_enable_osc_ck, + .disable = omap2_disable_osc_ck, +}; + +unsigned long omap2_osc_clk_recalc(struct clk *clk) +{ + return omap2xxx_get_apll_clkin() * omap2xxx_get_sysclkdiv(); +} + diff --git a/arch/arm/mach-omap2/clkt2xxx_sys.c b/arch/arm/mach-omap2/clkt2xxx_sys.c new file mode 100644 index 00000000000..8693cfdac49 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_sys.c @@ -0,0 +1,50 @@ +/* + * OMAP2xxx sys_clk-specific clock code + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "prm2xxx_3xxx.h" +#include "prm-regbits-24xx.h" + +void __iomem *prcm_clksrc_ctrl; + +u32 omap2xxx_get_sysclkdiv(void) +{ + u32 div; + + div = __raw_readl(prcm_clksrc_ctrl); + div &= OMAP_SYSCLKDIV_MASK; + div >>= OMAP_SYSCLKDIV_SHIFT; + + return div; +} + +unsigned long omap2xxx_sys_clk_recalc(struct clk *clk) +{ + return clk->parent->rate / omap2xxx_get_sysclkdiv(); +} + + diff --git a/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c new file mode 100644 index 00000000000..39f9d5a58d0 --- /dev/null +++ b/arch/arm/mach-omap2/clkt2xxx_virt_prcm_set.c @@ -0,0 +1,246 @@ +/* + * OMAP2xxx DVFS virtual clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, + * Gordon McNutt and RidgeRun, Inc. + * + * 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. + * + * XXX Some of this code should be replaceable by the upcoming OPP layer + * code. However, some notion of "rate set" is probably still necessary + * for OMAP2xxx at least. Rate sets should be generalized so they can be + * used for any OMAP chip, not just OMAP2xxx. In particular, Richard Woodruff + * has in the past expressed a preference to use rate sets for OPP changes, + * rather than dynamically recalculating the clock tree, so if someone wants + * this badly enough to write the code to handle it, we should support it + * as an option. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/cpufreq.h> +#include <linux/slab.h> + +#include <plat/clock.h> +#include <plat/sram.h> +#include <plat/sdrc.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "opp2xxx.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +const struct prcm_config *curr_prcm_set; +const struct prcm_config *rate_table; + +/** + * omap2_table_mpu_recalc - just return the MPU speed + * @clk: virt_prcm_set struct clk + * + * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set. + */ +unsigned long omap2_table_mpu_recalc(struct clk *clk) +{ + return curr_prcm_set->mpu_speed; +} + +/* + * Look for a rate equal or less than the target rate given a configuration set. + * + * What's not entirely clear is "which" field represents the key field. + * Some might argue L3-DDR, others ARM, others IVA. This code is simple and + * just uses the ARM rates. + */ +long omap2_round_to_table_rate(struct clk *clk, unsigned long rate) +{ + const struct prcm_config *ptr; + long highest_rate; + + highest_rate = -EINVAL; + + for (ptr = rate_table; ptr->mpu_speed; ptr++) { + if (!(ptr->flags & cpu_mask)) + continue; + if (ptr->xtal_speed != sclk->rate) + continue; + + highest_rate = ptr->mpu_speed; + + /* Can check only after xtal frequency check */ + if (ptr->mpu_speed <= rate) + break; + } + return highest_rate; +} + +/* Sets basic clocks based on the specified rate */ +int omap2_select_table_rate(struct clk *clk, unsigned long rate) +{ + u32 cur_rate, done_rate, bypass = 0, tmp; + const struct prcm_config *prcm; + unsigned long found_speed = 0; + unsigned long flags; + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + + if (prcm->xtal_speed != sclk->rate) + continue; + + if (prcm->mpu_speed <= rate) { + found_speed = prcm->mpu_speed; + break; + } + } + + if (!found_speed) { + printk(KERN_INFO "Could not set MPU rate to %luMHz\n", + rate / 1000000); + return -EINVAL; + } + + curr_prcm_set = prcm; + cur_rate = omap2xxx_clk_get_core_rate(dclk); + + if (prcm->dpll_speed == cur_rate / 2) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); + } else if (prcm->dpll_speed == cur_rate * 2) { + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + } else if (prcm->dpll_speed != cur_rate) { + local_irq_save(flags); + + if (prcm->dpll_speed == prcm->xtal_speed) + bypass = 1; + + if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) == + CORE_CLK_SRC_DPLL_X2) + done_rate = CORE_CLK_SRC_DPLL_X2; + else + done_rate = CORE_CLK_SRC_DPLL; + + /* MPU divider */ + omap2_cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL); + + /* dsp + iva1 div(2420), iva2.1(2430) */ + omap2_cm_write_mod_reg(prcm->cm_clksel_dsp, + OMAP24XX_DSP_MOD, CM_CLKSEL); + + omap2_cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL); + + /* Major subsystem dividers */ + tmp = omap2_cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK; + omap2_cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, + CM_CLKSEL1); + + if (cpu_is_omap2430()) + omap2_cm_write_mod_reg(prcm->cm_clksel_mdm, + OMAP2430_MDM_MOD, CM_CLKSEL); + + /* x2 to enter omap2xxx_sdrc_init_params() */ + omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); + + omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr, + bypass); + + omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); + omap2xxx_sdrc_reprogram(done_rate, 0); + + local_irq_restore(flags); + } + + return 0; +} + +#ifdef CONFIG_CPU_FREQ +/* + * Walk PRCM rate table and fillout cpufreq freq_table + * XXX This should be replaced by an OPP layer in the near future + */ +static struct cpufreq_frequency_table *freq_table; + +void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) +{ + const struct prcm_config *prcm; + int i = 0; + int tbl_sz = 0; + + if (!cpu_is_omap24xx()) + return; + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + if (prcm->xtal_speed != sclk->rate) + continue; + + /* don't put bypass rates in table */ + if (prcm->dpll_speed == prcm->xtal_speed) + continue; + + tbl_sz++; + } + + /* + * XXX Ensure that we're doing what CPUFreq expects for this error + * case and the following one + */ + if (tbl_sz == 0) { + pr_warning("%s: no matching entries in rate_table\n", + __func__); + return; + } + + /* Include the CPUFREQ_TABLE_END terminator entry */ + tbl_sz++; + + freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) * tbl_sz, + GFP_ATOMIC); + if (!freq_table) { + pr_err("%s: could not kzalloc frequency table\n", __func__); + return; + } + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + if (prcm->xtal_speed != sclk->rate) + continue; + + /* don't put bypass rates in table */ + if (prcm->dpll_speed == prcm->xtal_speed) + continue; + + freq_table[i].index = i; + freq_table[i].frequency = prcm->mpu_speed / 1000; + i++; + } + + freq_table[i].index = i; + freq_table[i].frequency = CPUFREQ_TABLE_END; + + *table = &freq_table[0]; +} + +void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table) +{ + if (!cpu_is_omap24xx()) + return; + + kfree(freq_table); +} + +#endif diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c new file mode 100644 index 00000000000..d6e34dd9e7e --- /dev/null +++ b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c @@ -0,0 +1,122 @@ +/* + * OMAP34xx M2 divider clock code + * + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Copyright (C) 2007-2010 Nokia Corporation + * + * Paul Walmsley + * Jouni Högander + * + * Parts of this code are based on code written by + * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> +#include <plat/sram.h> +#include <plat/sdrc.h> + +#include "clock.h" +#include "clock3xxx.h" +#include "clock34xx.h" +#include "sdrc.h" + +#define CYCLES_PER_MHZ 1000000 + +/* + * CORE DPLL (DPLL3) M2 divider rate programming functions + * + * These call into SRAM code to do the actual CM writes, since the SDRAM + * is clocked from DPLL3. + */ + +/** + * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider + * @clk: struct clk * of DPLL to set + * @rate: rounded target rate + * + * Program the DPLL M2 divider with the rounded target rate. Returns + * -EINVAL upon error, or 0 upon success. + */ +int omap3_core_dpll_m2_set_rate(struct clk *clk, unsigned long rate) +{ + u32 new_div = 0; + u32 unlock_dll = 0; + u32 c; + unsigned long validrate, sdrcrate, _mpurate; + struct omap_sdrc_params *sdrc_cs0; + struct omap_sdrc_params *sdrc_cs1; + int ret; + + if (!clk || !rate) + return -EINVAL; + + validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); + if (validrate != rate) + return -EINVAL; + + sdrcrate = sdrc_ick_p->rate; + if (rate > clk->rate) + sdrcrate <<= ((rate / clk->rate) >> 1); + else + sdrcrate >>= ((clk->rate / rate) >> 1); + + ret = omap2_sdrc_get_params(sdrcrate, &sdrc_cs0, &sdrc_cs1); + if (ret) + return -EINVAL; + + if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) { + pr_debug("clock: will unlock SDRC DLL\n"); + unlock_dll = 1; + } + + /* + * XXX This only needs to be done when the CPU frequency changes + */ + _mpurate = arm_fck_p->rate / CYCLES_PER_MHZ; + c = (_mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT; + c += 1; /* for safety */ + c *= SDRC_MPURATE_LOOPS; + c >>= SDRC_MPURATE_SCALE; + if (c == 0) + c = 1; + + pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n", clk->rate, + validrate); + pr_debug("clock: SDRC CS0 timing params used:" + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr); + if (sdrc_cs1) + pr_debug("clock: SDRC CS1 timing params used: " + " RFR %08x CTRLA %08x CTRLB %08x MR %08x\n", + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + + if (sdrc_cs1) + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla, + sdrc_cs1->actim_ctrlb, sdrc_cs1->mr); + else + omap3_configure_core_dpll( + new_div, unlock_dll, c, rate > clk->rate, + sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla, + sdrc_cs0->actim_ctrlb, sdrc_cs0->mr, + 0, 0, 0, 0); + clk->rate = rate; + + return 0; +} + diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c new file mode 100644 index 00000000000..e25364de028 --- /dev/null +++ b/arch/arm/mach-omap2/clkt_clksel.c @@ -0,0 +1,509 @@ +/* + * clkt_clksel.c - OMAP2/3/4 clksel clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * 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. + * + * + * clksel clocks are clocks that do not have a fixed parent, or that + * can divide their parent's rate, or possibly both at the same time, based + * on the contents of a hardware register bitfield. + * + * All of the various mux and divider settings can be encoded into + * struct clksel* data structures, and then these can be autogenerated + * from some hardware database for each new chip generation. This + * should avoid the need to write, review, and validate a lot of new + * clock code for each new chip, since it can be exported from the SoC + * design flow. This is now done on OMAP4. + * + * The fusion of mux and divider clocks is a software creation. In + * hardware reality, the multiplexer (parent selection) and the + * divider exist separately. XXX At some point these clksel clocks + * should be split into "divider" clocks and "mux" clocks to better + * match the hardware. + * + * (The name "clksel" comes from the name of the corresponding + * register field in the OMAP2/3 family of SoCs.) + * + * XXX Currently these clocks are only used in the OMAP2/3/4 code, but + * many of the OMAP1 clocks should be convertible to use this + * mechanism. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> + +#include "clock.h" + +/* Private functions */ + +/** + * _get_clksel_by_parent() - return clksel struct for a given clk & parent + * @clk: OMAP struct clk ptr to inspect + * @src_clk: OMAP struct clk ptr of the parent clk to search for + * + * Scan the struct clksel array associated with the clock to find + * the element associated with the supplied parent clock address. + * Returns a pointer to the struct clksel on success or NULL on error. + */ +static const struct clksel *_get_clksel_by_parent(struct clk *clk, + struct clk *src_clk) +{ + const struct clksel *clks; + + for (clks = clk->clksel; clks->parent; clks++) + if (clks->parent == src_clk) + break; /* Found the requested parent */ + + if (!clks->parent) { + /* This indicates a data problem */ + WARN(1, "clock: Could not find parent clock %s in clksel array " + "of clock %s\n", src_clk->name, clk->name); + return NULL; + } + + return clks; +} + +/** + * _get_div_and_fieldval() - find the new clksel divisor and field value to use + * @src_clk: planned new parent struct clk * + * @clk: struct clk * that is being reparented + * @field_val: pointer to a u32 to contain the register data for the divisor + * + * Given an intended new parent struct clk * @src_clk, and the struct + * clk * @clk to the clock that is being reparented, find the + * appropriate rate divisor for the new clock (returned as the return + * value), and the corresponding register bitfield data to program to + * reach that divisor (returned in the u32 pointed to by @field_val). + * Returns 0 on error, or returns the newly-selected divisor upon + * success (in this latter case, the corresponding register bitfield + * value is passed back in the variable pointed to by @field_val) + */ +static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk, + u32 *field_val) +{ + const struct clksel *clks; + const struct clksel_rate *clkr, *max_clkr = NULL; + u8 max_div = 0; + + clks = _get_clksel_by_parent(clk, src_clk); + if (!clks) + return 0; + + /* + * Find the highest divisor (e.g., the one resulting in the + * lowest rate) to use as the default. This should avoid + * clock rates that are too high for the device. XXX A better + * solution here would be to try to determine if there is a + * divisor matching the original clock rate before the parent + * switch, and if it cannot be found, to fall back to the + * highest divisor. + */ + for (clkr = clks->rates; clkr->div; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + if (clkr->div > max_div) { + max_div = clkr->div; + max_clkr = clkr; + } + } + + if (max_div == 0) { + /* This indicates an error in the clksel data */ + WARN(1, "clock: Could not find divisor for clock %s parent %s" + "\n", clk->name, src_clk->parent->name); + return 0; + } + + *field_val = max_clkr->val; + + return max_div; +} + +/** + * _write_clksel_reg() - program a clock's clksel register in hardware + * @clk: struct clk * to program + * @v: clksel bitfield value to program (with LSB at bit 0) + * + * Shift the clksel register bitfield value @v to its appropriate + * location in the clksel register and write it in. This function + * will ensure that the write to the clksel_reg reaches its + * destination before returning -- important since PRM and CM register + * accesses can be quite slow compared to ARM cycles -- but does not + * take into account any time the hardware might take to switch the + * clock source. + */ +static void _write_clksel_reg(struct clk *clk, u32 field_val) +{ + u32 v; + + v = __raw_readl(clk->clksel_reg); + v &= ~clk->clksel_mask; + v |= field_val << __ffs(clk->clksel_mask); + __raw_writel(v, clk->clksel_reg); + + v = __raw_readl(clk->clksel_reg); /* OCP barrier */ +} + +/** + * _clksel_to_divisor() - turn clksel field value into integer divider + * @clk: OMAP struct clk to use + * @field_val: register field value to find + * + * Given a struct clk of a rate-selectable clksel clock, and a register field + * value to search for, find the corresponding clock divisor. The register + * field value should be pre-masked and shifted down so the LSB is at bit 0 + * before calling. Returns 0 on error or returns the actual integer divisor + * upon success. + */ +static u32 _clksel_to_divisor(struct clk *clk, u32 field_val) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + + clks = _get_clksel_by_parent(clk, clk->parent); + if (!clks) + return 0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + if (clkr->val == field_val) + break; + } + + if (!clkr->div) { + /* This indicates a data error */ + WARN(1, "clock: Could not find fieldval %d for clock %s parent " + "%s\n", field_val, clk->name, clk->parent->name); + return 0; + } + + return clkr->div; +} + +/** + * _divisor_to_clksel() - turn clksel integer divisor into a field value + * @clk: OMAP struct clk to use + * @div: integer divisor to search for + * + * Given a struct clk of a rate-selectable clksel clock, and a clock + * divisor, find the corresponding register field value. Returns the + * register field value _before_ left-shifting (i.e., LSB is at bit + * 0); or returns 0xFFFFFFFF (~0) upon error. + */ +static u32 _divisor_to_clksel(struct clk *clk, u32 div) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + + /* should never happen */ + WARN_ON(div == 0); + + clks = _get_clksel_by_parent(clk, clk->parent); + if (!clks) + return ~0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + if (clkr->div == div) + break; + } + + if (!clkr->div) { + pr_err("clock: Could not find divisor %d for clock %s parent " + "%s\n", div, clk->name, clk->parent->name); + return ~0; + } + + return clkr->val; +} + +/** + * _read_divisor() - get current divisor applied to parent clock (from hdwr) + * @clk: OMAP struct clk to use. + * + * Read the current divisor register value for @clk that is programmed + * into the hardware, convert it into the actual divisor value, and + * return it; or return 0 on error. + */ +static u32 _read_divisor(struct clk *clk) +{ + u32 v; + + if (!clk->clksel || !clk->clksel_mask) + return 0; + + v = __raw_readl(clk->clksel_reg); + v &= clk->clksel_mask; + v >>= __ffs(clk->clksel_mask); + + return _clksel_to_divisor(clk, v); +} + +/* Public functions */ + +/** + * omap2_clksel_round_rate_div() - find divisor for the given clock and rate + * @clk: OMAP struct clk to use + * @target_rate: desired clock rate + * @new_div: ptr to where we should store the divisor + * + * Finds 'best' divider value in an array based on the source and target + * rates. The divider array must be sorted with smallest divider first. + * This function is also used by the DPLL3 M2 divider code. + * + * Returns the rounded clock rate or returns 0xffffffff on error. + */ +u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, + u32 *new_div) +{ + unsigned long test_rate; + const struct clksel *clks; + const struct clksel_rate *clkr; + u32 last_div = 0; + + if (!clk->clksel || !clk->clksel_mask) + return ~0; + + pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", + clk->name, target_rate); + + *new_div = 1; + + clks = _get_clksel_by_parent(clk, clk->parent); + if (!clks) + return ~0; + + for (clkr = clks->rates; clkr->div; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + /* Sanity check */ + if (clkr->div <= last_div) + pr_err("clock: clksel_rate table not sorted " + "for clock %s", clk->name); + + last_div = clkr->div; + + test_rate = clk->parent->rate / clkr->div; + + if (test_rate <= target_rate) + break; /* found it */ + } + + if (!clkr->div) { + pr_err("clock: Could not find divisor for target " + "rate %ld for clock %s parent %s\n", target_rate, + clk->name, clk->parent->name); + return ~0; + } + + *new_div = clkr->div; + + pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div, + (clk->parent->rate / clkr->div)); + + return clk->parent->rate / clkr->div; +} + +/* + * Clocktype interface functions to the OMAP clock code + * (i.e., those used in struct clk field function pointers, etc.) + */ + +/** + * omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr + * @clk: OMAP clock struct ptr to use + * + * Given a pointer @clk to a source-selectable struct clk, read the + * hardware register and determine what its parent is currently set + * to. Update @clk's .parent field with the appropriate clk ptr. No + * return value. + */ +void omap2_init_clksel_parent(struct clk *clk) +{ + const struct clksel *clks; + const struct clksel_rate *clkr; + u32 r, found = 0; + + if (!clk->clksel || !clk->clksel_mask) + return; + + r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; + r >>= __ffs(clk->clksel_mask); + + for (clks = clk->clksel; clks->parent && !found; clks++) { + for (clkr = clks->rates; clkr->div && !found; clkr++) { + if (!(clkr->flags & cpu_mask)) + continue; + + if (clkr->val == r) { + if (clk->parent != clks->parent) { + pr_debug("clock: inited %s parent " + "to %s (was %s)\n", + clk->name, clks->parent->name, + ((clk->parent) ? + clk->parent->name : "NULL")); + clk_reparent(clk, clks->parent); + }; + found = 1; + } + } + } + + /* This indicates a data error */ + WARN(!found, "clock: %s: init parent: could not find regval %0x\n", + clk->name, r); + + return; +} + +/** + * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field + * @clk: struct clk * + * + * This function is intended to be called only by the clock framework. + * Each clksel clock should have its struct clk .recalc field set to this + * function. Returns the clock's current rate, based on its parent's rate + * and its current divisor setting in the hardware. + */ +unsigned long omap2_clksel_recalc(struct clk *clk) +{ + unsigned long rate; + u32 div = 0; + + div = _read_divisor(clk); + if (div == 0) + return clk->rate; + + rate = clk->parent->rate / div; + + pr_debug("clock: %s: recalc'd rate is %ld (div %d)\n", clk->name, + rate, div); + + return rate; +} + +/** + * omap2_clksel_round_rate() - find rounded rate for the given clock and rate + * @clk: OMAP struct clk to use + * @target_rate: desired clock rate + * + * This function is intended to be called only by the clock framework. + * Finds best target rate based on the source clock and possible dividers. + * rates. The divider array must be sorted with smallest divider first. + * + * Returns the rounded clock rate or returns 0xffffffff on error. + */ +long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) +{ + u32 new_div; + + return omap2_clksel_round_rate_div(clk, target_rate, &new_div); +} + +/** + * omap2_clksel_set_rate() - program clock rate in hardware + * @clk: struct clk * to program rate + * @rate: target rate to program + * + * This function is intended to be called only by the clock framework. + * Program @clk's rate to @rate in the hardware. The clock can be + * either enabled or disabled when this happens, although if the clock + * is enabled, some downstream devices may glitch or behave + * unpredictably when the clock rate is changed - this depends on the + * hardware. This function does not currently check the usecount of + * the clock, so if multiple drivers are using the clock, and the rate + * is changed, they will all be affected without any notification. + * Returns -EINVAL upon error, or 0 upon success. + */ +int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) +{ + u32 field_val, validrate, new_div = 0; + + if (!clk->clksel || !clk->clksel_mask) + return -EINVAL; + + validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); + if (validrate != rate) + return -EINVAL; + + field_val = _divisor_to_clksel(clk, new_div); + if (field_val == ~0) + return -EINVAL; + + _write_clksel_reg(clk, field_val); + + clk->rate = clk->parent->rate / new_div; + + pr_debug("clock: %s: set rate to %ld\n", clk->name, clk->rate); + + return 0; +} + +/* + * Clksel parent setting function - not passed in struct clk function + * pointer - instead, the OMAP clock code currently assumes that any + * parent-setting clock is a clksel clock, and calls + * omap2_clksel_set_parent() by default + */ + +/** + * omap2_clksel_set_parent() - change a clock's parent clock + * @clk: struct clk * of the child clock + * @new_parent: struct clk * of the new parent clock + * + * This function is intended to be called only by the clock framework. + * Change the parent clock of clock @clk to @new_parent. This is + * intended to be used while @clk is disabled. This function does not + * currently check the usecount of the clock, so if multiple drivers + * are using the clock, and the parent is changed, they will all be + * affected without any notification. Returns -EINVAL upon error, or + * 0 upon success. + */ +int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) +{ + u32 field_val = 0; + u32 parent_div; + + if (!clk->clksel || !clk->clksel_mask) + return -EINVAL; + + parent_div = _get_div_and_fieldval(new_parent, clk, &field_val); + if (!parent_div) + return -EINVAL; + + _write_clksel_reg(clk, field_val); + + clk_reparent(clk, new_parent); + + /* CLKSEL clocks follow their parents' rates, divided by a divisor */ + clk->rate = new_parent->rate; + + if (parent_div > 0) + clk->rate /= parent_div; + + pr_debug("clock: %s: set parent to %s (new rate %ld)\n", + clk->name, clk->parent->name, clk->rate); + + return 0; +} diff --git a/arch/arm/mach-omap2/clkt_dpll.c b/arch/arm/mach-omap2/clkt_dpll.c new file mode 100644 index 00000000000..e069a9be93d --- /dev/null +++ b/arch/arm/mach-omap2/clkt_dpll.c @@ -0,0 +1,359 @@ +/* + * OMAP2/3/4 DPLL clock functions + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <asm/div64.h> + +#include <plat/clock.h> + +#include "clock.h" +#include "cm-regbits-24xx.h" +#include "cm-regbits-34xx.h" + +/* DPLL rate rounding: minimum DPLL multiplier, divider values */ +#define DPLL_MIN_MULTIPLIER 2 +#define DPLL_MIN_DIVIDER 1 + +/* Possible error results from _dpll_test_mult */ +#define DPLL_MULT_UNDERFLOW -1 + +/* + * Scale factor to mitigate roundoff errors in DPLL rate rounding. + * The higher the scale factor, the greater the risk of arithmetic overflow, + * but the closer the rounded rate to the target rate. DPLL_SCALE_FACTOR + * must be a power of DPLL_SCALE_BASE. + */ +#define DPLL_SCALE_FACTOR 64 +#define DPLL_SCALE_BASE 2 +#define DPLL_ROUNDING_VAL ((DPLL_SCALE_BASE / 2) * \ + (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE)) + +/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ +#define OMAP3430_DPLL_FINT_BAND1_MIN 750000 +#define OMAP3430_DPLL_FINT_BAND1_MAX 2100000 +#define OMAP3430_DPLL_FINT_BAND2_MIN 7500000 +#define OMAP3430_DPLL_FINT_BAND2_MAX 21000000 + +/* + * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx. + * From device data manual section 4.3 "DPLL and DLL Specifications". + */ +#define OMAP3PLUS_DPLL_FINT_JTYPE_MIN 500000 +#define OMAP3PLUS_DPLL_FINT_JTYPE_MAX 2500000 +#define OMAP3PLUS_DPLL_FINT_MIN 32000 +#define OMAP3PLUS_DPLL_FINT_MAX 52000000 + +/* _dpll_test_fint() return codes */ +#define DPLL_FINT_UNDERFLOW -1 +#define DPLL_FINT_INVALID -2 + +/* Private functions */ + +/* + * _dpll_test_fint - test whether an Fint value is valid for the DPLL + * @clk: DPLL struct clk to test + * @n: divider value (N) to test + * + * Tests whether a particular divider @n will result in a valid DPLL + * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter + * Correction". Returns 0 if OK, -1 if the enclosing loop can terminate + * (assuming that it is counting N upwards), or -2 if the enclosing loop + * should skip to the next iteration (again assuming N is increasing). + */ +static int _dpll_test_fint(struct clk *clk, u8 n) +{ + struct dpll_data *dd; + long fint, fint_min, fint_max; + int ret = 0; + + dd = clk->dpll_data; + + /* DPLL divider must result in a valid jitter correction val */ + fint = clk->parent->rate / n; + + if (cpu_is_omap24xx()) { + /* Should not be called for OMAP2, so warn if it is called */ + WARN(1, "No fint limits available for OMAP2!\n"); + return DPLL_FINT_INVALID; + } else if (cpu_is_omap3430()) { + fint_min = OMAP3430_DPLL_FINT_BAND1_MIN; + fint_max = OMAP3430_DPLL_FINT_BAND2_MAX; + } else if (dd->flags & DPLL_J_TYPE) { + fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN; + fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX; + } else { + fint_min = OMAP3PLUS_DPLL_FINT_MIN; + fint_max = OMAP3PLUS_DPLL_FINT_MAX; + } + + if (fint < fint_min) { + pr_debug("rejecting n=%d due to Fint failure, " + "lowering max_divider\n", n); + dd->max_divider = n; + ret = DPLL_FINT_UNDERFLOW; + } else if (fint > fint_max) { + pr_debug("rejecting n=%d due to Fint failure, " + "boosting min_divider\n", n); + dd->min_divider = n; + ret = DPLL_FINT_INVALID; + } else if (cpu_is_omap3430() && fint > OMAP3430_DPLL_FINT_BAND1_MAX && + fint < OMAP3430_DPLL_FINT_BAND2_MIN) { + pr_debug("rejecting n=%d due to Fint failure\n", n); + ret = DPLL_FINT_INVALID; + } + + return ret; +} + +static unsigned long _dpll_compute_new_rate(unsigned long parent_rate, + unsigned int m, unsigned int n) +{ + unsigned long long num; + + num = (unsigned long long)parent_rate * m; + do_div(num, n); + return num; +} + +/* + * _dpll_test_mult - test a DPLL multiplier value + * @m: pointer to the DPLL m (multiplier) value under test + * @n: current DPLL n (divider) value under test + * @new_rate: pointer to storage for the resulting rounded rate + * @target_rate: the desired DPLL rate + * @parent_rate: the DPLL's parent clock rate + * + * This code tests a DPLL multiplier value, ensuring that the + * resulting rate will not be higher than the target_rate, and that + * the multiplier value itself is valid for the DPLL. Initially, the + * integer pointed to by the m argument should be prescaled by + * multiplying by DPLL_SCALE_FACTOR. The code will replace this with + * a non-scaled m upon return. This non-scaled m will result in a + * new_rate as close as possible to target_rate (but not greater than + * target_rate) given the current (parent_rate, n, prescaled m) + * triple. Returns DPLL_MULT_UNDERFLOW in the event that the + * non-scaled m attempted to underflow, which can allow the calling + * function to bail out early; or 0 upon success. + */ +static int _dpll_test_mult(int *m, int n, unsigned long *new_rate, + unsigned long target_rate, + unsigned long parent_rate) +{ + int r = 0, carry = 0; + + /* Unscale m and round if necessary */ + if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL) + carry = 1; + *m = (*m / DPLL_SCALE_FACTOR) + carry; + + /* + * The new rate must be <= the target rate to avoid programming + * a rate that is impossible for the hardware to handle + */ + *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); + if (*new_rate > target_rate) { + (*m)--; + *new_rate = 0; + } + + /* Guard against m underflow */ + if (*m < DPLL_MIN_MULTIPLIER) { + *m = DPLL_MIN_MULTIPLIER; + *new_rate = 0; + r = DPLL_MULT_UNDERFLOW; + } + + if (*new_rate == 0) + *new_rate = _dpll_compute_new_rate(parent_rate, *m, n); + + return r; +} + +/* Public functions */ + +void omap2_init_dpll_parent(struct clk *clk) +{ + u32 v; + struct dpll_data *dd; + + dd = clk->dpll_data; + if (!dd) + return; + + v = __raw_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + /* Reparent the struct clk in case the dpll is in bypass */ + if (cpu_is_omap24xx()) { + if (v == OMAP2XXX_EN_DPLL_LPBYPASS || + v == OMAP2XXX_EN_DPLL_FRBYPASS) + clk_reparent(clk, dd->clk_bypass); + } else if (cpu_is_omap34xx()) { + if (v == OMAP3XXX_EN_DPLL_LPBYPASS || + v == OMAP3XXX_EN_DPLL_FRBYPASS) + clk_reparent(clk, dd->clk_bypass); + } else if (cpu_is_omap44xx()) { + if (v == OMAP4XXX_EN_DPLL_LPBYPASS || + v == OMAP4XXX_EN_DPLL_FRBYPASS || + v == OMAP4XXX_EN_DPLL_MNBYPASS) + clk_reparent(clk, dd->clk_bypass); + } + return; +} + +/** + * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate + * @clk: struct clk * of a DPLL + * + * DPLLs can be locked or bypassed - basically, enabled or disabled. + * When locked, the DPLL output depends on the M and N values. When + * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock + * or sys_clk. Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and + * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively + * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk. + * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is + * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0 + * if the clock @clk is not a DPLL. + */ +u32 omap2_get_dpll_rate(struct clk *clk) +{ + long long dpll_clk; + u32 dpll_mult, dpll_div, v; + struct dpll_data *dd; + + dd = clk->dpll_data; + if (!dd) + return 0; + + /* Return bypass rate if DPLL is bypassed */ + v = __raw_readl(dd->control_reg); + v &= dd->enable_mask; + v >>= __ffs(dd->enable_mask); + + if (cpu_is_omap24xx()) { + if (v == OMAP2XXX_EN_DPLL_LPBYPASS || + v == OMAP2XXX_EN_DPLL_FRBYPASS) + return dd->clk_bypass->rate; + } else if (cpu_is_omap34xx()) { + if (v == OMAP3XXX_EN_DPLL_LPBYPASS || + v == OMAP3XXX_EN_DPLL_FRBYPASS) + return dd->clk_bypass->rate; + } else if (cpu_is_omap44xx()) { + if (v == OMAP4XXX_EN_DPLL_LPBYPASS || + v == OMAP4XXX_EN_DPLL_FRBYPASS || + v == OMAP4XXX_EN_DPLL_MNBYPASS) + return dd->clk_bypass->rate; + } + + v = __raw_readl(dd->mult_div1_reg); + dpll_mult = v & dd->mult_mask; + dpll_mult >>= __ffs(dd->mult_mask); + dpll_div = v & dd->div1_mask; + dpll_div >>= __ffs(dd->div1_mask); + + dpll_clk = (long long)dd->clk_ref->rate * dpll_mult; + do_div(dpll_clk, dpll_div + 1); + + return dpll_clk; +} + +/* DPLL rate rounding code */ + +/** + * omap2_dpll_round_rate - round a target rate for an OMAP DPLL + * @clk: struct clk * for a DPLL + * @target_rate: desired DPLL clock rate + * + * Given a DPLL and a desired target rate, round the target rate to a + * possible, programmable rate for this DPLL. Attempts to select the + * minimum possible n. Stores the computed (m, n) in the DPLL's + * dpll_data structure so set_rate() will not need to call this + * (expensive) function again. Returns ~0 if the target rate cannot + * be rounded, or the rounded rate upon success. + */ +long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate) +{ + int m, n, r, scaled_max_m; + unsigned long scaled_rt_rp; + unsigned long new_rate = 0; + struct dpll_data *dd; + + if (!clk || !clk->dpll_data) + return ~0; + + dd = clk->dpll_data; + + pr_debug("clock: %s: starting DPLL round_rate, target rate %ld\n", + clk->name, target_rate); + + scaled_rt_rp = target_rate / (dd->clk_ref->rate / DPLL_SCALE_FACTOR); + scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR; + + dd->last_rounded_rate = 0; + + for (n = dd->min_divider; n <= dd->max_divider; n++) { + + /* Is the (input clk, divider) pair valid for the DPLL? */ + r = _dpll_test_fint(clk, n); + if (r == DPLL_FINT_UNDERFLOW) + break; + else if (r == DPLL_FINT_INVALID) + continue; + + /* Compute the scaled DPLL multiplier, based on the divider */ + m = scaled_rt_rp * n; + + /* + * Since we're counting n up, a m overflow means we + * can bail out completely (since as n increases in + * the next iteration, there's no way that m can + * increase beyond the current m) + */ + if (m > scaled_max_m) + break; + + r = _dpll_test_mult(&m, n, &new_rate, target_rate, + dd->clk_ref->rate); + + /* m can't be set low enough for this n - try with a larger n */ + if (r == DPLL_MULT_UNDERFLOW) + continue; + + pr_debug("clock: %s: m = %d: n = %d: new_rate = %ld\n", + clk->name, m, n, new_rate); + + if (target_rate == new_rate) { + dd->last_rounded_m = m; + dd->last_rounded_n = n; + dd->last_rounded_rate = target_rate; + break; + } + } + + if (target_rate != new_rate) { + pr_debug("clock: %s: cannot round to rate %ld\n", clk->name, + target_rate); + return ~0; + } + + return target_rate; +} + diff --git a/arch/arm/mach-omap2/clkt_iclk.c b/arch/arm/mach-omap2/clkt_iclk.c new file mode 100644 index 00000000000..3d43fba2542 --- /dev/null +++ b/arch/arm/mach-omap2/clkt_iclk.c @@ -0,0 +1,82 @@ +/* + * OMAP2/3 interface clock control + * + * Copyright (C) 2011 Nokia Corporation + * Paul Walmsley + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <plat/clock.h> +#include <plat/prcm.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" + +/* Private functions */ + +/* XXX */ +void omap2_clkt_iclk_allow_idle(struct clk *clk) +{ + u32 v, r; + + r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = __raw_readl((__force void __iomem *)r); + v |= (1 << clk->enable_bit); + __raw_writel(v, (__force void __iomem *)r); +} + +/* XXX */ +void omap2_clkt_iclk_deny_idle(struct clk *clk) +{ + u32 v, r; + + r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN)); + + v = __raw_readl((__force void __iomem *)r); + v &= ~(1 << clk->enable_bit); + __raw_writel(v, (__force void __iomem *)r); +} + +/* Public data */ + +const struct clkops clkops_omap2_iclk_dflt_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_companion = omap2_clk_dflt_find_companion, + .find_idlest = omap2_clk_dflt_find_idlest, + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clkops clkops_omap2_iclk_dflt = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clkops clkops_omap2_iclk_idle_only = { + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + +const struct clkops clkops_omap2_mdmclk_dflt_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_companion = omap2_clk_dflt_find_companion, + .find_idlest = omap2_clk_dflt_find_idlest, + .allow_idle = omap2_clkt_iclk_allow_idle, + .deny_idle = omap2_clkt_iclk_deny_idle, +}; + diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c new file mode 100644 index 00000000000..f57ed5baecc --- /dev/null +++ b/arch/arm/mach-omap2/clock.c @@ -0,0 +1,545 @@ +/* + * linux/arch/arm/mach-omap2/clock.c + * + * Copyright (C) 2005-2008 Texas Instruments, Inc. + * Copyright (C) 2004-2010 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/bitops.h> +#include <trace/events/power.h> + +#include <asm/cpu.h> +#include <plat/clock.h> +#include "clockdomain.h" +#include <plat/cpu.h> +#include <plat/prcm.h> + +#include "clock.h" +#include "cm2xxx_3xxx.h" +#include "cm-regbits-24xx.h" +#include "cm-regbits-34xx.h" + +u16 cpu_mask; + +/* + * clkdm_control: if true, then when a clock is enabled in the + * hardware, its clockdomain will first be enabled; and when a clock + * is disabled in the hardware, its clockdomain will be disabled + * afterwards. + */ +static bool clkdm_control = true; + +/* + * OMAP2+ specific clock functions + */ + +/* Private functions */ + +/** + * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE + * @clk: struct clk * belonging to the module + * + * If the necessary clocks for the OMAP hardware IP block that + * corresponds to clock @clk are enabled, then wait for the module to + * indicate readiness (i.e., to leave IDLE). This code does not + * belong in the clock code and will be moved in the medium term to + * module-dependent code. No return value. + */ +static void _omap2_module_wait_ready(struct clk *clk) +{ + void __iomem *companion_reg, *idlest_reg; + u8 other_bit, idlest_bit, idlest_val; + + /* Not all modules have multiple clocks that their IDLEST depends on */ + if (clk->ops->find_companion) { + clk->ops->find_companion(clk, &companion_reg, &other_bit); + if (!(__raw_readl(companion_reg) & (1 << other_bit))) + return; + } + + clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); + + omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), idlest_val, + clk->name); +} + +/* Public functions */ + +/** + * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk + * @clk: OMAP clock struct ptr to use + * + * Convert a clockdomain name stored in a struct clk 'clk' into a + * clockdomain pointer, and save it into the struct clk. Intended to be + * called during clk_register(). No return value. + */ +void omap2_init_clk_clkdm(struct clk *clk) +{ + struct clockdomain *clkdm; + + if (!clk->clkdm_name) + return; + + clkdm = clkdm_lookup(clk->clkdm_name); + if (clkdm) { + pr_debug("clock: associated clk %s to clkdm %s\n", + clk->name, clk->clkdm_name); + clk->clkdm = clkdm; + } else { + pr_debug("clock: could not associate clk %s to " + "clkdm %s\n", clk->name, clk->clkdm_name); + } +} + +/** + * omap2_clk_disable_clkdm_control - disable clkdm control on clk enable/disable + * + * Prevent the OMAP clock code from calling into the clockdomain code + * when a hardware clock in that clockdomain is enabled or disabled. + * Intended to be called at init time from omap*_clk_init(). No + * return value. + */ +void __init omap2_clk_disable_clkdm_control(void) +{ + clkdm_control = false; +} + +/** + * omap2_clk_dflt_find_companion - find companion clock to @clk + * @clk: struct clk * to find the companion clock of + * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in + * @other_bit: u8 ** to return the companion clock bit shift in + * + * Note: We don't need special code here for INVERT_ENABLE for the + * time being since INVERT_ENABLE only applies to clocks enabled by + * CM_CLKEN_PLL + * + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's + * just a matter of XORing the bits. + * + * Some clocks don't have companion clocks. For example, modules with + * only an interface clock (such as MAILBOXES) don't have a companion + * clock. Right now, this code relies on the hardware exporting a bit + * in the correct companion register that indicates that the + * nonexistent 'companion clock' is active. Future patches will + * associate this type of code with per-module data structures to + * avoid this issue, and remove the casts. No return value. + */ +void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, + u8 *other_bit) +{ + u32 r; + + /* + * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes + * it's just a matter of XORing the bits. + */ + r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); + + *other_reg = (__force void __iomem *)r; + *other_bit = clk->enable_bit; +} + +/** + * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk + * @clk: struct clk * to find IDLEST info for + * @idlest_reg: void __iomem ** to return the CM_IDLEST va in + * @idlest_bit: u8 * to return the CM_IDLEST bit shift in + * @idlest_val: u8 * to return the idle status indicator + * + * Return the CM_IDLEST register address and bit shift corresponding + * to the module that "owns" this clock. This default code assumes + * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that + * the IDLEST register address ID corresponds to the CM_*CLKEN + * register address ID (e.g., that CM_FCLKEN2 corresponds to + * CM_IDLEST2). This is not true for all modules. No return value. + */ +void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val) +{ + u32 r; + + r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); + *idlest_reg = (__force void __iomem *)r; + *idlest_bit = clk->enable_bit; + + /* + * 24xx uses 0 to indicate not ready, and 1 to indicate ready. + * 34xx reverses this, just to keep us on our toes + * AM35xx uses both, depending on the module. + */ + if (cpu_is_omap24xx()) + *idlest_val = OMAP24XX_CM_IDLEST_VAL; + else if (cpu_is_omap34xx()) + *idlest_val = OMAP34XX_CM_IDLEST_VAL; + else + BUG(); + +} + +int omap2_dflt_clk_enable(struct clk *clk) +{ + u32 v; + + if (unlikely(clk->enable_reg == NULL)) { + pr_err("clock.c: Enable for %s without enable code\n", + clk->name); + return 0; /* REVISIT: -EINVAL */ + } + + v = __raw_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v &= ~(1 << clk->enable_bit); + else + v |= (1 << clk->enable_bit); + __raw_writel(v, clk->enable_reg); + v = __raw_readl(clk->enable_reg); /* OCP barrier */ + + if (clk->ops->find_idlest) + _omap2_module_wait_ready(clk); + + return 0; +} + +void omap2_dflt_clk_disable(struct clk *clk) +{ + u32 v; + + if (!clk->enable_reg) { + /* + * 'Independent' here refers to a clock which is not + * controlled by its parent. + */ + printk(KERN_ERR "clock: clk_disable called on independent " + "clock %s which has no enable_reg\n", clk->name); + return; + } + + v = __raw_readl(clk->enable_reg); + if (clk->flags & INVERT_ENABLE) + v |= (1 << clk->enable_bit); + else + v &= ~(1 << clk->enable_bit); + __raw_writel(v, clk->enable_reg); + /* No OCP barrier needed here since it is a disable operation */ +} + +const struct clkops clkops_omap2_dflt_wait = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, + .find_companion = omap2_clk_dflt_find_companion, + .find_idlest = omap2_clk_dflt_find_idlest, +}; + +const struct clkops clkops_omap2_dflt = { + .enable = omap2_dflt_clk_enable, + .disable = omap2_dflt_clk_disable, +}; + +/** + * omap2_clk_disable - disable a clock, if the system is not using it + * @clk: struct clk * to disable + * + * Decrements the usecount on struct clk @clk. If there are no users + * left, call the clkops-specific clock disable function to disable it + * in hardware. If the clock is part of a clockdomain (which they all + * should be), request that the clockdomain be disabled. (It too has + * a usecount, and so will not be disabled in the hardware until it no + * longer has any users.) If the clock has a parent clock (most of + * them do), then call ourselves, recursing on the parent clock. This + * can cause an entire branch of the clock tree to be powered off by + * simply disabling one clock. Intended to be called with the clockfw_lock + * spinlock held. No return value. + */ +void omap2_clk_disable(struct clk *clk) +{ + if (clk->usecount == 0) { + WARN(1, "clock: %s: omap2_clk_disable() called, but usecount " + "already 0?", clk->name); + return; + } + + pr_debug("clock: %s: decrementing usecount\n", clk->name); + + clk->usecount--; + + if (clk->usecount > 0) + return; + + pr_debug("clock: %s: disabling in hardware\n", clk->name); + + if (clk->ops && clk->ops->disable) { + trace_clock_disable(clk->name, 0, smp_processor_id()); + clk->ops->disable(clk); + } + + if (clkdm_control && clk->clkdm) + clkdm_clk_disable(clk->clkdm, clk); + + if (clk->parent) + omap2_clk_disable(clk->parent); +} + +/** + * omap2_clk_enable - request that the system enable a clock + * @clk: struct clk * to enable + * + * Increments the usecount on struct clk @clk. If there were no users + * previously, then recurse up the clock tree, enabling all of the + * clock's parents and all of the parent clockdomains, and finally, + * enabling @clk's clockdomain, and @clk itself. Intended to be + * called with the clockfw_lock spinlock held. Returns 0 upon success + * or a negative error code upon failure. + */ +int omap2_clk_enable(struct clk *clk) +{ + int ret; + + pr_debug("clock: %s: incrementing usecount\n", clk->name); + + clk->usecount++; + + if (clk->usecount > 1) + return 0; + + pr_debug("clock: %s: enabling in hardware\n", clk->name); + + if (clk->parent) { + ret = omap2_clk_enable(clk->parent); + if (ret) { + WARN(1, "clock: %s: could not enable parent %s: %d\n", + clk->name, clk->parent->name, ret); + goto oce_err1; + } + } + + if (clkdm_control && clk->clkdm) { + ret = clkdm_clk_enable(clk->clkdm, clk); + if (ret) { + WARN(1, "clock: %s: could not enable clockdomain %s: " + "%d\n", clk->name, clk->clkdm->name, ret); + goto oce_err2; + } + } + + if (clk->ops && clk->ops->enable) { + trace_clock_enable(clk->name, 1, smp_processor_id()); + ret = clk->ops->enable(clk); + if (ret) { + WARN(1, "clock: %s: could not enable: %d\n", + clk->name, ret); + goto oce_err3; + } + } + + return 0; + +oce_err3: + if (clkdm_control && clk->clkdm) + clkdm_clk_disable(clk->clkdm, clk); +oce_err2: + if (clk->parent) + omap2_clk_disable(clk->parent); +oce_err1: + clk->usecount--; + + return ret; +} + +/* Given a clock and a rate apply a clock specific rounding function */ +long omap2_clk_round_rate(struct clk *clk, unsigned long rate) +{ + if (clk->round_rate) + return clk->round_rate(clk, rate); + + return clk->rate; +} + +/* Set the clock rate for a clock source */ +int omap2_clk_set_rate(struct clk *clk, unsigned long rate) +{ + int ret = -EINVAL; + + pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate); + + /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */ + if (clk->set_rate) { + trace_clock_set_rate(clk->name, rate, smp_processor_id()); + ret = clk->set_rate(clk, rate); + } + + return ret; +} + +int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) +{ + if (!clk->clksel) + return -EINVAL; + + if (clk->parent == new_parent) + return 0; + + return omap2_clksel_set_parent(clk, new_parent); +} + +/* OMAP3/4 non-CORE DPLL clkops */ + +#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4) + +const struct clkops clkops_omap3_noncore_dpll_ops = { + .enable = omap3_noncore_dpll_enable, + .disable = omap3_noncore_dpll_disable, + .allow_idle = omap3_dpll_allow_idle, + .deny_idle = omap3_dpll_deny_idle, +}; + +const struct clkops clkops_omap3_core_dpll_ops = { + .allow_idle = omap3_dpll_allow_idle, + .deny_idle = omap3_dpll_deny_idle, +}; + +#endif + +/* + * OMAP2+ clock reset and init functions + */ + +#ifdef CONFIG_OMAP_RESET_CLOCKS +void omap2_clk_disable_unused(struct clk *clk) +{ + u32 regval32, v; + + v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0; + + regval32 = __raw_readl(clk->enable_reg); + if ((regval32 & (1 << clk->enable_bit)) == v) + return; + + pr_debug("Disabling unused clock \"%s\"\n", clk->name); + if (cpu_is_omap34xx()) { + omap2_clk_enable(clk); + omap2_clk_disable(clk); + } else { + clk->ops->disable(clk); + } + if (clk->clkdm != NULL) + pwrdm_clkdm_state_switch(clk->clkdm); +} +#endif + +/** + * omap2_clk_switch_mpurate_at_boot - switch ARM MPU rate by boot-time argument + * @mpurate_ck_name: clk name of the clock to change rate + * + * Change the ARM MPU clock rate to the rate specified on the command + * line, if one was specified. @mpurate_ck_name should be + * "virt_prcm_set" on OMAP2xxx and "dpll1_ck" on OMAP34xx/OMAP36xx. + * XXX Does not handle voltage scaling - on OMAP2xxx this is currently + * handled by the virt_prcm_set clock, but this should be handled by + * the OPP layer. XXX This is intended to be handled by the OPP layer + * code in the near future and should be removed from the clock code. + * Returns -EINVAL if 'mpurate' is zero or if clk_set_rate() rejects + * the rate, -ENOENT if the struct clk referred to by @mpurate_ck_name + * cannot be found, or 0 upon success. + */ +int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name) +{ + struct clk *mpurate_ck; + int r; + + if (!mpurate) + return -EINVAL; + + mpurate_ck = clk_get(NULL, mpurate_ck_name); + if (WARN(IS_ERR(mpurate_ck), "Failed to get %s.\n", mpurate_ck_name)) + return -ENOENT; + + r = clk_set_rate(mpurate_ck, mpurate); + if (IS_ERR_VALUE(r)) { + WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n", + mpurate_ck->name, mpurate, r); + clk_put(mpurate_ck); + return -EINVAL; + } + + calibrate_delay(); + recalculate_root_clocks(); + + clk_put(mpurate_ck); + + return 0; +} + +/** + * omap2_clk_print_new_rates - print summary of current clock tree rates + * @hfclkin_ck_name: clk name for the off-chip HF oscillator + * @core_ck_name: clk name for the on-chip CORE_CLK + * @mpu_ck_name: clk name for the ARM MPU clock + * + * Prints a short message to the console with the HFCLKIN oscillator + * rate, the rate of the CORE clock, and the rate of the ARM MPU clock. + * Called by the boot-time MPU rate switching code. XXX This is intended + * to be handled by the OPP layer code in the near future and should be + * removed from the clock code. No return value. + */ +void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name, + const char *core_ck_name, + const char *mpu_ck_name) +{ + struct clk *hfclkin_ck, *core_ck, *mpu_ck; + unsigned long hfclkin_rate; + + mpu_ck = clk_get(NULL, mpu_ck_name); + if (WARN(IS_ERR(mpu_ck), "clock: failed to get %s.\n", mpu_ck_name)) + return; + + core_ck = clk_get(NULL, core_ck_name); + if (WARN(IS_ERR(core_ck), "clock: failed to get %s.\n", core_ck_name)) + return; + + hfclkin_ck = clk_get(NULL, hfclkin_ck_name); + if (WARN(IS_ERR(hfclkin_ck), "Failed to get %s.\n", hfclkin_ck_name)) + return; + + hfclkin_rate = clk_get_rate(hfclkin_ck); + + pr_info("Switched to new clocking rate (Crystal/Core/MPU): " + "%ld.%01ld/%ld/%ld MHz\n", + (hfclkin_rate / 1000000), + ((hfclkin_rate / 100000) % 10), + (clk_get_rate(core_ck) / 1000000), + (clk_get_rate(mpu_ck) / 1000000)); +} + +/* Common data */ + +struct clk_functions omap2_clk_functions = { + .clk_enable = omap2_clk_enable, + .clk_disable = omap2_clk_disable, + .clk_round_rate = omap2_clk_round_rate, + .clk_set_rate = omap2_clk_set_rate, + .clk_set_parent = omap2_clk_set_parent, + .clk_disable_unused = omap2_clk_disable_unused, +#ifdef CONFIG_CPU_FREQ + /* These will be removed when the OPP code is integrated */ + .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, + .clk_exit_cpufreq_table = omap2_clk_exit_cpufreq_table, +#endif +}; + diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h new file mode 100644 index 00000000000..b8c2a686481 --- /dev/null +++ b/arch/arm/mach-omap2/clock.h @@ -0,0 +1,166 @@ +/* + * linux/arch/arm/mach-omap2/clock.h + * + * Copyright (C) 2005-2009 Texas Instruments, Inc. + * Copyright (C) 2004-2011 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * 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. + */ + +#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H +#define __ARCH_ARM_MACH_OMAP2_CLOCK_H + +#include <linux/kernel.h> + +#include <plat/clock.h> + +/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */ +#define CORE_CLK_SRC_32K 0x0 +#define CORE_CLK_SRC_DPLL 0x1 +#define CORE_CLK_SRC_DPLL_X2 0x2 + +/* OMAP2xxx CM_CLKEN_PLL.EN_DPLL bits - for omap2_get_dpll_rate() */ +#define OMAP2XXX_EN_DPLL_LPBYPASS 0x1 +#define OMAP2XXX_EN_DPLL_FRBYPASS 0x2 +#define OMAP2XXX_EN_DPLL_LOCKED 0x3 + +/* OMAP3xxx CM_CLKEN_PLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */ +#define OMAP3XXX_EN_DPLL_LPBYPASS 0x5 +#define OMAP3XXX_EN_DPLL_FRBYPASS 0x6 +#define OMAP3XXX_EN_DPLL_LOCKED 0x7 + +/* OMAP4xxx CM_CLKMODE_DPLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */ +#define OMAP4XXX_EN_DPLL_MNBYPASS 0x4 +#define OMAP4XXX_EN_DPLL_LPBYPASS 0x5 +#define OMAP4XXX_EN_DPLL_FRBYPASS 0x6 +#define OMAP4XXX_EN_DPLL_LOCKED 0x7 + +/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */ +#define DPLL_LOW_POWER_STOP 0x1 +#define DPLL_LOW_POWER_BYPASS 0x5 +#define DPLL_LOCKED 0x7 + +/* DPLL Type and DCO Selection Flags */ +#define DPLL_J_TYPE 0x1 + +int omap2_clk_enable(struct clk *clk); +void omap2_clk_disable(struct clk *clk); +long omap2_clk_round_rate(struct clk *clk, unsigned long rate); +int omap2_clk_set_rate(struct clk *clk, unsigned long rate); +int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent); +long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate); +unsigned long omap3_dpll_recalc(struct clk *clk); +unsigned long omap3_clkoutx2_recalc(struct clk *clk); +void omap3_dpll_allow_idle(struct clk *clk); +void omap3_dpll_deny_idle(struct clk *clk); +u32 omap3_dpll_autoidle_read(struct clk *clk); +int omap3_noncore_dpll_set_rate(struct clk *clk, unsigned long rate); +int omap3_noncore_dpll_enable(struct clk *clk); +void omap3_noncore_dpll_disable(struct clk *clk); +int omap4_dpllmx_gatectrl_read(struct clk *clk); +void omap4_dpllmx_allow_gatectrl(struct clk *clk); +void omap4_dpllmx_deny_gatectrl(struct clk *clk); +long omap4_dpll_regm4xen_round_rate(struct clk *clk, unsigned long target_rate); +unsigned long omap4_dpll_regm4xen_recalc(struct clk *clk); + +#ifdef CONFIG_OMAP_RESET_CLOCKS +void omap2_clk_disable_unused(struct clk *clk); +#else +#define omap2_clk_disable_unused NULL +#endif + +void omap2_init_clk_clkdm(struct clk *clk); +void __init omap2_clk_disable_clkdm_control(void); + +/* clkt_clksel.c public functions */ +u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, + u32 *new_div); +void omap2_init_clksel_parent(struct clk *clk); +unsigned long omap2_clksel_recalc(struct clk *clk); +long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); +int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); +int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); + +/* clkt_iclk.c public functions */ +extern void omap2_clkt_iclk_allow_idle(struct clk *clk); +extern void omap2_clkt_iclk_deny_idle(struct clk *clk); + +u32 omap2_get_dpll_rate(struct clk *clk); +void omap2_init_dpll_parent(struct clk *clk); + +int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); + + +#ifdef CONFIG_ARCH_OMAP2 +void omap2xxx_clk_prepare_for_reboot(void); +#else +static inline void omap2xxx_clk_prepare_for_reboot(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP3 +void omap3_clk_prepare_for_reboot(void); +#else +static inline void omap3_clk_prepare_for_reboot(void) +{ +} +#endif + +#ifdef CONFIG_ARCH_OMAP4 +void omap4_clk_prepare_for_reboot(void); +#else +static inline void omap4_clk_prepare_for_reboot(void) +{ +} +#endif + +int omap2_dflt_clk_enable(struct clk *clk); +void omap2_dflt_clk_disable(struct clk *clk); +void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg, + u8 *other_bit); +void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg, + u8 *idlest_bit, u8 *idlest_val); +int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name); +void omap2_clk_print_new_rates(const char *hfclkin_ck_name, + const char *core_ck_name, + const char *mpu_ck_name); + +extern u16 cpu_mask; + +extern const struct clkops clkops_omap2_dflt_wait; +extern const struct clkops clkops_dummy; +extern const struct clkops clkops_omap2_dflt; + +extern struct clk_functions omap2_clk_functions; +extern struct clk *vclk, *sclk; + +extern const struct clksel_rate gpt_32k_rates[]; +extern const struct clksel_rate gpt_sys_rates[]; +extern const struct clksel_rate gfx_l3_rates[]; +extern const struct clksel_rate dsp_ick_rates[]; + +#if defined(CONFIG_ARCH_OMAP2) && defined(CONFIG_CPU_FREQ) +extern void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table); +extern void omap2_clk_exit_cpufreq_table(struct cpufreq_frequency_table **table); +#else +#define omap2_clk_init_cpufreq_table 0 +#define omap2_clk_exit_cpufreq_table 0 +#endif + +extern const struct clkops clkops_omap2_iclk_dflt_wait; +extern const struct clkops clkops_omap2_iclk_dflt; +extern const struct clkops clkops_omap2_iclk_idle_only; +extern const struct clkops clkops_omap2_mdmclk_dflt_wait; +extern const struct clkops clkops_omap2xxx_dpll_ops; +extern const struct clkops clkops_omap3_noncore_dpll_ops; +extern const struct clkops clkops_omap3_core_dpll_ops; +extern const struct clkops clkops_omap4_dpllmx_ops; + +#endif diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c new file mode 100644 index 00000000000..61ad3855f10 --- /dev/null +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -0,0 +1,2006 @@ +/* + * OMAP2420 clock data + * + * Copyright (C) 2005-2009 Texas Instruments, Inc. + * Copyright (C) 2004-2011 Nokia Corporation + * + * Contacts: + * Richard Woodruff <r-woodruff2@ti.com> + * Paul Walmsley + * + * 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/kernel.h> +#include <linux/clk.h> +#include <linux/list.h> + +#include <plat/clkdev_omap.h> + +#include "clock.h" +#include "clock2xxx.h" +#include "opp2xxx.h" +#include "cm2xxx_3xxx.h" +#include "prm2xxx_3xxx.h" +#include "prm-regbits-24xx.h" +#include "cm-regbits-24xx.h" +#include "sdrc.h" +#include "control.h" + +#define OMAP_CM_REGADDR OMAP2420_CM_REGADDR + +/* + * 2420 clock tree. + * + * NOTE:In many cases here we are assigning a 'default' parent. In + * many cases the parent is selectable. The set parent calls will + * also switch sources. + * + * Several sources are given initial rates which may be wrong, this will + * be fixed up in the init func. + * + * Things are broadly separated below by clock domains. It is + * noteworthy that most peripherals have dependencies on multiple clock + * domains. Many get their interface clocks from the L4 domain, but get + * functional clocks from fixed sources or other core domain derived + * clocks. + */ + +/* Base external input clocks */ +static struct clk func_32k_ck = { + .name = "func_32k_ck", + .ops = &clkops_null, + .rate = 32768, + .clkdm_name = "wkup_clkdm", +}; + +static struct clk secure_32k_ck = { + .name = "secure_32k_ck", + .ops = &clkops_null, + .rate = 32768, + .clkdm_name = "wkup_clkdm", +}; + +/* Typical 12/13MHz in standalone mode, will be 26Mhz in chassis mode */ +static struct clk osc_ck = { /* (*12, *13, 19.2, *26, 38.4)MHz */ + .name = "osc_ck", + .ops = &clkops_oscck, + .clkdm_name = "wkup_clkdm", + .recalc = &omap2_osc_clk_recalc, +}; + +/* Without modem likely 12MHz, with modem likely 13MHz */ +static struct clk sys_ck = { /* (*12, *13, 19.2, 26, 38.4)MHz */ + .name = "sys_ck", /* ~ ref_clk also */ + .ops = &clkops_null, + .parent = &osc_ck, + .clkdm_name = "wkup_clkdm", + .recalc = &omap2xxx_sys_clk_recalc, +}; + +static struct clk alt_ck = { /* Typical 54M or 48M, may not exist */ + .name = "alt_ck", + .ops = &clkops_null, + .rate = 54000000, + .clkdm_name = "wkup_clkdm", +}; + +/* Optional external clock input for McBSP CLKS */ +static struct clk mcbsp_clks = { + .name = "mcbsp_clks", + .ops = &clkops_null, +}; + +/* + * Analog domain root source clocks + */ + +/* dpll_ck, is broken out in to special cases through clksel */ +/* REVISIT: Rate changes on dpll_ck trigger a full set change. ... + * deal with this + */ + +static struct dpll_data dpll_dd = { + .mult_div1_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), + .mult_mask = OMAP24XX_DPLL_MULT_MASK, + .div1_mask = OMAP24XX_DPLL_DIV_MASK, + .clk_bypass = &sys_ck, + .clk_ref = &sys_ck, + .control_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN), + .enable_mask = OMAP24XX_EN_DPLL_MASK, + .max_multiplier = 1023, + .min_divider = 1, + .max_divider = 16, +}; + +/* + * XXX Cannot add round_rate here yet, as this is still a composite clock, + * not just a DPLL + */ +static struct clk dpll_ck = { + .name = "dpll_ck", + .ops = &clkops_omap2xxx_dpll_ops, + .parent = &sys_ck, /* Can be func_32k also */ + .dpll_data = &dpll_dd, + .clkdm_name = "wkup_clkdm", + .recalc = &omap2_dpllcore_recalc, + .set_rate = &omap2_reprogram_dpllcore, +}; + +static struct clk apll96_ck = { + .name = "apll96_ck", + .ops = &clkops_apll96, + .parent = &sys_ck, + .rate = 96000000, + .flags = ENABLE_ON_INIT, + .clkdm_name = "wkup_clkdm", + .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN), + .enable_bit = OMAP24XX_EN_96M_PLL_SHIFT, +}; + +static struct clk apll54_ck = { + .name = "apll54_ck", + .ops = &clkops_apll54, + .parent = &sys_ck, + .rate = 54000000, + .flags = ENABLE_ON_INIT, + .clkdm_name = "wkup_clkdm", + .enable_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKEN), + .enable_bit = OMAP24XX_EN_54M_PLL_SHIFT, +}; + +/* + * PRCM digital base sources + */ + +/* func_54m_ck */ + +static const struct clksel_rate func_54m_apll54_rates[] = { + { .div = 1, .val = 0, .flags = RATE_IN_24XX }, + { .div = 0 }, +}; + +static const struct clksel_rate func_54m_alt_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 0 }, +}; + +static const struct clksel func_54m_clksel[] = { + { .parent = &apll54_ck, .rates = func_54m_apll54_rates, }, + { .parent = &alt_ck, .rates = func_54m_alt_rates, }, + { .parent = NULL }, +}; + +static struct clk func_54m_ck = { + .name = "func_54m_ck", + .ops = &clkops_null, + .parent = &apll54_ck, /* can also be alt_clk */ + .clkdm_name = "wkup_clkdm", + .init = &omap2_init_clksel_parent, + .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), + .clksel_mask = OMAP24XX_54M_SOURCE_MASK, + .clksel = func_54m_clksel, + .recalc = &omap2_clksel_recalc, +}; + +static struct clk core_ck = { + .name = "core_ck", + .ops = &clkops_null, + .parent = &dpll_ck, /* can also be 32k */ + .clkdm_name = "wkup_clkdm", + .recalc = &followparent_recalc, +}; + +static struct clk func_96m_ck = { + .name = "func_96m_ck", + .ops = &clkops_null, + .parent = &apll96_ck, + .clkdm_name = "wkup_clkdm", + .recalc = &followparent_recalc, +}; + +/* func_48m_ck */ + +static const struct clksel_rate func_48m_apll96_rates[] = { + { .div = 2, .val = 0, .flags = RATE_IN_24XX }, + { .div = 0 }, +}; + +static const struct clksel_rate func_48m_alt_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 0 }, +}; + +static const struct clksel func_48m_clksel[] = { + { .parent = &apll96_ck, .rates = func_48m_apll96_rates }, + { .parent = &alt_ck, .rates = func_48m_alt_rates }, + { .parent = NULL } +}; + +static struct clk func_48m_ck = { + .name = "func_48m_ck", + .ops = &clkops_null, + .parent = &apll96_ck, /* 96M or Alt */ + .clkdm_name = "wkup_clkdm", + .init = &omap2_init_clksel_parent, + .clksel_reg = OMAP_CM_REGADDR(PLL_MOD, CM_CLKSEL1), + .clksel_mask = OMAP24XX_48M_SOURCE_MASK, + .clksel = func_48m_clksel, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate +}; + +static struct clk func_12m_ck = { + .name = "func_12m_ck", + .ops = &clkops_null, + .parent = &func_48m_ck, + .fixed_div = 4, + .clkdm_name = "wkup_clkdm", + .recalc = &omap_fixed_divisor_recalc, +}; + +/* Secure timer, only available in secure mode */ +static struct clk wdt1_osc_ck = { + .name = "ck_wdt1_osc", + .ops = &clkops_null, /* RMK: missing? */ + .parent = &osc_ck, + .recalc = &followparent_recalc, +}; + +/* + * The common_clkout* clksel_rate structs are common to + * sys_clkout, sys_clkout_src, sys_clkout2, and sys_clkout2_src. + * sys_clkout2_* are 2420-only, so the + * clksel_rate flags fields are inaccurate for those clocks. This is + * harmless since access to those clocks are gated by the struct clk + * flags fields, which mark them as 2420-only. + */ +static const struct clksel_rate common_clkout_src_core_rates[] = { + { .div = 1, .val = 0, .flags = RATE_IN_24XX }, + { .div = 0 } +}; + +static const struct clksel_rate common_clkout_src_sys_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 0 } +}; + +static const struct clksel_rate common_clkout_src_96m_rates[] = { + { .div = 1, .val = 2, .flags = RATE_IN_24XX }, + { .div = 0 } +}; + +static const struct clksel_rate common_clkout_src_54m_rates[] = { + { .div = 1, .val = 3, .flags = RATE_IN_24XX }, + { .div = 0 } +}; + +static const struct clksel common_clkout_src_clksel[] = { + { .parent = &core_ck, .rates = common_clkout_src_core_rates }, + { .parent = &sys_ck, .rates = common_clkout_src_sys_rates }, + { .parent = &func_96m_ck, .rates = common_clkout_src_96m_rates }, + { .parent = &func_54m_ck, .rates = common_clkout_src_54m_rates }, + { .parent = NULL } +}; + +static struct clk sys_clkout_src = { + .name = "sys_clkout_src", + .ops = &clkops_omap2_dflt, + .parent = &func_54m_ck, + .clkdm_name = "wkup_clkdm", + .enable_reg = OMAP2420_PRCM_CLKOUT_CTRL, + .enable_bit = OMAP24XX_CLKOUT_EN_SHIFT, + .init = &omap2_init_clksel_parent, + .clksel_reg = OMAP2420_PRCM_CLKOUT_CTRL, + .clksel_mask = OMAP24XX_CLKOUT_SOURCE_MASK, + .clksel = common_clkout_src_clksel, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate +}; + +static const struct clksel_rate common_clkout_rates[] = { + { .div = 1, .val = 0, .flags = RATE_IN_24XX }, + { .div = 2, .val = 1, .flags = RATE_IN_24XX }, + { .div = 4, .val = 2, .flags = RATE_IN_24XX }, + { .div = 8, .val = 3, .flags = RATE_IN_24XX }, + { .div = 16, .val = 4, .flags = RATE_IN_24XX }, + { .div = 0 }, +}; + +static const struct clksel sys_clkout_clksel[] = { + { .parent = &sys_clkout_src, .rates = common_clkout_rates }, + { .parent = NULL } +}; + +static struct clk sys_clkout = { + .name = "sys_clkout", + .ops = &clkops_null, + .parent = &sys_clkout_src, + .clkdm_name = "wkup_clkdm", + .clksel_reg = OMAP2420_PRCM_CLKOUT_CTRL, + .clksel_mask = OMAP24XX_CLKOUT_DIV_MASK, + .clksel = sys_clkout_clksel, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate +}; + +/* In 2430, new in 2420 ES2 */ +static struct clk sys_clkout2_src = { + .name = "sys_clkout2_src", + .ops = &clkops_omap2_dflt, + .parent = &func_54m_ck, + .clkdm_name = "wkup_clkdm", + .enable_reg = OMAP2420_PRCM_CLKOUT_CTRL, + .enable_bit = OMAP2420_CLKOUT2_EN_SHIFT, + .init = &omap2_init_clksel_parent, + .clksel_reg = OMAP2420_PRCM_CLKOUT_CTRL, + .clksel_mask = OMAP2420_CLKOUT2_SOURCE_MASK, + .clksel = common_clkout_src_clksel, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate +}; + +static const struct clksel sys_clkout2_clksel[] = { + { .parent = &sys_clkout2_src, .rates = common_clkout_rates }, + { .parent = NULL } +}; + +/* In 2430, new in 2420 ES2 */ +static struct clk sys_clkout2 = { + .name = "sys_clkout2", + .ops = &clkops_null, + .parent = &sys_clkout2_src, + .clkdm_name = "wkup_clkdm", + .clksel_reg = OMAP2420_PRCM_CLKOUT_CTRL, + .clksel_mask = OMAP2420_CLKOUT2_DIV_MASK, + .clksel = sys_clkout2_clksel, + .recalc = &omap2_clksel_recalc, + .round_rate = &omap2_clksel_round_rate, + .set_rate = &omap2_clksel_set_rate +}; + +static struct clk emul_ck = { + .name = "emul_ck", + .ops = &clkops_omap2_dflt, + .parent = &func_54m_ck, + .clkdm_name = "wkup_clkdm", + .enable_reg = OMAP2420_PRCM_CLKEMUL_CTRL, + .enable_bit = OMAP24XX_EMULATION_EN_SHIFT, + .recalc = &followparent_recalc, + +}; + +/* + * MPU clock domain + * Clocks: + * MPU_FCLK, MPU_ICLK + * INT_M_FCLK, INT_M_I_CLK + * + * - Individual clocks are hardware managed. + * - Base divider comes from: CM_CLKSEL_MPU + * + */ +static const struct clksel_rate mpu_core_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 2, .val = 2, .flags = RATE_IN_24XX }, + { .div = 4, .val = 4, .flags = RATE_IN_242X }, + { .div = 6, .val = 6, .flags = RATE_IN_242X }, + { .div = 8, .val = 8, .flags = RATE_IN_242X }, + { .div = 0 }, +}; + +static const struct clksel mpu_clksel[] = { + { .parent = &core_ck, .rates = mpu_core_rates }, + { .parent = NULL } +}; + +static struct clk mpu_ck = { /* Control cpu */ + .name = "mpu_ck", + .ops = &clkops_null, + .parent = &core_ck, + .clkdm_name = "mpu_clkdm", + .init = &omap2_init_clksel_parent, + .clksel_reg = OMAP_CM_REGADDR(MPU_MOD, CM_CLKSEL), + .clksel_mask = OMAP24XX_CLKSEL_MPU_MASK, + .clksel = mpu_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* + * DSP (2420-UMA+IVA1) clock domain + * Clocks: + * 2420: UMA_FCLK, UMA_ICLK, IVA_MPU, IVA_COP + * + * Won't be too specific here. The core clock comes into this block + * it is divided then tee'ed. One branch goes directly to xyz enable + * controls. The other branch gets further divided by 2 then possibly + * routed into a synchronizer and out of clocks abc. + */ +static const struct clksel_rate dsp_fck_core_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 2, .val = 2, .flags = RATE_IN_24XX }, + { .div = 3, .val = 3, .flags = RATE_IN_24XX }, + { .div = 4, .val = 4, .flags = RATE_IN_24XX }, + { .div = 6, .val = 6, .flags = RATE_IN_242X }, + { .div = 8, .val = 8, .flags = RATE_IN_242X }, + { .div = 12, .val = 12, .flags = RATE_IN_242X }, + { .div = 0 }, +}; + +static const struct clksel dsp_fck_clksel[] = { + { .parent = &core_ck, .rates = dsp_fck_core_rates }, + { .parent = NULL } +}; + +static struct clk dsp_fck = { + .name = "dsp_fck", + .ops = &clkops_omap2_dflt_wait, + .parent = &core_ck, + .clkdm_name = "dsp_clkdm", + .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN), + .enable_bit = OMAP24XX_CM_FCLKEN_DSP_EN_DSP_SHIFT, + .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL), + .clksel_mask = OMAP24XX_CLKSEL_DSP_MASK, + .clksel = dsp_fck_clksel, + .recalc = &omap2_clksel_recalc, +}; + +static const struct clksel dsp_ick_clksel[] = { + { .parent = &dsp_fck, .rates = dsp_ick_rates }, + { .parent = NULL } +}; + +static struct clk dsp_ick = { + .name = "dsp_ick", /* apparently ipi and isp */ + .ops = &clkops_omap2_iclk_dflt_wait, + .parent = &dsp_fck, + .clkdm_name = "dsp_clkdm", + .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_ICLKEN), + .enable_bit = OMAP2420_EN_DSP_IPI_SHIFT, /* for ipi */ + .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL), + .clksel_mask = OMAP24XX_CLKSEL_DSP_IF_MASK, + .clksel = dsp_ick_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* + * The IVA1 is an ARM7 core on the 2420 that has nothing to do with + * the C54x, but which is contained in the DSP powerdomain. Does not + * exist on later OMAPs. + */ +static struct clk iva1_ifck = { + .name = "iva1_ifck", + .ops = &clkops_omap2_dflt_wait, + .parent = &core_ck, + .clkdm_name = "iva1_clkdm", + .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN), + .enable_bit = OMAP2420_EN_IVA_COP_SHIFT, + .clksel_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_CLKSEL), + .clksel_mask = OMAP2420_CLKSEL_IVA_MASK, + .clksel = dsp_fck_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* IVA1 mpu/int/i/f clocks are /2 of parent */ +static struct clk iva1_mpu_int_ifck = { + .name = "iva1_mpu_int_ifck", + .ops = &clkops_omap2_dflt_wait, + .parent = &iva1_ifck, + .clkdm_name = "iva1_clkdm", + .enable_reg = OMAP_CM_REGADDR(OMAP24XX_DSP_MOD, CM_FCLKEN), + .enable_bit = OMAP2420_EN_IVA_MPU_SHIFT, + .fixed_div = 2, + .recalc = &omap_fixed_divisor_recalc, +}; + +/* + * L3 clock domain + * L3 clocks are used for both interface and functional clocks to + * multiple entities. Some of these clocks are completely managed + * by hardware, and some others allow software control. Hardware + * managed ones general are based on directly CLK_REQ signals and + * various auto idle settings. The functional spec sets many of these + * as 'tie-high' for their enables. + * + * I-CLOCKS: + * L3-Interconnect, SMS, GPMC, SDRC, OCM_RAM, OCM_ROM, SDMA + * CAM, HS-USB. + * F-CLOCK + * SSI. + * + * GPMC memories and SDRC have timing and clock sensitive registers which + * may very well need notification when the clock changes. Currently for low + * operating points, these are taken care of in sleep.S. + */ +static const struct clksel_rate core_l3_core_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 2, .val = 2, .flags = RATE_IN_242X }, + { .div = 4, .val = 4, .flags = RATE_IN_24XX }, + { .div = 6, .val = 6, .flags = RATE_IN_24XX }, + { .div = 8, .val = 8, .flags = RATE_IN_242X }, + { .div = 12, .val = 12, .flags = RATE_IN_242X }, + { .div = 16, .val = 16, .flags = RATE_IN_242X }, + { .div = 0 } +}; + +static const struct clksel core_l3_clksel[] = { + { .parent = &core_ck, .rates = core_l3_core_rates }, + { .parent = NULL } +}; + +static struct clk core_l3_ck = { /* Used for ick and fck, interconnect */ + .name = "core_l3_ck", + .ops = &clkops_null, + .parent = &core_ck, + .clkdm_name = "core_l3_clkdm", + .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), + .clksel_mask = OMAP24XX_CLKSEL_L3_MASK, + .clksel = core_l3_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* usb_l4_ick */ +static const struct clksel_rate usb_l4_ick_core_l3_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 2, .val = 2, .flags = RATE_IN_24XX }, + { .div = 4, .val = 4, .flags = RATE_IN_24XX }, + { .div = 0 } +}; + +static const struct clksel usb_l4_ick_clksel[] = { + { .parent = &core_l3_ck, .rates = usb_l4_ick_core_l3_rates }, + { .parent = NULL }, +}; + +/* It is unclear from TRM whether usb_l4_ick is really in L3 or L4 clkdm */ +static struct clk usb_l4_ick = { /* FS-USB interface clock */ + .name = "usb_l4_ick", + .ops = &clkops_omap2_iclk_dflt_wait, + .parent = &core_l3_ck, + .clkdm_name = "core_l4_clkdm", + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2), + .enable_bit = OMAP24XX_EN_USB_SHIFT, + .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), + .clksel_mask = OMAP24XX_CLKSEL_USB_MASK, + .clksel = usb_l4_ick_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* + * L4 clock management domain + * + * This domain contains lots of interface clocks from the L4 interface, some + * functional clocks. Fixed APLL functional source clocks are managed in + * this domain. + */ +static const struct clksel_rate l4_core_l3_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 2, .val = 2, .flags = RATE_IN_24XX }, + { .div = 0 } +}; + +static const struct clksel l4_clksel[] = { + { .parent = &core_l3_ck, .rates = l4_core_l3_rates }, + { .parent = NULL } +}; + +static struct clk l4_ck = { /* used both as an ick and fck */ + .name = "l4_ck", + .ops = &clkops_null, + .parent = &core_l3_ck, + .clkdm_name = "core_l4_clkdm", + .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), + .clksel_mask = OMAP24XX_CLKSEL_L4_MASK, + .clksel = l4_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* + * SSI is in L3 management domain, its direct parent is core not l3, + * many core power domain entities are grouped into the L3 clock + * domain. + * SSI_SSR_FCLK, SSI_SST_FCLK, SSI_L4_ICLK + * + * ssr = core/1/2/3/4/5, sst = 1/2 ssr. + */ +static const struct clksel_rate ssi_ssr_sst_fck_core_rates[] = { + { .div = 1, .val = 1, .flags = RATE_IN_24XX }, + { .div = 2, .val = 2, .flags = RATE_IN_24XX }, + { .div = 3, .val = 3, .flags = RATE_IN_24XX }, + { .div = 4, .val = 4, .flags = RATE_IN_24XX }, + { .div = 6, .val = 6, .flags = RATE_IN_242X }, + { .div = 8, .val = 8, .flags = RATE_IN_242X }, + { .div = 0 } +}; + +static const struct clksel ssi_ssr_sst_fck_clksel[] = { + { .parent = &core_ck, .rates = ssi_ssr_sst_fck_core_rates }, + { .parent = NULL } +}; + +static struct clk ssi_ssr_sst_fck = { + .name = "ssi_fck", + .ops = &clkops_omap2_dflt_wait, + .parent = &core_ck, + .clkdm_name = "core_l3_clkdm", + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2), + .enable_bit = OMAP24XX_EN_SSI_SHIFT, + .clksel_reg = OMAP_CM_REGADDR(CORE_MOD, CM_CLKSEL1), + .clksel_mask = OMAP24XX_CLKSEL_SSI_MASK, + .clksel = ssi_ssr_sst_fck_clksel, + .recalc = &omap2_clksel_recalc, +}; + +/* + * Presumably this is the same as SSI_ICLK. + * TRM contradicts itself on what clockdomain SSI_ICLK is in + */ +static struct clk ssi_l4_ick = { + .name = "ssi_l4_ick", + .ops = &clkops_omap2_iclk_dflt_wait, + .parent = &l4_ck, + .clkdm_name = "core_l4_clkdm", + .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN2), + .enable_bit = OMAP24XX_EN_SSI_SHIFT, + .recalc = &followparent_recalc, +}; + + +/* + * GFX clock domain + * Clocks: + * GFX_FCLK, GFX_ICLK + * GFX_CG1(2d), GFX_CG2(3d) + * + * GFX_FCLK runs from L3, and is divided by (1,2,3,4) + * The 2d and 3d clocks run at a hardware determined + * divided value of fclk. + * + */ + +/* This clksel struct is shared between gfx_3d_fck and gfx_2d_fck */ +static const struct clksel gfx_fck_clksel[] = { + { .parent = &core_l3_ck, .rates = gfx_l3_rates }, + { .parent = NULL }, +}; + +static struct clk gfx_3d_fck = { + .name = "gfx_3d_fck", + .ops = &clkops_omap2_dflt_wait, + .par |