diff options
Diffstat (limited to 'arch/arm/mach-s3c24xx')
96 files changed, 19384 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig new file mode 100644 index 00000000000..ad5316ae524 --- /dev/null +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -0,0 +1,633 @@ +# arch/arm/mach-s3c24xx/Kconfig +# +# Copyright (c) 2012 Samsung Electronics Co., Ltd. +#		http://www.samsung.com/ +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +if ARCH_S3C24XX + +config PLAT_S3C24XX +	def_bool y +	select ARCH_REQUIRE_GPIOLIB +	select NO_IOPORT_MAP +	select S3C_DEV_NAND +	select IRQ_DOMAIN +	help +	  Base platform code for any Samsung S3C24XX device + + + +menu "SAMSUNG S3C24XX SoCs Support" + +comment "S3C24XX SoCs" + +config CPU_S3C2410 +	bool "SAMSUNG S3C2410" +	default y +	select CPU_ARM920T +	select S3C2410_COMMON_CLK +	select S3C2410_DMA if S3C24XX_DMA +	select ARM_S3C2410_CPUFREQ if ARM_S3C24XX_CPUFREQ +	select S3C2410_PM if PM +	select SAMSUNG_WDT_RESET +	help +	  Support for S3C2410 and S3C2410A family from the S3C24XX line +	  of Samsung Mobile CPUs. + +config CPU_S3C2412 +	bool "SAMSUNG S3C2412" +	select CPU_ARM926T +	select S3C2412_COMMON_CLK +	select S3C2412_DMA if S3C24XX_DMA +	select S3C2412_PM if PM +	help +	  Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line + +config CPU_S3C2416 +	bool "SAMSUNG S3C2416/S3C2450" +	select CPU_ARM926T +	select S3C2416_PM if PM +	select S3C2443_COMMON_CLK +	select S3C2443_DMA if S3C24XX_DMA +	help +	  Support for the S3C2416 SoC from the S3C24XX line + +config CPU_S3C2440 +	bool "SAMSUNG S3C2440" +	select CPU_ARM920T +	select S3C2410_COMMON_CLK +	select S3C2410_PM if PM +	select S3C2440_DMA if S3C24XX_DMA +	help +	  Support for S3C2440 Samsung Mobile CPU based systems. + +config CPU_S3C2442 +	bool "SAMSUNG S3C2442" +	select CPU_ARM920T +	select S3C2410_COMMON_CLK +	select S3C2410_DMA if S3C24XX_DMA +	select S3C2410_PM if PM +	help +	  Support for S3C2442 Samsung Mobile CPU based systems. + +config CPU_S3C244X +	def_bool y +	depends on CPU_S3C2440 || CPU_S3C2442 +	select SAMSUNG_WDT_RESET + +config CPU_S3C2443 +	bool "SAMSUNG S3C2443" +	select CPU_ARM920T +	select S3C2443_COMMON_CLK +	select S3C2443_DMA if S3C24XX_DMA +	help +	  Support for the S3C2443 SoC from the S3C24XX line + +# common code + +config S3C24XX_SMDK +	bool +	help +	  Common machine code for SMDK2410 and SMDK2440 + +config S3C24XX_SIMTEC_AUDIO +	bool +	depends on (ARCH_BAST || MACH_VR1000 || MACH_OSIRIS || MACH_ANUBIS) +	default y +	help +	  Add audio devices for common Simtec S3C24XX boards + +config S3C24XX_SIMTEC_PM +	bool +	help +	  Common power management code for systems that are +	  compatible with the Simtec style of power management + +config S3C24XX_SIMTEC_USB +	bool +	help +	  USB management code for common Simtec S3C24XX boards + +config S3C24XX_SETUP_TS +	bool +	help +	  Compile in platform device definition for Samsung TouchScreen. + +config S3C24XX_DMA +	bool "S3C2410 DMA support (deprecated)" +	select S3C_DMA +	help +	  S3C2410 DMA support. This is needed for drivers like sound which +	  use the S3C2410's DMA system to move data to and from the +	  peripheral blocks. + +config S3C2410_DMA_DEBUG +	bool "S3C2410 DMA support debug" +	depends on S3C2410_DMA +	help +	  Enable debugging output for the DMA code. This option sends info +	  to the kernel log, at priority KERN_DEBUG. + +config S3C2410_DMA +	bool +	depends on S3C24XX_DMA && (CPU_S3C2410 || CPU_S3C2442) +	help +	  DMA device selection for S3C2410 and compatible CPUs + +config S3C2410_PM +	bool +	help +	  Power Management code common to S3C2410 and better + +config S3C24XX_PLL +	bool "Support CPUfreq changing of PLL frequency (EXPERIMENTAL)" +	depends on ARM_S3C24XX_CPUFREQ +	help +	  Compile in support for changing the PLL frequency from the +	  S3C24XX series CPUfreq driver. The PLL takes time to settle +	  after a frequency change, so by default it is not enabled. + +	  This also means that the PLL tables for the selected CPU(s) will +	  be built which may increase the size of the kernel image. + +# cpu frequency items common between s3c2410 and s3c2440/s3c2442 + +config S3C2410_IOTIMING +	bool +	depends on ARM_S3C24XX_CPUFREQ +	help +	  Internal node to select io timing code that is common to the s3c2410 +	  and s3c2440/s3c2442 cpu frequency support. + +config S3C2410_CPUFREQ_UTILS +       bool +       depends on ARM_S3C24XX_CPUFREQ +       help +         Internal node to select timing code that is common to the s3c2410 +         and s3c2440/s3c244 cpu frequency support. + +# cpu frequency support common to s3c2412, s3c2413 and s3c2442 + +config S3C2412_IOTIMING +	bool +	depends on ARM_S3C24XX_CPUFREQ && (CPU_S3C2412 || CPU_S3C2443) +	help +	  Intel node to select io timing code that is common to the s3c2412 +	  and the s3c2443. + +# cpu-specific sections + +if CPU_S3C2410 + +config S3C2410_PLL +	bool +	depends on ARM_S3C2410_CPUFREQ && S3C24XX_PLL +	default y +	help +	  Select the PLL table for the S3C2410 + +config S3C24XX_SIMTEC_NOR +	bool +	help +	  Internal node to specify machine has simtec NOR mapping + +config MACH_BAST_IDE +	bool +	select HAVE_PATA_PLATFORM +	help +	  Internal node for machines with an BAST style IDE +	  interface + +comment "S3C2410 Boards" + +# +# The "S3C2410 Boards" list is ordered alphabetically by option text. +# (without ARCH_ or MACH_) +# + +config MACH_AML_M5900 +	bool "AML M5900 Series" +	select S3C24XX_SIMTEC_PM if PM +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the American Microsystems M5900 Series +	  <http://www.amltd.com> + +config ARCH_BAST +	bool "Simtec Electronics BAST (EB2410ITX)" +	select ISA +	select MACH_BAST_IDE +	select S3C2410_COMMON_DCLK +	select S3C2410_IOTIMING if ARM_S3C2410_CPUFREQ +	select S3C24XX_SIMTEC_NOR +	select S3C24XX_SIMTEC_PM if PM +	select S3C24XX_SIMTEC_USB +	select S3C_DEV_HWMON +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Simtec Electronics EB2410ITX +	  development board (also known as BAST) + +config BAST_PC104_IRQ +	bool "BAST PC104 IRQ support" +	depends on ARCH_BAST +	default y +	help +	  Say Y	here to enable the PC104 IRQ routing on the +	  Simtec BAST (EB2410ITX) + +config ARCH_H1940 +	bool "IPAQ H1940" +	select PM_H1940 if PM +	select S3C24XX_SETUP_TS +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the HP IPAQ H1940 + +config H1940BT +	tristate "Control the state of H1940 bluetooth chip" +	depends on ARCH_H1940 +	select RFKILL +	help +	  This is a simple driver that is able to control +	  the state of built in bluetooth chip on h1940. + +config PM_H1940 +	bool +	help +	  Internal node for H1940 and related PM + +config MACH_N30 +	bool "Acer N30 family" +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you want suppt for the Acer N30, Acer N35, +	  Navman PiN570, Yakumo AlphaX or Airis NC05 PDAs. + +config MACH_OTOM +	bool "NexVision OTOM Board" +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Nex Vision OTOM board + +config MACH_QT2410 +	bool "QT2410" +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Armzone QT2410 + +config ARCH_SMDK2410 +	bool "SMDK2410/A9M2410" +	select S3C24XX_SMDK +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the SMDK2410 or the derived module A9M2410 +	  <http://www.fsforth.de> + +config MACH_TCT_HAMMER +	bool "TCT Hammer Board" +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the TinCanTools Hammer Board +	  <http://www.tincantools.com> + +config MACH_VR1000 +	bool "Thorcom VR1000" +	select MACH_BAST_IDE +	select S3C2410_COMMON_DCLK +	select S3C24XX_SIMTEC_NOR +	select S3C24XX_SIMTEC_PM if PM +	select S3C24XX_SIMTEC_USB +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Thorcom VR1000 board. + +endif	# CPU_S3C2410 + +config S3C2412_PM_SLEEP +	bool +	help +	  Internal config node to apply sleep for S3C2412 power management. +	  Can be selected by another SoCs such as S3C2416 with similar +	  sleep procedure. + +if CPU_S3C2412 + +config CPU_S3C2412_ONLY +	bool +	depends on !CPU_S3C2410 && !CPU_S3C2416 && !CPU_S3C2440 && \ +		   !CPU_S3C2442 && !CPU_S3C2443 +	default y + +config S3C2412_DMA +	bool +	help +	  Internal config node for S3C2412 DMA support + +config S3C2412_PM +	bool +	select S3C2412_PM_SLEEP +	select SAMSUNG_WAKEMASK +	help +	  Internal config node to apply S3C2412 power management + +comment "S3C2412 Boards" + +# +# The "S3C2412 Boards" list is ordered alphabetically by option text. +# (without ARCH_ or MACH_) +# + +config MACH_JIVE +	bool "Logitech Jive" +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Logitech Jive. + +config MACH_JIVE_SHOW_BOOTLOADER +	bool "Allow access to bootloader partitions in MTD" +	depends on MACH_JIVE + +config MACH_S3C2413 +	bool +	help +	  Internal node for S3C2413 version of SMDK2413, so that +	  machine_is_s3c2413() will work when MACH_SMDK2413 is +	  selected + +config MACH_SMDK2412 +	bool "SMDK2412" +	select MACH_SMDK2413 +	help +	  Say Y here if you are using an SMDK2412 + +	  Note, this shares support with SMDK2413, so will automatically +	  select MACH_SMDK2413. + +config MACH_SMDK2413 +	bool "SMDK2413" +	select MACH_S3C2413 +	select S3C24XX_SMDK +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using an SMDK2413 + +config MACH_VSTMS +	bool "VMSTMS" +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using an VSTMS board + +endif	# CPU_S3C2412 + +if CPU_S3C2416 + +config S3C2416_PM +	bool +	select S3C2412_PM_SLEEP +	help +	  Internal config node to apply S3C2416 power management + +config S3C2416_SETUP_SDHCI +	bool +	select S3C2416_SETUP_SDHCI_GPIO +	help +	  Internal helper functions for S3C2416 based SDHCI systems + +config S3C2416_SETUP_SDHCI_GPIO +	bool +	help +	  Common setup code for SDHCI gpio. + +comment "S3C2416 Boards" + +config MACH_SMDK2416 +	bool "SMDK2416" +	select S3C2416_SETUP_SDHCI +	select S3C24XX_SMDK +	select S3C_DEV_FB +	select S3C_DEV_HSMMC +	select S3C_DEV_HSMMC1 +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using an SMDK2416 + +config MACH_S3C2416_DT +	bool "Samsung S3C2416 machine using devicetree" +	select CLKSRC_OF +	select USE_OF +	select PINCTRL +	select PINCTRL_S3C24XX +	help +	  Machine support for Samsung S3C2416 machines with device tree enabled. +	  Select this if a fdt blob is available for the S3C2416 SoC based board. +	  Note: This is under development and not all peripherals can be supported +	  with this machine file. + +endif	# CPU_S3C2416 + +if CPU_S3C2440 + +config S3C2440_DMA +	bool +	help +	  Support for S3C2440 specific DMA code5A + +config S3C2440_XTAL_12000000 +	bool +	help +	  Indicate that the build needs to support 12MHz system +	  crystal. + +config S3C2440_XTAL_16934400 +	bool +	help +	  Indicate that the build needs to support 16.9344MHz system +	  crystal. + +config S3C2440_PLL_12000000 +	bool +	depends on ARM_S3C2440_CPUFREQ && S3C2440_XTAL_12000000 +	default y if S3C24XX_PLL +	help +	  PLL tables for S3C2440 or S3C2442 CPUs with 12MHz crystals. + +config S3C2440_PLL_16934400 +	bool +	depends on ARM_S3C2440_CPUFREQ && S3C2440_XTAL_16934400 +	default y if S3C24XX_PLL +	help +	  PLL tables for S3C2440 or S3C2442 CPUs with 16.934MHz crystals. + +comment "S3C2440 Boards" + +# +# The "S3C2440 Boards" list is ordered alphabetically by option text. +# (without ARCH_ or MACH_) +# + +config MACH_ANUBIS +	bool "Simtec Electronics ANUBIS" +	select HAVE_PATA_PLATFORM +	select S3C2410_COMMON_DCLK +	select S3C2440_XTAL_12000000 +	select S3C24XX_SIMTEC_PM if PM +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Simtec Electronics ANUBIS +	  development system + +config MACH_AT2440EVB +	bool "Avantech AT2440EVB development board" +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the AT2440EVB development board + +config MACH_MINI2440 +	bool "MINI2440 development board" +	select EEPROM_AT24 if I2C +	select LEDS_CLASS +	select LEDS_TRIGGERS +	select LEDS_TRIGGER_BACKLIGHT +	select NEW_LEDS +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	select S3C_SETUP_CAMIF +	help +	  Say Y here to select support for the MINI2440. Is a 10cm x 10cm board +	  available via various sources. It can come with a 3.5" or 7" touch LCD. + +config MACH_NEXCODER_2440 +	bool "NexVision NEXCODER 2440 Light Board" +	select S3C2440_XTAL_12000000 +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board + +config MACH_OSIRIS +	bool "Simtec IM2440D20 (OSIRIS) module" +	select S3C2410_COMMON_DCLK +	select S3C2410_IOTIMING if ARM_S3C2440_CPUFREQ +	select S3C2440_XTAL_12000000 +	select S3C24XX_SIMTEC_PM if PM +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the Simtec IM2440D20 module, also +	  known as the Osiris. + +config MACH_OSIRIS_DVS +	tristate "Simtec IM2440D20 (OSIRIS) Dynamic Voltage Scaling driver" +	depends on MACH_OSIRIS +	depends on TPS65010 +	help +	  Say Y/M here if you want to have dynamic voltage scaling support +	  on the Simtec IM2440D20 (OSIRIS) module via the TPS65011. + +	  The DVS driver alters the voltage supplied to the ARM core +	  depending on the frequency it is running at. The driver itself +	  does not do any of the frequency alteration, which is left up +	  to the cpufreq driver. + +config MACH_RX3715 +	bool "HP iPAQ rx3715" +	select PM_H1940 if PM +	select S3C2440_XTAL_16934400 +	select S3C_DEV_NAND +	help +	  Say Y here if you are using the HP iPAQ rx3715. + +config ARCH_S3C2440 +	bool "SMDK2440" +	select S3C2440_XTAL_16934400 +	select S3C24XX_SMDK +	select S3C_DEV_NAND +	select S3C_DEV_USB_HOST +	help +	  Say Y here if you are using the SMDK2440. + +config SMDK2440_CPU2440 +	bool "SMDK2440 with S3C2440 CPU module" +	default y if ARCH_S3C2440 +	select S3C2440_XTAL_16934400 + +endif	# CPU_S3C2440 + +if CPU_S3C2442 + +comment "S3C2442 Boards" + +# +# The "S3C2442 Boards" list is ordered alphabetically by option text. +# (without ARCH_ or MACH_) +# + +config MACH_NEO1973_GTA02 +	bool "Openmoko GTA02 / Freerunner phone" +	select I2C +	select MFD_PCF50633 +	select PCF50633_GPIO +	select POWER_SUPPLY +	select S3C24XX_PWM +	select S3C_DEV_USB_HOST +	help +	   Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone + +config MACH_RX1950 +	bool "HP iPAQ rx1950" +	select I2C +	select PM_H1940 if PM +	select S3C2410_COMMON_DCLK +	select S3C2410_IOTIMING if ARM_S3C2440_CPUFREQ +	select S3C2440_XTAL_16934400 +	select S3C24XX_PWM +	select S3C_DEV_NAND +	help +	   Say Y here if you're using HP iPAQ rx1950 + +endif	# CPU_S3C2442 + +if CPU_S3C2443 || CPU_S3C2416 + +config S3C2443_DMA +	bool +	help +	  Internal config node for S3C2443 DMA support + +config S3C2443_SETUP_SPI +	bool +	help +	  Common setup code for SPI GPIO configurations + +endif	# CPU_S3C2443 || CPU_S3C2416 + +if CPU_S3C2443 + +comment "S3C2443 Boards" + +config MACH_SMDK2443 +	bool "SMDK2443" +	select S3C24XX_SMDK +	select S3C_DEV_HSMMC1 +	help +	  Say Y here if you are using an SMDK2443 + +endif	# CPU_S3C2443 + +endmenu	# SAMSUNG S3C24XX SoCs Support + +endif	# ARCH_S3C24XX diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile new file mode 100644 index 00000000000..2235d0d3b38 --- /dev/null +++ b/arch/arm/mach-s3c24xx/Makefile @@ -0,0 +1,112 @@ +# arch/arm/mach-s3c24xx/Makefile +# +# Copyright (c) 2012 Samsung Electronics Co., Ltd. +#		http://www.samsung.com/ +# +# Copyright 2007 Simtec Electronics +# +# Licensed under GPLv2 + +obj-y				:= +obj-m				:= +obj-n				:= +obj-				:= + +# core + +obj-y				+= common.o + +obj-$(CONFIG_CPU_S3C2410)	+= s3c2410.o +obj-$(CONFIG_S3C2410_DMA)	+= dma-s3c2410.o +obj-$(CONFIG_S3C2410_PLL)	+= pll-s3c2410.o +obj-$(CONFIG_S3C2410_PM)	+= pm-s3c2410.o sleep-s3c2410.o + +obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o +obj-$(CONFIG_S3C2412_DMA)	+= dma-s3c2412.o +obj-$(CONFIG_S3C2412_PM)	+= pm-s3c2412.o +obj-$(CONFIG_S3C2412_PM_SLEEP)	+= sleep-s3c2412.o + +obj-$(CONFIG_CPU_S3C2416)	+= s3c2416.o +obj-$(CONFIG_S3C2416_PM)	+= pm-s3c2416.o + +obj-$(CONFIG_CPU_S3C2440)	+= s3c2440.o +obj-$(CONFIG_CPU_S3C2442)	+= s3c2442.o +obj-$(CONFIG_CPU_S3C244X)	+= s3c244x.o +obj-$(CONFIG_S3C2440_DMA)	+= dma-s3c2440.o +obj-$(CONFIG_S3C2440_PLL_12000000) += pll-s3c2440-12000000.o +obj-$(CONFIG_S3C2440_PLL_16934400) += pll-s3c2440-16934400.o + +obj-$(CONFIG_CPU_S3C2443)	+= s3c2443.o + +# PM + +obj-$(CONFIG_PM)		+= pm.o irq-pm.o sleep.o + +# common code + +obj-$(CONFIG_S3C24XX_DMA)	+= dma.o + +obj-$(CONFIG_S3C2410_CPUFREQ_UTILS) += cpufreq-utils.o + +obj-$(CONFIG_S3C2410_IOTIMING)	+= iotiming-s3c2410.o +obj-$(CONFIG_S3C2412_IOTIMING)	+= iotiming-s3c2412.o + +obj-$(CONFIG_S3C2443_DMA)	+= dma-s3c2443.o + +# +# machine support +# following is ordered alphabetically by option text. +# + +obj-$(CONFIG_MACH_AML_M5900)		+= mach-amlm5900.o +obj-$(CONFIG_ARCH_BAST)			+= mach-bast.o +obj-$(CONFIG_BAST_PC104_IRQ)		+= bast-irq.o +obj-$(CONFIG_ARCH_H1940)		+= mach-h1940.o +obj-$(CONFIG_H1940BT)			+= h1940-bluetooth.o +obj-$(CONFIG_PM_H1940)			+= pm-h1940.o +obj-$(CONFIG_MACH_N30)			+= mach-n30.o +obj-$(CONFIG_MACH_OTOM)			+= mach-otom.o +obj-$(CONFIG_MACH_QT2410)		+= mach-qt2410.o +obj-$(CONFIG_ARCH_SMDK2410)		+= mach-smdk2410.o +obj-$(CONFIG_MACH_TCT_HAMMER)		+= mach-tct_hammer.o +obj-$(CONFIG_MACH_VR1000)		+= mach-vr1000.o + +obj-$(CONFIG_MACH_JIVE)			+= mach-jive.o +obj-$(CONFIG_MACH_SMDK2413)		+= mach-smdk2413.o +obj-$(CONFIG_MACH_VSTMS)		+= mach-vstms.o + +obj-$(CONFIG_MACH_SMDK2416)		+= mach-smdk2416.o +obj-$(CONFIG_MACH_S3C2416_DT)		+= mach-s3c2416-dt.o + +obj-$(CONFIG_MACH_ANUBIS)		+= mach-anubis.o +obj-$(CONFIG_MACH_AT2440EVB)		+= mach-at2440evb.o +obj-$(CONFIG_MACH_MINI2440)		+= mach-mini2440.o +obj-$(CONFIG_MACH_NEXCODER_2440)	+= mach-nexcoder.o +obj-$(CONFIG_MACH_OSIRIS)		+= mach-osiris.o +obj-$(CONFIG_MACH_RX3715)		+= mach-rx3715.o +obj-$(CONFIG_ARCH_S3C2440)		+= mach-smdk2440.o + +obj-$(CONFIG_MACH_NEO1973_GTA02)	+= mach-gta02.o +obj-$(CONFIG_MACH_RX1950)		+= mach-rx1950.o + +obj-$(CONFIG_MACH_SMDK2443)		+= mach-smdk2443.o + +# common bits of machine support + +obj-$(CONFIG_S3C24XX_SMDK)		+= common-smdk.o +obj-$(CONFIG_S3C24XX_SIMTEC_AUDIO)	+= simtec-audio.o +obj-$(CONFIG_S3C24XX_SIMTEC_NOR)	+= simtec-nor.o +obj-$(CONFIG_S3C24XX_SIMTEC_PM)		+= simtec-pm.o +obj-$(CONFIG_S3C24XX_SIMTEC_USB)	+= simtec-usb.o + +# machine additions + +obj-$(CONFIG_MACH_BAST_IDE)		+= bast-ide.o +obj-$(CONFIG_MACH_OSIRIS_DVS)		+= mach-osiris-dvs.o + +# device setup + +obj-$(CONFIG_S3C2416_SETUP_SDHCI_GPIO)	+= setup-sdhci-gpio.o +obj-$(CONFIG_S3C2443_SETUP_SPI)		+= setup-spi.o +obj-$(CONFIG_ARCH_S3C24XX)		+= setup-i2c.o +obj-$(CONFIG_S3C24XX_SETUP_TS)		+= setup-ts.o diff --git a/arch/arm/mach-s3c24xx/Makefile.boot b/arch/arm/mach-s3c24xx/Makefile.boot new file mode 100644 index 00000000000..4457605ba04 --- /dev/null +++ b/arch/arm/mach-s3c24xx/Makefile.boot @@ -0,0 +1,7 @@ +ifeq ($(CONFIG_PM_H1940),y) +	zreladdr-y	+= 0x30108000 +	params_phys-y	:= 0x30100100 +else +	zreladdr-y	+= 0x30008000 +	params_phys-y	:= 0x30000100 +endif diff --git a/arch/arm/mach-s3c24xx/anubis.h b/arch/arm/mach-s3c24xx/anubis.h new file mode 100644 index 00000000000..2691665f27d --- /dev/null +++ b/arch/arm/mach-s3c24xx/anubis.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2005 Simtec Electronics + *	http://www.simtec.co.uk/products/ + *	Ben Dooks <ben@simtec.co.uk> + * + * ANUBIS - CPLD control constants + * ANUBIS - IRQ Number definitions + * ANUBIS - Memory map definitions + * + * 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 __MACH_S3C24XX_ANUBIS_H +#define __MACH_S3C24XX_ANUBIS_H __FILE__ + +/* CTRL2 - NAND WP control, IDE Reset assert/check */ + +#define ANUBIS_CTRL1_NANDSEL		(0x3) + +/* IDREG - revision */ + +#define ANUBIS_IDREG_REVMASK		(0x7) + +/* irq */ + +#define ANUBIS_IRQ_IDE0			IRQ_EINT2 +#define ANUBIS_IRQ_IDE1			IRQ_EINT3 +#define ANUBIS_IRQ_ASIX			IRQ_EINT1 + +/* map */ + +/* start peripherals off after the S3C2410 */ + +#define ANUBIS_IOADDR(x)		(S3C2410_ADDR((x) + 0x01800000)) + +#define ANUBIS_PA_CPLD			(S3C2410_CS1 | (1<<26)) + +/* we put the CPLD registers next, to get them out of the way */ + +#define ANUBIS_VA_CTRL1			ANUBIS_IOADDR(0x00000000) +#define ANUBIS_PA_CTRL1			ANUBIS_PA_CPLD + +#define ANUBIS_VA_IDREG			ANUBIS_IOADDR(0x00300000) +#define ANUBIS_PA_IDREG			(ANUBIS_PA_CPLD + (3 << 23)) + +#define ANUBIS_IDEPRI			ANUBIS_IOADDR(0x01000000) +#define ANUBIS_IDEPRIAUX		ANUBIS_IOADDR(0x01100000) +#define ANUBIS_IDESEC			ANUBIS_IOADDR(0x01200000) +#define ANUBIS_IDESECAUX		ANUBIS_IOADDR(0x01300000) + +#endif /* __MACH_S3C24XX_ANUBIS_H */ diff --git a/arch/arm/mach-s3c24xx/bast-ide.c b/arch/arm/mach-s3c24xx/bast-ide.c new file mode 100644 index 00000000000..3f0288f2f54 --- /dev/null +++ b/arch/arm/mach-s3c24xx/bast-ide.c @@ -0,0 +1,86 @@ +/* linux/arch/arm/mach-s3c2410/bast-ide.c + * + * Copyright 2007 Simtec Electronics + *	http://www.simtec.co.uk/products/EB2410ITX/ + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * 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/types.h> +#include <linux/init.h> +#include <linux/interrupt.h> + +#include <linux/platform_device.h> +#include <linux/ata_platform.h> + +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/map.h> + +#include "bast.h" + +/* IDE ports */ + +static struct pata_platform_info bast_ide_platdata = { +	.ioport_shift	= 5, +}; + +static struct resource bast_ide0_resource[] = { +	[0] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDEPRI, 8 * 0x20), +	[1] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDEPRIAUX + (6 * 0x20), 0x20), +	[2] = DEFINE_RES_IRQ(BAST_IRQ_IDE0), +}; + +static struct platform_device bast_device_ide0 = { +	.name		= "pata_platform", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(bast_ide0_resource), +	.resource	= bast_ide0_resource, +	.dev		= { +		.platform_data = &bast_ide_platdata, +		.coherent_dma_mask = ~0, +	} + +}; + +static struct resource bast_ide1_resource[] = { +	[0] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDESEC, 8 * 0x20), +	[1] = DEFINE_RES_MEM(BAST_IDE_CS + BAST_PA_IDESECAUX + (6 * 0x20), 0x20), +	[2] = DEFINE_RES_IRQ(BAST_IRQ_IDE1), +}; + +static struct platform_device bast_device_ide1 = { +	.name		= "pata_platform", +	.id		= 1, +	.num_resources	= ARRAY_SIZE(bast_ide1_resource), +	.resource	= bast_ide1_resource, +	.dev		= { +		.platform_data = &bast_ide_platdata, +		.coherent_dma_mask = ~0, +	} +}; + +static struct platform_device *bast_ide_devices[] __initdata = { +	&bast_device_ide0, +	&bast_device_ide1, +}; + +static __init int bast_ide_init(void) +{ +	if (machine_is_bast() || machine_is_vr1000()) +		return platform_add_devices(bast_ide_devices, +					    ARRAY_SIZE(bast_ide_devices)); + +	return 0; +} + +fs_initcall(bast_ide_init); diff --git a/arch/arm/mach-s3c24xx/bast-irq.c b/arch/arm/mach-s3c24xx/bast-irq.c new file mode 100644 index 00000000000..cb1b791954d --- /dev/null +++ b/arch/arm/mach-s3c24xx/bast-irq.c @@ -0,0 +1,157 @@ +/* linux/arch/arm/mach-s3c2410/bast-irq.c + * + * Copyright 2003-2005 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/io.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/regs-irq.h> + +#include "bast.h" + +#define irqdbf(x...) +#define irqdbf2(x...) + +/* handle PC104 ISA interrupts from the system CPLD */ + +/* table of ISA irq nos to the relevant mask... zero means + * the irq is not implemented +*/ +static unsigned char bast_pc104_irqmasks[] = { +	0,   /* 0 */ +	0,   /* 1 */ +	0,   /* 2 */ +	1,   /* 3 */ +	0,   /* 4 */ +	2,   /* 5 */ +	0,   /* 6 */ +	4,   /* 7 */ +	0,   /* 8 */ +	0,   /* 9 */ +	8,   /* 10 */ +	0,   /* 11 */ +	0,   /* 12 */ +	0,   /* 13 */ +	0,   /* 14 */ +	0,   /* 15 */ +}; + +static unsigned char bast_pc104_irqs[] = { 3, 5, 7, 10 }; + +static void +bast_pc104_mask(struct irq_data *data) +{ +	unsigned long temp; + +	temp = __raw_readb(BAST_VA_PC104_IRQMASK); +	temp &= ~bast_pc104_irqmasks[data->irq]; +	__raw_writeb(temp, BAST_VA_PC104_IRQMASK); +} + +static void +bast_pc104_maskack(struct irq_data *data) +{ +	struct irq_desc *desc = irq_desc + BAST_IRQ_ISA; + +	bast_pc104_mask(data); +	desc->irq_data.chip->irq_ack(&desc->irq_data); +} + +static void +bast_pc104_unmask(struct irq_data *data) +{ +	unsigned long temp; + +	temp = __raw_readb(BAST_VA_PC104_IRQMASK); +	temp |= bast_pc104_irqmasks[data->irq]; +	__raw_writeb(temp, BAST_VA_PC104_IRQMASK); +} + +static struct irq_chip  bast_pc104_chip = { +	.irq_mask	= bast_pc104_mask, +	.irq_unmask	= bast_pc104_unmask, +	.irq_ack	= bast_pc104_maskack +}; + +static void +bast_irq_pc104_demux(unsigned int irq, +		     struct irq_desc *desc) +{ +	unsigned int stat; +	unsigned int irqno; +	int i; + +	stat = __raw_readb(BAST_VA_PC104_IRQREQ) & 0xf; + +	if (unlikely(stat == 0)) { +		/* ack if we get an irq with nothing (ie, startup) */ + +		desc = irq_desc + BAST_IRQ_ISA; +		desc->irq_data.chip->irq_ack(&desc->irq_data); +	} else { +		/* handle the IRQ */ + +		for (i = 0; stat != 0; i++, stat >>= 1) { +			if (stat & 1) { +				irqno = bast_pc104_irqs[i]; +				generic_handle_irq(irqno); +			} +		} +	} +} + +static __init int bast_irq_init(void) +{ +	unsigned int i; + +	if (machine_is_bast()) { +		printk(KERN_INFO "BAST PC104 IRQ routing, Copyright 2005 Simtec Electronics\n"); + +		/* zap all the IRQs */ + +		__raw_writeb(0x0, BAST_VA_PC104_IRQMASK); + +		irq_set_chained_handler(BAST_IRQ_ISA, bast_irq_pc104_demux); + +		/* register our IRQs */ + +		for (i = 0; i < 4; i++) { +			unsigned int irqno = bast_pc104_irqs[i]; + +			irq_set_chip_and_handler(irqno, &bast_pc104_chip, +						 handle_level_irq); +			set_irq_flags(irqno, IRQF_VALID); +		} +	} + +	return 0; +} + +arch_initcall(bast_irq_init); diff --git a/arch/arm/mach-s3c24xx/bast.h b/arch/arm/mach-s3c24xx/bast.h new file mode 100644 index 00000000000..5c7534bae92 --- /dev/null +++ b/arch/arm/mach-s3c24xx/bast.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2003-2004 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * BAST - CPLD control constants + * BAST - IRQ Number definitions + * BAST - Memory map definitions + * + * 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 __MACH_S3C24XX_BAST_H +#define __MACH_S3C24XX_BAST_H __FILE__ + +/* CTRL1 - Audio LR routing */ + +#define BAST_CPLD_CTRL1_LRCOFF		(0x00) +#define BAST_CPLD_CTRL1_LRCADC		(0x01) +#define BAST_CPLD_CTRL1_LRCDAC		(0x02) +#define BAST_CPLD_CTRL1_LRCARM		(0x03) +#define BAST_CPLD_CTRL1_LRMASK		(0x03) + +/* CTRL2 - NAND WP control, IDE Reset assert/check */ + +#define BAST_CPLD_CTRL2_WNAND		(0x04) +#define BAST_CPLD_CTLR2_IDERST		(0x08) + +/* CTRL3 - rom write control, CPLD identity */ + +#define BAST_CPLD_CTRL3_IDMASK		(0x0e) +#define BAST_CPLD_CTRL3_ROMWEN		(0x01) + +/* CTRL4 - 8bit LCD interface control/status */ + +#define BAST_CPLD_CTRL4_LLAT		(0x01) +#define BAST_CPLD_CTRL4_LCDRW		(0x02) +#define BAST_CPLD_CTRL4_LCDCMD		(0x04) +#define BAST_CPLD_CTRL4_LCDE2		(0x01) + +/* CTRL5 - DMA routing */ + +#define BAST_CPLD_DMA0_PRIIDE		(0) +#define BAST_CPLD_DMA0_SECIDE		(1) +#define BAST_CPLD_DMA0_ISA15		(2) +#define BAST_CPLD_DMA0_ISA36		(3) + +#define BAST_CPLD_DMA1_PRIIDE		(0 << 2) +#define BAST_CPLD_DMA1_SECIDE		(1 << 2) +#define BAST_CPLD_DMA1_ISA15		(2 << 2) +#define BAST_CPLD_DMA1_ISA36		(3 << 2) + +/* irq numbers to onboard peripherals */ + +#define BAST_IRQ_USBOC			IRQ_EINT18 +#define BAST_IRQ_IDE0			IRQ_EINT16 +#define BAST_IRQ_IDE1			IRQ_EINT17 +#define BAST_IRQ_PCSERIAL1		IRQ_EINT15 +#define BAST_IRQ_PCSERIAL2		IRQ_EINT14 +#define BAST_IRQ_PCPARALLEL		IRQ_EINT13 +#define BAST_IRQ_ASIX			IRQ_EINT11 +#define BAST_IRQ_DM9000			IRQ_EINT10 +#define BAST_IRQ_ISA			IRQ_EINT9 +#define BAST_IRQ_SMALERT		IRQ_EINT8 + +/* map */ + +/* + * ok, we've used up to 0x13000000, now we need to find space for the + * peripherals that live in the nGCS[x] areas, which are quite numerous + * in their space. We also have the board's CPLD to find register space + * for. + */ + +#define BAST_IOADDR(x)			(S3C2410_ADDR((x) + 0x01300000)) + +/* we put the CPLD registers next, to get them out of the way */ + +#define BAST_VA_CTRL1			BAST_IOADDR(0x00000000) +#define BAST_PA_CTRL1			(S3C2410_CS5 | 0x7800000) + +#define BAST_VA_CTRL2			BAST_IOADDR(0x00100000) +#define BAST_PA_CTRL2			(S3C2410_CS1 | 0x6000000) + +#define BAST_VA_CTRL3			BAST_IOADDR(0x00200000) +#define BAST_PA_CTRL3			(S3C2410_CS1 | 0x6800000) + +#define BAST_VA_CTRL4			BAST_IOADDR(0x00300000) +#define BAST_PA_CTRL4			(S3C2410_CS1 | 0x7000000) + +/* next, we have the PC104 ISA interrupt registers */ + +#define BAST_PA_PC104_IRQREQ		(S3C2410_CS5 | 0x6000000) +#define BAST_VA_PC104_IRQREQ		BAST_IOADDR(0x00400000) + +#define BAST_PA_PC104_IRQRAW		(S3C2410_CS5 | 0x6800000) +#define BAST_VA_PC104_IRQRAW		BAST_IOADDR(0x00500000) + +#define BAST_PA_PC104_IRQMASK		(S3C2410_CS5 | 0x7000000) +#define BAST_VA_PC104_IRQMASK		BAST_IOADDR(0x00600000) + +#define BAST_PA_LCD_RCMD1		(0x8800000) +#define BAST_VA_LCD_RCMD1		BAST_IOADDR(0x00700000) + +#define BAST_PA_LCD_WCMD1		(0x8000000) +#define BAST_VA_LCD_WCMD1		BAST_IOADDR(0x00800000) + +#define BAST_PA_LCD_RDATA1		(0x9800000) +#define BAST_VA_LCD_RDATA1		BAST_IOADDR(0x00900000) + +#define BAST_PA_LCD_WDATA1		(0x9000000) +#define BAST_VA_LCD_WDATA1		BAST_IOADDR(0x00A00000) + +#define BAST_PA_LCD_RCMD2		(0xA800000) +#define BAST_VA_LCD_RCMD2		BAST_IOADDR(0x00B00000) + +#define BAST_PA_LCD_WCMD2		(0xA000000) +#define BAST_VA_LCD_WCMD2		BAST_IOADDR(0x00C00000) + +#define BAST_PA_LCD_RDATA2		(0xB800000) +#define BAST_VA_LCD_RDATA2		BAST_IOADDR(0x00D00000) + +#define BAST_PA_LCD_WDATA2		(0xB000000) +#define BAST_VA_LCD_WDATA2		BAST_IOADDR(0x00E00000) + + +/* + * 0xE0000000 contains the IO space that is split by speed and + * whether the access is for 8 or 16bit IO... this ensures that + * the correct access is made + * + * 0x10000000 of space, partitioned as so: + * + * 0x00000000 to 0x04000000  8bit,  slow + * 0x04000000 to 0x08000000  16bit, slow + * 0x08000000 to 0x0C000000  16bit, net + * 0x0C000000 to 0x10000000  16bit, fast + * + * each of these spaces has the following in: + * + * 0x00000000 to 0x01000000 16MB ISA IO space + * 0x01000000 to 0x02000000 16MB ISA memory space + * 0x02000000 to 0x02100000 1MB  IDE primary channel + * 0x02100000 to 0x02200000 1MB  IDE primary channel aux + * 0x02200000 to 0x02400000 1MB  IDE secondary channel + * 0x02300000 to 0x02400000 1MB  IDE secondary channel aux + * 0x02400000 to 0x02500000 1MB  ASIX ethernet controller + * 0x02500000 to 0x02600000 1MB  Davicom DM9000 ethernet controller + * 0x02600000 to 0x02700000 1MB  PC SuperIO controller + * + * the phyiscal layout of the zones are: + *  nGCS2 - 8bit, slow + *  nGCS3 - 16bit, slow + *  nGCS4 - 16bit, net + *  nGCS5 - 16bit, fast + */ + +#define BAST_VA_MULTISPACE		(0xE0000000) + +#define BAST_VA_ISAIO			(BAST_VA_MULTISPACE + 0x00000000) +#define BAST_VA_ISAMEM			(BAST_VA_MULTISPACE + 0x01000000) +#define BAST_VA_IDEPRI			(BAST_VA_MULTISPACE + 0x02000000) +#define BAST_VA_IDEPRIAUX		(BAST_VA_MULTISPACE + 0x02100000) +#define BAST_VA_IDESEC			(BAST_VA_MULTISPACE + 0x02200000) +#define BAST_VA_IDESECAUX		(BAST_VA_MULTISPACE + 0x02300000) +#define BAST_VA_ASIXNET			(BAST_VA_MULTISPACE + 0x02400000) +#define BAST_VA_DM9000			(BAST_VA_MULTISPACE + 0x02500000) +#define BAST_VA_SUPERIO			(BAST_VA_MULTISPACE + 0x02600000) + +#define BAST_VAM_CS2			(0x00000000) +#define BAST_VAM_CS3			(0x04000000) +#define BAST_VAM_CS4			(0x08000000) +#define BAST_VAM_CS5			(0x0C000000) + +/* physical offset addresses for the peripherals */ + +#define BAST_PA_ISAIO			(0x00000000) +#define BAST_PA_ASIXNET			(0x01000000) +#define BAST_PA_SUPERIO			(0x01800000) +#define BAST_PA_IDEPRI			(0x02000000) +#define BAST_PA_IDEPRIAUX		(0x02800000) +#define BAST_PA_IDESEC			(0x03000000) +#define BAST_PA_IDESECAUX		(0x03800000) +#define BAST_PA_ISAMEM			(0x04000000) +#define BAST_PA_DM9000			(0x05000000) + +/* some configurations for the peripherals */ + +#define BAST_PCSIO			(BAST_VA_SUPERIO + BAST_VAM_CS2) + +#define BAST_ASIXNET_CS			BAST_VAM_CS5 +#define BAST_DM9000_CS			BAST_VAM_CS4 + +#define BAST_IDE_CS	S3C2410_CS5 + +#endif /* __MACH_S3C24XX_BAST_H */ diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c new file mode 100644 index 00000000000..e9fbcc91c5c --- /dev/null +++ b/arch/arm/mach-s3c24xx/common-smdk.c @@ -0,0 +1,210 @@ +/* linux/arch/arm/plat-s3c24xx/common-smdk.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/mach-types.h> +#include <mach/hardware.h> +#include <asm/irq.h> + +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> +#include <linux/platform_data/leds-s3c24xx.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include <plat/gpio-cfg.h> +#include <plat/devs.h> +#include <plat/pm.h> + +#include "common-smdk.h" + +/* LED devices */ + +static struct s3c24xx_led_platdata smdk_pdata_led4 = { +	.gpio		= S3C2410_GPF(4), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.name		= "led4", +	.def_trigger	= "timer", +}; + +static struct s3c24xx_led_platdata smdk_pdata_led5 = { +	.gpio		= S3C2410_GPF(5), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.name		= "led5", +	.def_trigger	= "nand-disk", +}; + +static struct s3c24xx_led_platdata smdk_pdata_led6 = { +	.gpio		= S3C2410_GPF(6), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.name		= "led6", +}; + +static struct s3c24xx_led_platdata smdk_pdata_led7 = { +	.gpio		= S3C2410_GPF(7), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.name		= "led7", +}; + +static struct platform_device smdk_led4 = { +	.name		= "s3c24xx_led", +	.id		= 0, +	.dev		= { +		.platform_data = &smdk_pdata_led4, +	}, +}; + +static struct platform_device smdk_led5 = { +	.name		= "s3c24xx_led", +	.id		= 1, +	.dev		= { +		.platform_data = &smdk_pdata_led5, +	}, +}; + +static struct platform_device smdk_led6 = { +	.name		= "s3c24xx_led", +	.id		= 2, +	.dev		= { +		.platform_data = &smdk_pdata_led6, +	}, +}; + +static struct platform_device smdk_led7 = { +	.name		= "s3c24xx_led", +	.id		= 3, +	.dev		= { +		.platform_data = &smdk_pdata_led7, +	}, +}; + +/* NAND parititon from 2.4.18-swl5 */ + +static struct mtd_partition smdk_default_nand_part[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_16K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "S3C2410 flash partition 1", +		.offset = 0, +		.size	= SZ_2M, +	}, +	[2] = { +		.name	= "S3C2410 flash partition 2", +		.offset = SZ_4M, +		.size	= SZ_4M, +	}, +	[3] = { +		.name	= "S3C2410 flash partition 3", +		.offset	= SZ_8M, +		.size	= SZ_2M, +	}, +	[4] = { +		.name	= "S3C2410 flash partition 4", +		.offset = SZ_1M * 10, +		.size	= SZ_4M, +	}, +	[5] = { +		.name	= "S3C2410 flash partition 5", +		.offset	= SZ_1M * 14, +		.size	= SZ_1M * 10, +	}, +	[6] = { +		.name	= "S3C2410 flash partition 6", +		.offset	= SZ_1M * 24, +		.size	= SZ_1M * 24, +	}, +	[7] = { +		.name	= "S3C2410 flash partition 7", +		.offset = SZ_1M * 48, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +static struct s3c2410_nand_set smdk_nand_sets[] = { +	[0] = { +		.name		= "NAND", +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(smdk_default_nand_part), +		.partitions	= smdk_default_nand_part, +	}, +}; + +/* choose a set of timings which should suit most 512Mbit + * chips and beyond. +*/ + +static struct s3c2410_platform_nand smdk_nand_info = { +	.tacls		= 20, +	.twrph0		= 60, +	.twrph1		= 20, +	.nr_sets	= ARRAY_SIZE(smdk_nand_sets), +	.sets		= smdk_nand_sets, +}; + +/* devices we initialise */ + +static struct platform_device __initdata *smdk_devs[] = { +	&s3c_device_nand, +	&smdk_led4, +	&smdk_led5, +	&smdk_led6, +	&smdk_led7, +}; + +static const struct gpio smdk_led_gpios[] = { +	{ S3C2410_GPF(4), GPIOF_OUT_INIT_HIGH, NULL }, +	{ S3C2410_GPF(5), GPIOF_OUT_INIT_HIGH, NULL }, +	{ S3C2410_GPF(6), GPIOF_OUT_INIT_HIGH, NULL }, +	{ S3C2410_GPF(7), GPIOF_OUT_INIT_HIGH, NULL }, +}; + +void __init smdk_machine_init(void) +{ +	/* Configure the LEDs (even if we have no LED support)*/ + +	int ret = gpio_request_array(smdk_led_gpios, +				     ARRAY_SIZE(smdk_led_gpios)); +	if (!WARN_ON(ret < 0)) +		gpio_free_array(smdk_led_gpios, ARRAY_SIZE(smdk_led_gpios)); + +	if (machine_is_smdk2443()) +		smdk_nand_info.twrph0 = 50; + +	s3c_nand_set_platdata(&smdk_nand_info); + +	platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)); + +	s3c_pm_init(); +} diff --git a/arch/arm/mach-s3c24xx/common-smdk.h b/arch/arm/mach-s3c24xx/common-smdk.h new file mode 100644 index 00000000000..98f733e1cb4 --- /dev/null +++ b/arch/arm/mach-s3c24xx/common-smdk.h @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + * + * 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. +*/ + +extern void smdk_machine_init(void); diff --git a/arch/arm/mach-s3c24xx/common.c b/arch/arm/mach-s3c24xx/common.c new file mode 100644 index 00000000000..c0763b83774 --- /dev/null +++ b/arch/arm/mach-s3c24xx/common.c @@ -0,0 +1,571 @@ +/* linux/arch/arm/plat-s3c24xx/cpu.c + * + * Copyright (c) 2004-2005 Simtec Electronics + *	http://www.simtec.co.uk/products/SWLINUX/ + *	Ben Dooks <ben@simtec.co.uk> + * + * Common code for S3C24XX machines + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <clocksource/samsung_pwm.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/platform_data/dma-s3c24xx.h> + +#include <mach/hardware.h> +#include <mach/regs-clock.h> +#include <asm/irq.h> +#include <asm/cacheflush.h> +#include <asm/system_info.h> +#include <asm/system_misc.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/regs-gpio.h> +#include <mach/dma.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/clock.h> +#include <plat/cpu-freq.h> +#include <plat/pll.h> +#include <plat/pwm-core.h> +#include <plat/watchdog-reset.h> + +#include "common.h" + +/* table of supported CPUs */ + +static const char name_s3c2410[]  = "S3C2410"; +static const char name_s3c2412[]  = "S3C2412"; +static const char name_s3c2416[]  = "S3C2416/S3C2450"; +static const char name_s3c2440[]  = "S3C2440"; +static const char name_s3c2442[]  = "S3C2442"; +static const char name_s3c2442b[]  = "S3C2442B"; +static const char name_s3c2443[]  = "S3C2443"; +static const char name_s3c2410a[] = "S3C2410A"; +static const char name_s3c2440a[] = "S3C2440A"; + +static struct cpu_table cpu_ids[] __initdata = { +	{ +		.idcode		= 0x32410000, +		.idmask		= 0xffffffff, +		.map_io		= s3c2410_map_io, +		.init_uarts	= s3c2410_init_uarts, +		.init		= s3c2410_init, +		.name		= name_s3c2410 +	}, +	{ +		.idcode		= 0x32410002, +		.idmask		= 0xffffffff, +		.map_io		= s3c2410_map_io, +		.init_uarts	= s3c2410_init_uarts, +		.init		= s3c2410a_init, +		.name		= name_s3c2410a +	}, +	{ +		.idcode		= 0x32440000, +		.idmask		= 0xffffffff, +		.map_io		= s3c2440_map_io, +		.init_uarts	= s3c244x_init_uarts, +		.init		= s3c2440_init, +		.name		= name_s3c2440 +	}, +	{ +		.idcode		= 0x32440001, +		.idmask		= 0xffffffff, +		.map_io		= s3c2440_map_io, +		.init_uarts	= s3c244x_init_uarts, +		.init		= s3c2440_init, +		.name		= name_s3c2440a +	}, +	{ +		.idcode		= 0x32440aaa, +		.idmask		= 0xffffffff, +		.map_io		= s3c2442_map_io, +		.init_uarts	= s3c244x_init_uarts, +		.init		= s3c2442_init, +		.name		= name_s3c2442 +	}, +	{ +		.idcode		= 0x32440aab, +		.idmask		= 0xffffffff, +		.map_io		= s3c2442_map_io, +		.init_uarts	= s3c244x_init_uarts, +		.init		= s3c2442_init, +		.name		= name_s3c2442b +	}, +	{ +		.idcode		= 0x32412001, +		.idmask		= 0xffffffff, +		.map_io		= s3c2412_map_io, +		.init_uarts	= s3c2412_init_uarts, +		.init		= s3c2412_init, +		.name		= name_s3c2412, +	}, +	{			/* a newer version of the s3c2412 */ +		.idcode		= 0x32412003, +		.idmask		= 0xffffffff, +		.map_io		= s3c2412_map_io, +		.init_uarts	= s3c2412_init_uarts, +		.init		= s3c2412_init, +		.name		= name_s3c2412, +	}, +	{			/* a strange version of the s3c2416 */ +		.idcode		= 0x32450003, +		.idmask		= 0xffffffff, +		.map_io		= s3c2416_map_io, +		.init_uarts	= s3c2416_init_uarts, +		.init		= s3c2416_init, +		.name		= name_s3c2416, +	}, +	{ +		.idcode		= 0x32443001, +		.idmask		= 0xffffffff, +		.map_io		= s3c2443_map_io, +		.init_uarts	= s3c2443_init_uarts, +		.init		= s3c2443_init, +		.name		= name_s3c2443, +	}, +}; + +/* minimal IO mapping */ + +static struct map_desc s3c_iodesc[] __initdata = { +	IODESC_ENT(GPIO), +	IODESC_ENT(IRQ), +	IODESC_ENT(MEMCTRL), +	IODESC_ENT(UART) +}; + +/* read cpu identificaiton code */ + +static unsigned long s3c24xx_read_idcode_v5(void) +{ +#if defined(CONFIG_CPU_S3C2416) +	/* s3c2416 is v5, with S3C24XX_GSTATUS1 instead of S3C2412_GSTATUS1 */ + +	u32 gs = __raw_readl(S3C24XX_GSTATUS1); + +	/* test for s3c2416 or similar device */ +	if ((gs >> 16) == 0x3245) +		return gs; +#endif + +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) +	return __raw_readl(S3C2412_GSTATUS1); +#else +	return 1UL;	/* don't look like an 2400 */ +#endif +} + +static unsigned long s3c24xx_read_idcode_v4(void) +{ +	return __raw_readl(S3C2410_GSTATUS1); +} + +static void s3c24xx_default_idle(void) +{ +	unsigned long tmp = 0; +	int i; + +	/* idle the system by using the idle mode which will wait for an +	 * interrupt to happen before restarting the system. +	 */ + +	/* Warning: going into idle state upsets jtag scanning */ + +	__raw_writel(__raw_readl(S3C2410_CLKCON) | S3C2410_CLKCON_IDLE, +		     S3C2410_CLKCON); + +	/* the samsung port seems to do a loop and then unset idle.. */ +	for (i = 0; i < 50; i++) +		tmp += __raw_readl(S3C2410_CLKCON); /* ensure loop not optimised out */ + +	/* this bit is not cleared on re-start... */ + +	__raw_writel(__raw_readl(S3C2410_CLKCON) & ~S3C2410_CLKCON_IDLE, +		     S3C2410_CLKCON); +} + +static struct samsung_pwm_variant s3c24xx_pwm_variant = { +	.bits		= 16, +	.div_base	= 1, +	.has_tint_cstat	= false, +	.tclk_mask	= (1 << 4), +}; + +void __init s3c24xx_init_io(struct map_desc *mach_desc, int size) +{ +	arm_pm_idle = s3c24xx_default_idle; + +	/* initialise the io descriptors we need for initialisation */ +	iotable_init(mach_desc, size); +	iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); + +	if (cpu_architecture() >= CPU_ARCH_ARMv5) { +		samsung_cpu_id = s3c24xx_read_idcode_v5(); +	} else { +		samsung_cpu_id = s3c24xx_read_idcode_v4(); +	} + +	s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); + +	samsung_pwm_set_platdata(&s3c24xx_pwm_variant); +} + +void __init samsung_set_timer_source(unsigned int event, unsigned int source) +{ +	s3c24xx_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1; +	s3c24xx_pwm_variant.output_mask &= ~(BIT(event) | BIT(source)); +} + +void __init samsung_timer_init(void) +{ +	unsigned int timer_irqs[SAMSUNG_PWM_NUM] = { +		IRQ_TIMER0, IRQ_TIMER1, IRQ_TIMER2, IRQ_TIMER3, IRQ_TIMER4, +	}; + +	samsung_pwm_clocksource_init(S3C_VA_TIMER, +					timer_irqs, &s3c24xx_pwm_variant); +} + +/* Serial port registrations */ + +#define S3C2410_PA_UART0      (S3C24XX_PA_UART) +#define S3C2410_PA_UART1      (S3C24XX_PA_UART + 0x4000 ) +#define S3C2410_PA_UART2      (S3C24XX_PA_UART + 0x8000 ) +#define S3C2443_PA_UART3      (S3C24XX_PA_UART + 0xC000 ) + +static struct resource s3c2410_uart0_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_PA_UART0, SZ_16K), +	[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX0, \ +			IRQ_S3CUART_ERR0 - IRQ_S3CUART_RX0 + 1, \ +			NULL, IORESOURCE_IRQ) +}; + +static struct resource s3c2410_uart1_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_PA_UART1, SZ_16K), +	[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX1, \ +			IRQ_S3CUART_ERR1 - IRQ_S3CUART_RX1 + 1, \ +			NULL, IORESOURCE_IRQ) +}; + +static struct resource s3c2410_uart2_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_PA_UART2, SZ_16K), +	[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX2, \ +			IRQ_S3CUART_ERR2 - IRQ_S3CUART_RX2 + 1, \ +			NULL, IORESOURCE_IRQ) +}; + +static struct resource s3c2410_uart3_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2443_PA_UART3, SZ_16K), +	[1] = DEFINE_RES_NAMED(IRQ_S3CUART_RX3, \ +			IRQ_S3CUART_ERR3 - IRQ_S3CUART_RX3 + 1, \ +			NULL, IORESOURCE_IRQ) +}; + +struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = { +	[0] = { +		.resources	= s3c2410_uart0_resource, +		.nr_resources	= ARRAY_SIZE(s3c2410_uart0_resource), +	}, +	[1] = { +		.resources	= s3c2410_uart1_resource, +		.nr_resources	= ARRAY_SIZE(s3c2410_uart1_resource), +	}, +	[2] = { +		.resources	= s3c2410_uart2_resource, +		.nr_resources	= ARRAY_SIZE(s3c2410_uart2_resource), +	}, +	[3] = { +		.resources	= s3c2410_uart3_resource, +		.nr_resources	= ARRAY_SIZE(s3c2410_uart3_resource), +	}, +}; + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \ +	defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) +static struct resource s3c2410_dma_resource[] = { +	[0] = DEFINE_RES_MEM(S3C24XX_PA_DMA, S3C24XX_SZ_DMA), +	[1] = DEFINE_RES_IRQ(IRQ_DMA0), +	[2] = DEFINE_RES_IRQ(IRQ_DMA1), +	[3] = DEFINE_RES_IRQ(IRQ_DMA2), +	[4] = DEFINE_RES_IRQ(IRQ_DMA3), +}; +#endif + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2442) +static struct s3c24xx_dma_channel s3c2410_dma_channels[DMACH_MAX] = { +	[DMACH_XD0] = { S3C24XX_DMA_AHB, true, S3C24XX_DMA_CHANREQ(0, 0), }, +	[DMACH_XD1] = { S3C24XX_DMA_AHB, true, S3C24XX_DMA_CHANREQ(0, 1), }, +	[DMACH_SDI] = { S3C24XX_DMA_APB, false, S3C24XX_DMA_CHANREQ(2, 0) | +						S3C24XX_DMA_CHANREQ(2, 2) | +						S3C24XX_DMA_CHANREQ(1, 3), +	}, +	[DMACH_SPI0] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(3, 1), }, +	[DMACH_SPI1] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(2, 3), }, +	[DMACH_UART0] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(1, 0), }, +	[DMACH_UART1] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(1, 1), }, +	[DMACH_UART2] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(0, 3), }, +	[DMACH_TIMER] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(3, 0) | +						 S3C24XX_DMA_CHANREQ(3, 2) | +						 S3C24XX_DMA_CHANREQ(3, 3), +	}, +	[DMACH_I2S_IN] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(2, 1) | +						  S3C24XX_DMA_CHANREQ(1, 2), +	}, +	[DMACH_I2S_OUT] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(0, 2), }, +	[DMACH_USB_EP1] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 0), }, +	[DMACH_USB_EP2] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 1), }, +	[DMACH_USB_EP3] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 2), }, +	[DMACH_USB_EP4] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 3), }, +}; + +static struct s3c24xx_dma_platdata s3c2410_dma_platdata = { +	.num_phy_channels = 4, +	.channels = s3c2410_dma_channels, +	.num_channels = DMACH_MAX, +}; + +struct platform_device s3c2410_device_dma = { +	.name		= "s3c2410-dma", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(s3c2410_dma_resource), +	.resource	= s3c2410_dma_resource, +	.dev	= { +		.platform_data	= &s3c2410_dma_platdata, +	}, +}; +#endif + +#ifdef CONFIG_CPU_S3C2412 +static struct s3c24xx_dma_channel s3c2412_dma_channels[DMACH_MAX] = { +	[DMACH_XD0] = { S3C24XX_DMA_AHB, true, 17 }, +	[DMACH_XD1] = { S3C24XX_DMA_AHB, true, 18 }, +	[DMACH_SDI] = { S3C24XX_DMA_APB, false, 10 }, +	[DMACH_SPI0_RX] = { S3C24XX_DMA_APB, true, 1 }, +	[DMACH_SPI0_TX] = { S3C24XX_DMA_APB, true, 0 }, +	[DMACH_SPI1_RX] = { S3C24XX_DMA_APB, true, 3 }, +	[DMACH_SPI1_TX] = { S3C24XX_DMA_APB, true, 2 }, +	[DMACH_UART0] = { S3C24XX_DMA_APB, true, 19 }, +	[DMACH_UART1] = { S3C24XX_DMA_APB, true, 21 }, +	[DMACH_UART2] = { S3C24XX_DMA_APB, true, 23 }, +	[DMACH_UART0_SRC2] = { S3C24XX_DMA_APB, true, 20 }, +	[DMACH_UART1_SRC2] = { S3C24XX_DMA_APB, true, 22 }, +	[DMACH_UART2_SRC2] = { S3C24XX_DMA_APB, true, 24 }, +	[DMACH_TIMER] = { S3C24XX_DMA_APB, true, 9 }, +	[DMACH_I2S_IN] = { S3C24XX_DMA_APB, true, 5 }, +	[DMACH_I2S_OUT] = { S3C24XX_DMA_APB, true, 4 }, +	[DMACH_USB_EP1] = { S3C24XX_DMA_APB, true, 13 }, +	[DMACH_USB_EP2] = { S3C24XX_DMA_APB, true, 14 }, +	[DMACH_USB_EP3] = { S3C24XX_DMA_APB, true, 15 }, +	[DMACH_USB_EP4] = { S3C24XX_DMA_APB, true, 16 }, +}; + +static struct s3c24xx_dma_platdata s3c2412_dma_platdata = { +	.num_phy_channels = 4, +	.channels = s3c2412_dma_channels, +	.num_channels = DMACH_MAX, +}; + +struct platform_device s3c2412_device_dma = { +	.name		= "s3c2412-dma", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(s3c2410_dma_resource), +	.resource	= s3c2410_dma_resource, +	.dev	= { +		.platform_data	= &s3c2412_dma_platdata, +	}, +}; +#endif + +#if defined(CONFIG_CPU_S3C2440) +static struct s3c24xx_dma_channel s3c2440_dma_channels[DMACH_MAX] = { +	[DMACH_XD0] = { S3C24XX_DMA_AHB, true, S3C24XX_DMA_CHANREQ(0, 0), }, +	[DMACH_XD1] = { S3C24XX_DMA_AHB, true, S3C24XX_DMA_CHANREQ(0, 1), }, +	[DMACH_SDI] = { S3C24XX_DMA_APB, false, S3C24XX_DMA_CHANREQ(2, 0) | +						S3C24XX_DMA_CHANREQ(6, 1) | +						S3C24XX_DMA_CHANREQ(2, 2) | +						S3C24XX_DMA_CHANREQ(1, 3), +	}, +	[DMACH_SPI0] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(3, 1), }, +	[DMACH_SPI1] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(2, 3), }, +	[DMACH_UART0] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(1, 0), }, +	[DMACH_UART1] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(1, 1), }, +	[DMACH_UART2] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(0, 3), }, +	[DMACH_TIMER] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(3, 0) | +						 S3C24XX_DMA_CHANREQ(3, 2) | +						 S3C24XX_DMA_CHANREQ(3, 3), +	}, +	[DMACH_I2S_IN] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(2, 1) | +						  S3C24XX_DMA_CHANREQ(1, 2), +	}, +	[DMACH_I2S_OUT] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(5, 0) | +						   S3C24XX_DMA_CHANREQ(0, 2), +	}, +	[DMACH_PCM_IN] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(6, 0) | +						  S3C24XX_DMA_CHANREQ(5, 2), +	}, +	[DMACH_PCM_OUT] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(5, 1) | +						  S3C24XX_DMA_CHANREQ(6, 3), +	}, +	[DMACH_MIC_IN] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(6, 2) | +						  S3C24XX_DMA_CHANREQ(5, 3), +	}, +	[DMACH_USB_EP1] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 0), }, +	[DMACH_USB_EP2] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 1), }, +	[DMACH_USB_EP3] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 2), }, +	[DMACH_USB_EP4] = { S3C24XX_DMA_APB, true, S3C24XX_DMA_CHANREQ(4, 3), }, +}; + +static struct s3c24xx_dma_platdata s3c2440_dma_platdata = { +	.num_phy_channels = 4, +	.channels = s3c2440_dma_channels, +	.num_channels = DMACH_MAX, +}; + +struct platform_device s3c2440_device_dma = { +	.name		= "s3c2410-dma", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(s3c2410_dma_resource), +	.resource	= s3c2410_dma_resource, +	.dev	= { +		.platform_data	= &s3c2440_dma_platdata, +	}, +}; +#endif + +#if defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) +static struct resource s3c2443_dma_resource[] = { +	[0] = DEFINE_RES_MEM(S3C24XX_PA_DMA, S3C24XX_SZ_DMA), +	[1] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA0), +	[2] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA1), +	[3] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA2), +	[4] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA3), +	[5] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA4), +	[6] = DEFINE_RES_IRQ(IRQ_S3C2443_DMA5), +}; + +static struct s3c24xx_dma_channel s3c2443_dma_channels[DMACH_MAX] = { +	[DMACH_XD0] = { S3C24XX_DMA_AHB, true, 17 }, +	[DMACH_XD1] = { S3C24XX_DMA_AHB, true, 18 }, +	[DMACH_SDI] = { S3C24XX_DMA_APB, false, 10 }, +	[DMACH_SPI0_RX] = { S3C24XX_DMA_APB, true, 1 }, +	[DMACH_SPI0_TX] = { S3C24XX_DMA_APB, true, 0 }, +	[DMACH_SPI1_RX] = { S3C24XX_DMA_APB, true, 3 }, +	[DMACH_SPI1_TX] = { S3C24XX_DMA_APB, true, 2 }, +	[DMACH_UART0] = { S3C24XX_DMA_APB, true, 19 }, +	[DMACH_UART1] = { S3C24XX_DMA_APB, true, 21 }, +	[DMACH_UART2] = { S3C24XX_DMA_APB, true, 23 }, +	[DMACH_UART3] = { S3C24XX_DMA_APB, true, 25 }, +	[DMACH_UART0_SRC2] = { S3C24XX_DMA_APB, true, 20 }, +	[DMACH_UART1_SRC2] = { S3C24XX_DMA_APB, true, 22 }, +	[DMACH_UART2_SRC2] = { S3C24XX_DMA_APB, true, 24 }, +	[DMACH_UART3_SRC2] = { S3C24XX_DMA_APB, true, 26 }, +	[DMACH_TIMER] = { S3C24XX_DMA_APB, true, 9 }, +	[DMACH_I2S_IN] = { S3C24XX_DMA_APB, true, 5 }, +	[DMACH_I2S_OUT] = { S3C24XX_DMA_APB, true, 4 }, +	[DMACH_PCM_IN] = { S3C24XX_DMA_APB, true, 28 }, +	[DMACH_PCM_OUT] = { S3C24XX_DMA_APB, true, 27 }, +	[DMACH_MIC_IN] = { S3C24XX_DMA_APB, true, 29 }, +}; + +static struct s3c24xx_dma_platdata s3c2443_dma_platdata = { +	.num_phy_channels = 6, +	.channels = s3c2443_dma_channels, +	.num_channels = DMACH_MAX, +}; + +struct platform_device s3c2443_device_dma = { +	.name		= "s3c2443-dma", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(s3c2443_dma_resource), +	.resource	= s3c2443_dma_resource, +	.dev	= { +		.platform_data	= &s3c2443_dma_platdata, +	}, +}; +#endif + +#if defined(CONFIG_COMMON_CLK) && defined(CONFIG_CPU_S3C2410) +void __init s3c2410_init_clocks(int xtal) +{ +	s3c2410_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR); +	samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); +} +#endif + +#ifdef CONFIG_CPU_S3C2412 +void __init s3c2412_init_clocks(int xtal) +{ +	s3c2412_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR); +} +#endif + +#ifdef CONFIG_CPU_S3C2416 +void __init s3c2416_init_clocks(int xtal) +{ +	s3c2443_common_clk_init(NULL, xtal, 0, S3C24XX_VA_CLKPWR); +} +#endif + +#if defined(CONFIG_COMMON_CLK) && defined(CONFIG_CPU_S3C2440) +void __init s3c2440_init_clocks(int xtal) +{ +	s3c2410_common_clk_init(NULL, xtal, 1, S3C24XX_VA_CLKPWR); +	samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); +} +#endif + +#if defined(CONFIG_COMMON_CLK) && defined(CONFIG_CPU_S3C2442) +void __init s3c2442_init_clocks(int xtal) +{ +	s3c2410_common_clk_init(NULL, xtal, 2, S3C24XX_VA_CLKPWR); +	samsung_wdt_reset_init(S3C24XX_VA_WATCHDOG); +} +#endif + +#ifdef CONFIG_CPU_S3C2443 +void __init s3c2443_init_clocks(int xtal) +{ +	s3c2443_common_clk_init(NULL, xtal, 1, S3C24XX_VA_CLKPWR); +} +#endif + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2440) || \ +	defined(CONFIG_CPU_S3C2442) +static struct resource s3c2410_dclk_resource[] = { +	[0] = DEFINE_RES_MEM(0x56000084, 0x4), +}; + +struct platform_device s3c2410_device_dclk = { +	.name		= "s3c2410-dclk", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(s3c2410_dclk_resource), +	.resource	= s3c2410_dclk_resource, +}; +#endif diff --git a/arch/arm/mach-s3c24xx/common.h b/arch/arm/mach-s3c24xx/common.h new file mode 100644 index 00000000000..ac3ff12a060 --- /dev/null +++ b/arch/arm/mach-s3c24xx/common.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Common Header for S3C24XX SoCs + * + * 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_S3C24XX_COMMON_H +#define __ARCH_ARM_MACH_S3C24XX_COMMON_H __FILE__ + +#include <linux/reboot.h> + +struct s3c2410_uartcfg; + +#ifdef CONFIG_CPU_S3C2410 +extern  int s3c2410_init(void); +extern  int s3c2410a_init(void); +extern void s3c2410_map_io(void); +extern void s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2410_init_clocks(int xtal); +extern void s3c2410_restart(enum reboot_mode mode, const char *cmd); +extern void s3c2410_init_irq(void); +#else +#define s3c2410_init_clocks NULL +#define s3c2410_init_uarts NULL +#define s3c2410_map_io NULL +#define s3c2410_init NULL +#define s3c2410a_init NULL +#endif + +#ifdef CONFIG_CPU_S3C2412 +extern  int s3c2412_init(void); +extern void s3c2412_map_io(void); +extern void s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2412_init_clocks(int xtal); +extern  int s3c2412_baseclk_add(void); +extern void s3c2412_restart(enum reboot_mode mode, const char *cmd); +extern void s3c2412_init_irq(void); +#else +#define s3c2412_init_clocks NULL +#define s3c2412_init_uarts NULL +#define s3c2412_map_io NULL +#define s3c2412_init NULL +#endif + +#ifdef CONFIG_CPU_S3C2416 +extern  int s3c2416_init(void); +extern void s3c2416_map_io(void); +extern void s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2416_init_clocks(int xtal); +extern  int s3c2416_baseclk_add(void); +extern void s3c2416_restart(enum reboot_mode mode, const char *cmd); +extern void s3c2416_init_irq(void); + +extern struct syscore_ops s3c2416_irq_syscore_ops; +#else +#define s3c2416_init_clocks NULL +#define s3c2416_init_uarts NULL +#define s3c2416_map_io NULL +#define s3c2416_init NULL +#endif + +#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) +extern void s3c244x_map_io(void); +extern void s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c244x_restart(enum reboot_mode mode, const char *cmd); +#else +#define s3c244x_init_uarts NULL +#endif + +#ifdef CONFIG_CPU_S3C2440 +extern  int s3c2440_init(void); +extern void s3c2440_map_io(void); +extern void s3c2440_init_clocks(int xtal); +extern void s3c2440_init_irq(void); +#else +#define s3c2440_init NULL +#define s3c2440_map_io NULL +#endif + +#ifdef CONFIG_CPU_S3C2442 +extern  int s3c2442_init(void); +extern void s3c2442_map_io(void); +extern void s3c2442_init_clocks(int xtal); +extern void s3c2442_init_irq(void); +#else +#define s3c2442_init NULL +#define s3c2442_map_io NULL +#endif + +#ifdef CONFIG_CPU_S3C2443 +extern  int s3c2443_init(void); +extern void s3c2443_map_io(void); +extern void s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no); +extern void s3c2443_init_clocks(int xtal); +extern  int s3c2443_baseclk_add(void); +extern void s3c2443_restart(enum reboot_mode mode, const char *cmd); +extern void s3c2443_init_irq(void); +#else +#define s3c2443_init_clocks NULL +#define s3c2443_init_uarts NULL +#define s3c2443_map_io NULL +#define s3c2443_init NULL +#endif + +extern struct syscore_ops s3c24xx_irq_syscore_ops; + +extern struct platform_device s3c2410_device_dma; +extern struct platform_device s3c2412_device_dma; +extern struct platform_device s3c2440_device_dma; +extern struct platform_device s3c2443_device_dma; + +extern struct platform_device s3c2410_device_dclk; + +#ifdef CONFIG_S3C2410_COMMON_CLK +void __init s3c2410_common_clk_init(struct device_node *np, unsigned long xti_f, +				    int current_soc, +				    void __iomem *reg_base); +#endif +#ifdef CONFIG_S3C2412_COMMON_CLK +void __init s3c2412_common_clk_init(struct device_node *np, unsigned long xti_f, +				unsigned long ext_f, void __iomem *reg_base); +#endif +#ifdef CONFIG_S3C2443_COMMON_CLK +void __init s3c2443_common_clk_init(struct device_node *np, unsigned long xti_f, +				    int current_soc, +				    void __iomem *reg_base); +#endif + +#endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */ diff --git a/arch/arm/mach-s3c24xx/cpufreq-utils.c b/arch/arm/mach-s3c24xx/cpufreq-utils.c new file mode 100644 index 00000000000..d4d9514335f --- /dev/null +++ b/arch/arm/mach-s3c24xx/cpufreq-utils.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2009 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX CPU Frequency scaling - utils for S3C2410/S3C2440/S3C2442 + * + * 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/cpufreq.h> +#include <linux/io.h> +#include <linux/clk.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> + +#include <plat/cpu-freq-core.h> + +#include "regs-mem.h" + +/** + * s3c2410_cpufreq_setrefresh - set SDRAM refresh value + * @cfg: The frequency configuration + * + * Set the SDRAM refresh value appropriately for the configured + * frequency. + */ +void s3c2410_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) +{ +	struct s3c_cpufreq_board *board = cfg->board; +	unsigned long refresh; +	unsigned long refval; + +	/* Reduce both the refresh time (in ns) and the frequency (in MHz) +	 * down to ensure that we do not overflow 32 bit numbers. +	 * +	 * This should work for HCLK up to 133MHz and refresh period up +	 * to 30usec. +	 */ + +	refresh = (cfg->freq.hclk / 100) * (board->refresh / 10); +	refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale  */ +	refresh = (1 << 11) + 1 - refresh; + +	s3c_freq_dbg("%s: refresh value %lu\n", __func__, refresh); + +	refval = __raw_readl(S3C2410_REFRESH); +	refval &= ~((1 << 12) - 1); +	refval |= refresh; +	__raw_writel(refval, S3C2410_REFRESH); +} + +/** + * s3c2410_set_fvco - set the PLL value + * @cfg: The frequency configuration + */ +void s3c2410_set_fvco(struct s3c_cpufreq_config *cfg) +{ +	if (!IS_ERR(cfg->mpll)) +		clk_set_rate(cfg->mpll, cfg->pll.frequency); +} diff --git a/arch/arm/mach-s3c24xx/dma-s3c2410.c b/arch/arm/mach-s3c24xx/dma-s3c2410.c new file mode 100644 index 00000000000..09aa12da178 --- /dev/null +++ b/arch/arm/mach-s3c24xx/dma-s3c2410.c @@ -0,0 +1,182 @@ +/* linux/arch/arm/mach-s3c2410/dma.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * 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/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> + +#include <mach/map.h> +#include <mach/dma.h> + +#include <plat/cpu.h> +#include <plat/dma-s3c24xx.h> + +#include <mach/regs-gpio.h> +#include <plat/regs-dma.h> +#include <mach/regs-lcd.h> +#include <plat/regs-spi.h> + +static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = { +	[DMACH_XD0] = { +		.name		= "xdreq0", +		.channels[0]	= S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, +	}, +	[DMACH_XD1] = { +		.name		= "xdreq1", +		.channels[1]	= S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, +	}, +	[DMACH_SDI] = { +		.name		= "sdi", +		.channels[0]	= S3C2410_DCON_CH0_SDI | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_SDI | DMA_CH_VALID, +		.channels[3]	= S3C2410_DCON_CH3_SDI | DMA_CH_VALID, +	}, +	[DMACH_SPI0] = { +		.name		= "spi0", +		.channels[1]	= S3C2410_DCON_CH1_SPI | DMA_CH_VALID, +	}, +	[DMACH_SPI1] = { +		.name		= "spi1", +		.channels[3]	= S3C2410_DCON_CH3_SPI | DMA_CH_VALID, +	}, +	[DMACH_UART0] = { +		.name		= "uart0", +		.channels[0]	= S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, +	}, +	[DMACH_UART1] = { +		.name		= "uart1", +		.channels[1]	= S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, +	}, +      	[DMACH_UART2] = { +		.name		= "uart2", +		.channels[3]	= S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, +	}, +	[DMACH_TIMER] = { +		.name		= "timer", +		.channels[0]	= S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, +		.channels[3]	= S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, +	}, +	[DMACH_I2S_IN] = { +		.name		= "i2s-sdi", +		.channels[1]	= S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, +	}, +	[DMACH_I2S_OUT] = { +		.name		= "i2s-sdo", +		.channels[2]	= S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, +	}, +	[DMACH_USB_EP1] = { +		.name		= "usb-ep1", +		.channels[0]	= S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, +	}, +	[DMACH_USB_EP2] = { +		.name		= "usb-ep2", +		.channels[1]	= S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, +	}, +	[DMACH_USB_EP3] = { +		.name		= "usb-ep3", +		.channels[2]	= S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, +	}, +	[DMACH_USB_EP4] = { +		.name		= "usb-ep4", +		.channels[3]	=S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, +	}, +}; + +static void s3c2410_dma_select(struct s3c2410_dma_chan *chan, +			       struct s3c24xx_dma_map *map) +{ +	chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; +} + +static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = { +	.select		= s3c2410_dma_select, +	.dcon_mask	= 7 << 24, +	.map		= s3c2410_dma_mappings, +	.map_size	= ARRAY_SIZE(s3c2410_dma_mappings), +}; + +static struct s3c24xx_dma_order __initdata s3c2410_dma_order = { +	.channels	= { +		[DMACH_SDI]	= { +			.list	= { +				[0]	= 3 | DMA_CH_VALID, +				[1]	= 2 | DMA_CH_VALID, +				[2]	= 0 | DMA_CH_VALID, +			}, +		}, +		[DMACH_I2S_IN]	= { +			.list	= { +				[0]	= 1 | DMA_CH_VALID, +				[1]	= 2 | DMA_CH_VALID, +			}, +		}, +	}, +}; + +static int __init s3c2410_dma_add(struct device *dev, +				  struct subsys_interface *sif) +{ +	s3c2410_dma_init(); +	s3c24xx_dma_order_set(&s3c2410_dma_order); +	return s3c24xx_dma_init_map(&s3c2410_dma_sel); +} + +#if defined(CONFIG_CPU_S3C2410) +static struct subsys_interface s3c2410_dma_interface = { +	.name		= "s3c2410_dma", +	.subsys		= &s3c2410_subsys, +	.add_dev	= s3c2410_dma_add, +}; + +static int __init s3c2410_dma_drvinit(void) +{ +	return subsys_interface_register(&s3c2410_dma_interface); +} + +arch_initcall(s3c2410_dma_drvinit); + +static struct subsys_interface s3c2410a_dma_interface = { +	.name		= "s3c2410a_dma", +	.subsys		= &s3c2410a_subsys, +	.add_dev	= s3c2410_dma_add, +}; + +static int __init s3c2410a_dma_drvinit(void) +{ +	return subsys_interface_register(&s3c2410a_dma_interface); +} + +arch_initcall(s3c2410a_dma_drvinit); +#endif + +#if defined(CONFIG_CPU_S3C2442) +/* S3C2442 DMA contains the same selection table as the S3C2410 */ +static struct subsys_interface s3c2442_dma_interface = { +	.name		= "s3c2442_dma", +	.subsys		= &s3c2442_subsys, +	.add_dev	= s3c2410_dma_add, +}; + +static int __init s3c2442_dma_drvinit(void) +{ +	return subsys_interface_register(&s3c2442_dma_interface); +} + +arch_initcall(s3c2442_dma_drvinit); +#endif + diff --git a/arch/arm/mach-s3c24xx/dma-s3c2412.c b/arch/arm/mach-s3c24xx/dma-s3c2412.c new file mode 100644 index 00000000000..0c0106d1a4d --- /dev/null +++ b/arch/arm/mach-s3c24xx/dma-s3c2412.c @@ -0,0 +1,150 @@ +/* linux/arch/arm/mach-s3c2412/dma.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2412 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * 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/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <mach/dma.h> + +#include <plat/dma-s3c24xx.h> +#include <plat/cpu.h> + +#include <mach/regs-gpio.h> +#include <plat/regs-dma.h> +#include <mach/regs-lcd.h> +#include <plat/regs-spi.h> + +#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID } + +static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = { +	[DMACH_XD0] = { +		.name		= "xdreq0", +		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ0), +	}, +	[DMACH_XD1] = { +		.name		= "xdreq1", +		.channels	= MAP(S3C2412_DMAREQSEL_XDREQ1), +	}, +	[DMACH_SDI] = { +		.name		= "sdi", +		.channels	= MAP(S3C2412_DMAREQSEL_SDI), +	}, +	[DMACH_SPI0_RX] = { +		.name		= "spi0-rx", +		.channels	= MAP(S3C2412_DMAREQSEL_SPI0RX), +	}, +	[DMACH_SPI0_TX] = { +		.name		= "spi0-tx", +		.channels	= MAP(S3C2412_DMAREQSEL_SPI0TX), +	}, +	[DMACH_SPI1_RX] = { +		.name		= "spi1-rx", +		.channels	= MAP(S3C2412_DMAREQSEL_SPI1RX), +	}, +	[DMACH_SPI1_TX] = { +		.name		= "spi1-tx", +		.channels	= MAP(S3C2412_DMAREQSEL_SPI1TX), +	}, +	[DMACH_UART0] = { +		.name		= "uart0", +		.channels	= MAP(S3C2412_DMAREQSEL_UART0_0), +	}, +	[DMACH_UART1] = { +		.name		= "uart1", +		.channels	= MAP(S3C2412_DMAREQSEL_UART1_0), +	}, +      	[DMACH_UART2] = { +		.name		= "uart2", +		.channels	= MAP(S3C2412_DMAREQSEL_UART2_0), +	}, +	[DMACH_UART0_SRC2] = { +		.name		= "uart0", +		.channels	= MAP(S3C2412_DMAREQSEL_UART0_1), +	}, +	[DMACH_UART1_SRC2] = { +		.name		= "uart1", +		.channels	= MAP(S3C2412_DMAREQSEL_UART1_1), +	}, +      	[DMACH_UART2_SRC2] = { +		.name		= "uart2", +		.channels	= MAP(S3C2412_DMAREQSEL_UART2_1), +	}, +	[DMACH_TIMER] = { +		.name		= "timer", +		.channels	= MAP(S3C2412_DMAREQSEL_TIMER), +	}, +	[DMACH_I2S_IN] = { +		.name		= "i2s-sdi", +		.channels	= MAP(S3C2412_DMAREQSEL_I2SRX), +	}, +	[DMACH_I2S_OUT] = { +		.name		= "i2s-sdo", +		.channels	= MAP(S3C2412_DMAREQSEL_I2STX), +	}, +	[DMACH_USB_EP1] = { +		.name		= "usb-ep1", +		.channels	= MAP(S3C2412_DMAREQSEL_USBEP1), +	}, +	[DMACH_USB_EP2] = { +		.name		= "usb-ep2", +		.channels	= MAP(S3C2412_DMAREQSEL_USBEP2), +	}, +	[DMACH_USB_EP3] = { +		.name		= "usb-ep3", +		.channels	= MAP(S3C2412_DMAREQSEL_USBEP3), +	}, +	[DMACH_USB_EP4] = { +		.name		= "usb-ep4", +		.channels	= MAP(S3C2412_DMAREQSEL_USBEP4), +	}, +}; + +static void s3c2412_dma_select(struct s3c2410_dma_chan *chan, +			       struct s3c24xx_dma_map *map) +{ +	unsigned long chsel = map->channels[0] & (~DMA_CH_VALID); +	writel(chsel | S3C2412_DMAREQSEL_HW, +	       chan->regs + S3C2412_DMA_DMAREQSEL); +} + +static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = { +	.select		= s3c2412_dma_select, +	.dcon_mask	= 0, +	.map		= s3c2412_dma_mappings, +	.map_size	= ARRAY_SIZE(s3c2412_dma_mappings), +}; + +static int __init s3c2412_dma_add(struct device *dev, +				  struct subsys_interface *sif) +{ +	s3c2410_dma_init(); +	return s3c24xx_dma_init_map(&s3c2412_dma_sel); +} + +static struct subsys_interface s3c2412_dma_interface = { +	.name		= "s3c2412_dma", +	.subsys		= &s3c2412_subsys, +	.add_dev	= s3c2412_dma_add, +}; + +static int __init s3c2412_dma_init(void) +{ +	return subsys_interface_register(&s3c2412_dma_interface); +} + +arch_initcall(s3c2412_dma_init); diff --git a/arch/arm/mach-s3c24xx/dma-s3c2440.c b/arch/arm/mach-s3c24xx/dma-s3c2440.c new file mode 100644 index 00000000000..2f8e8a3017d --- /dev/null +++ b/arch/arm/mach-s3c24xx/dma-s3c2440.c @@ -0,0 +1,193 @@ +/* linux/arch/arm/mach-s3c2440/dma.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2440 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * 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/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> + +#include <mach/map.h> +#include <mach/dma.h> + +#include <plat/dma-s3c24xx.h> +#include <plat/cpu.h> + +#include <mach/regs-gpio.h> +#include <plat/regs-dma.h> +#include <mach/regs-lcd.h> +#include <plat/regs-spi.h> + +static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = { +	[DMACH_XD0] = { +		.name		= "xdreq0", +		.channels[0]	= S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, +	}, +	[DMACH_XD1] = { +		.name		= "xdreq1", +		.channels[1]	= S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, +	}, +	[DMACH_SDI] = { +		.name		= "sdi", +		.channels[0]	= S3C2410_DCON_CH0_SDI | DMA_CH_VALID, +		.channels[1]	= S3C2440_DCON_CH1_SDI | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_SDI | DMA_CH_VALID, +		.channels[3]	= S3C2410_DCON_CH3_SDI | DMA_CH_VALID, +	}, +	[DMACH_SPI0] = { +		.name		= "spi0", +		.channels[1]	= S3C2410_DCON_CH1_SPI | DMA_CH_VALID, +	}, +	[DMACH_SPI1] = { +		.name		= "spi1", +		.channels[3]	= S3C2410_DCON_CH3_SPI | DMA_CH_VALID, +	}, +	[DMACH_UART0] = { +		.name		= "uart0", +		.channels[0]	= S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, +	}, +	[DMACH_UART1] = { +		.name		= "uart1", +		.channels[1]	= S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, +	}, +      	[DMACH_UART2] = { +		.name		= "uart2", +		.channels[3]	= S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, +	}, +	[DMACH_TIMER] = { +		.name		= "timer", +		.channels[0]	= S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, +		.channels[3]	= S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, +	}, +	[DMACH_I2S_IN] = { +		.name		= "i2s-sdi", +		.channels[1]	= S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, +	}, +	[DMACH_I2S_OUT] = { +		.name		= "i2s-sdo", +		.channels[0]	= S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID, +		.channels[2]	= S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, +	}, +	[DMACH_PCM_IN] = { +		.name		= "pcm-in", +		.channels[0]	= S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID, +		.channels[2]	= S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID, +	}, +	[DMACH_PCM_OUT] = { +		.name		= "pcm-out", +		.channels[1]	= S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID, +		.channels[3]	= S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID, +	}, +	[DMACH_MIC_IN] = { +		.name		= "mic-in", +		.channels[2]	= S3C2440_DCON_CH2_MICIN | DMA_CH_VALID, +		.channels[3]	= S3C2440_DCON_CH3_MICIN | DMA_CH_VALID, +	}, +	[DMACH_USB_EP1] = { +		.name		= "usb-ep1", +		.channels[0]	= S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, +	}, +	[DMACH_USB_EP2] = { +		.name		= "usb-ep2", +		.channels[1]	= S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, +	}, +	[DMACH_USB_EP3] = { +		.name		= "usb-ep3", +		.channels[2]	= S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, +	}, +	[DMACH_USB_EP4] = { +		.name		= "usb-ep4", +		.channels[3]	= S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, +	}, +}; + +static void s3c2440_dma_select(struct s3c2410_dma_chan *chan, +			       struct s3c24xx_dma_map *map) +{ +	chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; +} + +static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = { +	.select		= s3c2440_dma_select, +	.dcon_mask	= 7 << 24, +	.map		= s3c2440_dma_mappings, +	.map_size	= ARRAY_SIZE(s3c2440_dma_mappings), +}; + +static struct s3c24xx_dma_order __initdata s3c2440_dma_order = { +	.channels	= { +		[DMACH_SDI]	= { +			.list	= { +				[0]	= 3 | DMA_CH_VALID, +				[1]	= 2 | DMA_CH_VALID, +				[2]	= 1 | DMA_CH_VALID, +				[3]	= 0 | DMA_CH_VALID, +			}, +		}, +		[DMACH_I2S_IN]	= { +			.list	= { +				[0]	= 1 | DMA_CH_VALID, +				[1]	= 2 | DMA_CH_VALID, +			}, +		}, +		[DMACH_I2S_OUT]	= { +			.list	= { +				[0]	= 2 | DMA_CH_VALID, +				[1]	= 1 | DMA_CH_VALID, +			}, +		}, +		[DMACH_PCM_IN] = { +			.list	= { +				[0]	= 2 | DMA_CH_VALID, +				[1]	= 1 | DMA_CH_VALID, +			}, +		}, +		[DMACH_PCM_OUT] = { +			.list	= { +				[0]	= 1 | DMA_CH_VALID, +				[1]	= 3 | DMA_CH_VALID, +			}, +		}, +		[DMACH_MIC_IN] = { +			.list	= { +				[0]	= 3 | DMA_CH_VALID, +				[1]	= 2 | DMA_CH_VALID, +			}, +		}, +	}, +}; + +static int __init s3c2440_dma_add(struct device *dev, +				  struct subsys_interface *sif) +{ +	s3c2410_dma_init(); +	s3c24xx_dma_order_set(&s3c2440_dma_order); +	return s3c24xx_dma_init_map(&s3c2440_dma_sel); +} + +static struct subsys_interface s3c2440_dma_interface = { +	.name		= "s3c2440_dma", +	.subsys		= &s3c2440_subsys, +	.add_dev	= s3c2440_dma_add, +}; + +static int __init s3c2440_dma_init(void) +{ +	return subsys_interface_register(&s3c2440_dma_interface); +} + +arch_initcall(s3c2440_dma_init); + diff --git a/arch/arm/mach-s3c24xx/dma-s3c2443.c b/arch/arm/mach-s3c24xx/dma-s3c2443.c new file mode 100644 index 00000000000..f4096ec0700 --- /dev/null +++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c @@ -0,0 +1,179 @@ +/* linux/arch/arm/mach-s3c2443/dma.c + * + * Copyright (c) 2007 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2443 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * 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/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <mach/dma.h> + +#include <plat/dma-s3c24xx.h> +#include <plat/cpu.h> + +#include <mach/regs-gpio.h> +#include <plat/regs-dma.h> +#include <mach/regs-lcd.h> +#include <plat/regs-spi.h> + +#define MAP(x) { \ +		[0]	= (x) | DMA_CH_VALID,	\ +		[1]	= (x) | DMA_CH_VALID,	\ +		[2]	= (x) | DMA_CH_VALID,	\ +		[3]	= (x) | DMA_CH_VALID,	\ +		[4]	= (x) | DMA_CH_VALID,	\ +		[5]     = (x) | DMA_CH_VALID,	\ +	} + +static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = { +	[DMACH_XD0] = { +		.name		= "xdreq0", +		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ0), +	}, +	[DMACH_XD1] = { +		.name		= "xdreq1", +		.channels	= MAP(S3C2443_DMAREQSEL_XDREQ1), +	}, +	[DMACH_SDI] = { /* only on S3C2443 */ +		.name		= "sdi", +		.channels	= MAP(S3C2443_DMAREQSEL_SDI), +	}, +	[DMACH_SPI0_RX] = { +		.name		= "spi0-rx", +		.channels	= MAP(S3C2443_DMAREQSEL_SPI0RX), +	}, +	[DMACH_SPI0_TX] = { +		.name		= "spi0-tx", +		.channels	= MAP(S3C2443_DMAREQSEL_SPI0TX), +	}, +	[DMACH_SPI1_RX] = { /* only on S3C2443/S3C2450 */ +		.name		= "spi1-rx", +		.channels	= MAP(S3C2443_DMAREQSEL_SPI1RX), +	}, +	[DMACH_SPI1_TX] = { /* only on S3C2443/S3C2450 */ +		.name		= "spi1-tx", +		.channels	= MAP(S3C2443_DMAREQSEL_SPI1TX), +	}, +	[DMACH_UART0] = { +		.name		= "uart0", +		.channels	= MAP(S3C2443_DMAREQSEL_UART0_0), +	}, +	[DMACH_UART1] = { +		.name		= "uart1", +		.channels	= MAP(S3C2443_DMAREQSEL_UART1_0), +	}, +	[DMACH_UART2] = { +		.name		= "uart2", +		.channels	= MAP(S3C2443_DMAREQSEL_UART2_0), +	}, +	[DMACH_UART3] = { +		.name		= "uart3", +		.channels	= MAP(S3C2443_DMAREQSEL_UART3_0), +	}, +	[DMACH_UART0_SRC2] = { +		.name		= "uart0", +		.channels	= MAP(S3C2443_DMAREQSEL_UART0_1), +	}, +	[DMACH_UART1_SRC2] = { +		.name		= "uart1", +		.channels	= MAP(S3C2443_DMAREQSEL_UART1_1), +	}, +	[DMACH_UART2_SRC2] = { +		.name		= "uart2", +		.channels	= MAP(S3C2443_DMAREQSEL_UART2_1), +	}, +	[DMACH_UART3_SRC2] = { +		.name		= "uart3", +		.channels	= MAP(S3C2443_DMAREQSEL_UART3_1), +	}, +	[DMACH_TIMER] = { +		.name		= "timer", +		.channels	= MAP(S3C2443_DMAREQSEL_TIMER), +	}, +	[DMACH_I2S_IN] = { +		.name		= "i2s-sdi", +		.channels	= MAP(S3C2443_DMAREQSEL_I2SRX), +	}, +	[DMACH_I2S_OUT] = { +		.name		= "i2s-sdo", +		.channels	= MAP(S3C2443_DMAREQSEL_I2STX), +	}, +	[DMACH_PCM_IN] = { +		.name		= "pcm-in", +		.channels	= MAP(S3C2443_DMAREQSEL_PCMIN), +	}, +	[DMACH_PCM_OUT] = { +		.name		= "pcm-out", +		.channels	= MAP(S3C2443_DMAREQSEL_PCMOUT), +	}, +	[DMACH_MIC_IN] = { +		.name		= "mic-in", +		.channels	= MAP(S3C2443_DMAREQSEL_MICIN), +	}, +}; + +static void s3c2443_dma_select(struct s3c2410_dma_chan *chan, +			       struct s3c24xx_dma_map *map) +{ +	unsigned long chsel = map->channels[0] & (~DMA_CH_VALID); +	writel(chsel | S3C2443_DMAREQSEL_HW, +	       chan->regs + S3C2443_DMA_DMAREQSEL); +} + +static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = { +	.select		= s3c2443_dma_select, +	.dcon_mask	= 0, +	.map		= s3c2443_dma_mappings, +	.map_size	= ARRAY_SIZE(s3c2443_dma_mappings), +}; + +static int __init s3c2443_dma_add(struct device *dev, +				  struct subsys_interface *sif) +{ +	s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100); +	return s3c24xx_dma_init_map(&s3c2443_dma_sel); +} + +#ifdef CONFIG_CPU_S3C2416 +/* S3C2416 DMA contains the same selection table as the S3C2443 */ +static struct subsys_interface s3c2416_dma_interface = { +	.name		= "s3c2416_dma", +	.subsys		= &s3c2416_subsys, +	.add_dev	= s3c2443_dma_add, +}; + +static int __init s3c2416_dma_init(void) +{ +	return subsys_interface_register(&s3c2416_dma_interface); +} + +arch_initcall(s3c2416_dma_init); +#endif + +#ifdef CONFIG_CPU_S3C2443 +static struct subsys_interface s3c2443_dma_interface = { +	.name		= "s3c2443_dma", +	.subsys		= &s3c2443_subsys, +	.add_dev	= s3c2443_dma_add, +}; + +static int __init s3c2443_dma_init(void) +{ +	return subsys_interface_register(&s3c2443_dma_interface); +} + +arch_initcall(s3c2443_dma_init); +#endif diff --git a/arch/arm/mach-s3c24xx/dma.c b/arch/arm/mach-s3c24xx/dma.c new file mode 100644 index 00000000000..a8dafc174fe --- /dev/null +++ b/arch/arm/mach-s3c24xx/dma.c @@ -0,0 +1,1465 @@ +/* + * Copyright 2003-2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 DMA core + * + * http://armlinux.simtec.co.uk/ + * + * 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. +*/ + + +#ifdef CONFIG_S3C2410_DMA_DEBUG +#define DEBUG +#endif + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/syscore_ops.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/io.h> + +#include <asm/irq.h> +#include <mach/hardware.h> +#include <mach/dma.h> +#include <mach/map.h> + +#include <plat/dma-s3c24xx.h> +#include <plat/regs-dma.h> + +/* io map for dma */ +static void __iomem *dma_base; +static struct kmem_cache *dma_kmem; + +static int dma_channels; + +static struct s3c24xx_dma_selection dma_sel; + + +/* debugging functions */ + +#define BUF_MAGIC (0xcafebabe) + +#define dmawarn(fmt...) printk(KERN_DEBUG fmt) + +#define dma_regaddr(chan, reg) ((chan)->regs + (reg)) + +#if 1 +#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg)) +#else +static inline void +dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val) +{ +	pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg); +	writel(val, dma_regaddr(chan, reg)); +} +#endif + +#define dma_rdreg(chan, reg) readl((chan)->regs + (reg)) + +/* captured register state for debug */ + +struct s3c2410_dma_regstate { +	unsigned long         dcsrc; +	unsigned long         disrc; +	unsigned long         dstat; +	unsigned long         dcon; +	unsigned long         dmsktrig; +}; + +#ifdef CONFIG_S3C2410_DMA_DEBUG + +/* dmadbg_showregs + * + * simple debug routine to print the current state of the dma registers +*/ + +static void +dmadbg_capture(struct s3c2410_dma_chan *chan, struct s3c2410_dma_regstate *regs) +{ +	regs->dcsrc    = dma_rdreg(chan, S3C2410_DMA_DCSRC); +	regs->disrc    = dma_rdreg(chan, S3C2410_DMA_DISRC); +	regs->dstat    = dma_rdreg(chan, S3C2410_DMA_DSTAT); +	regs->dcon     = dma_rdreg(chan, S3C2410_DMA_DCON); +	regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); +} + +static void +dmadbg_dumpregs(const char *fname, int line, struct s3c2410_dma_chan *chan, +		 struct s3c2410_dma_regstate *regs) +{ +	printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n", +	       chan->number, fname, line, +	       regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig, +	       regs->dcon); +} + +static void +dmadbg_showchan(const char *fname, int line, struct s3c2410_dma_chan *chan) +{ +	struct s3c2410_dma_regstate state; + +	dmadbg_capture(chan, &state); + +	printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n", +	       chan->number, fname, line, chan->load_state, +	       chan->curr, chan->next, chan->end); + +	dmadbg_dumpregs(fname, line, chan, &state); +} + +static void +dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan) +{ +	struct s3c2410_dma_regstate state; + +	dmadbg_capture(chan, &state); +	dmadbg_dumpregs(fname, line, chan, &state); +} + +#define dbg_showregs(chan) dmadbg_showregs(__func__, __LINE__, (chan)) +#define dbg_showchan(chan) dmadbg_showchan(__func__, __LINE__, (chan)) +#else +#define dbg_showregs(chan) do { } while(0) +#define dbg_showchan(chan) do { } while(0) +#endif /* CONFIG_S3C2410_DMA_DEBUG */ + +/* s3c2410_dma_stats_timeout + * + * Update DMA stats from timeout info +*/ + +static void +s3c2410_dma_stats_timeout(struct s3c2410_dma_stats *stats, int val) +{ +	if (stats == NULL) +		return; + +	if (val > stats->timeout_longest) +		stats->timeout_longest = val; +	if (val < stats->timeout_shortest) +		stats->timeout_shortest = val; + +	stats->timeout_avg += val; +} + +/* s3c2410_dma_waitforload + * + * wait for the DMA engine to load a buffer, and update the state accordingly +*/ + +static int +s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line) +{ +	int timeout = chan->load_timeout; +	int took; + +	if (chan->load_state != S3C2410_DMALOAD_1LOADED) { +		printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line); +		return 0; +	} + +	if (chan->stats != NULL) +		chan->stats->loads++; + +	while (--timeout > 0) { +		if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) { +			took = chan->load_timeout - timeout; + +			s3c2410_dma_stats_timeout(chan->stats, took); + +			switch (chan->load_state) { +			case S3C2410_DMALOAD_1LOADED: +				chan->load_state = S3C2410_DMALOAD_1RUNNING; +				break; + +			default: +				printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state); +			} + +			return 1; +		} +	} + +	if (chan->stats != NULL) { +		chan->stats->timeout_failed++; +	} + +	return 0; +} + +/* s3c2410_dma_loadbuffer + * + * load a buffer, and update the channel state +*/ + +static inline int +s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan, +		       struct s3c2410_dma_buf *buf) +{ +	unsigned long reload; + +	if (buf == NULL) { +		dmawarn("buffer is NULL\n"); +		return -EINVAL; +	} + +	pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n", +		 buf, (unsigned long)buf->data, buf->size); + +	/* check the state of the channel before we do anything */ + +	if (chan->load_state == S3C2410_DMALOAD_1LOADED) { +		dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n"); +	} + +	if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) { +		dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n"); +	} + +	/* it would seem sensible if we are the last buffer to not bother +	 * with the auto-reload bit, so that the DMA engine will not try +	 * and load another transfer after this one has finished... +	 */ +	if (chan->load_state == S3C2410_DMALOAD_NONE) { +		pr_debug("load_state is none, checking for noreload (next=%p)\n", +			 buf->next); +		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0; +	} else { +		//pr_debug("load_state is %d => autoreload\n", chan->load_state); +		reload = S3C2410_DCON_AUTORELOAD; +	} + +	if ((buf->data & 0xf0000000) != 0x30000000) { +		dmawarn("dmaload: buffer is %p\n", (void *)buf->data); +	} + +	writel(buf->data, chan->addr_reg); + +	dma_wrreg(chan, S3C2410_DMA_DCON, +		  chan->dcon | reload | (buf->size/chan->xfer_unit)); + +	chan->next = buf->next; + +	/* update the state of the channel */ + +	switch (chan->load_state) { +	case S3C2410_DMALOAD_NONE: +		chan->load_state = S3C2410_DMALOAD_1LOADED; +		break; + +	case S3C2410_DMALOAD_1RUNNING: +		chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING; +		break; + +	default: +		dmawarn("dmaload: unknown state %d in loadbuffer\n", +			chan->load_state); +		break; +	} + +	return 0; +} + +/* s3c2410_dma_call_op + * + * small routine to call the op routine with the given op if it has been + * registered +*/ + +static void +s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op) +{ +	if (chan->op_fn != NULL) { +		(chan->op_fn)(chan, op); +	} +} + +/* s3c2410_dma_buffdone + * + * small wrapper to check if callback routine needs to be called, and + * if so, call it +*/ + +static inline void +s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf, +		     enum s3c2410_dma_buffresult result) +{ +#if 0 +	pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n", +		 chan->callback_fn, buf, buf->id, buf->size, result); +#endif + +	if (chan->callback_fn != NULL) { +		(chan->callback_fn)(chan, buf->id, buf->size, result); +	} +} + +/* s3c2410_dma_start + * + * start a dma channel going +*/ + +static int s3c2410_dma_start(struct s3c2410_dma_chan *chan) +{ +	unsigned long tmp; +	unsigned long flags; + +	pr_debug("s3c2410_start_dma: channel=%d\n", chan->number); + +	local_irq_save(flags); + +	if (chan->state == S3C2410_DMA_RUNNING) { +		pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state); +		local_irq_restore(flags); +		return 0; +	} + +	chan->state = S3C2410_DMA_RUNNING; + +	/* check whether there is anything to load, and if not, see +	 * if we can find anything to load +	 */ + +	if (chan->load_state == S3C2410_DMALOAD_NONE) { +		if (chan->next == NULL) { +			printk(KERN_ERR "dma%d: channel has nothing loaded\n", +			       chan->number); +			chan->state = S3C2410_DMA_IDLE; +			local_irq_restore(flags); +			return -EINVAL; +		} + +		s3c2410_dma_loadbuffer(chan, chan->next); +	} + +	dbg_showchan(chan); + +	/* enable the channel */ + +	if (!chan->irq_enabled) { +		enable_irq(chan->irq); +		chan->irq_enabled = 1; +	} + +	/* start the channel going */ + +	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); +	tmp &= ~S3C2410_DMASKTRIG_STOP; +	tmp |= S3C2410_DMASKTRIG_ON; +	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + +	pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp); + +#if 0 +	/* the dma buffer loads should take care of clearing the AUTO +	 * reloading feature */ +	tmp = dma_rdreg(chan, S3C2410_DMA_DCON); +	tmp &= ~S3C2410_DCON_NORELOAD; +	dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + +	s3c2410_dma_call_op(chan, S3C2410_DMAOP_START); + +	dbg_showchan(chan); + +	/* if we've only loaded one buffer onto the channel, then chec +	 * to see if we have another, and if so, try and load it so when +	 * the first buffer is finished, the new one will be loaded onto +	 * the channel */ + +	if (chan->next != NULL) { +		if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + +			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { +				pr_debug("%s: buff not yet loaded, no more todo\n", +					 __func__); +			} else { +				chan->load_state = S3C2410_DMALOAD_1RUNNING; +				s3c2410_dma_loadbuffer(chan, chan->next); +			} + +		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { +			s3c2410_dma_loadbuffer(chan, chan->next); +		} +	} + + +	local_irq_restore(flags); + +	return 0; +} + +/* s3c2410_dma_canload + * + * work out if we can queue another buffer into the DMA engine +*/ + +static int +s3c2410_dma_canload(struct s3c2410_dma_chan *chan) +{ +	if (chan->load_state == S3C2410_DMALOAD_NONE || +	    chan->load_state == S3C2410_DMALOAD_1RUNNING) +		return 1; + +	return 0; +} + +/* s3c2410_dma_enqueue + * + * queue an given buffer for dma transfer. + * + * id         the device driver's id information for this buffer + * data       the physical address of the buffer data + * size       the size of the buffer in bytes + * + * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART + * is checked, and if set, the channel is started. If this flag isn't set, + * then an error will be returned. + * + * It is possible to queue more than one DMA buffer onto a channel at + * once, and the code will deal with the re-loading of the next buffer + * when necessary. +*/ + +int s3c2410_dma_enqueue(enum dma_ch channel, void *id, +			dma_addr_t data, int size) +{ +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); +	struct s3c2410_dma_buf *buf; +	unsigned long flags; + +	if (chan == NULL) +		return -EINVAL; + +	pr_debug("%s: id=%p, data=%08x, size=%d\n", +		 __func__, id, (unsigned int)data, size); + +	buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC); +	if (buf == NULL) { +		pr_debug("%s: out of memory (%ld alloc)\n", +			 __func__, (long)sizeof(*buf)); +		return -ENOMEM; +	} + +	//pr_debug("%s: new buffer %p\n", __func__, buf); +	//dbg_showchan(chan); + +	buf->next  = NULL; +	buf->data  = buf->ptr = data; +	buf->size  = size; +	buf->id    = id; +	buf->magic = BUF_MAGIC; + +	local_irq_save(flags); + +	if (chan->curr == NULL) { +		/* we've got nothing loaded... */ +		pr_debug("%s: buffer %p queued onto empty channel\n", +			 __func__, buf); + +		chan->curr = buf; +		chan->end  = buf; +		chan->next = NULL; +	} else { +		pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n", +			 chan->number, __func__, buf); + +		if (chan->end == NULL) { +			pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n", +				 chan->number, __func__, chan); +		} else { +			chan->end->next = buf; +			chan->end = buf; +		} +	} + +	/* if necessary, update the next buffer field */ +	if (chan->next == NULL) +		chan->next = buf; + +	/* check to see if we can load a buffer */ +	if (chan->state == S3C2410_DMA_RUNNING) { +		if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) { +			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { +				printk(KERN_ERR "dma%d: loadbuffer:" +				       "timeout loading buffer\n", +				       chan->number); +				dbg_showchan(chan); +				local_irq_restore(flags); +				return -EINVAL; +			} +		} + +		while (s3c2410_dma_canload(chan) && chan->next != NULL) { +			s3c2410_dma_loadbuffer(chan, chan->next); +		} +	} else if (chan->state == S3C2410_DMA_IDLE) { +		if (chan->flags & S3C2410_DMAF_AUTOSTART) { +			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, +					 S3C2410_DMAOP_START); +		} +	} + +	local_irq_restore(flags); +	return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_enqueue); + +static inline void +s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf) +{ +	int magicok = (buf->magic == BUF_MAGIC); + +	buf->magic = -1; + +	if (magicok) { +		kmem_cache_free(dma_kmem, buf); +	} else { +		printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf); +	} +} + +/* s3c2410_dma_lastxfer + * + * called when the system is out of buffers, to ensure that the channel + * is prepared for shutdown. +*/ + +static inline void +s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan) +{ +#if 0 +	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n", +		 chan->number, chan->load_state); +#endif + +	switch (chan->load_state) { +	case S3C2410_DMALOAD_NONE: +		break; + +	case S3C2410_DMALOAD_1LOADED: +		if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { +				/* flag error? */ +			printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", +			       chan->number, __func__); +			return; +		} +		break; + +	case S3C2410_DMALOAD_1LOADED_1RUNNING: +		/* I believe in this case we do not have anything to do +		 * until the next buffer comes along, and we turn off the +		 * reload */ +		return; + +	default: +		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n", +			 chan->number, chan->load_state); +		return; + +	} + +	/* hopefully this'll shut the damned thing up after the transfer... */ +	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD); +} + + +#define dmadbg2(x...) + +static irqreturn_t +s3c2410_dma_irq(int irq, void *devpw) +{ +	struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; +	struct s3c2410_dma_buf  *buf; + +	buf = chan->curr; + +	dbg_showchan(chan); + +	/* modify the channel state */ + +	switch (chan->load_state) { +	case S3C2410_DMALOAD_1RUNNING: +		/* TODO - if we are running only one buffer, we probably +		 * want to reload here, and then worry about the buffer +		 * callback */ + +		chan->load_state = S3C2410_DMALOAD_NONE; +		break; + +	case S3C2410_DMALOAD_1LOADED: +		/* iirc, we should go back to NONE loaded here, we +		 * had a buffer, and it was never verified as being +		 * loaded. +		 */ + +		chan->load_state = S3C2410_DMALOAD_NONE; +		break; + +	case S3C2410_DMALOAD_1LOADED_1RUNNING: +		/* we'll worry about checking to see if another buffer is +		 * ready after we've called back the owner. This should +		 * ensure we do not wait around too long for the DMA +		 * engine to start the next transfer +		 */ + +		chan->load_state = S3C2410_DMALOAD_1LOADED; +		break; + +	case S3C2410_DMALOAD_NONE: +		printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n", +		       chan->number); +		break; + +	default: +		printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n", +		       chan->number, chan->load_state); +		break; +	} + +	if (buf != NULL) { +		/* update the chain to make sure that if we load any more +		 * buffers when we call the callback function, things should +		 * work properly */ + +		chan->curr = buf->next; +		buf->next  = NULL; + +		if (buf->magic != BUF_MAGIC) { +			printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n", +			       chan->number, __func__, buf); +			return IRQ_HANDLED; +		} + +		s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK); + +		/* free resouces */ +		s3c2410_dma_freebuf(buf); +	} else { +	} + +	/* only reload if the channel is still running... our buffer done +	 * routine may have altered the state by requesting the dma channel +	 * to stop or shutdown... */ + +	/* todo: check that when the channel is shut-down from inside this +	 * function, we cope with unsetting reload, etc */ + +	if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) { +		unsigned long flags; + +		switch (chan->load_state) { +		case S3C2410_DMALOAD_1RUNNING: +			/* don't need to do anything for this state */ +			break; + +		case S3C2410_DMALOAD_NONE: +			/* can load buffer immediately */ +			break; + +		case S3C2410_DMALOAD_1LOADED: +			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { +				/* flag error? */ +				printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n", +				       chan->number, __func__); +				return IRQ_HANDLED; +			} + +			break; + +		case S3C2410_DMALOAD_1LOADED_1RUNNING: +			goto no_load; + +		default: +			printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n", +			       chan->number, chan->load_state); +			return IRQ_HANDLED; +		} + +		local_irq_save(flags); +		s3c2410_dma_loadbuffer(chan, chan->next); +		local_irq_restore(flags); +	} else { +		s3c2410_dma_lastxfer(chan); + +		/* see if we can stop this channel.. */ +		if (chan->load_state == S3C2410_DMALOAD_NONE) { +			pr_debug("dma%d: end of transfer, stopping channel (%ld)\n", +				 chan->number, jiffies); +			s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL, +					 S3C2410_DMAOP_STOP); +		} +	} + + no_load: +	return IRQ_HANDLED; +} + +static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel); + +/* s3c2410_request_dma + * + * get control of an dma channel +*/ + +int s3c2410_dma_request(enum dma_ch channel, +			struct s3c2410_dma_client *client, +			void *dev) +{ +	struct s3c2410_dma_chan *chan; +	unsigned long flags; +	int err; + +	pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n", +		 channel, client->name, dev); + +	local_irq_save(flags); + +	chan = s3c2410_dma_map_channel(channel); +	if (chan == NULL) { +		local_irq_restore(flags); +		return -EBUSY; +	} + +	dbg_showchan(chan); + +	chan->client = client; +	chan->in_use = 1; + +	if (!chan->irq_claimed) { +		pr_debug("dma%d: %s : requesting irq %d\n", +			 channel, __func__, chan->irq); + +		chan->irq_claimed = 1; +		local_irq_restore(flags); + +		err = request_irq(chan->irq, s3c2410_dma_irq, 0, +				  client->name, (void *)chan); + +		local_irq_save(flags); + +		if (err) { +			chan->in_use = 0; +			chan->irq_claimed = 0; +			local_irq_restore(flags); + +			printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n", +			       client->name, chan->irq, chan->number); +			return err; +		} + +		chan->irq_enabled = 1; +	} + +	local_irq_restore(flags); + +	/* need to setup */ + +	pr_debug("%s: channel initialised, %p\n", __func__, chan); + +	return chan->number | DMACH_LOW_LEVEL; +} + +EXPORT_SYMBOL(s3c2410_dma_request); + +/* s3c2410_dma_free + * + * release the given channel back to the system, will stop and flush + * any outstanding transfers, and ensure the channel is ready for the + * next claimant. + * + * Note, although a warning is currently printed if the freeing client + * info is not the same as the registrant's client info, the free is still + * allowed to go through. +*/ + +int s3c2410_dma_free(enum dma_ch channel, struct s3c2410_dma_client *client) +{ +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); +	unsigned long flags; + +	if (chan == NULL) +		return -EINVAL; + +	local_irq_save(flags); + +	if (chan->client != client) { +		printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n", +		       channel, chan->client, client); +	} + +	/* sort out stopping and freeing the channel */ + +	if (chan->state != S3C2410_DMA_IDLE) { +		pr_debug("%s: need to stop dma channel %p\n", +		       __func__, chan); + +		/* possibly flush the channel */ +		s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP); +	} + +	chan->client = NULL; +	chan->in_use = 0; + +	if (chan->irq_claimed) +		free_irq(chan->irq, (void *)chan); + +	chan->irq_claimed = 0; + +	if (!(channel & DMACH_LOW_LEVEL)) +		s3c_dma_chan_map[channel] = NULL; + +	local_irq_restore(flags); + +	return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_free); + +static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan) +{ +	unsigned long flags; +	unsigned long tmp; + +	pr_debug("%s:\n", __func__); + +	dbg_showchan(chan); + +	local_irq_save(flags); + +	s3c2410_dma_call_op(chan,  S3C2410_DMAOP_STOP); + +	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); +	tmp |= S3C2410_DMASKTRIG_STOP; +	//tmp &= ~S3C2410_DMASKTRIG_ON; +	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp); + +#if 0 +	/* should also clear interrupts, according to WinCE BSP */ +	tmp = dma_rdreg(chan, S3C2410_DMA_DCON); +	tmp |= S3C2410_DCON_NORELOAD; +	dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +#endif + +	/* should stop do this, or should we wait for flush? */ +	chan->state      = S3C2410_DMA_IDLE; +	chan->load_state = S3C2410_DMALOAD_NONE; + +	local_irq_restore(flags); + +	return 0; +} + +static void s3c2410_dma_waitforstop(struct s3c2410_dma_chan *chan) +{ +	unsigned long tmp; +	unsigned int timeout = 0x10000; + +	while (timeout-- > 0) { +		tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG); + +		if (!(tmp & S3C2410_DMASKTRIG_ON)) +			return; +	} + +	pr_debug("dma%d: failed to stop?\n", chan->number); +} + + +/* s3c2410_dma_flush + * + * stop the channel, and remove all current and pending transfers +*/ + +static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan) +{ +	struct s3c2410_dma_buf *buf, *next; +	unsigned long flags; + +	pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number); + +	dbg_showchan(chan); + +	local_irq_save(flags); + +	if (chan->state != S3C2410_DMA_IDLE) { +		pr_debug("%s: stopping channel...\n", __func__ ); +		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP); +	} + +	buf = chan->curr; +	if (buf == NULL) +		buf = chan->next; + +	chan->curr = chan->next = chan->end = NULL; + +	if (buf != NULL) { +		for ( ; buf != NULL; buf = next) { +			next = buf->next; + +			pr_debug("%s: free buffer %p, next %p\n", +			       __func__, buf, buf->next); + +			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT); +			s3c2410_dma_freebuf(buf); +		} +	} + +	dbg_showregs(chan); + +	s3c2410_dma_waitforstop(chan); + +#if 0 +	/* should also clear interrupts, according to WinCE BSP */ +	{ +		unsigned long tmp; + +		tmp = dma_rdreg(chan, S3C2410_DMA_DCON); +		tmp |= S3C2410_DCON_NORELOAD; +		dma_wrreg(chan, S3C2410_DMA_DCON, tmp); +	} +#endif + +	dbg_showregs(chan); + +	local_irq_restore(flags); + +	return 0; +} + +static int s3c2410_dma_started(struct s3c2410_dma_chan *chan) +{ +	unsigned long flags; + +	local_irq_save(flags); + +	dbg_showchan(chan); + +	/* if we've only loaded one buffer onto the channel, then chec +	 * to see if we have another, and if so, try and load it so when +	 * the first buffer is finished, the new one will be loaded onto +	 * the channel */ + +	if (chan->next != NULL) { +		if (chan->load_state == S3C2410_DMALOAD_1LOADED) { + +			if (s3c2410_dma_waitforload(chan, __LINE__) == 0) { +				pr_debug("%s: buff not yet loaded, no more todo\n", +					 __func__); +			} else { +				chan->load_state = S3C2410_DMALOAD_1RUNNING; +				s3c2410_dma_loadbuffer(chan, chan->next); +			} + +		} else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) { +			s3c2410_dma_loadbuffer(chan, chan->next); +		} +	} + + +	local_irq_restore(flags); + +	return 0; + +} + +int +s3c2410_dma_ctrl(enum dma_ch channel, enum s3c2410_chan_op op) +{ +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + +	if (chan == NULL) +		return -EINVAL; + +	switch (op) { +	case S3C2410_DMAOP_START: +		return s3c2410_dma_start(chan); + +	case S3C2410_DMAOP_STOP: +		return s3c2410_dma_dostop(chan); + +	case S3C2410_DMAOP_PAUSE: +	case S3C2410_DMAOP_RESUME: +		return -ENOENT; + +	case S3C2410_DMAOP_FLUSH: +		return s3c2410_dma_flush(chan); + +	case S3C2410_DMAOP_STARTED: +		return s3c2410_dma_started(chan); + +	case S3C2410_DMAOP_TIMEOUT: +		return 0; + +	} + +	return -ENOENT;      /* unknown, don't bother */ +} + +EXPORT_SYMBOL(s3c2410_dma_ctrl); + +/* DMA configuration for each channel + * + * DISRCC -> source of the DMA (AHB,APB) + * DISRC  -> source address of the DMA + * DIDSTC -> destination of the DMA (AHB,APD) + * DIDST  -> destination address of the DMA +*/ + +/* s3c2410_dma_config + * + * xfersize:     size of unit in bytes (1,2,4) +*/ + +int s3c2410_dma_config(enum dma_ch channel, +		       int xferunit) +{ +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); +	unsigned int dcon; + +	pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit); + +	if (chan == NULL) +		return -EINVAL; + +	dcon = chan->dcon & dma_sel.dcon_mask; +	pr_debug("%s: dcon is %08x\n", __func__, dcon); + +	switch (chan->req_ch) { +	case DMACH_I2S_IN: +	case DMACH_I2S_OUT: +	case DMACH_PCM_IN: +	case DMACH_PCM_OUT: +	case DMACH_MIC_IN: +	default: +		dcon |= S3C2410_DCON_HANDSHAKE; +		dcon |= S3C2410_DCON_SYNC_PCLK; +		break; + +	case DMACH_SDI: +		/* note, ensure if need HANDSHAKE or not */ +		dcon |= S3C2410_DCON_SYNC_PCLK; +		break; + +	case DMACH_XD0: +	case DMACH_XD1: +		dcon |= S3C2410_DCON_HANDSHAKE; +		dcon |= S3C2410_DCON_SYNC_HCLK; +		break; +	} + +	switch (xferunit) { +	case 1: +		dcon |= S3C2410_DCON_BYTE; +		break; + +	case 2: +		dcon |= S3C2410_DCON_HALFWORD; +		break; + +	case 4: +		dcon |= S3C2410_DCON_WORD; +		break; + +	default: +		pr_debug("%s: bad transfer size %d\n", __func__, xferunit); +		return -EINVAL; +	} + +	dcon |= S3C2410_DCON_HWTRIG; +	dcon |= S3C2410_DCON_INTREQ; + +	pr_debug("%s: dcon now %08x\n", __func__, dcon); + +	chan->dcon = dcon; +	chan->xfer_unit = xferunit; + +	return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_config); + + +/* s3c2410_dma_devconfig + * + * configure the dma source/destination hardware type and address + * + * source:    DMA_FROM_DEVICE: source is hardware + *            DMA_TO_DEVICE: source is memory + * + * devaddr:   physical address of the source +*/ + +int s3c2410_dma_devconfig(enum dma_ch channel, +			  enum dma_data_direction source, +			  unsigned long devaddr) +{ +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); +	unsigned int hwcfg; + +	if (chan == NULL) +		return -EINVAL; + +	pr_debug("%s: source=%d, devaddr=%08lx\n", +		 __func__, (int)source, devaddr); + +	chan->source = source; +	chan->dev_addr = devaddr; + +	switch (chan->req_ch) { +	case DMACH_XD0: +	case DMACH_XD1: +		hwcfg = 0; /* AHB */ +		break; + +	default: +		hwcfg = S3C2410_DISRCC_APB; +	} + +	/* always assume our peripheral desintation is a fixed +	 * address in memory. */ +	 hwcfg |= S3C2410_DISRCC_INC; + +	switch (source) { +	case DMA_FROM_DEVICE: +		/* source is hardware */ +		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n", +			 __func__, devaddr, hwcfg); +		dma_wrreg(chan, S3C2410_DMA_DISRCC, hwcfg & 3); +		dma_wrreg(chan, S3C2410_DMA_DISRC,  devaddr); +		dma_wrreg(chan, S3C2410_DMA_DIDSTC, (0<<1) | (0<<0)); + +		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST); +		break; + +	case DMA_TO_DEVICE: +		/* source is memory */ +		pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n", +			 __func__, devaddr, hwcfg); +		dma_wrreg(chan, S3C2410_DMA_DISRCC, (0<<1) | (0<<0)); +		dma_wrreg(chan, S3C2410_DMA_DIDST,  devaddr); +		dma_wrreg(chan, S3C2410_DMA_DIDSTC, hwcfg & 3); + +		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DISRC); +		break; + +	default: +		printk(KERN_ERR "dma%d: invalid source type (%d)\n", +		       channel, source); + +		return -EINVAL; +	} + +	return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_devconfig); + +/* s3c2410_dma_getposition + * + * returns the current transfer points for the dma source and destination +*/ + +int s3c2410_dma_getposition(enum dma_ch channel, dma_addr_t *src, dma_addr_t *dst) +{ +	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); + +	if (chan == NULL) +		return -EINVAL; + +	if (src != NULL) + 		*src = dma_rdreg(chan, S3C2410_DMA_DCSRC); + + 	if (dst != NULL) + 		*dst = dma_rdreg(chan, S3C2410_DMA_DCDST); + + 	return 0; +} + +EXPORT_SYMBOL(s3c2410_dma_getposition); + +/* system core operations */ + +#ifdef CONFIG_PM + +static void s3c2410_dma_suspend_chan(struct s3c2410_dma_chan *cp) +{ +	printk(KERN_DEBUG "suspending dma channel %d\n", cp->number); + +	if (dma_rdreg(cp, S3C2410_DMA_DMASKTRIG) & S3C2410_DMASKTRIG_ON) { +		/* the dma channel is still working, which is probably +		 * a bad thing to do over suspend/resume. We stop the +		 * channel and assume that the client is either going to +		 * retry after resume, or that it is broken. +		 */ + +		printk(KERN_INFO "dma: stopping channel %d due to suspend\n", +		       cp->number); + +		s3c2410_dma_dostop(cp); +	} +} + +static int s3c2410_dma_suspend(void) +{ +	struct s3c2410_dma_chan *cp = s3c2410_chans; +	int channel; + +	for (channel = 0; channel < dma_channels; cp++, channel++) +		s3c2410_dma_suspend_chan(cp); + +	return 0; +} + +static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) +{ +	unsigned int no = cp->number | DMACH_LOW_LEVEL; + +	/* restore channel's hardware configuration */ + +	if (!cp->in_use) +		return; + +	printk(KERN_INFO "dma%d: restoring configuration\n", cp->number); + +	s3c2410_dma_config(no, cp->xfer_unit); +	s3c2410_dma_devconfig(no, cp->source, cp->dev_addr); + +	/* re-select the dma source for this channel */ + +	if (cp->map != NULL) +		dma_sel.select(cp, cp->map); +} + +static void s3c2410_dma_resume(void) +{ +	struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1; +	int channel; + +	for (channel = dma_channels - 1; channel >= 0; cp--, channel--) +		s3c2410_dma_resume_chan(cp); +} + +#else +#define s3c2410_dma_suspend NULL +#define s3c2410_dma_resume  NULL +#endif /* CONFIG_PM */ + +struct syscore_ops dma_syscore_ops = { +	.suspend	= s3c2410_dma_suspend, +	.resume		= s3c2410_dma_resume, +}; + +/* kmem cache implementation */ + +static void s3c2410_dma_cache_ctor(void *p) +{ +	memset(p, 0, sizeof(struct s3c2410_dma_buf)); +} + +/* initialisation code */ + +static int __init s3c24xx_dma_syscore_init(void) +{ +	register_syscore_ops(&dma_syscore_ops); + +	return 0; +} + +late_initcall(s3c24xx_dma_syscore_init); + +int __init s3c24xx_dma_init(unsigned int channels, unsigned int irq, +			    unsigned int stride) +{ +	struct s3c2410_dma_chan *cp; +	int channel; +	int ret; + +	printk("S3C24XX DMA Driver, Copyright 2003-2006 Simtec Electronics\n"); + +	dma_channels = channels; + +	dma_base = ioremap(S3C24XX_PA_DMA, stride * channels); +	if (dma_base == NULL) { +		printk(KERN_ERR "dma failed to remap register block\n"); +		return -ENOMEM; +	} + +	dma_kmem = kmem_cache_create("dma_desc", +				     sizeof(struct s3c2410_dma_buf), 0, +				     SLAB_HWCACHE_ALIGN, +				     s3c2410_dma_cache_ctor); + +	if (dma_kmem == NULL) { +		printk(KERN_ERR "dma failed to make kmem cache\n"); +		ret = -ENOMEM; +		goto err; +	} + +	for (channel = 0; channel < channels;  channel++) { +		cp = &s3c2410_chans[channel]; + +		memset(cp, 0, sizeof(struct s3c2410_dma_chan)); + +		/* dma channel irqs are in order.. */ +		cp->number = channel; +		cp->irq    = channel + irq; +		cp->regs   = dma_base + (channel * stride); + +		/* point current stats somewhere */ +		cp->stats  = &cp->stats_store; +		cp->stats_store.timeout_shortest = LONG_MAX; + +		/* basic channel configuration */ + +		cp->load_timeout = 1<<18; + +		printk("DMA channel %d at %p, irq %d\n", +		       cp->number, cp->regs, cp->irq); +	} + +	return 0; + + err: +	kmem_cache_destroy(dma_kmem); +	iounmap(dma_base); +	dma_base = NULL; +	return ret; +} + +int __init s3c2410_dma_init(void) +{ +	return s3c24xx_dma_init(4, IRQ_DMA0, 0x40); +} + +static inline int is_channel_valid(unsigned int channel) +{ +	return (channel & DMA_CH_VALID); +} + +static struct s3c24xx_dma_order *dma_order; + + +/* s3c2410_dma_map_channel() + * + * turn the virtual channel number into a real, and un-used hardware + * channel. + * + * first, try the dma ordering given to us by either the relevant + * dma code, or the board. Then just find the first usable free + * channel +*/ + +static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel) +{ +	struct s3c24xx_dma_order_ch *ord = NULL; +	struct s3c24xx_dma_map *ch_map; +	struct s3c2410_dma_chan *dmach; +	int ch; + +	if (dma_sel.map == NULL || channel > dma_sel.map_size) +		return NULL; + +	ch_map = dma_sel.map + channel; + +	/* first, try the board mapping */ + +	if (dma_order) { +		ord = &dma_order->channels[channel]; + +		for (ch = 0; ch < dma_channels; ch++) { +			int tmp; +			if (!is_channel_valid(ord->list[ch])) +				continue; + +			tmp = ord->list[ch] & ~DMA_CH_VALID; +			if (s3c2410_chans[tmp].in_use == 0) { +				ch = tmp; +				goto found; +			} +		} + +		if (ord->flags & DMA_CH_NEVER) +			return NULL; +	} + +	/* second, search the channel map for first free */ + +	for (ch = 0; ch < dma_channels; ch++) { +		if (!is_channel_valid(ch_map->channels[ch])) +			continue; + +		if (s3c2410_chans[ch].in_use == 0) { +			printk("mapped channel %d to %d\n", channel, ch); +			break; +		} +	} + +	if (ch >= dma_channels) +		return NULL; + +	/* update our channel mapping */ + + found: +	dmach = &s3c2410_chans[ch]; +	dmach->map = ch_map; +	dmach->req_ch = channel; +	s3c_dma_chan_map[channel] = dmach; + +	/* select the channel */ + +	(dma_sel.select)(dmach, ch_map); + +	return dmach; +} + +static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch) +{ +	return 0; +} + +int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel) +{ +	struct s3c24xx_dma_map *nmap; +	size_t map_sz = sizeof(*nmap) * sel->map_size; +	int ptr; + +	nmap = kmemdup(sel->map, map_sz, GFP_KERNEL); +	if (nmap == NULL) +		return -ENOMEM; + +	memcpy(&dma_sel, sel, sizeof(*sel)); + +	dma_sel.map = nmap; + +	for (ptr = 0; ptr < sel->map_size; ptr++) +		s3c24xx_dma_check_entry(nmap+ptr, ptr); + +	return 0; +} + +int __init s3c24xx_dma_order_set(struct s3c24xx_dma_order *ord) +{ +	struct s3c24xx_dma_order *nord = dma_order; + +	if (nord == NULL) +		nord = kmalloc(sizeof(struct s3c24xx_dma_order), GFP_KERNEL); + +	if (nord == NULL) { +		printk(KERN_ERR "no memory to store dma channel order\n"); +		return -ENOMEM; +	} + +	dma_order = nord; +	memcpy(nord, ord, sizeof(struct s3c24xx_dma_order)); +	return 0; +} diff --git a/arch/arm/mach-s3c24xx/gta02.h b/arch/arm/mach-s3c24xx/gta02.h new file mode 100644 index 00000000000..9430a71e918 --- /dev/null +++ b/arch/arm/mach-s3c24xx/gta02.h @@ -0,0 +1,23 @@ +/* + * GTA02 header + * + * 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 __MACH_S3C24XX_GTA02_H +#define __MACH_S3C24XX_GTA02_H __FILE__ + +#include <mach/regs-gpio.h> + +#define GTA02_GPIO_AUX_LED	S3C2410_GPB(2) +#define GTA02_GPIO_USB_PULLUP	S3C2410_GPB(9) +#define GTA02_GPIO_AUX_KEY	S3C2410_GPF(6) +#define GTA02_GPIO_HOLD_KEY	S3C2410_GPF(7) +#define GTA02_GPIO_AMP_SHUT	S3C2410_GPJ(1)	/* v2 + v3 + v4 only */ +#define GTA02_GPIO_HP_IN	S3C2410_GPJ(2)	/* v2 + v3 + v4 only */ + +#define GTA02_IRQ_PCF50633	IRQ_EINT9 + +#endif /* __MACH_S3C24XX_GTA02_H */ diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c new file mode 100644 index 00000000000..b4d14b86436 --- /dev/null +++ b/arch/arm/mach-s3c24xx/h1940-bluetooth.c @@ -0,0 +1,147 @@ +/* + * arch/arm/mach-s3c2410/h1940-bluetooth.c + * Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org> + * + * This file is subject to the terms and conditions of the GNU General Public + * License.  See the file COPYING in the main directory of this archive for + * more details. + * + *	    S3C2410 bluetooth "driver" + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/string.h> +#include <linux/ctype.h> +#include <linux/leds.h> +#include <linux/gpio.h> +#include <linux/rfkill.h> + +#include <plat/gpio-cfg.h> +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> + +#include "h1940.h" + +#define DRV_NAME "h1940-bt" + +/* Bluetooth control */ +static void h1940bt_enable(int on) +{ +	if (on) { +		/* Power on the chip */ +		gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 1); +		/* Reset the chip */ +		mdelay(10); + +		gpio_set_value(S3C2410_GPH(1), 1); +		mdelay(10); +		gpio_set_value(S3C2410_GPH(1), 0); + +		h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL); +	} +	else { +		gpio_set_value(S3C2410_GPH(1), 1); +		mdelay(10); +		gpio_set_value(S3C2410_GPH(1), 0); +		mdelay(10); +		gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0); + +		h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL); +	} +} + +static int h1940bt_set_block(void *data, bool blocked) +{ +	h1940bt_enable(!blocked); +	return 0; +} + +static const struct rfkill_ops h1940bt_rfkill_ops = { +	.set_block = h1940bt_set_block, +}; + +static int h1940bt_probe(struct platform_device *pdev) +{ +	struct rfkill *rfk; +	int ret = 0; + +	ret = gpio_request(S3C2410_GPH(1), dev_name(&pdev->dev)); +	if (ret) { +		dev_err(&pdev->dev, "could not get GPH1\n"); +		return ret; +	} + +	ret = gpio_request(H1940_LATCH_BLUETOOTH_POWER, dev_name(&pdev->dev)); +	if (ret) { +		gpio_free(S3C2410_GPH(1)); +		dev_err(&pdev->dev, "could not get BT_POWER\n"); +		return ret; +	} + +	/* Configures BT serial port GPIOs */ +	s3c_gpio_cfgpin(S3C2410_GPH(0), S3C2410_GPH0_nCTS0); +	s3c_gpio_setpull(S3C2410_GPH(0), S3C_GPIO_PULL_NONE); +	s3c_gpio_cfgpin(S3C2410_GPH(1), S3C2410_GPIO_OUTPUT); +	s3c_gpio_setpull(S3C2410_GPH(1), S3C_GPIO_PULL_NONE); +	s3c_gpio_cfgpin(S3C2410_GPH(2), S3C2410_GPH2_TXD0); +	s3c_gpio_setpull(S3C2410_GPH(2), S3C_GPIO_PULL_NONE); +	s3c_gpio_cfgpin(S3C2410_GPH(3), S3C2410_GPH3_RXD0); +	s3c_gpio_setpull(S3C2410_GPH(3), S3C_GPIO_PULL_NONE); + +	rfk = rfkill_alloc(DRV_NAME, &pdev->dev, RFKILL_TYPE_BLUETOOTH, +			&h1940bt_rfkill_ops, NULL); +	if (!rfk) { +		ret = -ENOMEM; +		goto err_rfk_alloc; +	} + +	ret = rfkill_register(rfk); +	if (ret) +		goto err_rfkill; + +	platform_set_drvdata(pdev, rfk); + +	return 0; + +err_rfkill: +	rfkill_destroy(rfk); +err_rfk_alloc: +	return ret; +} + +static int h1940bt_remove(struct platform_device *pdev) +{ +	struct rfkill *rfk = platform_get_drvdata(pdev); + +	platform_set_drvdata(pdev, NULL); +	gpio_free(S3C2410_GPH(1)); + +	if (rfk) { +		rfkill_unregister(rfk); +		rfkill_destroy(rfk); +	} +	rfk = NULL; + +	h1940bt_enable(0); + +	return 0; +} + + +static struct platform_driver h1940bt_driver = { +	.driver		= { +		.name	= DRV_NAME, +	}, +	.probe		= h1940bt_probe, +	.remove		= h1940bt_remove, +}; + +module_platform_driver(h1940bt_driver); + +MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); +MODULE_DESCRIPTION("Driver for the iPAQ H1940 bluetooth chip"); +MODULE_LICENSE("GPL"); diff --git a/arch/arm/mach-s3c24xx/h1940.h b/arch/arm/mach-s3c24xx/h1940.h new file mode 100644 index 00000000000..2950cc46684 --- /dev/null +++ b/arch/arm/mach-s3c24xx/h1940.h @@ -0,0 +1,53 @@ +/* + * Copyright 2006 Ben Dooks <ben-linux@fluff.org> + * + * Copyright (c) 2005 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * iPAQ H1940 series definitions + * + * 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 __MACH_S3C24XX_H1940_H +#define __MACH_S3C24XX_H1940_H __FILE__ + +#define H1940_SUSPEND_CHECKSUM		(0x30003ff8) +#define H1940_SUSPEND_RESUMEAT		(0x30081000) +#define H1940_SUSPEND_CHECK		(0x30080000) + +extern void h1940_pm_return(void); +extern int h1940_led_blink_set(unsigned gpio, int state, +			       unsigned long *delay_on, +			       unsigned long *delay_off); + +#include <linux/gpio.h> + +#define H1940_LATCH_GPIO(x)		(S3C_GPIO_END + (x)) + +/* SD layer latch */ + +#define H1940_LATCH_LCD_P0		H1940_LATCH_GPIO(0) +#define H1940_LATCH_LCD_P1		H1940_LATCH_GPIO(1) +#define H1940_LATCH_LCD_P2		H1940_LATCH_GPIO(2) +#define H1940_LATCH_LCD_P3		H1940_LATCH_GPIO(3) +#define H1940_LATCH_MAX1698_nSHUTDOWN	H1940_LATCH_GPIO(4) +#define H1940_LATCH_LED_RED		H1940_LATCH_GPIO(5) +#define H1940_LATCH_SDQ7		H1940_LATCH_GPIO(6) +#define H1940_LATCH_USB_DP		H1940_LATCH_GPIO(7) + +/* CPU layer latch */ + +#define H1940_LATCH_UDA_POWER		H1940_LATCH_GPIO(8) +#define H1940_LATCH_AUDIO_POWER		H1940_LATCH_GPIO(9) +#define H1940_LATCH_SM803_ENABLE	H1940_LATCH_GPIO(10) +#define H1940_LATCH_LCD_P4		H1940_LATCH_GPIO(11) +#define H1940_LATCH_SD_POWER		H1940_LATCH_GPIO(12) +#define H1940_LATCH_BLUETOOTH_POWER	H1940_LATCH_GPIO(13) +#define H1940_LATCH_LED_GREEN		H1940_LATCH_GPIO(14) +#define H1940_LATCH_LED_FLASH		H1940_LATCH_GPIO(15) + +#endif /* __MACH_S3C24XX_H1940_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/dma.h b/arch/arm/mach-s3c24xx/include/mach/dma.h new file mode 100644 index 00000000000..b55da1d8cd8 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/dma.h @@ -0,0 +1,214 @@ +/* arch/arm/mach-s3c2410/include/mach/dma.h + * + * Copyright (C) 2003-2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C24XX DMA support + * + * 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 __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H __FILE__ + +#include <linux/device.h> + +#define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */ + +/* We use `virtual` dma channels to hide the fact we have only a limited + * number of DMA channels, and not of all of them (dependent on the device) + * can be attached to any DMA source. We therefore let the DMA core handle + * the allocation of hardware channels to clients. +*/ + +enum dma_ch { +	DMACH_XD0 = 0, +	DMACH_XD1, +	DMACH_SDI, +	DMACH_SPI0, +	DMACH_SPI1, +	DMACH_UART0, +	DMACH_UART1, +	DMACH_UART2, +	DMACH_TIMER, +	DMACH_I2S_IN, +	DMACH_I2S_OUT, +	DMACH_PCM_IN, +	DMACH_PCM_OUT, +	DMACH_MIC_IN, +	DMACH_USB_EP1, +	DMACH_USB_EP2, +	DMACH_USB_EP3, +	DMACH_USB_EP4, +	DMACH_UART0_SRC2,	/* s3c2412 second uart sources */ +	DMACH_UART1_SRC2, +	DMACH_UART2_SRC2, +	DMACH_UART3,		/* s3c2443 has extra uart */ +	DMACH_UART3_SRC2, +	DMACH_SPI0_TX,		/* s3c2443/2416/2450 hsspi0 */ +	DMACH_SPI0_RX,		/* s3c2443/2416/2450 hsspi0 */ +	DMACH_SPI1_TX,		/* s3c2443/2450 hsspi1 */ +	DMACH_SPI1_RX,		/* s3c2443/2450 hsspi1 */ +	DMACH_MAX,		/* the end entry */ +}; + +static inline bool samsung_dma_has_circular(void) +{ +	return false; +} + +static inline bool samsung_dma_is_dmadev(void) +{ +	return false; +} + +#include <plat/dma.h> + +#define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */ + +/* we have 4 dma channels */ +#if !defined(CONFIG_CPU_S3C2443) && !defined(CONFIG_CPU_S3C2416) +#define S3C_DMA_CHANNELS		(4) +#else +#define S3C_DMA_CHANNELS		(6) +#endif + +/* types */ + +enum s3c2410_dma_state { +	S3C2410_DMA_IDLE, +	S3C2410_DMA_RUNNING, +	S3C2410_DMA_PAUSED +}; + +/* enum s3c2410_dma_loadst + * + * This represents the state of the DMA engine, wrt to the loaded / running + * transfers. Since we don't have any way of knowing exactly the state of + * the DMA transfers, we need to know the state to make decisions on whether + * we can + * + * S3C2410_DMA_NONE + * + * There are no buffers loaded (the channel should be inactive) + * + * S3C2410_DMA_1LOADED + * + * There is one buffer loaded, however it has not been confirmed to be + * loaded by the DMA engine. This may be because the channel is not + * yet running, or the DMA driver decided that it was too costly to + * sit and wait for it to happen. + * + * S3C2410_DMA_1RUNNING + * + * The buffer has been confirmed running, and not finisged + * + * S3C2410_DMA_1LOADED_1RUNNING + * + * There is a buffer waiting to be loaded by the DMA engine, and one + * currently running. +*/ + +enum s3c2410_dma_loadst { +	S3C2410_DMALOAD_NONE, +	S3C2410_DMALOAD_1LOADED, +	S3C2410_DMALOAD_1RUNNING, +	S3C2410_DMALOAD_1LOADED_1RUNNING, +}; + + +/* flags */ + +#define S3C2410_DMAF_SLOW         (1<<0)   /* slow, so don't worry about +					    * waiting for reloads */ +#define S3C2410_DMAF_AUTOSTART    (1<<1)   /* auto-start if buffer queued */ + +#define S3C2410_DMAF_CIRCULAR	(1 << 2)	/* no circular dma support */ + +/* dma buffer */ + +struct s3c2410_dma_buf; + +/* s3c2410_dma_buf + * + * internally used buffer structure to describe a queued or running + * buffer. +*/ + +struct s3c2410_dma_buf { +	struct s3c2410_dma_buf	*next; +	int			 magic;		/* magic */ +	int			 size;		/* buffer size in bytes */ +	dma_addr_t		 data;		/* start of DMA data */ +	dma_addr_t		 ptr;		/* where the DMA got to [1] */ +	void			*id;		/* client's id */ +}; + +/* [1] is this updated for both recv/send modes? */ + +struct s3c2410_dma_stats { +	unsigned long		loads; +	unsigned long		timeout_longest; +	unsigned long		timeout_shortest; +	unsigned long		timeout_avg; +	unsigned long		timeout_failed; +}; + +struct s3c2410_dma_map; + +/* struct s3c2410_dma_chan + * + * full state information for each DMA channel +*/ + +struct s3c2410_dma_chan { +	/* channel state flags and information */ +	unsigned char		 number;      /* number of this dma channel */ +	unsigned char		 in_use;      /* channel allocated */ +	unsigned char		 irq_claimed; /* irq claimed for channel */ +	unsigned char		 irq_enabled; /* irq enabled for channel */ +	unsigned char		 xfer_unit;   /* size of an transfer */ + +	/* channel state */ + +	enum s3c2410_dma_state	 state; +	enum s3c2410_dma_loadst	 load_state; +	struct s3c2410_dma_client *client; + +	/* channel configuration */ +	enum dma_data_direction	 source; +	enum dma_ch		 req_ch; +	unsigned long		 dev_addr; +	unsigned long		 load_timeout; +	unsigned int		 flags;		/* channel flags */ + +	struct s3c24xx_dma_map	*map;		/* channel hw maps */ + +	/* channel's hardware position and configuration */ +	void __iomem		*regs;		/* channels registers */ +	void __iomem		*addr_reg;	/* data address register */ +	unsigned int		 irq;		/* channel irq */ +	unsigned long		 dcon;		/* default value of DCON */ + +	/* driver handles */ +	s3c2410_dma_cbfn_t	 callback_fn;	/* buffer done callback */ +	s3c2410_dma_opfn_t	 op_fn;		/* channel op callback */ + +	/* stats gathering */ +	struct s3c2410_dma_stats *stats; +	struct s3c2410_dma_stats  stats_store; + +	/* buffer list and information */ +	struct s3c2410_dma_buf	*curr;		/* current dma buffer */ +	struct s3c2410_dma_buf	*next;		/* next buffer to load */ +	struct s3c2410_dma_buf	*end;		/* end of queue */ + +	/* system device */ +	struct device	dev; +}; + +typedef unsigned long dma_device_t; + +#endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/fb.h b/arch/arm/mach-s3c24xx/include/mach/fb.h new file mode 100644 index 00000000000..a957bc8ed44 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/fb.h @@ -0,0 +1 @@ +#include <plat/fb-s3c2410.h> diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio-samsung.h b/arch/arm/mach-s3c24xx/include/mach/gpio-samsung.h new file mode 100644 index 00000000000..528fcdc4f63 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/gpio-samsung.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - GPIO lib support + * + * 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. +*/ + +/* some boards require extra gpio capacity to support external + * devices that need GPIO. + */ + +#ifndef GPIO_SAMSUNG_S3C24XX_H +#define GPIO_SAMSUNG_S3C24XX_H + +/* + * GPIO sizes for various SoCs: + * + *   2410 2412 2440 2443 2416 + *             2442 + *   ---- ---- ---- ---- ---- + * A  23   22   25   16   27 + * B  11   11   11   11   11 + * C  16   16   16   16   16 + * D  16   16   16   16   16 + * E  16   16   16   16   16 + * F  8    8    8    8    8 + * G  16   16   16   16   8 + * H  11   11   11   15   15 + * J  --   --   13   16   -- + * K  --   --   --   --   16 + * L  --   --   --   15   14 + * M  --   --   --   2    2 + */ + +/* GPIO bank sizes */ + +#define S3C2410_GPIO_A_NR	(32) +#define S3C2410_GPIO_B_NR	(32) +#define S3C2410_GPIO_C_NR	(32) +#define S3C2410_GPIO_D_NR	(32) +#define S3C2410_GPIO_E_NR	(32) +#define S3C2410_GPIO_F_NR	(32) +#define S3C2410_GPIO_G_NR	(32) +#define S3C2410_GPIO_H_NR	(32) +#define S3C2410_GPIO_J_NR	(32)	/* technically 16. */ +#define S3C2410_GPIO_K_NR	(32)	/* technically 16. */ +#define S3C2410_GPIO_L_NR	(32)	/* technically 15. */ +#define S3C2410_GPIO_M_NR	(32)	/* technically 2. */ + +#if CONFIG_S3C_GPIO_SPACE != 0 +#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment +#endif + +#define S3C2410_GPIO_NEXT(__gpio) \ +	((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0) + +#ifndef __ASSEMBLY__ + +enum s3c_gpio_number { +	S3C2410_GPIO_A_START = 0, +	S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A), +	S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B), +	S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C), +	S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D), +	S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E), +	S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F), +	S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G), +	S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H), +	S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J), +	S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K), +	S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L), +}; + +#endif /* __ASSEMBLY__ */ + +/* S3C2410 GPIO number definitions. */ + +#define S3C2410_GPA(_nr)	(S3C2410_GPIO_A_START + (_nr)) +#define S3C2410_GPB(_nr)	(S3C2410_GPIO_B_START + (_nr)) +#define S3C2410_GPC(_nr)	(S3C2410_GPIO_C_START + (_nr)) +#define S3C2410_GPD(_nr)	(S3C2410_GPIO_D_START + (_nr)) +#define S3C2410_GPE(_nr)	(S3C2410_GPIO_E_START + (_nr)) +#define S3C2410_GPF(_nr)	(S3C2410_GPIO_F_START + (_nr)) +#define S3C2410_GPG(_nr)	(S3C2410_GPIO_G_START + (_nr)) +#define S3C2410_GPH(_nr)	(S3C2410_GPIO_H_START + (_nr)) +#define S3C2410_GPJ(_nr)	(S3C2410_GPIO_J_START + (_nr)) +#define S3C2410_GPK(_nr)	(S3C2410_GPIO_K_START + (_nr)) +#define S3C2410_GPL(_nr)	(S3C2410_GPIO_L_START + (_nr)) +#define S3C2410_GPM(_nr)	(S3C2410_GPIO_M_START + (_nr)) + +#ifdef CONFIG_CPU_S3C244X +#define S3C_GPIO_END	(S3C2410_GPJ(0) + 32) +#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) +#define S3C_GPIO_END	(S3C2410_GPM(0) + 32) +#else +#define S3C_GPIO_END	(S3C2410_GPH(0) + 32) +#endif + +#endif /* GPIO_SAMSUNG_S3C24XX_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/hardware.h b/arch/arm/mach-s3c24xx/include/mach/hardware.h new file mode 100644 index 00000000000..dedd3837c19 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/hardware.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2003 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - hardware + * + * 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 __ASM_ARCH_HARDWARE_H +#define __ASM_ARCH_HARDWARE_H + +#ifndef __ASSEMBLY__ + +extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg); + +#endif /* __ASSEMBLY__ */ + +#include <asm/sizes.h> +#include <mach/map.h> + +#endif /* __ASM_ARCH_HARDWARE_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/io.h b/arch/arm/mach-s3c24xx/include/mach/io.h new file mode 100644 index 00000000000..5dd1db4e267 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/io.h @@ -0,0 +1,211 @@ +/* + * arch/arm/mach-s3c2410/include/mach/io.h + *  from arch/arm/mach-rpc/include/mach/io.h + * + * Copyright (C) 1997 Russell King + *	     (C) 2003 Simtec Electronics +*/ + +#ifndef __ASM_ARM_ARCH_IO_H +#define __ASM_ARM_ARCH_IO_H + +#include <mach/hardware.h> + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * We use two different types of addressing - PC style addresses, and ARM + * addresses.  PC style accesses the PC hardware with the normal PC IO + * addresses, eg 0x3f8 for serial#1.  ARM addresses are above A28 + * and are translated to the start of IO.  Note that all addresses are + * not shifted left! + */ + +#define __PORT_PCIO(x)	((x) < (1<<28)) + +#define PCIO_BASE	 (S3C24XX_VA_ISA_WORD) +#define PCIO_BASE_b	 (S3C24XX_VA_ISA_BYTE) +#define PCIO_BASE_w	 (S3C24XX_VA_ISA_WORD) +#define PCIO_BASE_l	 (S3C24XX_VA_ISA_WORD) +/* + * Dynamic IO functions - let the compiler + * optimize the expressions + */ + +#define DECLARE_DYN_OUT(sz,fnsuffix,instr) \ +static inline void __out##fnsuffix (unsigned int val, unsigned int port) \ +{ \ +	unsigned long temp;				      \ +	__asm__ __volatile__(				      \ +	"cmp	%2, #(1<<28)\n\t"			      \ +	"mov	%0, %2\n\t"				      \ +	"addcc	%0, %0, %3\n\t"				      \ +	"str" instr " %1, [%0, #0 ]	@ out" #fnsuffix      \ +	: "=&r" (temp)					      \ +	: "r" (val), "r" (port), "Ir" (PCIO_BASE_##fnsuffix)  \ +	: "cc");					      \ +} + + +#define DECLARE_DYN_IN(sz,fnsuffix,instr)				\ +static inline unsigned sz __in##fnsuffix (unsigned int port)		\ +{									\ +	unsigned long temp, value;					\ +	__asm__ __volatile__(						\ +	"cmp	%2, #(1<<28)\n\t"					\ +	"mov	%0, %2\n\t"						\ +	"addcc	%0, %0, %3\n\t"						\ +	"ldr" instr "	%1, [%0, #0 ]	@ in" #fnsuffix		\ +	: "=&r" (temp), "=r" (value)					\ +	: "r" (port), "Ir" (PCIO_BASE_##fnsuffix)	\ +	: "cc");							\ +	return (unsigned sz)value;					\ +} + +static inline void __iomem *__ioaddr (unsigned long port) +{ +	return __PORT_PCIO(port) ? (PCIO_BASE + port) : (void __iomem *)port; +} + +#define DECLARE_IO(sz,fnsuffix,instr)	\ +	DECLARE_DYN_IN(sz,fnsuffix,instr) \ +	DECLARE_DYN_OUT(sz,fnsuffix,instr) + +DECLARE_IO(char,b,"b") +DECLARE_IO(short,w,"h") +DECLARE_IO(int,l,"") + +#undef DECLARE_IO +#undef DECLARE_DYN_IN + +/* + * Constant address IO functions + * + * These have to be macros for the 'J' constraint to work - + * +/-4096 immediate operand. + */ +#define __outbc(value,port)						\ +({									\ +	if (__PORT_PCIO((port)))					\ +		__asm__ __volatile__(					\ +		"strb	%0, [%1, %2]	@ outbc"			\ +		: : "r" (value), "r" (PCIO_BASE), "Jr" ((port)));	\ +	else								\ +		__asm__ __volatile__(					\ +		"strb	%0, [%1, #0]	@ outbc"			\ +		: : "r" (value), "r" ((port)));				\ +}) + +#define __inbc(port)							\ +({									\ +	unsigned char result;						\ +	if (__PORT_PCIO((port)))					\ +		__asm__ __volatile__(					\ +		"ldrb	%0, [%1, %2]	@ inbc"				\ +		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));	\ +	else								\ +		__asm__ __volatile__(					\ +		"ldrb	%0, [%1, #0]	@ inbc"				\ +		: "=r" (result) : "r" ((port)));			\ +	result;								\ +}) + +#define __outwc(value,port)						\ +({									\ +	unsigned long v = value;					\ +	if (__PORT_PCIO((port))) {					\ +		if ((port) < 256 && (port) > -256)			\ +			__asm__ __volatile__(				\ +			"strh	%0, [%1, %2]	@ outwc"		\ +			: : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));	\ +		else if ((port) > 0)					\ +			__asm__ __volatile__(				\ +			"strh	%0, [%1, %2]	@ outwc"		\ +			: : "r" (v),					\ +			    "r" (PCIO_BASE + ((port) & ~0xff)),		\ +			     "Jr" (((port) & 0xff)));			\ +		else							\ +			__asm__ __volatile__(				\ +			"strh	%0, [%1, #0]	@ outwc"		\ +			: : "r" (v),					\ +			    "r" (PCIO_BASE + (port)));			\ +	} else								\ +		__asm__ __volatile__(					\ +		"strh	%0, [%1, #0]	@ outwc"			\ +		: : "r" (v), "r" ((port)));				\ +}) + +#define __inwc(port)							\ +({									\ +	unsigned short result;						\ +	if (__PORT_PCIO((port))) {					\ +		if ((port) < 256 && (port) > -256 )			\ +			__asm__ __volatile__(				\ +			"ldrh	%0, [%1, %2]	@ inwc"			\ +			: "=r" (result)					\ +			: "r" (PCIO_BASE),				\ +			  "Jr" ((port)));				\ +		else if ((port) > 0)					\ +			__asm__ __volatile__(				\ +			"ldrh	%0, [%1, %2]	@ inwc"			\ +			: "=r" (result)					\ +			: "r" (PCIO_BASE + ((port) & ~0xff)),		\ +			  "Jr" (((port) & 0xff)));			\ +		else							\ +			__asm__ __volatile__(				\ +			"ldrh	%0, [%1, #0]	@ inwc"			\ +			: "=r" (result)					\ +			: "r" (PCIO_BASE + ((port))));			\ +	} else								\ +		__asm__ __volatile__(					\ +		"ldrh	%0, [%1, #0]	@ inwc"				\ +		: "=r" (result) : "r" ((port)));			\ +	result;								\ +}) + +#define __outlc(value,port)						\ +({									\ +	unsigned long v = value;					\ +	if (__PORT_PCIO((port)))					\ +		__asm__ __volatile__(					\ +		"str	%0, [%1, %2]	@ outlc"			\ +		: : "r" (v), "r" (PCIO_BASE), "Jr" ((port)));	\ +	else								\ +		__asm__ __volatile__(					\ +		"str	%0, [%1, #0]	@ outlc"			\ +		: : "r" (v), "r" ((port)));		\ +}) + +#define __inlc(port)							\ +({									\ +	unsigned long result;						\ +	if (__PORT_PCIO((port)))					\ +		__asm__ __volatile__(					\ +		"ldr	%0, [%1, %2]	@ inlc"				\ +		: "=r" (result) : "r" (PCIO_BASE), "Jr" ((port)));	\ +	else								\ +		__asm__ __volatile__(					\ +		"ldr	%0, [%1, #0]	@ inlc"				\ +		: "=r" (result) : "r" ((port)));		\ +	result;								\ +}) + +#define __ioaddrc(port)	((__PORT_PCIO(port) ? PCIO_BASE + (port) : (void __iomem *)(port))) + +#define inb(p)		(__builtin_constant_p((p)) ? __inbc(p)	   : __inb(p)) +#define inw(p)		(__builtin_constant_p((p)) ? __inwc(p)	   : __inw(p)) +#define inl(p)		(__builtin_constant_p((p)) ? __inlc(p)	   : __inl(p)) +#define outb(v,p)	(__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p)) +#define outw(v,p)	(__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p)) +#define outl(v,p)	(__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p)) +#define __ioaddr(p)	(__builtin_constant_p((p)) ? __ioaddr(p)  : __ioaddrc(p)) + +#define insb(p,d,l)	__raw_readsb(__ioaddr(p),d,l) +#define insw(p,d,l)	__raw_readsw(__ioaddr(p),d,l) +#define insl(p,d,l)	__raw_readsl(__ioaddr(p),d,l) + +#define outsb(p,d,l)	__raw_writesb(__ioaddr(p),d,l) +#define outsw(p,d,l)	__raw_writesw(__ioaddr(p),d,l) +#define outsl(p,d,l)	__raw_writesl(__ioaddr(p),d,l) + +#endif diff --git a/arch/arm/mach-s3c24xx/include/mach/irqs.h b/arch/arm/mach-s3c24xx/include/mach/irqs.h new file mode 100644 index 00000000000..b6dd4cb5a2e --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/irqs.h @@ -0,0 +1,217 @@ +/* arch/arm/mach-s3c2410/include/mach/irqs.h + * + * Copyright (c) 2003-2005 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * 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 __ASM_ARCH_IRQS_H +#define __ASM_ARCH_IRQS_H __FILE__ + +/* we keep the first set of CPU IRQs out of the range of + * the ISA space, so that the PC104 has them to itself + * and we don't end up having to do horrible things to the + * standard ISA drivers.... + */ + +#define S3C2410_CPUIRQ_OFFSET	 (16) + +#define S3C2410_IRQ(x) ((x) + S3C2410_CPUIRQ_OFFSET) + +/* main cpu interrupts */ +#define IRQ_EINT0      S3C2410_IRQ(0)	    /* 16 */ +#define IRQ_EINT1      S3C2410_IRQ(1) +#define IRQ_EINT2      S3C2410_IRQ(2) +#define IRQ_EINT3      S3C2410_IRQ(3) +#define IRQ_EINT4t7    S3C2410_IRQ(4)	    /* 20 */ +#define IRQ_EINT8t23   S3C2410_IRQ(5) +#define IRQ_RESERVED6  S3C2410_IRQ(6)	    /* for s3c2410 */ +#define IRQ_CAM        S3C2410_IRQ(6)	    /* for s3c2440,s3c2443 */ +#define IRQ_BATT_FLT   S3C2410_IRQ(7) +#define IRQ_TICK       S3C2410_IRQ(8)	    /* 24 */ +#define IRQ_WDT	       S3C2410_IRQ(9)	    /* WDT/AC97 for s3c2443 */ +#define IRQ_TIMER0     S3C2410_IRQ(10) +#define IRQ_TIMER1     S3C2410_IRQ(11) +#define IRQ_TIMER2     S3C2410_IRQ(12) +#define IRQ_TIMER3     S3C2410_IRQ(13) +#define IRQ_TIMER4     S3C2410_IRQ(14) +#define IRQ_UART2      S3C2410_IRQ(15) +#define IRQ_LCD	       S3C2410_IRQ(16)	    /* 32 */ +#define IRQ_DMA0       S3C2410_IRQ(17)	    /* IRQ_DMA for s3c2443 */ +#define IRQ_DMA1       S3C2410_IRQ(18) +#define IRQ_DMA2       S3C2410_IRQ(19) +#define IRQ_DMA3       S3C2410_IRQ(20) +#define IRQ_SDI	       S3C2410_IRQ(21) +#define IRQ_SPI0       S3C2410_IRQ(22) +#define IRQ_UART1      S3C2410_IRQ(23) +#define IRQ_RESERVED24 S3C2410_IRQ(24)	    /* 40 */ +#define IRQ_NFCON      S3C2410_IRQ(24)	    /* for s3c2440 */ +#define IRQ_USBD       S3C2410_IRQ(25) +#define IRQ_USBH       S3C2410_IRQ(26) +#define IRQ_IIC	       S3C2410_IRQ(27) +#define IRQ_UART0      S3C2410_IRQ(28)	    /* 44 */ +#define IRQ_SPI1       S3C2410_IRQ(29) +#define IRQ_RTC	       S3C2410_IRQ(30) +#define IRQ_ADCPARENT  S3C2410_IRQ(31) + +/* interrupts generated from the external interrupts sources */ +#define IRQ_EINT0_2412 S3C2410_IRQ(32) +#define IRQ_EINT1_2412 S3C2410_IRQ(33) +#define IRQ_EINT2_2412 S3C2410_IRQ(34) +#define IRQ_EINT3_2412 S3C2410_IRQ(35) +#define IRQ_EINT4      S3C2410_IRQ(36)	   /* 52 */ +#define IRQ_EINT5      S3C2410_IRQ(37) +#define IRQ_EINT6      S3C2410_IRQ(38) +#define IRQ_EINT7      S3C2410_IRQ(39) +#define IRQ_EINT8      S3C2410_IRQ(40) +#define IRQ_EINT9      S3C2410_IRQ(41) +#define IRQ_EINT10     S3C2410_IRQ(42) +#define IRQ_EINT11     S3C2410_IRQ(43) +#define IRQ_EINT12     S3C2410_IRQ(44) +#define IRQ_EINT13     S3C2410_IRQ(45) +#define IRQ_EINT14     S3C2410_IRQ(46) +#define IRQ_EINT15     S3C2410_IRQ(47) +#define IRQ_EINT16     S3C2410_IRQ(48) +#define IRQ_EINT17     S3C2410_IRQ(49) +#define IRQ_EINT18     S3C2410_IRQ(50) +#define IRQ_EINT19     S3C2410_IRQ(51) +#define IRQ_EINT20     S3C2410_IRQ(52)	   /* 68 */ +#define IRQ_EINT21     S3C2410_IRQ(53) +#define IRQ_EINT22     S3C2410_IRQ(54) +#define IRQ_EINT23     S3C2410_IRQ(55) + +#define IRQ_EINT_BIT(x)	((x) - IRQ_EINT4 + 4) +#define IRQ_EINT(x)    (((x) >= 4) ? (IRQ_EINT4 + (x) - 4) : (IRQ_EINT0 + (x))) + +#define IRQ_LCD_FIFO   S3C2410_IRQ(56) +#define IRQ_LCD_FRAME  S3C2410_IRQ(57) + +/* IRQs for the interal UARTs, and ADC + * these need to be ordered in number of appearance in the + * SUBSRC mask register +*/ + +#define S3C2410_IRQSUB(x)	S3C2410_IRQ((x)+58) + +#define IRQ_S3CUART_RX0		S3C2410_IRQSUB(0)	/* 74 */ +#define IRQ_S3CUART_TX0		S3C2410_IRQSUB(1) +#define IRQ_S3CUART_ERR0	S3C2410_IRQSUB(2) + +#define IRQ_S3CUART_RX1		S3C2410_IRQSUB(3)	/* 77 */ +#define IRQ_S3CUART_TX1		S3C2410_IRQSUB(4) +#define IRQ_S3CUART_ERR1	S3C2410_IRQSUB(5) + +#define IRQ_S3CUART_RX2		S3C2410_IRQSUB(6)	/* 80 */ +#define IRQ_S3CUART_TX2		S3C2410_IRQSUB(7) +#define IRQ_S3CUART_ERR2	S3C2410_IRQSUB(8) + +#define IRQ_TC			S3C2410_IRQSUB(9) +#define IRQ_ADC			S3C2410_IRQSUB(10) + +/* extra irqs for s3c2412 */ + +#define IRQ_S3C2412_CFSDI	S3C2410_IRQ(21) + +#define IRQ_S3C2412_SDI		S3C2410_IRQSUB(13) +#define IRQ_S3C2412_CF		S3C2410_IRQSUB(14) + + +#define IRQ_S3C2416_EINT8t15	S3C2410_IRQ(5) +#define IRQ_S3C2416_DMA		S3C2410_IRQ(17) +#define IRQ_S3C2416_UART3	S3C2410_IRQ(18) +#define IRQ_S3C2416_SDI1	S3C2410_IRQ(20) +#define IRQ_S3C2416_SDI0	S3C2410_IRQ(21) + +#define IRQ_S3C2416_LCD2	S3C2410_IRQSUB(15) +#define IRQ_S3C2416_LCD3	S3C2410_IRQSUB(16) +#define IRQ_S3C2416_LCD4	S3C2410_IRQSUB(17) +#define IRQ_S3C2416_DMA0	S3C2410_IRQSUB(18) +#define IRQ_S3C2416_DMA1	S3C2410_IRQSUB(19) +#define IRQ_S3C2416_DMA2	S3C2410_IRQSUB(20) +#define IRQ_S3C2416_DMA3	S3C2410_IRQSUB(21) +#define IRQ_S3C2416_DMA4	S3C2410_IRQSUB(22) +#define IRQ_S3C2416_DMA5	S3C2410_IRQSUB(23) +#define IRQ_S32416_WDT		S3C2410_IRQSUB(27) +#define IRQ_S32416_AC97		S3C2410_IRQSUB(28) + +/* second interrupt-register of s3c2416/s3c2450 */ + +#define S3C2416_IRQ(x)		S3C2410_IRQ((x) + 58 + 29) +#define IRQ_S3C2416_2D		S3C2416_IRQ(0) +#define IRQ_S3C2416_IIC1	S3C2416_IRQ(1) +#define IRQ_S3C2416_RESERVED2	S3C2416_IRQ(2) +#define IRQ_S3C2416_RESERVED3	S3C2416_IRQ(3) +#define IRQ_S3C2416_PCM0	S3C2416_IRQ(4) +#define IRQ_S3C2416_PCM1	S3C2416_IRQ(5) +#define IRQ_S3C2416_I2S0	S3C2416_IRQ(6) +#define IRQ_S3C2416_I2S1	S3C2416_IRQ(7) + +/* extra irqs for s3c2440 */ + +#define IRQ_S3C2440_CAM_C	S3C2410_IRQSUB(11)	/* S3C2443 too */ +#define IRQ_S3C2440_CAM_P	S3C2410_IRQSUB(12)	/* S3C2443 too */ +#define IRQ_S3C2440_WDT		S3C2410_IRQSUB(13) +#define IRQ_S3C2440_AC97	S3C2410_IRQSUB(14) + +/* irqs for s3c2443 */ + +#define IRQ_S3C2443_DMA		S3C2410_IRQ(17)		/* IRQ_DMA1 */ +#define IRQ_S3C2443_UART3	S3C2410_IRQ(18)		/* IRQ_DMA2 */ +#define IRQ_S3C2443_CFCON	S3C2410_IRQ(19)		/* IRQ_DMA3 */ +#define IRQ_S3C2443_HSMMC	S3C2410_IRQ(20)		/* IRQ_SDI */ +#define IRQ_S3C2443_NAND	S3C2410_IRQ(24)		/* reserved */ + +#define IRQ_S3C2416_HSMMC0	S3C2410_IRQ(21)		/* S3C2416/S3C2450 */ + +#define IRQ_HSMMC0		IRQ_S3C2416_HSMMC0 +#define IRQ_HSMMC1		IRQ_S3C2443_HSMMC + +#define IRQ_S3C2443_LCD1	S3C2410_IRQSUB(14) +#define IRQ_S3C2443_LCD2	S3C2410_IRQSUB(15) +#define IRQ_S3C2443_LCD3	S3C2410_IRQSUB(16) +#define IRQ_S3C2443_LCD4	S3C2410_IRQSUB(17) + +#define IRQ_S3C2443_DMA0	S3C2410_IRQSUB(18) +#define IRQ_S3C2443_DMA1	S3C2410_IRQSUB(19) +#define IRQ_S3C2443_DMA2	S3C2410_IRQSUB(20) +#define IRQ_S3C2443_DMA3	S3C2410_IRQSUB(21) +#define IRQ_S3C2443_DMA4	S3C2410_IRQSUB(22) +#define IRQ_S3C2443_DMA5	S3C2410_IRQSUB(23) + +/* UART3 */ +#define IRQ_S3C2443_RX3		S3C2410_IRQSUB(24) +#define IRQ_S3C2443_TX3		S3C2410_IRQSUB(25) +#define IRQ_S3C2443_ERR3	S3C2410_IRQSUB(26) + +#define IRQ_S3C2443_WDT		S3C2410_IRQSUB(27) +#define IRQ_S3C2443_AC97	S3C2410_IRQSUB(28) + +#if defined(CONFIG_CPU_S3C2416) +#define NR_IRQS (IRQ_S3C2416_I2S1 + 1) +#else +#define NR_IRQS (IRQ_S3C2443_AC97 + 1) +#endif + +/* compatibility define. */ +#define IRQ_UART3		IRQ_S3C2443_UART3 +#define IRQ_S3CUART_RX3		IRQ_S3C2443_RX3 +#define IRQ_S3CUART_TX3		IRQ_S3C2443_TX3 +#define IRQ_S3CUART_ERR3	IRQ_S3C2443_ERR3 + +#define IRQ_LCD_VSYNC		IRQ_S3C2443_LCD3 +#define IRQ_LCD_SYSTEM		IRQ_S3C2443_LCD2 + +#ifdef CONFIG_CPU_S3C2440 +#define IRQ_S3C244X_AC97 IRQ_S3C2440_AC97 +#else +#define IRQ_S3C244X_AC97 IRQ_S3C2443_AC97 +#endif + +/* Our FIQs are routable from IRQ_EINT0 to IRQ_ADCPARENT */ +#define FIQ_START		IRQ_EINT0 + +#endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/map.h b/arch/arm/mach-s3c24xx/include/mach/map.h new file mode 100644 index 00000000000..444793f0f5f --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/map.h @@ -0,0 +1,172 @@ +/* arch/arm/mach-s3c2410/include/mach/map.h + * + * Copyright (c) 2003 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - Memory map definitions + * + * 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 __ASM_ARCH_MAP_H +#define __ASM_ARCH_MAP_H + +#include <plat/map-base.h> + +/* + * S3C2410 UART offset is 0x4000 but the other SoCs are 0x400. + * So need to define it, and here is to avoid redefinition warning. + */ +#define S3C_UART_OFFSET		(0x4000) + +#include <plat/map-s3c.h> + +/* + * interrupt controller is the first thing we put in, to make + * the assembly code for the irq detection easier + */ +#define S3C2410_PA_IRQ		(0x4A000000) +#define S3C24XX_SZ_IRQ		SZ_1M + +/* memory controller registers */ +#define S3C2410_PA_MEMCTRL	(0x48000000) +#define S3C24XX_SZ_MEMCTRL	SZ_1M + +/* UARTs */ +#define S3C_VA_UARTx(uart)	(S3C_VA_UART + ((uart * S3C_UART_OFFSET))) + +/* Timers */ +#define S3C2410_PA_TIMER	(0x51000000) +#define S3C24XX_SZ_TIMER	SZ_1M + +/* Clock and Power management */ +#define S3C24XX_SZ_CLKPWR	SZ_1M + +/* USB Device port */ +#define S3C2410_PA_USBDEV	(0x52000000) +#define S3C24XX_SZ_USBDEV	SZ_1M + +/* Watchdog */ +#define S3C2410_PA_WATCHDOG	(0x53000000) +#define S3C24XX_SZ_WATCHDOG	SZ_1M + +/* Standard size definitions for peripheral blocks. */ + +#define S3C24XX_SZ_UART		SZ_1M +#define S3C24XX_SZ_IIS		SZ_1M +#define S3C24XX_SZ_ADC		SZ_1M +#define S3C24XX_SZ_SPI		SZ_1M +#define S3C24XX_SZ_SDI		SZ_1M +#define S3C24XX_SZ_NAND		SZ_1M +#define S3C24XX_SZ_GPIO		SZ_1M + +/* USB host controller */ +#define S3C2410_PA_USBHOST (0x49000000) + +/* S3C2416/S3C2443/S3C2450 High-Speed USB Gadget */ +#define S3C2416_PA_HSUDC	(0x49800000) +#define S3C2416_SZ_HSUDC	(SZ_4K) + +/* DMA controller */ +#define S3C2410_PA_DMA	   (0x4B000000) +#define S3C24XX_SZ_DMA	   SZ_1M + +/* Clock and Power management */ +#define S3C2410_PA_CLKPWR  (0x4C000000) + +/* LCD controller */ +#define S3C2410_PA_LCD	   (0x4D000000) +#define S3C24XX_SZ_LCD	   SZ_1M + +/* NAND flash controller */ +#define S3C2410_PA_NAND	   (0x4E000000) + +/* IIC hardware controller */ +#define S3C2410_PA_IIC	   (0x54000000) + +/* IIS controller */ +#define S3C2410_PA_IIS	   (0x55000000) + +/* RTC */ +#define S3C2410_PA_RTC	   (0x57000000) +#define S3C24XX_SZ_RTC	   SZ_1M + +/* ADC */ +#define S3C2410_PA_ADC	   (0x58000000) + +/* SPI */ +#define S3C2410_PA_SPI	   (0x59000000) +#define S3C2443_PA_SPI0		(0x52000000) +#define S3C2443_PA_SPI1		S3C2410_PA_SPI + +/* SDI */ +#define S3C2410_PA_SDI	   (0x5A000000) + +/* CAMIF */ +#define S3C2440_PA_CAMIF   (0x4F000000) +#define S3C2440_SZ_CAMIF   SZ_1M + +/* AC97 */ + +#define S3C2440_PA_AC97	   (0x5B000000) +#define S3C2440_SZ_AC97	   SZ_1M + +/* S3C2443/S3C2416 High-speed SD/MMC */ +#define S3C2443_PA_HSMMC   (0x4A800000) +#define S3C2416_PA_HSMMC0  (0x4AC00000) + +#define	S3C2443_PA_FB	(0x4C800000) + +/* S3C2412 memory and IO controls */ +#define S3C2412_PA_SSMC	(0x4F000000) + +#define S3C2412_PA_EBI	(0x48800000) + +/* physical addresses of all the chip-select areas */ + +#define S3C2410_CS0 (0x00000000) +#define S3C2410_CS1 (0x08000000) +#define S3C2410_CS2 (0x10000000) +#define S3C2410_CS3 (0x18000000) +#define S3C2410_CS4 (0x20000000) +#define S3C2410_CS5 (0x28000000) +#define S3C2410_CS6 (0x30000000) +#define S3C2410_CS7 (0x38000000) + +#define S3C2410_SDRAM_PA    (S3C2410_CS6) + +/* Use a single interface for common resources between S3C24XX cpus */ + +#define S3C24XX_PA_IRQ      S3C2410_PA_IRQ +#define S3C24XX_PA_MEMCTRL  S3C2410_PA_MEMCTRL +#define S3C24XX_PA_DMA      S3C2410_PA_DMA +#define S3C24XX_PA_CLKPWR   S3C2410_PA_CLKPWR +#define S3C24XX_PA_LCD      S3C2410_PA_LCD +#define S3C24XX_PA_TIMER    S3C2410_PA_TIMER +#define S3C24XX_PA_USBDEV   S3C2410_PA_USBDEV +#define S3C24XX_PA_WATCHDOG S3C2410_PA_WATCHDOG +#define S3C24XX_PA_IIS      S3C2410_PA_IIS +#define S3C24XX_PA_RTC      S3C2410_PA_RTC +#define S3C24XX_PA_ADC      S3C2410_PA_ADC +#define S3C24XX_PA_SPI      S3C2410_PA_SPI +#define S3C24XX_PA_SPI1		(S3C2410_PA_SPI + S3C2410_SPI1) +#define S3C24XX_PA_SDI      S3C2410_PA_SDI +#define S3C24XX_PA_NAND	    S3C2410_PA_NAND + +#define S3C_PA_FB	    S3C2443_PA_FB +#define S3C_PA_IIC          S3C2410_PA_IIC +#define S3C_PA_UART	    S3C24XX_PA_UART +#define S3C_PA_USBHOST	S3C2410_PA_USBHOST +#define S3C_PA_HSMMC0	    S3C2416_PA_HSMMC0 +#define S3C_PA_HSMMC1	    S3C2443_PA_HSMMC +#define S3C_PA_WDT	    S3C2410_PA_WATCHDOG +#define S3C_PA_NAND	    S3C24XX_PA_NAND + +#define S3C_PA_SPI0		S3C2443_PA_SPI0 +#define S3C_PA_SPI1		S3C2443_PA_SPI1 + +#define SAMSUNG_PA_TIMER	S3C2410_PA_TIMER + +#endif /* __ASM_ARCH_MAP_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/pm-core.h b/arch/arm/mach-s3c24xx/include/mach/pm-core.h new file mode 100644 index 00000000000..2eef7e6f767 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/pm-core.h @@ -0,0 +1,67 @@ +/* linux/arch/arm/mach-s3c2410/include/pm-core.h + * + * Copyright 2008 Simtec Electronics + *      Ben Dooks <ben@simtec.co.uk> + *      http://armlinux.simtec.co.uk/ + * + * S3C24xx - PM core support for arch/arm/plat-s3c/pm.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. + */ + +static inline void s3c_pm_debug_init_uart(void) +{ +	unsigned long tmp = __raw_readl(S3C2410_CLKCON); + +	/* re-start uart clocks */ +	tmp |= S3C2410_CLKCON_UART0; +	tmp |= S3C2410_CLKCON_UART1; +	tmp |= S3C2410_CLKCON_UART2; + +	__raw_writel(tmp, S3C2410_CLKCON); +	udelay(10); +} + +static inline void s3c_pm_arch_prepare_irqs(void) +{ +	__raw_writel(s3c_irqwake_intmask, S3C2410_INTMSK); +	__raw_writel(s3c_irqwake_eintmask, S3C2410_EINTMASK); + +	/* ack any outstanding external interrupts before we go to sleep */ + +	__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND); +	__raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND); +	__raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND); + +} + +static inline void s3c_pm_arch_stop_clocks(void) +{ +	__raw_writel(0x00, S3C2410_CLKCON);  /* turn off clocks over sleep */ +} + +static void s3c_pm_show_resume_irqs(int start, unsigned long which, +				    unsigned long mask); + +static inline void s3c_pm_arch_show_resume_irqs(void) +{ +	S3C_PMDBG("post sleep: IRQs 0x%08x, 0x%08x\n", +		  __raw_readl(S3C2410_SRCPND), +		  __raw_readl(S3C2410_EINTPEND)); + +	s3c_pm_show_resume_irqs(IRQ_EINT0, __raw_readl(S3C2410_SRCPND), +				s3c_irqwake_intmask); + +	s3c_pm_show_resume_irqs(IRQ_EINT4-4, __raw_readl(S3C2410_EINTPEND), +				s3c_irqwake_eintmask); +} + +static inline void s3c_pm_arch_update_uart(void __iomem *regs, +					   struct pm_uart_save *save) +{ +} + +static inline void s3c_pm_restored_gpios(void) { } +static inline void samsung_pm_saved_gpios(void) { } diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-clock.h new file mode 100644 index 00000000000..3db6c10de02 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/regs-clock.h @@ -0,0 +1,148 @@ +/* arch/arm/mach-s3c2410/include/mach/regs-clock.h + * + * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk> + *	http://armlinux.simtec.co.uk/ + * + * 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. + * + * S3C2410 clock register definitions +*/ + +#ifndef __ASM_ARM_REGS_CLOCK +#define __ASM_ARM_REGS_CLOCK + +#define S3C2410_CLKREG(x) ((x) + S3C24XX_VA_CLKPWR) + +#define S3C2410_PLLVAL(_m,_p,_s) ((_m) << 12 | ((_p) << 4) | ((_s))) + +#define S3C2410_LOCKTIME    S3C2410_CLKREG(0x00) +#define S3C2410_MPLLCON	    S3C2410_CLKREG(0x04) +#define S3C2410_UPLLCON	    S3C2410_CLKREG(0x08) +#define S3C2410_CLKCON	    S3C2410_CLKREG(0x0C) +#define S3C2410_CLKSLOW	    S3C2410_CLKREG(0x10) +#define S3C2410_CLKDIVN	    S3C2410_CLKREG(0x14) + +#define S3C2410_CLKCON_IDLE	     (1<<2) +#define S3C2410_CLKCON_POWER	     (1<<3) +#define S3C2410_CLKCON_NAND	     (1<<4) +#define S3C2410_CLKCON_LCDC	     (1<<5) +#define S3C2410_CLKCON_USBH	     (1<<6) +#define S3C2410_CLKCON_USBD	     (1<<7) +#define S3C2410_CLKCON_PWMT	     (1<<8) +#define S3C2410_CLKCON_SDI	     (1<<9) +#define S3C2410_CLKCON_UART0	     (1<<10) +#define S3C2410_CLKCON_UART1	     (1<<11) +#define S3C2410_CLKCON_UART2	     (1<<12) +#define S3C2410_CLKCON_GPIO	     (1<<13) +#define S3C2410_CLKCON_RTC	     (1<<14) +#define S3C2410_CLKCON_ADC	     (1<<15) +#define S3C2410_CLKCON_IIC	     (1<<16) +#define S3C2410_CLKCON_IIS	     (1<<17) +#define S3C2410_CLKCON_SPI	     (1<<18) + +#define S3C2410_CLKDIVN_PDIVN	     (1<<0) +#define S3C2410_CLKDIVN_HDIVN	     (1<<1) + +#define S3C2410_CLKSLOW_UCLK_OFF	(1<<7) +#define S3C2410_CLKSLOW_MPLL_OFF	(1<<5) +#define S3C2410_CLKSLOW_SLOW		(1<<4) +#define S3C2410_CLKSLOW_SLOWVAL(x)	(x) +#define S3C2410_CLKSLOW_GET_SLOWVAL(x)	((x) & 7) + +#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) + +/* extra registers */ +#define S3C2440_CAMDIVN	    S3C2410_CLKREG(0x18) + +#define S3C2440_CLKCON_CAMERA        (1<<19) +#define S3C2440_CLKCON_AC97          (1<<20) + +#define S3C2440_CLKDIVN_PDIVN	     (1<<0) +#define S3C2440_CLKDIVN_HDIVN_MASK   (3<<1) +#define S3C2440_CLKDIVN_HDIVN_1      (0<<1) +#define S3C2440_CLKDIVN_HDIVN_2      (1<<1) +#define S3C2440_CLKDIVN_HDIVN_4_8    (2<<1) +#define S3C2440_CLKDIVN_HDIVN_3_6    (3<<1) +#define S3C2440_CLKDIVN_UCLK         (1<<3) + +#define S3C2440_CAMDIVN_CAMCLK_MASK  (0xf<<0) +#define S3C2440_CAMDIVN_CAMCLK_SEL   (1<<4) +#define S3C2440_CAMDIVN_HCLK3_HALF   (1<<8) +#define S3C2440_CAMDIVN_HCLK4_HALF   (1<<9) +#define S3C2440_CAMDIVN_DVSEN        (1<<12) + +#define S3C2442_CAMDIVN_CAMCLK_DIV3  (1<<5) + +#endif /* CONFIG_CPU_S3C2440 or CONFIG_CPU_S3C2442 */ + +#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413) + +#define S3C2412_OSCSET		S3C2410_CLKREG(0x18) +#define S3C2412_CLKSRC		S3C2410_CLKREG(0x1C) + +#define S3C2412_PLLCON_OFF		(1<<20) + +#define S3C2412_CLKDIVN_PDIVN		(1<<2) +#define S3C2412_CLKDIVN_HDIVN_MASK	(3<<0) +#define S3C2412_CLKDIVN_ARMDIVN		(1<<3) +#define S3C2412_CLKDIVN_DVSEN		(1<<4) +#define S3C2412_CLKDIVN_HALFHCLK	(1<<5) +#define S3C2412_CLKDIVN_USB48DIV	(1<<6) +#define S3C2412_CLKDIVN_UARTDIV_MASK	(15<<8) +#define S3C2412_CLKDIVN_UARTDIV_SHIFT	(8) +#define S3C2412_CLKDIVN_I2SDIV_MASK	(15<<12) +#define S3C2412_CLKDIVN_I2SDIV_SHIFT	(12) +#define S3C2412_CLKDIVN_CAMDIV_MASK	(15<<16) +#define S3C2412_CLKDIVN_CAMDIV_SHIFT	(16) + +#define S3C2412_CLKCON_WDT		(1<<28) +#define S3C2412_CLKCON_SPI		(1<<27) +#define S3C2412_CLKCON_IIS		(1<<26) +#define S3C2412_CLKCON_IIC		(1<<25) +#define S3C2412_CLKCON_ADC		(1<<24) +#define S3C2412_CLKCON_RTC		(1<<23) +#define S3C2412_CLKCON_GPIO		(1<<22) +#define S3C2412_CLKCON_UART2		(1<<21) +#define S3C2412_CLKCON_UART1		(1<<20) +#define S3C2412_CLKCON_UART0		(1<<19) +#define S3C2412_CLKCON_SDI		(1<<18) +#define S3C2412_CLKCON_PWMT		(1<<17) +#define S3C2412_CLKCON_USBD		(1<<16) +#define S3C2412_CLKCON_CAMCLK		(1<<15) +#define S3C2412_CLKCON_UARTCLK		(1<<14) +/* missing 13 */ +#define S3C2412_CLKCON_USB_HOST48	(1<<12) +#define S3C2412_CLKCON_USB_DEV48	(1<<11) +#define S3C2412_CLKCON_HCLKdiv2		(1<<10) +#define S3C2412_CLKCON_HCLKx2		(1<<9) +#define S3C2412_CLKCON_SDRAM		(1<<8) +/* missing 7 */ +#define S3C2412_CLKCON_USBH		S3C2410_CLKCON_USBH +#define S3C2412_CLKCON_LCDC		S3C2410_CLKCON_LCDC +#define S3C2412_CLKCON_NAND		S3C2410_CLKCON_NAND +#define S3C2412_CLKCON_DMA3		(1<<3) +#define S3C2412_CLKCON_DMA2		(1<<2) +#define S3C2412_CLKCON_DMA1		(1<<1) +#define S3C2412_CLKCON_DMA0		(1<<0) + +/* clock sourec controls */ + +#define S3C2412_CLKSRC_EXTCLKDIV_MASK		(7 << 0) +#define S3C2412_CLKSRC_EXTCLKDIV_SHIFT		(0) +#define S3C2412_CLKSRC_MDIVCLK_EXTCLKDIV	(1<<3) +#define S3C2412_CLKSRC_MSYSCLK_MPLL		(1<<4) +#define S3C2412_CLKSRC_USYSCLK_UPLL		(1<<5) +#define S3C2412_CLKSRC_UARTCLK_MPLL		(1<<8) +#define S3C2412_CLKSRC_I2SCLK_MPLL		(1<<9) +#define S3C2412_CLKSRC_USBCLK_HCLK		(1<<10) +#define S3C2412_CLKSRC_CAMCLK_HCLK		(1<<11) +#define S3C2412_CLKSRC_UREFCLK_EXTCLK	(1<<12) +#define S3C2412_CLKSRC_EREFCLK_EXTCLK	(1<<14) + +#endif /* CONFIG_CPU_S3C2412 | CONFIG_CPU_S3C2413 */ + +#define S3C2416_CLKDIV2		S3C2410_CLKREG(0x28) + +#endif /* __ASM_ARM_REGS_CLOCK */ diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h new file mode 100644 index 00000000000..c6583cfa583 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/regs-gpio.h @@ -0,0 +1,610 @@ +/* arch/arm/mach-s3c2410/include/mach/regs-gpio.h + * + * Copyright (c) 2003-2004 Simtec Electronics <linux@simtec.co.uk> + *	http://www.simtec.co.uk/products/SWLINUX/ + * + * 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. + * + * S3C2410 GPIO register definitions +*/ + + +#ifndef __ASM_ARCH_REGS_GPIO_H +#define __ASM_ARCH_REGS_GPIO_H + +#define S3C24XX_MISCCR		S3C24XX_GPIOREG2(0x80) + +/* general configuration options */ + +#define S3C2410_GPIO_LEAVE   (0xFFFFFFFF) +#define S3C2410_GPIO_INPUT   (0xFFFFFFF0)	/* not available on A */ +#define S3C2410_GPIO_OUTPUT  (0xFFFFFFF1) +#define S3C2410_GPIO_IRQ     (0xFFFFFFF2)	/* not available for all */ +#define S3C2410_GPIO_SFN2    (0xFFFFFFF2)	/* bank A => addr/cs/nand */ +#define S3C2410_GPIO_SFN3    (0xFFFFFFF3)	/* not available on A */ + +/* register address for the GPIO registers. + * S3C24XX_GPIOREG2 is for the second set of registers in the + * GPIO which move between s3c2410 and s3c2412 type systems */ + +#define S3C2410_GPIOREG(x) ((x) + S3C24XX_VA_GPIO) +#define S3C24XX_GPIOREG2(x) ((x) + S3C24XX_VA_GPIO2) + + +/* configure GPIO ports A..G */ + +/* port A - S3C2410: 22bits, zero in bit X makes pin X output + * 1 makes port special function, this is default +*/ +#define S3C2410_GPACON	   S3C2410_GPIOREG(0x00) +#define S3C2410_GPADAT	   S3C2410_GPIOREG(0x04) + +#define S3C2410_GPA0_ADDR0   (1<<0) +#define S3C2410_GPA1_ADDR16  (1<<1) +#define S3C2410_GPA2_ADDR17  (1<<2) +#define S3C2410_GPA3_ADDR18  (1<<3) +#define S3C2410_GPA4_ADDR19  (1<<4) +#define S3C2410_GPA5_ADDR20  (1<<5) +#define S3C2410_GPA6_ADDR21  (1<<6) +#define S3C2410_GPA7_ADDR22  (1<<7) +#define S3C2410_GPA8_ADDR23  (1<<8) +#define S3C2410_GPA9_ADDR24  (1<<9) +#define S3C2410_GPA10_ADDR25 (1<<10) +#define S3C2410_GPA11_ADDR26 (1<<11) +#define S3C2410_GPA12_nGCS1  (1<<12) +#define S3C2410_GPA13_nGCS2  (1<<13) +#define S3C2410_GPA14_nGCS3  (1<<14) +#define S3C2410_GPA15_nGCS4  (1<<15) +#define S3C2410_GPA16_nGCS5  (1<<16) +#define S3C2410_GPA17_CLE    (1<<17) +#define S3C2410_GPA18_ALE    (1<<18) +#define S3C2410_GPA19_nFWE   (1<<19) +#define S3C2410_GPA20_nFRE   (1<<20) +#define S3C2410_GPA21_nRSTOUT (1<<21) +#define S3C2410_GPA22_nFCE   (1<<22) + +/* 0x08 and 0x0c are reserved on S3C2410 */ + +/* S3C2410: + * GPB is 10 IO pins, each configured by 2 bits each in GPBCON. + *   00 = input, 01 = output, 10=special function, 11=reserved + + * bit 0,1 = pin 0, 2,3= pin 1... + * + * CPBUP = pull up resistor control, 1=disabled, 0=enabled +*/ + +#define S3C2410_GPBCON	   S3C2410_GPIOREG(0x10) +#define S3C2410_GPBDAT	   S3C2410_GPIOREG(0x14) +#define S3C2410_GPBUP	   S3C2410_GPIOREG(0x18) + +/* no i/o pin in port b can have value 3 (unless it is a s3c2443) ! */ + +#define S3C2410_GPB0_TOUT0   (0x02 << 0) + +#define S3C2410_GPB1_TOUT1   (0x02 << 2) + +#define S3C2410_GPB2_TOUT2   (0x02 << 4) + +#define S3C2410_GPB3_TOUT3   (0x02 << 6) + +#define S3C2410_GPB4_TCLK0   (0x02 << 8) +#define S3C2410_GPB4_MASK    (0x03 << 8) + +#define S3C2410_GPB5_nXBACK  (0x02 << 10) +#define S3C2443_GPB5_XBACK   (0x03 << 10) + +#define S3C2410_GPB6_nXBREQ  (0x02 << 12) +#define S3C2443_GPB6_XBREQ   (0x03 << 12) + +#define S3C2410_GPB7_nXDACK1 (0x02 << 14) +#define S3C2443_GPB7_XDACK1  (0x03 << 14) + +#define S3C2410_GPB8_nXDREQ1 (0x02 << 16) + +#define S3C2410_GPB9_nXDACK0 (0x02 << 18) +#define S3C2443_GPB9_XDACK0  (0x03 << 18) + +#define S3C2410_GPB10_nXDRE0 (0x02 << 20) +#define S3C2443_GPB10_XDREQ0 (0x03 << 20) + +#define S3C2410_GPB_PUPDIS(x)  (1<<(x)) + +/* Port C consits of 16 GPIO/Special function + * + * almost identical setup to port b, but the special functions are mostly + * to do with the video system's sync/etc. +*/ + +#define S3C2410_GPCCON	   S3C2410_GPIOREG(0x20) +#define S3C2410_GPCDAT	   S3C2410_GPIOREG(0x24) +#define S3C2410_GPCUP	   S3C2410_GPIOREG(0x28) +#define S3C2410_GPC0_LEND	(0x02 << 0) +#define S3C2410_GPC1_VCLK	(0x02 << 2) +#define S3C2410_GPC2_VLINE	(0x02 << 4) +#define S3C2410_GPC3_VFRAME	(0x02 << 6) +#define S3C2410_GPC4_VM		(0x02 << 8) +#define S3C2410_GPC5_LCDVF0	(0x02 << 10) +#define S3C2410_GPC6_LCDVF1	(0x02 << 12) +#define S3C2410_GPC7_LCDVF2	(0x02 << 14) +#define S3C2410_GPC8_VD0	(0x02 << 16) +#define S3C2410_GPC9_VD1	(0x02 << 18) +#define S3C2410_GPC10_VD2	(0x02 << 20) +#define S3C2410_GPC11_VD3	(0x02 << 22) +#define S3C2410_GPC12_VD4	(0x02 << 24) +#define S3C2410_GPC13_VD5	(0x02 << 26) +#define S3C2410_GPC14_VD6	(0x02 << 28) +#define S3C2410_GPC15_VD7	(0x02 << 30) +#define S3C2410_GPC_PUPDIS(x)  (1<<(x)) + +/* + * S3C2410: Port D consists of 16 GPIO/Special function + * + * almost identical setup to port b, but the special functions are mostly + * to do with the video system's data. + * + * almost identical setup to port c +*/ + +#define S3C2410_GPDCON	   S3C2410_GPIOREG(0x30) +#define S3C2410_GPDDAT	   S3C2410_GPIOREG(0x34) +#define S3C2410_GPDUP	   S3C2410_GPIOREG(0x38) + +#define S3C2410_GPD0_VD8	(0x02 << 0) +#define S3C2442_GPD0_nSPICS1	(0x03 << 0) + +#define S3C2410_GPD1_VD9	(0x02 << 2) +#define S3C2442_GPD1_SPICLK1	(0x03 << 2) + +#define S3C2410_GPD2_VD10	(0x02 << 4) + +#define S3C2410_GPD3_VD11	(0x02 << 6) + +#define S3C2410_GPD4_VD12	(0x02 << 8) + +#define S3C2410_GPD5_VD13	(0x02 << 10) + +#define S3C2410_GPD6_VD14	(0x02 << 12) + +#define S3C2410_GPD7_VD15	(0x02 << 14) + +#define S3C2410_GPD8_VD16	(0x02 << 16) +#define S3C2440_GPD8_SPIMISO1	(0x03 << 16) + +#define S3C2410_GPD9_VD17	(0x02 << 18) +#define S3C2440_GPD9_SPIMOSI1	(0x03 << 18) + +#define S3C2410_GPD10_VD18	(0x02 << 20) +#define S3C2440_GPD10_SPICLK1	(0x03 << 20) + +#define S3C2410_GPD11_VD19	(0x02 << 22) + +#define S3C2410_GPD12_VD20	(0x02 << 24) + +#define S3C2410_GPD13_VD21	(0x02 << 26) + +#define S3C2410_GPD14_VD22	(0x02 << 28) +#define S3C2410_GPD14_nSS1	(0x03 << 28) + +#define S3C2410_GPD15_VD23	(0x02 << 30) +#define S3C2410_GPD15_nSS0	(0x03 << 30) + +#define S3C2410_GPD_PUPDIS(x)  (1<<(x)) + +/* S3C2410: + * Port E consists of 16 GPIO/Special function + * + * again, the same as port B, but dealing with I2S, SDI, and + * more miscellaneous functions + * + * GPIO / interrupt inputs +*/ + +#define S3C2410_GPECON	   S3C2410_GPIOREG(0x40) +#define S3C2410_GPEDAT	   S3C2410_GPIOREG(0x44) +#define S3C2410_GPEUP	   S3C2410_GPIOREG(0x48) + +#define S3C2410_GPE0_I2SLRCK   (0x02 << 0) +#define S3C2443_GPE0_AC_nRESET (0x03 << 0) +#define S3C2410_GPE0_MASK      (0x03 << 0) + +#define S3C2410_GPE1_I2SSCLK   (0x02 << 2) +#define S3C2443_GPE1_AC_SYNC   (0x03 << 2) +#define S3C2410_GPE1_MASK      (0x03 << 2) + +#define S3C2410_GPE2_CDCLK     (0x02 << 4) +#define S3C2443_GPE2_AC_BITCLK (0x03 << 4) + +#define S3C2410_GPE3_I2SSDI    (0x02 << 6) +#define S3C2443_GPE3_AC_SDI    (0x03 << 6) +#define S3C2410_GPE3_nSS0      (0x03 << 6) +#define S3C2410_GPE3_MASK      (0x03 << 6) + +#define S3C2410_GPE4_I2SSDO    (0x02 << 8) +#define S3C2443_GPE4_AC_SDO    (0x03 << 8) +#define S3C2410_GPE4_I2SSDI    (0x03 << 8) +#define S3C2410_GPE4_MASK      (0x03 << 8) + +#define S3C2410_GPE5_SDCLK     (0x02 << 10) +#define S3C2443_GPE5_SD1_CLK   (0x02 << 10) +#define S3C2443_GPE5_AC_BITCLK (0x03 << 10) + +#define S3C2410_GPE6_SDCMD     (0x02 << 12) +#define S3C2443_GPE6_SD1_CMD   (0x02 << 12) +#define S3C2443_GPE6_AC_SDI    (0x03 << 12) + +#define S3C2410_GPE7_SDDAT0    (0x02 << 14) +#define S3C2443_GPE5_SD1_DAT0  (0x02 << 14) +#define S3C2443_GPE7_AC_SDO    (0x03 << 14) + +#define S3C2410_GPE8_SDDAT1    (0x02 << 16) +#define S3C2443_GPE8_SD1_DAT1  (0x02 << 16) +#define S3C2443_GPE8_AC_SYNC   (0x03 << 16) + +#define S3C2410_GPE9_SDDAT2    (0x02 << 18) +#define S3C2443_GPE9_SD1_DAT2  (0x02 << 18) +#define S3C2443_GPE9_AC_nRESET (0x03 << 18) + +#define S3C2410_GPE10_SDDAT3   (0x02 << 20) +#define S3C2443_GPE10_SD1_DAT3 (0x02 << 20) + +#define S3C2410_GPE11_SPIMISO0 (0x02 << 22) + +#define S3C2410_GPE12_SPIMOSI0 (0x02 << 24) + +#define S3C2410_GPE13_SPICLK0  (0x02 << 26) + +#define S3C2410_GPE14_IICSCL   (0x02 << 28) +#define S3C2410_GPE14_MASK     (0x03 << 28) + +#define S3C2410_GPE15_IICSDA   (0x02 << 30) +#define S3C2410_GPE15_MASK     (0x03 << 30) + +#define S3C2440_GPE0_ACSYNC    (0x03 << 0) +#define S3C2440_GPE1_ACBITCLK  (0x03 << 2) +#define S3C2440_GPE2_ACRESET   (0x03 << 4) +#define S3C2440_GPE3_ACIN      (0x03 << 6) +#define S3C2440_GPE4_ACOUT     (0x03 << 8) + +#define S3C2410_GPE_PUPDIS(x)  (1<<(x)) + +/* S3C2410: + * Port F consists of 8 GPIO/Special function + * + * GPIO / interrupt inputs + * + * GPFCON has 2 bits for each of the input pins on port F + *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 undefined + * + * pull up works like all other ports. + * + * GPIO/serial/misc pins +*/ + +#define S3C2410_GPFCON	   S3C2410_GPIOREG(0x50) +#define S3C2410_GPFDAT	   S3C2410_GPIOREG(0x54) +#define S3C2410_GPFUP	   S3C2410_GPIOREG(0x58) + +#define S3C2410_GPF0_EINT0  (0x02 << 0) +#define S3C2410_GPF1_EINT1  (0x02 << 2) +#define S3C2410_GPF2_EINT2  (0x02 << 4) +#define S3C2410_GPF3_EINT3  (0x02 << 6) +#define S3C2410_GPF4_EINT4  (0x02 << 8) +#define S3C2410_GPF5_EINT5  (0x02 << 10) +#define S3C2410_GPF6_EINT6  (0x02 << 12) +#define S3C2410_GPF7_EINT7  (0x02 << 14) +#define S3C2410_GPF_PUPDIS(x)  (1<<(x)) + +/* S3C2410: + * Port G consists of 8 GPIO/IRQ/Special function + * + * GPGCON has 2 bits for each of the input pins on port G + *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func + * + * pull up works like all other ports. +*/ + +#define S3C2410_GPGCON	   S3C2410_GPIOREG(0x60) +#define S3C2410_GPGDAT	   S3C2410_GPIOREG(0x64) +#define S3C2410_GPGUP	   S3C2410_GPIOREG(0x68) + +#define S3C2410_GPG0_EINT8    (0x02 << 0) + +#define S3C2410_GPG1_EINT9    (0x02 << 2) + +#define S3C2410_GPG2_EINT10   (0x02 << 4) +#define S3C2410_GPG2_nSS0     (0x03 << 4) + +#define S3C2410_GPG3_EINT11   (0x02 << 6) +#define S3C2410_GPG3_nSS1     (0x03 << 6) + +#define S3C2410_GPG4_EINT12   (0x02 << 8) +#define S3C2410_GPG4_LCDPWREN (0x03 << 8) +#define S3C2443_GPG4_LCDPWRDN (0x03 << 8) + +#define S3C2410_GPG5_EINT13   (0x02 << 10) +#define S3C2410_GPG5_SPIMISO1 (0x03 << 10)	/* not s3c2443 */ + +#define S3C2410_GPG6_EINT14   (0x02 << 12) +#define S3C2410_GPG6_SPIMOSI1 (0x03 << 12) + +#define S3C2410_GPG7_EINT15   (0x02 << 14) +#define S3C2410_GPG7_SPICLK1  (0x03 << 14) + +#define S3C2410_GPG8_EINT16   (0x02 << 16) + +#define S3C2410_GPG9_EINT17   (0x02 << 18) + +#define S3C2410_GPG10_EINT18  (0x02 << 20) + +#define S3C2410_GPG11_EINT19  (0x02 << 22) +#define S3C2410_GPG11_TCLK1   (0x03 << 22) +#define S3C2443_GPG11_CF_nIREQ (0x03 << 22) + +#define S3C2410_GPG12_EINT20  (0x02 << 24) +#define S3C2410_GPG12_XMON    (0x03 << 24) +#define S3C2442_GPG12_nSPICS0 (0x03 << 24) +#define S3C2443_GPG12_nINPACK (0x03 << 24) + +#define S3C2410_GPG13_EINT21  (0x02 << 26) +#define S3C2410_GPG13_nXPON   (0x03 << 26) +#define S3C2443_GPG13_CF_nREG (0x03 << 26) + +#define S3C2410_GPG14_EINT22  (0x02 << 28) +#define S3C2410_GPG14_YMON    (0x03 << 28) +#define S3C2443_GPG14_CF_RESET (0x03 << 28) + +#define S3C2410_GPG15_EINT23  (0x02 << 30) +#define S3C2410_GPG15_nYPON   (0x03 << 30) +#define S3C2443_GPG15_CF_PWR  (0x03 << 30) + +#define S3C2410_GPG_PUPDIS(x)  (1<<(x)) + +/* Port H consists of11 GPIO/serial/Misc pins + * + * GPHCON has 2 bits for each of the input pins on port H + *   00 = 0 input, 1 output, 2 interrupt (EINT0..7), 3 special func + * + * pull up works like all other ports. +*/ + +#define S3C2410_GPHCON	   S3C2410_GPIOREG(0x70) +#define S3C2410_GPHDAT	   S3C2410_GPIOREG(0x74) +#define S3C2410_GPHUP	   S3C2410_GPIOREG(0x78) + +#define S3C2410_GPH0_nCTS0  (0x02 << 0) +#define S3C2416_GPH0_TXD0  (0x02 << 0) + +#define S3C2410_GPH1_nRTS0  (0x02 << 2) +#define S3C2416_GPH1_RXD0  (0x02 << 2) + +#define S3C2410_GPH2_TXD0   (0x02 << 4) +#define S3C2416_GPH2_TXD1   (0x02 << 4) + +#define S3C2410_GPH3_RXD0   (0x02 << 6) +#define S3C2416_GPH3_RXD1   (0x02 << 6) + +#define S3C2410_GPH4_TXD1   (0x02 << 8) +#define S3C2416_GPH4_TXD2   (0x02 << 8) + +#define S3C2410_GPH5_RXD1   (0x02 << 10) +#define S3C2416_GPH5_RXD2   (0x02 << 10) + +#define S3C2410_GPH6_TXD2   (0x02 << 12) +#define S3C2416_GPH6_TXD3   (0x02 << 12) +#define S3C2410_GPH6_nRTS1  (0x03 << 12) +#define S3C2416_GPH6_nRTS2  (0x03 << 12) + +#define S3C2410_GPH7_RXD2   (0x02 << 14) +#define S3C2416_GPH7_RXD3   (0x02 << 14) +#define S3C2410_GPH7_nCTS1  (0x03 << 14) +#define S3C2416_GPH7_nCTS2  (0x03 << 14) + +#define S3C2410_GPH8_UCLK   (0x02 << 16) +#define S3C2416_GPH8_nCTS0  (0x02 << 16) + +#define S3C2410_GPH9_CLKOUT0  (0x02 << 18) +#define S3C2442_GPH9_nSPICS0  (0x03 << 18) +#define S3C2416_GPH9_nRTS0    (0x02 << 18) + +#define S3C2410_GPH10_CLKOUT1 (0x02 << 20) +#define S3C2416_GPH10_nCTS1   (0x02 << 20) + +#define S3C2416_GPH11_nRTS1   (0x02 << 22) + +#define S3C2416_GPH12_EXTUARTCLK (0x02 << 24) + +#define S3C2416_GPH13_CLKOUT0 (0x02 << 26) + +#define S3C2416_GPH14_CLKOUT1 (0x02 << 28) + +/* The S3C2412 and S3C2413 move the GPJ register set to after + * GPH, which means all registers after 0x80 are now offset by 0x10 + * for the 2412/2413 from the 2410/2440/2442 +*/ + +/* + * Port J consists of 13 GPIO/Camera pins. GPJCON has 2 bits + * for each of the pins on port J. + *   00 - input, 01 output, 10 - camera + * + * Pull up works like all other ports. + */ + +#define S3C2413_GPJCON	   S3C2410_GPIOREG(0x80) +#define S3C2413_GPJDAT	   S3C2410_GPIOREG(0x84) +#define S3C2413_GPJUP	   S3C2410_GPIOREG(0x88) +#define S3C2413_GPJSLPCON  S3C2410_GPIOREG(0x8C) + +/* S3C2443 and above */ +#define S3C2440_GPJCON	   S3C2410_GPIOREG(0xD0) +#define S3C2440_GPJDAT	   S3C2410_GPIOREG(0xD4) +#define S3C2440_GPJUP	   S3C2410_GPIOREG(0xD8) + +#define S3C2443_GPKCON	   S3C2410_GPIOREG(0xE0) +#define S3C2443_GPKDAT	   S3C2410_GPIOREG(0xE4) +#define S3C2443_GPKUP	   S3C2410_GPIOREG(0xE8) + +#define S3C2443_GPLCON	   S3C2410_GPIOREG(0xF0) +#define S3C2443_GPLDAT	   S3C2410_GPIOREG(0xF4) +#define S3C2443_GPLUP	   S3C2410_GPIOREG(0xF8) + +#define S3C2443_GPMCON	   S3C2410_GPIOREG(0x100) +#define S3C2443_GPMDAT	   S3C2410_GPIOREG(0x104) +#define S3C2443_GPMUP	   S3C2410_GPIOREG(0x108) + +/* miscellaneous control */ +#define S3C2410_MISCCR	   S3C2410_GPIOREG(0x80) + +/* see clock.h for dclk definitions */ + +/* pullup control on databus */ +#define S3C2410_MISCCR_SPUCR_HEN    (0<<0) +#define S3C2410_MISCCR_SPUCR_HDIS   (1<<0) +#define S3C2410_MISCCR_SPUCR_LEN    (0<<1) +#define S3C2410_MISCCR_SPUCR_LDIS   (1<<1) + +#define S3C2410_MISCCR_USBDEV	    (0<<3) +#define S3C2410_MISCCR_USBHOST	    (1<<3) + +#define S3C2410_MISCCR_CLK0_MPLL    (0<<4) +#define S3C2410_MISCCR_CLK0_UPLL    (1<<4) +#define S3C2410_MISCCR_CLK0_FCLK    (2<<4) +#define S3C2410_MISCCR_CLK0_HCLK    (3<<4) +#define S3C2410_MISCCR_CLK0_PCLK    (4<<4) +#define S3C2410_MISCCR_CLK0_DCLK0   (5<<4) +#define S3C2410_MISCCR_CLK0_MASK    (7<<4) + +#define S3C2412_MISCCR_CLK0_RTC	    (2<<4) + +#define S3C2410_MISCCR_CLK1_MPLL    (0<<8) +#define S3C2410_MISCCR_CLK1_UPLL    (1<<8) +#define S3C2410_MISCCR_CLK1_FCLK    (2<<8) +#define S3C2410_MISCCR_CLK1_HCLK    (3<<8) +#define S3C2410_MISCCR_CLK1_PCLK    (4<<8) +#define S3C2410_MISCCR_CLK1_DCLK1   (5<<8) +#define S3C2410_MISCCR_CLK1_MASK    (7<<8) + +#define S3C2412_MISCCR_CLK1_CLKsrc  (0<<8) + +#define S3C2410_MISCCR_USBSUSPND0   (1<<12) +#define S3C2416_MISCCR_SEL_SUSPND   (1<<12) +#define S3C2410_MISCCR_USBSUSPND1   (1<<13) + +#define S3C2410_MISCCR_nRSTCON	    (1<<16) + +#define S3C2410_MISCCR_nEN_SCLK0    (1<<17) +#define S3C2410_MISCCR_nEN_SCLK1    (1<<18) +#define S3C2410_MISCCR_nEN_SCLKE    (1<<19)	/* not 2412 */ +#define S3C2410_MISCCR_SDSLEEP	    (7<<17) + +#define S3C2416_MISCCR_FLT_I2C      (1<<24) +#define S3C2416_MISCCR_HSSPI_EN2    (1<<31) + +/* external interrupt control... */ +/* S3C2410_EXTINT0 -> irq sense control for EINT0..EINT7 + * S3C2410_EXTINT1 -> irq sense control for EINT8..EINT15 + * S3C2410_EXTINT2 -> irq sense control for EINT16..EINT23 + * + * note S3C2410_EXTINT2 has filtering options for EINT16..EINT23 + * + * Samsung datasheet p9-25 +*/ +#define S3C2410_EXTINT0	   S3C2410_GPIOREG(0x88) +#define S3C2410_EXTINT1	   S3C2410_GPIOREG(0x8C) +#define S3C2410_EXTINT2	   S3C2410_GPIOREG(0x90) + +#define S3C24XX_EXTINT0	   S3C24XX_GPIOREG2(0x88) +#define S3C24XX_EXTINT1	   S3C24XX_GPIOREG2(0x8C) +#define S3C24XX_EXTINT2	   S3C24XX_GPIOREG2(0x90) + +/* interrupt filtering conrrol for EINT16..EINT23 */ +#define S3C2410_EINFLT0	   S3C2410_GPIOREG(0x94) +#define S3C2410_EINFLT1	   S3C2410_GPIOREG(0x98) +#define S3C2410_EINFLT2	   S3C2410_GPIOREG(0x9C) +#define S3C2410_EINFLT3	   S3C2410_GPIOREG(0xA0) + +#define S3C24XX_EINFLT0	   S3C24XX_GPIOREG2(0x94) +#define S3C24XX_EINFLT1	   S3C24XX_GPIOREG2(0x98) +#define S3C24XX_EINFLT2	   S3C24XX_GPIOREG2(0x9C) +#define S3C24XX_EINFLT3	   S3C24XX_GPIOREG2(0xA0) + +/* values for interrupt filtering */ +#define S3C2410_EINTFLT_PCLK		(0x00) +#define S3C2410_EINTFLT_EXTCLK		(1<<7) +#define S3C2410_EINTFLT_WIDTHMSK(x)	((x) & 0x3f) + +/* removed EINTxxxx defs from here, not meant for this */ + +/* GSTATUS have miscellaneous information in them + * + * These move between s3c2410 and s3c2412 style systems. + */ + +#define S3C2410_GSTATUS0   S3C2410_GPIOREG(0x0AC) +#define S3C2410_GSTATUS1   S3C2410_GPIOREG(0x0B0) +#define S3C2410_GSTATUS2   S3C2410_GPIOREG(0x0B4) +#define S3C2410_GSTATUS3   S3C2410_GPIOREG(0x0B8) +#define S3C2410_GSTATUS4   S3C2410_GPIOREG(0x0BC) + +#define S3C2412_GSTATUS0   S3C2410_GPIOREG(0x0BC) +#define S3C2412_GSTATUS1   S3C2410_GPIOREG(0x0C0) +#define S3C2412_GSTATUS2   S3C2410_GPIOREG(0x0C4) +#define S3C2412_GSTATUS3   S3C2410_GPIOREG(0x0C8) +#define S3C2412_GSTATUS4   S3C2410_GPIOREG(0x0CC) + +#define S3C24XX_GSTATUS0   S3C24XX_GPIOREG2(0x0AC) +#define S3C24XX_GSTATUS1   S3C24XX_GPIOREG2(0x0B0) +#define S3C24XX_GSTATUS2   S3C24XX_GPIOREG2(0x0B4) +#define S3C24XX_GSTATUS3   S3C24XX_GPIOREG2(0x0B8) +#define S3C24XX_GSTATUS4   S3C24XX_GPIOREG2(0x0BC) + +#define S3C2410_GSTATUS0_nWAIT	   (1<<3) +#define S3C2410_GSTATUS0_NCON	   (1<<2) +#define S3C2410_GSTATUS0_RnB	   (1<<1) +#define S3C2410_GSTATUS0_nBATTFLT  (1<<0) + +#define S3C2410_GSTATUS1_IDMASK	   (0xffff0000) +#define S3C2410_GSTATUS1_2410	   (0x32410000) +#define S3C2410_GSTATUS1_2412	   (0x32412001) +#define S3C2410_GSTATUS1_2416	   (0x32416003) +#define S3C2410_GSTATUS1_2440	   (0x32440000) +#define S3C2410_GSTATUS1_2442	   (0x32440aaa) +/* some 2416 CPUs report this value also */ +#define S3C2410_GSTATUS1_2450	   (0x32450003) + +#define S3C2410_GSTATUS2_WTRESET   (1<<2) +#define S3C2410_GSTATUS2_OFFRESET  (1<<1) +#define S3C2410_GSTATUS2_PONRESET  (1<<0) + +/* 2412/2413 sleep configuration registers */ + +#define S3C2412_GPBSLPCON	S3C2410_GPIOREG(0x1C) +#define S3C2412_GPCSLPCON	S3C2410_GPIOREG(0x2C) +#define S3C2412_GPDSLPCON	S3C2410_GPIOREG(0x3C) +#define S3C2412_GPFSLPCON	S3C2410_GPIOREG(0x5C) +#define S3C2412_GPGSLPCON	S3C2410_GPIOREG(0x6C) +#define S3C2412_GPHSLPCON	S3C2410_GPIOREG(0x7C) + +/* definitions for each pin bit */ +#define S3C2412_GPIO_SLPCON_LOW	 ( 0x00 ) +#define S3C2412_GPIO_SLPCON_HIGH ( 0x01 ) +#define S3C2412_GPIO_SLPCON_IN   ( 0x02 ) +#define S3C2412_GPIO_SLPCON_PULL ( 0x03 ) + +#define S3C2412_SLPCON_LOW(x)	( 0x00 << ((x) * 2)) +#define S3C2412_SLPCON_HIGH(x)	( 0x01 << ((x) * 2)) +#define S3C2412_SLPCON_IN(x)	( 0x02 << ((x) * 2)) +#define S3C2412_SLPCON_PULL(x)	( 0x03 << ((x) * 2)) +#define S3C2412_SLPCON_EINT(x)	( 0x02 << ((x) * 2))  /* only IRQ pins */ +#define S3C2412_SLPCON_MASK(x)	( 0x03 << ((x) * 2)) + +#define S3C2412_SLPCON_ALL_LOW	(0x0) +#define S3C2412_SLPCON_ALL_HIGH	(0x11111111 | 0x44444444) +#define S3C2412_SLPCON_ALL_IN  	(0x22222222 | 0x88888888) +#define S3C2412_SLPCON_ALL_PULL	(0x33333333) + +#endif	/* __ASM_ARCH_REGS_GPIO_H */ + diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-irq.h b/arch/arm/mach-s3c24xx/include/mach/regs-irq.h new file mode 100644 index 00000000000..0f07ba30b1f --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/regs-irq.h @@ -0,0 +1,53 @@ +/* arch/arm/mach-s3c2410/include/mach/regs-irq.h + * + * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> + *		      http://www.simtec.co.uk/products/SWLINUX/ + * + * 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 ___ASM_ARCH_REGS_IRQ_H +#define ___ASM_ARCH_REGS_IRQ_H + +/* interrupt controller */ + +#define S3C2410_IRQREG(x)   ((x) + S3C24XX_VA_IRQ) +#define S3C2410_EINTREG(x)  ((x) + S3C24XX_VA_GPIO) +#define S3C24XX_EINTREG(x)  ((x) + S3C24XX_VA_GPIO2) + +#define S3C2410_SRCPND	       S3C2410_IRQREG(0x000) +#define S3C2410_INTMOD	       S3C2410_IRQREG(0x004) +#define S3C2410_INTMSK	       S3C2410_IRQREG(0x008) +#define S3C2410_PRIORITY       S3C2410_IRQREG(0x00C) +#define S3C2410_INTPND	       S3C2410_IRQREG(0x010) +#define S3C2410_INTOFFSET      S3C2410_IRQREG(0x014) +#define S3C2410_SUBSRCPND      S3C2410_IRQREG(0x018) +#define S3C2410_INTSUBMSK      S3C2410_IRQREG(0x01C) + +#define S3C2416_PRIORITY_MODE1		S3C2410_IRQREG(0x030) +#define S3C2416_PRIORITY_UPDATE1	S3C2410_IRQREG(0x034) +#define S3C2416_SRCPND2			S3C2410_IRQREG(0x040) +#define S3C2416_INTMOD2			S3C2410_IRQREG(0x044) +#define S3C2416_INTMSK2			S3C2410_IRQREG(0x048) +#define S3C2416_INTPND2			S3C2410_IRQREG(0x050) +#define S3C2416_INTOFFSET2		S3C2410_IRQREG(0x054) +#define S3C2416_PRIORITY_MODE2		S3C2410_IRQREG(0x070) +#define S3C2416_PRIORITY_UPDATE2	S3C2410_IRQREG(0x074) + +/* mask: 0=enable, 1=disable + * 1 bit EINT, 4=EINT4, 23=EINT23 + * EINT0,1,2,3 are not handled here. +*/ + +#define S3C2410_EINTMASK       S3C2410_EINTREG(0x0A4) +#define S3C2410_EINTPEND       S3C2410_EINTREG(0X0A8) +#define S3C2412_EINTMASK       S3C2410_EINTREG(0x0B4) +#define S3C2412_EINTPEND       S3C2410_EINTREG(0X0B8) + +#define S3C24XX_EINTMASK       S3C24XX_EINTREG(0x0A4) +#define S3C24XX_EINTPEND       S3C24XX_EINTREG(0X0A8) + +#endif /* ___ASM_ARCH_REGS_IRQ_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-lcd.h b/arch/arm/mach-s3c24xx/include/mach/regs-lcd.h new file mode 100644 index 00000000000..ee8f040aff5 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/regs-lcd.h @@ -0,0 +1,162 @@ +/* arch/arm/mach-s3c2410/include/mach/regs-lcd.h + * + * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> + *		      http://www.simtec.co.uk/products/SWLINUX/ + * + * 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 ___ASM_ARCH_REGS_LCD_H +#define ___ASM_ARCH_REGS_LCD_H + +#define S3C2410_LCDREG(x)	(x) + +/* LCD control registers */ +#define S3C2410_LCDCON1	    S3C2410_LCDREG(0x00) +#define S3C2410_LCDCON2	    S3C2410_LCDREG(0x04) +#define S3C2410_LCDCON3	    S3C2410_LCDREG(0x08) +#define S3C2410_LCDCON4	    S3C2410_LCDREG(0x0C) +#define S3C2410_LCDCON5	    S3C2410_LCDREG(0x10) + +#define S3C2410_LCDCON1_CLKVAL(x)  ((x) << 8) +#define S3C2410_LCDCON1_MMODE	   (1<<7) +#define S3C2410_LCDCON1_DSCAN4	   (0<<5) +#define S3C2410_LCDCON1_STN4	   (1<<5) +#define S3C2410_LCDCON1_STN8	   (2<<5) +#define S3C2410_LCDCON1_TFT	   (3<<5) + +#define S3C2410_LCDCON1_STN1BPP	   (0<<1) +#define S3C2410_LCDCON1_STN2GREY   (1<<1) +#define S3C2410_LCDCON1_STN4GREY   (2<<1) +#define S3C2410_LCDCON1_STN8BPP	   (3<<1) +#define S3C2410_LCDCON1_STN12BPP   (4<<1) + +#define S3C2410_LCDCON1_TFT1BPP	   (8<<1) +#define S3C2410_LCDCON1_TFT2BPP	   (9<<1) +#define S3C2410_LCDCON1_TFT4BPP	   (10<<1) +#define S3C2410_LCDCON1_TFT8BPP	   (11<<1) +#define S3C2410_LCDCON1_TFT16BPP   (12<<1) +#define S3C2410_LCDCON1_TFT24BPP   (13<<1) + +#define S3C2410_LCDCON1_ENVID	   (1) + +#define S3C2410_LCDCON1_MODEMASK    0x1E + +#define S3C2410_LCDCON2_VBPD(x)	    ((x) << 24) +#define S3C2410_LCDCON2_LINEVAL(x)  ((x) << 14) +#define S3C2410_LCDCON2_VFPD(x)	    ((x) << 6) +#define S3C2410_LCDCON2_VSPW(x)	    ((x) << 0) + +#define S3C2410_LCDCON2_GET_VBPD(x) ( ((x) >> 24) & 0xFF) +#define S3C2410_LCDCON2_GET_VFPD(x) ( ((x) >>  6) & 0xFF) +#define S3C2410_LCDCON2_GET_VSPW(x) ( ((x) >>  0) & 0x3F) + +#define S3C2410_LCDCON3_HBPD(x)	    ((x) << 19) +#define S3C2410_LCDCON3_WDLY(x)	    ((x) << 19) +#define S3C2410_LCDCON3_HOZVAL(x)   ((x) << 8) +#define S3C2410_LCDCON3_HFPD(x)	    ((x) << 0) +#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0) + +#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F) +#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >>  0) & 0xFF) + +/* LDCCON4 changes for STN mode on the S3C2412 */ + +#define S3C2410_LCDCON4_MVAL(x)	    ((x) << 8) +#define S3C2410_LCDCON4_HSPW(x)	    ((x) << 0) +#define S3C2410_LCDCON4_WLH(x)	    ((x) << 0) + +#define S3C2410_LCDCON4_GET_HSPW(x) ( ((x) >>  0) & 0xFF) + +#define S3C2410_LCDCON5_BPP24BL	    (1<<12) +#define S3C2410_LCDCON5_FRM565	    (1<<11) +#define S3C2410_LCDCON5_INVVCLK	    (1<<10) +#define S3C2410_LCDCON5_INVVLINE    (1<<9) +#define S3C2410_LCDCON5_INVVFRAME   (1<<8) +#define S3C2410_LCDCON5_INVVD	    (1<<7) +#define S3C2410_LCDCON5_INVVDEN	    (1<<6) +#define S3C2410_LCDCON5_INVPWREN    (1<<5) +#define S3C2410_LCDCON5_INVLEND	    (1<<4) +#define S3C2410_LCDCON5_PWREN	    (1<<3) +#define S3C2410_LCDCON5_ENLEND	    (1<<2) +#define S3C2410_LCDCON5_BSWP	    (1<<1) +#define S3C2410_LCDCON5_HWSWP	    (1<<0) + +/* framebuffer start addressed */ +#define S3C2410_LCDSADDR1   S3C2410_LCDREG(0x14) +#define S3C2410_LCDSADDR2   S3C2410_LCDREG(0x18) +#define S3C2410_LCDSADDR3   S3C2410_LCDREG(0x1C) + +#define S3C2410_LCDBANK(x)	((x) << 21) +#define S3C2410_LCDBASEU(x)	(x) + +#define S3C2410_OFFSIZE(x)	((x) << 11) +#define S3C2410_PAGEWIDTH(x)	(x) + +/* colour lookup and miscellaneous controls */ + +#define S3C2410_REDLUT	   S3C2410_LCDREG(0x20) +#define S3C2410_GREENLUT   S3C2410_LCDREG(0x24) +#define S3C2410_BLUELUT	   S3C2410_LCDREG(0x28) + +#define S3C2410_DITHMODE   S3C2410_LCDREG(0x4C) +#define S3C2410_TPAL	   S3C2410_LCDREG(0x50) + +#define S3C2410_TPAL_EN		(1<<24) + +/* interrupt info */ +#define S3C2410_LCDINTPND  S3C2410_LCDREG(0x54) +#define S3C2410_LCDSRCPND  S3C2410_LCDREG(0x58) +#define S3C2410_LCDINTMSK  S3C2410_LCDREG(0x5C) +#define S3C2410_LCDINT_FIWSEL	(1<<2) +#define	S3C2410_LCDINT_FRSYNC	(1<<1) +#define S3C2410_LCDINT_FICNT	(1<<0) + +/* s3c2442 extra stn registers */ + +#define S3C2442_REDLUT		S3C2410_LCDREG(0x20) +#define S3C2442_GREENLUT	S3C2410_LCDREG(0x24) +#define S3C2442_BLUELUT		S3C2410_LCDREG(0x28) +#define S3C2442_DITHMODE	S3C2410_LCDREG(0x20) + +#define S3C2410_LPCSEL	   S3C2410_LCDREG(0x60) + +#define S3C2410_TFTPAL(x)  S3C2410_LCDREG((0x400 + (x)*4)) + +/* S3C2412 registers */ + +#define S3C2412_TPAL		S3C2410_LCDREG(0x20) + +#define S3C2412_LCDINTPND	S3C2410_LCDREG(0x24) +#define S3C2412_LCDSRCPND	S3C2410_LCDREG(0x28) +#define S3C2412_LCDINTMSK	S3C2410_LCDREG(0x2C) + +#define S3C2412_TCONSEL		S3C2410_LCDREG(0x30) + +#define S3C2412_LCDCON6		S3C2410_LCDREG(0x34) +#define S3C2412_LCDCON7		S3C2410_LCDREG(0x38) +#define S3C2412_LCDCON8		S3C2410_LCDREG(0x3C) +#define S3C2412_LCDCON9		S3C2410_LCDREG(0x40) + +#define S3C2412_REDLUT(x)	S3C2410_LCDREG(0x44 + ((x)*4)) +#define S3C2412_GREENLUT(x)	S3C2410_LCDREG(0x60 + ((x)*4)) +#define S3C2412_BLUELUT(x)	S3C2410_LCDREG(0x98 + ((x)*4)) + +#define S3C2412_FRCPAT(x)	S3C2410_LCDREG(0xB4 + ((x)*4)) + +/* general registers */ + +/* base of the LCD registers, where INTPND, INTSRC and then INTMSK + * are available. */ + +#define S3C2410_LCDINTBASE	S3C2410_LCDREG(0x54) +#define S3C2412_LCDINTBASE	S3C2410_LCDREG(0x24) + +#define S3C24XX_LCDINTPND	(0x00) +#define S3C24XX_LCDSRCPND	(0x04) +#define S3C24XX_LCDINTMSK	(0x08) + +#endif /* ___ASM_ARCH_REGS_LCD_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h new file mode 100644 index 00000000000..c3feff3c048 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/regs-s3c2443-clock.h @@ -0,0 +1,194 @@ +/* arch/arm/mach-s3c2410/include/mach/regs-s3c2443-clock.h + * + * Copyright (c) 2007 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + *	http://armlinux.simtec.co.uk/ + * + * 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. + * + * S3C2443 clock register definitions +*/ + +#ifndef __ASM_ARM_REGS_S3C2443_CLOCK +#define __ASM_ARM_REGS_S3C2443_CLOCK + +#define S3C2443_CLKREG(x)		((x) + S3C24XX_VA_CLKPWR) + +#define S3C2443_PLLCON_MDIVSHIFT	16 +#define S3C2443_PLLCON_PDIVSHIFT	8 +#define S3C2443_PLLCON_SDIVSHIFT	0 +#define S3C2443_PLLCON_MDIVMASK		((1<<(1+(23-16)))-1) +#define S3C2443_PLLCON_PDIVMASK		((1<<(1+(9-8)))-1) +#define S3C2443_PLLCON_SDIVMASK		(3) + +#define S3C2443_MPLLCON			S3C2443_CLKREG(0x10) +#define S3C2443_EPLLCON			S3C2443_CLKREG(0x18) +#define S3C2443_CLKSRC			S3C2443_CLKREG(0x20) +#define S3C2443_CLKDIV0			S3C2443_CLKREG(0x24) +#define S3C2443_CLKDIV1			S3C2443_CLKREG(0x28) +#define S3C2443_HCLKCON			S3C2443_CLKREG(0x30) +#define S3C2443_PCLKCON			S3C2443_CLKREG(0x34) +#define S3C2443_SCLKCON			S3C2443_CLKREG(0x38) +#define S3C2443_PWRMODE			S3C2443_CLKREG(0x40) +#define S3C2443_SWRST			S3C2443_CLKREG(0x44) +#define S3C2443_BUSPRI0			S3C2443_CLKREG(0x50) +#define S3C2443_SYSID			S3C2443_CLKREG(0x5C) +#define S3C2443_PWRCFG			S3C2443_CLKREG(0x60) +#define S3C2443_RSTCON			S3C2443_CLKREG(0x64) +#define S3C2443_PHYCTRL			S3C2443_CLKREG(0x80) +#define S3C2443_PHYPWR			S3C2443_CLKREG(0x84) +#define S3C2443_URSTCON			S3C2443_CLKREG(0x88) +#define S3C2443_UCLKCON			S3C2443_CLKREG(0x8C) + +#define S3C2443_SWRST_RESET		(0x533c2443) + +#define S3C2443_PLLCON_OFF		(1<<24) + +#define S3C2443_CLKSRC_EPLLREF_XTAL	(2<<7) +#define S3C2443_CLKSRC_EPLLREF_EXTCLK	(3<<7) +#define S3C2443_CLKSRC_EPLLREF_MPLLREF	(0<<7) +#define S3C2443_CLKSRC_EPLLREF_MPLLREF2	(1<<7) +#define S3C2443_CLKSRC_EPLLREF_MASK	(3<<7) + +#define S3C2443_CLKSRC_EXTCLK_DIV	(1<<3) + +#define S3C2443_CLKDIV0_HALF_HCLK	(1<<3) +#define S3C2443_CLKDIV0_HALF_PCLK	(1<<2) + +#define S3C2443_CLKDIV0_HCLKDIV_MASK	(3<<0) + +#define S3C2443_CLKDIV0_EXTDIV_MASK	(3<<6) +#define S3C2443_CLKDIV0_EXTDIV_SHIFT	(6) + +#define S3C2443_CLKDIV0_PREDIV_MASK	(3<<4) +#define S3C2443_CLKDIV0_PREDIV_SHIFT	(4) + +#define S3C2416_CLKDIV0_ARMDIV_MASK	(7 << 9) +#define S3C2443_CLKDIV0_ARMDIV_MASK	(15<<9) +#define S3C2443_CLKDIV0_ARMDIV_SHIFT	(9) +#define S3C2443_CLKDIV0_ARMDIV_1	(0<<9) +#define S3C2443_CLKDIV0_ARMDIV_2	(8<<9) +#define S3C2443_CLKDIV0_ARMDIV_3	(2<<9) +#define S3C2443_CLKDIV0_ARMDIV_4	(9<<9) +#define S3C2443_CLKDIV0_ARMDIV_6	(10<<9) +#define S3C2443_CLKDIV0_ARMDIV_8	(11<<9) +#define S3C2443_CLKDIV0_ARMDIV_12	(13<<9) +#define S3C2443_CLKDIV0_ARMDIV_16	(15<<9) + +/* S3C2443_CLKDIV1 removed, only used in clock.c code */ + +#define S3C2443_CLKCON_NAND + +#define S3C2443_HCLKCON_DMA0		(1<<0) +#define S3C2443_HCLKCON_DMA1		(1<<1) +#define S3C2443_HCLKCON_DMA2		(1<<2) +#define S3C2443_HCLKCON_DMA3		(1<<3) +#define S3C2443_HCLKCON_DMA4		(1<<4) +#define S3C2443_HCLKCON_DMA5		(1<<5) +#define S3C2443_HCLKCON_CAMIF		(1<<8) +#define S3C2443_HCLKCON_LCDC		(1<<9) +#define S3C2443_HCLKCON_USBH		(1<<11) +#define S3C2443_HCLKCON_USBD		(1<<12) +#define S3C2416_HCLKCON_HSMMC0		(1<<15) +#define S3C2443_HCLKCON_HSMMC		(1<<16) +#define S3C2443_HCLKCON_CFC		(1<<17) +#define S3C2443_HCLKCON_SSMC		(1<<18) +#define S3C2443_HCLKCON_DRAMC		(1<<19) + +#define S3C2443_PCLKCON_UART0		(1<<0) +#define S3C2443_PCLKCON_UART1		(1<<1) +#define S3C2443_PCLKCON_UART2		(1<<2) +#define S3C2443_PCLKCON_UART3		(1<<3) +#define S3C2443_PCLKCON_IIC		(1<<4) +#define S3C2443_PCLKCON_SDI		(1<<5) +#define S3C2443_PCLKCON_HSSPI		(1<<6) +#define S3C2443_PCLKCON_ADC		(1<<7) +#define S3C2443_PCLKCON_AC97		(1<<8) +#define S3C2443_PCLKCON_IIS		(1<<9) +#define S3C2443_PCLKCON_PWMT		(1<<10) +#define S3C2443_PCLKCON_WDT		(1<<11) +#define S3C2443_PCLKCON_RTC		(1<<12) +#define S3C2443_PCLKCON_GPIO		(1<<13) +#define S3C2443_PCLKCON_SPI0		(1<<14) +#define S3C2443_PCLKCON_SPI1		(1<<15) + +#define S3C2443_SCLKCON_DDRCLK		(1<<16) +#define S3C2443_SCLKCON_SSMCCLK		(1<<15) +#define S3C2443_SCLKCON_HSSPICLK	(1<<14) +#define S3C2443_SCLKCON_HSMMCCLK_EXT	(1<<13) +#define S3C2443_SCLKCON_HSMMCCLK_EPLL	(1<<12) +#define S3C2443_SCLKCON_CAMCLK		(1<<11) +#define S3C2443_SCLKCON_DISPCLK		(1<<10) +#define S3C2443_SCLKCON_I2SCLK		(1<<9) +#define S3C2443_SCLKCON_UARTCLK		(1<<8) +#define S3C2443_SCLKCON_USBHOST		(1<<1) + +#define S3C2443_PWRCFG_SLEEP		(1<<15) + +#define S3C2443_PWRCFG_USBPHY		(1 << 4) + +#define S3C2443_URSTCON_FUNCRST		(1 << 2) +#define S3C2443_URSTCON_PHYRST		(1 << 0) + +#define S3C2443_PHYCTRL_CLKSEL		(1 << 3) +#define S3C2443_PHYCTRL_EXTCLK		(1 << 2) +#define S3C2443_PHYCTRL_PLLSEL		(1 << 1) +#define S3C2443_PHYCTRL_DSPORT		(1 << 0) + +#define S3C2443_PHYPWR_COMMON_ON	(1 << 31) +#define S3C2443_PHYPWR_ANALOG_PD	(1 << 4) +#define S3C2443_PHYPWR_PLL_REFCLK	(1 << 3) +#define S3C2443_PHYPWR_XO_ON		(1 << 2) +#define S3C2443_PHYPWR_PLL_PWRDN	(1 << 1) +#define S3C2443_PHYPWR_FSUSPEND		(1 << 0) + +#define S3C2443_UCLKCON_DETECT_VBUS	(1 << 31) +#define S3C2443_UCLKCON_FUNC_CLKEN	(1 << 2) +#define S3C2443_UCLKCON_TCLKEN		(1 << 0) + +#include <asm/div64.h> + +static inline unsigned int +s3c2443_get_mpll(unsigned int pllval, unsigned int baseclk) +{ +	unsigned int mdiv, pdiv, sdiv; +	uint64_t fvco; + +	mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT; +	pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT; +	sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT; + +	mdiv &= S3C2443_PLLCON_MDIVMASK; +	pdiv &= S3C2443_PLLCON_PDIVMASK; +	sdiv &= S3C2443_PLLCON_SDIVMASK; + +	fvco = (uint64_t)baseclk * (2 * (mdiv + 8)); +	do_div(fvco, pdiv << sdiv); + +	return (unsigned int)fvco; +} + +static inline unsigned int +s3c2443_get_epll(unsigned int pllval, unsigned int baseclk) +{ +	unsigned int mdiv, pdiv, sdiv; +	uint64_t fvco; + +	mdiv = pllval >> S3C2443_PLLCON_MDIVSHIFT; +	pdiv = pllval >> S3C2443_PLLCON_PDIVSHIFT; +	sdiv = pllval >> S3C2443_PLLCON_SDIVSHIFT; + +	mdiv &= S3C2443_PLLCON_MDIVMASK; +	pdiv &= S3C2443_PLLCON_PDIVMASK; +	sdiv &= S3C2443_PLLCON_SDIVMASK; + +	fvco = (uint64_t)baseclk * (mdiv + 8); +	do_div(fvco, (pdiv + 2) << sdiv); + +	return (unsigned int)fvco; +} + +#endif /*  __ASM_ARM_REGS_S3C2443_CLOCK */ + diff --git a/arch/arm/mach-s3c24xx/include/mach/rtc-core.h b/arch/arm/mach-s3c24xx/include/mach/rtc-core.h new file mode 100644 index 00000000000..4d5f5768f70 --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/rtc-core.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de> + * + * Samsung RTC Controller core functions + * + * 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 __RTC_CORE_H +#define __RTC_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +extern struct platform_device s3c_device_rtc; + +/* re-define device name depending on support. */ +static inline void s3c_rtc_setname(char *name) +{ +	s3c_device_rtc.name = name; +} + +#endif /* __RTC_CORE_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/s3c2412.h b/arch/arm/mach-s3c24xx/include/mach/s3c2412.h new file mode 100644 index 00000000000..548ced42cbb --- /dev/null +++ b/arch/arm/mach-s3c24xx/include/mach/s3c2412.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2008 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + *	http://armlinux.simtec.co.uk/ + * + * 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_S3C24XX_S3C2412_H +#define __ARCH_ARM_REGS_S3C24XX_S3C2412_H __FILE__ + +#define S3C2412_MEMREG(x)		(S3C24XX_VA_MEMCTRL + (x)) +#define S3C2412_EBIREG(x)		(S3C2412_VA_EBI + (x)) + +#define S3C2412_SSMCREG(x)		(S3C2412_VA_SSMC + (x)) +#define S3C2412_SSMC(x, o)		(S3C2412_SSMCREG((x * 0x20) + (o))) + +#define S3C2412_REFRESH			S3C2412_MEMREG(0x10) + +#define S3C2412_EBI_BANKCFG		S3C2412_EBIREG(0x4) + +#define S3C2412_SSMC_BANK(x)		S3C2412_SSMC(x, 0x0) + +#endif /* __ARCH_ARM_MACH_S3C24XX_S3C2412_H */ diff --git a/arch/arm/mach-s3c24xx/iotiming-s3c2410.c b/arch/arm/mach-s3c24xx/iotiming-s3c2410.c new file mode 100644 index 00000000000..4cd13ab6496 --- /dev/null +++ b/arch/arm/mach-s3c24xx/iotiming-s3c2410.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2006-2009 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX CPU Frequency scaling - IO timing for S3C2410/S3C2440/S3C2442 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/cpufreq.h> +#include <linux/seq_file.h> +#include <linux/io.h> +#include <linux/slab.h> + +#include <mach/map.h> +#include <mach/regs-clock.h> + +#include <plat/cpu-freq-core.h> + +#include "regs-mem.h" + +#define print_ns(x) ((x) / 10), ((x) % 10) + +/** + * s3c2410_print_timing - print bank timing data for debug purposes + * @pfx: The prefix to put on the output + * @timings: The timing inforamtion to print. +*/ +static void s3c2410_print_timing(const char *pfx, +				 struct s3c_iotimings *timings) +{ +	struct s3c2410_iobank_timing *bt; +	int bank; + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bt = timings->bank[bank].io_2410; +		if (!bt) +			continue; + +		printk(KERN_DEBUG "%s %d: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, " +		       "Tcoh=%d.%d, Tcah=%d.%d\n", pfx, bank, +		       print_ns(bt->tacs), +		       print_ns(bt->tcos), +		       print_ns(bt->tacc), +		       print_ns(bt->tcoh), +		       print_ns(bt->tcah)); +	} +} + +/** + * bank_reg - convert bank number to pointer to the control register. + * @bank: The IO bank number. + */ +static inline void __iomem *bank_reg(unsigned int bank) +{ +	return S3C2410_BANKCON0 + (bank << 2); +} + +/** + * bank_is_io - test whether bank is used for IO + * @bankcon: The bank control register. + * + * This is a simplistic test to see if any BANKCON[x] is not an IO + * bank. It currently does not take into account whether BWSCON has + * an illegal width-setting in it, or if the pin connected to nCS[x] + * is actually being handled as a chip-select. + */ +static inline int bank_is_io(unsigned long bankcon) +{ +	return !(bankcon & S3C2410_BANKCON_SDRAM); +} + +/** + * to_div - convert cycle time to divisor + * @cyc: The cycle time, in 10ths of nanoseconds. + * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. + * + * Convert the given cycle time into the divisor to use to obtain it from + * HCLK. +*/ +static inline unsigned int to_div(unsigned int cyc, unsigned int hclk_tns) +{ +	if (cyc == 0) +		return 0; + +	return DIV_ROUND_UP(cyc, hclk_tns); +} + +/** + * calc_0124 - calculate divisor control for divisors that do /0, /1. /2 and /4 + * @cyc: The cycle time, in 10ths of nanoseconds. + * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. + * @v: Pointer to register to alter. + * @shift: The shift to get to the control bits. + * + * Calculate the divisor, and turn it into the correct control bits to + * set in the result, @v. + */ +static unsigned int calc_0124(unsigned int cyc, unsigned long hclk_tns, +			      unsigned long *v, int shift) +{ +	unsigned int div = to_div(cyc, hclk_tns); +	unsigned long val; + +	s3c_freq_iodbg("%s: cyc=%d, hclk=%lu, shift=%d => div %d\n", +		       __func__, cyc, hclk_tns, shift, div); + +	switch (div) { +	case 0: +		val = 0; +		break; +	case 1: +		val = 1; +		break; +	case 2: +		val = 2; +		break; +	case 3: +	case 4: +		val = 3; +		break; +	default: +		return -1; +	} + +	*v |= val << shift; +	return 0; +} + +int calc_tacp(unsigned int cyc, unsigned long hclk, unsigned long *v) +{ +	/* Currently no support for Tacp calculations. */ +	return 0; +} + +/** + * calc_tacc - calculate divisor control for tacc. + * @cyc: The cycle time, in 10ths of nanoseconds. + * @nwait_en: IS nWAIT enabled for this bank. + * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. + * @v: Pointer to register to alter. + * + * Calculate the divisor control for tACC, taking into account whether + * the bank has nWAIT enabled. The result is used to modify the value + * pointed to by @v. +*/ +static int calc_tacc(unsigned int cyc, int nwait_en, +		     unsigned long hclk_tns, unsigned long *v) +{ +	unsigned int div = to_div(cyc, hclk_tns); +	unsigned long val; + +	s3c_freq_iodbg("%s: cyc=%u, nwait=%d, hclk=%lu => div=%u\n", +		       __func__, cyc, nwait_en, hclk_tns, div); + +	/* if nWait enabled on an bank, Tacc must be at-least 4 cycles. */ +	if (nwait_en && div < 4) +		div = 4; + +	switch (div) { +	case 0: +		val = 0; +		break; + +	case 1: +	case 2: +	case 3: +	case 4: +		val = div - 1; +		break; + +	case 5: +	case 6: +		val = 4; +		break; + +	case 7: +	case 8: +		val = 5; +		break; + +	case 9: +	case 10: +		val = 6; +		break; + +	case 11: +	case 12: +	case 13: +	case 14: +		val = 7; +		break; + +	default: +		return -1; +	} + +	*v |= val << 8; +	return 0; +} + +/** + * s3c2410_calc_bank - calculate bank timing infromation + * @cfg: The configuration we need to calculate for. + * @bt: The bank timing information. + * + * Given the cycle timine for a bank @bt, calculate the new BANKCON + * setting for the @cfg timing. This updates the timing information + * ready for the cpu frequency change. + */ +static int s3c2410_calc_bank(struct s3c_cpufreq_config *cfg, +			     struct s3c2410_iobank_timing *bt) +{ +	unsigned long hclk = cfg->freq.hclk_tns; +	unsigned long res; +	int ret; + +	res  = bt->bankcon; +	res &= (S3C2410_BANKCON_SDRAM | S3C2410_BANKCON_PMC16); + +	/* tacp: 2,3,4,5 */ +	/* tcah: 0,1,2,4 */ +	/* tcoh: 0,1,2,4 */ +	/* tacc: 1,2,3,4,6,7,10,14 (>4 for nwait) */ +	/* tcos: 0,1,2,4 */ +	/* tacs: 0,1,2,4 */ + +	ret  = calc_0124(bt->tacs, hclk, &res, S3C2410_BANKCON_Tacs_SHIFT); +	ret |= calc_0124(bt->tcos, hclk, &res, S3C2410_BANKCON_Tcos_SHIFT); +	ret |= calc_0124(bt->tcah, hclk, &res, S3C2410_BANKCON_Tcah_SHIFT); +	ret |= calc_0124(bt->tcoh, hclk, &res, S3C2410_BANKCON_Tcoh_SHIFT); + +	if (ret) +		return -EINVAL; + +	ret |= calc_tacp(bt->tacp, hclk, &res); +	ret |= calc_tacc(bt->tacc, bt->nwait_en, hclk, &res); + +	if (ret) +		return -EINVAL; + +	bt->bankcon = res; +	return 0; +} + +static unsigned int tacc_tab[] = { +	[0]	= 1, +	[1]	= 2, +	[2]	= 3, +	[3]	= 4, +	[4]	= 6, +	[5]	= 9, +	[6]	= 10, +	[7]	= 14, +}; + +/** + * get_tacc - turn tACC value into cycle time + * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. + * @val: The bank timing register value, shifed down. + */ +static unsigned int get_tacc(unsigned long hclk_tns, +			     unsigned long val) +{ +	val &= 7; +	return hclk_tns * tacc_tab[val]; +} + +/** + * get_0124 - turn 0/1/2/4 divider into cycle time + * @hclk_tns: The cycle time for HCLK, in 10ths of nanoseconds. + * @val: The bank timing register value, shifed down. + */ +static unsigned int get_0124(unsigned long hclk_tns, +			     unsigned long val) +{ +	val &= 3; +	return hclk_tns * ((val == 3) ? 4 : val); +} + +/** + * s3c2410_iotiming_getbank - turn BANKCON into cycle time information + * @cfg: The frequency configuration + * @bt: The bank timing to fill in (uses cached BANKCON) + * + * Given the BANKCON setting in @bt and the current frequency settings + * in @cfg, update the cycle timing information. + */ +void s3c2410_iotiming_getbank(struct s3c_cpufreq_config *cfg, +			      struct s3c2410_iobank_timing *bt) +{ +	unsigned long bankcon = bt->bankcon; +	unsigned long hclk = cfg->freq.hclk_tns; + +	bt->tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT); +	bt->tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT); +	bt->tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT); +	bt->tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT); +	bt->tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT); +} + +/** + * s3c2410_iotiming_debugfs - debugfs show io bank timing information + * @seq: The seq_file to write output to using seq_printf(). + * @cfg: The current configuration. + * @iob: The IO bank information to decode. + */ +void s3c2410_iotiming_debugfs(struct seq_file *seq, +			      struct s3c_cpufreq_config *cfg, +			      union s3c_iobank *iob) +{ +	struct s3c2410_iobank_timing *bt = iob->io_2410; +	unsigned long bankcon = bt->bankcon; +	unsigned long hclk = cfg->freq.hclk_tns; +	unsigned int tacs; +	unsigned int tcos; +	unsigned int tacc; +	unsigned int tcoh; +	unsigned int tcah; + +	seq_printf(seq, "BANKCON=0x%08lx\n", bankcon); + +	tcah = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcah_SHIFT); +	tcoh = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcoh_SHIFT); +	tcos = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tcos_SHIFT); +	tacs = get_0124(hclk, bankcon >> S3C2410_BANKCON_Tacs_SHIFT); +	tacc = get_tacc(hclk, bankcon >> S3C2410_BANKCON_Tacc_SHIFT); + +	seq_printf(seq, +		   "\tRead: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n", +		   print_ns(bt->tacs), +		   print_ns(bt->tcos), +		   print_ns(bt->tacc), +		   print_ns(bt->tcoh), +		   print_ns(bt->tcah)); + +	seq_printf(seq, +		   "\t Set: Tacs=%d.%d, Tcos=%d.%d, Tacc=%d.%d, Tcoh=%d.%d, Tcah=%d.%d\n", +		   print_ns(tacs), +		   print_ns(tcos), +		   print_ns(tacc), +		   print_ns(tcoh), +		   print_ns(tcah)); +} + +/** + * s3c2410_iotiming_calc - Calculate bank timing for frequency change. + * @cfg: The frequency configuration + * @iot: The IO timing information to fill out. + * + * Calculate the new values for the banks in @iot based on the new + * frequency information in @cfg. This is then used by s3c2410_iotiming_set() + * to update the timing when necessary. + */ +int s3c2410_iotiming_calc(struct s3c_cpufreq_config *cfg, +			  struct s3c_iotimings *iot) +{ +	struct s3c2410_iobank_timing *bt; +	unsigned long bankcon; +	int bank; +	int ret; + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bankcon = __raw_readl(bank_reg(bank)); +		bt = iot->bank[bank].io_2410; + +		if (!bt) +			continue; + +		bt->bankcon = bankcon; + +		ret = s3c2410_calc_bank(cfg, bt); +		if (ret) { +			printk(KERN_ERR "%s: cannot calculate bank %d io\n", +			       __func__, bank); +			goto err; +		} + +		s3c_freq_iodbg("%s: bank %d: con=%08lx\n", +			       __func__, bank, bt->bankcon); +	} + +	return 0; + err: +	return ret; +} + +/** + * s3c2410_iotiming_set - set the IO timings from the given setup. + * @cfg: The frequency configuration + * @iot: The IO timing information to use. + * + * Set all the currently used IO bank timing information generated + * by s3c2410_iotiming_calc() once the core has validated that all + * the new values are within permitted bounds. + */ +void s3c2410_iotiming_set(struct s3c_cpufreq_config *cfg, +			  struct s3c_iotimings *iot) +{ +	struct s3c2410_iobank_timing *bt; +	int bank; + +	/* set the io timings from the specifier */ + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bt = iot->bank[bank].io_2410; +		if (!bt) +			continue; + +		__raw_writel(bt->bankcon, bank_reg(bank)); +	} +} + +/** + * s3c2410_iotiming_get - Get the timing information from current registers. + * @cfg: The frequency configuration + * @timings: The IO timing information to fill out. + * + * Calculate the @timings timing information from the current frequency + * information in @cfg, and the new frequency configur + * through all the IO banks, reading the state and then updating @iot + * as necessary. + * + * This is used at the moment on initialisation to get the current + * configuration so that boards do not have to carry their own setup + * if the timings are correct on initialisation. + */ + +int s3c2410_iotiming_get(struct s3c_cpufreq_config *cfg, +			 struct s3c_iotimings *timings) +{ +	struct s3c2410_iobank_timing *bt; +	unsigned long bankcon; +	unsigned long bwscon; +	int bank; + +	bwscon = __raw_readl(S3C2410_BWSCON); + +	/* look through all banks to see what is currently set. */ + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bankcon = __raw_readl(bank_reg(bank)); + +		if (!bank_is_io(bankcon)) +			continue; + +		s3c_freq_iodbg("%s: bank %d: con %08lx\n", +			       __func__, bank, bankcon); + +		bt = kzalloc(sizeof(struct s3c2410_iobank_timing), GFP_KERNEL); +		if (!bt) { +			printk(KERN_ERR "%s: no memory for bank\n", __func__); +			return -ENOMEM; +		} + +		/* find out in nWait is enabled for bank. */ + +		if (bank != 0) { +			unsigned long tmp  = S3C2410_BWSCON_GET(bwscon, bank); +			if (tmp & S3C2410_BWSCON_WS) +				bt->nwait_en = 1; +		} + +		timings->bank[bank].io_2410 = bt; +		bt->bankcon = bankcon; + +		s3c2410_iotiming_getbank(cfg, bt); +	} + +	s3c2410_print_timing("get", timings); +	return 0; +} diff --git a/arch/arm/mach-s3c24xx/iotiming-s3c2412.c b/arch/arm/mach-s3c24xx/iotiming-s3c2412.c new file mode 100644 index 00000000000..bd064c05c47 --- /dev/null +++ b/arch/arm/mach-s3c24xx/iotiming-s3c2412.c @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2006-2008 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2412/S3C2443 (PL093 based) IO timing support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/cpufreq.h> +#include <linux/seq_file.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/slab.h> + +#include <linux/amba/pl093.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <plat/cpu.h> +#include <plat/cpu-freq-core.h> +#include <plat/clock.h> + +#include <mach/s3c2412.h> + +#define print_ns(x) ((x) / 10), ((x) % 10) + +/** + * s3c2412_print_timing - print timing infromation via printk. + * @pfx: The prefix to print each line with. + * @iot: The IO timing information + */ +static void s3c2412_print_timing(const char *pfx, struct s3c_iotimings *iot) +{ +	struct s3c2412_iobank_timing *bt; +	unsigned int bank; + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bt = iot->bank[bank].io_2412; +		if (!bt) +			continue; + +		printk(KERN_DEBUG "%s: %d: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d" +		       "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", pfx, bank, +		       print_ns(bt->idcy), +		       print_ns(bt->wstrd), +		       print_ns(bt->wstwr), +		       print_ns(bt->wstoen), +		       print_ns(bt->wstwen), +		       print_ns(bt->wstbrd)); +	} +} + +/** + * to_div - turn a cycle length into a divisor setting. + * @cyc_tns: The cycle time in 10ths of nanoseconds. + * @clk_tns: The clock period in 10ths of nanoseconds. + */ +static inline unsigned int to_div(unsigned int cyc_tns, unsigned int clk_tns) +{ +	return cyc_tns ? DIV_ROUND_UP(cyc_tns, clk_tns) : 0; +} + +/** + * calc_timing - calculate timing divisor value and check in range. + * @hwtm: The hardware timing in 10ths of nanoseconds. + * @clk_tns: The clock period in 10ths of nanoseconds. + * @err: Pointer to err variable to update in event of failure. + */ +static unsigned int calc_timing(unsigned int hwtm, unsigned int clk_tns, +				unsigned int *err) +{ +	unsigned int ret = to_div(hwtm, clk_tns); + +	if (ret > 0xf) +		*err = -EINVAL; + +	return ret; +} + +/** + * s3c2412_calc_bank - calculate the bank divisor settings. + * @cfg: The current frequency configuration. + * @bt: The bank timing. + */ +static int s3c2412_calc_bank(struct s3c_cpufreq_config *cfg, +			     struct s3c2412_iobank_timing *bt) +{ +	unsigned int hclk = cfg->freq.hclk_tns; +	int err = 0; + +	bt->smbidcyr = calc_timing(bt->idcy, hclk, &err); +	bt->smbwstrd = calc_timing(bt->wstrd, hclk, &err); +	bt->smbwstwr = calc_timing(bt->wstwr, hclk, &err); +	bt->smbwstoen = calc_timing(bt->wstoen, hclk, &err); +	bt->smbwstwen = calc_timing(bt->wstwen, hclk, &err); +	bt->smbwstbrd = calc_timing(bt->wstbrd, hclk, &err); + +	return err; +} + +/** + * s3c2412_iotiming_debugfs - debugfs show io bank timing information + * @seq: The seq_file to write output to using seq_printf(). + * @cfg: The current configuration. + * @iob: The IO bank information to decode. +*/ +void s3c2412_iotiming_debugfs(struct seq_file *seq, +			      struct s3c_cpufreq_config *cfg, +			      union s3c_iobank *iob) +{ +	struct s3c2412_iobank_timing *bt = iob->io_2412; + +	seq_printf(seq, +		   "\tRead: idcy=%d.%d wstrd=%d.%d wstwr=%d,%d" +		   "wstoen=%d.%d wstwen=%d.%d wstbrd=%d.%d\n", +		   print_ns(bt->idcy), +		   print_ns(bt->wstrd), +		   print_ns(bt->wstwr), +		   print_ns(bt->wstoen), +		   print_ns(bt->wstwen), +		   print_ns(bt->wstbrd)); +} + +/** + * s3c2412_iotiming_calc - calculate all the bank divisor settings. + * @cfg: The current frequency configuration. + * @iot: The bank timing information. + * + * Calculate the timing information for all the banks that are + * configured as IO, using s3c2412_calc_bank(). + */ +int s3c2412_iotiming_calc(struct s3c_cpufreq_config *cfg, +			  struct s3c_iotimings *iot) +{ +	struct s3c2412_iobank_timing *bt; +	int bank; +	int ret; + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bt = iot->bank[bank].io_2412; +		if (!bt) +			continue; + +		ret = s3c2412_calc_bank(cfg, bt); +		if (ret) { +			printk(KERN_ERR "%s: cannot calculate bank %d io\n", +			       __func__, bank); +			goto err; +		} +	} + +	return 0; + err: +	return ret; +} + +/** + * s3c2412_iotiming_set - set the timing information + * @cfg: The current frequency configuration. + * @iot: The bank timing information. + * + * Set the IO bank information from the details calculated earlier from + * calling s3c2412_iotiming_calc(). + */ +void s3c2412_iotiming_set(struct s3c_cpufreq_config *cfg, +			  struct s3c_iotimings *iot) +{ +	struct s3c2412_iobank_timing *bt; +	void __iomem *regs; +	int bank; + +	/* set the io timings from the specifier */ + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		bt = iot->bank[bank].io_2412; +		if (!bt) +			continue; + +		regs = S3C2412_SSMC_BANK(bank); + +		__raw_writel(bt->smbidcyr, regs + SMBIDCYR); +		__raw_writel(bt->smbwstrd, regs + SMBWSTRDR); +		__raw_writel(bt->smbwstwr, regs + SMBWSTWRR); +		__raw_writel(bt->smbwstoen, regs + SMBWSTOENR); +		__raw_writel(bt->smbwstwen, regs + SMBWSTWENR); +		__raw_writel(bt->smbwstbrd, regs + SMBWSTBRDR); +	} +} + +static inline unsigned int s3c2412_decode_timing(unsigned int clock, u32 reg) +{ +	return (reg & 0xf) * clock; +} + +static void s3c2412_iotiming_getbank(struct s3c_cpufreq_config *cfg, +				     struct s3c2412_iobank_timing *bt, +				     unsigned int bank) +{ +	unsigned long clk = cfg->freq.hclk_tns;  /* ssmc clock??? */ +	void __iomem *regs = S3C2412_SSMC_BANK(bank); + +	bt->idcy = s3c2412_decode_timing(clk, __raw_readl(regs + SMBIDCYR)); +	bt->wstrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTRDR)); +	bt->wstoen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTOENR)); +	bt->wstwen = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTWENR)); +	bt->wstbrd = s3c2412_decode_timing(clk, __raw_readl(regs + SMBWSTBRDR)); +} + +/** + * bank_is_io - return true if bank is (possibly) IO. + * @bank: The bank number. + * @bankcfg: The value of S3C2412_EBI_BANKCFG. + */ +static inline bool bank_is_io(unsigned int bank, u32 bankcfg) +{ +	if (bank < 2) +		return true; + +	return !(bankcfg & (1 << bank)); +} + +int s3c2412_iotiming_get(struct s3c_cpufreq_config *cfg, +			 struct s3c_iotimings *timings) +{ +	struct s3c2412_iobank_timing *bt; +	u32 bankcfg = __raw_readl(S3C2412_EBI_BANKCFG); +	unsigned int bank; + +	/* look through all banks to see what is currently set. */ + +	for (bank = 0; bank < MAX_BANKS; bank++) { +		if (!bank_is_io(bank, bankcfg)) +			continue; + +		bt = kzalloc(sizeof(struct s3c2412_iobank_timing), GFP_KERNEL); +		if (!bt) { +			printk(KERN_ERR "%s: no memory for bank\n", __func__); +			return -ENOMEM; +		} + +		timings->bank[bank].io_2412 = bt; +		s3c2412_iotiming_getbank(cfg, bt, bank); +	} + +	s3c2412_print_timing("get", timings); +	return 0; +} + +/* this is in here as it is so small, it doesn't currently warrant a file + * to itself. We expect that any s3c24xx needing this is going to also + * need the iotiming support. + */ +void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) +{ +	struct s3c_cpufreq_board *board = cfg->board; +	u32 refresh; + +	WARN_ON(board == NULL); + +	/* Reduce both the refresh time (in ns) and the frequency (in MHz) +	 * down to ensure that we do not overflow 32 bit numbers. +	 * +	 * This should work for HCLK up to 133MHz and refresh period up +	 * to 30usec. +	 */ + +	refresh = (cfg->freq.hclk / 100) * (board->refresh / 10); +	refresh = DIV_ROUND_UP(refresh, (1000 * 1000)); /* apply scale  */ +	refresh &= ((1 << 16) - 1); + +	s3c_freq_dbg("%s: refresh value %u\n", __func__, (unsigned int)refresh); + +	__raw_writel(refresh, S3C2412_REFRESH); +} diff --git a/arch/arm/mach-s3c24xx/irq-pm.c b/arch/arm/mach-s3c24xx/irq-pm.c new file mode 100644 index 00000000000..b91341ef2b2 --- /dev/null +++ b/arch/arm/mach-s3c24xx/irq-pm.c @@ -0,0 +1,129 @@ +/* linux/arch/arm/plat-s3c24xx/irq-om.c + * + * Copyright (c) 2003-2004 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + *	http://armlinux.simtec.co.uk/ + * + * S3C24XX - IRQ PM code + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/syscore_ops.h> +#include <linux/io.h> + +#include <plat/cpu.h> +#include <plat/pm.h> +#include <plat/map-base.h> +#include <plat/map-s3c.h> + +#include <mach/regs-irq.h> +#include <mach/regs-gpio.h> + +#include <asm/irq.h> + +/* state for IRQs over sleep */ + +/* default is to allow for EINT0..EINT15, and IRQ_RTC as wakeup sources + * + * set bit to 1 in allow bitfield to enable the wakeup settings on it +*/ + +unsigned long s3c_irqwake_intallow	= 1L << 30 | 0xfL; +unsigned long s3c_irqwake_eintallow	= 0x0000fff0L; + +int s3c_irq_wake(struct irq_data *data, unsigned int state) +{ +	unsigned long irqbit = 1 << data->hwirq; + +	if (!(s3c_irqwake_intallow & irqbit)) +		return -ENOENT; + +	pr_info("wake %s for hwirq %lu\n", +		state ? "enabled" : "disabled", data->hwirq); + +	if (!state) +		s3c_irqwake_intmask |= irqbit; +	else +		s3c_irqwake_intmask &= ~irqbit; + +	return 0; +} + +static struct sleep_save irq_save[] = { +	SAVE_ITEM(S3C2410_INTMSK), +	SAVE_ITEM(S3C2410_INTSUBMSK), +}; + +/* the extint values move between the s3c2410/s3c2440 and the s3c2412 + * so we use an array to hold them, and to calculate the address of + * the register at run-time +*/ + +static unsigned long save_extint[3]; +static unsigned long save_eintflt[4]; +static unsigned long save_eintmask; + +static int s3c24xx_irq_suspend(void) +{ +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(save_extint); i++) +		save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4)); + +	for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) +		save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4)); + +	s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); +	save_eintmask = __raw_readl(S3C24XX_EINTMASK); + +	return 0; +} + +static void s3c24xx_irq_resume(void) +{ +	unsigned int i; + +	for (i = 0; i < ARRAY_SIZE(save_extint); i++) +		__raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4)); + +	for (i = 0; i < ARRAY_SIZE(save_eintflt); i++) +		__raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4)); + +	s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); +	__raw_writel(save_eintmask, S3C24XX_EINTMASK); +} + +struct syscore_ops s3c24xx_irq_syscore_ops = { +	.suspend	= s3c24xx_irq_suspend, +	.resume		= s3c24xx_irq_resume, +}; + +#ifdef CONFIG_CPU_S3C2416 +static struct sleep_save s3c2416_irq_save[] = { +	SAVE_ITEM(S3C2416_INTMSK2), +}; + +static int s3c2416_irq_suspend(void) +{ +	s3c_pm_do_save(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save)); + +	return 0; +} + +static void s3c2416_irq_resume(void) +{ +	s3c_pm_do_restore(s3c2416_irq_save, ARRAY_SIZE(s3c2416_irq_save)); +} + +struct syscore_ops s3c2416_irq_syscore_ops = { +	.suspend	= s3c2416_irq_suspend, +	.resume		= s3c2416_irq_resume, +}; +#endif diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c new file mode 100644 index 00000000000..5157e250dd1 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c @@ -0,0 +1,251 @@ +/* linux/arch/arm/mach-s3c2410/mach-amlm5900.c + * + * linux/arch/arm/mach-s3c2410/mach-amlm5900.c + * + * Copyright (c) 2006 American Microsystems Limited + *	David Anders <danders@amltd.com> + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * @History: + * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by + * Ben Dooks <ben@simtec.co.uk> + * + ***********************************************************************/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/proc_fs.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> +#include <asm/mach/flash.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <mach/fb.h> + +#include <mach/regs-lcd.h> +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/gpio-cfg.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> + +#include <plat/samsung-time.h> + +#include "common.h" + +static struct resource amlm5900_nor_resource = +			DEFINE_RES_MEM(0x00000000, SZ_16M); + +static struct mtd_partition amlm5900_mtd_partitions[] = { +	{ +		.name		= "System", +		.size		= 0x240000, +		.offset		= 0, +		.mask_flags 	= MTD_WRITEABLE,  /* force read-only */ +	}, { +		.name		= "Kernel", +		.size		= 0x100000, +		.offset		= MTDPART_OFS_APPEND, +	}, { +		.name		= "Ramdisk", +		.size		= 0x300000, +		.offset		= MTDPART_OFS_APPEND, +	}, { +		.name		= "JFFS2", +		.size		= 0x9A0000, +		.offset		= MTDPART_OFS_APPEND, +	}, { +		.name		= "Settings", +		.size		= MTDPART_SIZ_FULL, +		.offset		= MTDPART_OFS_APPEND, +	} +}; + +static struct physmap_flash_data amlm5900_flash_data = { +	.width		= 2, +	.parts		= amlm5900_mtd_partitions, +	.nr_parts	= ARRAY_SIZE(amlm5900_mtd_partitions), +}; + +static struct platform_device amlm5900_device_nor = { +	.name		= "physmap-flash", +	.id		= 0, +	.dev = { +			.platform_data = &amlm5900_flash_data, +		}, +	.num_resources	= 1, +	.resource	= &amlm5900_nor_resource, +}; + +static struct map_desc amlm5900_iodesc[] __initdata = { +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg amlm5900_uartcfgs[] = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + + +static struct platform_device *amlm5900_devices[] __initdata = { +#ifdef CONFIG_FB_S3C2410 +	&s3c_device_lcd, +#endif +	&s3c_device_adc, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_ohci, + 	&s3c_device_rtc, +	&s3c_device_usbgadget, +        &s3c_device_sdi, +	&amlm5900_device_nor, +}; + +static void __init amlm5900_map_io(void) +{ +	s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc)); +	s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init amlm5900_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +#ifdef CONFIG_FB_S3C2410 +static struct s3c2410fb_display __initdata amlm5900_lcd_info = { +	.width		= 160, +	.height		= 160, + +	.type		= S3C2410_LCDCON1_STN4, + +	.pixclock	= 680000, /* HCLK = 100MHz */ +	.xres		= 160, +	.yres		= 160, +	.bpp		= 4, +	.left_margin	= 1 << (4 + 3), +	.right_margin	= 8 << 3, +	.hsync_len	= 48, +	.upper_margin	= 0, +	.lower_margin	= 0, + +	.lcdcon5	= 0x00000001, +}; + +static struct s3c2410fb_mach_info __initdata amlm5900_fb_info = { + +	.displays = &amlm5900_lcd_info, +	.num_displays = 1, +	.default_display = 0, + +	.gpccon =	0xaaaaaaaa, +	.gpccon_mask =	0xffffffff, +	.gpcup =	0x0000ffff, +	.gpcup_mask =	0xffffffff, + +	.gpdcon =	0xaaaaaaaa, +	.gpdcon_mask =	0xffffffff, +	.gpdup =	0x0000ffff, +	.gpdup_mask =	0xffffffff, +}; +#endif + +static irqreturn_t +amlm5900_wake_interrupt(int irq, void *ignored) +{ +	return IRQ_HANDLED; +} + +static void amlm5900_init_pm(void) +{ +	int ret = 0; + +	ret = request_irq(IRQ_EINT9, &amlm5900_wake_interrupt, +				IRQF_TRIGGER_RISING | IRQF_SHARED, +				"amlm5900_wakeup", &amlm5900_wake_interrupt); +	if (ret != 0) { +		printk(KERN_ERR "AML-M5900: no wakeup irq, %d?\n", ret); +	} else { +		enable_irq_wake(IRQ_EINT9); +		/* configure the suspend/resume status pin */ +		s3c_gpio_cfgpin(S3C2410_GPF(2), S3C2410_GPIO_OUTPUT); +		s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_UP); +	} +} +static void __init amlm5900_init(void) +{ +	amlm5900_init_pm(); +#ifdef CONFIG_FB_S3C2410 +	s3c24xx_fb_set_platdata(&amlm5900_fb_info); +#endif +	s3c_i2c0_set_platdata(NULL); +	platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices)); +} + +MACHINE_START(AML_M5900, "AML_M5900") +	.atag_offset	= 0x100, +	.map_io		= amlm5900_map_io, +	.init_irq	= s3c2410_init_irq, +	.init_machine	= amlm5900_init, +	.init_time	= amlm5900_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c new file mode 100644 index 00000000000..e053581cab0 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -0,0 +1,434 @@ +/* linux/arch/arm/mach-s3c2440/mach-anubis.c + * + * Copyright 2003-2009 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/ata_platform.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/sm501.h> +#include <linux/sm501-regs.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <net/ax88796.h> + +#include <plat/devs.h> +#include <plat/cpu.h> +#include <linux/platform_data/asoc-s3c24xx_simtec.h> +#include <plat/samsung-time.h> + +#include "anubis.h" +#include "common.h" +#include "simtec.h" + +#define COPYRIGHT ", Copyright 2005-2009 Simtec Electronics" + +static struct map_desc anubis_iodesc[] __initdata = { +  /* ISA IO areas */ + +  { +	.virtual	= (u32)S3C24XX_VA_ISA_BYTE, +	.pfn		= __phys_to_pfn(0x0), +	.length		= SZ_4M, +	.type		= MT_DEVICE, +  }, { +	.virtual	= (u32)S3C24XX_VA_ISA_WORD, +	.pfn		= __phys_to_pfn(0x0), +	.length 	= SZ_4M, +	.type		= MT_DEVICE, +  }, + +  /* we could possibly compress the next set down into a set of smaller tables +   * pagetables, but that would mean using an L2 section, and it still means +   * we cannot actually feed the same register to an LDR due to 16K spacing +   */ + +  /* CPLD control registers */ + +  { +	.virtual	= (u32)ANUBIS_VA_CTRL1, +	.pfn		= __phys_to_pfn(ANUBIS_PA_CTRL1), +	.length		= SZ_4K, +	.type		= MT_DEVICE, +  }, { +	.virtual	= (u32)ANUBIS_VA_IDREG, +	.pfn		= __phys_to_pfn(ANUBIS_PA_IDREG), +	.length		= SZ_4K, +	.type		= MT_DEVICE, +  }, +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg anubis_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	}, +	[1] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	}, +}; + +/* NAND Flash on Anubis board */ + +static int external_map[]   = { 2 }; +static int chip0_map[]      = { 0 }; +static int chip1_map[]      = { 1 }; + +static struct mtd_partition __initdata anubis_default_nand_part[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_16K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "/boot", +		.size	= SZ_4M - SZ_16K, +		.offset	= SZ_16K, +	}, +	[2] = { +		.name	= "user1", +		.offset	= SZ_4M, +		.size	= SZ_32M - SZ_4M, +	}, +	[3] = { +		.name	= "user2", +		.offset	= SZ_32M, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +static struct mtd_partition __initdata anubis_default_nand_part_large[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_128K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "/boot", +		.size	= SZ_4M - SZ_128K, +		.offset	= SZ_128K, +	}, +	[2] = { +		.name	= "user1", +		.offset	= SZ_4M, +		.size	= SZ_32M - SZ_4M, +	}, +	[3] = { +		.name	= "user2", +		.offset	= SZ_32M, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +/* the Anubis has 3 selectable slots for nand-flash, the two + * on-board chip areas, as well as the external slot. + * + * Note, there is no current hot-plug support for the External + * socket. +*/ + +static struct s3c2410_nand_set __initdata anubis_nand_sets[] = { +	[1] = { +		.name		= "External", +		.nr_chips	= 1, +		.nr_map		= external_map, +		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part), +		.partitions	= anubis_default_nand_part, +	}, +	[0] = { +		.name		= "chip0", +		.nr_chips	= 1, +		.nr_map		= chip0_map, +		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part), +		.partitions	= anubis_default_nand_part, +	}, +	[2] = { +		.name		= "chip1", +		.nr_chips	= 1, +		.nr_map		= chip1_map, +		.nr_partitions	= ARRAY_SIZE(anubis_default_nand_part), +		.partitions	= anubis_default_nand_part, +	}, +}; + +static void anubis_nand_select(struct s3c2410_nand_set *set, int slot) +{ +	unsigned int tmp; + +	slot = set->nr_map[slot] & 3; + +	pr_debug("anubis_nand: selecting slot %d (set %p,%p)\n", +		 slot, set, set->nr_map); + +	tmp = __raw_readb(ANUBIS_VA_CTRL1); +	tmp &= ~ANUBIS_CTRL1_NANDSEL; +	tmp |= slot; + +	pr_debug("anubis_nand: ctrl1 now %02x\n", tmp); + +	__raw_writeb(tmp, ANUBIS_VA_CTRL1); +} + +static struct s3c2410_platform_nand __initdata anubis_nand_info = { +	.tacls		= 25, +	.twrph0		= 55, +	.twrph1		= 40, +	.nr_sets	= ARRAY_SIZE(anubis_nand_sets), +	.sets		= anubis_nand_sets, +	.select_chip	= anubis_nand_select, +}; + +/* IDE channels */ + +static struct pata_platform_info anubis_ide_platdata = { +	.ioport_shift	= 5, +}; + +static struct resource anubis_ide0_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS3, 8 * 32), +	[2] = DEFINE_RES_MEM(S3C2410_CS3 + (1 << 26) + (6 * 32), 32), +	[3] = DEFINE_RES_IRQ(ANUBIS_IRQ_IDE0), +}; + +static struct platform_device anubis_device_ide0 = { +	.name		= "pata_platform", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(anubis_ide0_resource), +	.resource	= anubis_ide0_resource, +	.dev	= { +		.platform_data = &anubis_ide_platdata, +		.coherent_dma_mask = ~0, +	}, +}; + +static struct resource anubis_ide1_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS4, 8 * 32), +	[1] = DEFINE_RES_MEM(S3C2410_CS4 + (1 << 26) + (6 * 32), 32), +	[2] = DEFINE_RES_IRQ(ANUBIS_IRQ_IDE0), +}; + +static struct platform_device anubis_device_ide1 = { +	.name		= "pata_platform", +	.id		= 1, +	.num_resources	= ARRAY_SIZE(anubis_ide1_resource), +	.resource	= anubis_ide1_resource, +	.dev	= { +		.platform_data = &anubis_ide_platdata, +		.coherent_dma_mask = ~0, +	}, +}; + +/* Asix AX88796 10/100 ethernet controller */ + +static struct ax_plat_data anubis_asix_platdata = { +	.flags		= AXFLG_MAC_FROMDEV, +	.wordlength	= 2, +	.dcr_val	= 0x48, +	.rcr_val	= 0x40, +}; + +static struct resource anubis_asix_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS5, 0x20 * 0x20), +	[1] = DEFINE_RES_IRQ(ANUBIS_IRQ_ASIX), +}; + +static struct platform_device anubis_device_asix = { +	.name		= "ax88796", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(anubis_asix_resource), +	.resource	= anubis_asix_resource, +	.dev		= { +		.platform_data = &anubis_asix_platdata, +	} +}; + +/* SM501 */ + +static struct resource anubis_sm501_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS2, SZ_8M), +	[1] = DEFINE_RES_MEM(S3C2410_CS2 + SZ_64M - SZ_2M, SZ_2M), +	[2] = DEFINE_RES_IRQ(IRQ_EINT0), +}; + +static struct sm501_initdata anubis_sm501_initdata = { +	.gpio_high	= { +		.set	= 0x3F000000,		/* 24bit panel */ +		.mask	= 0x0, +	}, +	.misc_timing	= { +		.set	= 0x010100,		/* SDRAM timing */ +		.mask	= 0x1F1F00, +	}, +	.misc_control	= { +		.set	= SM501_MISC_PNL_24BIT, +		.mask	= 0, +	}, + +	.devices	= SM501_USE_GPIO, + +	/* set the SDRAM and bus clocks */ +	.mclk		= 72 * MHZ, +	.m1xclk		= 144 * MHZ, +}; + +static struct sm501_platdata_gpio_i2c anubis_sm501_gpio_i2c[] = { +	[0] = { +		.bus_num	= 1, +		.pin_scl	= 44, +		.pin_sda	= 45, +	}, +	[1] = { +		.bus_num	= 2, +		.pin_scl	= 40, +		.pin_sda	= 41, +	}, +}; + +static struct sm501_platdata anubis_sm501_platdata = { +	.init		= &anubis_sm501_initdata, +	.gpio_base	= -1, +	.gpio_i2c	= anubis_sm501_gpio_i2c, +	.gpio_i2c_nr	= ARRAY_SIZE(anubis_sm501_gpio_i2c), +}; + +static struct platform_device anubis_device_sm501 = { +	.name		= "sm501", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(anubis_sm501_resource), +	.resource	= anubis_sm501_resource, +	.dev		= { +		.platform_data = &anubis_sm501_platdata, +	}, +}; + +/* Standard Anubis devices */ + +static struct platform_device *anubis_devices[] __initdata = { +	&s3c2410_device_dclk, +	&s3c_device_ohci, +	&s3c_device_wdt, +	&s3c_device_adc, +	&s3c_device_i2c0, + 	&s3c_device_rtc, +	&s3c_device_nand, +	&anubis_device_ide0, +	&anubis_device_ide1, +	&anubis_device_asix, +	&anubis_device_sm501, +}; + +/* I2C devices. */ + +static struct i2c_board_info anubis_i2c_devs[] __initdata = { +	{ +		I2C_BOARD_INFO("tps65011", 0x48), +		.irq	= IRQ_EINT20, +	} +}; + +/* Audio setup */ +static struct s3c24xx_audio_simtec_pdata __initdata anubis_audio = { +	.have_mic	= 1, +	.have_lout	= 1, +	.output_cdclk	= 1, +	.use_mpllin	= 1, +	.amp_gpio	= S3C2410_GPB(2), +	.amp_gain[0]	= S3C2410_GPD(10), +	.amp_gain[1]	= S3C2410_GPD(11), +}; + +static void __init anubis_map_io(void) +{ +	s3c24xx_init_io(anubis_iodesc, ARRAY_SIZE(anubis_iodesc)); +	s3c24xx_init_uarts(anubis_uartcfgs, ARRAY_SIZE(anubis_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); + +	/* check for the newer revision boards with large page nand */ + +	if ((__raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK) >= 4) { +		printk(KERN_INFO "ANUBIS-B detected (revision %d)\n", +		       __raw_readb(ANUBIS_VA_IDREG) & ANUBIS_IDREG_REVMASK); +		anubis_nand_sets[0].partitions = anubis_default_nand_part_large; +		anubis_nand_sets[0].nr_partitions = ARRAY_SIZE(anubis_default_nand_part_large); +	} else { +		/* ensure that the GPIO is setup */ +		gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL); +		gpio_free(S3C2410_GPA(0)); +	} +} + +static void __init anubis_init_time(void) +{ +	s3c2440_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init anubis_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	s3c_nand_set_platdata(&anubis_nand_info); +	simtec_audio_add(NULL, false, &anubis_audio); + +	platform_add_devices(anubis_devices, ARRAY_SIZE(anubis_devices)); + +	i2c_register_board_info(0, anubis_i2c_devs, +				ARRAY_SIZE(anubis_i2c_devs)); +} + + +MACHINE_START(ANUBIS, "Simtec-Anubis") +	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */ +	.atag_offset	= 0x100, +	.map_io		= anubis_map_io, +	.init_machine	= anubis_init, +	.init_irq	= s3c2440_init_irq, +	.init_time	= anubis_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c new file mode 100644 index 00000000000..9db768f448a --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -0,0 +1,222 @@ +/* linux/arch/arm/mach-s3c2440/mach-at2440evb.c + * + * Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com> + *      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk> + *      and modifications by SBZ <sbz@spgui.org> and + *      Weibing <http://weibing.blogbus.com> + * + * For product information, visit http://www.arm.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/types.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/dm9000.h> +#include <linux/platform_device.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/fb.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <plat/devs.h> +#include <plat/cpu.h> +#include <linux/platform_data/mmc-s3cmci.h> +#include <plat/samsung-time.h> + +#include "common.h" + +static struct map_desc at2440evb_iodesc[] __initdata = { +	/* Nothing here */ +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE) +#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) + +static struct s3c2410_uartcfg at2440evb_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	}, +}; + +/* NAND Flash on AT2440EVB board */ + +static struct mtd_partition __initdata at2440evb_default_nand_part[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_256K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "Kernel", +		.size	= SZ_2M, +		.offset	= SZ_256K, +	}, +	[2] = { +		.name	= "Root", +		.offset	= SZ_256K + SZ_2M, +		.size	= MTDPART_SIZ_FULL, +	}, +}; + +static struct s3c2410_nand_set __initdata at2440evb_nand_sets[] = { +	[0] = { +		.name		= "nand", +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(at2440evb_default_nand_part), +		.partitions	= at2440evb_default_nand_part, +	}, +}; + +static struct s3c2410_platform_nand __initdata at2440evb_nand_info = { +	.tacls		= 25, +	.twrph0		= 55, +	.twrph1		= 40, +	.nr_sets	= ARRAY_SIZE(at2440evb_nand_sets), +	.sets		= at2440evb_nand_sets, +}; + +/* DM9000AEP 10/100 ethernet controller */ + +static struct resource at2440evb_dm9k_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS3, 4), +	[1] = DEFINE_RES_MEM(S3C2410_CS3 + 4, 4), +	[2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \ +					| IORESOURCE_IRQ_HIGHEDGE), +}; + +static struct dm9000_plat_data at2440evb_dm9k_pdata = { +	.flags		= (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), +}; + +static struct platform_device at2440evb_device_eth = { +	.name		= "dm9000", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(at2440evb_dm9k_resource), +	.resource	= at2440evb_dm9k_resource, +	.dev		= { +		.platform_data	= &at2440evb_dm9k_pdata, +	}, +}; + +static struct s3c24xx_mci_pdata at2440evb_mci_pdata __initdata = { +	.gpio_detect	= S3C2410_GPG(10), +}; + +/* 7" LCD panel */ + +static struct s3c2410fb_display at2440evb_lcd_cfg __initdata = { + +	.lcdcon5	= S3C2410_LCDCON5_FRM565 | +			  S3C2410_LCDCON5_INVVLINE | +			  S3C2410_LCDCON5_INVVFRAME | +			  S3C2410_LCDCON5_PWREN | +			  S3C2410_LCDCON5_HWSWP, + +	.type		= S3C2410_LCDCON1_TFT, + +	.width		= 800, +	.height		= 480, + +	.pixclock	= 33333, /* HCLK 60 MHz, divisor 2 */ +	.xres		= 800, +	.yres		= 480, +	.bpp		= 16, +	.left_margin	= 88, +	.right_margin	= 40, +	.hsync_len	= 128, +	.upper_margin	= 32, +	.lower_margin	= 11, +	.vsync_len	= 2, +}; + +static struct s3c2410fb_mach_info at2440evb_fb_info __initdata = { +	.displays	= &at2440evb_lcd_cfg, +	.num_displays	= 1, +	.default_display = 0, +}; + +static struct platform_device *at2440evb_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_wdt, +	&s3c_device_adc, +	&s3c_device_i2c0, +	&s3c_device_rtc, +	&s3c_device_nand, +	&s3c_device_sdi, +	&s3c_device_lcd, +	&at2440evb_device_eth, +}; + +static void __init at2440evb_map_io(void) +{ +	s3c24xx_init_io(at2440evb_iodesc, ARRAY_SIZE(at2440evb_iodesc)); +	s3c24xx_init_uarts(at2440evb_uartcfgs, ARRAY_SIZE(at2440evb_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init at2440evb_init_time(void) +{ +	s3c2440_init_clocks(16934400); +	samsung_timer_init(); +} + +static void __init at2440evb_init(void) +{ +	s3c24xx_fb_set_platdata(&at2440evb_fb_info); +	s3c24xx_mci_set_platdata(&at2440evb_mci_pdata); +	s3c_nand_set_platdata(&at2440evb_nand_info); +	s3c_i2c0_set_platdata(NULL); + +	platform_add_devices(at2440evb_devices, ARRAY_SIZE(at2440evb_devices)); +} + + +MACHINE_START(AT2440EVB, "AT2440EVB") +	.atag_offset	= 0x100, +	.map_io		= at2440evb_map_io, +	.init_machine	= at2440evb_init, +	.init_irq	= s3c2440_init_irq, +	.init_time	= at2440evb_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c new file mode 100644 index 00000000000..f9112b801a3 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -0,0 +1,595 @@ +/* linux/arch/arm/mach-s3c2410/mach-bast.c + * + * Copyright 2003-2008 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/syscore_ops.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/dm9000.h> +#include <linux/ata_platform.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/serial_8250.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <linux/platform_data/asoc-s3c24xx_simtec.h> +#include <linux/platform_data/hwmon-s3c.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include <net/ax88796.h> + +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> +#include <asm/mach-types.h> + +#include <mach/fb.h> +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> + +#include <plat/cpu.h> +#include <plat/cpu-freq.h> +#include <plat/devs.h> +#include <plat/gpio-cfg.h> +#include <plat/samsung-time.h> + +#include "bast.h" +#include "common.h" +#include "simtec.h" + +#define COPYRIGHT ", Copyright 2004-2008 Simtec Electronics" + +/* macros for virtual address mods for the io space entries */ +#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5) +#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4) +#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3) +#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2) + +/* macros to modify the physical addresses for io space */ + +#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2)) +#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3)) +#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4)) +#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5)) + +static struct map_desc bast_iodesc[] __initdata = { +  /* ISA IO areas */ +  { +	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE, +	  .pfn		= PA_CS2(BAST_PA_ISAIO), +	  .length	= SZ_16M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)S3C24XX_VA_ISA_WORD, +	  .pfn		= PA_CS3(BAST_PA_ISAIO), +	  .length	= SZ_16M, +	  .type		= MT_DEVICE, +  }, +  /* bast CPLD control registers, and external interrupt controls */ +  { +	  .virtual	= (u32)BAST_VA_CTRL1, +	  .pfn		= __phys_to_pfn(BAST_PA_CTRL1), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)BAST_VA_CTRL2, +	  .pfn		= __phys_to_pfn(BAST_PA_CTRL2), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)BAST_VA_CTRL3, +	  .pfn		= __phys_to_pfn(BAST_PA_CTRL3), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)BAST_VA_CTRL4, +	  .pfn		= __phys_to_pfn(BAST_PA_CTRL4), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, +  /* PC104 IRQ mux */ +  { +	  .virtual	= (u32)BAST_VA_PC104_IRQREQ, +	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQREQ), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)BAST_VA_PC104_IRQRAW, +	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQRAW), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)BAST_VA_PC104_IRQMASK, +	  .pfn		= __phys_to_pfn(BAST_PA_PC104_IRQMASK), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, + +  /* peripheral space... one for each of fast/slow/byte/16bit */ +  /* note, ide is only decoded in word space, even though some registers +   * are only 8bit */ + +  /* slow, byte */ +  { VA_C2(BAST_VA_ISAIO),   PA_CS2(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE }, +  { VA_C2(BAST_VA_ISAMEM),  PA_CS2(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE }, +  { VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE }, + +  /* slow, word */ +  { VA_C3(BAST_VA_ISAIO),   PA_CS3(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE }, +  { VA_C3(BAST_VA_ISAMEM),  PA_CS3(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE }, +  { VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE }, + +  /* fast, byte */ +  { VA_C4(BAST_VA_ISAIO),   PA_CS4(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE }, +  { VA_C4(BAST_VA_ISAMEM),  PA_CS4(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE }, +  { VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE }, + +  /* fast, word */ +  { VA_C5(BAST_VA_ISAIO),   PA_CS5(BAST_PA_ISAIO),    SZ_16M, MT_DEVICE }, +  { VA_C5(BAST_VA_ISAMEM),  PA_CS5(BAST_PA_ISAMEM),   SZ_16M, MT_DEVICE }, +  { VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO),  SZ_1M,  MT_DEVICE }, +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg bast_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	/* port 2 is not actually used */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +/* NAND Flash on BAST board */ + +#ifdef CONFIG_PM +static int bast_pm_suspend(void) +{ +	/* ensure that an nRESET is not generated on resume. */ +	gpio_direction_output(S3C2410_GPA(21), 1); +	return 0; +} + +static void bast_pm_resume(void) +{ +	s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); +} + +#else +#define bast_pm_suspend NULL +#define bast_pm_resume NULL +#endif + +static struct syscore_ops bast_pm_syscore_ops = { +	.suspend	= bast_pm_suspend, +	.resume		= bast_pm_resume, +}; + +static int smartmedia_map[] = { 0 }; +static int chip0_map[] = { 1 }; +static int chip1_map[] = { 2 }; +static int chip2_map[] = { 3 }; + +static struct mtd_partition __initdata bast_default_nand_part[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_16K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "/boot", +		.size	= SZ_4M - SZ_16K, +		.offset	= SZ_16K, +	}, +	[2] = { +		.name	= "user", +		.offset	= SZ_4M, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +/* the bast has 4 selectable slots for nand-flash, the three + * on-board chip areas, as well as the external SmartMedia + * slot. + * + * Note, there is no current hot-plug support for the SmartMedia + * socket. +*/ + +static struct s3c2410_nand_set __initdata bast_nand_sets[] = { +	[0] = { +		.name		= "SmartMedia", +		.nr_chips	= 1, +		.nr_map		= smartmedia_map, +		.options        = NAND_SCAN_SILENT_NODEV, +		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part), +		.partitions	= bast_default_nand_part, +	}, +	[1] = { +		.name		= "chip0", +		.nr_chips	= 1, +		.nr_map		= chip0_map, +		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part), +		.partitions	= bast_default_nand_part, +	}, +	[2] = { +		.name		= "chip1", +		.nr_chips	= 1, +		.nr_map		= chip1_map, +		.options        = NAND_SCAN_SILENT_NODEV, +		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part), +		.partitions	= bast_default_nand_part, +	}, +	[3] = { +		.name		= "chip2", +		.nr_chips	= 1, +		.nr_map		= chip2_map, +		.options        = NAND_SCAN_SILENT_NODEV, +		.nr_partitions	= ARRAY_SIZE(bast_default_nand_part), +		.partitions	= bast_default_nand_part, +	} +}; + +static void bast_nand_select(struct s3c2410_nand_set *set, int slot) +{ +	unsigned int tmp; + +	slot = set->nr_map[slot] & 3; + +	pr_debug("bast_nand: selecting slot %d (set %p,%p)\n", +		 slot, set, set->nr_map); + +	tmp = __raw_readb(BAST_VA_CTRL2); +	tmp &= BAST_CPLD_CTLR2_IDERST; +	tmp |= slot; +	tmp |= BAST_CPLD_CTRL2_WNAND; + +	pr_debug("bast_nand: ctrl2 now %02x\n", tmp); + +	__raw_writeb(tmp, BAST_VA_CTRL2); +} + +static struct s3c2410_platform_nand __initdata bast_nand_info = { +	.tacls		= 30, +	.twrph0		= 60, +	.twrph1		= 60, +	.nr_sets	= ARRAY_SIZE(bast_nand_sets), +	.sets		= bast_nand_sets, +	.select_chip	= bast_nand_select, +}; + +/* DM9000 */ + +static struct resource bast_dm9k_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000, 4), +	[1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_DM9000 + 0x40, 0x40), +	[2] = DEFINE_RES_NAMED(BAST_IRQ_DM9000 , 1, NULL, IORESOURCE_IRQ \ +					| IORESOURCE_IRQ_HIGHLEVEL), +}; + +/* for the moment we limit ourselves to 16bit IO until some + * better IO routines can be written and tested +*/ + +static struct dm9000_plat_data bast_dm9k_platdata = { +	.flags		= DM9000_PLATF_16BITONLY, +}; + +static struct platform_device bast_device_dm9k = { +	.name		= "dm9000", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(bast_dm9k_resource), +	.resource	= bast_dm9k_resource, +	.dev		= { +		.platform_data = &bast_dm9k_platdata, +	} +}; + +/* serial devices */ + +#define SERIAL_BASE  (S3C2410_CS2 + BAST_PA_SUPERIO) +#define SERIAL_FLAGS (UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SHARE_IRQ) +#define SERIAL_CLK   (1843200) + +static struct plat_serial8250_port bast_sio_data[] = { +	[0] = { +		.mapbase	= SERIAL_BASE + 0x2f8, +		.irq		= BAST_IRQ_PCSERIAL1, +		.flags		= SERIAL_FLAGS, +		.iotype		= UPIO_MEM, +		.regshift	= 0, +		.uartclk	= SERIAL_CLK, +	}, +	[1] = { +		.mapbase	= SERIAL_BASE + 0x3f8, +		.irq		= BAST_IRQ_PCSERIAL2, +		.flags		= SERIAL_FLAGS, +		.iotype		= UPIO_MEM, +		.regshift	= 0, +		.uartclk	= SERIAL_CLK, +	}, +	{ } +}; + +static struct platform_device bast_sio = { +	.name			= "serial8250", +	.id			= PLAT8250_DEV_PLATFORM, +	.dev			= { +		.platform_data	= &bast_sio_data, +	}, +}; + +/* we have devices on the bus which cannot work much over the + * standard 100KHz i2c bus frequency +*/ + +static struct s3c2410_platform_i2c __initdata bast_i2c_info = { +	.flags		= 0, +	.slave_addr	= 0x10, +	.frequency	= 100*1000, +}; + +/* Asix AX88796 10/100 ethernet controller */ + +static struct ax_plat_data bast_asix_platdata = { +	.flags		= AXFLG_MAC_FROMDEV, +	.wordlength	= 2, +	.dcr_val	= 0x48, +	.rcr_val	= 0x40, +}; + +static struct resource bast_asix_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET, 0x18 * 0x20), +	[1] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x1f * 0x20), 1), +	[2] = DEFINE_RES_IRQ(BAST_IRQ_ASIX), +}; + +static struct platform_device bast_device_asix = { +	.name		= "ax88796", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(bast_asix_resource), +	.resource	= bast_asix_resource, +	.dev		= { +		.platform_data = &bast_asix_platdata +	} +}; + +/* Asix AX88796 10/100 ethernet controller parallel port */ + +static struct resource bast_asixpp_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS5 + BAST_PA_ASIXNET + (0x18 * 0x20), \ +					0x30 * 0x20), +}; + +static struct platform_device bast_device_axpp = { +	.name		= "ax88796-pp", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(bast_asixpp_resource), +	.resource	= bast_asixpp_resource, +}; + +/* LCD/VGA controller */ + +static struct s3c2410fb_display __initdata bast_lcd_info[] = { +	{ +		.type		= S3C2410_LCDCON1_TFT, +		.width		= 640, +		.height		= 480, + +		.pixclock	= 33333, +		.xres		= 640, +		.yres		= 480, +		.bpp		= 4, +		.left_margin	= 40, +		.right_margin	= 20, +		.hsync_len	= 88, +		.upper_margin	= 30, +		.lower_margin	= 32, +		.vsync_len	= 3, + +		.lcdcon5	= 0x00014b02, +	}, +	{ +		.type		= S3C2410_LCDCON1_TFT, +		.width		= 640, +		.height		= 480, + +		.pixclock	= 33333, +		.xres		= 640, +		.yres		= 480, +		.bpp		= 8, +		.left_margin	= 40, +		.right_margin	= 20, +		.hsync_len	= 88, +		.upper_margin	= 30, +		.lower_margin	= 32, +		.vsync_len	= 3, + +		.lcdcon5	= 0x00014b02, +	}, +	{ +		.type		= S3C2410_LCDCON1_TFT, +		.width		= 640, +		.height		= 480, + +		.pixclock	= 33333, +		.xres		= 640, +		.yres		= 480, +		.bpp		= 16, +		.left_margin	= 40, +		.right_margin	= 20, +		.hsync_len	= 88, +		.upper_margin	= 30, +		.lower_margin	= 32, +		.vsync_len	= 3, + +		.lcdcon5	= 0x00014b02, +	}, +}; + +/* LCD/VGA controller */ + +static struct s3c2410fb_mach_info __initdata bast_fb_info = { + +	.displays = bast_lcd_info, +	.num_displays = ARRAY_SIZE(bast_lcd_info), +	.default_display = 1, +}; + +/* I2C devices fitted. */ + +static struct i2c_board_info bast_i2c_devs[] __initdata = { +	{ +		I2C_BOARD_INFO("tlv320aic23", 0x1a), +	}, { +		I2C_BOARD_INFO("simtec-pmu", 0x6b), +	}, { +		I2C_BOARD_INFO("ch7013", 0x75), +	}, +}; + +static struct s3c_hwmon_pdata bast_hwmon_info = { +	/* LCD contrast (0-6.6V) */ +	.in[0] = &(struct s3c_hwmon_chcfg) { +		.name		= "lcd-contrast", +		.mult		= 3300, +		.div		= 512, +	}, +	/* LED current feedback */ +	.in[1] = &(struct s3c_hwmon_chcfg) { +		.name		= "led-feedback", +		.mult		= 3300, +		.div		= 1024, +	}, +	/* LCD feedback (0-6.6V) */ +	.in[2] = &(struct s3c_hwmon_chcfg) { +		.name		= "lcd-feedback", +		.mult		= 3300, +		.div		= 512, +	}, +	/* Vcore (1.8-2.0V), Vref 3.3V  */ +	.in[3] = &(struct s3c_hwmon_chcfg) { +		.name		= "vcore", +		.mult		= 3300, +		.div		= 1024, +	}, +}; + +/* Standard BAST devices */ +// cat /sys/devices/platform/s3c24xx-adc/s3c-hwmon/in_0 + +static struct platform_device *bast_devices[] __initdata = { +	&s3c2410_device_dclk, +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, + 	&s3c_device_rtc, +	&s3c_device_nand, +	&s3c_device_adc, +	&s3c_device_hwmon, +	&bast_device_dm9k, +	&bast_device_asix, +	&bast_device_axpp, +	&bast_sio, +}; + +static struct s3c_cpufreq_board __initdata bast_cpufreq = { +	.refresh	= 7800, /* 7.8usec */ +	.auto_io	= 1, +	.need_io	= 1, +}; + +static struct s3c24xx_audio_simtec_pdata __initdata bast_audio = { +	.have_mic	= 1, +	.have_lout	= 1, +}; + +static void __init bast_map_io(void) +{ +	s3c_hwmon_set_platdata(&bast_hwmon_info); + +	s3c24xx_init_io(bast_iodesc, ARRAY_SIZE(bast_iodesc)); +	s3c24xx_init_uarts(bast_uartcfgs, ARRAY_SIZE(bast_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init bast_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init bast_init(void) +{ +	register_syscore_ops(&bast_pm_syscore_ops); + +	s3c_i2c0_set_platdata(&bast_i2c_info); +	s3c_nand_set_platdata(&bast_nand_info); +	s3c24xx_fb_set_platdata(&bast_fb_info); +	platform_add_devices(bast_devices, ARRAY_SIZE(bast_devices)); + +	i2c_register_board_info(0, bast_i2c_devs, +				ARRAY_SIZE(bast_i2c_devs)); + +	usb_simtec_init(); +	nor_simtec_init(); +	simtec_audio_add(NULL, true, &bast_audio); + +	WARN_ON(gpio_request(S3C2410_GPA(21), "bast nreset")); +	 +	s3c_cpufreq_setboard(&bast_cpufreq); +} + +MACHINE_START(BAST, "Simtec-BAST") +	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */ +	.atag_offset	= 0x100, +	.map_io		= bast_map_io, +	.init_irq	= s3c2410_init_irq, +	.init_machine	= bast_init, +	.init_time	= bast_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c new file mode 100644 index 00000000000..fc3a08d0cb3 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -0,0 +1,601 @@ +/* + * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner. + * + * Copyright (C) 2006-2009 by Openmoko, Inc. + * Authors: Harald Welte <laforge@openmoko.org> + *          Andy Green <andy@openmoko.org> + *          Werner Almesberger <werner@openmoko.org> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/i2c.h> + +#include <linux/mmc/host.h> + +#include <linux/mfd/pcf50633/adc.h> +#include <linux/mfd/pcf50633/backlight.h> +#include <linux/mfd/pcf50633/core.h> +#include <linux/mfd/pcf50633/gpio.h> +#include <linux/mfd/pcf50633/mbc.h> +#include <linux/mfd/pcf50633/pmic.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/physmap.h> + +#include <linux/regulator/machine.h> + +#include <linux/spi/spi.h> +#include <linux/spi/s3c24xx.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/touchscreen-s3c2410.h> +#include <linux/platform_data/usb-ohci-s3c2410.h> +#include <linux/platform_data/usb-s3c2410_udc.h> + +#include <mach/fb.h> +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/regs-irq.h> +#include <mach/gpio-samsung.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/gpio-cfg.h> +#include <plat/pm.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "gta02.h" + +static struct pcf50633 *gta02_pcf; + +/* + * This gets called frequently when we paniced. + */ + +static long gta02_panic_blink(int state) +{ +	long delay = 0; +	char led; + +	led = (state) ? 1 : 0; +	gpio_direction_output(GTA02_GPIO_AUX_LED, led); + +	return delay; +} + + +static struct map_desc gta02_iodesc[] __initdata = { +	{ +		.virtual	= 0xe0000000, +		.pfn		= __phys_to_pfn(S3C2410_CS3 + 0x01000000), +		.length		= SZ_1M, +		.type		= MT_DEVICE +	}, +}; + +#define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN) +#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) +#define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) + +static struct s3c2410_uartcfg gta02_uartcfgs[] = { +	[0] = { +		.hwport		= 0, +		.flags		= 0, +		.ucon		= UCON, +		.ulcon		= ULCON, +		.ufcon		= UFCON, +	}, +	[1] = { +		.hwport		= 1, +		.flags		= 0, +		.ucon		= UCON, +		.ulcon		= ULCON, +		.ufcon		= UFCON, +	}, +	[2] = { +		.hwport		= 2, +		.flags		= 0, +		.ucon		= UCON, +		.ulcon		= ULCON, +		.ufcon		= UFCON, +	}, +}; + +#ifdef CONFIG_CHARGER_PCF50633 +/* + * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin. + * We use this to recognize that we can pull 1A from the USB socket. + * + * These constants are the measured pcf50633 ADC levels with the 1A + * charger / 48K resistor, and with no pulldown resistor. + */ + +#define ADC_NOM_CHG_DETECT_1A 6 +#define ADC_NOM_CHG_DETECT_USB 43 + +static void +gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res) +{ +	int  ma; + +	/* Interpret charger type */ +	if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) { + +		/* +		 * Sanity - stop GPO driving out now that we have a 1A charger +		 * GPO controls USB Host power generation on GTA02 +		 */ +		pcf50633_gpio_set(pcf, PCF50633_GPO, 0); + +		ma = 1000; +	} else +		ma = 100; + +	pcf50633_mbc_usb_curlim_set(pcf, ma); +} + +static struct delayed_work gta02_charger_work; +static int gta02_usb_vbus_draw; + +static void gta02_charger_worker(struct work_struct *work) +{ +	if (gta02_usb_vbus_draw) { +		pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw); +		return; +	} + +#ifdef CONFIG_PCF50633_ADC +	pcf50633_adc_async_read(gta02_pcf, +				PCF50633_ADCC1_MUX_ADCIN1, +				PCF50633_ADCC1_AVERAGE_16, +				gta02_configure_pmu_for_charger, +				NULL); +#else +	/* +	 * If the PCF50633 ADC is disabled we fallback to a +	 * 100mA limit for safety. +	 */ +	pcf50633_mbc_usb_curlim_set(gta02_pcf, 100); +#endif +} + +#define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000) + +static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq) +{ +	if (irq == PCF50633_IRQ_USBINS) { +		schedule_delayed_work(>a02_charger_work, +				      GTA02_CHARGER_CONFIGURE_TIMEOUT); + +		return; +	} + +	if (irq == PCF50633_IRQ_USBREM) { +		cancel_delayed_work_sync(>a02_charger_work); +		gta02_usb_vbus_draw = 0; +	} +} + +static void gta02_udc_vbus_draw(unsigned int ma) +{ +	if (!gta02_pcf) +		return; + +	gta02_usb_vbus_draw = ma; + +	schedule_delayed_work(>a02_charger_work, +			      GTA02_CHARGER_CONFIGURE_TIMEOUT); +} +#else /* !CONFIG_CHARGER_PCF50633 */ +#define gta02_pmu_event_callback	NULL +#define gta02_udc_vbus_draw		NULL +#endif + +/* + * This is called when pc50633 is probed, unfortunately quite late in the + * day since it is an I2C bus device. Here we can belatedly define some + * platform devices with the advantage that we can mark the pcf50633 as the + * parent. This makes them get suspended and resumed with their parent + * the pcf50633 still around. + */ + +static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf); + + +static char *gta02_batteries[] = { +	"battery", +}; + +static struct pcf50633_bl_platform_data gta02_backlight_data = { +	.default_brightness = 0x3f, +	.default_brightness_limit = 0, +	.ramp_time = 5, +}; + +static struct pcf50633_platform_data gta02_pcf_pdata = { +	.resumers = { +		[0] =	PCF50633_INT1_USBINS | +			PCF50633_INT1_USBREM | +			PCF50633_INT1_ALARM, +		[1] =	PCF50633_INT2_ONKEYF, +		[2] =	PCF50633_INT3_ONKEY1S, +		[3] =	PCF50633_INT4_LOWSYS | +			PCF50633_INT4_LOWBAT | +			PCF50633_INT4_HIGHTMP, +	}, + +	.batteries = gta02_batteries, +	.num_batteries = ARRAY_SIZE(gta02_batteries), + +	.charger_reference_current_ma = 1000, + +	.backlight_data = >a02_backlight_data, + +	.reg_init_data = { +		[PCF50633_REGULATOR_AUTO] = { +			.constraints = { +				.min_uV = 3300000, +				.max_uV = 3300000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.always_on = 1, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_DOWN1] = { +			.constraints = { +				.min_uV = 1300000, +				.max_uV = 1600000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.always_on = 1, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_DOWN2] = { +			.constraints = { +				.min_uV = 1800000, +				.max_uV = 1800000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.apply_uV = 1, +				.always_on = 1, +			}, +		}, +		[PCF50633_REGULATOR_HCLDO] = { +			.constraints = { +				.min_uV = 2000000, +				.max_uV = 3300000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | +						REGULATOR_CHANGE_STATUS, +			}, +		}, +		[PCF50633_REGULATOR_LDO1] = { +			.constraints = { +				.min_uV = 3300000, +				.max_uV = 3300000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.valid_ops_mask = REGULATOR_CHANGE_STATUS, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_LDO2] = { +			.constraints = { +				.min_uV = 3300000, +				.max_uV = 3300000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_LDO3] = { +			.constraints = { +				.min_uV = 3000000, +				.max_uV = 3000000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_LDO4] = { +			.constraints = { +				.min_uV = 3200000, +				.max_uV = 3200000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.valid_ops_mask = REGULATOR_CHANGE_STATUS, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_LDO5] = { +			.constraints = { +				.min_uV = 3000000, +				.max_uV = 3000000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +				.valid_ops_mask = REGULATOR_CHANGE_STATUS, +				.apply_uV = 1, +			}, +		}, +		[PCF50633_REGULATOR_LDO6] = { +			.constraints = { +				.min_uV = 3000000, +				.max_uV = 3000000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +			}, +		}, +		[PCF50633_REGULATOR_MEMLDO] = { +			.constraints = { +				.min_uV = 1800000, +				.max_uV = 1800000, +				.valid_modes_mask = REGULATOR_MODE_NORMAL, +			}, +		}, + +	}, +	.probe_done = gta02_pmu_attach_child_devices, +	.mbc_event_callback = gta02_pmu_event_callback, +}; + + +/* NOR Flash. */ + +#define GTA02_FLASH_BASE	0x18000000 /* GCS3 */ +#define GTA02_FLASH_SIZE	0x200000 /* 2MBytes */ + +static struct physmap_flash_data gta02_nor_flash_data = { +	.width		= 2, +}; + +static struct resource gta02_nor_flash_resource = +	DEFINE_RES_MEM(GTA02_FLASH_BASE, GTA02_FLASH_SIZE); + +static struct platform_device gta02_nor_flash = { +	.name		= "physmap-flash", +	.id		= 0, +	.dev		= { +		.platform_data	= >a02_nor_flash_data, +	}, +	.resource	= >a02_nor_flash_resource, +	.num_resources	= 1, +}; + + +static struct platform_device s3c24xx_pwm_device = { +	.name		= "s3c24xx_pwm", +	.num_resources	= 0, +}; + +static struct platform_device gta02_dfbmcs320_device = { +	.name = "dfbmcs320", +}; + +static struct i2c_board_info gta02_i2c_devs[] __initdata = { +	{ +		I2C_BOARD_INFO("pcf50633", 0x73), +		.irq = GTA02_IRQ_PCF50633, +		.platform_data = >a02_pcf_pdata, +	}, +	{ +		I2C_BOARD_INFO("wm8753", 0x1a), +	}, +}; + +static struct s3c2410_nand_set __initdata gta02_nand_sets[] = { +	[0] = { +		/* +		 * This name is also hard-coded in the boot loaders, so +		 * changing it would would require all users to upgrade +		 * their boot loaders, some of which are stored in a NOR +		 * that is considered to be immutable. +		 */ +		.name		= "neo1973-nand", +		.nr_chips	= 1, +		.flash_bbt	= 1, +	}, +}; + +/* + * Choose a set of timings derived from S3C@2442B MCP54 + * data sheet (K5D2G13ACM-D075 MCP Memory). + */ + +static struct s3c2410_platform_nand __initdata gta02_nand_info = { +	.tacls		= 0, +	.twrph0		= 25, +	.twrph1		= 15, +	.nr_sets	= ARRAY_SIZE(gta02_nand_sets), +	.sets		= gta02_nand_sets, +}; + + +/* Get PMU to set USB current limit accordingly. */ +static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = { +	.vbus_draw	= gta02_udc_vbus_draw, +	.pullup_pin = GTA02_GPIO_USB_PULLUP, +}; + +/* USB */ +static struct s3c2410_hcd_info gta02_usb_info __initdata = { +	.port[0]	= { +		.flags	= S3C_HCDFLG_USED, +	}, +	.port[1]	= { +		.flags	= 0, +	}, +}; + +/* Touchscreen */ +static struct s3c2410_ts_mach_info gta02_ts_info = { +	.delay			= 10000, +	.presc			= 0xff, /* slow as we can go */ +	.oversampling_shift	= 2, +}; + +/* Buttons */ +static struct gpio_keys_button gta02_buttons[] = { +	{ +		.gpio = GTA02_GPIO_AUX_KEY, +		.code = KEY_PHONE, +		.desc = "Aux", +		.type = EV_KEY, +		.debounce_interval = 100, +	}, +	{ +		.gpio = GTA02_GPIO_HOLD_KEY, +		.code = KEY_PAUSE, +		.desc = "Hold", +		.type = EV_KEY, +		.debounce_interval = 100, +	}, +}; + +static struct gpio_keys_platform_data gta02_buttons_pdata = { +	.buttons = gta02_buttons, +	.nbuttons = ARRAY_SIZE(gta02_buttons), +}; + +static struct platform_device gta02_buttons_device = { +	.name = "gpio-keys", +	.id = -1, +	.dev = { +		.platform_data = >a02_buttons_pdata, +	}, +}; + +static void __init gta02_map_io(void) +{ +	s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc)); +	s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + + +/* These are the guys that don't need to be children of PMU. */ + +static struct platform_device *gta02_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_wdt, +	&s3c_device_sdi, +	&s3c_device_usbgadget, +	&s3c_device_nand, +	>a02_nor_flash, +	&s3c24xx_pwm_device, +	&s3c_device_iis, +	&s3c_device_i2c0, +	>a02_dfbmcs320_device, +	>a02_buttons_device, +	&s3c_device_adc, +	&s3c_device_ts, +}; + +/* These guys DO need to be children of PMU. */ + +static struct platform_device *gta02_devices_pmu_children[] = { +}; + + +/* + * This is called when pc50633 is probed, quite late in the day since it is an + * I2C bus device.  Here we can define platform devices with the advantage that + * we can mark the pcf50633 as the parent.  This makes them get suspended and + * resumed with their parent the pcf50633 still around.  All devices whose + * operation depends on something from pcf50633 must have this relationship + * made explicit like this, or suspend and resume will become an unreliable + * hellworld. + */ + +static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf) +{ +	int n; + +	/* Grab a copy of the now probed PMU pointer. */ +	gta02_pcf = pcf; + +	for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++) +		gta02_devices_pmu_children[n]->dev.parent = pcf->dev; + +	platform_add_devices(gta02_devices_pmu_children, +			     ARRAY_SIZE(gta02_devices_pmu_children)); +} + +static void gta02_poweroff(void) +{ +	pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1); +} + +static void __init gta02_machine_init(void) +{ +	/* Set the panic callback to turn AUX LED on or off. */ +	panic_blink = gta02_panic_blink; + +	s3c_pm_init(); + +#ifdef CONFIG_CHARGER_PCF50633 +	INIT_DELAYED_WORK(>a02_charger_work, gta02_charger_worker); +#endif + +	s3c24xx_udc_set_platdata(>a02_udc_cfg); +	s3c24xx_ts_set_platdata(>a02_ts_info); +	s3c_ohci_set_platdata(>a02_usb_info); +	s3c_nand_set_platdata(>a02_nand_info); +	s3c_i2c0_set_platdata(NULL); + +	i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs)); + +	platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices)); +	pm_power_off = gta02_poweroff; + +	regulator_has_full_constraints(); +} + +static void __init gta02_init_time(void) +{ +	s3c2442_init_clocks(12000000); +	samsung_timer_init(); +} + +MACHINE_START(NEO1973_GTA02, "GTA02") +	/* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */ +	.atag_offset	= 0x100, +	.map_io		= gta02_map_io, +	.init_irq	= s3c2442_init_irq, +	.init_machine	= gta02_machine_init, +	.init_time	= gta02_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c new file mode 100644 index 00000000000..fbf5487ae5d --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -0,0 +1,748 @@ +/* + * Copyright (c) 2003-2005 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * http://www.handhelds.org/projects/h1940.html + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/memblock.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/pwm_backlight.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/pda_power.h> +#include <linux/s3c_adc_battery.h> +#include <linux/delay.h> + +#include <video/platform_lcd.h> + +#include <linux/mmc/host.h> +#include <linux/export.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/touchscreen-s3c2410.h> +#include <linux/platform_data/usb-s3c2410_udc.h> + +#include <sound/uda1380.h> + +#include <mach/fb.h> +#include <mach/hardware.h> +#include <mach/regs-clock.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/gpio-cfg.h> +#include <plat/pll.h> +#include <plat/pm.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "h1940.h" + +#define H1940_LATCH		((void __force __iomem *)0xF8000000) + +#define H1940_PA_LATCH		S3C2410_CS2 + +#define H1940_LATCH_BIT(x)	(1 << ((x) + 16 - S3C_GPIO_END)) + +static struct map_desc h1940_iodesc[] __initdata = { +	[0] = { +		.virtual	= (unsigned long)H1940_LATCH, +		.pfn		= __phys_to_pfn(H1940_PA_LATCH), +		.length		= SZ_16K, +		.type		= MT_DEVICE +	}, +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg h1940_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = 0x245, +		.ulcon	     = 0x03, +		.ufcon	     = 0x00, +	}, +	/* IR port */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.uart_flags  = UPF_CONS_FLOW, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x43, +		.ufcon	     = 0x51, +	} +}; + +/* Board control latch control */ + +static unsigned int latch_state; + +static void h1940_latch_control(unsigned int clear, unsigned int set) +{ +	unsigned long flags; + +	local_irq_save(flags); + +	latch_state &= ~clear; +	latch_state |= set; + +	__raw_writel(latch_state, H1940_LATCH); + +	local_irq_restore(flags); +} + +static inline int h1940_gpiolib_to_latch(int offset) +{ +	return 1 << (offset + 16); +} + +static void h1940_gpiolib_latch_set(struct gpio_chip *chip, +					unsigned offset, int value) +{ +	int latch_bit = h1940_gpiolib_to_latch(offset); + +	h1940_latch_control(value ? 0 : latch_bit, +		value ? latch_bit : 0); +} + +static int h1940_gpiolib_latch_output(struct gpio_chip *chip, +					unsigned offset, int value) +{ +	h1940_gpiolib_latch_set(chip, offset, value); +	return 0; +} + +static int h1940_gpiolib_latch_get(struct gpio_chip *chip, +					unsigned offset) +{ +	return (latch_state >> (offset + 16)) & 1; +} + +static struct gpio_chip h1940_latch_gpiochip = { +	.base			= H1940_LATCH_GPIO(0), +	.owner			= THIS_MODULE, +	.label			= "H1940_LATCH", +	.ngpio			= 16, +	.direction_output	= h1940_gpiolib_latch_output, +	.set			= h1940_gpiolib_latch_set, +	.get			= h1940_gpiolib_latch_get, +}; + +static struct s3c2410_udc_mach_info h1940_udc_cfg __initdata = { +	.vbus_pin		= S3C2410_GPG(5), +	.vbus_pin_inverted	= 1, +	.pullup_pin		= H1940_LATCH_USB_DP, +}; + +static struct s3c2410_ts_mach_info h1940_ts_cfg __initdata = { +		.delay = 10000, +		.presc = 49, +		.oversampling_shift = 2, +		.cfg_gpio = s3c24xx_ts_cfg_gpio, +}; + +/** + * Set lcd on or off + **/ +static struct s3c2410fb_display h1940_lcd __initdata = { +	.lcdcon5=	S3C2410_LCDCON5_FRM565 | \ +			S3C2410_LCDCON5_INVVLINE | \ +			S3C2410_LCDCON5_HWSWP, + +	.type =		S3C2410_LCDCON1_TFT, +	.width =	240, +	.height =	320, +	.pixclock =	260000, +	.xres =		240, +	.yres =		320, +	.bpp =		16, +	.left_margin =	8, +	.right_margin =	20, +	.hsync_len =	4, +	.upper_margin =	8, +	.lower_margin = 7, +	.vsync_len =	1, +}; + +static struct s3c2410fb_mach_info h1940_fb_info __initdata = { +	.displays = &h1940_lcd, +	.num_displays = 1, +	.default_display = 0, + +	.lpcsel =	0x02, +	.gpccon =	0xaa940659, +	.gpccon_mask =	0xffffc0f0, +	.gpcup =	0x0000ffff, +	.gpcup_mask =	0xffffffff, +	.gpdcon =	0xaa84aaa0, +	.gpdcon_mask =	0xffffffff, +	.gpdup =	0x0000faff, +	.gpdup_mask =	0xffffffff, +}; + +static int power_supply_init(struct device *dev) +{ +	return gpio_request(S3C2410_GPF(2), "cable plugged"); +} + +static int h1940_is_ac_online(void) +{ +	return !gpio_get_value(S3C2410_GPF(2)); +} + +static void power_supply_exit(struct device *dev) +{ +	gpio_free(S3C2410_GPF(2)); +} + +static char *h1940_supplicants[] = { +	"main-battery", +	"backup-battery", +}; + +static struct pda_power_pdata power_supply_info = { +	.init			= power_supply_init, +	.is_ac_online		= h1940_is_ac_online, +	.exit			= power_supply_exit, +	.supplied_to		= h1940_supplicants, +	.num_supplicants	= ARRAY_SIZE(h1940_supplicants), +}; + +static struct resource power_supply_resources[] = { +	[0] = DEFINE_RES_NAMED(IRQ_EINT2, 1, "ac", IORESOURCE_IRQ \ +			| IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE), +}; + +static struct platform_device power_supply = { +	.name		= "pda-power", +	.id		= -1, +	.dev		= { +				.platform_data = +					&power_supply_info, +	}, +	.resource	= power_supply_resources, +	.num_resources	= ARRAY_SIZE(power_supply_resources), +}; + +static const struct s3c_adc_bat_thresh bat_lut_noac[] = { +	{ .volt = 4070, .cur = 162, .level = 100}, +	{ .volt = 4040, .cur = 165, .level = 95}, +	{ .volt = 4016, .cur = 164, .level = 90}, +	{ .volt = 3996, .cur = 166, .level = 85}, +	{ .volt = 3971, .cur = 168, .level = 80}, +	{ .volt = 3951, .cur = 168, .level = 75}, +	{ .volt = 3931, .cur = 170, .level = 70}, +	{ .volt = 3903, .cur = 172, .level = 65}, +	{ .volt = 3886, .cur = 172, .level = 60}, +	{ .volt = 3858, .cur = 176, .level = 55}, +	{ .volt = 3842, .cur = 176, .level = 50}, +	{ .volt = 3818, .cur = 176, .level = 45}, +	{ .volt = 3789, .cur = 180, .level = 40}, +	{ .volt = 3769, .cur = 180, .level = 35}, +	{ .volt = 3749, .cur = 184, .level = 30}, +	{ .volt = 3732, .cur = 184, .level = 25}, +	{ .volt = 3716, .cur = 184, .level = 20}, +	{ .volt = 3708, .cur = 184, .level = 15}, +	{ .volt = 3716, .cur = 96, .level = 10}, +	{ .volt = 3700, .cur = 96, .level = 5}, +	{ .volt = 3684, .cur = 96, .level = 0}, +}; + +static const struct s3c_adc_bat_thresh bat_lut_acin[] = { +	{ .volt = 4130, .cur = 0, .level = 100}, +	{ .volt = 3982, .cur = 0, .level = 50}, +	{ .volt = 3854, .cur = 0, .level = 10}, +	{ .volt = 3841, .cur = 0, .level = 0}, +}; + +static int h1940_bat_init(void) +{ +	int ret; + +	ret = gpio_request(H1940_LATCH_SM803_ENABLE, "h1940-charger-enable"); +	if (ret) +		return ret; +	gpio_direction_output(H1940_LATCH_SM803_ENABLE, 0); + +	return 0; + +} + +static void h1940_bat_exit(void) +{ +	gpio_free(H1940_LATCH_SM803_ENABLE); +} + +static void h1940_enable_charger(void) +{ +	gpio_set_value(H1940_LATCH_SM803_ENABLE, 1); +} + +static void h1940_disable_charger(void) +{ +	gpio_set_value(H1940_LATCH_SM803_ENABLE, 0); +} + +static struct s3c_adc_bat_pdata h1940_bat_cfg = { +	.init = h1940_bat_init, +	.exit = h1940_bat_exit, +	.enable_charger = h1940_enable_charger, +	.disable_charger = h1940_disable_charger, +	.gpio_charge_finished = S3C2410_GPF(3), +	.gpio_inverted = 1, +	.lut_noac = bat_lut_noac, +	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac), +	.lut_acin = bat_lut_acin, +	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin), +	.volt_channel = 0, +	.current_channel = 1, +	.volt_mult = 4056, +	.current_mult = 1893, +	.internal_impedance = 200, +	.backup_volt_channel = 3, +	/* TODO Check backup volt multiplier */ +	.backup_volt_mult = 4056, +	.backup_volt_min = 0, +	.backup_volt_max = 4149288 +}; + +static struct platform_device h1940_battery = { +	.name             = "s3c-adc-battery", +	.id               = -1, +	.dev = { +		.parent = &s3c_device_adc.dev, +		.platform_data = &h1940_bat_cfg, +	}, +}; + +static DEFINE_SPINLOCK(h1940_blink_spin); + +int h1940_led_blink_set(unsigned gpio, int state, +	unsigned long *delay_on, unsigned long *delay_off) +{ +	int blink_gpio, check_gpio1, check_gpio2; + +	switch (gpio) { +	case H1940_LATCH_LED_GREEN: +		blink_gpio = S3C2410_GPA(7); +		check_gpio1 = S3C2410_GPA(1); +		check_gpio2 = S3C2410_GPA(3); +		break; +	case H1940_LATCH_LED_RED: +		blink_gpio = S3C2410_GPA(1); +		check_gpio1 = S3C2410_GPA(7); +		check_gpio2 = S3C2410_GPA(3); +		break; +	default: +		blink_gpio = S3C2410_GPA(3); +		check_gpio1 = S3C2410_GPA(1); +		check_gpio2 = S3C2410_GPA(7); +		break; +	} + +	if (delay_on && delay_off && !*delay_on && !*delay_off) +		*delay_on = *delay_off = 500; + +	spin_lock(&h1940_blink_spin); + +	switch (state) { +	case GPIO_LED_NO_BLINK_LOW: +	case GPIO_LED_NO_BLINK_HIGH: +		if (!gpio_get_value(check_gpio1) && +		    !gpio_get_value(check_gpio2)) +			gpio_set_value(H1940_LATCH_LED_FLASH, 0); +		gpio_set_value(blink_gpio, 0); +		if (gpio_is_valid(gpio)) +			gpio_set_value(gpio, state); +		break; +	case GPIO_LED_BLINK: +		if (gpio_is_valid(gpio)) +			gpio_set_value(gpio, 0); +		gpio_set_value(H1940_LATCH_LED_FLASH, 1); +		gpio_set_value(blink_gpio, 1); +		break; +	} + +	spin_unlock(&h1940_blink_spin); + +	return 0; +} +EXPORT_SYMBOL(h1940_led_blink_set); + +static struct gpio_led h1940_leds_desc[] = { +	{ +		.name			= "Green", +		.default_trigger	= "main-battery-full", +		.gpio			= H1940_LATCH_LED_GREEN, +		.retain_state_suspended	= 1, +	}, +	{ +		.name			= "Red", +		.default_trigger +			= "main-battery-charging-blink-full-solid", +		.gpio			= H1940_LATCH_LED_RED, +		.retain_state_suspended	= 1, +	}, +}; + +static struct gpio_led_platform_data h1940_leds_pdata = { +	.num_leds	= ARRAY_SIZE(h1940_leds_desc), +	.leds		= h1940_leds_desc, +	.gpio_blink_set	= h1940_led_blink_set, +}; + +static struct platform_device h1940_device_leds = { +	.name	= "leds-gpio", +	.id	= -1, +	.dev	= { +			.platform_data = &h1940_leds_pdata, +	}, +}; + +static struct platform_device h1940_device_bluetooth = { +	.name             = "h1940-bt", +	.id               = -1, +}; + +static void h1940_set_mmc_power(unsigned char power_mode, unsigned short vdd) +{ +	switch (power_mode) { +	case MMC_POWER_OFF: +		gpio_set_value(H1940_LATCH_SD_POWER, 0); +		break; +	case MMC_POWER_UP: +	case MMC_POWER_ON: +		gpio_set_value(H1940_LATCH_SD_POWER, 1); +		break; +	default: +		break; +	} +} + +static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = { +	.gpio_detect   = S3C2410_GPF(5), +	.gpio_wprotect = S3C2410_GPH(8), +	.set_power     = h1940_set_mmc_power, +	.ocr_avail     = MMC_VDD_32_33, +}; + +static int h1940_backlight_init(struct device *dev) +{ +	gpio_request(S3C2410_GPB(0), "Backlight"); + +	gpio_direction_output(S3C2410_GPB(0), 0); +	s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE); +	s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0); +	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1); + +	return 0; +} + +static int h1940_backlight_notify(struct device *dev, int brightness) +{ +	if (!brightness) { +		gpio_direction_output(S3C2410_GPB(0), 1); +		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0); +	} else { +		gpio_direction_output(S3C2410_GPB(0), 0); +		s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE); +		s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0); +		gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 1); +	} +	return brightness; +} + +static void h1940_backlight_exit(struct device *dev) +{ +	gpio_direction_output(S3C2410_GPB(0), 1); +	gpio_set_value(H1940_LATCH_MAX1698_nSHUTDOWN, 0); +} + + +static struct platform_pwm_backlight_data backlight_data = { +	.pwm_id         = 0, +	.max_brightness = 100, +	.dft_brightness = 50, +	/* tcnt = 0x31 */ +	.pwm_period_ns  = 36296, +	.enable_gpio    = -1, +	.init           = h1940_backlight_init, +	.notify		= h1940_backlight_notify, +	.exit           = h1940_backlight_exit, +}; + +static struct platform_device h1940_backlight = { +	.name = "pwm-backlight", +	.dev  = { +		.parent = &samsung_device_pwm.dev, +		.platform_data = &backlight_data, +	}, +	.id   = -1, +}; + +static void h1940_lcd_power_set(struct plat_lcd_data *pd, +					unsigned int power) +{ +	int value, retries = 100; + +	if (!power) { +		gpio_set_value(S3C2410_GPC(0), 0); +		/* wait for 3ac */ +		do { +			value = gpio_get_value(S3C2410_GPC(6)); +		} while (value && retries--); + +		gpio_set_value(H1940_LATCH_LCD_P2, 0); +		gpio_set_value(H1940_LATCH_LCD_P3, 0); +		gpio_set_value(H1940_LATCH_LCD_P4, 0); + +		gpio_direction_output(S3C2410_GPC(1), 0); +		gpio_direction_output(S3C2410_GPC(4), 0); + +		gpio_set_value(H1940_LATCH_LCD_P1, 0); +		gpio_set_value(H1940_LATCH_LCD_P0, 0); + +		gpio_set_value(S3C2410_GPC(5), 0); + +	} else { +		gpio_set_value(H1940_LATCH_LCD_P0, 1); +		gpio_set_value(H1940_LATCH_LCD_P1, 1); + +		gpio_direction_input(S3C2410_GPC(1)); +		gpio_direction_input(S3C2410_GPC(4)); +		mdelay(10); +		s3c_gpio_cfgpin(S3C2410_GPC(1), S3C_GPIO_SFN(2)); +		s3c_gpio_cfgpin(S3C2410_GPC(4), S3C_GPIO_SFN(2)); + +		gpio_set_value(S3C2410_GPC(5), 1); +		gpio_set_value(S3C2410_GPC(0), 1); + +		gpio_set_value(H1940_LATCH_LCD_P3, 1); +		gpio_set_value(H1940_LATCH_LCD_P2, 1); +		gpio_set_value(H1940_LATCH_LCD_P4, 1); +	} +} + +static struct plat_lcd_data h1940_lcd_power_data = { +	.set_power      = h1940_lcd_power_set, +}; + +static struct platform_device h1940_lcd_powerdev = { +	.name                   = "platform-lcd", +	.dev.parent             = &s3c_device_lcd.dev, +	.dev.platform_data      = &h1940_lcd_power_data, +}; + +static struct uda1380_platform_data uda1380_info = { +	.gpio_power	= H1940_LATCH_UDA_POWER, +	.gpio_reset	= S3C2410_GPA(12), +	.dac_clk	= UDA1380_DAC_CLK_SYSCLK, +}; + +static struct i2c_board_info h1940_i2c_devices[] = { +	{ +		I2C_BOARD_INFO("uda1380", 0x1a), +		.platform_data = &uda1380_info, +	}, +}; + +#define DECLARE_BUTTON(p, k, n, w)	\ +	{				\ +		.gpio		= p,	\ +		.code		= k,	\ +		.desc		= n,	\ +		.wakeup		= w,	\ +		.active_low	= 1,	\ +	} + +static struct gpio_keys_button h1940_buttons[] = { +	DECLARE_BUTTON(S3C2410_GPF(0),       KEY_POWER,          "Power", 1), +	DECLARE_BUTTON(S3C2410_GPF(6),       KEY_ENTER,         "Select", 1), +	DECLARE_BUTTON(S3C2410_GPF(7),      KEY_RECORD,         "Record", 0), +	DECLARE_BUTTON(S3C2410_GPG(0),         KEY_F11,       "Calendar", 0), +	DECLARE_BUTTON(S3C2410_GPG(2),         KEY_F12,       "Contacts", 0), +	DECLARE_BUTTON(S3C2410_GPG(3),        KEY_MAIL,           "Mail", 0), +	DECLARE_BUTTON(S3C2410_GPG(6),        KEY_LEFT,     "Left_arrow", 0), +	DECLARE_BUTTON(S3C2410_GPG(7),    KEY_HOMEPAGE,           "Home", 0), +	DECLARE_BUTTON(S3C2410_GPG(8),       KEY_RIGHT,    "Right_arrow", 0), +	DECLARE_BUTTON(S3C2410_GPG(9),          KEY_UP,       "Up_arrow", 0), +	DECLARE_BUTTON(S3C2410_GPG(10),       KEY_DOWN,     "Down_arrow", 0), +}; + +static struct gpio_keys_platform_data h1940_buttons_data = { +	.buttons	= h1940_buttons, +	.nbuttons	= ARRAY_SIZE(h1940_buttons), +}; + +static struct platform_device h1940_dev_buttons = { +	.name		= "gpio-keys", +	.id		= -1, +	.dev		= { +		.platform_data  = &h1940_buttons_data, +	} +}; + +static struct platform_device *h1940_devices[] __initdata = { +	&h1940_dev_buttons, +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_usbgadget, +	&h1940_device_leds, +	&h1940_device_bluetooth, +	&s3c_device_sdi, +	&s3c_device_rtc, +	&samsung_device_pwm, +	&h1940_backlight, +	&h1940_lcd_powerdev, +	&s3c_device_adc, +	&s3c_device_ts, +	&power_supply, +	&h1940_battery, +}; + +static void __init h1940_map_io(void) +{ +	s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); +	s3c24xx_init_uarts(h1940_uartcfgs, ARRAY_SIZE(h1940_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); + +	/* setup PM */ + +#ifdef CONFIG_PM_H1940 +	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024); +#endif +	s3c_pm_init(); + +	/* Add latch gpio chip, set latch initial value */ +	h1940_latch_control(0, 0); +	WARN_ON(gpiochip_add(&h1940_latch_gpiochip)); +} + +static void __init h1940_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +/* H1940 and RX3715 need to reserve this for suspend */ +static void __init h1940_reserve(void) +{ +	memblock_reserve(0x30003000, 0x1000); +	memblock_reserve(0x30081000, 0x1000); +} + +static void __init h1940_init(void) +{ +	u32 tmp; + +	s3c24xx_fb_set_platdata(&h1940_fb_info); +	s3c24xx_mci_set_platdata(&h1940_mmc_cfg); + 	s3c24xx_udc_set_platdata(&h1940_udc_cfg); +	s3c24xx_ts_set_platdata(&h1940_ts_cfg); +	s3c_i2c0_set_platdata(NULL); + +	/* Turn off suspend on both USB ports, and switch the +	 * selectable USB port to USB device mode. */ + +	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +			      S3C2410_MISCCR_USBSUSPND0 | +			      S3C2410_MISCCR_USBSUSPND1, 0x0); + +	tmp =   (0x78 << S3C24XX_PLL_MDIV_SHIFT) +	      | (0x02 << S3C24XX_PLL_PDIV_SHIFT) +	      | (0x03 << S3C24XX_PLL_SDIV_SHIFT); +	writel(tmp, S3C2410_UPLLCON); + +	gpio_request(S3C2410_GPC(0), "LCD power"); +	gpio_request(S3C2410_GPC(1), "LCD power"); +	gpio_request(S3C2410_GPC(4), "LCD power"); +	gpio_request(S3C2410_GPC(5), "LCD power"); +	gpio_request(S3C2410_GPC(6), "LCD power"); +	gpio_request(H1940_LATCH_LCD_P0, "LCD power"); +	gpio_request(H1940_LATCH_LCD_P1, "LCD power"); +	gpio_request(H1940_LATCH_LCD_P2, "LCD power"); +	gpio_request(H1940_LATCH_LCD_P3, "LCD power"); +	gpio_request(H1940_LATCH_LCD_P4, "LCD power"); +	gpio_request(H1940_LATCH_MAX1698_nSHUTDOWN, "LCD power"); +	gpio_direction_output(S3C2410_GPC(0), 0); +	gpio_direction_output(S3C2410_GPC(1), 0); +	gpio_direction_output(S3C2410_GPC(4), 0); +	gpio_direction_output(S3C2410_GPC(5), 0); +	gpio_direction_input(S3C2410_GPC(6)); +	gpio_direction_output(H1940_LATCH_LCD_P0, 0); +	gpio_direction_output(H1940_LATCH_LCD_P1, 0); +	gpio_direction_output(H1940_LATCH_LCD_P2, 0); +	gpio_direction_output(H1940_LATCH_LCD_P3, 0); +	gpio_direction_output(H1940_LATCH_LCD_P4, 0); +	gpio_direction_output(H1940_LATCH_MAX1698_nSHUTDOWN, 0); + +	gpio_request(H1940_LATCH_SD_POWER, "SD power"); +	gpio_direction_output(H1940_LATCH_SD_POWER, 0); + +	platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices)); + +	gpio_request(S3C2410_GPA(1), "Red LED blink"); +	gpio_request(S3C2410_GPA(3), "Blue LED blink"); +	gpio_request(S3C2410_GPA(7), "Green LED blink"); +	gpio_request(H1940_LATCH_LED_FLASH, "LED blink"); +	gpio_direction_output(S3C2410_GPA(1), 0); +	gpio_direction_output(S3C2410_GPA(3), 0); +	gpio_direction_output(S3C2410_GPA(7), 0); +	gpio_direction_output(H1940_LATCH_LED_FLASH, 0); + +	i2c_register_board_info(0, h1940_i2c_devices, +		ARRAY_SIZE(h1940_i2c_devices)); +} + +MACHINE_START(H1940, "IPAQ-H1940") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, +	.map_io		= h1940_map_io, +	.reserve	= h1940_reserve, +	.init_irq	= s3c2410_init_irq, +	.init_machine	= h1940_init, +	.init_time	= h1940_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c new file mode 100644 index 00000000000..e81ea82c55f --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -0,0 +1,675 @@ +/* linux/arch/arm/mach-s3c2410/mach-jive.c + * + * Copyright 2007 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://armlinux.simtec.co.uk/ + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/syscore_ops.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> + +#include <video/ili9320.h> + +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/fb.h> +#include <mach/gpio-samsung.h> + +#include <asm/mach-types.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <plat/gpio-cfg.h> +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/pm.h> +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "s3c2412-power.h" + +static struct map_desc jive_iodesc[] __initdata = { +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg jive_uartcfgs[] = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +/* Jive flash assignment + * + * 0x00000000-0x00028000 : uboot + * 0x00028000-0x0002c000 : uboot env + * 0x0002c000-0x00030000 : spare + * 0x00030000-0x00200000 : zimage A + * 0x00200000-0x01600000 : cramfs A + * 0x01600000-0x017d0000 : zimage B + * 0x017d0000-0x02bd0000 : cramfs B + * 0x02bd0000-0x03fd0000 : yaffs + */ +static struct mtd_partition __initdata jive_imageA_nand_part[] = { + +#ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER +	/* Don't allow access to the bootloader from linux */ +	{ +		.name           = "uboot", +		.offset         = 0, +		.size           = (160 * SZ_1K), +		.mask_flags	= MTD_WRITEABLE, /* force read-only */ +	}, + +	/* spare */ +        { +                .name           = "spare", +                .offset         = (176 * SZ_1K), +                .size           = (16 * SZ_1K), +        }, +#endif + +	/* booted images */ +        { +		.name		= "kernel (ro)", +		.offset		= (192 * SZ_1K), +		.size		= (SZ_2M) - (192 * SZ_1K), +		.mask_flags	= MTD_WRITEABLE, /* force read-only */ +        }, { +                .name           = "root (ro)", +                .offset         = (SZ_2M), +                .size           = (20 * SZ_1M), +		.mask_flags	= MTD_WRITEABLE, /* force read-only */ +        }, + +	/* yaffs */ +	{ +		.name		= "yaffs", +		.offset		= (44 * SZ_1M), +		.size		= (20 * SZ_1M), +	}, + +	/* bootloader environment */ +	{ +                .name		= "env", +		.offset		= (160 * SZ_1K), +		.size		= (16 * SZ_1K), +	}, + +	/* upgrade images */ +        { +		.name		= "zimage", +		.offset		= (22 * SZ_1M), +		.size		= (2 * SZ_1M) - (192 * SZ_1K), +        }, { +		.name		= "cramfs", +		.offset		= (24 * SZ_1M) - (192*SZ_1K), +		.size		= (20 * SZ_1M), +        }, +}; + +static struct mtd_partition __initdata jive_imageB_nand_part[] = { + +#ifdef CONFIG_MACH_JIVE_SHOW_BOOTLOADER +	/* Don't allow access to the bootloader from linux */ +	{ +		.name           = "uboot", +		.offset         = 0, +		.size           = (160 * SZ_1K), +		.mask_flags	= MTD_WRITEABLE, /* force read-only */ +	}, + +	/* spare */ +        { +                .name           = "spare", +                .offset         = (176 * SZ_1K), +                .size           = (16 * SZ_1K), +        }, +#endif + +	/* booted images */ +        { +		.name           = "kernel (ro)", +		.offset         = (22 * SZ_1M), +		.size           = (2 * SZ_1M) - (192 * SZ_1K), +		.mask_flags	= MTD_WRITEABLE, /* force read-only */ +        }, +	{ +		.name		= "root (ro)", +		.offset		= (24 * SZ_1M) - (192 * SZ_1K), +                .size		= (20 * SZ_1M), +		.mask_flags	= MTD_WRITEABLE, /* force read-only */ +	}, + +	/* yaffs */ +	{ +		.name		= "yaffs", +		.offset		= (44 * SZ_1M), +		.size		= (20 * SZ_1M), +        }, + +	/* bootloader environment */ +	{ +		.name		= "env", +		.offset		= (160 * SZ_1K), +		.size		= (16 * SZ_1K), +	}, + +	/* upgrade images */ +	{ +		.name		= "zimage", +		.offset		= (192 * SZ_1K), +		.size		= (2 * SZ_1M) - (192 * SZ_1K), +        }, { +		.name		= "cramfs", +		.offset		= (2 * SZ_1M), +		.size		= (20 * SZ_1M), +        }, +}; + +static struct s3c2410_nand_set __initdata jive_nand_sets[] = { +	[0] = { +		.name           = "flash", +		.nr_chips       = 1, +		.nr_partitions  = ARRAY_SIZE(jive_imageA_nand_part), +		.partitions     = jive_imageA_nand_part, +	}, +}; + +static struct s3c2410_platform_nand __initdata jive_nand_info = { +	/* set taken from osiris nand timings, possibly still conservative */ +	.tacls		= 30, +	.twrph0		= 55, +	.twrph1		= 40, +	.sets		= jive_nand_sets, +	.nr_sets	= ARRAY_SIZE(jive_nand_sets), +}; + +static int __init jive_mtdset(char *options) +{ +	struct s3c2410_nand_set *nand = &jive_nand_sets[0]; +	unsigned long set; + +	if (options == NULL || options[0] == '\0') +		return 0; + +	if (strict_strtoul(options, 10, &set)) { +		printk(KERN_ERR "failed to parse mtdset=%s\n", options); +		return 0; +	} + +	switch (set) { +	case 1: +		nand->nr_partitions = ARRAY_SIZE(jive_imageB_nand_part); +		nand->partitions = jive_imageB_nand_part; +	case 0: +		/* this is already setup in the nand info */ +		break; +	default: +		printk(KERN_ERR "Unknown mtd set %ld specified," +		       "using default.", set); +	} + +	return 0; +} + +/* parse the mtdset= option given to the kernel command line */ +__setup("mtdset=", jive_mtdset); + +/* LCD timing and setup */ + +#define LCD_XRES	 (240) +#define LCD_YRES	 (320) +#define LCD_LEFT_MARGIN  (12) +#define LCD_RIGHT_MARGIN (12) +#define LCD_LOWER_MARGIN (12) +#define LCD_UPPER_MARGIN (12) +#define LCD_VSYNC	 (2) +#define LCD_HSYNC	 (2) + +#define LCD_REFRESH	 (60) + +#define LCD_HTOT (LCD_HSYNC + LCD_LEFT_MARGIN + LCD_XRES + LCD_RIGHT_MARGIN) +#define LCD_VTOT (LCD_VSYNC + LCD_LOWER_MARGIN + LCD_YRES + LCD_UPPER_MARGIN) + +static struct s3c2410fb_display jive_vgg2432a4_display[] = { +	[0] = { +		.width		= LCD_XRES, +		.height		= LCD_YRES, +		.xres		= LCD_XRES, +		.yres		= LCD_YRES, +		.left_margin	= LCD_LEFT_MARGIN, +		.right_margin	= LCD_RIGHT_MARGIN, +		.upper_margin	= LCD_UPPER_MARGIN, +		.lower_margin	= LCD_LOWER_MARGIN, +		.hsync_len	= LCD_HSYNC, +		.vsync_len	= LCD_VSYNC, + +		.pixclock	= (1000000000000LL / +				   (LCD_REFRESH * LCD_HTOT * LCD_VTOT)), + +		.bpp		= 16, +		.type		= (S3C2410_LCDCON1_TFT16BPP | +				   S3C2410_LCDCON1_TFT), + +		.lcdcon5	= (S3C2410_LCDCON5_FRM565 | +				   S3C2410_LCDCON5_INVVLINE | +				   S3C2410_LCDCON5_INVVFRAME | +				   S3C2410_LCDCON5_INVVDEN | +				   S3C2410_LCDCON5_PWREN), +	}, +}; + +/* todo - put into gpio header */ + +#define S3C2410_GPCCON_MASK(x)	(3 << ((x) * 2)) +#define S3C2410_GPDCON_MASK(x)	(3 << ((x) * 2)) + +static struct s3c2410fb_mach_info jive_lcd_config = { +	.displays	 = jive_vgg2432a4_display, +	.num_displays	 = ARRAY_SIZE(jive_vgg2432a4_display), +	.default_display = 0, + +	/* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN +	 * and disable the pull down resistors on pins we are using for LCD +	 * data. */ + +	.gpcup		= (0xf << 1) | (0x3f << 10), + +	.gpccon		= (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE | +			   S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM | +			   S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 | +			   S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 | +			   S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7), + +	.gpccon_mask	= (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  | +			   S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  | +			   S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) | +			   S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) | +			   S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)), + +	.gpdup		= (0x3f << 2) | (0x3f << 10), + +	.gpdcon		= (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 | +			   S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 | +			   S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 | +			   S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 | +			   S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 | +			   S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23), + +	.gpdcon_mask	= (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) | +			   S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) | +			   S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) | +			   S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)| +			   S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)| +			   S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)), +}; + +/* ILI9320 support. */ + +static void jive_lcm_reset(unsigned int set) +{ +	printk(KERN_DEBUG "%s(%d)\n", __func__, set); + +	gpio_set_value(S3C2410_GPG(13), set); +} + +#undef LCD_UPPER_MARGIN +#define LCD_UPPER_MARGIN 2 + +static struct ili9320_platdata jive_lcm_config = { +	.hsize		= LCD_XRES, +	.vsize		= LCD_YRES, + +	.reset		= jive_lcm_reset, +	.suspend	= ILI9320_SUSPEND_DEEP, + +	.entry_mode	= ILI9320_ENTRYMODE_ID(3) | ILI9320_ENTRYMODE_BGR, +	.display2	= (ILI9320_DISPLAY2_FP(LCD_UPPER_MARGIN) | +			   ILI9320_DISPLAY2_BP(LCD_LOWER_MARGIN)), +	.display3	= 0x0, +	.display4	= 0x0, +	.rgb_if1	= (ILI9320_RGBIF1_RIM_RGB18 | +			   ILI9320_RGBIF1_RM | ILI9320_RGBIF1_CLK_RGBIF), +	.rgb_if2	= ILI9320_RGBIF2_DPL, +	.interface2	= 0x0, +	.interface3	= 0x3, +	.interface4	= (ILI9320_INTERFACE4_RTNE(16) | +			   ILI9320_INTERFACE4_DIVE(1)), +	.interface5	= 0x0, +	.interface6	= 0x0, +}; + +/* LCD SPI support */ + +static struct spi_gpio_platform_data jive_lcd_spi = { +	.sck		= S3C2410_GPG(8), +	.mosi		= S3C2410_GPB(8), +	.miso		= SPI_GPIO_NO_MISO, +}; + +static struct platform_device jive_device_lcdspi = { +	.name		= "spi-gpio", +	.id		= 1, +	.dev.platform_data = &jive_lcd_spi, +}; + + +/* WM8750 audio code SPI definition */ + +static struct spi_gpio_platform_data jive_wm8750_spi = { +	.sck		= S3C2410_GPB(4), +	.mosi		= S3C2410_GPB(9), +	.miso		= SPI_GPIO_NO_MISO, +}; + +static struct platform_device jive_device_wm8750 = { +	.name		= "spi-gpio", +	.id		= 2, +	.dev.platform_data = &jive_wm8750_spi, +}; + +/* JIVE SPI devices. */ + +static struct spi_board_info __initdata jive_spi_devs[] = { +	[0] = { +		.modalias	= "VGG2432A4", +		.bus_num	= 1, +		.chip_select	= 0, +		.mode		= SPI_MODE_3,	/* CPOL=1, CPHA=1 */ +		.max_speed_hz	= 100000, +		.platform_data	= &jive_lcm_config, +		.controller_data = (void *)S3C2410_GPB(7), +	}, { +		.modalias	= "WM8750", +		.bus_num	= 2, +		.chip_select	= 0, +		.mode		= SPI_MODE_0,	/* CPOL=0, CPHA=0 */ +		.max_speed_hz	= 100000, +		.controller_data = (void *)S3C2410_GPH(10), +	}, +}; + +/* I2C bus and device configuration. */ + +static struct s3c2410_platform_i2c jive_i2c_cfg __initdata = { +	.frequency	= 80 * 1000, +	.flags		= S3C_IICFLG_FILTER, +	.sda_delay	= 2, +}; + +static struct i2c_board_info jive_i2c_devs[] __initdata = { +	[0] = { +		I2C_BOARD_INFO("lis302dl", 0x1c), +		.irq	= IRQ_EINT14, +	}, +}; + +/* The platform devices being used. */ + +static struct platform_device *jive_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_rtc, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_lcd, +	&jive_device_lcdspi, +	&jive_device_wm8750, +	&s3c_device_nand, +	&s3c_device_usbgadget, +	&s3c2412_device_dma, +}; + +static struct s3c2410_udc_mach_info jive_udc_cfg __initdata = { +	.vbus_pin	= S3C2410_GPG(1),		/* detect is on GPG1 */ +}; + +/* Jive power management device */ + +#ifdef CONFIG_PM +static int jive_pm_suspend(void) +{ +	/* Write the magic value u-boot uses to check for resume into +	 * the INFORM0 register, and ensure INFORM1 is set to the +	 * correct address to resume from. */ + +	__raw_writel(0x2BED, S3C2412_INFORM0); +	__raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1); + +	return 0; +} + +static void jive_pm_resume(void) +{ +	__raw_writel(0x0, S3C2412_INFORM0); +} + +#else +#define jive_pm_suspend NULL +#define jive_pm_resume NULL +#endif + +static struct syscore_ops jive_pm_syscore_ops = { +	.suspend	= jive_pm_suspend, +	.resume		= jive_pm_resume, +}; + +static void __init jive_map_io(void) +{ +	s3c24xx_init_io(jive_iodesc, ARRAY_SIZE(jive_iodesc)); +	s3c24xx_init_uarts(jive_uartcfgs, ARRAY_SIZE(jive_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init jive_init_time(void) +{ +	s3c2412_init_clocks(12000000); +	samsung_timer_init(); +} + +static void jive_power_off(void) +{ +	printk(KERN_INFO "powering system down...\n"); + +	gpio_request_one(S3C2410_GPC(5), GPIOF_OUT_INIT_HIGH, NULL); +	gpio_free(S3C2410_GPC(5)); +} + +static void __init jive_machine_init(void) +{ +	/* register system core operations for managing low level suspend */ + +	register_syscore_ops(&jive_pm_syscore_ops); + +	/* write our sleep configurations for the IO. Pull down all unused +	 * IO, ensure that we have turned off all peripherals we do not +	 * need, and configure the ones we do need. */ + +	/* Port B sleep */ + +	__raw_writel(S3C2412_SLPCON_IN(0)   | +		     S3C2412_SLPCON_PULL(1) | +		     S3C2412_SLPCON_HIGH(2) | +		     S3C2412_SLPCON_PULL(3) | +		     S3C2412_SLPCON_PULL(4) | +		     S3C2412_SLPCON_PULL(5) | +		     S3C2412_SLPCON_PULL(6) | +		     S3C2412_SLPCON_HIGH(7) | +		     S3C2412_SLPCON_PULL(8) | +		     S3C2412_SLPCON_PULL(9) | +		     S3C2412_SLPCON_PULL(10), S3C2412_GPBSLPCON); + +	/* Port C sleep */ + +	__raw_writel(S3C2412_SLPCON_PULL(0) | +		     S3C2412_SLPCON_PULL(1) | +		     S3C2412_SLPCON_PULL(2) | +		     S3C2412_SLPCON_PULL(3) | +		     S3C2412_SLPCON_PULL(4) | +		     S3C2412_SLPCON_PULL(5) | +		     S3C2412_SLPCON_LOW(6)  | +		     S3C2412_SLPCON_PULL(6) | +		     S3C2412_SLPCON_PULL(7) | +		     S3C2412_SLPCON_PULL(8) | +		     S3C2412_SLPCON_PULL(9) | +		     S3C2412_SLPCON_PULL(10) | +		     S3C2412_SLPCON_PULL(11) | +		     S3C2412_SLPCON_PULL(12) | +		     S3C2412_SLPCON_PULL(13) | +		     S3C2412_SLPCON_PULL(14) | +		     S3C2412_SLPCON_PULL(15), S3C2412_GPCSLPCON); + +	/* Port D sleep */ + +	__raw_writel(S3C2412_SLPCON_ALL_PULL, S3C2412_GPDSLPCON); + +	/* Port F sleep */ + +	__raw_writel(S3C2412_SLPCON_LOW(0)  | +		     S3C2412_SLPCON_LOW(1)  | +		     S3C2412_SLPCON_LOW(2)  | +		     S3C2412_SLPCON_EINT(3) | +		     S3C2412_SLPCON_EINT(4) | +		     S3C2412_SLPCON_EINT(5) | +		     S3C2412_SLPCON_EINT(6) | +		     S3C2412_SLPCON_EINT(7), S3C2412_GPFSLPCON); + +	/* Port G sleep */ + +	__raw_writel(S3C2412_SLPCON_IN(0)    | +		     S3C2412_SLPCON_IN(1)    | +		     S3C2412_SLPCON_IN(2)    | +		     S3C2412_SLPCON_IN(3)    | +		     S3C2412_SLPCON_IN(4)    | +		     S3C2412_SLPCON_IN(5)    | +		     S3C2412_SLPCON_IN(6)    | +		     S3C2412_SLPCON_IN(7)    | +		     S3C2412_SLPCON_PULL(8)  | +		     S3C2412_SLPCON_PULL(9)  | +		     S3C2412_SLPCON_IN(10)   | +		     S3C2412_SLPCON_PULL(11) | +		     S3C2412_SLPCON_PULL(12) | +		     S3C2412_SLPCON_PULL(13) | +		     S3C2412_SLPCON_IN(14)   | +		     S3C2412_SLPCON_PULL(15), S3C2412_GPGSLPCON); + +	/* Port H sleep */ + +	__raw_writel(S3C2412_SLPCON_PULL(0) | +		     S3C2412_SLPCON_PULL(1) | +		     S3C2412_SLPCON_PULL(2) | +		     S3C2412_SLPCON_PULL(3) | +		     S3C2412_SLPCON_PULL(4) | +		     S3C2412_SLPCON_PULL(5) | +		     S3C2412_SLPCON_PULL(6) | +		     S3C2412_SLPCON_IN(7)   | +		     S3C2412_SLPCON_IN(8)   | +		     S3C2412_SLPCON_PULL(9) | +		     S3C2412_SLPCON_IN(10), S3C2412_GPHSLPCON); + +	/* initialise the power management now we've setup everything. */ + +	s3c_pm_init(); + +	/** TODO - check that this is after the cmdline option! */ +	s3c_nand_set_platdata(&jive_nand_info); + +	/* initialise the spi */ + +	gpio_request(S3C2410_GPG(13), "lcm reset"); +	gpio_direction_output(S3C2410_GPG(13), 0); + +	gpio_request(S3C2410_GPB(7), "jive spi"); +	gpio_direction_output(S3C2410_GPB(7), 1); + +	gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL); +	gpio_free(S3C2410_GPB(6)); + +	gpio_request_one(S3C2410_GPG(8), GPIOF_OUT_INIT_HIGH, NULL); +	gpio_free(S3C2410_GPG(8)); + +	/* initialise the WM8750 spi */ + +	gpio_request(S3C2410_GPH(10), "jive wm8750 spi"); +	gpio_direction_output(S3C2410_GPH(10), 1); + +	/* Turn off suspend on both USB ports, and switch the +	 * selectable USB port to USB device mode. */ + +	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +			      S3C2410_MISCCR_USBSUSPND0 | +			      S3C2410_MISCCR_USBSUSPND1, 0x0); + +	s3c24xx_udc_set_platdata(&jive_udc_cfg); +	s3c24xx_fb_set_platdata(&jive_lcd_config); + +	spi_register_board_info(jive_spi_devs, ARRAY_SIZE(jive_spi_devs)); + +	s3c_i2c0_set_platdata(&jive_i2c_cfg); +	i2c_register_board_info(0, jive_i2c_devs, ARRAY_SIZE(jive_i2c_devs)); + +	pm_power_off = jive_power_off; + +	platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices)); +} + +MACHINE_START(JIVE, "JIVE") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, + +	.init_irq	= s3c2412_init_irq, +	.map_io		= jive_map_io, +	.init_machine	= jive_machine_init, +	.init_time	= jive_init_time, +	.restart	= s3c2412_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c new file mode 100644 index 00000000000..5cc40ec1d25 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -0,0 +1,699 @@ +/* linux/arch/arm/mach-s3c2440/mach-mini2440.c + * + * Copyright (c) 2008 Ramax Lo <ramaxlo@gmail.com> + *      Based on mach-anubis.c by Ben Dooks <ben@simtec.co.uk> + *      and modifications by SBZ <sbz@spgui.org> and + *      Weibing <http://weibing.blogbus.com> and + *      Michel Pollet <buserror@gmail.com> + * + * For product information, visit http://code.google.com/p/mini2440/ + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/io.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/dm9000.h> +#include <linux/platform_data/at24.h> +#include <linux/platform_device.h> +#include <linux/gpio_keys.h> +#include <linux/i2c.h> +#include <linux/mmc/host.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> +#include <mach/fb.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <linux/platform_data/leds-s3c24xx.h> +#include <mach/regs-lcd.h> +#include <mach/irqs.h> +#include <mach/gpio-samsung.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/usb-s3c2410_udc.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <plat/gpio-cfg.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include <sound/s3c24xx_uda134x.h> + +#include "common.h" + +#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300) + +static struct map_desc mini2440_iodesc[] __initdata = { +	/* nothing to declare, move along */ +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + + +static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +}; + +/* USB device UDC support */ + +static struct s3c2410_udc_mach_info mini2440_udc_cfg __initdata = { +	.pullup_pin = S3C2410_GPC(5), +}; + + +/* LCD timing and setup */ + +/* + * This macro simplifies the table bellow + */ +#define _LCD_DECLARE(_clock,_xres,margin_left,margin_right,hsync, \ +			_yres,margin_top,margin_bottom,vsync, refresh) \ +	.width = _xres, \ +	.xres = _xres, \ +	.height = _yres, \ +	.yres = _yres, \ +	.left_margin	= margin_left,	\ +	.right_margin	= margin_right,	\ +	.upper_margin	= margin_top,	\ +	.lower_margin	= margin_bottom,	\ +	.hsync_len	= hsync,	\ +	.vsync_len	= vsync,	\ +	.pixclock	= ((_clock*100000000000LL) /	\ +			   ((refresh) * \ +			   (hsync + margin_left + _xres + margin_right) * \ +			   (vsync + margin_top + _yres + margin_bottom))), \ +	.bpp		= 16,\ +	.type		= (S3C2410_LCDCON1_TFT16BPP |\ +			   S3C2410_LCDCON1_TFT) + +static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = { +	[0] = {	/* mini2440 + 3.5" TFT + touchscreen */ +		_LCD_DECLARE( +			7,			/* The 3.5 is quite fast */ +			240, 21, 38, 6, 	/* x timing */ +			320, 4, 4, 2,		/* y timing */ +			60),			/* refresh rate */ +		.lcdcon5	= (S3C2410_LCDCON5_FRM565 | +				   S3C2410_LCDCON5_INVVLINE | +				   S3C2410_LCDCON5_INVVFRAME | +				   S3C2410_LCDCON5_INVVDEN | +				   S3C2410_LCDCON5_PWREN), +	}, +	[1] = { /* mini2440 + 7" TFT + touchscreen */ +		_LCD_DECLARE( +			10,			/* the 7" runs slower */ +			800, 40, 40, 48, 	/* x timing */ +			480, 29, 3, 3,		/* y timing */ +			50),			/* refresh rate */ +		.lcdcon5	= (S3C2410_LCDCON5_FRM565 | +				   S3C2410_LCDCON5_INVVLINE | +				   S3C2410_LCDCON5_INVVFRAME | +				   S3C2410_LCDCON5_PWREN), +	}, +	/* The VGA shield can outout at several resolutions. All share  +	 * the same timings, however, anything smaller than 1024x768 +	 * will only be displayed in the top left corner of a 1024x768 +	 * XGA output unless you add optional dip switches to the shield. +	 * Therefore timings for other resolutions have been omitted here. +	 */ +	[2] = { +		_LCD_DECLARE( +			10, +			1024, 1, 2, 2,		/* y timing */ +			768, 200, 16, 16, 	/* x timing */ +			24),	/* refresh rate, maximum stable, +				 tested with the FPGA shield */ +		.lcdcon5	= (S3C2410_LCDCON5_FRM565 | +				   S3C2410_LCDCON5_HWSWP), +	}, +	/* mini2440 + 3.5" TFT (LCD-W35i, LQ035Q1DG06 type) + touchscreen*/ +	[3] = { +		_LCD_DECLARE( +			/* clock */ +			7, +			/* xres, margin_right, margin_left, hsync */ +			320, 68, 66, 4, +			/* yres, margin_top, margin_bottom, vsync */ +			240, 4, 4, 9, +			/* refresh rate */ +			60), +		.lcdcon5	= (S3C2410_LCDCON5_FRM565 | +				   S3C2410_LCDCON5_INVVDEN | +				   S3C2410_LCDCON5_INVVFRAME | +				   S3C2410_LCDCON5_INVVLINE | +				   S3C2410_LCDCON5_INVVCLK | +				   S3C2410_LCDCON5_HWSWP), +	}, +}; + +/* todo - put into gpio header */ + +#define S3C2410_GPCCON_MASK(x)	(3 << ((x) * 2)) +#define S3C2410_GPDCON_MASK(x)	(3 << ((x) * 2)) + +static struct s3c2410fb_mach_info mini2440_fb_info __initdata = { +	.displays	 = &mini2440_lcd_cfg[0], /* not constant! see init */ +	.num_displays	 = 1, +	.default_display = 0, + +	/* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN +	 * and disable the pull down resistors on pins we are using for LCD +	 * data. */ + +	.gpcup		= (0xf << 1) | (0x3f << 10), + +	.gpccon		= (S3C2410_GPC1_VCLK   | S3C2410_GPC2_VLINE | +			   S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM | +			   S3C2410_GPC10_VD2   | S3C2410_GPC11_VD3 | +			   S3C2410_GPC12_VD4   | S3C2410_GPC13_VD5 | +			   S3C2410_GPC14_VD6   | S3C2410_GPC15_VD7), + +	.gpccon_mask	= (S3C2410_GPCCON_MASK(1)  | S3C2410_GPCCON_MASK(2)  | +			   S3C2410_GPCCON_MASK(3)  | S3C2410_GPCCON_MASK(4)  | +			   S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) | +			   S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) | +			   S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)), + +	.gpdup		= (0x3f << 2) | (0x3f << 10), + +	.gpdcon		= (S3C2410_GPD2_VD10  | S3C2410_GPD3_VD11 | +			   S3C2410_GPD4_VD12  | S3C2410_GPD5_VD13 | +			   S3C2410_GPD6_VD14  | S3C2410_GPD7_VD15 | +			   S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 | +			   S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 | +			   S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23), + +	.gpdcon_mask	= (S3C2410_GPDCON_MASK(2)  | S3C2410_GPDCON_MASK(3) | +			   S3C2410_GPDCON_MASK(4)  | S3C2410_GPDCON_MASK(5) | +			   S3C2410_GPDCON_MASK(6)  | S3C2410_GPDCON_MASK(7) | +			   S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)| +			   S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)| +			   S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)), +}; + +/* MMC/SD  */ + +static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = { +   .gpio_detect   = S3C2410_GPG(8), +   .gpio_wprotect = S3C2410_GPH(8), +   .set_power     = NULL, +   .ocr_avail     = MMC_VDD_32_33|MMC_VDD_33_34, +}; + +/* NAND Flash on MINI2440 board */ + +static struct mtd_partition mini2440_default_nand_part[] __initdata = { +	[0] = { +		.name	= "u-boot", +		.size	= SZ_256K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "u-boot-env", +		.size	= SZ_128K, +		.offset	= SZ_256K, +	}, +	[2] = { +		.name	= "kernel", +		/* 5 megabytes, for a kernel with no modules +		 * or a uImage with a ramdisk attached */ +		.size	= 0x00500000, +		.offset	= SZ_256K + SZ_128K, +	}, +	[3] = { +		.name	= "root", +		.offset	= SZ_256K + SZ_128K + 0x00500000, +		.size	= MTDPART_SIZ_FULL, +	}, +}; + +static struct s3c2410_nand_set mini2440_nand_sets[] __initdata = { +	[0] = { +		.name		= "nand", +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(mini2440_default_nand_part), +		.partitions	= mini2440_default_nand_part, +		.flash_bbt 	= 1, /* we use u-boot to create a BBT */ +	}, +}; + +static struct s3c2410_platform_nand mini2440_nand_info __initdata = { +	.tacls		= 0, +	.twrph0		= 25, +	.twrph1		= 15, +	.nr_sets	= ARRAY_SIZE(mini2440_nand_sets), +	.sets		= mini2440_nand_sets, +	.ignore_unset_ecc = 1, +}; + +/* DM9000AEP 10/100 ethernet controller */ + +static struct resource mini2440_dm9k_resource[] = { +	[0] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE, 4), +	[1] = DEFINE_RES_MEM(MACH_MINI2440_DM9K_BASE + 4, 4), +	[2] = DEFINE_RES_NAMED(IRQ_EINT7, 1, NULL, IORESOURCE_IRQ \ +						| IORESOURCE_IRQ_HIGHEDGE), +}; + +/* + * The DM9000 has no eeprom, and it's MAC address is set by + * the bootloader before starting the kernel. + */ +static struct dm9000_plat_data mini2440_dm9k_pdata = { +	.flags		= (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), +}; + +static struct platform_device mini2440_device_eth = { +	.name		= "dm9000", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(mini2440_dm9k_resource), +	.resource	= mini2440_dm9k_resource, +	.dev		= { +		.platform_data	= &mini2440_dm9k_pdata, +	}, +}; + +/*  CON5 + *	+--+	 /-----\ + *	|  |    |	| + *	|  |	|  BAT	| + *	|  |	 \_____/ + *	|  | + *	|  |  +----+  +----+ + *	|  |  | K5 |  | K1 | + *	|  |  +----+  +----+ + *	|  |  +----+  +----+ + *	|  |  | K4 |  | K2 | + *	|  |  +----+  +----+ + *	|  |  +----+  +----+ + *	|  |  | K6 |  | K3 | + *	|  |  +----+  +----+ + *	  ..... + */ +static struct gpio_keys_button mini2440_buttons[] = { +	{ +		.gpio		= S3C2410_GPG(0),		/* K1 */ +		.code		= KEY_F1, +		.desc		= "Button 1", +		.active_low	= 1, +	}, +	{ +		.gpio		= S3C2410_GPG(3),		/* K2 */ +		.code		= KEY_F2, +		.desc		= "Button 2", +		.active_low	= 1, +	}, +	{ +		.gpio		= S3C2410_GPG(5),		/* K3 */ +		.code		= KEY_F3, +		.desc		= "Button 3", +		.active_low	= 1, +	}, +	{ +		.gpio		= S3C2410_GPG(6),		/* K4 */ +		.code		= KEY_POWER, +		.desc		= "Power", +		.active_low	= 1, +	}, +	{ +		.gpio		= S3C2410_GPG(7),		/* K5 */ +		.code		= KEY_F5, +		.desc		= "Button 5", +		.active_low	= 1, +	}, +#if 0 +	/* this pin is also known as TCLK1 and seems to already +	 * marked as "in use" somehow in the kernel -- possibly wrongly */ +	{ +		.gpio		= S3C2410_GPG(11),	/* K6 */ +		.code		= KEY_F6, +		.desc		= "Button 6", +		.active_low	= 1, +	}, +#endif +}; + +static struct gpio_keys_platform_data mini2440_button_data = { +	.buttons	= mini2440_buttons, +	.nbuttons	= ARRAY_SIZE(mini2440_buttons), +}; + +static struct platform_device mini2440_button_device = { +	.name		= "gpio-keys", +	.id		= -1, +	.dev		= { +		.platform_data	= &mini2440_button_data, +	} +}; + +/* LEDS */ + +static struct s3c24xx_led_platdata mini2440_led1_pdata = { +	.name		= "led1", +	.gpio		= S3C2410_GPB(5), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.def_trigger	= "heartbeat", +}; + +static struct s3c24xx_led_platdata mini2440_led2_pdata = { +	.name		= "led2", +	.gpio		= S3C2410_GPB(6), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.def_trigger	= "nand-disk", +}; + +static struct s3c24xx_led_platdata mini2440_led3_pdata = { +	.name		= "led3", +	.gpio		= S3C2410_GPB(7), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.def_trigger	= "mmc0", +}; + +static struct s3c24xx_led_platdata mini2440_led4_pdata = { +	.name		= "led4", +	.gpio		= S3C2410_GPB(8), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.def_trigger	= "", +}; + +static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = { +	.name		= "backlight", +	.gpio		= S3C2410_GPG(4), +	.def_trigger	= "backlight", +}; + +static struct platform_device mini2440_led1 = { +	.name		= "s3c24xx_led", +	.id		= 1, +	.dev		= { +		.platform_data	= &mini2440_led1_pdata, +	}, +}; + +static struct platform_device mini2440_led2 = { +	.name		= "s3c24xx_led", +	.id		= 2, +	.dev		= { +		.platform_data	= &mini2440_led2_pdata, +	}, +}; + +static struct platform_device mini2440_led3 = { +	.name		= "s3c24xx_led", +	.id		= 3, +	.dev		= { +		.platform_data	= &mini2440_led3_pdata, +	}, +}; + +static struct platform_device mini2440_led4 = { +	.name		= "s3c24xx_led", +	.id		= 4, +	.dev		= { +		.platform_data	= &mini2440_led4_pdata, +	}, +}; + +static struct platform_device mini2440_led_backlight = { +	.name		= "s3c24xx_led", +	.id		= 5, +	.dev		= { +		.platform_data	= &mini2440_led_backlight_pdata, +	}, +}; + +/* AUDIO */ + +static struct s3c24xx_uda134x_platform_data mini2440_audio_pins = { +	.l3_clk = S3C2410_GPB(4), +	.l3_mode = S3C2410_GPB(2), +	.l3_data = S3C2410_GPB(3), +	.model = UDA134X_UDA1341 +}; + +static struct platform_device mini2440_audio = { +	.name		= "s3c24xx_uda134x", +	.id		= 0, +	.dev		= { +		.platform_data	= &mini2440_audio_pins, +	}, +}; + +/* + * I2C devices + */ +static struct at24_platform_data at24c08 = { +	.byte_len	= SZ_8K / 8, +	.page_size	= 16, +}; + +static struct i2c_board_info mini2440_i2c_devs[] __initdata = { +	{ +		I2C_BOARD_INFO("24c08", 0x50), +		.platform_data = &at24c08, +	}, +}; + +static struct platform_device uda1340_codec = { +		.name = "uda134x-codec", +		.id = -1, +}; + +static struct platform_device *mini2440_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_rtc, +	&s3c_device_usbgadget, +	&mini2440_device_eth, +	&mini2440_led1, +	&mini2440_led2, +	&mini2440_led3, +	&mini2440_led4, +	&mini2440_button_device, +	&s3c_device_nand, +	&s3c_device_sdi, +	&s3c_device_iis, +	&uda1340_codec, +	&mini2440_audio, +}; + +static void __init mini2440_map_io(void) +{ +	s3c24xx_init_io(mini2440_iodesc, ARRAY_SIZE(mini2440_iodesc)); +	s3c24xx_init_uarts(mini2440_uartcfgs, ARRAY_SIZE(mini2440_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init mini2440_init_time(void) +{ +	s3c2440_init_clocks(12000000); +	samsung_timer_init(); +} + +/* + * mini2440_features string + * + * t = Touchscreen present + * b = backlight control + * c = camera [TODO] + * 0-9 LCD configuration + * + */ +static char mini2440_features_str[12] __initdata = "0tb"; + +static int __init mini2440_features_setup(char *str) +{ +	if (str) +		strlcpy(mini2440_features_str, str, sizeof(mini2440_features_str)); +	return 1; +} + +__setup("mini2440=", mini2440_features_setup); + +#define FEATURE_SCREEN (1 << 0) +#define FEATURE_BACKLIGHT (1 << 1) +#define FEATURE_TOUCH (1 << 2) +#define FEATURE_CAMERA (1 << 3) + +struct mini2440_features_t { +	int count; +	int done; +	int lcd_index; +	struct platform_device *optional[8]; +}; + +static void __init mini2440_parse_features( +		struct mini2440_features_t * features, +		const char * features_str ) +{ +	const char * fp = features_str; + +	features->count = 0; +	features->done = 0; +	features->lcd_index = -1; + +	while (*fp) { +		char f = *fp++; + +		switch (f) { +		case '0'...'9':	/* tft screen */ +			if (features->done & FEATURE_SCREEN) { +				printk(KERN_INFO "MINI2440: '%c' ignored, " +					"screen type already set\n", f); +			} else { +				int li = f - '0'; +				if (li >= ARRAY_SIZE(mini2440_lcd_cfg)) +					printk(KERN_INFO "MINI2440: " +						"'%c' out of range LCD mode\n", f); +				else { +					features->optional[features->count++] = +							&s3c_device_lcd; +					features->lcd_index = li; +				} +			} +			features->done |= FEATURE_SCREEN; +			break; +		case 'b': +			if (features->done & FEATURE_BACKLIGHT) +				printk(KERN_INFO "MINI2440: '%c' ignored, " +					"backlight already set\n", f); +			else { +				features->optional[features->count++] = +						&mini2440_led_backlight; +			} +			features->done |= FEATURE_BACKLIGHT; +			break; +		case 't': +			printk(KERN_INFO "MINI2440: '%c' ignored, " +				"touchscreen not compiled in\n", f); +			break; +		case 'c': +			if (features->done & FEATURE_CAMERA) +				printk(KERN_INFO "MINI2440: '%c' ignored, " +					"camera already registered\n", f); +			else +				features->optional[features->count++] = +					&s3c_device_camif; +			features->done |= FEATURE_CAMERA; +			break; +		} +	} +} + +static void __init mini2440_init(void) +{ +	struct mini2440_features_t features = { 0 }; +	int i; + +	printk(KERN_INFO "MINI2440: Option string mini2440=%s\n", +			mini2440_features_str); + +	/* Parse the feature string */ +	mini2440_parse_features(&features, mini2440_features_str); + +	/* turn LCD on */ +	s3c_gpio_cfgpin(S3C2410_GPC(0), S3C2410_GPC0_LEND); + +	/* Turn the backlight early on */ +	WARN_ON(gpio_request_one(S3C2410_GPG(4), GPIOF_OUT_INIT_HIGH, NULL)); +	gpio_free(S3C2410_GPG(4)); + +	/* remove pullup on optional PWM backlight -- unused on 3.5 and 7"s */ +	gpio_request_one(S3C2410_GPB(1), GPIOF_IN, NULL); +	s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_UP); +	gpio_free(S3C2410_GPB(1)); + +	/* mark the key as input, without pullups (there is one on the board) */ +	for (i = 0; i < ARRAY_SIZE(mini2440_buttons); i++) { +		s3c_gpio_setpull(mini2440_buttons[i].gpio, S3C_GPIO_PULL_UP); +		s3c_gpio_cfgpin(mini2440_buttons[i].gpio, S3C2410_GPIO_INPUT); +	} +	if (features.lcd_index != -1) { +		int li; + +		mini2440_fb_info.displays = +			&mini2440_lcd_cfg[features.lcd_index]; + +		printk(KERN_INFO "MINI2440: LCD"); +		for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++) +			if (li == features.lcd_index) +				printk(" [%d:%dx%d]", li, +					mini2440_lcd_cfg[li].width, +					mini2440_lcd_cfg[li].height); +			else +				printk(" %d:%dx%d", li, +					mini2440_lcd_cfg[li].width, +					mini2440_lcd_cfg[li].height); +		printk("\n"); +		s3c24xx_fb_set_platdata(&mini2440_fb_info); +	} + +	s3c24xx_udc_set_platdata(&mini2440_udc_cfg); +	s3c24xx_mci_set_platdata(&mini2440_mmc_cfg); +	s3c_nand_set_platdata(&mini2440_nand_info); +	s3c_i2c0_set_platdata(NULL); + +	i2c_register_board_info(0, mini2440_i2c_devs, +				ARRAY_SIZE(mini2440_i2c_devs)); + +	platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); + +	if (features.count)	/* the optional features */ +		platform_add_devices(features.optional, features.count); + +} + + +MACHINE_START(MINI2440, "MINI2440") +	/* Maintainer: Michel Pollet <buserror@gmail.com> */ +	.atag_offset	= 0x100, +	.map_io		= mini2440_map_io, +	.init_machine	= mini2440_init, +	.init_irq	= s3c2440_init_irq, +	.init_time	= mini2440_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c new file mode 100644 index 00000000000..3ac2a54348d --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-n30.c @@ -0,0 +1,614 @@ +/* Machine specific code for the Acer n30, Acer N35, Navman PiN 570, + * Yakumo AlphaX and Airis NC05 PDAs. + * + * Copyright (c) 2003-2005 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * Copyright (c) 2005-2008 Christer Weinigel <christer@weinigel.se> + * + * There is a wiki with more information about the n30 port at + * http://handhelds.org/moin/moin.cgi/AcerN30Documentation . + * + * 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/types.h> + +#include <linux/gpio_keys.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/timer.h> +#include <linux/io.h> +#include <linux/mmc/host.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/fb.h> +#include <linux/platform_data/leds-s3c24xx.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> + +#include <linux/platform_data/i2c-s3c2410.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <plat/samsung-time.h> + +#include "common.h" + +static struct map_desc n30_iodesc[] __initdata = { +	/* nothing here yet */ +}; + +static struct s3c2410_uartcfg n30_uartcfgs[] = { +	/* Normal serial port */ +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x2c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	/* IR port */ +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.uart_flags  = UPF_CONS_FLOW, +		.ucon	     = 0x2c5, +		.ulcon	     = 0x43, +		.ufcon	     = 0x51, +	}, +	/* On the N30 the bluetooth controller is connected here. +	 * On the N35 and variants the GPS receiver is connected here. */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = 0x2c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +}; + +static struct s3c2410_udc_mach_info n30_udc_cfg __initdata = { +	.vbus_pin		= S3C2410_GPG(1), +	.vbus_pin_inverted	= 0, +	.pullup_pin		= S3C2410_GPB(3), +}; + +static struct gpio_keys_button n30_buttons[] = { +	{ +		.gpio		= S3C2410_GPF(0), +		.code		= KEY_POWER, +		.desc		= "Power", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(9), +		.code		= KEY_UP, +		.desc		= "Thumbwheel Up", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(8), +		.code		= KEY_DOWN, +		.desc		= "Thumbwheel Down", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(7), +		.code		= KEY_ENTER, +		.desc		= "Thumbwheel Press", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(7), +		.code		= KEY_HOMEPAGE, +		.desc		= "Home", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(6), +		.code		= KEY_CALENDAR, +		.desc		= "Calendar", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(5), +		.code		= KEY_ADDRESSBOOK, +		.desc		= "Contacts", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(4), +		.code		= KEY_MAIL, +		.desc		= "Mail", +		.active_low	= 0, +	}, +}; + +static struct gpio_keys_platform_data n30_button_data = { +	.buttons	= n30_buttons, +	.nbuttons	= ARRAY_SIZE(n30_buttons), +}; + +static struct platform_device n30_button_device = { +	.name		= "gpio-keys", +	.id		= -1, +	.dev		= { +		.platform_data	= &n30_button_data, +	} +}; + +static struct gpio_keys_button n35_buttons[] = { +	{ +		.gpio		= S3C2410_GPF(0), +		.code		= KEY_POWER, +		.type		= EV_PWR, +		.desc		= "Power", +		.active_low	= 0, +		.wakeup		= 1, +	}, +	{ +		.gpio		= S3C2410_GPG(9), +		.code		= KEY_UP, +		.desc		= "Joystick Up", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(8), +		.code		= KEY_DOWN, +		.desc		= "Joystick Down", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(6), +		.code		= KEY_DOWN, +		.desc		= "Joystick Left", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(5), +		.code		= KEY_DOWN, +		.desc		= "Joystick Right", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(7), +		.code		= KEY_ENTER, +		.desc		= "Joystick Press", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(7), +		.code		= KEY_HOMEPAGE, +		.desc		= "Home", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(6), +		.code		= KEY_CALENDAR, +		.desc		= "Calendar", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(5), +		.code		= KEY_ADDRESSBOOK, +		.desc		= "Contacts", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(4), +		.code		= KEY_MAIL, +		.desc		= "Mail", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPF(3), +		.code		= SW_RADIO, +		.desc		= "GPS Antenna", +		.active_low	= 0, +	}, +	{ +		.gpio		= S3C2410_GPG(2), +		.code		= SW_HEADPHONE_INSERT, +		.desc		= "Headphone", +		.active_low	= 0, +	}, +}; + +static struct gpio_keys_platform_data n35_button_data = { +	.buttons	= n35_buttons, +	.nbuttons	= ARRAY_SIZE(n35_buttons), +}; + +static struct platform_device n35_button_device = { +	.name		= "gpio-keys", +	.id		= -1, +	.num_resources	= 0, +	.dev		= { +		.platform_data	= &n35_button_data, +	} +}; + +/* This is the bluetooth LED on the device. */ +static struct s3c24xx_led_platdata n30_blue_led_pdata = { +	.name		= "blue_led", +	.gpio		= S3C2410_GPG(6), +	.def_trigger	= "", +}; + +/* This is the blue LED on the device. Originally used to indicate GPS activity + * by flashing. */ +static struct s3c24xx_led_platdata n35_blue_led_pdata = { +	.name		= "blue_led", +	.gpio		= S3C2410_GPD(8), +	.def_trigger	= "", +}; + +/* This LED is driven by the battery microcontroller, and is blinking + * red, blinking green or solid green when the battery is low, + * charging or full respectively.  By driving GPD9 low, it's possible + * to force the LED to blink red, so call that warning LED.  */ +static struct s3c24xx_led_platdata n30_warning_led_pdata = { +	.name		= "warning_led", +	.flags          = S3C24XX_LEDF_ACTLOW, +	.gpio		= S3C2410_GPD(9), +	.def_trigger	= "", +}; + +static struct s3c24xx_led_platdata n35_warning_led_pdata = { +	.name		= "warning_led", +	.flags          = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.gpio		= S3C2410_GPD(9), +	.def_trigger	= "", +}; + +static struct platform_device n30_blue_led = { +	.name		= "s3c24xx_led", +	.id		= 1, +	.dev		= { +		.platform_data	= &n30_blue_led_pdata, +	}, +}; + +static struct platform_device n35_blue_led = { +	.name		= "s3c24xx_led", +	.id		= 1, +	.dev		= { +		.platform_data	= &n35_blue_led_pdata, +	}, +}; + +static struct platform_device n30_warning_led = { +	.name		= "s3c24xx_led", +	.id		= 2, +	.dev		= { +		.platform_data	= &n30_warning_led_pdata, +	}, +}; + +static struct platform_device n35_warning_led = { +	.name		= "s3c24xx_led", +	.id		= 2, +	.dev		= { +		.platform_data	= &n35_warning_led_pdata, +	}, +}; + +static struct s3c2410fb_display n30_display __initdata = { +	.type		= S3C2410_LCDCON1_TFT, +	.width		= 240, +	.height		= 320, +	.pixclock	= 170000, + +	.xres		= 240, +	.yres		= 320, +	.bpp		= 16, +	.left_margin	= 3, +	.right_margin	= 40, +	.hsync_len	= 40, +	.upper_margin	= 2, +	.lower_margin	= 3, +	.vsync_len	= 2, + +	.lcdcon5 = S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME, +}; + +static struct s3c2410fb_mach_info n30_fb_info __initdata = { +	.displays	= &n30_display, +	.num_displays	= 1, +	.default_display = 0, +	.lpcsel		= 0x06, +}; + +static void n30_sdi_set_power(unsigned char power_mode, unsigned short vdd) +{ +	switch (power_mode) { +	case MMC_POWER_ON: +	case MMC_POWER_UP: +		gpio_set_value(S3C2410_GPG(4), 1); +		break; +	case MMC_POWER_OFF: +	default: +		gpio_set_value(S3C2410_GPG(4), 0); +		break; +	} +} + +static struct s3c24xx_mci_pdata n30_mci_cfg __initdata = { +	.gpio_detect	= S3C2410_GPF(1), +	.gpio_wprotect  = S3C2410_GPG(10), +	.ocr_avail	= MMC_VDD_32_33, +	.set_power	= n30_sdi_set_power, +}; + +static struct platform_device *n30_devices[] __initdata = { +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_ohci, +	&s3c_device_rtc, +	&s3c_device_usbgadget, +	&s3c_device_sdi, +	&n30_button_device, +	&n30_blue_led, +	&n30_warning_led, +}; + +static struct platform_device *n35_devices[] __initdata = { +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_rtc, +	&s3c_device_usbgadget, +	&s3c_device_sdi, +	&n35_button_device, +	&n35_blue_led, +	&n35_warning_led, +}; + +static struct s3c2410_platform_i2c __initdata n30_i2ccfg = { +	.flags		= 0, +	.slave_addr	= 0x10, +	.frequency	= 10*1000, +}; + +/* Lots of hardcoded stuff, but it sets up the hardware in a useful + * state so that we can boot Linux directly from flash. */ +static void __init n30_hwinit(void) +{ +	/* GPA0-11 special functions -- unknown what they do +	 * GPA12 N30 special function -- unknown what it does +	 *       N35/PiN output -- unknown what it does +	 * +	 * A12 is nGCS1 on the N30 and an output on the N35/PiN.  I +	 * don't think it does anything useful on the N30, so I ought +	 * to make it an output there too since it always driven to 0 +	 * as far as I can tell. */ +	if (machine_is_n30()) +		__raw_writel(0x007fffff, S3C2410_GPACON); +	if (machine_is_n35()) +		__raw_writel(0x007fefff, S3C2410_GPACON); +	__raw_writel(0x00000000, S3C2410_GPADAT); + +	/* GPB0 TOUT0 backlight level +	 * GPB1 output 1=backlight on +	 * GPB2 output IrDA enable 0=transceiver enabled, 1=disabled +	 * GPB3 output USB D+ pull up 0=disabled, 1=enabled +	 * GPB4 N30 output -- unknown function +	 *      N30/PiN GPS control 0=GPS enabled, 1=GPS disabled +	 * GPB5 output -- unknown function +	 * GPB6 input -- unknown function +	 * GPB7 output -- unknown function +	 * GPB8 output -- probably LCD driver enable +	 * GPB9 output -- probably LCD VSYNC driver enable +	 * GPB10 output -- probably LCD HSYNC driver enable +	 */ +	__raw_writel(0x00154556, S3C2410_GPBCON); +	__raw_writel(0x00000750, S3C2410_GPBDAT); +	__raw_writel(0x00000073, S3C2410_GPBUP); + +	/* GPC0 input RS232 DCD/DSR/RI +	 * GPC1 LCD +	 * GPC2 output RS232 DTR? +	 * GPC3 input RS232 DCD/DSR/RI +	 * GPC4 LCD +	 * GPC5 output 0=NAND write enabled, 1=NAND write protect +	 * GPC6 input -- unknown function +	 * GPC7 input charger status 0=charger connected +	 *      this input can be triggered by power on the USB device +	 *      port too, but will go back to disconnected soon after. +	 * GPC8 N30/N35 output -- unknown function, always driven to 1 +	 *      PiN input -- unknown function, always read as 1 +	 *      Make it an input with a pull up for all models. +	 * GPC9-15 LCD +	 */ +	__raw_writel(0xaaa80618, S3C2410_GPCCON); +	__raw_writel(0x0000014c, S3C2410_GPCDAT); +	__raw_writel(0x0000fef2, S3C2410_GPCUP); + +	/* GPD0 input -- unknown function +	 * GPD1-D7 LCD +	 * GPD8 N30 output -- unknown function +	 *      N35/PiN output 1=GPS LED on +	 * GPD9 output 0=power led blinks red, 1=normal power led function +	 * GPD10 output -- unknown function +	 * GPD11-15 LCD drivers +	 */ +	__raw_writel(0xaa95aaa4, S3C2410_GPDCON); +	__raw_writel(0x00000601, S3C2410_GPDDAT); +	__raw_writel(0x0000fbfe, S3C2410_GPDUP); + +	/* GPE0-4 I2S audio bus +	 * GPE5-10 SD/MMC bus +	 * E11-13 outputs -- unknown function, probably power management +	 * E14-15 I2C bus connected to the battery controller +	 */ +	__raw_writel(0xa56aaaaa, S3C2410_GPECON); +	__raw_writel(0x0000efc5, S3C2410_GPEDAT); +	__raw_writel(0x0000f81f, S3C2410_GPEUP); + +	/* GPF0  input 0=power button pressed +	 * GPF1  input SD/MMC switch 0=card present +	 * GPF2  N30 1=reset button pressed (inverted compared to the rest) +	 *	 N35/PiN 0=reset button pressed +	 * GPF3  N30/PiN input -- unknown function +	 *       N35 input GPS antenna position, 0=antenna closed, 1=open +	 * GPF4  input 0=button 4 pressed +	 * GPF5  input 0=button 3 pressed +	 * GPF6  input 0=button 2 pressed +	 * GPF7  input 0=button 1 pressed +	 */ +	__raw_writel(0x0000aaaa, S3C2410_GPFCON); +	__raw_writel(0x00000000, S3C2410_GPFDAT); +	__raw_writel(0x000000ff, S3C2410_GPFUP); + +	/* GPG0  input RS232 DCD/DSR/RI +	 * GPG1  input 1=USB gadget port has power from a host +	 * GPG2  N30 input -- unknown function +	 *       N35/PiN input 0=headphones plugged in, 1=not plugged in +	 * GPG3  N30 output -- unknown function +	 *       N35/PiN input with unknown function +	 * GPG4  N30 output 0=MMC enabled, 1=MMC disabled +	 * GPG5  N30 output 0=BlueTooth chip disabled, 1=enabled +	 *       N35/PiN input joystick right +	 * GPG6  N30 output 0=blue led on, 1=off +	 *       N35/PiN input joystick left +	 * GPG7  input 0=thumbwheel pressed +	 * GPG8  input 0=thumbwheel down +	 * GPG9  input 0=thumbwheel up +	 * GPG10 input SD/MMC write protect switch +	 * GPG11 N30 input -- unknown function +	 *       N35 output 0=GPS antenna powered, 1=not powered +	 *       PiN output -- unknown function +	 * GPG12-15 touch screen functions +	 * +	 * The pullups differ between the models, so enable all +	 * pullups that are enabled on any of the models. +	 */ +	if (machine_is_n30()) +		__raw_writel(0xff0a956a, S3C2410_GPGCON); +	if (machine_is_n35()) +		__raw_writel(0xff4aa92a, S3C2410_GPGCON); +	__raw_writel(0x0000e800, S3C2410_GPGDAT); +	__raw_writel(0x0000f86f, S3C2410_GPGUP); + +	/* GPH0/1/2/3 RS232 serial port +	 * GPH4/5 IrDA serial port +	 * GPH6/7  N30 BlueTooth serial port +	 *         N35/PiN GPS receiver +	 * GPH8 input -- unknown function +	 * GPH9 CLKOUT0 HCLK -- unknown use +	 * GPH10 CLKOUT1 FCLK -- unknown use +	 * +	 * The pull ups for H6/H7 are enabled on N30 but not on the +	 * N35/PiN.  I suppose is useful for a budget model of the N30 +	 * with no bluetooh.  It doesn't hurt to have the pull ups +	 * enabled on the N35, so leave them enabled for all models. +	 */ +	__raw_writel(0x0028aaaa, S3C2410_GPHCON); +	__raw_writel(0x000005ef, S3C2410_GPHDAT); +	__raw_writel(0x0000063f, S3C2410_GPHUP); +} + +static void __init n30_map_io(void) +{ +	s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc)); +	n30_hwinit(); +	s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init n30_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +/* GPB3 is the line that controls the pull-up for the USB D+ line */ + +static void __init n30_init(void) +{ +	WARN_ON(gpio_request(S3C2410_GPG(4), "mmc power")); + +	s3c24xx_fb_set_platdata(&n30_fb_info); +	s3c24xx_udc_set_platdata(&n30_udc_cfg); +	s3c24xx_mci_set_platdata(&n30_mci_cfg); +	s3c_i2c0_set_platdata(&n30_i2ccfg); + +	/* Turn off suspend on both USB ports, and switch the +	 * selectable USB port to USB device mode. */ + +	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +			      S3C2410_MISCCR_USBSUSPND0 | +			      S3C2410_MISCCR_USBSUSPND1, 0x0); + +	if (machine_is_n30()) { +		/* Turn off suspend on both USB ports, and switch the +		 * selectable USB port to USB device mode. */ +		s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +				      S3C2410_MISCCR_USBSUSPND0 | +				      S3C2410_MISCCR_USBSUSPND1, 0x0); + +		platform_add_devices(n30_devices, ARRAY_SIZE(n30_devices)); +	} + +	if (machine_is_n35()) { +		/* Turn off suspend and switch the selectable USB port +		 * to USB device mode.  Turn on suspend for the host +		 * port since it is not connected on the N35. +		 * +		 * Actually, the host port is available at some pads +		 * on the back of the device, so it would actually be +		 * possible to add a USB device inside the N35 if you +		 * are willing to do some hardware modifications. */ +		s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +				      S3C2410_MISCCR_USBSUSPND0 | +				      S3C2410_MISCCR_USBSUSPND1, +				      S3C2410_MISCCR_USBSUSPND0); + +		platform_add_devices(n35_devices, ARRAY_SIZE(n35_devices)); +	} +} + +MACHINE_START(N30, "Acer-N30") +	/* Maintainer: Christer Weinigel <christer@weinigel.se>, +				Ben Dooks <ben-linux@fluff.org> +	*/ +	.atag_offset	= 0x100, +	.init_time	= n30_init_time, +	.init_machine	= n30_init, +	.init_irq	= s3c2410_init_irq, +	.map_io		= n30_map_io, +	.restart	= s3c2410_restart, +MACHINE_END + +MACHINE_START(N35, "Acer-N35") +	/* Maintainer: Christer Weinigel <christer@weinigel.se> +	*/ +	.atag_offset	= 0x100, +	.init_time	= n30_init_time, +	.init_machine	= n30_init, +	.init_irq	= s3c2410_init_irq, +	.map_io		= n30_map_io, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c new file mode 100644 index 00000000000..c82c281ce35 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c @@ -0,0 +1,163 @@ +/* linux/arch/arm/mach-s3c2440/mach-nexcoder.c + * + * Copyright (c) 2004 Nex Vision + *   Guillaume GOURAT <guillaume.gourat@nexvision.tv> + * + * 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. + * + * Modifications: + *     15-10-2004 GG  Created initial version + *     12-03-2005 BJD Updated for release + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/string.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <linux/mtd/map.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/setup.h> +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +//#include <asm/debug-ll.h> +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <plat/gpio-cfg.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include "common.h" + +static struct map_desc nexcoder_iodesc[] __initdata = { +	/* nothing here yet */ +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg nexcoder_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +/* NOR Flash on NexVision NexCoder 2440 board */ + +static struct resource nexcoder_nor_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS0, SZ_8M), +}; + +static struct map_info nexcoder_nor_map = { +	.bankwidth = 2, +}; + +static struct platform_device nexcoder_device_nor = { +	.name		= "mtd-flash", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(nexcoder_nor_resource), +	.resource	= nexcoder_nor_resource, +	.dev = +	{ +		.platform_data = &nexcoder_nor_map, +	} +}; + +/* Standard Nexcoder devices */ + +static struct platform_device *nexcoder_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, + 	&s3c_device_rtc, +	&s3c_device_camif, +	&s3c_device_spi0, +	&s3c_device_spi1, +	&nexcoder_device_nor, +}; + +static void __init nexcoder_sensorboard_init(void) +{ +	/* Initialize SCCB bus */ +	gpio_request_one(S3C2410_GPE(14), GPIOF_OUT_INIT_HIGH, NULL); +	gpio_free(S3C2410_GPE(14)); /* IICSCL */ +	gpio_request_one(S3C2410_GPE(15), GPIOF_OUT_INIT_HIGH, NULL); +	gpio_free(S3C2410_GPE(15)); /* IICSDA */ + +	/* Power up the sensor board */ +	gpio_request_one(S3C2410_GPF(1), GPIOF_OUT_INIT_HIGH, NULL); +	gpio_free(S3C2410_GPF(1)); /* CAM_GPIO7 => nLDO_PWRDN */ +	gpio_request_one(S3C2410_GPF(2), GPIOF_OUT_INIT_LOW, NULL); +	gpio_free(S3C2410_GPF(2)); /* CAM_GPIO6 => CAM_PWRDN */ +} + +static void __init nexcoder_map_io(void) +{ +	s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc)); +	s3c24xx_init_uarts(nexcoder_uartcfgs, ARRAY_SIZE(nexcoder_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); + +	nexcoder_sensorboard_init(); +} + +static void __init nexcoder_init_time(void) +{ +	s3c2440_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init nexcoder_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	platform_add_devices(nexcoder_devices, ARRAY_SIZE(nexcoder_devices)); +}; + +MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440") +	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */ +	.atag_offset	= 0x100, +	.map_io		= nexcoder_map_io, +	.init_machine	= nexcoder_init, +	.init_irq	= s3c2440_init_irq, +	.init_time	= nexcoder_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-osiris-dvs.c b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c new file mode 100644 index 00000000000..33afb919009 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-osiris-dvs.c @@ -0,0 +1,184 @@ +/* linux/arch/arm/mach-s3c2440/mach-osiris-dvs.c + * + * Copyright (c) 2009 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * Simtec Osiris Dynamic Voltage Scaling support. + * + * 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/module.h> +#include <linux/platform_device.h> +#include <linux/cpufreq.h> +#include <linux/gpio.h> + +#include <linux/i2c/tps65010.h> + +#include <plat/cpu-freq.h> +#include <mach/gpio-samsung.h> + +#define OSIRIS_GPIO_DVS	S3C2410_GPB(5) + +static bool dvs_en; + +static void osiris_dvs_tps_setdvs(bool on) +{ +	unsigned vregs1 = 0, vdcdc2 = 0; + +	if (!on) { +		vdcdc2 = TPS_VCORE_DISCH | TPS_LP_COREOFF; +		vregs1 = TPS_LDO1_OFF;	/* turn off in low-power mode */ +	} + +	dvs_en = on; +	vdcdc2 |= TPS_VCORE_1_3V | TPS_VCORE_LP_1_0V; +	vregs1 |= TPS_LDO2_ENABLE | TPS_LDO1_ENABLE; + +	tps65010_config_vregs1(vregs1); +	tps65010_config_vdcdc2(vdcdc2); +} + +static bool is_dvs(struct s3c_freq *f) +{ +	/* at the moment, we assume ARMCLK = HCLK => DVS */ +	return f->armclk == f->hclk; +} + +/* keep track of current state */ +static bool cur_dvs = false; + +static int osiris_dvs_notify(struct notifier_block *nb, +			      unsigned long val, void *data) +{ +	struct cpufreq_freqs *cf = data; +	struct s3c_cpufreq_freqs *freqs = to_s3c_cpufreq(cf); +	bool old_dvs = is_dvs(&freqs->old); +	bool new_dvs = is_dvs(&freqs->new); +	int ret = 0; + +	if (!dvs_en) +		return 0; + +	printk(KERN_DEBUG "%s: old %ld,%ld new %ld,%ld\n", __func__, +	       freqs->old.armclk, freqs->old.hclk, +	       freqs->new.armclk, freqs->new.hclk); + +	switch (val) { +	case CPUFREQ_PRECHANGE: +		if (old_dvs & !new_dvs || +		    cur_dvs & !new_dvs) { +			pr_debug("%s: exiting dvs\n", __func__); +			cur_dvs = false; +			gpio_set_value(OSIRIS_GPIO_DVS, 1); +		} +		break; +	case CPUFREQ_POSTCHANGE: +		if (!old_dvs & new_dvs || +		    !cur_dvs & new_dvs) { +			pr_debug("entering dvs\n"); +			cur_dvs = true; +			gpio_set_value(OSIRIS_GPIO_DVS, 0); +		} +		break; +	} + +	return ret; +} + +static struct notifier_block osiris_dvs_nb = { +	.notifier_call	= osiris_dvs_notify, +}; + +static int osiris_dvs_probe(struct platform_device *pdev) +{ +	int ret; + +	dev_info(&pdev->dev, "initialising\n"); + +	ret = gpio_request(OSIRIS_GPIO_DVS, "osiris-dvs"); +	if (ret) { +		dev_err(&pdev->dev, "cannot claim gpio\n"); +		goto err_nogpio; +	} + +	/* start with dvs disabled */ +	gpio_direction_output(OSIRIS_GPIO_DVS, 1); + +	ret = cpufreq_register_notifier(&osiris_dvs_nb, +					CPUFREQ_TRANSITION_NOTIFIER); +	if (ret) { +		dev_err(&pdev->dev, "failed to register with cpufreq\n"); +		goto err_nofreq; +	} + +	osiris_dvs_tps_setdvs(true); + +	return 0; + +err_nofreq: +	gpio_free(OSIRIS_GPIO_DVS); + +err_nogpio: +	return ret; +} + +static int osiris_dvs_remove(struct platform_device *pdev) +{ +	dev_info(&pdev->dev, "exiting\n"); + +	/* disable any current dvs */ +	gpio_set_value(OSIRIS_GPIO_DVS, 1); +	osiris_dvs_tps_setdvs(false); + +	cpufreq_unregister_notifier(&osiris_dvs_nb, +				    CPUFREQ_TRANSITION_NOTIFIER); + +	gpio_free(OSIRIS_GPIO_DVS); + +	return 0; +} + +/* the CONFIG_PM block is so small, it isn't worth actaully compiling it + * out if the configuration isn't set. */ + +static int osiris_dvs_suspend(struct device *dev) +{ +	gpio_set_value(OSIRIS_GPIO_DVS, 1); +	osiris_dvs_tps_setdvs(false); +	cur_dvs = false; + +	return 0; +} + +static int osiris_dvs_resume(struct device *dev) +{ +	osiris_dvs_tps_setdvs(true); +	return 0; +} + +static const struct dev_pm_ops osiris_dvs_pm = { +	.suspend	= osiris_dvs_suspend, +	.resume		= osiris_dvs_resume, +}; + +static struct platform_driver osiris_dvs_driver = { +	.probe		= osiris_dvs_probe, +	.remove		= osiris_dvs_remove, +	.driver		= { +		.name	= "osiris-dvs", +		.owner	= THIS_MODULE, +		.pm	= &osiris_dvs_pm, +	}, +}; + +module_platform_driver(osiris_dvs_driver); + +MODULE_DESCRIPTION("Simtec OSIRIS DVS support"); +MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:osiris-dvs"); diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c new file mode 100644 index 00000000000..189147b80ec --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2005-2008 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <linux/i2c/tps65010.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> +#include <asm/irq.h> + +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <plat/cpu.h> +#include <plat/cpu-freq.h> +#include <plat/devs.h> +#include <plat/gpio-cfg.h> +#include <plat/samsung-time.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> + +#include "common.h" +#include "osiris.h" +#include "regs-mem.h" + +/* onboard perihperal map */ + +static struct map_desc osiris_iodesc[] __initdata = { +  /* ISA IO areas (may be over-written later) */ + +  { +	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE, +	  .pfn		= __phys_to_pfn(S3C2410_CS5), +	  .length	= SZ_16M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)S3C24XX_VA_ISA_WORD, +	  .pfn		= __phys_to_pfn(S3C2410_CS5), +	  .length	= SZ_16M, +	  .type		= MT_DEVICE, +  }, + +  /* CPLD control registers */ + +  { +	  .virtual	= (u32)OSIRIS_VA_CTRL0, +	  .pfn		= __phys_to_pfn(OSIRIS_PA_CTRL0), +	  .length	= SZ_16K, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)OSIRIS_VA_CTRL1, +	  .pfn		= __phys_to_pfn(OSIRIS_PA_CTRL1), +	  .length	= SZ_16K, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)OSIRIS_VA_CTRL2, +	  .pfn		= __phys_to_pfn(OSIRIS_PA_CTRL2), +	  .length	= SZ_16K, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)OSIRIS_VA_IDREG, +	  .pfn		= __phys_to_pfn(OSIRIS_PA_IDREG), +	  .length	= SZ_16K, +	  .type		= MT_DEVICE, +  }, +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg osiris_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +		.clk_sel	= S3C2410_UCON_CLKSEL1 | S3C2410_UCON_CLKSEL2, +	} +}; + +/* NAND Flash on Osiris board */ + +static int external_map[]   = { 2 }; +static int chip0_map[]      = { 0 }; +static int chip1_map[]      = { 1 }; + +static struct mtd_partition __initdata osiris_default_nand_part[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_16K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "/boot", +		.size	= SZ_4M - SZ_16K, +		.offset	= SZ_16K, +	}, +	[2] = { +		.name	= "user1", +		.offset	= SZ_4M, +		.size	= SZ_32M - SZ_4M, +	}, +	[3] = { +		.name	= "user2", +		.offset	= SZ_32M, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +static struct mtd_partition __initdata osiris_default_nand_part_large[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= SZ_128K, +		.offset	= 0, +	}, +	[1] = { +		.name	= "/boot", +		.size	= SZ_4M - SZ_128K, +		.offset	= SZ_128K, +	}, +	[2] = { +		.name	= "user1", +		.offset	= SZ_4M, +		.size	= SZ_32M - SZ_4M, +	}, +	[3] = { +		.name	= "user2", +		.offset	= SZ_32M, +		.size	= MTDPART_SIZ_FULL, +	} +}; + +/* the Osiris has 3 selectable slots for nand-flash, the two + * on-board chip areas, as well as the external slot. + * + * Note, there is no current hot-plug support for the External + * socket. +*/ + +static struct s3c2410_nand_set __initdata osiris_nand_sets[] = { +	[1] = { +		.name		= "External", +		.nr_chips	= 1, +		.nr_map		= external_map, +		.options	= NAND_SCAN_SILENT_NODEV, +		.nr_partitions	= ARRAY_SIZE(osiris_default_nand_part), +		.partitions	= osiris_default_nand_part, +	}, +	[0] = { +		.name		= "chip0", +		.nr_chips	= 1, +		.nr_map		= chip0_map, +		.nr_partitions	= ARRAY_SIZE(osiris_default_nand_part), +		.partitions	= osiris_default_nand_part, +	}, +	[2] = { +		.name		= "chip1", +		.nr_chips	= 1, +		.nr_map		= chip1_map, +		.options	= NAND_SCAN_SILENT_NODEV, +		.nr_partitions	= ARRAY_SIZE(osiris_default_nand_part), +		.partitions	= osiris_default_nand_part, +	}, +}; + +static void osiris_nand_select(struct s3c2410_nand_set *set, int slot) +{ +	unsigned int tmp; + +	slot = set->nr_map[slot] & 3; + +	pr_debug("osiris_nand: selecting slot %d (set %p,%p)\n", +		 slot, set, set->nr_map); + +	tmp = __raw_readb(OSIRIS_VA_CTRL0); +	tmp &= ~OSIRIS_CTRL0_NANDSEL; +	tmp |= slot; + +	pr_debug("osiris_nand: ctrl0 now %02x\n", tmp); + +	__raw_writeb(tmp, OSIRIS_VA_CTRL0); +} + +static struct s3c2410_platform_nand __initdata osiris_nand_info = { +	.tacls		= 25, +	.twrph0		= 60, +	.twrph1		= 60, +	.nr_sets	= ARRAY_SIZE(osiris_nand_sets), +	.sets		= osiris_nand_sets, +	.select_chip	= osiris_nand_select, +}; + +/* PCMCIA control and configuration */ + +static struct resource osiris_pcmcia_resource[] = { +	[0] = DEFINE_RES_MEM(0x0f000000, SZ_1M), +	[1] = DEFINE_RES_MEM(0x0c000000, SZ_1M), +}; + +static struct platform_device osiris_pcmcia = { +	.name		= "osiris-pcmcia", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(osiris_pcmcia_resource), +	.resource	= osiris_pcmcia_resource, +}; + +/* Osiris power management device */ + +#ifdef CONFIG_PM +static unsigned char pm_osiris_ctrl0; + +static int osiris_pm_suspend(void) +{ +	unsigned int tmp; + +	pm_osiris_ctrl0 = __raw_readb(OSIRIS_VA_CTRL0); +	tmp = pm_osiris_ctrl0 & ~OSIRIS_CTRL0_NANDSEL; + +	/* ensure correct NAND slot is selected on resume */ +	if ((pm_osiris_ctrl0 & OSIRIS_CTRL0_BOOT_INT) == 0) +	        tmp |= 2; + +	__raw_writeb(tmp, OSIRIS_VA_CTRL0); + +	/* ensure that an nRESET is not generated on resume. */ +	gpio_request_one(S3C2410_GPA(21), GPIOF_OUT_INIT_HIGH, NULL); +	gpio_free(S3C2410_GPA(21)); + +	return 0; +} + +static void osiris_pm_resume(void) +{ +	if (pm_osiris_ctrl0 & OSIRIS_CTRL0_FIX8) +		__raw_writeb(OSIRIS_CTRL1_FIX8, OSIRIS_VA_CTRL1); + +	__raw_writeb(pm_osiris_ctrl0, OSIRIS_VA_CTRL0); + +	s3c_gpio_cfgpin(S3C2410_GPA(21), S3C2410_GPA21_nRSTOUT); +} + +#else +#define osiris_pm_suspend NULL +#define osiris_pm_resume NULL +#endif + +static struct syscore_ops osiris_pm_syscore_ops = { +	.suspend	= osiris_pm_suspend, +	.resume		= osiris_pm_resume, +}; + +/* Link for DVS driver to TPS65011 */ + +static void osiris_tps_release(struct device *dev) +{ +	/* static device, do not need to release anything */ +} + +static struct platform_device osiris_tps_device = { +	.name	= "osiris-dvs", +	.id	= -1, +	.dev.release = osiris_tps_release, +}; + +static int osiris_tps_setup(struct i2c_client *client, void *context) +{ +	osiris_tps_device.dev.parent = &client->dev; +	return platform_device_register(&osiris_tps_device); +} + +static int osiris_tps_remove(struct i2c_client *client, void *context) +{ +	platform_device_unregister(&osiris_tps_device); +	return 0; +} + +static struct tps65010_board osiris_tps_board = { +	.base		= -1,	/* GPIO can go anywhere at the moment */ +	.setup		= osiris_tps_setup, +	.teardown	= osiris_tps_remove, +}; + +/* I2C devices fitted. */ + +static struct i2c_board_info osiris_i2c_devs[] __initdata = { +	{ +		I2C_BOARD_INFO("tps65011", 0x48), +		.irq	= IRQ_EINT20, +		.platform_data = &osiris_tps_board, +	}, +}; + +/* Standard Osiris devices */ + +static struct platform_device *osiris_devices[] __initdata = { +	&s3c2410_device_dclk, +	&s3c_device_i2c0, +	&s3c_device_wdt, +	&s3c_device_nand, +	&osiris_pcmcia, +}; + +static struct s3c_cpufreq_board __initdata osiris_cpufreq = { +	.refresh	= 7800, /* refresh period is 7.8usec */ +	.auto_io	= 1, +	.need_io	= 1, +}; + +static void __init osiris_map_io(void) +{ +	unsigned long flags; + +	s3c24xx_init_io(osiris_iodesc, ARRAY_SIZE(osiris_iodesc)); +	s3c24xx_init_uarts(osiris_uartcfgs, ARRAY_SIZE(osiris_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); + +	/* check for the newer revision boards with large page nand */ + +	if ((__raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK) >= 4) { +		printk(KERN_INFO "OSIRIS-B detected (revision %d)\n", +		       __raw_readb(OSIRIS_VA_IDREG) & OSIRIS_ID_REVMASK); +		osiris_nand_sets[0].partitions = osiris_default_nand_part_large; +		osiris_nand_sets[0].nr_partitions = ARRAY_SIZE(osiris_default_nand_part_large); +	} else { +		/* write-protect line to the NAND */ +		gpio_request_one(S3C2410_GPA(0), GPIOF_OUT_INIT_HIGH, NULL); +		gpio_free(S3C2410_GPA(0)); +	} + +	/* fix bus configuration (nBE settings wrong on ABLE pre v2.20) */ + +	local_irq_save(flags); +	__raw_writel(__raw_readl(S3C2410_BWSCON) | S3C2410_BWSCON_ST1 | S3C2410_BWSCON_ST2 | S3C2410_BWSCON_ST3 | S3C2410_BWSCON_ST4 | S3C2410_BWSCON_ST5, S3C2410_BWSCON); +	local_irq_restore(flags); +} + +static void __init osiris_init_time(void) +{ +	s3c2440_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init osiris_init(void) +{ +	register_syscore_ops(&osiris_pm_syscore_ops); + +	s3c_i2c0_set_platdata(NULL); +	s3c_nand_set_platdata(&osiris_nand_info); + +	s3c_cpufreq_setboard(&osiris_cpufreq); + +	i2c_register_board_info(0, osiris_i2c_devs, +				ARRAY_SIZE(osiris_i2c_devs)); + +	platform_add_devices(osiris_devices, ARRAY_SIZE(osiris_devices)); +}; + +MACHINE_START(OSIRIS, "Simtec-OSIRIS") +	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */ +	.atag_offset	= 0x100, +	.map_io		= osiris_map_io, +	.init_irq	= s3c2440_init_irq, +	.init_machine	= osiris_init, +	.init_time	= osiris_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-otom.c b/arch/arm/mach-s3c24xx/mach-otom.c new file mode 100644 index 00000000000..45833001186 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-otom.c @@ -0,0 +1,126 @@ +/* + * + * Copyright (c) 2004 Nex Vision + *   Guillaume GOURAT <guillaume.gourat@nexvision.fr> + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <linux/platform_data/i2c-s3c2410.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "otom.h" + +static struct map_desc otom11_iodesc[] __initdata = { +  /* Device area */ +	{ (u32)OTOM_VA_CS8900A_BASE, OTOM_PA_CS8900A_BASE, SZ_16M, MT_DEVICE }, +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG12 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg otom11_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	/* port 2 is not actually used */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +/* NOR Flash on NexVision OTOM board */ + +static struct resource otom_nor_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS0, SZ_4M), +}; + +static struct platform_device otom_device_nor = { +	.name		= "mtd-flash", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(otom_nor_resource), +	.resource	= otom_nor_resource, +}; + +/* Standard OTOM devices */ + +static struct platform_device *otom11_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, + 	&s3c_device_rtc, +	&otom_device_nor, +}; + +static void __init otom11_map_io(void) +{ +	s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc)); +	s3c24xx_init_uarts(otom11_uartcfgs, ARRAY_SIZE(otom11_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init otom11_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init otom11_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	platform_add_devices(otom11_devices, ARRAY_SIZE(otom11_devices)); +} + +MACHINE_START(OTOM, "Nex Vision - Otom 1.1") +	/* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */ +	.atag_offset	= 0x100, +	.map_io		= otom11_map_io, +	.init_machine	= otom11_init, +	.init_irq	= s3c2410_init_irq, +	.init_time	= otom11_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c new file mode 100644 index 00000000000..228c9094519 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -0,0 +1,356 @@ +/* linux/arch/arm/mach-s3c2410/mach-qt2410.c + * + * Copyright (C) 2006 by OpenMoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_gpio.h> +#include <linux/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/leds-s3c24xx.h> +#include <mach/regs-lcd.h> +#include <mach/fb.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <mach/gpio-samsung.h> + +#include <plat/gpio-cfg.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/pm.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "common-smdk.h" + +static struct map_desc qt2410_iodesc[] __initdata = { +	{ 0xe0000000, __phys_to_pfn(S3C2410_CS3+0x01000000), SZ_1M, MT_DEVICE } +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg smdk2410_uartcfgs[] = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +/* LCD driver info */ + +static struct s3c2410fb_display qt2410_lcd_cfg[] __initdata = { +	{ +		/* Configuration for 640x480 SHARP LQ080V3DG01 */ +		.lcdcon5 = S3C2410_LCDCON5_FRM565 | +			   S3C2410_LCDCON5_INVVLINE | +			   S3C2410_LCDCON5_INVVFRAME | +			   S3C2410_LCDCON5_PWREN | +			   S3C2410_LCDCON5_HWSWP, + +		.type		= S3C2410_LCDCON1_TFT, +		.width		= 640, +		.height		= 480, + +		.pixclock	= 40000, /* HCLK/4 */ +		.xres		= 640, +		.yres		= 480, +		.bpp		= 16, +		.left_margin	= 44, +		.right_margin	= 116, +		.hsync_len	= 96, +		.upper_margin	= 19, +		.lower_margin	= 11, +		.vsync_len	= 15, +	}, +	{ +		/* Configuration for 480x640 toppoly TD028TTEC1 */ +		.lcdcon5 = S3C2410_LCDCON5_FRM565 | +			   S3C2410_LCDCON5_INVVLINE | +			   S3C2410_LCDCON5_INVVFRAME | +			   S3C2410_LCDCON5_PWREN | +			   S3C2410_LCDCON5_HWSWP, + +		.type		= S3C2410_LCDCON1_TFT, +		.width		= 480, +		.height		= 640, +		.pixclock	= 40000, /* HCLK/4 */ +		.xres		= 480, +		.yres		= 640, +		.bpp		= 16, +		.left_margin	= 8, +		.right_margin	= 24, +		.hsync_len	= 8, +		.upper_margin	= 2, +		.lower_margin	= 4, +		.vsync_len	= 2, +	}, +	{ +		/* Config for 240x320 LCD */ +		.lcdcon5 = S3C2410_LCDCON5_FRM565 | +			   S3C2410_LCDCON5_INVVLINE | +			   S3C2410_LCDCON5_INVVFRAME | +			   S3C2410_LCDCON5_PWREN | +			   S3C2410_LCDCON5_HWSWP, + +		.type		= S3C2410_LCDCON1_TFT, +		.width		= 240, +		.height		= 320, +		.pixclock	= 100000, /* HCLK/10 */ +		.xres		= 240, +		.yres		= 320, +		.bpp		= 16, +		.left_margin	= 13, +		.right_margin	= 8, +		.hsync_len	= 4, +		.upper_margin	= 2, +		.lower_margin	= 7, +		.vsync_len	= 4, +	}, +}; + + +static struct s3c2410fb_mach_info qt2410_fb_info __initdata = { +	.displays 	= qt2410_lcd_cfg, +	.num_displays 	= ARRAY_SIZE(qt2410_lcd_cfg), +	.default_display = 0, + +	.lpcsel		= ((0xCE6) & ~7) | 1<<4, +}; + +/* CS8900 */ + +static struct resource qt2410_cs89x0_resources[] = { +	[0] = DEFINE_RES_MEM(0x19000000, 17), +	[1] = DEFINE_RES_IRQ(IRQ_EINT9), +}; + +static struct platform_device qt2410_cs89x0 = { +	.name		= "cirrus-cs89x0", +	.num_resources	= ARRAY_SIZE(qt2410_cs89x0_resources), +	.resource	= qt2410_cs89x0_resources, +}; + +/* LED */ + +static struct s3c24xx_led_platdata qt2410_pdata_led = { +	.gpio		= S3C2410_GPB(0), +	.flags		= S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +	.name		= "led", +	.def_trigger	= "timer", +}; + +static struct platform_device qt2410_led = { +	.name		= "s3c24xx_led", +	.id		= 0, +	.dev		= { +		.platform_data = &qt2410_pdata_led, +	}, +}; + +/* SPI */ + +static struct spi_gpio_platform_data spi_gpio_cfg = { +	.sck		= S3C2410_GPG(7), +	.mosi		= S3C2410_GPG(6), +	.miso		= S3C2410_GPG(5), +}; + +static struct platform_device qt2410_spi = { +	.name		= "spi-gpio", +	.id		= 1, +	.dev.platform_data = &spi_gpio_cfg, +}; + +/* Board devices */ + +static struct platform_device *qt2410_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_sdi, +	&s3c_device_usbgadget, +	&qt2410_spi, +	&qt2410_cs89x0, +	&qt2410_led, +}; + +static struct mtd_partition __initdata qt2410_nand_part[] = { +	[0] = { +		.name	= "U-Boot", +		.size	= 0x30000, +		.offset	= 0, +	}, +	[1] = { +		.name	= "U-Boot environment", +		.offset = 0x30000, +		.size	= 0x4000, +	}, +	[2] = { +		.name	= "kernel", +		.offset = 0x34000, +		.size	= SZ_2M, +	}, +	[3] = { +		.name	= "initrd", +		.offset	= 0x234000, +		.size	= SZ_4M, +	}, +	[4] = { +		.name	= "jffs2", +		.offset = 0x634000, +		.size	= 0x39cc000, +	}, +}; + +static struct s3c2410_nand_set __initdata qt2410_nand_sets[] = { +	[0] = { +		.name		= "NAND", +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(qt2410_nand_part), +		.partitions	= qt2410_nand_part, +	}, +}; + +/* choose a set of timings which should suit most 512Mbit + * chips and beyond. + */ + +static struct s3c2410_platform_nand __initdata qt2410_nand_info = { +	.tacls		= 20, +	.twrph0		= 60, +	.twrph1		= 20, +	.nr_sets	= ARRAY_SIZE(qt2410_nand_sets), +	.sets		= qt2410_nand_sets, +}; + +/* UDC */ + +static struct s3c2410_udc_mach_info qt2410_udc_cfg = { +}; + +static char tft_type = 's'; + +static int __init qt2410_tft_setup(char *str) +{ +	tft_type = str[0]; +	return 1; +} + +__setup("tft=", qt2410_tft_setup); + +static void __init qt2410_map_io(void) +{ +	s3c24xx_init_io(qt2410_iodesc, ARRAY_SIZE(qt2410_iodesc)); +	s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init qt2410_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init qt2410_machine_init(void) +{ +	s3c_nand_set_platdata(&qt2410_nand_info); + +	switch (tft_type) { +	case 'p': /* production */ +		qt2410_fb_info.default_display = 1; +		break; +	case 'b': /* big */ +		qt2410_fb_info.default_display = 0; +		break; +	case 's': /* small */ +	default: +		qt2410_fb_info.default_display = 2; +		break; +	} +	s3c24xx_fb_set_platdata(&qt2410_fb_info); + +	/* set initial state of the LED GPIO */ +	WARN_ON(gpio_request_one(S3C2410_GPB(0), GPIOF_OUT_INIT_HIGH, NULL)); +	gpio_free(S3C2410_GPB(0)); + +	s3c24xx_udc_set_platdata(&qt2410_udc_cfg); +	s3c_i2c0_set_platdata(NULL); + +	WARN_ON(gpio_request(S3C2410_GPB(5), "spi cs")); +	gpio_direction_output(S3C2410_GPB(5), 1); + +	platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices)); +	s3c_pm_init(); +} + +MACHINE_START(QT2410, "QT2410") +	.atag_offset	= 0x100, +	.map_io		= qt2410_map_io, +	.init_irq	= s3c2410_init_irq, +	.init_machine	= qt2410_machine_init, +	.init_time	= qt2410_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c new file mode 100644 index 00000000000..e2c6541909c --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -0,0 +1,816 @@ +/* + * Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev, + * Copyright (c) 2007-2010 Vasily Khoruzhick + * + * based on smdk2440 written by Ben Dooks + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/memblock.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/device.h> +#include <linux/pda_power.h> +#include <linux/pwm_backlight.h> +#include <linux/pwm.h> +#include <linux/s3c_adc_battery.h> +#include <linux/leds.h> +#include <linux/i2c.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include <linux/mmc/host.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/touchscreen-s3c2410.h> +#include <linux/platform_data/usb-s3c2410_udc.h> + +#include <sound/uda1380.h> + +#include <mach/fb.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/pm.h> +#include <plat/samsung-time.h> +#include <plat/gpio-cfg.h> + +#include "common.h" +#include "h1940.h" + +#define LCD_PWM_PERIOD 192960 +#define LCD_PWM_DUTY 127353 + +static struct map_desc rx1950_iodesc[] __initdata = { +}; + +static struct s3c2410_uartcfg rx1950_uartcfgs[] __initdata = { +	[0] = { +	       .hwport = 0, +	       .flags = 0, +	       .ucon = 0x3c5, +	       .ulcon = 0x03, +	       .ufcon = 0x51, +		.clk_sel = S3C2410_UCON_CLKSEL3, +	}, +	[1] = { +	       .hwport = 1, +	       .flags = 0, +	       .ucon = 0x3c5, +	       .ulcon = 0x03, +	       .ufcon = 0x51, +		.clk_sel = S3C2410_UCON_CLKSEL3, +	}, +	/* IR port */ +	[2] = { +	       .hwport = 2, +	       .flags = 0, +	       .ucon = 0x3c5, +	       .ulcon = 0x43, +	       .ufcon = 0xf1, +		.clk_sel = S3C2410_UCON_CLKSEL3, +	}, +}; + +static struct s3c2410fb_display rx1950_display = { +	.type = S3C2410_LCDCON1_TFT, +	.width = 240, +	.height = 320, +	.xres = 240, +	.yres = 320, +	.bpp = 16, + +	.pixclock = 260000, +	.left_margin = 10, +	.right_margin = 20, +	.hsync_len = 10, +	.upper_margin = 2, +	.lower_margin = 2, +	.vsync_len = 2, + +	.lcdcon5 = S3C2410_LCDCON5_FRM565 | +			   S3C2410_LCDCON5_INVVCLK | +			   S3C2410_LCDCON5_INVVLINE | +			   S3C2410_LCDCON5_INVVFRAME | +			   S3C2410_LCDCON5_HWSWP | +			   (0x02 << 13) | +			   (0x02 << 15), + +}; + +static int power_supply_init(struct device *dev) +{ +	return gpio_request(S3C2410_GPF(2), "cable plugged"); +} + +static int rx1950_is_ac_online(void) +{ +	return !gpio_get_value(S3C2410_GPF(2)); +} + +static void power_supply_exit(struct device *dev) +{ +	gpio_free(S3C2410_GPF(2)); +} + +static char *rx1950_supplicants[] = { +	"main-battery" +}; + +static struct pda_power_pdata power_supply_info = { +	.init			= power_supply_init, +	.is_ac_online		= rx1950_is_ac_online, +	.exit			= power_supply_exit, +	.supplied_to		= rx1950_supplicants, +	.num_supplicants	= ARRAY_SIZE(rx1950_supplicants), +}; + +static struct resource power_supply_resources[] = { +	[0] = DEFINE_RES_NAMED(IRQ_EINT2, 1, "ac", IORESOURCE_IRQ \ +			| IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE), +}; + +static struct platform_device power_supply = { +	.name			= "pda-power", +	.id			= -1, +	.dev			= { +					.platform_data = +						&power_supply_info, +	}, +	.resource		= power_supply_resources, +	.num_resources		= ARRAY_SIZE(power_supply_resources), +}; + +static const struct s3c_adc_bat_thresh bat_lut_noac[] = { +	{ .volt = 4100, .cur = 156, .level = 100}, +	{ .volt = 4050, .cur = 156, .level = 95}, +	{ .volt = 4025, .cur = 141, .level = 90}, +	{ .volt = 3995, .cur = 144, .level = 85}, +	{ .volt = 3957, .cur = 162, .level = 80}, +	{ .volt = 3931, .cur = 147, .level = 75}, +	{ .volt = 3902, .cur = 147, .level = 70}, +	{ .volt = 3863, .cur = 153, .level = 65}, +	{ .volt = 3838, .cur = 150, .level = 60}, +	{ .volt = 3800, .cur = 153, .level = 55}, +	{ .volt = 3765, .cur = 153, .level = 50}, +	{ .volt = 3748, .cur = 172, .level = 45}, +	{ .volt = 3740, .cur = 153, .level = 40}, +	{ .volt = 3714, .cur = 175, .level = 35}, +	{ .volt = 3710, .cur = 156, .level = 30}, +	{ .volt = 3963, .cur = 156, .level = 25}, +	{ .volt = 3672, .cur = 178, .level = 20}, +	{ .volt = 3651, .cur = 178, .level = 15}, +	{ .volt = 3629, .cur = 178, .level = 10}, +	{ .volt = 3612, .cur = 162, .level = 5}, +	{ .volt = 3605, .cur = 162, .level = 0}, +}; + +static const struct s3c_adc_bat_thresh bat_lut_acin[] = { +	{ .volt = 4200, .cur = 0, .level = 100}, +	{ .volt = 4190, .cur = 0, .level = 99}, +	{ .volt = 4178, .cur = 0, .level = 95}, +	{ .volt = 4110, .cur = 0, .level = 70}, +	{ .volt = 4076, .cur = 0, .level = 65}, +	{ .volt = 4046, .cur = 0, .level = 60}, +	{ .volt = 4021, .cur = 0, .level = 55}, +	{ .volt = 3999, .cur = 0, .level = 50}, +	{ .volt = 3982, .cur = 0, .level = 45}, +	{ .volt = 3965, .cur = 0, .level = 40}, +	{ .volt = 3957, .cur = 0, .level = 35}, +	{ .volt = 3948, .cur = 0, .level = 30}, +	{ .volt = 3936, .cur = 0, .level = 25}, +	{ .volt = 3927, .cur = 0, .level = 20}, +	{ .volt = 3906, .cur = 0, .level = 15}, +	{ .volt = 3880, .cur = 0, .level = 10}, +	{ .volt = 3829, .cur = 0, .level = 5}, +	{ .volt = 3820, .cur = 0, .level = 0}, +}; + +static int rx1950_bat_init(void) +{ +	int ret; + +	ret = gpio_request(S3C2410_GPJ(2), "rx1950-charger-enable-1"); +	if (ret) +		goto err_gpio1; +	ret = gpio_request(S3C2410_GPJ(3), "rx1950-charger-enable-2"); +	if (ret) +		goto err_gpio2; + +	return 0; + +err_gpio2: +	gpio_free(S3C2410_GPJ(2)); +err_gpio1: +	return ret; +} + +static void rx1950_bat_exit(void) +{ +	gpio_free(S3C2410_GPJ(2)); +	gpio_free(S3C2410_GPJ(3)); +} + +static void rx1950_enable_charger(void) +{ +	gpio_direction_output(S3C2410_GPJ(2), 1); +	gpio_direction_output(S3C2410_GPJ(3), 1); +} + +static void rx1950_disable_charger(void) +{ +	gpio_direction_output(S3C2410_GPJ(2), 0); +	gpio_direction_output(S3C2410_GPJ(3), 0); +} + +static DEFINE_SPINLOCK(rx1950_blink_spin); + +static int rx1950_led_blink_set(unsigned gpio, int state, +	unsigned long *delay_on, unsigned long *delay_off) +{ +	int blink_gpio, check_gpio; + +	switch (gpio) { +	case S3C2410_GPA(6): +		blink_gpio = S3C2410_GPA(4); +		check_gpio = S3C2410_GPA(3); +		break; +	case S3C2410_GPA(7): +		blink_gpio = S3C2410_GPA(3); +		check_gpio = S3C2410_GPA(4); +		break; +	default: +		return -EINVAL; +		break; +	} + +	if (delay_on && delay_off && !*delay_on && !*delay_off) +		*delay_on = *delay_off = 500; + +	spin_lock(&rx1950_blink_spin); + +	switch (state) { +	case GPIO_LED_NO_BLINK_LOW: +	case GPIO_LED_NO_BLINK_HIGH: +		if (!gpio_get_value(check_gpio)) +			gpio_set_value(S3C2410_GPJ(6), 0); +		gpio_set_value(blink_gpio, 0); +		gpio_set_value(gpio, state); +		break; +	case GPIO_LED_BLINK: +		gpio_set_value(gpio, 0); +		gpio_set_value(S3C2410_GPJ(6), 1); +		gpio_set_value(blink_gpio, 1); +		break; +	} + +	spin_unlock(&rx1950_blink_spin); + +	return 0; +} + +static struct gpio_led rx1950_leds_desc[] = { +	{ +		.name			= "Green", +		.default_trigger	= "main-battery-full", +		.gpio			= S3C2410_GPA(6), +		.retain_state_suspended	= 1, +	}, +	{ +		.name			= "Red", +		.default_trigger +			= "main-battery-charging-blink-full-solid", +		.gpio			= S3C2410_GPA(7), +		.retain_state_suspended	= 1, +	}, +	{ +		.name			= "Blue", +		.default_trigger	= "rx1950-acx-mem", +		.gpio			= S3C2410_GPA(11), +		.retain_state_suspended	= 1, +	}, +}; + +static struct gpio_led_platform_data rx1950_leds_pdata = { +	.num_leds	= ARRAY_SIZE(rx1950_leds_desc), +	.leds		= rx1950_leds_desc, +	.gpio_blink_set	= rx1950_led_blink_set, +}; + +static struct platform_device rx1950_leds = { +	.name	= "leds-gpio", +	.id		= -1, +	.dev	= { +				.platform_data = &rx1950_leds_pdata, +	}, +}; + +static struct s3c_adc_bat_pdata rx1950_bat_cfg = { +	.init = rx1950_bat_init, +	.exit = rx1950_bat_exit, +	.enable_charger = rx1950_enable_charger, +	.disable_charger = rx1950_disable_charger, +	.gpio_charge_finished = S3C2410_GPF(3), +	.lut_noac = bat_lut_noac, +	.lut_noac_cnt = ARRAY_SIZE(bat_lut_noac), +	.lut_acin = bat_lut_acin, +	.lut_acin_cnt = ARRAY_SIZE(bat_lut_acin), +	.volt_channel = 0, +	.current_channel = 1, +	.volt_mult = 4235, +	.current_mult = 2900, +	.internal_impedance = 200, +}; + +static struct platform_device rx1950_battery = { +	.name             = "s3c-adc-battery", +	.id               = -1, +	.dev = { +		.parent = &s3c_device_adc.dev, +		.platform_data = &rx1950_bat_cfg, +	}, +}; + +static struct s3c2410fb_mach_info rx1950_lcd_cfg = { +	.displays = &rx1950_display, +	.num_displays = 1, +	.default_display = 0, + +	.lpcsel = 0x02, +	.gpccon = 0xaa9556a9, +	.gpccon_mask = 0xffc003fc, +	.gpcup = 0x0000ffff, +	.gpcup_mask = 0xffffffff, + +	.gpdcon = 0xaa90aaa1, +	.gpdcon_mask = 0xffc0fff0, +	.gpdup = 0x0000fcfd, +	.gpdup_mask = 0xffffffff, + +}; + +static struct pwm_device *lcd_pwm; + +static void rx1950_lcd_power(int enable) +{ +	int i; +	static int enabled; +	if (enabled == enable) +		return; +	if (!enable) { + +		/* GPC11-GPC15->OUTPUT */ +		for (i = 11; i < 16; i++) +			gpio_direction_output(S3C2410_GPC(i), 1); + +		/* Wait a bit here... */ +		mdelay(100); + +		/* GPD2-GPD7->OUTPUT */ +		/* GPD11-GPD15->OUTPUT */ +		/* GPD2-GPD7->1, GPD11-GPD15->1 */ +		for (i = 2; i < 8; i++) +			gpio_direction_output(S3C2410_GPD(i), 1); +		for (i = 11; i < 16; i++) +			gpio_direction_output(S3C2410_GPD(i), 1); + +		/* Wait a bit here...*/ +		mdelay(100); + +		/* GPB0->OUTPUT, GPB0->0 */ +		gpio_direction_output(S3C2410_GPB(0), 0); + +		/* GPC1-GPC4->OUTPUT, GPC1-4->0 */ +		for (i = 1; i < 5; i++) +			gpio_direction_output(S3C2410_GPC(i), 0); + +		/* GPC15-GPC11->0 */ +		for (i = 11; i < 16; i++) +			gpio_direction_output(S3C2410_GPC(i), 0); + +		/* GPD15-GPD11->0, GPD2->GPD7->0 */ +		for (i = 11; i < 16; i++) +			gpio_direction_output(S3C2410_GPD(i), 0); + +		for (i = 2; i < 8; i++) +			gpio_direction_output(S3C2410_GPD(i), 0); + +		/* GPC6->0, GPC7->0, GPC5->0 */ +		gpio_direction_output(S3C2410_GPC(6), 0); +		gpio_direction_output(S3C2410_GPC(7), 0); +		gpio_direction_output(S3C2410_GPC(5), 0); + +		/* GPB1->OUTPUT, GPB1->0 */ +		gpio_direction_output(S3C2410_GPB(1), 0); +		pwm_config(lcd_pwm, 0, LCD_PWM_PERIOD); +		pwm_disable(lcd_pwm); + +		/* GPC0->0, GPC10->0 */ +		gpio_direction_output(S3C2410_GPC(0), 0); +		gpio_direction_output(S3C2410_GPC(10), 0); +	} else { +		pwm_config(lcd_pwm, LCD_PWM_DUTY, LCD_PWM_PERIOD); +		pwm_enable(lcd_pwm); + +		gpio_direction_output(S3C2410_GPC(0), 1); +		gpio_direction_output(S3C2410_GPC(5), 1); + +		s3c_gpio_cfgpin(S3C2410_GPB(1), S3C2410_GPB1_TOUT1); +		gpio_direction_output(S3C2410_GPC(7), 1); + +		for (i = 1; i < 5; i++) +			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2)); + +		for (i = 11; i < 16; i++) +			s3c_gpio_cfgpin(S3C2410_GPC(i), S3C_GPIO_SFN(2)); + +		for (i = 2; i < 8; i++) +			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2)); + +		for (i = 11; i < 16; i++) +			s3c_gpio_cfgpin(S3C2410_GPD(i), S3C_GPIO_SFN(2)); + +		gpio_direction_output(S3C2410_GPC(10), 1); +		gpio_direction_output(S3C2410_GPC(6), 1); +	} +	enabled = enable; +} + +static void rx1950_bl_power(int enable) +{ +	static int enabled; +	if (enabled == enable) +		return; +	if (!enable) { +			gpio_direction_output(S3C2410_GPB(0), 0); +	} else { +			/* LED driver need a "push" to power on */ +			gpio_direction_output(S3C2410_GPB(0), 1); +			/* Warm up backlight for one period of PWM. +			 * Without this trick its almost impossible to +			 * enable backlight with low brightness value +			 */ +			ndelay(48000); +			s3c_gpio_cfgpin(S3C2410_GPB(0), S3C2410_GPB0_TOUT0); +	} +	enabled = enable; +} + +static int rx1950_backlight_init(struct device *dev) +{ +	WARN_ON(gpio_request(S3C2410_GPB(0), "Backlight")); +	lcd_pwm = pwm_request(1, "RX1950 LCD"); +	if (IS_ERR(lcd_pwm)) { +		dev_err(dev, "Unable to request PWM for LCD power!\n"); +		return PTR_ERR(lcd_pwm); +	} + +	rx1950_lcd_power(1); +	rx1950_bl_power(1); + +	return 0; +} + +static void rx1950_backlight_exit(struct device *dev) +{ +	rx1950_bl_power(0); +	rx1950_lcd_power(0); + +	pwm_free(lcd_pwm); +	gpio_free(S3C2410_GPB(0)); +} + + +static int rx1950_backlight_notify(struct device *dev, int brightness) +{ +	if (!brightness) { +		rx1950_bl_power(0); +		rx1950_lcd_power(0); +	} else { +		rx1950_lcd_power(1); +		rx1950_bl_power(1); +	} +	return brightness; +} + +static struct platform_pwm_backlight_data rx1950_backlight_data = { +	.pwm_id = 0, +	.max_brightness = 24, +	.dft_brightness = 4, +	.pwm_period_ns = 48000, +	.enable_gpio = -1, +	.init = rx1950_backlight_init, +	.notify = rx1950_backlight_notify, +	.exit = rx1950_backlight_exit, +}; + +static struct platform_device rx1950_backlight = { +	.name = "pwm-backlight", +	.dev = { +		.parent = &samsung_device_pwm.dev, +		.platform_data = &rx1950_backlight_data, +	}, +}; + +static void rx1950_set_mmc_power(unsigned char power_mode, unsigned short vdd) +{ +	switch (power_mode) { +	case MMC_POWER_OFF: +		gpio_direction_output(S3C2410_GPJ(1), 0); +		break; +	case MMC_POWER_UP: +	case MMC_POWER_ON: +		gpio_direction_output(S3C2410_GPJ(1), 1); +		break; +	default: +		break; +	} +} + +static struct s3c24xx_mci_pdata rx1950_mmc_cfg __initdata = { +	.gpio_detect = S3C2410_GPF(5), +	.gpio_wprotect = S3C2410_GPH(8), +	.set_power = rx1950_set_mmc_power, +	.ocr_avail = MMC_VDD_32_33, +}; + +static struct mtd_partition rx1950_nand_part[] = { +	[0] = { +			.name = "Boot0", +			.offset = 0, +			.size = 0x4000, +			.mask_flags = MTD_WRITEABLE, +	}, +	[1] = { +			.name = "Boot1", +			.offset = MTDPART_OFS_APPEND, +			.size = 0x40000, +			.mask_flags = MTD_WRITEABLE, +	}, +	[2] = { +			.name = "Kernel", +			.offset = MTDPART_OFS_APPEND, +			.size = 0x300000, +			.mask_flags = 0, +	}, +	[3] = { +			.name = "Filesystem", +			.offset = MTDPART_OFS_APPEND, +			.size = MTDPART_SIZ_FULL, +			.mask_flags = 0, +	}, +}; + +static struct s3c2410_nand_set rx1950_nand_sets[] = { +	[0] = { +			.name = "Internal", +			.nr_chips = 1, +			.nr_partitions = ARRAY_SIZE(rx1950_nand_part), +			.partitions = rx1950_nand_part, +	}, +}; + +static struct s3c2410_platform_nand rx1950_nand_info = { +	.tacls = 25, +	.twrph0 = 50, +	.twrph1 = 15, +	.nr_sets = ARRAY_SIZE(rx1950_nand_sets), +	.sets = rx1950_nand_sets, +}; + +static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = { +	.vbus_pin = S3C2410_GPG(5), +	.vbus_pin_inverted = 1, +	.pullup_pin = S3C2410_GPJ(5), +}; + +static struct s3c2410_ts_mach_info rx1950_ts_cfg __initdata = { +	.delay = 10000, +	.presc = 49, +	.oversampling_shift = 3, +}; + +static struct gpio_keys_button rx1950_gpio_keys_table[] = { +	{ +		.code		= KEY_POWER, +		.gpio		= S3C2410_GPF(0), +		.active_low	= 1, +		.desc		= "Power button", +		.wakeup		= 1, +	}, +	{ +		.code		= KEY_F5, +		.gpio		= S3C2410_GPF(7), +		.active_low	= 1, +		.desc		= "Record button", +	}, +	{ +		.code		= KEY_F1, +		.gpio		= S3C2410_GPG(0), +		.active_low	= 1, +		.desc		= "Calendar button", +	}, +	{ +		.code		= KEY_F2, +		.gpio		= S3C2410_GPG(2), +		.active_low	= 1, +		.desc		= "Contacts button", +	}, +	{ +		.code		= KEY_F3, +		.gpio		= S3C2410_GPG(3), +		.active_low	= 1, +		.desc		= "Mail button", +	}, +	{ +		.code		= KEY_F4, +		.gpio		= S3C2410_GPG(7), +		.active_low	= 1, +		.desc		= "WLAN button", +	}, +	{ +		.code		= KEY_LEFT, +		.gpio		= S3C2410_GPG(10), +		.active_low	= 1, +		.desc		= "Left button", +	}, +	{ +		.code		= KEY_RIGHT, +		.gpio		= S3C2410_GPG(11), +		.active_low	= 1, +		.desc		= "Right button", +	}, +	{ +		.code		= KEY_UP, +		.gpio		= S3C2410_GPG(4), +		.active_low	= 1, +		.desc		= "Up button", +	}, +	{ +		.code		= KEY_DOWN, +		.gpio		= S3C2410_GPG(6), +		.active_low	= 1, +		.desc		= "Down button", +	}, +	{ +		.code		= KEY_ENTER, +		.gpio		= S3C2410_GPG(9), +		.active_low	= 1, +		.desc		= "Ok button" +	}, +}; + +static struct gpio_keys_platform_data rx1950_gpio_keys_data = { +	.buttons = rx1950_gpio_keys_table, +	.nbuttons = ARRAY_SIZE(rx1950_gpio_keys_table), +}; + +static struct platform_device rx1950_device_gpiokeys = { +	.name = "gpio-keys", +	.dev.platform_data = &rx1950_gpio_keys_data, +}; + +static struct uda1380_platform_data uda1380_info = { +	.gpio_power	= S3C2410_GPJ(0), +	.gpio_reset	= S3C2410_GPD(0), +	.dac_clk	= UDA1380_DAC_CLK_SYSCLK, +}; + +static struct i2c_board_info rx1950_i2c_devices[] = { +	{ +		I2C_BOARD_INFO("uda1380", 0x1a), +		.platform_data = &uda1380_info, +	}, +}; + +static struct platform_device *rx1950_devices[] __initdata = { +	&s3c2410_device_dclk, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_usbgadget, +	&s3c_device_rtc, +	&s3c_device_nand, +	&s3c_device_sdi, +	&s3c_device_adc, +	&s3c_device_ts, +	&samsung_device_pwm, +	&rx1950_backlight, +	&rx1950_device_gpiokeys, +	&power_supply, +	&rx1950_battery, +	&rx1950_leds, +}; + +static void __init rx1950_map_io(void) +{ +	s3c24xx_init_io(rx1950_iodesc, ARRAY_SIZE(rx1950_iodesc)); +	s3c24xx_init_uarts(rx1950_uartcfgs, ARRAY_SIZE(rx1950_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); + +	/* setup PM */ + +#ifdef CONFIG_PM_H1940 +	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 8); +#endif + +	s3c_pm_init(); +} + +static void __init rx1950_init_time(void) +{ +	s3c2442_init_clocks(16934000); +	samsung_timer_init(); +} + +static void __init rx1950_init_machine(void) +{ +	int i; + +	s3c24xx_fb_set_platdata(&rx1950_lcd_cfg); +	s3c24xx_udc_set_platdata(&rx1950_udc_cfg); +	s3c24xx_ts_set_platdata(&rx1950_ts_cfg); +	s3c24xx_mci_set_platdata(&rx1950_mmc_cfg); +	s3c_i2c0_set_platdata(NULL); +	s3c_nand_set_platdata(&rx1950_nand_info); + +	/* Turn off suspend on both USB ports, and switch the +	 * selectable USB port to USB device mode. */ +	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +						S3C2410_MISCCR_USBSUSPND0 | +						S3C2410_MISCCR_USBSUSPND1, 0x0); + +	/* mmc power is disabled by default */ +	WARN_ON(gpio_request(S3C2410_GPJ(1), "MMC power")); +	gpio_direction_output(S3C2410_GPJ(1), 0); + +	for (i = 0; i < 8; i++) +		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power")); + +	for (i = 10; i < 16; i++) +		WARN_ON(gpio_request(S3C2410_GPC(i), "LCD power")); + +	for (i = 2; i < 8; i++) +		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power")); + +	for (i = 11; i < 16; i++) +		WARN_ON(gpio_request(S3C2410_GPD(i), "LCD power")); + +	WARN_ON(gpio_request(S3C2410_GPB(1), "LCD power")); + +	WARN_ON(gpio_request(S3C2410_GPA(3), "Red blink")); +	WARN_ON(gpio_request(S3C2410_GPA(4), "Green blink")); +	WARN_ON(gpio_request(S3C2410_GPJ(6), "LED blink")); +	gpio_direction_output(S3C2410_GPA(3), 0); +	gpio_direction_output(S3C2410_GPA(4), 0); +	gpio_direction_output(S3C2410_GPJ(6), 0); + +	platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices)); + +	i2c_register_board_info(0, rx1950_i2c_devices, +		ARRAY_SIZE(rx1950_i2c_devices)); +} + +/* H1940 and RX3715 need to reserve this for suspend */ +static void __init rx1950_reserve(void) +{ +	memblock_reserve(0x30003000, 0x1000); +	memblock_reserve(0x30081000, 0x1000); +} + +MACHINE_START(RX1950, "HP iPAQ RX1950") +    /* Maintainers: Vasily Khoruzhick */ +	.atag_offset = 0x100, +	.map_io = rx1950_map_io, +	.reserve	= rx1950_reserve, +	.init_irq	= s3c2442_init_irq, +	.init_machine = rx1950_init_machine, +	.init_time	= rx1950_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c new file mode 100644 index 00000000000..6e749ec3a2e --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -0,0 +1,219 @@ +/* linux/arch/arm/mach-s3c2440/mach-rx3715.c + * + * Copyright (c) 2003-2004 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://www.handhelds.org/projects/rx3715.html + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/memblock.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/console.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/serial.h> +#include <linux/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> + +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/fb.h> +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/gpio-samsung.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/pm.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "h1940.h" + +static struct map_desc rx3715_iodesc[] __initdata = { +	/* dump ISA space somewhere unused */ + +	{ +		.virtual	= (u32)S3C24XX_VA_ISA_WORD, +		.pfn		= __phys_to_pfn(S3C2410_CS3), +		.length		= SZ_1M, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE, +		.pfn		= __phys_to_pfn(S3C2410_CS3), +		.length		= SZ_1M, +		.type		= MT_DEVICE, +	}, +}; + +static struct s3c2410_uartcfg rx3715_uartcfgs[] = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +		.clk_sel	= S3C2410_UCON_CLKSEL3, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x00, +		.clk_sel	= S3C2410_UCON_CLKSEL3, +	}, +	/* IR port */ +	[2] = { +		.hwport	     = 2, +		.uart_flags  = UPF_CONS_FLOW, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x43, +		.ufcon	     = 0x51, +		.clk_sel	= S3C2410_UCON_CLKSEL3, +	} +}; + +/* framebuffer lcd controller information */ + +static struct s3c2410fb_display rx3715_lcdcfg __initdata = { +	.lcdcon5 =	S3C2410_LCDCON5_INVVLINE | +			S3C2410_LCDCON5_FRM565 | +			S3C2410_LCDCON5_HWSWP, + +	.type		= S3C2410_LCDCON1_TFT, +	.width		= 240, +	.height		= 320, + +	.pixclock	= 260000, +	.xres		= 240, +	.yres		= 320, +	.bpp		= 16, +	.left_margin	= 36, +	.right_margin	= 36, +	.hsync_len	= 8, +	.upper_margin	= 6, +	.lower_margin	= 7, +	.vsync_len	= 3, +}; + +static struct s3c2410fb_mach_info rx3715_fb_info __initdata = { + +	.displays =	&rx3715_lcdcfg, +	.num_displays =	1, +	.default_display = 0, + +	.lpcsel =	0xf82, + +	.gpccon =	0xaa955699, +	.gpccon_mask =	0xffc003cc, +	.gpcup =	0x0000ffff, +	.gpcup_mask =	0xffffffff, + +	.gpdcon =	0xaa95aaa1, +	.gpdcon_mask =	0xffc0fff0, +	.gpdup =	0x0000faff, +	.gpdup_mask =	0xffffffff, +}; + +static struct mtd_partition __initdata rx3715_nand_part[] = { +	[0] = { +		.name		= "Whole Flash", +		.offset		= 0, +		.size		= MTDPART_SIZ_FULL, +		.mask_flags	= MTD_WRITEABLE, +	} +}; + +static struct s3c2410_nand_set __initdata rx3715_nand_sets[] = { +	[0] = { +		.name		= "Internal", +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(rx3715_nand_part), +		.partitions	= rx3715_nand_part, +	}, +}; + +static struct s3c2410_platform_nand __initdata rx3715_nand_info = { +	.tacls		= 25, +	.twrph0		= 50, +	.twrph1		= 15, +	.nr_sets	= ARRAY_SIZE(rx3715_nand_sets), +	.sets		= rx3715_nand_sets, +}; + +static struct platform_device *rx3715_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_nand, +}; + +static void __init rx3715_map_io(void) +{ +	s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); +	s3c24xx_init_uarts(rx3715_uartcfgs, ARRAY_SIZE(rx3715_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init rx3715_init_time(void) +{ +	s3c2440_init_clocks(16934000); +	samsung_timer_init(); +} + +/* H1940 and RX3715 need to reserve this for suspend */ +static void __init rx3715_reserve(void) +{ +	memblock_reserve(0x30003000, 0x1000); +	memblock_reserve(0x30081000, 0x1000); +} + +static void __init rx3715_init_machine(void) +{ +#ifdef CONFIG_PM_H1940 +	memcpy(phys_to_virt(H1940_SUSPEND_RESUMEAT), h1940_pm_return, 1024); +#endif +	s3c_pm_init(); + +	s3c_nand_set_platdata(&rx3715_nand_info); +	s3c24xx_fb_set_platdata(&rx3715_fb_info); +	platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices)); +} + +MACHINE_START(RX3715, "IPAQ-RX3715") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, +	.map_io		= rx3715_map_io, +	.reserve	= rx3715_reserve, +	.init_irq	= s3c2440_init_irq, +	.init_machine	= rx3715_init_machine, +	.init_time	= rx3715_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c b/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c new file mode 100644 index 00000000000..e4dcb9aa2ca --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-s3c2416-dt.c @@ -0,0 +1,55 @@ +/* + * Samsung's S3C2416 flattened device tree enabled machine + * + * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de> + * + * based on mach-exynos/mach-exynos4-dt.c + * + * Copyright (c) 2010-2011 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * Copyright (c) 2010-2011 Linaro Ltd. + *		www.linaro.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/clocksource.h> +#include <linux/irqchip.h> +#include <linux/of_platform.h> +#include <linux/serial_s3c.h> + +#include <asm/mach/arch.h> +#include <mach/map.h> + +#include <plat/cpu.h> +#include <plat/pm.h> + +#include "common.h" + +static void __init s3c2416_dt_map_io(void) +{ +	s3c24xx_init_io(NULL, 0); +} + +static void __init s3c2416_dt_machine_init(void) +{ +	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); +	s3c_pm_init(); +} + +static char const *s3c2416_dt_compat[] __initdata = { +	"samsung,s3c2416", +	"samsung,s3c2450", +	NULL +}; + +DT_MACHINE_START(S3C2416_DT, "Samsung S3C2416 (Flattened Device Tree)") +	/* Maintainer: Heiko Stuebner <heiko@sntech.de> */ +	.dt_compat	= s3c2416_dt_compat, +	.map_io		= s3c2416_dt_map_io, +	.init_irq	= irqchip_init, +	.init_machine	= s3c2416_dt_machine_init, +	.restart	= s3c2416_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2410.c b/arch/arm/mach-s3c24xx/mach-smdk2410.c new file mode 100644 index 00000000000..419fadd6e44 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-smdk2410.c @@ -0,0 +1,128 @@ +/* linux/arch/arm/mach-s3c2410/mach-smdk2410.c + * + * linux/arch/arm/mach-s3c2410/mach-smdk2410.c + * + * Copyright (C) 2004 by FS Forth-Systeme GmbH + * All rights reserved. + * + * @Author: Jonas Dietsche + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * @History: + * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by + * Ben Dooks <ben@simtec.co.uk> + * + ***********************************************************************/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/i2c-s3c2410.h> + +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "common-smdk.h" + +static struct map_desc smdk2410_iodesc[] __initdata = { +  /* nothing here yet */ +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg smdk2410_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +static struct platform_device *smdk2410_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +}; + +static void __init smdk2410_map_io(void) +{ +	s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); +	s3c24xx_init_uarts(smdk2410_uartcfgs, ARRAY_SIZE(smdk2410_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init smdk2410_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init smdk2410_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices)); +	smdk_machine_init(); +} + +MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch +				    * to SMDK2410 */ +	/* Maintainer: Jonas Dietsche */ +	.atag_offset	= 0x100, +	.map_io		= smdk2410_map_io, +	.init_irq	= s3c2410_init_irq, +	.init_machine	= smdk2410_init, +	.init_time	= smdk2410_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c new file mode 100644 index 00000000000..fb3b80e4459 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-smdk2413.c @@ -0,0 +1,167 @@ +/* linux/arch/arm/mach-s3c2412/mach-smdk2413.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * Thanks to Dimity Andric (TomTom) and Steven Ryu (Samsung) for the + * loans of SMDK2413 to work with. + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/memblock.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/hardware/iomd.h> +#include <asm/setup.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +//#include <asm/debug-ll.h> +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> + +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <mach/gpio-samsung.h> +#include <mach/fb.h> + +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "common-smdk.h" + +static struct map_desc smdk2413_iodesc[] __initdata = { +}; + +static struct s3c2410_uartcfg smdk2413_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	/* IR port */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x43, +		.ufcon	     = 0x51, +	} +}; + + +static struct s3c2410_udc_mach_info smdk2413_udc_cfg __initdata = { +	.pullup_pin = S3C2410_GPF(2), +}; + + +static struct platform_device *smdk2413_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_usbgadget, +	&s3c2412_device_dma, +}; + +static void __init smdk2413_fixup(struct tag *tags, char **cmdline) +{ +	if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) { +		memblock_add(0x30000000, SZ_64M); +	} +} + +static void __init smdk2413_map_io(void) +{ +	s3c24xx_init_io(smdk2413_iodesc, ARRAY_SIZE(smdk2413_iodesc)); +	s3c24xx_init_uarts(smdk2413_uartcfgs, ARRAY_SIZE(smdk2413_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init smdk2413_init_time(void) +{ +	s3c2412_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init smdk2413_machine_init(void) +{	/* Turn off suspend on both USB ports, and switch the +	 * selectable USB port to USB device mode. */ + +	s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST | +			      S3C2410_MISCCR_USBSUSPND0 | +			      S3C2410_MISCCR_USBSUSPND1, 0x0); + + + 	s3c24xx_udc_set_platdata(&smdk2413_udc_cfg); +	s3c_i2c0_set_platdata(NULL); + +	platform_add_devices(smdk2413_devices, ARRAY_SIZE(smdk2413_devices)); +	smdk_machine_init(); +} + +MACHINE_START(S3C2413, "S3C2413") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, + +	.fixup		= smdk2413_fixup, +	.init_irq	= s3c2412_init_irq, +	.map_io		= smdk2413_map_io, +	.init_machine	= smdk2413_machine_init, +	.init_time	= samsung_timer_init, +	.restart	= s3c2412_restart, +MACHINE_END + +MACHINE_START(SMDK2412, "SMDK2412") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, + +	.fixup		= smdk2413_fixup, +	.init_irq	= s3c2412_init_irq, +	.map_io		= smdk2413_map_io, +	.init_machine	= smdk2413_machine_init, +	.init_time	= samsung_timer_init, +	.restart	= s3c2412_restart, +MACHINE_END + +MACHINE_START(SMDK2413, "SMDK2413") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, + +	.fixup		= smdk2413_fixup, +	.init_irq	= s3c2412_init_irq, +	.map_io		= smdk2413_map_io, +	.init_machine	= smdk2413_machine_init, +	.init_time	= smdk2413_init_time, +	.restart	= s3c2412_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c new file mode 100644 index 00000000000..fa6f30d2360 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c @@ -0,0 +1,267 @@ +/* linux/arch/arm/mach-s3c2416/mach-hanlin_v3c.c + * + * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>, + *	as part of OpenInkpot project + * Copyright (c) 2009 Promwad Innovation Company + *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/mtd/partitions.h> +#include <linux/gpio.h> +#include <linux/fb.h> +#include <linux/delay.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <video/samsung_fimd.h> +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> +#include <mach/regs-s3c2443-clock.h> +#include <mach/gpio-samsung.h> + +#include <linux/platform_data/leds-s3c24xx.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <plat/gpio-cfg.h> +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <plat/sdhci.h> +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/s3c-hsudc.h> +#include <plat/samsung-time.h> + +#include <plat/fb.h> + +#include "common.h" +#include "common-smdk.h" + +static struct map_desc smdk2416_iodesc[] __initdata = { +	/* ISA IO Space map (memory space selected by A24) */ + +	{ +		.virtual	= (u32)S3C24XX_VA_ISA_WORD, +		.pfn		= __phys_to_pfn(S3C2410_CS2), +		.length		= 0x10000, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_WORD + 0x10000, +		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)), +		.length		= SZ_4M, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE, +		.pfn		= __phys_to_pfn(S3C2410_CS2), +		.length		= 0x10000, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE + 0x10000, +		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)), +		.length		= SZ_4M, +		.type		= MT_DEVICE, +	} +}; + +#define UCON (S3C2410_UCON_DEFAULT	| \ +		S3C2440_UCON_PCLK	| \ +		S3C2443_UCON_RXERR_IRQEN) + +#define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE) + +#define UFCON (S3C2410_UFCON_RXTRIG8	| \ +		S3C2410_UFCON_FIFOMODE	| \ +		S3C2440_UFCON_TXTRIG16) + +static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	/* IR port */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON | 0x50, +		.ufcon	     = UFCON, +	}, +	[3] = { +		.hwport	     = 3, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +static void smdk2416_hsudc_gpio_init(void) +{ +	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_UP); +	s3c_gpio_setpull(S3C2410_GPF(2), S3C_GPIO_PULL_NONE); +	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(1)); +	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 0); +} + +static void smdk2416_hsudc_gpio_uninit(void) +{ +	s3c2410_modify_misccr(S3C2416_MISCCR_SEL_SUSPND, 1); +	s3c_gpio_setpull(S3C2410_GPH(14), S3C_GPIO_PULL_NONE); +	s3c_gpio_cfgpin(S3C2410_GPH(14), S3C_GPIO_SFN(0)); +} + +static struct s3c24xx_hsudc_platdata smdk2416_hsudc_platdata = { +	.epnum = 9, +	.gpio_init = smdk2416_hsudc_gpio_init, +	.gpio_uninit = smdk2416_hsudc_gpio_uninit, +}; + +static struct s3c_fb_pd_win smdk2416_fb_win[] = { +	[0] = { +		.default_bpp	= 16, +		.max_bpp	= 32, +		.xres           = 800, +		.yres           = 480, +	}, +}; + +static struct fb_videomode smdk2416_lcd_timing = { +	.pixclock	= 41094, +	.left_margin	= 8, +	.right_margin	= 13, +	.upper_margin	= 7, +	.lower_margin	= 5, +	.hsync_len	= 3, +	.vsync_len	= 1, +	.xres           = 800, +	.yres           = 480, +}; + +static void s3c2416_fb_gpio_setup_24bpp(void) +{ +	unsigned int gpio; + +	for (gpio = S3C2410_GPC(1); gpio <= S3C2410_GPC(4); gpio++) { +		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); +		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); +	} + +	for (gpio = S3C2410_GPC(8); gpio <= S3C2410_GPC(15); gpio++) { +		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); +		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); +	} + +	for (gpio = S3C2410_GPD(0); gpio <= S3C2410_GPD(15); gpio++) { +		s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); +		s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); +	} +} + +static struct s3c_fb_platdata smdk2416_fb_platdata = { +	.win[0]		= &smdk2416_fb_win[0], +	.vtiming	= &smdk2416_lcd_timing, +	.setup_gpio	= s3c2416_fb_gpio_setup_24bpp, +	.vidcon0	= VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, +	.vidcon1	= VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, +}; + +static struct s3c_sdhci_platdata smdk2416_hsmmc0_pdata __initdata = { +	.max_width		= 4, +	.cd_type		= S3C_SDHCI_CD_GPIO, +	.ext_cd_gpio		= S3C2410_GPF(1), +	.ext_cd_gpio_invert	= 1, +}; + +static struct s3c_sdhci_platdata smdk2416_hsmmc1_pdata __initdata = { +	.max_width		= 4, +	.cd_type		= S3C_SDHCI_CD_NONE, +}; + +static struct platform_device *smdk2416_devices[] __initdata = { +	&s3c_device_fb, +	&s3c_device_wdt, +	&s3c_device_ohci, +	&s3c_device_i2c0, +	&s3c_device_hsmmc0, +	&s3c_device_hsmmc1, +	&s3c_device_usb_hsudc, +	&s3c2443_device_dma, +}; + +static void __init smdk2416_init_time(void) +{ +	s3c2416_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init smdk2416_map_io(void) +{ +	s3c24xx_init_io(smdk2416_iodesc, ARRAY_SIZE(smdk2416_iodesc)); +	s3c24xx_init_uarts(smdk2416_uartcfgs, ARRAY_SIZE(smdk2416_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init smdk2416_machine_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	s3c_fb_set_platdata(&smdk2416_fb_platdata); + +	s3c_sdhci0_set_platdata(&smdk2416_hsmmc0_pdata); +	s3c_sdhci1_set_platdata(&smdk2416_hsmmc1_pdata); + +	s3c24xx_hsudc_set_platdata(&smdk2416_hsudc_platdata); + +	gpio_request(S3C2410_GPB(4), "USBHost Power"); +	gpio_direction_output(S3C2410_GPB(4), 1); + +	gpio_request(S3C2410_GPB(3), "Display Power"); +	gpio_direction_output(S3C2410_GPB(3), 1); + +	gpio_request(S3C2410_GPB(1), "Display Reset"); +	gpio_direction_output(S3C2410_GPB(1), 1); + +	platform_add_devices(smdk2416_devices, ARRAY_SIZE(smdk2416_devices)); +	smdk_machine_init(); +} + +MACHINE_START(SMDK2416, "SMDK2416") +	/* Maintainer: Yauhen Kharuzhy <jekhor@gmail.com> */ +	.atag_offset	= 0x100, + +	.init_irq	= s3c2416_init_irq, +	.map_io		= smdk2416_map_io, +	.init_machine	= smdk2416_machine_init, +	.init_time	= smdk2416_init_time, +	.restart	= s3c2416_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2440.c b/arch/arm/mach-s3c24xx/mach-smdk2440.c new file mode 100644 index 00000000000..5fb89c0ae17 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-smdk2440.c @@ -0,0 +1,189 @@ +/* linux/arch/arm/mach-s3c2440/mach-smdk2440.c + * + * Copyright (c) 2004-2005 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://www.fluff.org/ben/smdk2440/ + * + * Thanks to Dimity Andric and TomTom for the loan of an SMDK2440. + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> + +#include <mach/fb.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "common-smdk.h" + +static struct map_desc smdk2440_iodesc[] __initdata = { +	/* ISA IO Space map (memory space selected by A24) */ + +	{ +		.virtual	= (u32)S3C24XX_VA_ISA_WORD, +		.pfn		= __phys_to_pfn(S3C2410_CS2), +		.length		= 0x10000, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_WORD + 0x10000, +		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)), +		.length		= SZ_4M, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE, +		.pfn		= __phys_to_pfn(S3C2410_CS2), +		.length		= 0x10000, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE + 0x10000, +		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)), +		.length		= SZ_4M, +		.type		= MT_DEVICE, +	} +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg smdk2440_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	/* IR port */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x43, +		.ufcon	     = 0x51, +	} +}; + +/* LCD driver info */ + +static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = { + +	.lcdcon5	= S3C2410_LCDCON5_FRM565 | +			  S3C2410_LCDCON5_INVVLINE | +			  S3C2410_LCDCON5_INVVFRAME | +			  S3C2410_LCDCON5_PWREN | +			  S3C2410_LCDCON5_HWSWP, + +	.type		= S3C2410_LCDCON1_TFT, + +	.width		= 240, +	.height		= 320, + +	.pixclock	= 166667, /* HCLK 60 MHz, divisor 10 */ +	.xres		= 240, +	.yres		= 320, +	.bpp		= 16, +	.left_margin	= 20, +	.right_margin	= 8, +	.hsync_len	= 4, +	.upper_margin	= 8, +	.lower_margin	= 7, +	.vsync_len	= 4, +}; + +static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = { +	.displays	= &smdk2440_lcd_cfg, +	.num_displays	= 1, +	.default_display = 0, + +#if 0 +	/* currently setup by downloader */ +	.gpccon		= 0xaa940659, +	.gpccon_mask	= 0xffffffff, +	.gpcup		= 0x0000ffff, +	.gpcup_mask	= 0xffffffff, +	.gpdcon		= 0xaa84aaa0, +	.gpdcon_mask	= 0xffffffff, +	.gpdup		= 0x0000faff, +	.gpdup_mask	= 0xffffffff, +#endif + +	.lpcsel		= ((0xCE6) & ~7) | 1<<4, +}; + +static struct platform_device *smdk2440_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +}; + +static void __init smdk2440_map_io(void) +{ +	s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); +	s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init smdk2440_init_time(void) +{ +	s3c2440_init_clocks(16934400); +	samsung_timer_init(); +} + +static void __init smdk2440_machine_init(void) +{ +	s3c24xx_fb_set_platdata(&smdk2440_fb_info); +	s3c_i2c0_set_platdata(NULL); + +	platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); +	smdk_machine_init(); +} + +MACHINE_START(S3C2440, "SMDK2440") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, + +	.init_irq	= s3c2440_init_irq, +	.map_io		= smdk2440_map_io, +	.init_machine	= smdk2440_machine_init, +	.init_time	= smdk2440_init_time, +	.restart	= s3c244x_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-smdk2443.c b/arch/arm/mach-s3c24xx/mach-smdk2443.c new file mode 100644 index 00000000000..ef5d5ea3318 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-smdk2443.c @@ -0,0 +1,155 @@ +/* linux/arch/arm/mach-s3c2443/mach-smdk2443.c + * + * Copyright (c) 2007 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://www.fluff.org/ben/smdk2443/ + * + * Thanks to Samsung for the loan of an SMDK2443 + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> + +#include <mach/fb.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include "common.h" +#include "common-smdk.h" + +static struct map_desc smdk2443_iodesc[] __initdata = { +	/* ISA IO Space map (memory space selected by A24) */ + +	{ +		.virtual	= (u32)S3C24XX_VA_ISA_WORD, +		.pfn		= __phys_to_pfn(S3C2410_CS2), +		.length		= 0x10000, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_WORD + 0x10000, +		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)), +		.length		= SZ_4M, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE, +		.pfn		= __phys_to_pfn(S3C2410_CS2), +		.length		= 0x10000, +		.type		= MT_DEVICE, +	}, { +		.virtual	= (u32)S3C24XX_VA_ISA_BYTE + 0x10000, +		.pfn		= __phys_to_pfn(S3C2410_CS2 + (1<<24)), +		.length		= SZ_4M, +		.type		= MT_DEVICE, +	} +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg smdk2443_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	/* IR port */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x43, +		.ufcon	     = 0x51, +	}, +	[3] = { +		.hwport	     = 3, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	} +}; + +static struct platform_device *smdk2443_devices[] __initdata = { +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_hsmmc1, +#ifdef CONFIG_SND_SOC_SMDK2443_WM9710 +	&s3c_device_ac97, +#endif +	&s3c2443_device_dma, +}; + +static void __init smdk2443_map_io(void) +{ +	s3c24xx_init_io(smdk2443_iodesc, ARRAY_SIZE(smdk2443_iodesc)); +	s3c24xx_init_uarts(smdk2443_uartcfgs, ARRAY_SIZE(smdk2443_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init smdk2443_init_time(void) +{ +	s3c2443_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init smdk2443_machine_init(void) +{ +	s3c_i2c0_set_platdata(NULL); + +#ifdef CONFIG_SND_SOC_SMDK2443_WM9710 +	s3c24xx_ac97_setup_gpio(S3C24XX_AC97_GPE0); +#endif + +	platform_add_devices(smdk2443_devices, ARRAY_SIZE(smdk2443_devices)); +	smdk_machine_init(); +} + +MACHINE_START(SMDK2443, "SMDK2443") +	/* Maintainer: Ben Dooks <ben-linux@fluff.org> */ +	.atag_offset	= 0x100, + +	.init_irq	= s3c2443_init_irq, +	.map_io		= smdk2443_map_io, +	.init_machine	= smdk2443_machine_init, +	.init_time	= smdk2443_init_time, +	.restart	= s3c2443_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-tct_hammer.c b/arch/arm/mach-s3c24xx/mach-tct_hammer.c new file mode 100644 index 00000000000..c616ca2d409 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-tct_hammer.c @@ -0,0 +1,161 @@ +/* linux/arch/arm/mach-s3c2410/mach-tct_hammer.c + * + * Copyright (c) 2007 TinCanTools + *	David Anders <danders@amltd.com> + + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * @History: + * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by + * Ben Dooks <ben@simtec.co.uk> + * + ***********************************************************************/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> +#include <asm/mach/flash.h> + +#include <mach/hardware.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <plat/devs.h> +#include <plat/cpu.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> +#include <plat/samsung-time.h> + +#include "common.h" + +static struct resource tct_hammer_nor_resource = +			DEFINE_RES_MEM(0x00000000, SZ_16M); + +static struct mtd_partition tct_hammer_mtd_partitions[] = { +	{ +		.name		= "System", +		.size		= 0x240000, +		.offset		= 0, +		.mask_flags 	= MTD_WRITEABLE,  /* force read-only */ +	}, { +		.name		= "JFFS2", +		.size		= MTDPART_SIZ_FULL, +		.offset		= MTDPART_OFS_APPEND, +	} +}; + +static struct physmap_flash_data tct_hammer_flash_data = { +	.width		= 2, +	.parts		= tct_hammer_mtd_partitions, +	.nr_parts	= ARRAY_SIZE(tct_hammer_mtd_partitions), +}; + +static struct platform_device tct_hammer_device_nor = { +	.name		= "physmap-flash", +	.id		= 0, +	.dev = { +			.platform_data = &tct_hammer_flash_data, +		}, +	.num_resources	= 1, +	.resource	= &tct_hammer_nor_resource, +}; + +static struct map_desc tct_hammer_iodesc[] __initdata = { +}; + +#define UCON S3C2410_UCON_DEFAULT +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg tct_hammer_uartcfgs[] = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + + +static struct platform_device *tct_hammer_devices[] __initdata = { +	&s3c_device_adc, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_ohci, +	&s3c_device_rtc, +	&s3c_device_usbgadget, +	&s3c_device_sdi, +	&tct_hammer_device_nor, +}; + +static void __init tct_hammer_map_io(void) +{ +	s3c24xx_init_io(tct_hammer_iodesc, ARRAY_SIZE(tct_hammer_iodesc)); +	s3c24xx_init_uarts(tct_hammer_uartcfgs, ARRAY_SIZE(tct_hammer_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init tct_hammer_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init tct_hammer_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	platform_add_devices(tct_hammer_devices, ARRAY_SIZE(tct_hammer_devices)); +} + +MACHINE_START(TCT_HAMMER, "TCT_HAMMER") +	.atag_offset	= 0x100, +	.map_io		= tct_hammer_map_io, +	.init_irq	= s3c2410_init_irq, +	.init_machine	= tct_hammer_init, +	.init_time	= tct_hammer_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c new file mode 100644 index 00000000000..f88c584c300 --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-vr1000.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2003-2008 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * Machine support for Thorcom VR1000 board. Designed for Thorcom by + * Simtec Electronics, http://www.simtec.co.uk/ + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/dm9000.h> +#include <linux/i2c.h> + +#include <linux/serial.h> +#include <linux/tty.h> +#include <linux/serial_8250.h> +#include <linux/serial_reg.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/leds-s3c24xx.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/asoc-s3c24xx_simtec.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/samsung-time.h> + +#include "bast.h" +#include "common.h" +#include "simtec.h" +#include "vr1000.h" + +/* macros for virtual address mods for the io space entries */ +#define VA_C5(item) ((unsigned long)(item) + BAST_VAM_CS5) +#define VA_C4(item) ((unsigned long)(item) + BAST_VAM_CS4) +#define VA_C3(item) ((unsigned long)(item) + BAST_VAM_CS3) +#define VA_C2(item) ((unsigned long)(item) + BAST_VAM_CS2) + +/* macros to modify the physical addresses for io space */ + +#define PA_CS2(item) (__phys_to_pfn((item) + S3C2410_CS2)) +#define PA_CS3(item) (__phys_to_pfn((item) + S3C2410_CS3)) +#define PA_CS4(item) (__phys_to_pfn((item) + S3C2410_CS4)) +#define PA_CS5(item) (__phys_to_pfn((item) + S3C2410_CS5)) + +static struct map_desc vr1000_iodesc[] __initdata = { +  /* ISA IO areas */ +  { +	  .virtual	= (u32)S3C24XX_VA_ISA_BYTE, +	  .pfn		= PA_CS2(BAST_PA_ISAIO), +	  .length	= SZ_16M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)S3C24XX_VA_ISA_WORD, +	  .pfn		= PA_CS3(BAST_PA_ISAIO), +	  .length	= SZ_16M, +	  .type		= MT_DEVICE, +  }, + +  /*  CPLD control registers, and external interrupt controls */ +  { +	  .virtual	= (u32)VR1000_VA_CTRL1, +	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL1), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)VR1000_VA_CTRL2, +	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL2), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)VR1000_VA_CTRL3, +	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL3), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, { +	  .virtual	= (u32)VR1000_VA_CTRL4, +	  .pfn		= __phys_to_pfn(VR1000_PA_CTRL4), +	  .length	= SZ_1M, +	  .type		= MT_DEVICE, +  }, +}; + +#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK +#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB +#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE + +static struct s3c2410_uartcfg vr1000_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	}, +	/* port 2 is not actually used */ +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = UCON, +		.ulcon	     = ULCON, +		.ufcon	     = UFCON, +	} +}; + +/* definitions for the vr1000 extra 16550 serial ports */ + +#define VR1000_BAUDBASE (3692307) + +#define VR1000_SERIAL_MAPBASE(x) (VR1000_PA_SERIAL + 0x80 + ((x) << 5)) + +static struct plat_serial8250_port serial_platform_data[] = { +	[0] = { +		.mapbase	= VR1000_SERIAL_MAPBASE(0), +		.irq		= VR1000_IRQ_SERIAL + 0, +		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP, +		.iotype		= UPIO_MEM, +		.regshift	= 0, +		.uartclk	= VR1000_BAUDBASE, +	}, +	[1] = { +		.mapbase	= VR1000_SERIAL_MAPBASE(1), +		.irq		= VR1000_IRQ_SERIAL + 1, +		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP, +		.iotype		= UPIO_MEM, +		.regshift	= 0, +		.uartclk	= VR1000_BAUDBASE, +	}, +	[2] = { +		.mapbase	= VR1000_SERIAL_MAPBASE(2), +		.irq		= VR1000_IRQ_SERIAL + 2, +		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP, +		.iotype		= UPIO_MEM, +		.regshift	= 0, +		.uartclk	= VR1000_BAUDBASE, +	}, +	[3] = { +		.mapbase	= VR1000_SERIAL_MAPBASE(3), +		.irq		= VR1000_IRQ_SERIAL + 3, +		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP, +		.iotype		= UPIO_MEM, +		.regshift	= 0, +		.uartclk	= VR1000_BAUDBASE, +	}, +	{ }, +}; + +static struct platform_device serial_device = { +	.name			= "serial8250", +	.id			= PLAT8250_DEV_PLATFORM, +	.dev			= { +		.platform_data	= serial_platform_data, +	}, +}; + +/* DM9000 ethernet devices */ + +static struct resource vr1000_dm9k0_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000, 4), +	[1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x40, 0x40), +	[2] = DEFINE_RES_NAMED(VR1000_IRQ_DM9000A, 1, NULL, IORESOURCE_IRQ \ +						| IORESOURCE_IRQ_HIGHLEVEL), +}; + +static struct resource vr1000_dm9k1_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0x80, 4), +	[1] = DEFINE_RES_MEM(S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0, 0x40), +	[2] = DEFINE_RES_NAMED(VR1000_IRQ_DM9000N, 1, NULL, IORESOURCE_IRQ \ +						| IORESOURCE_IRQ_HIGHLEVEL), +}; + +/* for the moment we limit ourselves to 16bit IO until some + * better IO routines can be written and tested +*/ + +static struct dm9000_plat_data vr1000_dm9k_platdata = { +	.flags		= DM9000_PLATF_16BITONLY, +}; + +static struct platform_device vr1000_dm9k0 = { +	.name		= "dm9000", +	.id		= 0, +	.num_resources	= ARRAY_SIZE(vr1000_dm9k0_resource), +	.resource	= vr1000_dm9k0_resource, +	.dev		= { +		.platform_data = &vr1000_dm9k_platdata, +	} +}; + +static struct platform_device vr1000_dm9k1 = { +	.name		= "dm9000", +	.id		= 1, +	.num_resources	= ARRAY_SIZE(vr1000_dm9k1_resource), +	.resource	= vr1000_dm9k1_resource, +	.dev		= { +		.platform_data = &vr1000_dm9k_platdata, +	} +}; + +/* LEDS */ + +static struct s3c24xx_led_platdata vr1000_led1_pdata = { +	.name		= "led1", +	.gpio		= S3C2410_GPB(0), +	.def_trigger	= "", +}; + +static struct s3c24xx_led_platdata vr1000_led2_pdata = { +	.name		= "led2", +	.gpio		= S3C2410_GPB(1), +	.def_trigger	= "", +}; + +static struct s3c24xx_led_platdata vr1000_led3_pdata = { +	.name		= "led3", +	.gpio		= S3C2410_GPB(2), +	.def_trigger	= "", +}; + +static struct platform_device vr1000_led1 = { +	.name		= "s3c24xx_led", +	.id		= 1, +	.dev		= { +		.platform_data	= &vr1000_led1_pdata, +	}, +}; + +static struct platform_device vr1000_led2 = { +	.name		= "s3c24xx_led", +	.id		= 2, +	.dev		= { +		.platform_data	= &vr1000_led2_pdata, +	}, +}; + +static struct platform_device vr1000_led3 = { +	.name		= "s3c24xx_led", +	.id		= 3, +	.dev		= { +		.platform_data	= &vr1000_led3_pdata, +	}, +}; + +/* I2C devices. */ + +static struct i2c_board_info vr1000_i2c_devs[] __initdata = { +	{ +		I2C_BOARD_INFO("tlv320aic23", 0x1a), +	}, { +		I2C_BOARD_INFO("tmp101", 0x48), +	}, { +		I2C_BOARD_INFO("m41st87", 0x68), +	}, +}; + +/* devices for this board */ + +static struct platform_device *vr1000_devices[] __initdata = { +	&s3c2410_device_dclk, +	&s3c_device_ohci, +	&s3c_device_lcd, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_adc, +	&serial_device, +	&vr1000_dm9k0, +	&vr1000_dm9k1, +	&vr1000_led1, +	&vr1000_led2, +	&vr1000_led3, +}; + +static void vr1000_power_off(void) +{ +	gpio_direction_output(S3C2410_GPB(9), 1); +} + +static void __init vr1000_map_io(void) +{ +	pm_power_off = vr1000_power_off; + +	s3c24xx_init_io(vr1000_iodesc, ARRAY_SIZE(vr1000_iodesc)); +	s3c24xx_init_uarts(vr1000_uartcfgs, ARRAY_SIZE(vr1000_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init vr1000_init_time(void) +{ +	s3c2410_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init vr1000_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	platform_add_devices(vr1000_devices, ARRAY_SIZE(vr1000_devices)); + +	i2c_register_board_info(0, vr1000_i2c_devs, +				ARRAY_SIZE(vr1000_i2c_devs)); + +	nor_simtec_init(); +	simtec_audio_add(NULL, true, NULL); + +	WARN_ON(gpio_request(S3C2410_GPB(9), "power off")); +} + +MACHINE_START(VR1000, "Thorcom-VR1000") +	/* Maintainer: Ben Dooks <ben@simtec.co.uk> */ +	.atag_offset	= 0x100, +	.map_io		= vr1000_map_io, +	.init_machine	= vr1000_init, +	.init_irq	= s3c2410_init_irq, +	.init_time	= vr1000_init_time, +	.restart	= s3c2410_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c new file mode 100644 index 00000000000..9104c2be36c --- /dev/null +++ b/arch/arm/mach-s3c24xx/mach-vstms.c @@ -0,0 +1,170 @@ +/* linux/arch/arm/mach-s3c2412/mach-vstms.c + * + * (C) 2006 Thomas Gleixner <tglx@linutronix.de> + * + * Derived from mach-smdk2413.c - (C) 2006 Simtec Electronics + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/mtd/partitions.h> +#include <linux/memblock.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/setup.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-lcd.h> + +#include <mach/fb.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/samsung-time.h> + +#include "common.h" + +static struct map_desc vstms_iodesc[] __initdata = { +}; + +static struct s3c2410_uartcfg vstms_uartcfgs[] __initdata = { +	[0] = { +		.hwport	     = 0, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	[1] = { +		.hwport	     = 1, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	}, +	[2] = { +		.hwport	     = 2, +		.flags	     = 0, +		.ucon	     = 0x3c5, +		.ulcon	     = 0x03, +		.ufcon	     = 0x51, +	} +}; + +static struct mtd_partition __initdata vstms_nand_part[] = { +	[0] = { +		.name	= "Boot Agent", +		.size	= 0x7C000, +		.offset	= 0, +	}, +	[1] = { +		.name	= "UBoot Config", +		.offset = 0x7C000, +		.size	= 0x4000, +	}, +	[2] = { +		.name	= "Kernel", +		.offset = 0x80000, +		.size	= 0x200000, +	}, +	[3] = { +		.name	= "RFS", +		.offset	= 0x280000, +		.size	= 0x3d80000, +	}, +}; + +static struct s3c2410_nand_set __initdata vstms_nand_sets[] = { +	[0] = { +		.name		= "NAND", +		.nr_chips	= 1, +		.nr_partitions	= ARRAY_SIZE(vstms_nand_part), +		.partitions	= vstms_nand_part, +	}, +}; + +/* choose a set of timings which should suit most 512Mbit + * chips and beyond. +*/ + +static struct s3c2410_platform_nand __initdata vstms_nand_info = { +	.tacls		= 20, +	.twrph0		= 60, +	.twrph1		= 20, +	.nr_sets	= ARRAY_SIZE(vstms_nand_sets), +	.sets		= vstms_nand_sets, +}; + +static struct platform_device *vstms_devices[] __initdata = { +	&s3c_device_ohci, +	&s3c_device_wdt, +	&s3c_device_i2c0, +	&s3c_device_iis, +	&s3c_device_rtc, +	&s3c_device_nand, +	&s3c2412_device_dma, +}; + +static void __init vstms_fixup(struct tag *tags, char **cmdline) +{ +	if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) { +		memblock_add(0x30000000, SZ_64M); +	} +} + +static void __init vstms_map_io(void) +{ +	s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc)); +	s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs)); +	samsung_set_timer_source(SAMSUNG_PWM3, SAMSUNG_PWM4); +} + +static void __init vstms_init_time(void) +{ +	s3c2412_init_clocks(12000000); +	samsung_timer_init(); +} + +static void __init vstms_init(void) +{ +	s3c_i2c0_set_platdata(NULL); +	s3c_nand_set_platdata(&vstms_nand_info); + +	platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices)); +} + +MACHINE_START(VSTMS, "VSTMS") +	.atag_offset	= 0x100, + +	.fixup		= vstms_fixup, +	.init_irq	= s3c2412_init_irq, +	.init_machine	= vstms_init, +	.map_io		= vstms_map_io, +	.init_time	= vstms_init_time, +	.restart	= s3c2412_restart, +MACHINE_END diff --git a/arch/arm/mach-s3c24xx/osiris.h b/arch/arm/mach-s3c24xx/osiris.h new file mode 100644 index 00000000000..b8d56074aba --- /dev/null +++ b/arch/arm/mach-s3c24xx/osiris.h @@ -0,0 +1,53 @@ +/* + * Copyright 2005 Simtec Electronics + *	http://www.simtec.co.uk/products/ + *	Ben Dooks <ben@simtec.co.uk> + * + * OSIRIS - CPLD control constants + * OSIRIS - Memory map definitions + * + * 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 __MACH_S3C24XX_OSIRIS_H +#define __MACH_S3C24XX_OSIRIS_H __FILE__ + +/* CTRL0 - NAND WP control */ + +#define OSIRIS_CTRL0_NANDSEL		(0x3) +#define OSIRIS_CTRL0_BOOT_INT		(1<<3) +#define OSIRIS_CTRL0_PCMCIA		(1<<4) +#define OSIRIS_CTRL0_FIX8		(1<<5) +#define OSIRIS_CTRL0_PCMCIA_nWAIT	(1<<6) +#define OSIRIS_CTRL0_PCMCIA_nIOIS16	(1<<7) + +#define OSIRIS_CTRL1_FIX8		(1<<0) + +#define OSIRIS_ID_REVMASK		(0x7) + +/* start peripherals off after the S3C2410 */ + +#define OSIRIS_IOADDR(x)	(S3C2410_ADDR((x) + 0x04000000)) + +#define OSIRIS_PA_CPLD		(S3C2410_CS1 | (1<<26)) + +/* we put the CPLD registers next, to get them out of the way */ + +#define OSIRIS_VA_CTRL0		OSIRIS_IOADDR(0x00000000) +#define OSIRIS_PA_CTRL0		(OSIRIS_PA_CPLD) + +#define OSIRIS_VA_CTRL1		OSIRIS_IOADDR(0x00100000) +#define OSIRIS_PA_CTRL1		(OSIRIS_PA_CPLD + (1<<23)) + +#define OSIRIS_VA_CTRL2		OSIRIS_IOADDR(0x00200000) +#define OSIRIS_PA_CTRL2		(OSIRIS_PA_CPLD + (2<<23)) + +#define OSIRIS_VA_CTRL3		OSIRIS_IOADDR(0x00300000) +#define OSIRIS_PA_CTRL3		(OSIRIS_PA_CPLD + (2<<23)) + +#define OSIRIS_VA_IDREG		OSIRIS_IOADDR(0x00700000) +#define OSIRIS_PA_IDREG		(OSIRIS_PA_CPLD + (7<<23)) + +#endif /* __MACH_S3C24XX_OSIRIS_H */ diff --git a/arch/arm/mach-s3c24xx/otom.h b/arch/arm/mach-s3c24xx/otom.h new file mode 100644 index 00000000000..321b7be1c0f --- /dev/null +++ b/arch/arm/mach-s3c24xx/otom.h @@ -0,0 +1,28 @@ +/* + * (c) 2005 Guillaume GOURAT / NexVision + *          guillaume.gourat@nexvision.fr + * + * NexVision OTOM board memory map definitions + * + * 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. +*/ + +/* + * ok, we've used up to 0x01300000, now we need to find space for the + * peripherals that live in the nGCS[x] areas, which are quite numerous + * in their space. + */ + +#ifndef __MACH_S3C24XX_OTOM_H +#define __MACH_S3C24XX_OTOM_H __FILE__ + +#define OTOM_PA_CS8900A_BASE	(S3C2410_CS3 + 0x01000000)	/* nGCS3 +0x01000000 */ +#define OTOM_VA_CS8900A_BASE	S3C2410_ADDR(0x04000000)	/* 0xF4000000 */ + +/* physical offset addresses for the peripherals */ + +#define OTOM_PA_FLASH0_BASE	(S3C2410_CS0) + +#endif /* __MACH_S3C24XX_OTOM_H */ diff --git a/arch/arm/mach-s3c24xx/pll-s3c2410.c b/arch/arm/mach-s3c24xx/pll-s3c2410.c new file mode 100644 index 00000000000..5e37d368594 --- /dev/null +++ b/arch/arm/mach-s3c24xx/pll-s3c2410.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2006-2007 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + *	Vincent Sanders <vince@arm.linux.org.uk> + * + * S3C2410 CPU PLL tables + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <plat/cpu.h> +#include <plat/cpu-freq-core.h> + +static struct cpufreq_frequency_table pll_vals_12MHz[] = { +    { .frequency = 34000000,  .driver_data = PLLVAL(82, 2, 3),   }, +    { .frequency = 45000000,  .driver_data = PLLVAL(82, 1, 3),   }, +    { .frequency = 51000000,  .driver_data = PLLVAL(161, 3, 3),  }, +    { .frequency = 48000000,  .driver_data = PLLVAL(120, 2, 3),  }, +    { .frequency = 56000000,  .driver_data = PLLVAL(142, 2, 3),  }, +    { .frequency = 68000000,  .driver_data = PLLVAL(82, 2, 2),   }, +    { .frequency = 79000000,  .driver_data = PLLVAL(71, 1, 2),   }, +    { .frequency = 85000000,  .driver_data = PLLVAL(105, 2, 2),  }, +    { .frequency = 90000000,  .driver_data = PLLVAL(112, 2, 2),  }, +    { .frequency = 101000000, .driver_data = PLLVAL(127, 2, 2),  }, +    { .frequency = 113000000, .driver_data = PLLVAL(105, 1, 2),  }, +    { .frequency = 118000000, .driver_data = PLLVAL(150, 2, 2),  }, +    { .frequency = 124000000, .driver_data = PLLVAL(116, 1, 2),  }, +    { .frequency = 135000000, .driver_data = PLLVAL(82, 2, 1),   }, +    { .frequency = 147000000, .driver_data = PLLVAL(90, 2, 1),   }, +    { .frequency = 152000000, .driver_data = PLLVAL(68, 1, 1),   }, +    { .frequency = 158000000, .driver_data = PLLVAL(71, 1, 1),   }, +    { .frequency = 170000000, .driver_data = PLLVAL(77, 1, 1),   }, +    { .frequency = 180000000, .driver_data = PLLVAL(82, 1, 1),   }, +    { .frequency = 186000000, .driver_data = PLLVAL(85, 1, 1),   }, +    { .frequency = 192000000, .driver_data = PLLVAL(88, 1, 1),   }, +    { .frequency = 203000000, .driver_data = PLLVAL(161, 3, 1),  }, + +    /* 2410A extras */ + +    { .frequency = 210000000, .driver_data = PLLVAL(132, 2, 1),  }, +    { .frequency = 226000000, .driver_data = PLLVAL(105, 1, 1),  }, +    { .frequency = 266000000, .driver_data = PLLVAL(125, 1, 1),  }, +    { .frequency = 268000000, .driver_data = PLLVAL(126, 1, 1),  }, +    { .frequency = 270000000, .driver_data = PLLVAL(127, 1, 1),  }, +}; + +static int s3c2410_plls_add(struct device *dev, struct subsys_interface *sif) +{ +	return s3c_plltab_register(pll_vals_12MHz, ARRAY_SIZE(pll_vals_12MHz)); +} + +static struct subsys_interface s3c2410_plls_interface = { +	.name		= "s3c2410_plls", +	.subsys		= &s3c2410_subsys, +	.add_dev	= s3c2410_plls_add, +}; + +static int __init s3c2410_pll_init(void) +{ +	return subsys_interface_register(&s3c2410_plls_interface); + +} +arch_initcall(s3c2410_pll_init); + +static struct subsys_interface s3c2410a_plls_interface = { +	.name		= "s3c2410a_plls", +	.subsys		= &s3c2410a_subsys, +	.add_dev	= s3c2410_plls_add, +}; + +static int __init s3c2410a_pll_init(void) +{ +	return subsys_interface_register(&s3c2410a_plls_interface); +} +arch_initcall(s3c2410a_pll_init); diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c new file mode 100644 index 00000000000..a19460e6e7b --- /dev/null +++ b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2006-2007 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + *	Vincent Sanders <vince@arm.linux.org.uk> + * + * S3C2440/S3C2442 CPU PLL tables (12MHz Crystal) + * + * 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/types.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <plat/cpu.h> +#include <plat/cpu-freq-core.h> + +static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = { +	{ .frequency = 75000000,	.driver_data = PLLVAL(0x75, 3, 3),  }, 	/* FVco 600.000000 */ +	{ .frequency = 80000000,	.driver_data = PLLVAL(0x98, 4, 3),  }, 	/* FVco 640.000000 */ +	{ .frequency = 90000000,	.driver_data = PLLVAL(0x70, 2, 3),  }, 	/* FVco 720.000000 */ +	{ .frequency = 100000000,	.driver_data = PLLVAL(0x5c, 1, 3),  }, 	/* FVco 800.000000 */ +	{ .frequency = 110000000,	.driver_data = PLLVAL(0x66, 1, 3),  }, 	/* FVco 880.000000 */ +	{ .frequency = 120000000,	.driver_data = PLLVAL(0x70, 1, 3),  }, 	/* FVco 960.000000 */ +	{ .frequency = 150000000,	.driver_data = PLLVAL(0x75, 3, 2),  }, 	/* FVco 600.000000 */ +	{ .frequency = 160000000,	.driver_data = PLLVAL(0x98, 4, 2),  }, 	/* FVco 640.000000 */ +	{ .frequency = 170000000,	.driver_data = PLLVAL(0x4d, 1, 2),  }, 	/* FVco 680.000000 */ +	{ .frequency = 180000000,	.driver_data = PLLVAL(0x70, 2, 2),  }, 	/* FVco 720.000000 */ +	{ .frequency = 190000000,	.driver_data = PLLVAL(0x57, 1, 2),  }, 	/* FVco 760.000000 */ +	{ .frequency = 200000000,	.driver_data = PLLVAL(0x5c, 1, 2),  }, 	/* FVco 800.000000 */ +	{ .frequency = 210000000,	.driver_data = PLLVAL(0x84, 2, 2),  }, 	/* FVco 840.000000 */ +	{ .frequency = 220000000,	.driver_data = PLLVAL(0x66, 1, 2),  }, 	/* FVco 880.000000 */ +	{ .frequency = 230000000,	.driver_data = PLLVAL(0x6b, 1, 2),  }, 	/* FVco 920.000000 */ +	{ .frequency = 240000000,	.driver_data = PLLVAL(0x70, 1, 2),  }, 	/* FVco 960.000000 */ +	{ .frequency = 300000000,	.driver_data = PLLVAL(0x75, 3, 1),  }, 	/* FVco 600.000000 */ +	{ .frequency = 310000000,	.driver_data = PLLVAL(0x93, 4, 1),  }, 	/* FVco 620.000000 */ +	{ .frequency = 320000000,	.driver_data = PLLVAL(0x98, 4, 1),  }, 	/* FVco 640.000000 */ +	{ .frequency = 330000000,	.driver_data = PLLVAL(0x66, 2, 1),  }, 	/* FVco 660.000000 */ +	{ .frequency = 340000000,	.driver_data = PLLVAL(0x4d, 1, 1),  }, 	/* FVco 680.000000 */ +	{ .frequency = 350000000,	.driver_data = PLLVAL(0xa7, 4, 1),  }, 	/* FVco 700.000000 */ +	{ .frequency = 360000000,	.driver_data = PLLVAL(0x70, 2, 1),  }, 	/* FVco 720.000000 */ +	{ .frequency = 370000000,	.driver_data = PLLVAL(0xb1, 4, 1),  }, 	/* FVco 740.000000 */ +	{ .frequency = 380000000,	.driver_data = PLLVAL(0x57, 1, 1),  }, 	/* FVco 760.000000 */ +	{ .frequency = 390000000,	.driver_data = PLLVAL(0x7a, 2, 1),  }, 	/* FVco 780.000000 */ +	{ .frequency = 400000000,	.driver_data = PLLVAL(0x5c, 1, 1),  }, 	/* FVco 800.000000 */ +}; + +static int s3c2440_plls12_add(struct device *dev, struct subsys_interface *sif) +{ +	struct clk *xtal_clk; +	unsigned long xtal; + +	xtal_clk = clk_get(NULL, "xtal"); +	if (IS_ERR(xtal_clk)) +		return PTR_ERR(xtal_clk); + +	xtal = clk_get_rate(xtal_clk); +	clk_put(xtal_clk); + +	if (xtal == 12000000) { +		printk(KERN_INFO "Using PLL table for 12MHz crystal\n"); +		return s3c_plltab_register(s3c2440_plls_12, +					   ARRAY_SIZE(s3c2440_plls_12)); +	} + +	return 0; +} + +static struct subsys_interface s3c2440_plls12_interface = { +	.name		= "s3c2440_plls12", +	.subsys		= &s3c2440_subsys, +	.add_dev	= s3c2440_plls12_add, +}; + +static int __init s3c2440_pll_12mhz(void) +{ +	return subsys_interface_register(&s3c2440_plls12_interface); + +} +arch_initcall(s3c2440_pll_12mhz); + +static struct subsys_interface s3c2442_plls12_interface = { +	.name		= "s3c2442_plls12", +	.subsys		= &s3c2442_subsys, +	.add_dev	= s3c2440_plls12_add, +}; + +static int __init s3c2442_pll_12mhz(void) +{ +	return subsys_interface_register(&s3c2442_plls12_interface); + +} +arch_initcall(s3c2442_pll_12mhz); diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c new file mode 100644 index 00000000000..1191b290562 --- /dev/null +++ b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2006-2008 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + *	Vincent Sanders <vince@arm.linux.org.uk> + * + * S3C2440/S3C2442 CPU PLL tables (16.93444MHz Crystal) + * + * 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/types.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <plat/cpu.h> +#include <plat/cpu-freq-core.h> + +static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = { +	{ .frequency = 78019200,	.driver_data = PLLVAL(121, 5, 3), 	}, 	/* FVco 624.153600 */ +	{ .frequency = 84067200,	.driver_data = PLLVAL(131, 5, 3), 	}, 	/* FVco 672.537600 */ +	{ .frequency = 90115200,	.driver_data = PLLVAL(141, 5, 3), 	}, 	/* FVco 720.921600 */ +	{ .frequency = 96163200,	.driver_data = PLLVAL(151, 5, 3), 	}, 	/* FVco 769.305600 */ +	{ .frequency = 102135600,	.driver_data = PLLVAL(185, 6, 3), 	}, 	/* FVco 817.084800 */ +	{ .frequency = 108259200,	.driver_data = PLLVAL(171, 5, 3), 	}, 	/* FVco 866.073600 */ +	{ .frequency = 114307200,	.driver_data = PLLVAL(127, 3, 3), 	}, 	/* FVco 914.457600 */ +	{ .frequency = 120234240,	.driver_data = PLLVAL(134, 3, 3), 	}, 	/* FVco 961.873920 */ +	{ .frequency = 126161280,	.driver_data = PLLVAL(141, 3, 3), 	}, 	/* FVco 1009.290240 */ +	{ .frequency = 132088320,	.driver_data = PLLVAL(148, 3, 3), 	}, 	/* FVco 1056.706560 */ +	{ .frequency = 138015360,	.driver_data = PLLVAL(155, 3, 3), 	}, 	/* FVco 1104.122880 */ +	{ .frequency = 144789120,	.driver_data = PLLVAL(163, 3, 3), 	}, 	/* FVco 1158.312960 */ +	{ .frequency = 150100363,	.driver_data = PLLVAL(187, 9, 2), 	}, 	/* FVco 600.401454 */ +	{ .frequency = 156038400,	.driver_data = PLLVAL(121, 5, 2), 	}, 	/* FVco 624.153600 */ +	{ .frequency = 162086400,	.driver_data = PLLVAL(126, 5, 2), 	}, 	/* FVco 648.345600 */ +	{ .frequency = 168134400,	.driver_data = PLLVAL(131, 5, 2), 	}, 	/* FVco 672.537600 */ +	{ .frequency = 174048000,	.driver_data = PLLVAL(177, 7, 2), 	}, 	/* FVco 696.192000 */ +	{ .frequency = 180230400,	.driver_data = PLLVAL(141, 5, 2), 	}, 	/* FVco 720.921600 */ +	{ .frequency = 186278400,	.driver_data = PLLVAL(124, 4, 2), 	}, 	/* FVco 745.113600 */ +	{ .frequency = 192326400,	.driver_data = PLLVAL(151, 5, 2), 	}, 	/* FVco 769.305600 */ +	{ .frequency = 198132480,	.driver_data = PLLVAL(109, 3, 2), 	}, 	/* FVco 792.529920 */ +	{ .frequency = 204271200,	.driver_data = PLLVAL(185, 6, 2), 	}, 	/* FVco 817.084800 */ +	{ .frequency = 210268800,	.driver_data = PLLVAL(141, 4, 2), 	}, 	/* FVco 841.075200 */ +	{ .frequency = 216518400,	.driver_data = PLLVAL(171, 5, 2), 	}, 	/* FVco 866.073600 */ +	{ .frequency = 222264000,	.driver_data = PLLVAL(97, 2, 2), 	}, 	/* FVco 889.056000 */ +	{ .frequency = 228614400,	.driver_data = PLLVAL(127, 3, 2), 	}, 	/* FVco 914.457600 */ +	{ .frequency = 234259200,	.driver_data = PLLVAL(158, 4, 2), 	}, 	/* FVco 937.036800 */ +	{ .frequency = 240468480,	.driver_data = PLLVAL(134, 3, 2), 	}, 	/* FVco 961.873920 */ +	{ .frequency = 246960000,	.driver_data = PLLVAL(167, 4, 2), 	}, 	/* FVco 987.840000 */ +	{ .frequency = 252322560,	.driver_data = PLLVAL(141, 3, 2), 	}, 	/* FVco 1009.290240 */ +	{ .frequency = 258249600,	.driver_data = PLLVAL(114, 2, 2), 	}, 	/* FVco 1032.998400 */ +	{ .frequency = 264176640,	.driver_data = PLLVAL(148, 3, 2), 	}, 	/* FVco 1056.706560 */ +	{ .frequency = 270950400,	.driver_data = PLLVAL(120, 2, 2), 	}, 	/* FVco 1083.801600 */ +	{ .frequency = 276030720,	.driver_data = PLLVAL(155, 3, 2), 	}, 	/* FVco 1104.122880 */ +	{ .frequency = 282240000,	.driver_data = PLLVAL(92, 1, 2), 	}, 	/* FVco 1128.960000 */ +	{ .frequency = 289578240,	.driver_data = PLLVAL(163, 3, 2), 	}, 	/* FVco 1158.312960 */ +	{ .frequency = 294235200,	.driver_data = PLLVAL(131, 2, 2), 	}, 	/* FVco 1176.940800 */ +	{ .frequency = 300200727,	.driver_data = PLLVAL(187, 9, 1), 	}, 	/* FVco 600.401454 */ +	{ .frequency = 306358690,	.driver_data = PLLVAL(191, 9, 1), 	}, 	/* FVco 612.717380 */ +	{ .frequency = 312076800,	.driver_data = PLLVAL(121, 5, 1), 	}, 	/* FVco 624.153600 */ +	{ .frequency = 318366720,	.driver_data = PLLVAL(86, 3, 1), 	}, 	/* FVco 636.733440 */ +	{ .frequency = 324172800,	.driver_data = PLLVAL(126, 5, 1), 	}, 	/* FVco 648.345600 */ +	{ .frequency = 330220800,	.driver_data = PLLVAL(109, 4, 1), 	}, 	/* FVco 660.441600 */ +	{ .frequency = 336268800,	.driver_data = PLLVAL(131, 5, 1), 	}, 	/* FVco 672.537600 */ +	{ .frequency = 342074880,	.driver_data = PLLVAL(93, 3, 1), 	}, 	/* FVco 684.149760 */ +	{ .frequency = 348096000,	.driver_data = PLLVAL(177, 7, 1), 	}, 	/* FVco 696.192000 */ +	{ .frequency = 355622400,	.driver_data = PLLVAL(118, 4, 1), 	}, 	/* FVco 711.244800 */ +	{ .frequency = 360460800,	.driver_data = PLLVAL(141, 5, 1), 	}, 	/* FVco 720.921600 */ +	{ .frequency = 366206400,	.driver_data = PLLVAL(165, 6, 1), 	}, 	/* FVco 732.412800 */ +	{ .frequency = 372556800,	.driver_data = PLLVAL(124, 4, 1), 	}, 	/* FVco 745.113600 */ +	{ .frequency = 378201600,	.driver_data = PLLVAL(126, 4, 1), 	}, 	/* FVco 756.403200 */ +	{ .frequency = 384652800,	.driver_data = PLLVAL(151, 5, 1), 	}, 	/* FVco 769.305600 */ +	{ .frequency = 391608000,	.driver_data = PLLVAL(177, 6, 1), 	}, 	/* FVco 783.216000 */ +	{ .frequency = 396264960,	.driver_data = PLLVAL(109, 3, 1), 	}, 	/* FVco 792.529920 */ +	{ .frequency = 402192000,	.driver_data = PLLVAL(87, 2, 1), 	}, 	/* FVco 804.384000 */ +}; + +static int s3c2440_plls169344_add(struct device *dev, +				  struct subsys_interface *sif) +{ +	struct clk *xtal_clk; +	unsigned long xtal; + +	xtal_clk = clk_get(NULL, "xtal"); +	if (IS_ERR(xtal_clk)) +		return PTR_ERR(xtal_clk); + +	xtal = clk_get_rate(xtal_clk); +	clk_put(xtal_clk); + +	if (xtal == 169344000) { +		printk(KERN_INFO "Using PLL table for 16.9344MHz crystal\n"); +		return s3c_plltab_register(s3c2440_plls_169344, +					   ARRAY_SIZE(s3c2440_plls_169344)); +	} + +	return 0; +} + +static struct subsys_interface s3c2440_plls169344_interface = { +	.name		= "s3c2440_plls169344", +	.subsys		= &s3c2440_subsys, +	.add_dev	= s3c2440_plls169344_add, +}; + +static int __init s3c2440_pll_16934400(void) +{ +	return subsys_interface_register(&s3c2440_plls169344_interface); +} +arch_initcall(s3c2440_pll_16934400); + +static struct subsys_interface s3c2442_plls169344_interface = { +	.name		= "s3c2442_plls169344", +	.subsys		= &s3c2442_subsys, +	.add_dev	= s3c2440_plls169344_add, +}; + +static int __init s3c2442_pll_16934400(void) +{ +	return subsys_interface_register(&s3c2442_plls169344_interface); +} +arch_initcall(s3c2442_pll_16934400); diff --git a/arch/arm/mach-s3c24xx/pm-h1940.S b/arch/arm/mach-s3c24xx/pm-h1940.S new file mode 100644 index 00000000000..6183a688012 --- /dev/null +++ b/arch/arm/mach-s3c24xx/pm-h1940.S @@ -0,0 +1,33 @@ +/* linux/arch/arm/mach-s3c2410/pm-h1940.S + * + * Copyright (c) 2006 Ben Dooks <ben-linux@fluff.org> + * + * H1940 Suspend to RAM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <mach/hardware.h> +#include <mach/map.h> + +#include <mach/regs-gpio.h> + +	.text +	.global	h1940_pm_return + +h1940_pm_return: +	mov	r0, #S3C2410_PA_GPIO +	ldr	pc, [r0, #S3C2410_GSTATUS3 - S3C24XX_VA_GPIO] diff --git a/arch/arm/mach-s3c24xx/pm-s3c2410.c b/arch/arm/mach-s3c24xx/pm-s3c2410.c new file mode 100644 index 00000000000..20e481d8a33 --- /dev/null +++ b/arch/arm/mach-s3c24xx/pm-s3c2410.c @@ -0,0 +1,186 @@ +/* linux/arch/arm/mach-s3c2410/pm.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/time.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/gpio.h> +#include <linux/io.h> + +#include <asm/mach-types.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> + +#include <plat/gpio-cfg.h> +#include <plat/cpu.h> +#include <plat/pm.h> + +#include "h1940.h" + +static void s3c2410_pm_prepare(void) +{ +	/* ensure at least GSTATUS3 has the resume address */ + +	__raw_writel(virt_to_phys(s3c_cpu_resume), S3C2410_GSTATUS3); + +	S3C_PMDBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3)); +	S3C_PMDBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4)); + +	if (machine_is_h1940()) { +		void *base = phys_to_virt(H1940_SUSPEND_CHECK); +		unsigned long ptr; +		unsigned long calc = 0; + +		/* generate check for the bootloader to check on resume */ + +		for (ptr = 0; ptr < 0x40000; ptr += 0x400) +			calc += __raw_readl(base+ptr); + +		__raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); +	} + +	/* RX3715 and RX1950 use similar to H1940 code and the +	 * same offsets for resume and checksum pointers */ + +	if (machine_is_rx3715() || machine_is_rx1950()) { +		void *base = phys_to_virt(H1940_SUSPEND_CHECK); +		unsigned long ptr; +		unsigned long calc = 0; + +		/* generate check for the bootloader to check on resume */ + +		for (ptr = 0; ptr < 0x40000; ptr += 0x4) +			calc += __raw_readl(base+ptr); + +		__raw_writel(calc, phys_to_virt(H1940_SUSPEND_CHECKSUM)); +	} + +	if (machine_is_aml_m5900()) { +		gpio_request_one(S3C2410_GPF(2), GPIOF_OUT_INIT_HIGH, NULL); +		gpio_free(S3C2410_GPF(2)); +	} + +	if (machine_is_rx1950()) { +		/* According to S3C2442 user's manual, page 7-17, +		 * when the system is operating in NAND boot mode, +		 * the hardware pin configuration - EINT[23:21] – +		 * must be set as input for starting up after +		 * wakeup from sleep mode +		 */ +		s3c_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPIO_INPUT); +		s3c_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPIO_INPUT); +		s3c_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPIO_INPUT); +	} +} + +static void s3c2410_pm_resume(void) +{ +	unsigned long tmp; + +	/* unset the return-from-sleep flag, to ensure reset */ + +	tmp = __raw_readl(S3C2410_GSTATUS2); +	tmp &= S3C2410_GSTATUS2_OFFRESET; +	__raw_writel(tmp, S3C2410_GSTATUS2); + +	if (machine_is_aml_m5900()) { +		gpio_request_one(S3C2410_GPF(2), GPIOF_OUT_INIT_LOW, NULL); +		gpio_free(S3C2410_GPF(2)); +	} +} + +struct syscore_ops s3c2410_pm_syscore_ops = { +	.resume		= s3c2410_pm_resume, +}; + +static int s3c2410_pm_add(struct device *dev, struct subsys_interface *sif) +{ +	pm_cpu_prep = s3c2410_pm_prepare; +	pm_cpu_sleep = s3c2410_cpu_suspend; + +	return 0; +} + +#if defined(CONFIG_CPU_S3C2410) +static struct subsys_interface s3c2410_pm_interface = { +	.name		= "s3c2410_pm", +	.subsys		= &s3c2410_subsys, +	.add_dev	= s3c2410_pm_add, +}; + +/* register ourselves */ + +static int __init s3c2410_pm_drvinit(void) +{ +	return subsys_interface_register(&s3c2410_pm_interface); +} + +arch_initcall(s3c2410_pm_drvinit); + +static struct subsys_interface s3c2410a_pm_interface = { +	.name		= "s3c2410a_pm", +	.subsys		= &s3c2410a_subsys, +	.add_dev	= s3c2410_pm_add, +}; + +static int __init s3c2410a_pm_drvinit(void) +{ +	return subsys_interface_register(&s3c2410a_pm_interface); +} + +arch_initcall(s3c2410a_pm_drvinit); +#endif + +#if defined(CONFIG_CPU_S3C2440) +static struct subsys_interface s3c2440_pm_interface = { +	.name		= "s3c2440_pm", +	.subsys		= &s3c2440_subsys, +	.add_dev	= s3c2410_pm_add, +}; + +static int __init s3c2440_pm_drvinit(void) +{ +	return subsys_interface_register(&s3c2440_pm_interface); +} + +arch_initcall(s3c2440_pm_drvinit); +#endif + +#if defined(CONFIG_CPU_S3C2442) +static struct subsys_interface s3c2442_pm_interface = { +	.name		= "s3c2442_pm", +	.subsys		= &s3c2442_subsys, +	.add_dev	= s3c2410_pm_add, +}; + +static int __init s3c2442_pm_drvinit(void) +{ +	return subsys_interface_register(&s3c2442_pm_interface); +} + +arch_initcall(s3c2442_pm_drvinit); +#endif diff --git a/arch/arm/mach-s3c24xx/pm-s3c2412.c b/arch/arm/mach-s3c24xx/pm-s3c2412.c new file mode 100644 index 00000000000..d75f95e487e --- /dev/null +++ b/arch/arm/mach-s3c24xx/pm-s3c2412.c @@ -0,0 +1,131 @@ +/* linux/arch/arm/mach-s3c2412/pm.c + * + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://armlinux.simtec.co.uk/. + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/irq.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> + +#include <plat/cpu.h> +#include <plat/pm.h> +#include <plat/wakeup-mask.h> + +#include "regs-dsc.h" +#include "s3c2412-power.h" + +extern void s3c2412_sleep_enter(void); + +static int s3c2412_cpu_suspend(unsigned long arg) +{ +	unsigned long tmp; + +	/* set our standby method to sleep */ + +	tmp = __raw_readl(S3C2412_PWRCFG); +	tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP; +	__raw_writel(tmp, S3C2412_PWRCFG); + +	s3c2412_sleep_enter(); + +	pr_info("Failed to suspend the system\n"); +	return 1; /* Aborting suspend */ +} + +/* mapping of interrupts to parts of the wakeup mask */ +static struct samsung_wakeup_mask wake_irqs[] = { +	{ .irq = IRQ_RTC,	.bit = S3C2412_PWRCFG_RTC_MASKIRQ, }, +}; + +static void s3c2412_pm_prepare(void) +{ +	samsung_sync_wakemask(S3C2412_PWRCFG, +			      wake_irqs, ARRAY_SIZE(wake_irqs)); +} + +static int s3c2412_pm_add(struct device *dev, struct subsys_interface *sif) +{ +	pm_cpu_prep = s3c2412_pm_prepare; +	pm_cpu_sleep = s3c2412_cpu_suspend; + +	return 0; +} + +static struct sleep_save s3c2412_sleep[] = { +	SAVE_ITEM(S3C2412_DSC0), +	SAVE_ITEM(S3C2412_DSC1), +	SAVE_ITEM(S3C2413_GPJDAT), +	SAVE_ITEM(S3C2413_GPJCON), +	SAVE_ITEM(S3C2413_GPJUP), + +	/* save the PWRCFG to get back to original sleep method */ + +	SAVE_ITEM(S3C2412_PWRCFG), + +	/* save the sleep configuration anyway, just in case these +	 * get damaged during wakeup */ + +	SAVE_ITEM(S3C2412_GPBSLPCON), +	SAVE_ITEM(S3C2412_GPCSLPCON), +	SAVE_ITEM(S3C2412_GPDSLPCON), +	SAVE_ITEM(S3C2412_GPFSLPCON), +	SAVE_ITEM(S3C2412_GPGSLPCON), +	SAVE_ITEM(S3C2412_GPHSLPCON), +	SAVE_ITEM(S3C2413_GPJSLPCON), +}; + +static struct subsys_interface s3c2412_pm_interface = { +	.name		= "s3c2412_pm", +	.subsys		= &s3c2412_subsys, +	.add_dev	= s3c2412_pm_add, +}; + +static __init int s3c2412_pm_init(void) +{ +	return subsys_interface_register(&s3c2412_pm_interface); +} + +arch_initcall(s3c2412_pm_init); + +static int s3c2412_pm_suspend(void) +{ +	s3c_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); +	return 0; +} + +static void s3c2412_pm_resume(void) +{ +	unsigned long tmp; + +	tmp = __raw_readl(S3C2412_PWRCFG); +	tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK; +	tmp |=  S3C2412_PWRCFG_STANDBYWFI_IDLE; +	__raw_writel(tmp, S3C2412_PWRCFG); + +	s3c_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep)); +} + +struct syscore_ops s3c2412_pm_syscore_ops = { +	.suspend	= s3c2412_pm_suspend, +	.resume		= s3c2412_pm_resume, +}; diff --git a/arch/arm/mach-s3c24xx/pm-s3c2416.c b/arch/arm/mach-s3c24xx/pm-s3c2416.c new file mode 100644 index 00000000000..44923895f55 --- /dev/null +++ b/arch/arm/mach-s3c24xx/pm-s3c2416.c @@ -0,0 +1,85 @@ +/* linux/arch/arm/mach-s3c2416/pm.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * S3C2416 - PM support (Based on Ben Dooks' S3C2412 PM support) + * + * 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/device.h> +#include <linux/syscore_ops.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> + +#include <mach/regs-s3c2443-clock.h> + +#include <plat/cpu.h> +#include <plat/pm.h> + +#include "s3c2412-power.h" + +extern void s3c2412_sleep_enter(void); + +static int s3c2416_cpu_suspend(unsigned long arg) +{ +	/* enable wakeup sources regardless of battery state */ +	__raw_writel(S3C2443_PWRCFG_SLEEP, S3C2443_PWRCFG); + +	/* set the mode as sleep, 2BED represents "Go to BED" */ +	__raw_writel(0x2BED, S3C2443_PWRMODE); + +	s3c2412_sleep_enter(); + +	pr_info("Failed to suspend the system\n"); +	return 1; /* Aborting suspend */ +} + +static void s3c2416_pm_prepare(void) +{ +	/* +	 * write the magic value u-boot uses to check for resume into +	 * the INFORM0 register, and ensure INFORM1 is set to the +	 * correct address to resume from. +	 */ +	__raw_writel(0x2BED, S3C2412_INFORM0); +	__raw_writel(virt_to_phys(s3c_cpu_resume), S3C2412_INFORM1); +} + +static int s3c2416_pm_add(struct device *dev, struct subsys_interface *sif) +{ +	pm_cpu_prep = s3c2416_pm_prepare; +	pm_cpu_sleep = s3c2416_cpu_suspend; + +	return 0; +} + +static struct subsys_interface s3c2416_pm_interface = { +	.name		= "s3c2416_pm", +	.subsys		= &s3c2416_subsys, +	.add_dev	= s3c2416_pm_add, +}; + +static __init int s3c2416_pm_init(void) +{ +	return subsys_interface_register(&s3c2416_pm_interface); +} + +arch_initcall(s3c2416_pm_init); + + +static void s3c2416_pm_resume(void) +{ +	/* unset the return-from-sleep amd inform flags */ +	__raw_writel(0x0, S3C2443_PWRMODE); +	__raw_writel(0x0, S3C2412_INFORM0); +	__raw_writel(0x0, S3C2412_INFORM1); +} + +struct syscore_ops s3c2416_pm_syscore_ops = { +	.resume		= s3c2416_pm_resume, +}; diff --git a/arch/arm/mach-s3c24xx/pm.c b/arch/arm/mach-s3c24xx/pm.c new file mode 100644 index 00000000000..b19256ec8d4 --- /dev/null +++ b/arch/arm/mach-s3c24xx/pm.c @@ -0,0 +1,134 @@ +/* linux/arch/arm/plat-s3c24xx/pm.c + * + * Copyright (c) 2004-2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX Power Manager (Suspend-To-RAM) support + * + * See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + * Parts based on arch/arm/mach-pxa/pm.c + * + * Thanks to Dimitry Andric for debugging +*/ + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/time.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <mach/regs-clock.h> +#include <mach/regs-gpio.h> +#include <mach/regs-irq.h> +#include <mach/gpio-samsung.h> + +#include <asm/mach/time.h> + +#include <plat/gpio-cfg.h> +#include <plat/pm.h> + +#include "regs-mem.h" + +#define PFX "s3c24xx-pm: " + +static struct sleep_save core_save[] = { +	/* we restore the timings here, with the proviso that the board +	 * brings the system up in an slower, or equal frequency setting +	 * to the original system. +	 * +	 * if we cannot guarantee this, then things are going to go very +	 * wrong here, as we modify the refresh and both pll settings. +	 */ + +	SAVE_ITEM(S3C2410_BWSCON), +	SAVE_ITEM(S3C2410_BANKCON0), +	SAVE_ITEM(S3C2410_BANKCON1), +	SAVE_ITEM(S3C2410_BANKCON2), +	SAVE_ITEM(S3C2410_BANKCON3), +	SAVE_ITEM(S3C2410_BANKCON4), +	SAVE_ITEM(S3C2410_BANKCON5), +}; + +/* s3c_pm_check_resume_pin + * + * check to see if the pin is configured correctly for sleep mode, and + * make any necessary adjustments if it is not +*/ + +static void s3c_pm_check_resume_pin(unsigned int pin, unsigned int irqoffs) +{ +	unsigned long irqstate; +	unsigned long pinstate; +	int irq = gpio_to_irq(pin); + +	if (irqoffs < 4) +		irqstate = s3c_irqwake_intmask & (1L<<irqoffs); +	else +		irqstate = s3c_irqwake_eintmask & (1L<<irqoffs); + +	pinstate = s3c_gpio_getcfg(pin); + +	if (!irqstate) { +		if (pinstate == S3C2410_GPIO_IRQ) +			S3C_PMDBG("Leaving IRQ %d (pin %d) as is\n", irq, pin); +	} else { +		if (pinstate == S3C2410_GPIO_IRQ) { +			S3C_PMDBG("Disabling IRQ %d (pin %d)\n", irq, pin); +			s3c_gpio_cfgpin(pin, S3C2410_GPIO_INPUT); +		} +	} +} + +/* s3c_pm_configure_extint + * + * configure all external interrupt pins +*/ + +void s3c_pm_configure_extint(void) +{ +	int pin; + +	/* for each of the external interrupts (EINT0..EINT15) we +	 * need to check whether it is an external interrupt source, +	 * and then configure it as an input if it is not +	*/ + +	for (pin = S3C2410_GPF(0); pin <= S3C2410_GPF(7); pin++) { +		s3c_pm_check_resume_pin(pin, pin - S3C2410_GPF(0)); +	} + +	for (pin = S3C2410_GPG(0); pin <= S3C2410_GPG(7); pin++) { +		s3c_pm_check_resume_pin(pin, (pin - S3C2410_GPG(0))+8); +	} +} + + +void s3c_pm_restore_core(void) +{ +	s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); +} + +void s3c_pm_save_core(void) +{ +	s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); +} + diff --git a/arch/arm/mach-s3c24xx/regs-dsc.h b/arch/arm/mach-s3c24xx/regs-dsc.h new file mode 100644 index 00000000000..61b3d1387d7 --- /dev/null +++ b/arch/arm/mach-s3c24xx/regs-dsc.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> + *		      http://www.simtec.co.uk/products/SWLINUX/ + * + * 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. + * + * S3C2440/S3C2412 Signal Drive Strength Control +*/ + + +#ifndef __ASM_ARCH_REGS_DSC_H +#define __ASM_ARCH_REGS_DSC_H __FILE__ + +/* S3C2412 */ +#define S3C2412_DSC0	   S3C2410_GPIOREG(0xdc) +#define S3C2412_DSC1	   S3C2410_GPIOREG(0xe0) + +/* S3C2440 */ +#define S3C2440_DSC0	   S3C2410_GPIOREG(0xc4) +#define S3C2440_DSC1	   S3C2410_GPIOREG(0xc8) + +#endif	/* __ASM_ARCH_REGS_DSC_H */ + diff --git a/arch/arm/mach-s3c24xx/regs-mem.h b/arch/arm/mach-s3c24xx/regs-mem.h new file mode 100644 index 00000000000..86b1258368c --- /dev/null +++ b/arch/arm/mach-s3c24xx/regs-mem.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> + *		http://www.simtec.co.uk/products/SWLINUX/ + * + * 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. + * + * S3C2410 Memory Control register definitions + */ + +#ifndef __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H +#define __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H __FILE__ + +#define S3C2410_MEMREG(x)		(S3C24XX_VA_MEMCTRL + (x)) + +#define S3C2410_BWSCON			S3C2410_MEMREG(0x00) +#define S3C2410_BANKCON0		S3C2410_MEMREG(0x04) +#define S3C2410_BANKCON1		S3C2410_MEMREG(0x08) +#define S3C2410_BANKCON2		S3C2410_MEMREG(0x0C) +#define S3C2410_BANKCON3		S3C2410_MEMREG(0x10) +#define S3C2410_BANKCON4		S3C2410_MEMREG(0x14) +#define S3C2410_BANKCON5		S3C2410_MEMREG(0x18) +#define S3C2410_BANKCON6		S3C2410_MEMREG(0x1C) +#define S3C2410_BANKCON7		S3C2410_MEMREG(0x20) +#define S3C2410_REFRESH			S3C2410_MEMREG(0x24) +#define S3C2410_BANKSIZE		S3C2410_MEMREG(0x28) + +#define S3C2410_BWSCON_ST1		(1 << 7) +#define S3C2410_BWSCON_ST2		(1 << 11) +#define S3C2410_BWSCON_ST3		(1 << 15) +#define S3C2410_BWSCON_ST4		(1 << 19) +#define S3C2410_BWSCON_ST5		(1 << 23) + +#define S3C2410_BWSCON_GET(_bwscon, _bank) (((_bwscon) >> ((_bank) * 4)) & 0xf) + +#define S3C2410_BWSCON_WS		(1 << 2) + +#define S3C2410_BANKCON_PMC16		(0x3) + +#define S3C2410_BANKCON_Tacp_SHIFT	(2) +#define S3C2410_BANKCON_Tcah_SHIFT	(4) +#define S3C2410_BANKCON_Tcoh_SHIFT	(6) +#define S3C2410_BANKCON_Tacc_SHIFT	(8) +#define S3C2410_BANKCON_Tcos_SHIFT	(11) +#define S3C2410_BANKCON_Tacs_SHIFT	(13) + +#define S3C2410_BANKCON_SDRAM		(0x3 << 15) + +#define S3C2410_REFRESH_SELF		(1 << 22) + +#define S3C2410_BANKSIZE_MASK		(0x7 << 0) + +#endif /* __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H */ diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c new file mode 100644 index 00000000000..7eab8882988 --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2410.c @@ -0,0 +1,155 @@ +/* linux/arch/arm/mach-s3c2410/s3c2410.c + * + * Copyright (c) 2003-2005 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> +#include <asm/irq.h> +#include <asm/system_misc.h> + +#include <plat/cpu-freq.h> + +#include <mach/regs-clock.h> + +#include <plat/cpu.h> +#include <plat/devs.h> +#include <plat/clock.h> +#include <plat/pll.h> +#include <plat/pm.h> +#include <plat/watchdog-reset.h> + +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> + +#include "common.h" + +/* Initial IO mappings */ + +static struct map_desc s3c2410_iodesc[] __initdata = { +	IODESC_ENT(CLKPWR), +	IODESC_ENT(TIMER), +	IODESC_ENT(WATCHDOG), +}; + +/* our uart devices */ + +/* uart registration process */ + +void __init s3c2410_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ +	s3c24xx_init_uartdevs("s3c2410-uart", s3c2410_uart_resources, cfg, no); +} + +/* s3c2410_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. +*/ + +void __init s3c2410_map_io(void) +{ +	s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up; +	s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up; + +	iotable_init(s3c2410_iodesc, ARRAY_SIZE(s3c2410_iodesc)); +} + +void __init_or_cpufreq s3c2410_setup_clocks(void) +{ +} + +struct bus_type s3c2410_subsys = { +	.name = "s3c2410-core", +	.dev_name = "s3c2410-core", +}; + +/* Note, we would have liked to name this s3c2410-core, but we cannot + * register two subsystems with the same name. + */ +struct bus_type s3c2410a_subsys = { +	.name = "s3c2410a-core", +	.dev_name = "s3c2410a-core", +}; + +static struct device s3c2410_dev = { +	.bus		= &s3c2410_subsys, +}; + +/* need to register the subsystem before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2410 based system) + * as a driver which may support both 2410 and 2440 may try and use it. +*/ + +static int __init s3c2410_core_init(void) +{ +	return subsys_system_register(&s3c2410_subsys, NULL); +} + +core_initcall(s3c2410_core_init); + +static int __init s3c2410a_core_init(void) +{ +	return subsys_system_register(&s3c2410a_subsys, NULL); +} + +core_initcall(s3c2410a_core_init); + +int __init s3c2410_init(void) +{ +	printk("S3C2410: Initialising architecture\n"); + +#ifdef CONFIG_PM +	register_syscore_ops(&s3c2410_pm_syscore_ops); +	register_syscore_ops(&s3c24xx_irq_syscore_ops); +#endif + +	return device_register(&s3c2410_dev); +} + +int __init s3c2410a_init(void) +{ +	s3c2410_dev.bus = &s3c2410a_subsys; +	return s3c2410_init(); +} + +void s3c2410_restart(enum reboot_mode mode, const char *cmd) +{ +	if (mode == REBOOT_SOFT) { +		soft_restart(0); +	} + +	samsung_wdt_reset(); + +	/* we'll take a jump through zero as a poor second */ +	soft_restart(0); +} diff --git a/arch/arm/mach-s3c24xx/s3c2412-power.h b/arch/arm/mach-s3c24xx/s3c2412-power.h new file mode 100644 index 00000000000..1b02c5ddb31 --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2412-power.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk> + *	http://armlinux.simtec.co.uk/ + * + * 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_S3C24XX_S3C2412_POWER_H +#define __ARCH_ARM_MACH_S3C24XX_S3C2412_POWER_H __FILE__ + +#define S3C24XX_PWRREG(x)			((x) + S3C24XX_VA_CLKPWR) + +#define S3C2412_PWRMODECON			S3C24XX_PWRREG(0x20) +#define S3C2412_PWRCFG				S3C24XX_PWRREG(0x24) + +#define S3C2412_INFORM0				S3C24XX_PWRREG(0x70) +#define S3C2412_INFORM1				S3C24XX_PWRREG(0x74) +#define S3C2412_INFORM2				S3C24XX_PWRREG(0x78) +#define S3C2412_INFORM3				S3C24XX_PWRREG(0x7C) + +#define S3C2412_PWRCFG_BATF_IRQ			(1 << 0) +#define S3C2412_PWRCFG_BATF_IGNORE		(2 << 0) +#define S3C2412_PWRCFG_BATF_SLEEP		(3 << 0) +#define S3C2412_PWRCFG_BATF_MASK		(3 << 0) + +#define S3C2412_PWRCFG_STANDBYWFI_IGNORE	(0 << 6) +#define S3C2412_PWRCFG_STANDBYWFI_IDLE		(1 << 6) +#define S3C2412_PWRCFG_STANDBYWFI_STOP		(2 << 6) +#define S3C2412_PWRCFG_STANDBYWFI_SLEEP		(3 << 6) +#define S3C2412_PWRCFG_STANDBYWFI_MASK		(3 << 6) + +#define S3C2412_PWRCFG_RTC_MASKIRQ		(1 << 8) +#define S3C2412_PWRCFG_NAND_NORST		(1 << 9) + +#endif /* __ARCH_ARM_MACH_S3C24XX_S3C2412_POWER_H */ diff --git a/arch/arm/mach-s3c24xx/s3c2412.c b/arch/arm/mach-s3c24xx/s3c2412.c new file mode 100644 index 00000000000..d49f52fbc84 --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2412.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2006 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://armlinux.simtec.co.uk/. + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/reboot.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/proc-fns.h> +#include <asm/irq.h> +#include <asm/system_misc.h> + +#include <mach/hardware.h> +#include <mach/regs-clock.h> +#include <mach/regs-gpio.h> + +#include <plat/clock.h> +#include <plat/cpu.h> +#include <plat/cpu-freq.h> +#include <plat/devs.h> +#include <plat/nand-core.h> +#include <plat/pll.h> +#include <plat/pm.h> +#include <plat/regs-spi.h> + +#include "common.h" +#include "regs-dsc.h" +#include "s3c2412-power.h" + +#define S3C2412_SWRST			(S3C24XX_VA_CLKPWR + 0x30) +#define S3C2412_SWRST_RESET		(0x533C2412) + +#ifndef CONFIG_CPU_S3C2412_ONLY +void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO; + +static inline void s3c2412_init_gpio2(void) +{ +	s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10; +} +#else +#define s3c2412_init_gpio2() do { } while(0) +#endif + +/* Initial IO mappings */ + +static struct map_desc s3c2412_iodesc[] __initdata = { +	IODESC_ENT(CLKPWR), +	IODESC_ENT(TIMER), +	IODESC_ENT(WATCHDOG), +	{ +		.virtual = (unsigned long)S3C2412_VA_SSMC, +		.pfn	 = __phys_to_pfn(S3C2412_PA_SSMC), +		.length	 = SZ_1M, +		.type	 = MT_DEVICE, +	}, +	{ +		.virtual = (unsigned long)S3C2412_VA_EBI, +		.pfn	 = __phys_to_pfn(S3C2412_PA_EBI), +		.length	 = SZ_1M, +		.type	 = MT_DEVICE, +	}, +}; + +/* uart registration process */ + +void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ +	s3c24xx_init_uartdevs("s3c2412-uart", s3c2410_uart_resources, cfg, no); + +	/* rename devices that are s3c2412/s3c2413 specific */ +	s3c_device_sdi.name  = "s3c2412-sdi"; +	s3c_device_lcd.name  = "s3c2412-lcd"; +	s3c_nand_setname("s3c2412-nand"); + +	/* alter IRQ of SDI controller */ + +	s3c_device_sdi.resource[1].start = IRQ_S3C2412_SDI; +	s3c_device_sdi.resource[1].end   = IRQ_S3C2412_SDI; + +	/* spi channel related changes, s3c2412/13 specific */ +	s3c_device_spi0.name = "s3c2412-spi"; +	s3c_device_spi0.resource[0].end = S3C24XX_PA_SPI + 0x24; +	s3c_device_spi1.name = "s3c2412-spi"; +	s3c_device_spi1.resource[0].start = S3C24XX_PA_SPI + S3C2412_SPI1; +	s3c_device_spi1.resource[0].end = S3C24XX_PA_SPI + S3C2412_SPI1 + 0x24; + +} + +/* s3c2412_idle + * + * use the standard idle call by ensuring the idle mode + * in power config, then issuing the idle co-processor + * instruction +*/ + +static void s3c2412_idle(void) +{ +	unsigned long tmp; + +	/* ensure our idle mode is to go to idle */ + +	tmp = __raw_readl(S3C2412_PWRCFG); +	tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK; +	tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE; +	__raw_writel(tmp, S3C2412_PWRCFG); + +	cpu_do_idle(); +} + +void s3c2412_restart(enum reboot_mode mode, const char *cmd) +{ +	if (mode == REBOOT_SOFT) +		soft_restart(0); + +	/* errata "Watch-dog/Software Reset Problem" specifies that +	 * this reset must be done with the SYSCLK sourced from +	 * EXTCLK instead of FOUT to avoid a glitch in the reset +	 * mechanism. +	 * +	 * See the watchdog section of the S3C2412 manual for more +	 * information on this fix. +	 */ + +	__raw_writel(0x00, S3C2412_CLKSRC); +	__raw_writel(S3C2412_SWRST_RESET, S3C2412_SWRST); + +	mdelay(1); +} + +/* s3c2412_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. +*/ + +void __init s3c2412_map_io(void) +{ +	/* move base of IO */ + +	s3c2412_init_gpio2(); + +	/* set our idle function */ + +	arm_pm_idle = s3c2412_idle; + +	/* register our io-tables */ + +	iotable_init(s3c2412_iodesc, ARRAY_SIZE(s3c2412_iodesc)); +} + +void __init_or_cpufreq s3c2412_setup_clocks(void) +{ +} + +/* need to register the subsystem before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2412 based system) + * as a driver which may support both 2410 and 2440 may try and use it. +*/ + +struct bus_type s3c2412_subsys = { +	.name = "s3c2412-core", +	.dev_name = "s3c2412-core", +}; + +static int __init s3c2412_core_init(void) +{ +	return subsys_system_register(&s3c2412_subsys, NULL); +} + +core_initcall(s3c2412_core_init); + +static struct device s3c2412_dev = { +	.bus		= &s3c2412_subsys, +}; + +int __init s3c2412_init(void) +{ +	printk("S3C2412: Initialising architecture\n"); + +#ifdef CONFIG_PM +	register_syscore_ops(&s3c2412_pm_syscore_ops); +	register_syscore_ops(&s3c24xx_irq_syscore_ops); +#endif + +	return device_register(&s3c2412_dev); +} diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c new file mode 100644 index 00000000000..9fe260ae11e --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2416.c @@ -0,0 +1,155 @@ +/* linux/arch/arm/mach-s3c2416/s3c2416.c + * + * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>, + *	as part of OpenInkpot project + * Copyright (c) 2009 Promwad Innovation Company + *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com> + * + * Samsung S3C2416 Mobile CPU support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/reboot.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> +#include <asm/proc-fns.h> +#include <asm/irq.h> +#include <asm/system_misc.h> + +#include <mach/regs-s3c2443-clock.h> +#include <mach/rtc-core.h> + +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/sdhci.h> +#include <plat/pm.h> + +#include <plat/iic-core.h> +#include <plat/fb-core.h> +#include <plat/nand-core.h> +#include <plat/adc-core.h> +#include <plat/spi-core.h> + +#include "common.h" + +static struct map_desc s3c2416_iodesc[] __initdata = { +	IODESC_ENT(WATCHDOG), +	IODESC_ENT(CLKPWR), +	IODESC_ENT(TIMER), +}; + +struct bus_type s3c2416_subsys = { +	.name = "s3c2416-core", +	.dev_name = "s3c2416-core", +}; + +static struct device s3c2416_dev = { +	.bus		= &s3c2416_subsys, +}; + +void s3c2416_restart(enum reboot_mode mode, const char *cmd) +{ +	if (mode == REBOOT_SOFT) +		soft_restart(0); + +	__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST); +} + +int __init s3c2416_init(void) +{ +	printk(KERN_INFO "S3C2416: Initializing architecture\n"); + +	/* change WDT IRQ number */ +	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT; +	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT; + +	/* the i2c devices are directly compatible with s3c2440 */ +	s3c_i2c0_setname("s3c2440-i2c"); +	s3c_i2c1_setname("s3c2440-i2c"); + +	s3c_fb_setname("s3c2443-fb"); + +	s3c_adc_setname("s3c2416-adc"); +	s3c_rtc_setname("s3c2416-rtc"); + +#ifdef CONFIG_PM +	register_syscore_ops(&s3c2416_pm_syscore_ops); +	register_syscore_ops(&s3c24xx_irq_syscore_ops); +	register_syscore_ops(&s3c2416_irq_syscore_ops); +#endif + +	return device_register(&s3c2416_dev); +} + +void __init s3c2416_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ +	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); + +	s3c_nand_setname("s3c2412-nand"); +} + +/* s3c2416_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. + */ + +void __init s3c2416_map_io(void) +{ +	s3c24xx_gpiocfg_default.set_pull = samsung_gpio_setpull_updown; +	s3c24xx_gpiocfg_default.get_pull = samsung_gpio_getpull_updown; + +	/* initialize device information early */ +	s3c2416_default_sdhci0(); +	s3c2416_default_sdhci1(); +	s3c64xx_spi_setname("s3c2443-spi"); + +	iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc)); +} + +/* need to register the subsystem before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2416 based system) + * as a driver which may support both 2443 and 2440 may try and use it. +*/ + +static int __init s3c2416_core_init(void) +{ +	return subsys_system_register(&s3c2416_subsys, NULL); +} + +core_initcall(s3c2416_core_init); diff --git a/arch/arm/mach-s3c24xx/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c new file mode 100644 index 00000000000..03d379f1fc5 --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2440.c @@ -0,0 +1,77 @@ +/* linux/arch/arm/mach-s3c2440/s3c2440.c + * + * Copyright (c) 2004-2006 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C2440 Mobile CPU support + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/gpio.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> +#include <asm/irq.h> + +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/pm.h> + +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> + +#include "common.h" + +static struct device s3c2440_dev = { +	.bus		= &s3c2440_subsys, +}; + +int __init s3c2440_init(void) +{ +	printk("S3C2440: Initialising architecture\n"); + +	/* change irq for watchdog */ + +	s3c_device_wdt.resource[1].start = IRQ_S3C2440_WDT; +	s3c_device_wdt.resource[1].end   = IRQ_S3C2440_WDT; + +	/* register suspend/resume handlers */ + +#ifdef CONFIG_PM +	register_syscore_ops(&s3c2410_pm_syscore_ops); +	register_syscore_ops(&s3c24xx_irq_syscore_ops); +#endif +	register_syscore_ops(&s3c244x_pm_syscore_ops); + +	/* register our system device for everything else */ + +	return device_register(&s3c2440_dev); +} + +void __init s3c2440_map_io(void) +{ +	s3c244x_map_io(); + +	s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1up; +	s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1up; +} diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c new file mode 100644 index 00000000000..fb9da2b603a --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2442.c @@ -0,0 +1,79 @@ +/* linux/arch/arm/mach-s3c2442/s3c2442.c + * + * Copyright (c) 2004-2005 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2442 core and lock support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/errno.h> +#include <linux/err.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/mutex.h> +#include <linux/gpio.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> +#include <linux/atomic.h> +#include <asm/irq.h> + +#include <mach/regs-clock.h> + +#include <plat/clock.h> +#include <plat/cpu.h> +#include <plat/pm.h> + +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> + +#include "common.h" + +static struct device s3c2442_dev = { +	.bus		= &s3c2442_subsys, +}; + +int __init s3c2442_init(void) +{ +	printk("S3C2442: Initialising architecture\n"); + +#ifdef CONFIG_PM +	register_syscore_ops(&s3c2410_pm_syscore_ops); +	register_syscore_ops(&s3c24xx_irq_syscore_ops); +#endif +	register_syscore_ops(&s3c244x_pm_syscore_ops); + +	return device_register(&s3c2442_dev); +} + +void __init s3c2442_map_io(void) +{ +	s3c244x_map_io(); + +	s3c24xx_gpiocfg_default.set_pull = s3c24xx_gpio_setpull_1down; +	s3c24xx_gpiocfg_default.get_pull = s3c24xx_gpio_getpull_1down; +} diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c new file mode 100644 index 00000000000..c7a804d0348 --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c2443.c @@ -0,0 +1,122 @@ +/* linux/arch/arm/mach-s3c2443/s3c2443.c + * + * Copyright (c) 2007 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C2443 Mobile CPU support + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/reboot.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> +#include <asm/irq.h> +#include <asm/system_misc.h> + +#include <mach/regs-s3c2443-clock.h> +#include <mach/rtc-core.h> + +#include <plat/gpio-core.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/fb-core.h> +#include <plat/nand-core.h> +#include <plat/adc-core.h> +#include <plat/spi-core.h> + +static struct map_desc s3c2443_iodesc[] __initdata = { +	IODESC_ENT(WATCHDOG), +	IODESC_ENT(CLKPWR), +	IODESC_ENT(TIMER), +}; + +struct bus_type s3c2443_subsys = { +	.name = "s3c2443-core", +	.dev_name = "s3c2443-core", +}; + +static struct device s3c2443_dev = { +	.bus		= &s3c2443_subsys, +}; + +void s3c2443_restart(enum reboot_mode mode, const char *cmd) +{ +	if (mode == REBOOT_SOFT) +		soft_restart(0); + +	__raw_writel(S3C2443_SWRST_RESET, S3C2443_SWRST); +} + +int __init s3c2443_init(void) +{ +	printk("S3C2443: Initialising architecture\n"); + +	s3c_nand_setname("s3c2412-nand"); +	s3c_fb_setname("s3c2443-fb"); + +	s3c_adc_setname("s3c2443-adc"); +	s3c_rtc_setname("s3c2443-rtc"); + +	/* change WDT IRQ number */ +	s3c_device_wdt.resource[1].start = IRQ_S3C2443_WDT; +	s3c_device_wdt.resource[1].end   = IRQ_S3C2443_WDT; + +	return device_register(&s3c2443_dev); +} + +void __init s3c2443_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ +	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); +} + +/* s3c2443_map_io + * + * register the standard cpu IO areas, and any passed in from the + * machine specific initialisation. + */ + +void __init s3c2443_map_io(void) +{ +	s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull; +	s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull; + +	/* initialize device information early */ +	s3c64xx_spi_setname("s3c2443-spi"); + +	iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc)); +} + +/* need to register the subsystem before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2443 based system) + * as a driver which may support both 2443 and 2440 may try and use it. +*/ + +static int __init s3c2443_core_init(void) +{ +	return subsys_system_register(&s3c2443_subsys, NULL); +} + +core_initcall(s3c2443_core_init); diff --git a/arch/arm/mach-s3c24xx/s3c244x.c b/arch/arm/mach-s3c24xx/s3c244x.c new file mode 100644 index 00000000000..4a64bcc9eb5 --- /dev/null +++ b/arch/arm/mach-s3c24xx/s3c244x.c @@ -0,0 +1,156 @@ +/* linux/arch/arm/plat-s3c24xx/s3c244x.c + * + * Copyright (c) 2004-2006 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443) + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <asm/system_misc.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <asm/irq.h> + +#include <plat/cpu-freq.h> + +#include <mach/regs-clock.h> +#include <mach/regs-gpio.h> + +#include <plat/clock.h> +#include <plat/devs.h> +#include <plat/cpu.h> +#include <plat/pm.h> +#include <plat/pll.h> +#include <plat/nand-core.h> +#include <plat/watchdog-reset.h> + +#include "common.h" +#include "regs-dsc.h" + +static struct map_desc s3c244x_iodesc[] __initdata = { +	IODESC_ENT(CLKPWR), +	IODESC_ENT(TIMER), +	IODESC_ENT(WATCHDOG), +}; + +/* uart initialisation */ + +void __init s3c244x_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ +	s3c24xx_init_uartdevs("s3c2440-uart", s3c2410_uart_resources, cfg, no); +} + +void __init s3c244x_map_io(void) +{ +	/* register our io-tables */ + +	iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc)); + +	/* rename any peripherals used differing from the s3c2410 */ + +	s3c_device_sdi.name  = "s3c2440-sdi"; +	s3c_device_i2c0.name  = "s3c2440-i2c"; +	s3c_nand_setname("s3c2440-nand"); +	s3c_device_ts.name = "s3c2440-ts"; +	s3c_device_usbgadget.name = "s3c2440-usbgadget"; +	s3c2410_device_dclk.name = "s3c2440-dclk"; +} + +void __init_or_cpufreq s3c244x_setup_clocks(void) +{ +} + +/* Since the S3C2442 and S3C2440 share items, put both subsystems here */ + +struct bus_type s3c2440_subsys = { +	.name		= "s3c2440-core", +	.dev_name	= "s3c2440-core", +}; + +struct bus_type s3c2442_subsys = { +	.name		= "s3c2442-core", +	.dev_name	= "s3c2442-core", +}; + +/* need to register the subsystem before we actually register the device, and + * we also need to ensure that it has been initialised before any of the + * drivers even try to use it (even if not on an s3c2440 based system) + * as a driver which may support both 2410 and 2440 may try and use it. +*/ + +static int __init s3c2440_core_init(void) +{ +	return subsys_system_register(&s3c2440_subsys, NULL); +} + +core_initcall(s3c2440_core_init); + +static int __init s3c2442_core_init(void) +{ +	return subsys_system_register(&s3c2442_subsys, NULL); +} + +core_initcall(s3c2442_core_init); + + +#ifdef CONFIG_PM +static struct sleep_save s3c244x_sleep[] = { +	SAVE_ITEM(S3C2440_DSC0), +	SAVE_ITEM(S3C2440_DSC1), +	SAVE_ITEM(S3C2440_GPJDAT), +	SAVE_ITEM(S3C2440_GPJCON), +	SAVE_ITEM(S3C2440_GPJUP) +}; + +static int s3c244x_suspend(void) +{ +	s3c_pm_do_save(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); +	return 0; +} + +static void s3c244x_resume(void) +{ +	s3c_pm_do_restore(s3c244x_sleep, ARRAY_SIZE(s3c244x_sleep)); +} +#else +#define s3c244x_suspend NULL +#define s3c244x_resume  NULL +#endif + +struct syscore_ops s3c244x_pm_syscore_ops = { +	.suspend	= s3c244x_suspend, +	.resume		= s3c244x_resume, +}; + +void s3c244x_restart(enum reboot_mode mode, const char *cmd) +{ +	if (mode == REBOOT_SOFT) +		soft_restart(0); + +	samsung_wdt_reset(); + +	/* we'll take a jump through zero as a poor second */ +	soft_restart(0); +} diff --git a/arch/arm/mach-s3c24xx/setup-i2c.c b/arch/arm/mach-s3c24xx/setup-i2c.c new file mode 100644 index 00000000000..1852696ca16 --- /dev/null +++ b/arch/arm/mach-s3c24xx/setup-i2c.c @@ -0,0 +1,28 @@ +/* linux/arch/arm/plat-s3c24xx/setup-i2c.c + * + * Copyright 2008 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX Base setup for i2c device + * + * 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/gpio.h> + +struct platform_device; + +#include <plat/gpio-cfg.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <mach/hardware.h> +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> + +void s3c_i2c0_cfg_gpio(struct platform_device *dev) +{ +	s3c_gpio_cfgpin(S3C2410_GPE(15), S3C2410_GPE15_IICSDA); +	s3c_gpio_cfgpin(S3C2410_GPE(14), S3C2410_GPE14_IICSCL); +} diff --git a/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c b/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c new file mode 100644 index 00000000000..c99b0f664db --- /dev/null +++ b/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c @@ -0,0 +1,35 @@ +/* linux/arch/arm/plat-s3c2416/setup-sdhci-gpio.c + * + * Copyright 2010 Promwad Innovation Company + *	Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com> + * + * S3C2416 - Helper functions for setting up SDHCI device(s) GPIO (HSMMC) + * + * Based on mach-s3c64xx/setup-sdhci-gpio.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/types.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <mach/regs-gpio.h> +#include <mach/gpio-samsung.h> +#include <plat/gpio-cfg.h> + +void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) +{ +	s3c_gpio_cfgrange_nopull(S3C2410_GPE(5), 2 + width, S3C_GPIO_SFN(2)); +} + +void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) +{ +	s3c_gpio_cfgrange_nopull(S3C2410_GPL(0), width, S3C_GPIO_SFN(2)); +	s3c_gpio_cfgrange_nopull(S3C2410_GPL(8), 2, S3C_GPIO_SFN(2)); +} diff --git a/arch/arm/mach-s3c24xx/setup-spi.c b/arch/arm/mach-s3c24xx/setup-spi.c new file mode 100644 index 00000000000..3d47e023ce9 --- /dev/null +++ b/arch/arm/mach-s3c24xx/setup-spi.c @@ -0,0 +1,31 @@ +/* + * HS-SPI device setup for S3C2443/S3C2416 + * + * Copyright (C) 2011 Samsung Electronics Ltd. + *		http://www.samsung.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/gpio.h> +#include <linux/platform_device.h> + +#include <plat/gpio-cfg.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> + +#ifdef CONFIG_S3C64XX_DEV_SPI0 +int s3c64xx_spi0_cfg_gpio(void) +{ +	/* enable hsspi bit in misccr */ +	s3c2410_modify_misccr(S3C2416_MISCCR_HSSPI_EN2, 1); + +	s3c_gpio_cfgall_range(S3C2410_GPE(11), 3, +			      S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); + +	return 0; +} +#endif diff --git a/arch/arm/mach-s3c24xx/setup-ts.c b/arch/arm/mach-s3c24xx/setup-ts.c new file mode 100644 index 00000000000..46466d20257 --- /dev/null +++ b/arch/arm/mach-s3c24xx/setup-ts.c @@ -0,0 +1,32 @@ +/* linux/arch/arm/plat-s3c24xx/setup-ts.c + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + *                     http://www.samsung.com/ + * + * Based on S3C24XX setup for i2c device + * + * 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/gpio.h> + +struct platform_device; /* don't need the contents */ + +#include <plat/gpio-cfg.h> +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> + +/** + * s3c24xx_ts_cfg_gpio - configure gpio for s3c2410 systems + * + * Configure the GPIO for the S3C2410 system, where we have external FETs + * connected to the device (later systems such as the S3C2440 integrate + * these into the device). + */ +void s3c24xx_ts_cfg_gpio(struct platform_device *dev) +{ +	s3c_gpio_cfgpin_range(S3C2410_GPG(12), 4, S3C_GPIO_SFN(3)); +} diff --git a/arch/arm/mach-s3c24xx/simtec-audio.c b/arch/arm/mach-s3c24xx/simtec-audio.c new file mode 100644 index 00000000000..67cb5120dfe --- /dev/null +++ b/arch/arm/mach-s3c24xx/simtec-audio.c @@ -0,0 +1,76 @@ +/* linux/arch/arm/plat-s3c24xx/simtec-audio.c + * + * Copyright (c) 2009 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * Audio setup for various Simtec S3C24XX implementations + * + * 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/interrupt.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/regs-gpio.h> + +#include <linux/platform_data/asoc-s3c24xx_simtec.h> +#include <plat/devs.h> + +#include "bast.h" +#include "simtec.h" + +/* platform ops for audio */ + +static void simtec_audio_startup_lrroute(void) +{ +	unsigned int tmp; +	unsigned long flags; + +	local_irq_save(flags); + +	tmp = __raw_readb(BAST_VA_CTRL1); +	tmp &= ~BAST_CPLD_CTRL1_LRMASK; +	tmp |= BAST_CPLD_CTRL1_LRCDAC; +	__raw_writeb(tmp, BAST_VA_CTRL1); + +	local_irq_restore(flags); +} + +static struct s3c24xx_audio_simtec_pdata simtec_audio_platdata; +static char our_name[32]; + +static struct platform_device simtec_audio_dev = { +	.name	= our_name, +	.id	= -1, +	.dev	= { +		.parent		= &s3c_device_iis.dev, +		.platform_data	= &simtec_audio_platdata, +	}, +}; + +int __init simtec_audio_add(const char *name, bool has_lr_routing, +			    struct s3c24xx_audio_simtec_pdata *spd) +{ +	if (!name) +		name = "tlv320aic23"; + +	snprintf(our_name, sizeof(our_name)-1, "s3c24xx-simtec-%s", name); + +	/* copy platform data so the source can be __initdata */ +	if (spd) +		simtec_audio_platdata = *spd; + +	if (has_lr_routing) +		simtec_audio_platdata.startup = simtec_audio_startup_lrroute; + +	platform_device_register(&s3c_device_iis); +	platform_device_register(&simtec_audio_dev); +	return 0; +} diff --git a/arch/arm/mach-s3c24xx/simtec-nor.c b/arch/arm/mach-s3c24xx/simtec-nor.c new file mode 100644 index 00000000000..8884bffa619 --- /dev/null +++ b/arch/arm/mach-s3c24xx/simtec-nor.c @@ -0,0 +1,79 @@ +/* linux/arch/arm/mach-s3c2410/nor-simtec.c + * + * Copyright (c) 2008 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * Simtec NOR mapping + * + * 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/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/map.h> + +#include "bast.h" +#include "simtec.h" + +static void simtec_nor_vpp(struct platform_device *pdev, int vpp) +{ +	unsigned int val; + +	val = __raw_readb(BAST_VA_CTRL3); + +	printk(KERN_DEBUG "%s(%d)\n", __func__, vpp); + +	if (vpp) +		val |= BAST_CPLD_CTRL3_ROMWEN; +	else +		val &= ~BAST_CPLD_CTRL3_ROMWEN; + +	__raw_writeb(val, BAST_VA_CTRL3); +} + +static struct physmap_flash_data simtec_nor_pdata = { +	.width		= 2, +	.set_vpp	= simtec_nor_vpp, +	.nr_parts	= 0, +}; + +static struct resource simtec_nor_resource[] = { +	[0] = DEFINE_RES_MEM(S3C2410_CS1 + 0x4000000, SZ_8M), +}; + +static struct platform_device simtec_device_nor = { +	.name		= "physmap-flash", +	.id		= -1, +	.num_resources	= ARRAY_SIZE(simtec_nor_resource), +	.resource	= simtec_nor_resource, +	.dev		= { +		.platform_data = &simtec_nor_pdata, +	}, +}; + +void __init nor_simtec_init(void) +{ +	int ret; + +	ret = platform_device_register(&simtec_device_nor); +	if (ret < 0) +		printk(KERN_ERR "failed to register physmap-flash device\n"); +	else +		simtec_nor_vpp(NULL, 1); +} diff --git a/arch/arm/mach-s3c24xx/simtec-pm.c b/arch/arm/mach-s3c24xx/simtec-pm.c new file mode 100644 index 00000000000..38a2f1fdeba --- /dev/null +++ b/arch/arm/mach-s3c24xx/simtec-pm.c @@ -0,0 +1,67 @@ +/* linux/arch/arm/plat-s3c24xx/pm-simtec.c + * + * Copyright 2004 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * http://armlinux.simtec.co.uk/ + * + * Power Management helpers for Simtec S3C24XX implementations + * + * 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/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/hardware.h> + +#include <mach/map.h> +#include <mach/regs-gpio.h> + +#include <asm/mach-types.h> + +#include <plat/pm.h> + +#include "regs-mem.h" + +#define COPYRIGHT ", Copyright 2005 Simtec Electronics" + +/* pm_simtec_init + * + * enable the power management functions +*/ + +static __init int pm_simtec_init(void) +{ +	unsigned long gstatus4; + +	/* check which machine we are running on */ + +	if (!machine_is_bast() && !machine_is_vr1000() && +	    !machine_is_anubis() && !machine_is_osiris() && +	    !machine_is_aml_m5900()) +		return 0; + +	printk(KERN_INFO "Simtec Board Power Management" COPYRIGHT "\n"); + +	gstatus4  = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30; +	gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28; +	gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK); + +	__raw_writel(gstatus4, S3C2410_GSTATUS4); + +	return s3c_pm_init(); +} + +arch_initcall(pm_simtec_init); diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c new file mode 100644 index 00000000000..b70aa66efeb --- /dev/null +++ b/arch/arm/mach-s3c24xx/simtec-usb.c @@ -0,0 +1,130 @@ +/* linux/arch/arm/mach-s3c2410/usb-simtec.c + * + * Copyright 2004-2005 Simtec Electronics + *   Ben Dooks <ben@simtec.co.uk> + * + * http://www.simtec.co.uk/products/EB2410ITX/ + * + * Simtec BAST and Thorcom VR1000 USB port support functions + * + * 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. +*/ + +#define DEBUG + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/gpio.h> +#include <linux/timer.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <mach/hardware.h> +#include <mach/gpio-samsung.h> +#include <asm/irq.h> + +#include <linux/platform_data/usb-ohci-s3c2410.h> +#include <plat/devs.h> + +#include "bast.h" +#include "simtec.h" + +/* control power and monitor over-current events on various Simtec + * designed boards. +*/ + +static unsigned int power_state[2]; + +static void +usb_simtec_powercontrol(int port, int to) +{ +	pr_debug("usb_simtec_powercontrol(%d,%d)\n", port, to); + +	power_state[port] = to; + +	if (power_state[0] && power_state[1]) +		gpio_set_value(S3C2410_GPB(4), 0); +	else +		gpio_set_value(S3C2410_GPB(4), 1); +} + +static irqreturn_t +usb_simtec_ocirq(int irq, void *pw) +{ +	struct s3c2410_hcd_info *info = pw; + +	if (gpio_get_value(S3C2410_GPG(10)) == 0) { +		pr_debug("usb_simtec: over-current irq (oc detected)\n"); +		s3c2410_usb_report_oc(info, 3); +	} else { +		pr_debug("usb_simtec: over-current irq (oc cleared)\n"); +		s3c2410_usb_report_oc(info, 0); +	} + +	return IRQ_HANDLED; +} + +static void usb_simtec_enableoc(struct s3c2410_hcd_info *info, int on) +{ +	int ret; + +	if (on) { +		ret = request_irq(BAST_IRQ_USBOC, usb_simtec_ocirq, +				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, +				  "USB Over-current", info); +		if (ret != 0) { +			printk(KERN_ERR "failed to request usb oc irq\n"); +		} +	} else { +		free_irq(BAST_IRQ_USBOC, info); +	} +} + +static struct s3c2410_hcd_info usb_simtec_info __initdata = { +	.port[0]	= { +		.flags	= S3C_HCDFLG_USED +	}, +	.port[1]	= { +		.flags	= S3C_HCDFLG_USED +	}, + +	.power_control	= usb_simtec_powercontrol, +	.enable_oc	= usb_simtec_enableoc, +}; + + +int __init usb_simtec_init(void) +{ +	int ret; + +	printk("USB Power Control, Copyright 2004 Simtec Electronics\n"); + +	ret = gpio_request(S3C2410_GPB(4), "USB power control"); +	if (ret < 0) { +		pr_err("%s: failed to get GPB4\n", __func__); +		return ret; +	} + +	ret = gpio_request(S3C2410_GPG(10), "USB overcurrent"); +	if (ret < 0) { +		pr_err("%s: failed to get GPG10\n", __func__); +		gpio_free(S3C2410_GPB(4)); +		return ret; +	} + +	/* turn power on */ +	gpio_direction_output(S3C2410_GPB(4), 1); +	gpio_direction_input(S3C2410_GPG(10)); + +	s3c_ohci_set_platdata(&usb_simtec_info); +	return 0; +} diff --git a/arch/arm/mach-s3c24xx/simtec.h b/arch/arm/mach-s3c24xx/simtec.h new file mode 100644 index 00000000000..ae8f4f9ad2e --- /dev/null +++ b/arch/arm/mach-s3c24xx/simtec.h @@ -0,0 +1,21 @@ +/* linux/arch/arm/mach-s3c2410/nor-simtec.h + * + * Copyright (c) 2008 Simtec Electronics + *	http://armlinux.simtec.co.uk/ + *	Ben Dooks <ben@simtec.co.uk> + * + * Simtec common functions + * + * 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. +*/ + +struct s3c24xx_audio_simtec_pdata; + +extern void nor_simtec_init(void); + +extern int usb_simtec_init(void); + +extern int simtec_audio_add(const char *codec_name, bool has_lr_routing, +			    struct s3c24xx_audio_simtec_pdata *pdata); diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2410.S b/arch/arm/mach-s3c24xx/sleep-s3c2410.S new file mode 100644 index 00000000000..c9b91223697 --- /dev/null +++ b/arch/arm/mach-s3c24xx/sleep-s3c2410.S @@ -0,0 +1,69 @@ +/* linux/arch/arm/mach-s3c2410/sleep.S + * + * Copyright (c) 2004 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 Power Manager (Suspend-To-RAM) support + * + * Based on PXA/SA1100 sleep code by: + *	Nicolas Pitre, (c) 2002 Monta Vista Software Inc + *	Cliff Brake, (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/linkage.h> +#include <linux/serial_s3c.h> +#include <asm/assembler.h> +#include <mach/hardware.h> +#include <mach/map.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-clock.h> + +#include "regs-mem.h" + +	/* s3c2410_cpu_suspend +	 * +	 * put the cpu into sleep mode +	*/ + +ENTRY(s3c2410_cpu_suspend) +	@@ prepare cpu to sleep + +	ldr	r4, =S3C2410_REFRESH +	ldr	r5, =S3C24XX_MISCCR +	ldr	r6, =S3C2410_CLKCON +	ldr	r7, [r4]		@ get REFRESH (and ensure in TLB) +	ldr	r8, [r5]		@ get MISCCR (and ensure in TLB) +	ldr	r9, [r6]		@ get CLKCON (and ensure in TLB) + +	orr	r7, r7, #S3C2410_REFRESH_SELF	@ SDRAM sleep command +	orr	r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals +	orr	r9, r9, #S3C2410_CLKCON_POWER	@ power down command + +	teq	pc, #0			@ first as a trial-run to load cache +	bl	s3c2410_do_sleep +	teq	r0, r0			@ now do it for real +	b	s3c2410_do_sleep	@ + +	@@ align next bit of code to cache line +	.align	5 +s3c2410_do_sleep: +	streq	r7, [r4]			@ SDRAM sleep command +	streq	r8, [r5]			@ SDRAM power-down config +	streq	r9, [r6]			@ CPU sleep +1:	beq	1b +	mov	pc, r14 diff --git a/arch/arm/mach-s3c24xx/sleep-s3c2412.S b/arch/arm/mach-s3c24xx/sleep-s3c2412.S new file mode 100644 index 00000000000..5adaceb7da1 --- /dev/null +++ b/arch/arm/mach-s3c24xx/sleep-s3c2412.S @@ -0,0 +1,68 @@ +/* linux/arch/arm/mach-s3c2412/sleep.S + * + * Copyright (c) 2007 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2412 Power Manager low-level sleep support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <mach/hardware.h> +#include <mach/map.h> + +#include <mach/regs-irq.h> + +	.text + +	.global	s3c2412_sleep_enter + +s3c2412_sleep_enter: +	mov	r0, #0			/* argument for coprocessors */ +	ldr	r1, =S3C2410_INTPND +	ldr	r2, =S3C2410_SRCPND +	ldr	r3, =S3C2410_EINTPEND + +	teq	r0, r0 +	bl	s3c2412_sleep_enter1 +	teq	pc, r0 +	bl	s3c2412_sleep_enter1 + +	.align	5 + +	/* this is called twice, first with the Z flag to ensure that the +	 * instructions have been loaded into the cache, and the second +	 * time to try and suspend the system. +	*/ +s3c2412_sleep_enter1: +	mcr	p15, 0, r0, c7, c10, 4 +	mcrne	p15, 0, r0, c7, c0, 4 + +	/* if we return from here, it is because an interrupt was +	 * active when we tried to shutdown. Try and ack the IRQ and +	 * retry, as simply returning causes the system to lock. +	*/ + +	ldrne	r9, [r1] +	strne	r9, [r1] +	ldrne	r9, [r2] +	strne	r9, [r2] +	ldrne	r9, [r3] +	strne	r9, [r3] +	bne	s3c2412_sleep_enter1 + +	mov	pc, r14 diff --git a/arch/arm/mach-s3c24xx/sleep.S b/arch/arm/mach-s3c24xx/sleep.S new file mode 100644 index 00000000000..d833d616bd2 --- /dev/null +++ b/arch/arm/mach-s3c24xx/sleep.S @@ -0,0 +1,83 @@ +/* linux/arch/arm/plat-s3c24xx/sleep.S + * + * Copyright (c) 2004 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 Power Manager (Suspend-To-RAM) support + * + * Based on PXA/SA1100 sleep code by: + *	Nicolas Pitre, (c) 2002 Monta Vista Software Inc + *	Cliff Brake, (c) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA +*/ + +#include <linux/linkage.h> +#include <linux/serial_s3c.h> +#include <asm/assembler.h> +#include <mach/hardware.h> +#include <mach/map.h> + +#include <mach/regs-gpio.h> +#include <mach/regs-clock.h> + +/* CONFIG_DEBUG_RESUME is dangerous if your bootloader does not + * reset the UART configuration, only enable if you really need this! +*/ +//#define CONFIG_DEBUG_RESUME + +	.text + +	/* sleep magic, to allow the bootloader to check for an valid +	 * image to resume to. Must be the first word before the +	 * s3c_cpu_resume entry. +	*/ + +	.word	0x2bedf00d + +	/* s3c_cpu_resume +	 * +	 * resume code entry for bootloader to call +	*/ + +ENTRY(s3c_cpu_resume) +	mov	r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE +	msr	cpsr_c, r0 + +	@@ load UART to allow us to print the two characters for +	@@ resume debug + +	mov	r2, #S3C24XX_PA_UART & 0xff000000 +	orr	r2, r2, #S3C24XX_PA_UART & 0xff000 + +#if 0 +	/* SMDK2440 LED set */ +	mov	r14, #S3C24XX_PA_GPIO +	ldr	r12, [ r14, #0x54 ] +	bic	r12, r12, #3<<4 +	orr	r12, r12, #1<<7 +	str	r12, [ r14, #0x54 ] +#endif + +#ifdef CONFIG_DEBUG_RESUME +	mov	r3, #'L' +	strb	r3, [ r2, #S3C2410_UTXH ] +1001: +	ldrb	r14, [ r3, #S3C2410_UTRSTAT ] +	tst	r14, #S3C2410_UTRSTAT_TXE +	beq	1001b +#endif /* CONFIG_DEBUG_RESUME */ + +	b	cpu_resume diff --git a/arch/arm/mach-s3c24xx/vr1000.h b/arch/arm/mach-s3c24xx/vr1000.h new file mode 100644 index 00000000000..7fcd2c2f183 --- /dev/null +++ b/arch/arm/mach-s3c24xx/vr1000.h @@ -0,0 +1,118 @@ + +/* arch/arm/mach-s3c2410/include/mach/vr1000-cpld.h + * + * Copyright (c) 2003 Simtec Electronics + *	Ben Dooks <ben@simtec.co.uk> + * + * VR1000 - CPLD control constants + * Machine VR1000 - IRQ Number definitions + * Machine VR1000 - Memory map definitions + * + * 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 __MACH_S3C24XX_VR1000_H +#define __MACH_S3C24XX_VR1000_H __FILE__ + +#define VR1000_CPLD_CTRL2_RAMWEN	(0x04)	/* SRAM Write Enable */ + +/* irq numbers to onboard peripherals */ + +#define VR1000_IRQ_USBOC		IRQ_EINT19 +#define VR1000_IRQ_IDE0			IRQ_EINT16 +#define VR1000_IRQ_IDE1			IRQ_EINT17 +#define VR1000_IRQ_SERIAL		IRQ_EINT12 +#define VR1000_IRQ_DM9000A		IRQ_EINT10 +#define VR1000_IRQ_DM9000N		IRQ_EINT9 +#define VR1000_IRQ_SMALERT		IRQ_EINT8 + +/* map */ + +#define VR1000_IOADDR(x)		(S3C2410_ADDR((x) + 0x01300000)) + +/* we put the CPLD registers next, to get them out of the way */ + +#define VR1000_VA_CTRL1			VR1000_IOADDR(0x00000000) /* 0x01300000 */ +#define VR1000_PA_CTRL1			(S3C2410_CS5 | 0x7800000) + +#define VR1000_VA_CTRL2			VR1000_IOADDR(0x00100000) /* 0x01400000 */ +#define VR1000_PA_CTRL2			(S3C2410_CS1 | 0x6000000) + +#define VR1000_VA_CTRL3			VR1000_IOADDR(0x00200000) /* 0x01500000 */ +#define VR1000_PA_CTRL3			(S3C2410_CS1 | 0x6800000) + +#define VR1000_VA_CTRL4			VR1000_IOADDR(0x00300000) /* 0x01600000 */ +#define VR1000_PA_CTRL4			(S3C2410_CS1 | 0x7000000) + +/* next, we have the PC104 ISA interrupt registers */ + +#define VR1000_PA_PC104_IRQREQ		(S3C2410_CS5 | 0x6000000) /* 0x01700000 */ +#define VR1000_VA_PC104_IRQREQ		VR1000_IOADDR(0x00400000) + +#define VR1000_PA_PC104_IRQRAW		(S3C2410_CS5 | 0x6800000) /* 0x01800000 */ +#define VR1000_VA_PC104_IRQRAW		VR1000_IOADDR(0x00500000) + +#define VR1000_PA_PC104_IRQMASK		(S3C2410_CS5 | 0x7000000) /* 0x01900000 */ +#define VR1000_VA_PC104_IRQMASK		VR1000_IOADDR(0x00600000) + +/* + * 0xE0000000 contains the IO space that is split by speed and + * whether the access is for 8 or 16bit IO... this ensures that + * the correct access is made + * + * 0x10000000 of space, partitioned as so: + * + * 0x00000000 to 0x04000000  8bit,  slow + * 0x04000000 to 0x08000000  16bit, slow + * 0x08000000 to 0x0C000000  16bit, net + * 0x0C000000 to 0x10000000  16bit, fast + * + * each of these spaces has the following in: + * + * 0x02000000 to 0x02100000 1MB  IDE primary channel + * 0x02100000 to 0x02200000 1MB  IDE primary channel aux + * 0x02200000 to 0x02400000 1MB  IDE secondary channel + * 0x02300000 to 0x02400000 1MB  IDE secondary channel aux + * 0x02500000 to 0x02600000 1MB  Davicom DM9000 ethernet controllers + * 0x02600000 to 0x02700000 1MB + * + * the phyiscal layout of the zones are: + *  nGCS2 - 8bit, slow + *  nGCS3 - 16bit, slow + *  nGCS4 - 16bit, net + *  nGCS5 - 16bit, fast + */ + +#define VR1000_VA_MULTISPACE	(0xE0000000) + +#define VR1000_VA_ISAIO		(VR1000_VA_MULTISPACE + 0x00000000) +#define VR1000_VA_ISAMEM	(VR1000_VA_MULTISPACE + 0x01000000) +#define VR1000_VA_IDEPRI	(VR1000_VA_MULTISPACE + 0x02000000) +#define VR1000_VA_IDEPRIAUX	(VR1000_VA_MULTISPACE + 0x02100000) +#define VR1000_VA_IDESEC	(VR1000_VA_MULTISPACE + 0x02200000) +#define VR1000_VA_IDESECAUX	(VR1000_VA_MULTISPACE + 0x02300000) +#define VR1000_VA_ASIXNET	(VR1000_VA_MULTISPACE + 0x02400000) +#define VR1000_VA_DM9000	(VR1000_VA_MULTISPACE + 0x02500000) +#define VR1000_VA_SUPERIO	(VR1000_VA_MULTISPACE + 0x02600000) + +/* physical offset addresses for the peripherals */ + +#define VR1000_PA_IDEPRI	(0x02000000) +#define VR1000_PA_IDEPRIAUX	(0x02800000) +#define VR1000_PA_IDESEC	(0x03000000) +#define VR1000_PA_IDESECAUX	(0x03800000) +#define VR1000_PA_DM9000	(0x05000000) + +#define VR1000_PA_SERIAL	(0x11800000) +#define VR1000_VA_SERIAL	(VR1000_IOADDR(0x00700000)) + +/* VR1000 ram is in CS1, with A26..A24 = 2_101 */ +#define VR1000_PA_SRAM		(S3C2410_CS1 | 0x05000000) + +/* some configurations for the peripherals */ + +#define VR1000_DM9000_CS	VR1000_VAM_CS4 + +#endif /* __MACH_S3C24XX_VR1000_H */  | 
