diff options
Diffstat (limited to 'arch/arm/mach-s3c')
189 files changed, 32049 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c/Kconfig b/arch/arm/mach-s3c/Kconfig new file mode 100644 index 000000000..a64143574 --- /dev/null +++ b/arch/arm/mach-s3c/Kconfig @@ -0,0 +1,230 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2009 Simtec Electronics + +source "arch/arm/mach-s3c/Kconfig.s3c24xx" +source "arch/arm/mach-s3c/Kconfig.s3c64xx" + +config PLAT_SAMSUNG + bool + depends on PLAT_S3C24XX || ARCH_S3C64XX + default y + select GENERIC_IRQ_CHIP + select NO_IOPORT_MAP + select SOC_SAMSUNG + help + Base platform code for all Samsung SoC based systems + +config SAMSUNG_PM + bool + depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX) + default y + help + Base platform power management code for samsung code + +if PLAT_SAMSUNG +menu "Samsung Common options" + +# boot configurations + +comment "Boot options" + +config S3C_LOWLEVEL_UART_PORT + int "S3C UART to use for low-level messages" + depends on ARCH_S3C64XX + default 0 + help + Choice of which UART port to use for the low-level messages, + such as the `Uncompressing...` at start time. The value of + this configuration should be between zero and two. The port + must have been initialised by the boot-loader before use. + +config SAMSUNG_ATAGS + def_bool n + depends on ATAGS + help + This option enables ATAGS based boot support code for + Samsung platforms, including static platform devices, legacy + clock, timer and interrupt initialization, etc. + + Platforms that support only DT based boot need not to select + this option. + +if SAMSUNG_ATAGS + +config S3C_GPIO_SPACE + int "Space between gpio banks" + default 0 + help + Add a number of spare GPIO entries between each bank for debugging + purposes. This allows any problems where an counter overflows from + one bank to another to be caught, at the expense of using a little + more memory. + +config S3C_GPIO_TRACK + bool + help + Internal configuration option to enable the s3c specific gpio + chip tracking if the platform requires it. + +# ADC driver + +config S3C_ADC + bool "ADC common driver support" + depends on !ARCH_MULTIPLATFORM + help + Core support for the ADC block found in the Samsung SoC systems + for drivers such as the touchscreen and hwmon to use to share + this resource. + +# device definitions to compile in + +config S3C_DEV_HSMMC + bool + help + Compile in platform device definitions for HSMMC code + +config S3C_DEV_HSMMC1 + bool + help + Compile in platform device definitions for HSMMC channel 1 + +config S3C_DEV_HSMMC2 + bool + help + Compile in platform device definitions for HSMMC channel 2 + +config S3C_DEV_HSMMC3 + bool + help + Compile in platform device definitions for HSMMC channel 3 + +config S3C_DEV_HWMON + bool + help + Compile in platform device definitions for HWMON + +config S3C_DEV_I2C1 + bool + help + Compile in platform device definitions for I2C channel 1 + +config S3C_DEV_I2C2 + bool + help + Compile in platform device definitions for I2C channel 2 + +config S3C_DEV_I2C3 + bool + help + Compile in platform device definition for I2C controller 3 + +config S3C_DEV_I2C4 + bool + help + Compile in platform device definition for I2C controller 4 + +config S3C_DEV_I2C5 + bool + help + Compile in platform device definition for I2C controller 5 + +config S3C_DEV_I2C6 + bool + help + Compile in platform device definition for I2C controller 6 + +config S3C_DEV_I2C7 + bool + help + Compile in platform device definition for I2C controller 7 + +config S3C_DEV_FB + bool + help + Compile in platform device definition for framebuffer + +config S3C_DEV_USB_HOST + bool + help + Compile in platform device definition for USB host. + +config S3C_DEV_USB_HSOTG + bool + help + Compile in platform device definition for USB high-speed OtG + +config S3C_DEV_WDT + bool + default y if ARCH_S3C24XX + help + Compile in platform device definition for Watchdog Timer + +config S3C_DEV_NAND + bool + help + Compile in platform device definition for NAND controller + +config S3C_DEV_ONENAND + bool + help + Compile in platform device definition for OneNAND controller + +config S3C_DEV_RTC + bool + help + Compile in platform device definition for RTC + +config SAMSUNG_DEV_ADC + bool + help + Compile in platform device definition for ADC controller + +config SAMSUNG_DEV_IDE + bool + help + Compile in platform device definitions for IDE + +config S3C64XX_DEV_SPI0 + bool + help + Compile in platform device definitions for S3C64XX's type + SPI controller 0 + +config SAMSUNG_DEV_TS + bool + help + Common in platform device definitions for touchscreen device + +config SAMSUNG_DEV_KEYPAD + bool + help + Compile in platform device definitions for keypad + +config SAMSUNG_DEV_PWM + bool + default y if ARCH_S3C24XX + help + Compile in platform device definition for PWM Timer + +config GPIO_SAMSUNG + def_bool y + +config SAMSUNG_PM_GPIO + bool + default y if GPIO_SAMSUNG && PM + help + Include legacy GPIO power management code for platforms not using + pinctrl-samsung driver. +endif + +config SAMSUNG_WAKEMASK + bool + depends on PM + help + Compile support for wakeup-mask controls found on the S3C6400 + and above. This code allows a set of interrupt to wakeup-mask + mappings. See <plat/wakeup-mask.h> + +endmenu +endif diff --git a/arch/arm/mach-s3c/Kconfig.s3c24xx b/arch/arm/mach-s3c/Kconfig.s3c24xx new file mode 100644 index 000000000..7287e173f --- /dev/null +++ b/arch/arm/mach-s3c/Kconfig.s3c24xx @@ -0,0 +1,604 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2012 Samsung Electronics Co., Ltd. +# http://www.samsung.com/ +# +# Copyright 2007 Simtec Electronics +menuconfig ARCH_S3C24XX + bool "Samsung S3C24XX SoCs (deprecated, see help)" + depends on ARCH_MULTI_V4T || ARCH_MULTI_V5 + depends on CPU_LITTLE_ENDIAN + depends on ATAGS && UNUSED_BOARD_FILES + select CLKSRC_SAMSUNG_PWM + select GPIO_SAMSUNG + select GPIOLIB + select S3C2410_WATCHDOG + select SAMSUNG_ATAGS + select WATCHDOG + help + Samsung S3C2410, S3C2412, S3C2413, S3C2416, S3C2440, S3C2442, S3C2443 + and S3C2450 SoCs based systems, such as the Simtec Electronics BAST + (<http://www.simtec.co.uk/products/EB110ITX/>), the IPAQ 1940 or the + Samsung SMDK2410 development board (and derivatives). + + The platform is deprecated and scheduled for removal. Please reach to + the maintainers of the platform and linux-samsung-soc@vger.kernel.org if + you still use it. + Without such feedback, the platform will be removed after 2022. + +if ARCH_S3C24XX + +config PLAT_S3C24XX + def_bool y + select GPIOLIB + select NO_IOPORT_MAP + select S3C_DEV_NAND + select COMMON_CLK + help + Base platform code for any Samsung S3C24XX device + +menu "Samsung S3C24XX SoCs Support" + +comment "S3C24XX SoCs" + +config CPU_S3C2410 + bool "Samsung S3C2410" + depends on ARCH_MULTI_V4T + default y + select CPU_ARM920T + select S3C2410_COMMON_CLK + select ARM_S3C2410_CPUFREQ if ARM_S3C24XX_CPUFREQ + select S3C2410_PM if PM + help + Support for S3C2410 and S3C2410A family from the S3C24XX line + of Samsung Mobile CPUs. + +config CPU_S3C2412 + bool "Samsung S3C2412" + depends on ARCH_MULTI_V5 + select CPU_ARM926T + select S3C2412_COMMON_CLK + select S3C2412_PM if PM_SLEEP + help + Support for the S3C2412 and S3C2413 SoCs from the S3C24XX line + +config CPU_S3C2416 + bool "Samsung S3C2416/S3C2450" + depends on ARCH_MULTI_V5 + select CPU_ARM926T + select S3C2416_PM if PM_SLEEP + select S3C2443_COMMON_CLK + help + Support for the S3C2416 SoC from the S3C24XX line + +config CPU_S3C2440 + bool "Samsung S3C2440" + depends on ARCH_MULTI_V4T + select CPU_ARM920T + select S3C2410_COMMON_CLK + select S3C2410_PM if PM_SLEEP + help + Support for S3C2440 Samsung Mobile CPU based systems. + +config CPU_S3C2442 + bool "Samsung S3C2442" + depends on ARCH_MULTI_V4T + select CPU_ARM920T + select S3C2410_COMMON_CLK + select S3C2410_PM if PM_SLEEP + help + Support for S3C2442 Samsung Mobile CPU based systems. + +config CPU_S3C244X + def_bool y + depends on CPU_S3C2440 || CPU_S3C2442 + +config CPU_S3C2443 + bool "Samsung S3C2443" + depends on ARCH_MULTI_V4T + select CPU_ARM920T + select S3C2443_COMMON_CLK + 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 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. + +# 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 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 + depends on RFKILL + help + This is a simple driver that is able to control + the state of built in bluetooth chip on h1940. + +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 + <https://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_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 + select SAMSUNG_WAKEMASK + 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 TIMER_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 || CPU_S3C2442 + +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. +endif # CPU_S3C2440 || CPU_S3C2442 + +if CPU_S3C2440 + +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 LEDS_CLASS + select LEDS_TRIGGERS + select LEDS_TRIGGER_BACKLIGHT + select NEW_LEDS + select S3C_DEV_NAND + select S3C_DEV_USB_HOST + 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 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 S3C_DEV_NAND + help + Say Y here if you're using HP iPAQ rx1950 + +endif # CPU_S3C2442 + +if CPU_S3C2443 || CPU_S3C2416 + +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 + +config PM_H1940 + bool + help + Internal node for H1940 and related PM + +endmenu # "Samsung S3C24XX SoCs Support" + +endif # ARCH_S3C24XX diff --git a/arch/arm/mach-s3c/Kconfig.s3c64xx b/arch/arm/mach-s3c/Kconfig.s3c64xx new file mode 100644 index 000000000..0c1b91c3a --- /dev/null +++ b/arch/arm/mach-s3c/Kconfig.s3c64xx @@ -0,0 +1,354 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2008 Openmoko, Inc. +# Simtec Electronics, Ben Dooks <ben@simtec.co.uk> + +menuconfig ARCH_S3C64XX + bool "Samsung S3C64XX (deprecated, see help)" + depends on ARCH_MULTI_V6 + select ARM_AMBA + select ARM_VIC + select CLKSRC_SAMSUNG_PWM + select COMMON_CLK_SAMSUNG + select GPIO_SAMSUNG if ATAGS + select GPIOLIB + select HAVE_TCM + select PLAT_SAMSUNG + select PM_GENERIC_DOMAINS if PM + select S3C_DEV_NAND if ATAGS + select S3C_GPIO_TRACK if ATAGS + select S3C2410_WATCHDOG + select SAMSUNG_ATAGS if ATAGS + select SAMSUNG_WAKEMASK if PM + select WATCHDOG + help + Samsung S3C64XX series based systems + + The platform is deprecated and scheduled for removal. Please reach to + the maintainers of the platform and linux-samsung-soc@vger.kernel.org if + you still use it. + Without such feedback, the platform will be removed after 2024. + +if ARCH_S3C64XX + +# Configuration options for the S3C6410 CPU + +config CPU_S3C6400 + bool + help + Enable S3C6400 CPU support + +config CPU_S3C6410 + bool + help + Enable S3C6410 CPU support + +config S3C64XX_PL080 + def_bool DMADEVICES + select AMBA_PL08X + +config S3C64XX_SETUP_SDHCI + bool + select S3C64XX_SETUP_SDHCI_GPIO + help + Internal configuration for default SDHCI setup for S3C6400 and + S3C6410 SoCs. + +config S3C64XX_DEV_ONENAND1 + bool + help + Compile in platform device definition for OneNAND1 controller + +config SAMSUNG_DEV_BACKLIGHT + bool + depends on SAMSUNG_DEV_PWM + help + Compile in platform device definition LCD backlight with PWM Timer + +# platform specific device setup + +config S3C64XX_SETUP_I2C0 + bool + default y + help + Common setup code for i2c bus 0. + + Note, currently since i2c0 is always compiled, this setup helper + is always compiled with it. + +config S3C64XX_SETUP_I2C1 + bool + help + Common setup code for i2c bus 1. + +config S3C64XX_SETUP_IDE + bool + help + Common setup code for S3C64XX IDE. + +config S3C64XX_SETUP_FB_24BPP + bool + help + Common setup code for S3C64XX with an 24bpp RGB display helper. + +config S3C64XX_SETUP_KEYPAD + bool + help + Common setup code for S3C64XX KEYPAD GPIO configurations + +config S3C64XX_SETUP_SDHCI_GPIO + bool + help + Common setup code for S3C64XX SDHCI GPIO configurations + +config S3C64XX_SETUP_SPI + bool + help + Common setup code for SPI GPIO configurations + +config S3C64XX_SETUP_USB_PHY + bool + help + Common setup code for USB PHY controller + +# S36400 Macchine support + +config MACH_SMDK6400 + bool "SMDK6400" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6400 + select S3C64XX_SETUP_SDHCI + select S3C_DEV_HSMMC1 + help + Machine support for the Samsung SMDK6400 + +# S3C6410 machine support + +config MACH_ANW6410 + bool "A&W6410" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6410 + select S3C64XX_SETUP_FB_24BPP + select S3C_DEV_FB + help + Machine support for the A&W6410 + +config MACH_MINI6410 + bool "MINI6410" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6410 + select S3C64XX_SETUP_FB_24BPP + select S3C64XX_SETUP_SDHCI + select S3C_DEV_FB + select S3C_DEV_HSMMC + select S3C_DEV_HSMMC1 + select S3C_DEV_NAND + select S3C_DEV_USB_HOST + select SAMSUNG_DEV_ADC + select SAMSUNG_DEV_TS + help + Machine support for the FriendlyARM MINI6410 + +config MACH_REAL6410 + bool "REAL6410" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6410 + select S3C64XX_SETUP_FB_24BPP + select S3C64XX_SETUP_SDHCI + select S3C_DEV_FB + select S3C_DEV_HSMMC + select S3C_DEV_HSMMC1 + select S3C_DEV_NAND + select S3C_DEV_USB_HOST + select SAMSUNG_DEV_ADC + select SAMSUNG_DEV_TS + help + Machine support for the CoreWind REAL6410 + +config MACH_SMDK6410 + bool "SMDK6410" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6410 + select S3C64XX_SETUP_FB_24BPP + select S3C64XX_SETUP_I2C1 + select S3C64XX_SETUP_IDE + select S3C64XX_SETUP_KEYPAD + select S3C64XX_SETUP_SDHCI + select S3C64XX_SETUP_USB_PHY + select S3C_DEV_FB + select S3C_DEV_HSMMC + select S3C_DEV_HSMMC1 + select S3C_DEV_I2C1 + select S3C_DEV_RTC + select S3C_DEV_USB_HOST + select S3C_DEV_USB_HSOTG + select S3C_DEV_WDT + select SAMSUNG_DEV_ADC + select SAMSUNG_DEV_BACKLIGHT + select SAMSUNG_DEV_IDE + select SAMSUNG_DEV_KEYPAD + select SAMSUNG_DEV_PWM + select SAMSUNG_DEV_TS + help + Machine support for the Samsung SMDK6410 + +# At least some of the SMDK6410s were shipped with the card detect +# for the MMC/SD slots connected to the same input. This means that +# either the boards need to be altered to have channel0 to an alternate +# configuration or that only one slot can be used. + +choice + prompt "SMDK6410 MMC/SD slot setup" + depends on MACH_SMDK6410 + +config SMDK6410_SD_CH0 + bool "Use channel 0 only" + depends on MACH_SMDK6410 + help + Select CON7 (channel 0) as the MMC/SD slot, as + at least some SMDK6410 boards come with the + resistors fitted so that the card detects for + channels 0 and 1 are the same. + +config SMDK6410_SD_CH1 + bool "Use channel 1 only" + depends on MACH_SMDK6410 + help + Select CON6 (channel 1) as the MMC/SD slot, as + at least some SMDK6410 boards come with the + resistors fitted so that the card detects for + channels 0 and 1 are the same. + +endchoice + +config SMDK6410_WM1190_EV1 + bool "Support Wolfson Microelectronics 1190-EV1 PMIC card" + depends on MACH_SMDK6410 + depends on I2C=y + select MFD_WM8350_I2C + select REGULATOR + select REGULATOR_WM8350 + help + The Wolfson Microelectronics 1190-EV1 is a WM835x based PMIC + and audio daughtercard for the Samsung SMDK6410 reference + platform. Enabling this option will build support for this + module into the kernel. The presence of the module will be + detected at runtime so the resulting kernel can be used + with or without the 1190-EV1 fitted. + +config SMDK6410_WM1192_EV1 + bool "Support Wolfson Microelectronics 1192-EV1 PMIC card" + depends on MACH_SMDK6410 + depends on I2C=y + select MFD_WM831X + select MFD_WM831X_I2C + select REGULATOR + select REGULATOR_WM831X + help + The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC + daughtercard for the Samsung SMDK6410 reference platform. + Enabling this option will build support for this module into + the kernel. The presence of the daughtercard will be + detected at runtime so the resulting kernel can be used + with or without the 1192-EV1 fitted. + +config MACH_NCP + bool "NCP" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6410 + select S3C64XX_SETUP_I2C1 + select S3C_DEV_HSMMC1 + select S3C_DEV_I2C1 + help + Machine support for the Samsung NCP + +config MACH_HMT + bool "Airgoo HMT" + depends on ATAGS && UNUSED_BOARD_FILES + select CPU_S3C6410 + select S3C64XX_SETUP_FB_24BPP + select S3C_DEV_FB + select S3C_DEV_NAND + select S3C_DEV_USB_HOST + select SAMSUNG_DEV_PWM + help + Machine support for the Airgoo HMT + +config MACH_SMARTQ + bool + select CPU_S3C6410 + select S3C64XX_SETUP_FB_24BPP + select S3C64XX_SETUP_SDHCI + select S3C64XX_SETUP_USB_PHY + select S3C_DEV_FB + select S3C_DEV_HSMMC + select S3C_DEV_HSMMC1 + select S3C_DEV_HSMMC2 + select S3C_DEV_HWMON + select S3C_DEV_RTC + select S3C_DEV_USB_HOST + select S3C_DEV_USB_HSOTG + select SAMSUNG_DEV_ADC + select SAMSUNG_DEV_PWM + select SAMSUNG_DEV_TS + help + Shared machine support for SmartQ 5/7 + +config MACH_SMARTQ5 + bool "SmartQ 5" + depends on ATAGS && UNUSED_BOARD_FILES + select MACH_SMARTQ + help + Machine support for the SmartQ 5 + +config MACH_SMARTQ7 + bool "SmartQ 7" + depends on ATAGS && UNUSED_BOARD_FILES + select MACH_SMARTQ + help + Machine support for the SmartQ 7 + +config MACH_WLF_CRAGG_6410 + bool "Wolfson Cragganmore 6410" + depends on ATAGS + depends on I2C=y + select CPU_S3C6410 + select LEDS_GPIO_REGISTER + select S3C64XX_DEV_SPI0 + select S3C64XX_SETUP_FB_24BPP + select S3C64XX_SETUP_I2C1 + select S3C64XX_SETUP_IDE + select S3C64XX_SETUP_KEYPAD + select S3C64XX_SETUP_SDHCI + select S3C64XX_SETUP_SPI + select S3C64XX_SETUP_USB_PHY + select S3C_DEV_FB + select S3C_DEV_HSMMC + select S3C_DEV_HSMMC1 + select S3C_DEV_HSMMC2 + select S3C_DEV_I2C1 + select S3C_DEV_RTC + select S3C_DEV_USB_HOST + select S3C_DEV_USB_HSOTG + select S3C_DEV_WDT + select SAMSUNG_DEV_ADC + select SAMSUNG_DEV_KEYPAD + select SAMSUNG_DEV_PWM + help + Machine support for the Wolfson Cragganmore S3C6410 variant. + +config MACH_S3C64XX_DT + bool "Samsung S3C6400/S3C6410 machine using Device Tree" + select CPU_S3C6400 + select CPU_S3C6410 + select PINCTRL + select PINCTRL_S3C64XX + help + Machine support for Samsung S3C6400/S3C6410 machines with Device Tree + enabled. + Select this if a fdt blob is available for your S3C64XX SoC based + board. + Note: This is under development and not all peripherals can be + supported with this machine file. + +endif diff --git a/arch/arm/mach-s3c/Makefile b/arch/arm/mach-s3c/Makefile new file mode 100644 index 000000000..7c7d3318f --- /dev/null +++ b/arch/arm/mach-s3c/Makefile @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2009 Simtec Electronics + +ifdef CONFIG_ARCH_S3C24XX +include $(src)/Makefile.s3c24xx +endif + +ifdef CONFIG_ARCH_S3C64XX +include $(src)/Makefile.s3c64xx +endif + +# Objects we always build independent of SoC choice + +obj-y += init.o cpu.o + +# ADC + +obj-$(CONFIG_S3C_ADC) += adc.o + +# devices + +obj-$(CONFIG_SAMSUNG_ATAGS) += platformdata.o + +obj-$(CONFIG_SAMSUNG_ATAGS) += devs.o +obj-$(CONFIG_SAMSUNG_ATAGS) += dev-uart.o + +obj-$(CONFIG_GPIO_SAMSUNG) += gpio-samsung.o + +# PM support + +obj-$(CONFIG_SAMSUNG_PM) += pm.o pm-common.o +obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o + +obj-$(CONFIG_SAMSUNG_WAKEMASK) += wakeup-mask.o diff --git a/arch/arm/mach-s3c/Makefile.s3c24xx b/arch/arm/mach-s3c/Makefile.s3c24xx new file mode 100644 index 000000000..3483ab3a2 --- /dev/null +++ b/arch/arm/mach-s3c/Makefile.s3c24xx @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (c) 2012 Samsung Electronics Co., Ltd. +# http://www.samsung.com/ +# +# Copyright 2007 Simtec Electronics + +# core + +obj-y += s3c24xx.o +obj-y += irq-s3c24xx.o +obj-$(CONFIG_SPI_S3C24XX_FIQ) += irq-s3c24xx-fiq.o +obj-$(CONFIG_SPI_S3C24XX_FIQ) += irq-s3c24xx-fiq-exports.o + +obj-$(CONFIG_CPU_S3C2410) += 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_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_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-s3c24xx.o +obj-$(CONFIG_PM_SLEEP) += irq-pm-s3c24xx.o sleep-s3c24xx.o + +# common code + +obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += cpufreq-utils-s3c24xx.o + +obj-$(CONFIG_S3C2410_IOTIMING) += iotiming-s3c2410.o +obj-$(CONFIG_S3C2412_IOTIMING) += iotiming-s3c2412.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-s3c24xx.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-s3c24xx.o +obj-$(CONFIG_S3C2443_SETUP_SPI) += setup-spi-s3c24xx.o +obj-$(CONFIG_ARCH_S3C24XX) += setup-i2c-s3c24xx.o +obj-$(CONFIG_S3C24XX_SETUP_TS) += setup-ts-s3c24xx.o diff --git a/arch/arm/mach-s3c/Makefile.s3c64xx b/arch/arm/mach-s3c/Makefile.s3c64xx new file mode 100644 index 000000000..21e919bf2 --- /dev/null +++ b/arch/arm/mach-s3c/Makefile.s3c64xx @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright 2008 Openmoko, Inc. +# Copyright 2008 Simtec Electronics + +# PM + +obj-$(CONFIG_PM) += pm-s3c64xx.o +obj-$(CONFIG_PM_SLEEP) += sleep-s3c64xx.o +obj-$(CONFIG_CPU_IDLE) += cpuidle-s3c64xx.o + +ifdef CONFIG_SAMSUNG_ATAGS + +obj-$(CONFIG_PM_SLEEP) += irq-pm-s3c64xx.o + +# Core + +obj-y += s3c64xx.o +obj-$(CONFIG_CPU_S3C6400) += s3c6400.o +obj-$(CONFIG_CPU_S3C6410) += s3c6410.o + +# DMA support + +obj-$(CONFIG_S3C64XX_PL080) += pl080.o + +# Device support + +obj-y += dev-uart-s3c64xx.o +obj-y += dev-audio-s3c64xx.o + +# Device setup + +obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_I2C0) += setup-i2c0-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_IDE) += setup-ide-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_KEYPAD) += setup-keypad-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_SPI) += setup-spi-s3c64xx.o +obj-$(CONFIG_S3C64XX_SETUP_USB_PHY) += setup-usb-phy-s3c64xx.o + +obj-$(CONFIG_SAMSUNG_DEV_BACKLIGHT) += dev-backlight-s3c64xx.o + +# Machine support + +obj-$(CONFIG_MACH_ANW6410) += mach-anw6410.o +obj-$(CONFIG_MACH_HMT) += mach-hmt.o +obj-$(CONFIG_MACH_MINI6410) += mach-mini6410.o +obj-$(CONFIG_MACH_NCP) += mach-ncp.o +obj-$(CONFIG_MACH_REAL6410) += mach-real6410.o +obj-$(CONFIG_MACH_SMARTQ) += mach-smartq.o +obj-$(CONFIG_MACH_SMARTQ5) += mach-smartq5.o +obj-$(CONFIG_MACH_SMARTQ7) += mach-smartq7.o +obj-$(CONFIG_MACH_SMDK6400) += mach-smdk6400.o +obj-$(CONFIG_MACH_SMDK6410) += mach-smdk6410.o +obj-$(CONFIG_MACH_WLF_CRAGG_6410) += mach-crag6410.o mach-crag6410-module.o +endif + +obj-$(CONFIG_MACH_S3C64XX_DT) += mach-s3c64xx-dt.o diff --git a/arch/arm/mach-s3c/adc-core.h b/arch/arm/mach-s3c/adc-core.h new file mode 100644 index 000000000..039f6862b --- /dev/null +++ b/arch/arm/mach-s3c/adc-core.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Samsung ADC Controller core functions + */ + +#ifndef __ASM_PLAT_ADC_CORE_H +#define __ASM_PLAT_ADC_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_adc_setname(char *name) +{ +#if defined(CONFIG_SAMSUNG_DEV_ADC) || defined(CONFIG_PLAT_S3C24XX) + s3c_device_adc.name = name; +#endif +} + +#endif /* __ASM_PLAT_ADC_CORE_H */ diff --git a/arch/arm/mach-s3c/adc.c b/arch/arm/mach-s3c/adc.c new file mode 100644 index 000000000..0232520d3 --- /dev/null +++ b/arch/arm/mach-s3c/adc.c @@ -0,0 +1,510 @@ +// SPDX-License-Identifier: GPL-1.0+ +// +// Copyright (c) 2008 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org> +// +// Samsung ADC device core + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/regulator/consumer.h> + +#include "regs-adc.h" +#include <linux/soc/samsung/s3c-adc.h> + +/* This driver is designed to control the usage of the ADC block between + * the touchscreen and any other drivers that may need to use it, such as + * the hwmon driver. + * + * Priority will be given to the touchscreen driver, but as this itself is + * rate limited it should not starve other requests which are processed in + * order that they are received. + * + * Each user registers to get a client block which uniquely identifies it + * and stores information such as the necessary functions to callback when + * action is required. + */ + +enum s3c_cpu_type { + TYPE_ADCV1, /* S3C24XX */ + TYPE_ADCV11, /* S3C2443 */ + TYPE_ADCV12, /* S3C2416, S3C2450 */ + TYPE_ADCV2, /* S3C64XX */ + TYPE_ADCV3, /* S5PV210, S5PC110, Exynos4210 */ +}; + +struct s3c_adc_client { + struct platform_device *pdev; + struct list_head pend; + wait_queue_head_t *wait; + + unsigned int nr_samples; + int result; + unsigned char is_ts; + unsigned char channel; + + void (*select_cb)(struct s3c_adc_client *c, unsigned selected); + void (*convert_cb)(struct s3c_adc_client *c, + unsigned val1, unsigned val2, + unsigned *samples_left); +}; + +struct adc_device { + struct platform_device *pdev; + struct platform_device *owner; + struct clk *clk; + struct s3c_adc_client *cur; + struct s3c_adc_client *ts_pend; + void __iomem *regs; + spinlock_t lock; + + unsigned int prescale; + + int irq; + struct regulator *vdd; +}; + +static struct adc_device *adc_dev; + +static LIST_HEAD(adc_pending); /* protected by adc_device.lock */ + +#define adc_dbg(_adc, msg...) dev_dbg(&(_adc)->pdev->dev, msg) + +static inline void s3c_adc_convert(struct adc_device *adc) +{ + unsigned con = readl(adc->regs + S3C2410_ADCCON); + + con |= S3C2410_ADCCON_ENABLE_START; + writel(con, adc->regs + S3C2410_ADCCON); +} + +static inline void s3c_adc_select(struct adc_device *adc, + struct s3c_adc_client *client) +{ + unsigned con = readl(adc->regs + S3C2410_ADCCON); + enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data; + + client->select_cb(client, 1); + + if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV2) + con &= ~S3C2410_ADCCON_MUXMASK; + con &= ~S3C2410_ADCCON_STDBM; + con &= ~S3C2410_ADCCON_STARTMASK; + + if (!client->is_ts) { + if (cpu == TYPE_ADCV3) + writel(client->channel & 0xf, adc->regs + S5P_ADCMUX); + else if (cpu == TYPE_ADCV11 || cpu == TYPE_ADCV12) + writel(client->channel & 0xf, + adc->regs + S3C2443_ADCMUX); + else + con |= S3C2410_ADCCON_SELMUX(client->channel); + } + + writel(con, adc->regs + S3C2410_ADCCON); +} + +static void s3c_adc_dbgshow(struct adc_device *adc) +{ + adc_dbg(adc, "CON=%08x, TSC=%08x, DLY=%08x\n", + readl(adc->regs + S3C2410_ADCCON), + readl(adc->regs + S3C2410_ADCTSC), + readl(adc->regs + S3C2410_ADCDLY)); +} + +static void s3c_adc_try(struct adc_device *adc) +{ + struct s3c_adc_client *next = adc->ts_pend; + + if (!next && !list_empty(&adc_pending)) { + next = list_first_entry(&adc_pending, + struct s3c_adc_client, pend); + list_del(&next->pend); + } else + adc->ts_pend = NULL; + + if (next) { + adc_dbg(adc, "new client is %p\n", next); + adc->cur = next; + s3c_adc_select(adc, next); + s3c_adc_convert(adc); + s3c_adc_dbgshow(adc); + } +} + +int s3c_adc_start(struct s3c_adc_client *client, + unsigned int channel, unsigned int nr_samples) +{ + struct adc_device *adc = adc_dev; + unsigned long flags; + + if (!adc) { + printk(KERN_ERR "%s: failed to find adc\n", __func__); + return -EINVAL; + } + + spin_lock_irqsave(&adc->lock, flags); + + if (client->is_ts && adc->ts_pend) { + spin_unlock_irqrestore(&adc->lock, flags); + return -EAGAIN; + } + + client->channel = channel; + client->nr_samples = nr_samples; + + if (client->is_ts) + adc->ts_pend = client; + else + list_add_tail(&client->pend, &adc_pending); + + if (!adc->cur) + s3c_adc_try(adc); + + spin_unlock_irqrestore(&adc->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_adc_start); + +static void s3c_convert_done(struct s3c_adc_client *client, + unsigned v, unsigned u, unsigned *left) +{ + client->result = v; + wake_up(client->wait); +} + +int s3c_adc_read(struct s3c_adc_client *client, unsigned int ch) +{ + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); + int ret; + + client->convert_cb = s3c_convert_done; + client->wait = &wake; + client->result = -1; + + ret = s3c_adc_start(client, ch, 1); + if (ret < 0) + goto err; + + ret = wait_event_timeout(wake, client->result >= 0, HZ / 2); + if (client->result < 0) { + ret = -ETIMEDOUT; + goto err; + } + + client->convert_cb = NULL; + return client->result; + +err: + return ret; +} +EXPORT_SYMBOL_GPL(s3c_adc_read); + +static void s3c_adc_default_select(struct s3c_adc_client *client, + unsigned select) +{ +} + +struct s3c_adc_client *s3c_adc_register(struct platform_device *pdev, + void (*select)(struct s3c_adc_client *client, + unsigned int selected), + void (*conv)(struct s3c_adc_client *client, + unsigned d0, unsigned d1, + unsigned *samples_left), + unsigned int is_ts) +{ + struct s3c_adc_client *client; + + WARN_ON(!pdev); + + if (!select) + select = s3c_adc_default_select; + + if (!pdev) + return ERR_PTR(-EINVAL); + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + client->pdev = pdev; + client->is_ts = is_ts; + client->select_cb = select; + client->convert_cb = conv; + + return client; +} +EXPORT_SYMBOL_GPL(s3c_adc_register); + +void s3c_adc_release(struct s3c_adc_client *client) +{ + unsigned long flags; + + spin_lock_irqsave(&adc_dev->lock, flags); + + /* We should really check that nothing is in progress. */ + if (adc_dev->cur == client) + adc_dev->cur = NULL; + if (adc_dev->ts_pend == client) + adc_dev->ts_pend = NULL; + else { + struct list_head *p, *n; + struct s3c_adc_client *tmp; + + list_for_each_safe(p, n, &adc_pending) { + tmp = list_entry(p, struct s3c_adc_client, pend); + if (tmp == client) + list_del(&tmp->pend); + } + } + + if (adc_dev->cur == NULL) + s3c_adc_try(adc_dev); + + spin_unlock_irqrestore(&adc_dev->lock, flags); + kfree(client); +} +EXPORT_SYMBOL_GPL(s3c_adc_release); + +static irqreturn_t s3c_adc_irq(int irq, void *pw) +{ + struct adc_device *adc = pw; + struct s3c_adc_client *client = adc->cur; + enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data; + unsigned data0, data1; + + if (!client) { + dev_warn(&adc->pdev->dev, "%s: no adc pending\n", __func__); + goto exit; + } + + data0 = readl(adc->regs + S3C2410_ADCDAT0); + data1 = readl(adc->regs + S3C2410_ADCDAT1); + adc_dbg(adc, "read %d: 0x%04x, 0x%04x\n", client->nr_samples, data0, data1); + + client->nr_samples--; + + if (cpu == TYPE_ADCV1 || cpu == TYPE_ADCV11) { + data0 &= 0x3ff; + data1 &= 0x3ff; + } else { + /* S3C2416/S3C64XX/S5P ADC resolution is 12-bit */ + data0 &= 0xfff; + data1 &= 0xfff; + } + + if (client->convert_cb) + (client->convert_cb)(client, data0, data1, &client->nr_samples); + + if (client->nr_samples > 0) { + /* fire another conversion for this */ + + client->select_cb(client, 1); + s3c_adc_convert(adc); + } else { + spin_lock(&adc->lock); + (client->select_cb)(client, 0); + adc->cur = NULL; + + s3c_adc_try(adc); + spin_unlock(&adc->lock); + } + +exit: + if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) { + /* Clear ADC interrupt */ + writel(0, adc->regs + S3C64XX_ADCCLRINT); + } + return IRQ_HANDLED; +} + +static int s3c_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct adc_device *adc; + enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data; + int ret; + unsigned tmp; + + adc = devm_kzalloc(dev, sizeof(*adc), GFP_KERNEL); + if (!adc) + return -ENOMEM; + + spin_lock_init(&adc->lock); + + adc->pdev = pdev; + adc->prescale = S3C2410_ADCCON_PRSCVL(49); + + adc->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(adc->vdd)) { + dev_err(dev, "operating without regulator \"vdd\" .\n"); + return PTR_ERR(adc->vdd); + } + + adc->irq = platform_get_irq(pdev, 1); + if (adc->irq <= 0) + return -ENOENT; + + ret = devm_request_irq(dev, adc->irq, s3c_adc_irq, 0, dev_name(dev), + adc); + if (ret < 0) { + dev_err(dev, "failed to attach adc irq\n"); + return ret; + } + + adc->clk = devm_clk_get(dev, "adc"); + if (IS_ERR(adc->clk)) { + dev_err(dev, "failed to get adc clock\n"); + return PTR_ERR(adc->clk); + } + + adc->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(adc->regs)) + return PTR_ERR(adc->regs); + + ret = regulator_enable(adc->vdd); + if (ret) + return ret; + + clk_prepare_enable(adc->clk); + + tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; + + /* Enable 12-bit ADC resolution */ + if (cpu == TYPE_ADCV12) + tmp |= S3C2416_ADCCON_RESSEL; + if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) + tmp |= S3C64XX_ADCCON_RESSEL; + + writel(tmp, adc->regs + S3C2410_ADCCON); + + dev_info(dev, "attached adc driver\n"); + + platform_set_drvdata(pdev, adc); + adc_dev = adc; + + return 0; +} + +static int s3c_adc_remove(struct platform_device *pdev) +{ + struct adc_device *adc = platform_get_drvdata(pdev); + + clk_disable_unprepare(adc->clk); + regulator_disable(adc->vdd); + + return 0; +} + +#ifdef CONFIG_PM +static int s3c_adc_suspend(struct device *dev) +{ + struct adc_device *adc = dev_get_drvdata(dev); + unsigned long flags; + u32 con; + + spin_lock_irqsave(&adc->lock, flags); + + con = readl(adc->regs + S3C2410_ADCCON); + con |= S3C2410_ADCCON_STDBM; + writel(con, adc->regs + S3C2410_ADCCON); + + disable_irq(adc->irq); + spin_unlock_irqrestore(&adc->lock, flags); + clk_disable(adc->clk); + regulator_disable(adc->vdd); + + return 0; +} + +static int s3c_adc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct adc_device *adc = platform_get_drvdata(pdev); + enum s3c_cpu_type cpu = platform_get_device_id(pdev)->driver_data; + int ret; + unsigned long tmp; + + ret = regulator_enable(adc->vdd); + if (ret) + return ret; + clk_enable(adc->clk); + enable_irq(adc->irq); + + tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; + + /* Enable 12-bit ADC resolution */ + if (cpu == TYPE_ADCV12) + tmp |= S3C2416_ADCCON_RESSEL; + if (cpu == TYPE_ADCV2 || cpu == TYPE_ADCV3) + tmp |= S3C64XX_ADCCON_RESSEL; + + writel(tmp, adc->regs + S3C2410_ADCCON); + + return 0; +} + +#else +#define s3c_adc_suspend NULL +#define s3c_adc_resume NULL +#endif + +static const struct platform_device_id s3c_adc_driver_ids[] = { + { + .name = "s3c24xx-adc", + .driver_data = TYPE_ADCV1, + }, { + .name = "s3c2443-adc", + .driver_data = TYPE_ADCV11, + }, { + .name = "s3c2416-adc", + .driver_data = TYPE_ADCV12, + }, { + .name = "s3c64xx-adc", + .driver_data = TYPE_ADCV2, + }, { + .name = "samsung-adc-v3", + .driver_data = TYPE_ADCV3, + }, + { } +}; +MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids); + +static const struct dev_pm_ops adc_pm_ops = { + .suspend = s3c_adc_suspend, + .resume = s3c_adc_resume, +}; + +static struct platform_driver s3c_adc_driver = { + .id_table = s3c_adc_driver_ids, + .driver = { + .name = "s3c-adc", + .pm = &adc_pm_ops, + }, + .probe = s3c_adc_probe, + .remove = s3c_adc_remove, +}; + +static int __init adc_init(void) +{ + int ret; + + ret = platform_driver_register(&s3c_adc_driver); + if (ret) + printk(KERN_ERR "%s: failed to add adc driver\n", __func__); + + return ret; +} + +module_init(adc_init); diff --git a/arch/arm/mach-s3c/anubis.h b/arch/arm/mach-s3c/anubis.h new file mode 100644 index 000000000..13847292e --- /dev/null +++ b/arch/arm/mach-s3c/anubis.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 + */ + +#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-s3c/ata-core-s3c64xx.h b/arch/arm/mach-s3c/ata-core-s3c64xx.h new file mode 100644 index 000000000..4863ad9d3 --- /dev/null +++ b/arch/arm/mach-s3c/ata-core-s3c64xx.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Samsung CF-ATA Controller core functions + */ + +#ifndef __ASM_PLAT_ATA_CORE_S3C64XX_H +#define __ASM_PLAT_ATA_CORE_S3C64XX_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code +*/ + +/* re-define device name depending on support. */ +static inline void s3c_cfcon_setname(char *name) +{ +#ifdef CONFIG_SAMSUNG_DEV_IDE + s3c_device_cfcon.name = name; +#endif +} + +#endif /* __ASM_PLAT_ATA_CORE_S3C64XX_H */ diff --git a/arch/arm/mach-s3c/backlight-s3c64xx.h b/arch/arm/mach-s3c/backlight-s3c64xx.h new file mode 100644 index 000000000..2a2b35821 --- /dev/null +++ b/arch/arm/mach-s3c/backlight-s3c64xx.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + */ + +#ifndef __ASM_PLAT_BACKLIGHT_S3C64XX_H +#define __ASM_PLAT_BACKLIGHT_S3C64XX_H __FILE__ + +/* samsung_bl_gpio_info - GPIO info for PWM Backlight control + * @no: GPIO number for PWM timer out + * @func: Special function of GPIO line for PWM timer + */ +struct samsung_bl_gpio_info { + int no; + int func; +}; + +extern void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, + struct platform_pwm_backlight_data *bl_data); + +#endif /* __ASM_PLAT_BACKLIGHT_S3C64XX_H */ diff --git a/arch/arm/mach-s3c/bast-ide.c b/arch/arm/mach-s3c/bast-ide.c new file mode 100644 index 000000000..67f0adc1f --- /dev/null +++ b/arch/arm/mach-s3c/bast-ide.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2007 Simtec Electronics +// http://www.simtec.co.uk/products/EB2410ITX/ +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk> + +#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 "map.h" +#include "irqs.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-s3c/bast-irq.c b/arch/arm/mach-s3c/bast-irq.c new file mode 100644 index 000000000..cfc2ddc65 --- /dev/null +++ b/arch/arm/mach-s3c/bast-irq.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2003-2005 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://www.simtec.co.uk/products/EB2410ITX/ + +#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 "regs-irq.h" +#include "irqs.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 const 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 const 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_to_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(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_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); + irq_clear_status_flags(irqno, IRQ_NOREQUEST); + } + } + + return 0; +} + +arch_initcall(bast_irq_init); diff --git a/arch/arm/mach-s3c/bast.h b/arch/arm/mach-s3c/bast.h new file mode 100644 index 000000000..a7726f93f --- /dev/null +++ b/arch/arm/mach-s3c/bast.h @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003-2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * BAST - CPLD control constants + * BAST - IRQ Number definitions + * BAST - Memory map definitions + */ + +#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-s3c/common-smdk-s3c24xx.c b/arch/arm/mach-s3c/common-smdk-s3c24xx.c new file mode 100644 index 000000000..6d124bbd3 --- /dev/null +++ b/arch/arm/mach-s3c/common-smdk-s3c24xx.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2006 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// Common code for SMDK2410 and SMDK2440 boards +// +// http://www.fluff.org/ben/smdk2440/ + +#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/gpio/machine.h> +#include <linux/device.h> +#include <linux/platform_device.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.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 <asm/irq.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include <linux/platform_data/leds-s3c24xx.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include "gpio-cfg.h" +#include "devs.h" +#include "pm.h" + +#include "common-smdk-s3c24xx.h" + +/* LED devices */ + +static struct gpiod_lookup_table smdk_led4_gpio_table = { + .dev_id = "s3c24xx_led.0", + .table = { + GPIO_LOOKUP("GPF", 4, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table smdk_led5_gpio_table = { + .dev_id = "s3c24xx_led.1", + .table = { + GPIO_LOOKUP("GPF", 5, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table smdk_led6_gpio_table = { + .dev_id = "s3c24xx_led.2", + .table = { + GPIO_LOOKUP("GPF", 6, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table smdk_led7_gpio_table = { + .dev_id = "s3c24xx_led.3", + .table = { + GPIO_LOOKUP("GPF", 7, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct s3c24xx_led_platdata smdk_pdata_led4 = { + .name = "led4", + .def_trigger = "timer", +}; + +static struct s3c24xx_led_platdata smdk_pdata_led5 = { + .name = "led5", + .def_trigger = "nand-disk", +}; + +static struct s3c24xx_led_platdata smdk_pdata_led6 = { + .name = "led6", +}; + +static struct s3c24xx_led_platdata smdk_pdata_led7 = { + .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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +/* devices we initialise */ + +static struct platform_device __initdata *smdk_devs[] = { + &s3c_device_nand, + &smdk_led4, + &smdk_led5, + &smdk_led6, + &smdk_led7, +}; + +void __init smdk_machine_init(void) +{ + if (machine_is_smdk2443()) + smdk_nand_info.twrph0 = 50; + + s3c_nand_set_platdata(&smdk_nand_info); + + /* Disable pull-up on the LED lines */ + s3c_gpio_setpull(S3C2410_GPF(4), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPF(5), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPF(6), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPF(7), S3C_GPIO_PULL_NONE); + + /* Add lookups for the lines */ + gpiod_add_lookup_table(&smdk_led4_gpio_table); + gpiod_add_lookup_table(&smdk_led5_gpio_table); + gpiod_add_lookup_table(&smdk_led6_gpio_table); + gpiod_add_lookup_table(&smdk_led7_gpio_table); + + platform_add_devices(smdk_devs, ARRAY_SIZE(smdk_devs)); + + s3c_pm_init(); +} diff --git a/arch/arm/mach-s3c/common-smdk-s3c24xx.h b/arch/arm/mach-s3c/common-smdk-s3c24xx.h new file mode 100644 index 000000000..c0352b06e --- /dev/null +++ b/arch/arm/mach-s3c/common-smdk-s3c24xx.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Common code for SMDK2410 and SMDK2440 boards + * + * http://www.fluff.org/ben/smdk2440/ + */ + +extern void smdk_machine_init(void); diff --git a/arch/arm/mach-s3c/cpu.c b/arch/arm/mach-s3c/cpu.c new file mode 100644 index 000000000..3491f790d --- /dev/null +++ b/arch/arm/mach-s3c/cpu.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Samsung CPU Support + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> + +#include "map-base.h" +#include "cpu.h" + +unsigned long samsung_cpu_id; + +void __init s3c64xx_init_cpu(void) +{ + samsung_cpu_id = readl_relaxed(S3C_VA_SYS + 0x118); + if (!samsung_cpu_id) { + /* + * S3C6400 has the ID register in a different place, + * and needs a write before it can be read. + */ + writel_relaxed(0x0, S3C_VA_SYS + 0xA1C); + samsung_cpu_id = readl_relaxed(S3C_VA_SYS + 0xA1C); + } + + pr_info("Samsung CPU ID: 0x%08lx\n", samsung_cpu_id); + pr_err("The platform is deprecated and scheduled for removal. Please reach to the maintainers of the platform and linux-samsung-soc@vger.kernel.org if you still use it. Without such feedback, the platform will be removed after 2022.\n"); +} diff --git a/arch/arm/mach-s3c/cpu.h b/arch/arm/mach-s3c/cpu.h new file mode 100644 index 000000000..20ff98d05 --- /dev/null +++ b/arch/arm/mach-s3c/cpu.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Copyright (c) 2004-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for Samsung CPU support + */ + +/* todo - fix when rmk changes iodescs to use `void __iomem *` */ + +#ifndef __SAMSUNG_PLAT_CPU_H +#define __SAMSUNG_PLAT_CPU_H + +extern unsigned long samsung_cpu_id; + +#define S3C2410_CPU_ID 0x32410000 +#define S3C2410_CPU_MASK 0xFFFFFFFF + +#define S3C24XX_CPU_ID 0x32400000 +#define S3C24XX_CPU_MASK 0xFFF00000 + +#define S3C2412_CPU_ID 0x32412000 +#define S3C2412_CPU_MASK 0xFFFFF000 + +#define S3C6400_CPU_ID 0x36400000 +#define S3C6410_CPU_ID 0x36410000 +#define S3C64XX_CPU_MASK 0xFFFFF000 + +#define S5PV210_CPU_ID 0x43110000 +#define S5PV210_CPU_MASK 0xFFFFF000 + +#define IS_SAMSUNG_CPU(name, id, mask) \ +static inline int is_samsung_##name(void) \ +{ \ + return ((samsung_cpu_id & mask) == (id & mask)); \ +} + +IS_SAMSUNG_CPU(s3c2410, S3C2410_CPU_ID, S3C2410_CPU_MASK) +IS_SAMSUNG_CPU(s3c24xx, S3C24XX_CPU_ID, S3C24XX_CPU_MASK) +IS_SAMSUNG_CPU(s3c2412, S3C2412_CPU_ID, S3C2412_CPU_MASK) +IS_SAMSUNG_CPU(s3c6400, S3C6400_CPU_ID, S3C64XX_CPU_MASK) +IS_SAMSUNG_CPU(s3c6410, S3C6410_CPU_ID, S3C64XX_CPU_MASK) + +#if defined(CONFIG_CPU_S3C2410) || defined(CONFIG_CPU_S3C2412) || \ + defined(CONFIG_CPU_S3C2416) || defined(CONFIG_CPU_S3C2440) || \ + defined(CONFIG_CPU_S3C2442) || defined(CONFIG_CPU_S3C244X) || \ + defined(CONFIG_CPU_S3C2443) +# define soc_is_s3c24xx() is_samsung_s3c24xx() +# define soc_is_s3c2410() is_samsung_s3c2410() +#else +# define soc_is_s3c24xx() 0 +# define soc_is_s3c2410() 0 +#endif + +#if defined(CONFIG_CPU_S3C2412) +# define soc_is_s3c2412() is_samsung_s3c2412() +#else +# define soc_is_s3c2412() 0 +#endif + +#if defined(CONFIG_CPU_S3C6400) || defined(CONFIG_CPU_S3C6410) +# define soc_is_s3c6400() is_samsung_s3c6400() +# define soc_is_s3c6410() is_samsung_s3c6410() +# define soc_is_s3c64xx() (is_samsung_s3c6400() || is_samsung_s3c6410()) +#else +# define soc_is_s3c6400() 0 +# define soc_is_s3c6410() 0 +# define soc_is_s3c64xx() 0 +#endif + +#define IODESC_ENT(x) { (unsigned long)S3C24XX_VA_##x, __phys_to_pfn(S3C24XX_PA_##x), S3C24XX_SZ_##x, MT_DEVICE } + +#ifndef KHZ +#define KHZ (1000) +#endif + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +#define print_mhz(m) ((m) / MHZ), (((m) / 1000) % 1000) + +/* forward declaration */ +struct s3c24xx_uart_resources; +struct platform_device; +struct s3c2410_uartcfg; +struct map_desc; + +/* per-cpu initialisation function table. */ + +struct cpu_table { + unsigned long idcode; + unsigned long idmask; + void (*map_io)(void); + void (*init_uarts)(struct s3c2410_uartcfg *cfg, int no); + void (*init_clocks)(int xtal); + int (*init)(void); + const char *name; +}; + +extern void s3c_init_cpu(unsigned long idcode, + struct cpu_table *cpus, unsigned int cputab_size); + +/* core initialisation functions */ + +extern void s3c24xx_init_io(struct map_desc *mach_desc, int size); + +extern void s3c64xx_init_cpu(void); + +extern void s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no); + +extern void s3c24xx_init_clocks(int xtal); + +extern void s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no); + +extern struct syscore_ops s3c2410_pm_syscore_ops; +extern struct syscore_ops s3c2412_pm_syscore_ops; +extern struct syscore_ops s3c2416_pm_syscore_ops; +extern struct syscore_ops s3c244x_pm_syscore_ops; + +extern struct bus_type s3c6410_subsys; + +#endif diff --git a/arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c b/arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c new file mode 100644 index 000000000..c1784d8fa --- /dev/null +++ b/arch/arm/mach-s3c/cpufreq-utils-s3c24xx.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/cpufreq.h> +#include <linux/io.h> +#include <linux/clk.h> + +#include "map.h" +#include "regs-clock.h" + +#include <linux/soc/samsung/s3c-cpufreq-core.h> + +#include "regs-mem-s3c24xx.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); +} + +#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2442) +u32 s3c2440_read_camdivn(void) +{ + return __raw_readl(S3C2440_CAMDIVN); +} + +void s3c2440_write_camdivn(u32 camdiv) +{ + __raw_writel(camdiv, S3C2440_CAMDIVN); +} +#endif + +u32 s3c24xx_read_clkdivn(void) +{ + return __raw_readl(S3C2410_CLKDIVN); +} + +void s3c24xx_write_clkdivn(u32 clkdiv) +{ + __raw_writel(clkdiv, S3C2410_CLKDIVN); +} + +u32 s3c24xx_read_mpllcon(void) +{ + return __raw_readl(S3C2410_MPLLCON); +} + +void s3c24xx_write_locktime(u32 locktime) +{ + return __raw_writel(locktime, S3C2410_LOCKTIME); +} diff --git a/arch/arm/mach-s3c/cpuidle-s3c64xx.c b/arch/arm/mach-s3c/cpuidle-s3c64xx.c new file mode 100644 index 000000000..b1c5f43d4 --- /dev/null +++ b/arch/arm/mach-s3c/cpuidle-s3c64xx.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2011 Wolfson Microelectronics, plc +// Copyright (c) 2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/cpuidle.h> +#include <linux/io.h> +#include <linux/export.h> +#include <linux/time.h> + +#include <asm/cpuidle.h> + +#include "cpu.h" +#include "map.h" + +#include "regs-sys-s3c64xx.h" +#include "regs-syscon-power-s3c64xx.h" + +static int s3c64xx_enter_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + unsigned long tmp; + + /* Setup PWRCFG to enter idle mode */ + tmp = __raw_readl(S3C64XX_PWR_CFG); + tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK; + tmp |= S3C64XX_PWRCFG_CFG_WFI_IDLE; + __raw_writel(tmp, S3C64XX_PWR_CFG); + + cpu_do_idle(); + + return index; +} + +static struct cpuidle_driver s3c64xx_cpuidle_driver = { + .name = "s3c64xx_cpuidle", + .owner = THIS_MODULE, + .states = { + { + .enter = s3c64xx_enter_idle, + .exit_latency = 1, + .target_residency = 1, + .name = "IDLE", + .desc = "System active, ARM gated", + }, + }, + .state_count = 1, +}; + +static int __init s3c64xx_init_cpuidle(void) +{ + if (soc_is_s3c64xx()) + return cpuidle_register(&s3c64xx_cpuidle_driver, NULL); + return 0; +} +device_initcall(s3c64xx_init_cpuidle); diff --git a/arch/arm/mach-s3c/crag6410.h b/arch/arm/mach-s3c/crag6410.h new file mode 100644 index 000000000..f39ea2ca7 --- /dev/null +++ b/arch/arm/mach-s3c/crag6410.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Cragganmore 6410 shared definitions + * + * Copyright 2011 Wolfson Microelectronics plc + * Mark Brown <broonie@opensource.wolfsonmicro.com> + */ + +#ifndef MACH_CRAG6410_H +#define MACH_CRAG6410_H + +#include "gpio-samsung.h" + +#define GLENFARCLAS_PMIC_IRQ_BASE IRQ_BOARD_START +#define BANFF_PMIC_IRQ_BASE (IRQ_BOARD_START + 64) + +#define PCA935X_GPIO_BASE GPIO_BOARD_START +#define CODEC_GPIO_BASE (GPIO_BOARD_START + 8) +#define GLENFARCLAS_PMIC_GPIO_BASE (GPIO_BOARD_START + 32) +#define BANFF_PMIC_GPIO_BASE (GPIO_BOARD_START + 64) +#define MMGPIO_GPIO_BASE (GPIO_BOARD_START + 96) + +#endif diff --git a/arch/arm/mach-s3c/dev-audio-s3c64xx.c b/arch/arm/mach-s3c/dev-audio-s3c64xx.c new file mode 100644 index 000000000..909e82c14 --- /dev/null +++ b/arch/arm/mach-s3c/dev-audio-s3c64xx.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2009 Wolfson Microelectronics +// Mark Brown <broonie@opensource.wolfsonmicro.com> + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/gpio.h> +#include <linux/export.h> + +#include "irqs.h" +#include "map.h" + +#include "devs.h" +#include <linux/platform_data/asoc-s3c.h> +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev) +{ + unsigned int base; + + switch (pdev->id) { + case 0: + base = S3C64XX_GPD(0); + break; + case 1: + base = S3C64XX_GPE(0); + break; + case 2: + s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5)); + s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5)); + s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5)); + s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5)); + return 0; + default: + printk(KERN_DEBUG "Invalid I2S Controller number: %d\n", + pdev->id); + return -EINVAL; + } + + s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(3)); + + return 0; +} + +static struct resource s3c64xx_iis0_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256), +}; + +static struct s3c_audio_pdata i2s0_pdata = { + .cfg_gpio = s3c64xx_i2s_cfg_gpio, +}; + +struct platform_device s3c64xx_device_iis0 = { + .name = "samsung-i2s", + .id = 0, + .num_resources = ARRAY_SIZE(s3c64xx_iis0_resource), + .resource = s3c64xx_iis0_resource, + .dev = { + .platform_data = &i2s0_pdata, + }, +}; +EXPORT_SYMBOL(s3c64xx_device_iis0); + +static struct resource s3c64xx_iis1_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256), +}; + +static struct s3c_audio_pdata i2s1_pdata = { + .cfg_gpio = s3c64xx_i2s_cfg_gpio, +}; + +struct platform_device s3c64xx_device_iis1 = { + .name = "samsung-i2s", + .id = 1, + .num_resources = ARRAY_SIZE(s3c64xx_iis1_resource), + .resource = s3c64xx_iis1_resource, + .dev = { + .platform_data = &i2s1_pdata, + }, +}; +EXPORT_SYMBOL(s3c64xx_device_iis1); + +static struct resource s3c64xx_iisv4_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256), +}; + +static struct s3c_audio_pdata i2sv4_pdata = { + .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .type = { + .quirks = QUIRK_PRI_6CHAN, + }, +}; + +struct platform_device s3c64xx_device_iisv4 = { + .name = "samsung-i2s", + .id = 2, + .num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource), + .resource = s3c64xx_iisv4_resource, + .dev = { + .platform_data = &i2sv4_pdata, + }, +}; +EXPORT_SYMBOL(s3c64xx_device_iisv4); + + +/* PCM Controller platform_devices */ + +static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev) +{ + unsigned int base; + + switch (pdev->id) { + case 0: + base = S3C64XX_GPD(0); + break; + case 1: + base = S3C64XX_GPE(0); + break; + default: + printk(KERN_DEBUG "Invalid PCM Controller number: %d\n", + pdev->id); + return -EINVAL; + } + + s3c_gpio_cfgpin_range(base, 5, S3C_GPIO_SFN(2)); + return 0; +} + +static struct resource s3c64xx_pcm0_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256), +}; + +static struct s3c_audio_pdata s3c_pcm0_pdata = { + .cfg_gpio = s3c64xx_pcm_cfg_gpio, +}; + +struct platform_device s3c64xx_device_pcm0 = { + .name = "samsung-pcm", + .id = 0, + .num_resources = ARRAY_SIZE(s3c64xx_pcm0_resource), + .resource = s3c64xx_pcm0_resource, + .dev = { + .platform_data = &s3c_pcm0_pdata, + }, +}; +EXPORT_SYMBOL(s3c64xx_device_pcm0); + +static struct resource s3c64xx_pcm1_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256), +}; + +static struct s3c_audio_pdata s3c_pcm1_pdata = { + .cfg_gpio = s3c64xx_pcm_cfg_gpio, +}; + +struct platform_device s3c64xx_device_pcm1 = { + .name = "samsung-pcm", + .id = 1, + .num_resources = ARRAY_SIZE(s3c64xx_pcm1_resource), + .resource = s3c64xx_pcm1_resource, + .dev = { + .platform_data = &s3c_pcm1_pdata, + }, +}; +EXPORT_SYMBOL(s3c64xx_device_pcm1); + +/* AC97 Controller platform devices */ + +static int s3c64xx_ac97_cfg_gpd(struct platform_device *pdev) +{ + return s3c_gpio_cfgpin_range(S3C64XX_GPD(0), 5, S3C_GPIO_SFN(4)); +} + +static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev) +{ + return s3c_gpio_cfgpin_range(S3C64XX_GPE(0), 5, S3C_GPIO_SFN(4)); +} + +static struct resource s3c64xx_ac97_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_AC97), +}; + +static struct s3c_audio_pdata s3c_ac97_pdata = { +}; + +static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32); + +struct platform_device s3c64xx_device_ac97 = { + .name = "samsung-ac97", + .id = -1, + .num_resources = ARRAY_SIZE(s3c64xx_ac97_resource), + .resource = s3c64xx_ac97_resource, + .dev = { + .platform_data = &s3c_ac97_pdata, + .dma_mask = &s3c64xx_ac97_dmamask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; +EXPORT_SYMBOL(s3c64xx_device_ac97); + +void __init s3c64xx_ac97_setup_gpio(int num) +{ + if (num == S3C64XX_AC97_GPD) + s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpd; + else + s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe; +} diff --git a/arch/arm/mach-s3c/dev-backlight-s3c64xx.c b/arch/arm/mach-s3c/dev-backlight-s3c64xx.c new file mode 100644 index 000000000..65488b61e --- /dev/null +++ b/arch/arm/mach-s3c/dev-backlight-s3c64xx.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Common infrastructure for PWM Backlight for Samsung boards + +#include <linux/gpio.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/pwm_backlight.h> + +#include "devs.h" +#include "gpio-cfg.h" + +#include "backlight-s3c64xx.h" + +struct samsung_bl_drvdata { + struct platform_pwm_backlight_data plat_data; + struct samsung_bl_gpio_info *gpio_info; +}; + +static int samsung_bl_init(struct device *dev) +{ + int ret = 0; + struct platform_pwm_backlight_data *pdata = dev->platform_data; + struct samsung_bl_drvdata *drvdata = container_of(pdata, + struct samsung_bl_drvdata, plat_data); + struct samsung_bl_gpio_info *bl_gpio_info = drvdata->gpio_info; + + ret = gpio_request(bl_gpio_info->no, "Backlight"); + if (ret) { + printk(KERN_ERR "failed to request GPIO for LCD Backlight\n"); + return ret; + } + + /* Configure GPIO pin with specific GPIO function for PWM timer */ + s3c_gpio_cfgpin(bl_gpio_info->no, bl_gpio_info->func); + + return 0; +} + +static void samsung_bl_exit(struct device *dev) +{ + struct platform_pwm_backlight_data *pdata = dev->platform_data; + struct samsung_bl_drvdata *drvdata = container_of(pdata, + struct samsung_bl_drvdata, plat_data); + struct samsung_bl_gpio_info *bl_gpio_info = drvdata->gpio_info; + + s3c_gpio_cfgpin(bl_gpio_info->no, S3C_GPIO_OUTPUT); + gpio_free(bl_gpio_info->no); +} + +/* Initialize few important fields of platform_pwm_backlight_data + * structure with default values. These fields can be overridden by + * board-specific values sent from machine file. + * For ease of operation, these fields are initialized with values + * used by most samsung boards. + * Users has the option of sending info about other parameters + * for their specific boards + */ + +static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = { + .plat_data = { + .max_brightness = 255, + .dft_brightness = 255, + .init = samsung_bl_init, + .exit = samsung_bl_exit, + }, +}; + +static struct platform_device samsung_dfl_bl_device __initdata = { + .name = "pwm-backlight", +}; + +/* samsung_bl_set - Set board specific data (if any) provided by user for + * PWM Backlight control and register specific PWM and backlight device. + * @gpio_info: structure containing GPIO info for PWM timer + * @bl_data: structure containing Backlight control data + */ +void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info, + struct platform_pwm_backlight_data *bl_data) +{ + int ret = 0; + struct platform_device *samsung_bl_device; + struct samsung_bl_drvdata *samsung_bl_drvdata; + struct platform_pwm_backlight_data *samsung_bl_data; + + samsung_bl_device = kmemdup(&samsung_dfl_bl_device, + sizeof(struct platform_device), GFP_KERNEL); + if (!samsung_bl_device) + return; + + samsung_bl_drvdata = kmemdup(&samsung_dfl_bl_data, + sizeof(samsung_dfl_bl_data), GFP_KERNEL); + if (!samsung_bl_drvdata) + goto err_data; + + samsung_bl_device->dev.platform_data = &samsung_bl_drvdata->plat_data; + samsung_bl_drvdata->gpio_info = gpio_info; + samsung_bl_data = &samsung_bl_drvdata->plat_data; + + /* Copy board specific data provided by user */ + samsung_bl_device->dev.parent = &samsung_device_pwm.dev; + + if (bl_data->max_brightness) + samsung_bl_data->max_brightness = bl_data->max_brightness; + if (bl_data->dft_brightness) + samsung_bl_data->dft_brightness = bl_data->dft_brightness; + if (bl_data->lth_brightness) + samsung_bl_data->lth_brightness = bl_data->lth_brightness; + if (bl_data->init) + samsung_bl_data->init = bl_data->init; + if (bl_data->notify) + samsung_bl_data->notify = bl_data->notify; + if (bl_data->notify_after) + samsung_bl_data->notify_after = bl_data->notify_after; + if (bl_data->exit) + samsung_bl_data->exit = bl_data->exit; + if (bl_data->check_fb) + samsung_bl_data->check_fb = bl_data->check_fb; + + /* Register the Backlight dev */ + ret = platform_device_register(samsung_bl_device); + if (ret) { + printk(KERN_ERR "failed to register backlight device: %d\n", ret); + goto err_plat_reg2; + } + + return; + +err_plat_reg2: + kfree(samsung_bl_data); +err_data: + kfree(samsung_bl_device); +} diff --git a/arch/arm/mach-s3c/dev-uart-s3c64xx.c b/arch/arm/mach-s3c/dev-uart-s3c64xx.c new file mode 100644 index 000000000..f9c947b89 --- /dev/null +++ b/arch/arm/mach-s3c/dev-uart-s3c64xx.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Base S3C64XX UART resource and device definitions + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/platform_device.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include "map.h" +#include "irqs.h" + +#include "devs.h" + +/* Serial port registrations */ + +/* 64xx uarts are closer together */ + +static struct resource s3c64xx_uart0_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_UART0, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_UART0), +}; + +static struct resource s3c64xx_uart1_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_UART1, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_UART1), +}; + +static struct resource s3c6xx_uart2_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_UART2, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_UART2), +}; + +static struct resource s3c64xx_uart3_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_UART3, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_UART3), +}; + + +struct s3c24xx_uart_resources s3c64xx_uart_resources[] __initdata = { + [0] = { + .resources = s3c64xx_uart0_resource, + .nr_resources = ARRAY_SIZE(s3c64xx_uart0_resource), + }, + [1] = { + .resources = s3c64xx_uart1_resource, + .nr_resources = ARRAY_SIZE(s3c64xx_uart1_resource), + }, + [2] = { + .resources = s3c6xx_uart2_resource, + .nr_resources = ARRAY_SIZE(s3c6xx_uart2_resource), + }, + [3] = { + .resources = s3c64xx_uart3_resource, + .nr_resources = ARRAY_SIZE(s3c64xx_uart3_resource), + }, +}; diff --git a/arch/arm/mach-s3c/dev-uart.c b/arch/arm/mach-s3c/dev-uart.c new file mode 100644 index 000000000..3d1f7f2fd --- /dev/null +++ b/arch/arm/mach-s3c/dev-uart.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// originally from arch/arm/plat-s3c24xx/devs.c +// +// Copyright (c) 2004 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// Base S3C24XX platform device definitions + +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include "devs.h" + +/* uart devices */ + +static struct platform_device s3c24xx_uart_device0 = { + .id = 0, +}; + +static struct platform_device s3c24xx_uart_device1 = { + .id = 1, +}; + +static struct platform_device s3c24xx_uart_device2 = { + .id = 2, +}; + +static struct platform_device s3c24xx_uart_device3 = { + .id = 3, +}; + +struct platform_device *s3c24xx_uart_src[4] = { + &s3c24xx_uart_device0, + &s3c24xx_uart_device1, + &s3c24xx_uart_device2, + &s3c24xx_uart_device3, +}; + +struct platform_device *s3c24xx_uart_devs[4] = { +}; diff --git a/arch/arm/mach-s3c/devs.c b/arch/arm/mach-s3c/devs.c new file mode 100644 index 000000000..9ac07c023 --- /dev/null +++ b/arch/arm/mach-s3c/devs.c @@ -0,0 +1,1126 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Base Samsung platform device definitions + +#include <linux/gpio.h> +#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/slab.h> +#include <linux/string.h> +#include <linux/dma-mapping.h> +#include <linux/fb.h> +#include <linux/gfp.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/onenand.h> +#include <linux/mtd/partitions.h> +#include <linux/mmc/host.h> +#include <linux/ioport.h> +#include <linux/sizes.h> +#include <linux/platform_data/s3c-hsudc.h> +#include <linux/platform_data/s3c-hsotg.h> +#include <linux/platform_data/dma-s3c24xx.h> + +#include <linux/platform_data/media/s5p_hdmi.h> + +#include <asm/irq.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include "irqs.h" +#include "map.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#ifdef CONFIG_PLAT_S3C24XX +#include "regs-s3c2443-clock.h" +#endif /* CONFIG_PLAT_S3C24XX */ + +#include "cpu.h" +#include "devs.h" +#include <linux/soc/samsung/s3c-adc.h> +#include <linux/platform_data/ata-samsung_cf.h> +#include "fb.h" +#include <linux/platform_data/fb-s3c2410.h> +#include <linux/platform_data/hwmon-s3c.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include "keypad.h" +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include "pwm-core.h" +#include "sdhci.h" +#include <linux/platform_data/touchscreen-s3c2410.h> +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/usb-ohci-s3c2410.h> +#include "usb-phy.h" +#include <linux/platform_data/asoc-s3c.h> +#include <linux/platform_data/spi-s3c64xx.h> + +#define samsung_device_dma_mask (*((u64[]) { DMA_BIT_MASK(32) })) + +/* AC97 */ +#ifdef CONFIG_CPU_S3C2440 +static struct resource s3c_ac97_resource[] = { + [0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97), + [1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97), +}; + +struct platform_device s3c_device_ac97 = { + .name = "samsung-ac97", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_ac97_resource), + .resource = s3c_ac97_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_CPU_S3C2440 */ + +/* ADC */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_adc_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC), + [1] = DEFINE_RES_IRQ(IRQ_TC), + [2] = DEFINE_RES_IRQ(IRQ_ADC), +}; + +struct platform_device s3c_device_adc = { + .name = "s3c24xx-adc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_adc_resource), + .resource = s3c_adc_resource, +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +#if defined(CONFIG_SAMSUNG_DEV_ADC) +static struct resource s3c_adc_resource[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_ADC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_ADC), + [2] = DEFINE_RES_IRQ(IRQ_TC), +}; + +struct platform_device s3c_device_adc = { + .name = "exynos-adc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_adc_resource), + .resource = s3c_adc_resource, +}; +#endif /* CONFIG_SAMSUNG_DEV_ADC */ + +/* Camif Controller */ + +#ifdef CONFIG_CPU_S3C2440 +static struct resource s3c_camif_resource[] = { + [0] = DEFINE_RES_MEM(S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF), + [1] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_C), + [2] = DEFINE_RES_IRQ(IRQ_S3C2440_CAM_P), +}; + +struct platform_device s3c_device_camif = { + .name = "s3c2440-camif", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_camif_resource), + .resource = s3c_camif_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_CPU_S3C2440 */ + +/* FB */ + +#ifdef CONFIG_S3C_DEV_FB +static struct resource s3c_fb_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_FB, SZ_16K), + [1] = DEFINE_RES_IRQ(IRQ_LCD_VSYNC), + [2] = DEFINE_RES_IRQ(IRQ_LCD_FIFO), + [3] = DEFINE_RES_IRQ(IRQ_LCD_SYSTEM), +}; + +struct platform_device s3c_device_fb = { + .name = "s3c-fb", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_fb_resource), + .resource = s3c_fb_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c_fb_set_platdata(struct s3c_fb_platdata *pd) +{ + s3c_set_platdata(pd, sizeof(struct s3c_fb_platdata), + &s3c_device_fb); +} +#endif /* CONFIG_S3C_DEV_FB */ + +/* HWMON */ + +#ifdef CONFIG_S3C_DEV_HWMON +struct platform_device s3c_device_hwmon = { + .name = "s3c-hwmon", + .id = -1, + .dev.parent = &s3c_device_adc.dev, +}; + +void __init s3c_hwmon_set_platdata(struct s3c_hwmon_pdata *pd) +{ + s3c_set_platdata(pd, sizeof(struct s3c_hwmon_pdata), + &s3c_device_hwmon); +} +#endif /* CONFIG_S3C_DEV_HWMON */ + +/* HSMMC */ + +#ifdef CONFIG_S3C_DEV_HSMMC +static struct resource s3c_hsmmc_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC0, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC0), +}; + +struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc0 = { + .name = "s3c-sdhci", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_hsmmc_resource), + .resource = s3c_hsmmc_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc0_def_platdata, + }, +}; + +void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc0_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC */ + +#ifdef CONFIG_S3C_DEV_HSMMC1 +static struct resource s3c_hsmmc1_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC1, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC1), +}; + +struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc1 = { + .name = "s3c-sdhci", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_hsmmc1_resource), + .resource = s3c_hsmmc1_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc1_def_platdata, + }, +}; + +void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc1_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC1 */ + +/* HSMMC2 */ + +#ifdef CONFIG_S3C_DEV_HSMMC2 +static struct resource s3c_hsmmc2_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC2, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC2), +}; + +struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc2 = { + .name = "s3c-sdhci", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_hsmmc2_resource), + .resource = s3c_hsmmc2_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc2_def_platdata, + }, +}; + +void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc2_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC2 */ + +#ifdef CONFIG_S3C_DEV_HSMMC3 +static struct resource s3c_hsmmc3_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_HSMMC3, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_HSMMC3), +}; + +struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata = { + .max_width = 4, + .host_caps = (MMC_CAP_4_BIT_DATA | + MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED), +}; + +struct platform_device s3c_device_hsmmc3 = { + .name = "s3c-sdhci", + .id = 3, + .num_resources = ARRAY_SIZE(s3c_hsmmc3_resource), + .resource = s3c_hsmmc3_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_hsmmc3_def_platdata, + }, +}; + +void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd) +{ + s3c_sdhci_set_platdata(pd, &s3c_hsmmc3_def_platdata); +} +#endif /* CONFIG_S3C_DEV_HSMMC3 */ + +/* I2C */ + +static struct resource s3c_i2c0_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC), +}; + +struct platform_device s3c_device_i2c0 = { + .name = "s3c2410-i2c", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_i2c0_resource), + .resource = s3c_i2c0_resource, +}; + +struct s3c2410_platform_i2c default_i2c_data __initdata = { + .flags = 0, + .slave_addr = 0x10, + .frequency = 100*1000, + .sda_delay = 100, +}; + +void __init s3c_i2c0_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 0; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c0); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c0_cfg_gpio; +} + +#ifdef CONFIG_S3C_DEV_I2C1 +static struct resource s3c_i2c1_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC1, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC1), +}; + +struct platform_device s3c_device_i2c1 = { + .name = "s3c2410-i2c", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_i2c1_resource), + .resource = s3c_i2c1_resource, +}; + +void __init s3c_i2c1_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 1; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c1); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c1_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C1 */ + +#ifdef CONFIG_S3C_DEV_I2C2 +static struct resource s3c_i2c2_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC2, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC2), +}; + +struct platform_device s3c_device_i2c2 = { + .name = "s3c2410-i2c", + .id = 2, + .num_resources = ARRAY_SIZE(s3c_i2c2_resource), + .resource = s3c_i2c2_resource, +}; + +void __init s3c_i2c2_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 2; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c2); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c2_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C2 */ + +#ifdef CONFIG_S3C_DEV_I2C3 +static struct resource s3c_i2c3_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC3, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC3), +}; + +struct platform_device s3c_device_i2c3 = { + .name = "s3c2440-i2c", + .id = 3, + .num_resources = ARRAY_SIZE(s3c_i2c3_resource), + .resource = s3c_i2c3_resource, +}; + +void __init s3c_i2c3_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 3; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c3); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c3_cfg_gpio; +} +#endif /*CONFIG_S3C_DEV_I2C3 */ + +#ifdef CONFIG_S3C_DEV_I2C4 +static struct resource s3c_i2c4_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC4, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC4), +}; + +struct platform_device s3c_device_i2c4 = { + .name = "s3c2440-i2c", + .id = 4, + .num_resources = ARRAY_SIZE(s3c_i2c4_resource), + .resource = s3c_i2c4_resource, +}; + +void __init s3c_i2c4_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 4; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c4); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c4_cfg_gpio; +} +#endif /*CONFIG_S3C_DEV_I2C4 */ + +#ifdef CONFIG_S3C_DEV_I2C5 +static struct resource s3c_i2c5_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC5, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC5), +}; + +struct platform_device s3c_device_i2c5 = { + .name = "s3c2440-i2c", + .id = 5, + .num_resources = ARRAY_SIZE(s3c_i2c5_resource), + .resource = s3c_i2c5_resource, +}; + +void __init s3c_i2c5_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 5; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c5); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c5_cfg_gpio; +} +#endif /*CONFIG_S3C_DEV_I2C5 */ + +#ifdef CONFIG_S3C_DEV_I2C6 +static struct resource s3c_i2c6_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC6, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC6), +}; + +struct platform_device s3c_device_i2c6 = { + .name = "s3c2440-i2c", + .id = 6, + .num_resources = ARRAY_SIZE(s3c_i2c6_resource), + .resource = s3c_i2c6_resource, +}; + +void __init s3c_i2c6_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 6; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c6); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c6_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C6 */ + +#ifdef CONFIG_S3C_DEV_I2C7 +static struct resource s3c_i2c7_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_IIC7, SZ_4K), + [1] = DEFINE_RES_IRQ(IRQ_IIC7), +}; + +struct platform_device s3c_device_i2c7 = { + .name = "s3c2440-i2c", + .id = 7, + .num_resources = ARRAY_SIZE(s3c_i2c7_resource), + .resource = s3c_i2c7_resource, +}; + +void __init s3c_i2c7_set_platdata(struct s3c2410_platform_i2c *pd) +{ + struct s3c2410_platform_i2c *npd; + + if (!pd) { + pd = &default_i2c_data; + pd->bus_num = 7; + } + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_i2c7); + + if (!npd->cfg_gpio) + npd->cfg_gpio = s3c_i2c7_cfg_gpio; +} +#endif /* CONFIG_S3C_DEV_I2C7 */ + +/* I2S */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_iis_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS), +}; + +struct platform_device s3c_device_iis = { + .name = "s3c24xx-iis", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_iis_resource), + .resource = s3c_iis_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +/* IDE CFCON */ + +#ifdef CONFIG_SAMSUNG_DEV_IDE +static struct resource s3c_cfcon_resource[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_CFCON, SZ_16K), + [1] = DEFINE_RES_IRQ(IRQ_CFCON), +}; + +struct platform_device s3c_device_cfcon = { + .id = 0, + .num_resources = ARRAY_SIZE(s3c_cfcon_resource), + .resource = s3c_cfcon_resource, +}; + +void __init s3c_ide_set_platdata(struct s3c_ide_platdata *pdata) +{ + s3c_set_platdata(pdata, sizeof(struct s3c_ide_platdata), + &s3c_device_cfcon); +} +#endif /* CONFIG_SAMSUNG_DEV_IDE */ + +/* KEYPAD */ + +#ifdef CONFIG_SAMSUNG_DEV_KEYPAD +static struct resource samsung_keypad_resources[] = { + [0] = DEFINE_RES_MEM(SAMSUNG_PA_KEYPAD, SZ_32), + [1] = DEFINE_RES_IRQ(IRQ_KEYPAD), +}; + +struct platform_device samsung_device_keypad = { + .name = "samsung-keypad", + .id = -1, + .num_resources = ARRAY_SIZE(samsung_keypad_resources), + .resource = samsung_keypad_resources, +}; + +void __init samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd) +{ + struct samsung_keypad_platdata *npd; + + npd = s3c_set_platdata(pd, sizeof(*npd), &samsung_device_keypad); + + if (!npd->cfg_gpio) + npd->cfg_gpio = samsung_keypad_cfg_gpio; +} +#endif /* CONFIG_SAMSUNG_DEV_KEYPAD */ + +/* LCD Controller */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_lcd_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_LCD, S3C24XX_SZ_LCD), + [1] = DEFINE_RES_IRQ(IRQ_LCD), +}; + +struct platform_device s3c_device_lcd = { + .name = "s3c2410-lcd", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_lcd_resource), + .resource = s3c_lcd_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; + +void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd) +{ + struct s3c2410fb_mach_info *npd; + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_lcd); + if (npd) { + npd->displays = kmemdup(pd->displays, + sizeof(struct s3c2410fb_display) * npd->num_displays, + GFP_KERNEL); + if (!npd->displays) + printk(KERN_ERR "no memory for LCD display data\n"); + } else { + printk(KERN_ERR "no memory for LCD platform data\n"); + } +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* NAND */ + +#ifdef CONFIG_S3C_DEV_NAND +static struct resource s3c_nand_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_NAND, SZ_1M), +}; + +struct platform_device s3c_device_nand = { + .name = "s3c2410-nand", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_nand_resource), + .resource = s3c_nand_resource, +}; + +/* + * s3c_nand_copy_set() - copy nand set data + * @set: The new structure, directly copied from the old. + * + * Copy all the fields from the NAND set field from what is probably __initdata + * to new kernel memory. The code returns 0 if the copy happened correctly or + * an error code for the calling function to display. + * + * Note, we currently do not try and look to see if we've already copied the + * data in a previous set. + */ +static int __init s3c_nand_copy_set(struct s3c2410_nand_set *set) +{ + void *ptr; + int size; + + size = sizeof(struct mtd_partition) * set->nr_partitions; + if (size) { + ptr = kmemdup(set->partitions, size, GFP_KERNEL); + set->partitions = ptr; + + if (!ptr) + return -ENOMEM; + } + + if (set->nr_map && set->nr_chips) { + size = sizeof(int) * set->nr_chips; + ptr = kmemdup(set->nr_map, size, GFP_KERNEL); + set->nr_map = ptr; + + if (!ptr) + return -ENOMEM; + } + + return 0; +} + +void __init s3c_nand_set_platdata(struct s3c2410_platform_nand *nand) +{ + struct s3c2410_platform_nand *npd; + int size; + int ret; + + /* note, if we get a failure in allocation, we simply drop out of the + * function. If there is so little memory available at initialisation + * time then there is little chance the system is going to run. + */ + + npd = s3c_set_platdata(nand, sizeof(*npd), &s3c_device_nand); + if (!npd) + return; + + /* now see if we need to copy any of the nand set data */ + + size = sizeof(struct s3c2410_nand_set) * npd->nr_sets; + if (size) { + struct s3c2410_nand_set *from = npd->sets; + struct s3c2410_nand_set *to; + int i; + + to = kmemdup(from, size, GFP_KERNEL); + npd->sets = to; /* set, even if we failed */ + + if (!to) { + printk(KERN_ERR "%s: no memory for sets\n", __func__); + return; + } + + for (i = 0; i < npd->nr_sets; i++) { + ret = s3c_nand_copy_set(to); + if (ret) { + printk(KERN_ERR "%s: failed to copy set %d\n", + __func__, i); + return; + } + to++; + } + } +} +#endif /* CONFIG_S3C_DEV_NAND */ + +/* ONENAND */ + +#ifdef CONFIG_S3C_DEV_ONENAND +static struct resource s3c_onenand_resources[] = { + [0] = DEFINE_RES_MEM(S3C_PA_ONENAND, SZ_1K), + [1] = DEFINE_RES_MEM(S3C_PA_ONENAND_BUF, S3C_SZ_ONENAND_BUF), + [2] = DEFINE_RES_IRQ(IRQ_ONENAND), +}; + +struct platform_device s3c_device_onenand = { + .name = "samsung-onenand", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_onenand_resources), + .resource = s3c_onenand_resources, +}; +#endif /* CONFIG_S3C_DEV_ONENAND */ + +#ifdef CONFIG_S3C64XX_DEV_ONENAND1 +static struct resource s3c64xx_onenand1_resources[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_ONENAND1, SZ_1K), + [1] = DEFINE_RES_MEM(S3C64XX_PA_ONENAND1_BUF, S3C64XX_SZ_ONENAND1_BUF), + [2] = DEFINE_RES_IRQ(IRQ_ONENAND1), +}; + +struct platform_device s3c64xx_device_onenand1 = { + .name = "samsung-onenand", + .id = 1, + .num_resources = ARRAY_SIZE(s3c64xx_onenand1_resources), + .resource = s3c64xx_onenand1_resources, +}; + +void __init s3c64xx_onenand1_set_platdata(struct onenand_platform_data *pdata) +{ + s3c_set_platdata(pdata, sizeof(struct onenand_platform_data), + &s3c64xx_device_onenand1); +} +#endif /* CONFIG_S3C64XX_DEV_ONENAND1 */ + +/* PWM Timer */ + +#ifdef CONFIG_SAMSUNG_DEV_PWM +static struct resource samsung_pwm_resource[] = { + DEFINE_RES_MEM(SAMSUNG_PA_TIMER, SZ_4K), +}; + +struct platform_device samsung_device_pwm = { + .name = "samsung-pwm", + .id = -1, + .num_resources = ARRAY_SIZE(samsung_pwm_resource), + .resource = samsung_pwm_resource, +}; + +void __init samsung_pwm_set_platdata(struct samsung_pwm_variant *pd) +{ + samsung_device_pwm.dev.platform_data = pd; +} +#endif /* CONFIG_SAMSUNG_DEV_PWM */ + +/* RTC */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_rtc_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_RTC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_RTC), + [2] = DEFINE_RES_IRQ(IRQ_TICK), +}; + +struct platform_device s3c_device_rtc = { + .name = "s3c2410-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_rtc_resource), + .resource = s3c_rtc_resource, +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +#ifdef CONFIG_S3C_DEV_RTC +static struct resource s3c_rtc_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_RTC, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_RTC_ALARM), + [2] = DEFINE_RES_IRQ(IRQ_RTC_TIC), +}; + +struct platform_device s3c_device_rtc = { + .name = "s3c64xx-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_rtc_resource), + .resource = s3c_rtc_resource, +}; +#endif /* CONFIG_S3C_DEV_RTC */ + +/* SDI */ + +#ifdef CONFIG_PLAT_S3C24XX +void s3c24xx_mci_def_set_power(unsigned char power_mode, unsigned short vdd) +{ + switch (power_mode) { + case MMC_POWER_ON: + case MMC_POWER_UP: + /* Configure GPE5...GPE10 pins in SD mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + break; + + case MMC_POWER_OFF: + default: + gpio_direction_output(S3C2410_GPE(5), 0); + break; + } +} + +static struct resource s3c_sdi_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI), + [1] = DEFINE_RES_IRQ(IRQ_SDI), +}; + +static struct s3c24xx_mci_pdata s3cmci_def_pdata = { + /* This is currently here to avoid a number of if (host->pdata) + * checks. Any zero fields to ensure reasonable defaults are picked. */ + .no_wprotect = 1, + .no_detect = 1, + .set_power = s3c24xx_mci_def_set_power, +}; + +struct platform_device s3c_device_sdi = { + .name = "s3c2410-sdi", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_sdi_resource), + .resource = s3c_sdi_resource, + .dev.platform_data = &s3cmci_def_pdata, +}; + +void __init s3c24xx_mci_set_platdata(struct s3c24xx_mci_pdata *pdata) +{ + s3c_set_platdata(pdata, sizeof(struct s3c24xx_mci_pdata), + &s3c_device_sdi); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* SPI */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_spi0_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_SPI, SZ_32), + [1] = DEFINE_RES_IRQ(IRQ_SPI0), +}; + +struct platform_device s3c_device_spi0 = { + .name = "s3c2410-spi", + .id = 0, + .num_resources = ARRAY_SIZE(s3c_spi0_resource), + .resource = s3c_spi0_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; + +static struct resource s3c_spi1_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_SPI1, SZ_32), + [1] = DEFINE_RES_IRQ(IRQ_SPI1), +}; + +struct platform_device s3c_device_spi1 = { + .name = "s3c2410-spi", + .id = 1, + .num_resources = ARRAY_SIZE(s3c_spi1_resource), + .resource = s3c_spi1_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; +#endif /* CONFIG_PLAT_S3C24XX */ + +/* Touchscreen */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_ts_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_ADC, S3C24XX_SZ_ADC), + [1] = DEFINE_RES_IRQ(IRQ_TC), +}; + +struct platform_device s3c_device_ts = { + .name = "s3c2410-ts", + .id = -1, + .dev.parent = &s3c_device_adc.dev, + .num_resources = ARRAY_SIZE(s3c_ts_resource), + .resource = s3c_ts_resource, +}; + +void __init s3c24xx_ts_set_platdata(struct s3c2410_ts_mach_info *hard_s3c2410ts_info) +{ + s3c_set_platdata(hard_s3c2410ts_info, + sizeof(struct s3c2410_ts_mach_info), &s3c_device_ts); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +#ifdef CONFIG_SAMSUNG_DEV_TS +static struct s3c2410_ts_mach_info default_ts_data __initdata = { + .delay = 10000, + .presc = 49, + .oversampling_shift = 2, +}; + +void __init s3c64xx_ts_set_platdata(struct s3c2410_ts_mach_info *pd) +{ + if (!pd) + pd = &default_ts_data; + + s3c_set_platdata(pd, sizeof(struct s3c2410_ts_mach_info), + &s3c_device_adc); +} +#endif /* CONFIG_SAMSUNG_DEV_TS */ + +/* USB */ + +#ifdef CONFIG_S3C_DEV_USB_HOST +static struct resource s3c_usb_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_USBHOST, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_USBH), +}; + +struct platform_device s3c_device_ohci = { + .name = "s3c2410-ohci", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_resource), + .resource = s3c_usb_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + } +}; + +/* + * s3c_ohci_set_platdata - initialise OHCI device platform data + * @info: The platform data. + * + * This call copies the @info passed in and sets the device .platform_data + * field to that copy. The @info is copied so that the original can be marked + * __initdata. + */ + +void __init s3c_ohci_set_platdata(struct s3c2410_hcd_info *info) +{ + s3c_set_platdata(info, sizeof(struct s3c2410_hcd_info), + &s3c_device_ohci); +} +#endif /* CONFIG_S3C_DEV_USB_HOST */ + +/* USB Device (Gadget) */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_usbgadget_resource[] = { + [0] = DEFINE_RES_MEM(S3C24XX_PA_USBDEV, S3C24XX_SZ_USBDEV), + [1] = DEFINE_RES_IRQ(IRQ_USBD), +}; + +struct platform_device s3c_device_usbgadget = { + .name = "s3c2410-usbgadget", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usbgadget_resource), + .resource = s3c_usbgadget_resource, +}; + +void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *pd) +{ + s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usbgadget); +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* USB HSOTG */ + +#ifdef CONFIG_S3C_DEV_USB_HSOTG +static struct resource s3c_usb_hsotg_resources[] = { + [0] = DEFINE_RES_MEM(S3C_PA_USB_HSOTG, SZ_128K), + [1] = DEFINE_RES_IRQ(IRQ_OTG), +}; + +struct platform_device s3c_device_usb_hsotg = { + .name = "s3c-hsotg", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_hsotg_resources), + .resource = s3c_usb_hsotg_resources, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init dwc2_hsotg_set_platdata(struct dwc2_hsotg_plat *pd) +{ + struct dwc2_hsotg_plat *npd; + + npd = s3c_set_platdata(pd, sizeof(*npd), &s3c_device_usb_hsotg); + + if (!npd->phy_init) + npd->phy_init = s3c_usb_phy_init; + if (!npd->phy_exit) + npd->phy_exit = s3c_usb_phy_exit; +} +#endif /* CONFIG_S3C_DEV_USB_HSOTG */ + +/* USB High Spped 2.0 Device (Gadget) */ + +#ifdef CONFIG_PLAT_S3C24XX +static struct resource s3c_hsudc_resource[] = { + [0] = DEFINE_RES_MEM(S3C2416_PA_HSUDC, S3C2416_SZ_HSUDC), + [1] = DEFINE_RES_IRQ(IRQ_USBD), +}; + +struct platform_device s3c_device_usb_hsudc = { + .name = "s3c-hsudc", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_hsudc_resource), + .resource = s3c_hsudc_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd) +{ + s3c_set_platdata(pd, sizeof(*pd), &s3c_device_usb_hsudc); + pd->phy_init = s3c_hsudc_init_phy; + pd->phy_uninit = s3c_hsudc_uninit_phy; +} +#endif /* CONFIG_PLAT_S3C24XX */ + +/* WDT */ + +#ifdef CONFIG_S3C_DEV_WDT +static struct resource s3c_wdt_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_WDT, SZ_1K), + [1] = DEFINE_RES_IRQ(IRQ_WDT), +}; + +struct platform_device s3c_device_wdt = { + .name = "s3c2410-wdt", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_wdt_resource), + .resource = s3c_wdt_resource, +}; +#endif /* CONFIG_S3C_DEV_WDT */ + +#ifdef CONFIG_S3C64XX_DEV_SPI0 +static struct resource s3c64xx_spi0_resource[] = { + [0] = DEFINE_RES_MEM(S3C_PA_SPI0, SZ_256), + [1] = DEFINE_RES_IRQ(IRQ_SPI0), +}; + +struct platform_device s3c64xx_device_spi0 = { + .name = "s3c6410-spi", + .id = 0, + .num_resources = ARRAY_SIZE(s3c64xx_spi0_resource), + .resource = s3c64xx_spi0_resource, + .dev = { + .dma_mask = &samsung_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + }, +}; + +void __init s3c64xx_spi0_set_platdata(int src_clk_nr, int num_cs) +{ + struct s3c64xx_spi_info pd; + + /* Reject invalid configuration */ + if (!num_cs || src_clk_nr < 0) { + pr_err("%s: Invalid SPI configuration\n", __func__); + return; + } + + pd.num_cs = num_cs; + pd.src_clk_nr = src_clk_nr; + pd.cfg_gpio = s3c64xx_spi0_cfg_gpio; + + s3c_set_platdata(&pd, sizeof(pd), &s3c64xx_device_spi0); +} +#endif /* CONFIG_S3C64XX_DEV_SPI0 */ diff --git a/arch/arm/mach-s3c/devs.h b/arch/arm/mach-s3c/devs.h new file mode 100644 index 000000000..991b9b200 --- /dev/null +++ b/arch/arm/mach-s3c/devs.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright (c) 2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for s3c2410 standard platform devices + */ + +#ifndef __PLAT_DEVS_H +#define __PLAT_DEVS_H __FILE__ + +#include <linux/platform_device.h> + +struct s3c24xx_uart_resources { + struct resource *resources; + unsigned long nr_resources; +}; + +extern struct s3c24xx_uart_resources s3c2410_uart_resources[]; +extern struct s3c24xx_uart_resources s3c64xx_uart_resources[]; + +extern struct platform_device *s3c24xx_uart_devs[]; +extern struct platform_device *s3c24xx_uart_src[]; + +extern struct platform_device s3c64xx_device_ac97; +extern struct platform_device s3c64xx_device_iis0; +extern struct platform_device s3c64xx_device_iis1; +extern struct platform_device s3c64xx_device_iisv4; +extern struct platform_device s3c64xx_device_onenand1; +extern struct platform_device s3c64xx_device_pcm0; +extern struct platform_device s3c64xx_device_pcm1; +extern struct platform_device s3c64xx_device_spi0; + +extern struct platform_device s3c_device_adc; +extern struct platform_device s3c_device_cfcon; +extern struct platform_device s3c_device_fb; +extern struct platform_device s3c_device_hwmon; +extern struct platform_device s3c_device_hsmmc0; +extern struct platform_device s3c_device_hsmmc1; +extern struct platform_device s3c_device_hsmmc2; +extern struct platform_device s3c_device_hsmmc3; +extern struct platform_device s3c_device_i2c0; +extern struct platform_device s3c_device_i2c1; +extern struct platform_device s3c_device_i2c2; +extern struct platform_device s3c_device_i2c3; +extern struct platform_device s3c_device_i2c4; +extern struct platform_device s3c_device_i2c5; +extern struct platform_device s3c_device_i2c6; +extern struct platform_device s3c_device_i2c7; +extern struct platform_device s3c_device_iis; +extern struct platform_device s3c_device_lcd; +extern struct platform_device s3c_device_nand; +extern struct platform_device s3c_device_ohci; +extern struct platform_device s3c_device_onenand; +extern struct platform_device s3c_device_rtc; +extern struct platform_device s3c_device_sdi; +extern struct platform_device s3c_device_spi0; +extern struct platform_device s3c_device_spi1; +extern struct platform_device s3c_device_ts; +extern struct platform_device s3c_device_timer[]; +extern struct platform_device s3c_device_usbgadget; +extern struct platform_device s3c_device_usb_hsotg; +extern struct platform_device s3c_device_usb_hsudc; +extern struct platform_device s3c_device_wdt; + +extern struct platform_device samsung_asoc_idma; +extern struct platform_device samsung_device_keypad; +extern struct platform_device samsung_device_pwm; + +/* s3c2440 specific devices */ + +#ifdef CONFIG_CPU_S3C2440 + +extern struct platform_device s3c_device_camif; +extern struct platform_device s3c_device_ac97; + +#endif + +/** + * s3c_set_platdata() - helper for setting platform data + * @pd: The default platform data for this device. + * @pdsize: The size of the platform data. + * @pdev: Pointer to the device to fill in. + * + * This helper replaces a number of calls that copy and then set the + * platform data of the device. + */ +extern void *s3c_set_platdata(void *pd, size_t pdsize, + struct platform_device *pdev); + +#endif /* __PLAT_DEVS_H */ diff --git a/arch/arm/mach-s3c/dma-s3c24xx.h b/arch/arm/mach-s3c/dma-s3c24xx.h new file mode 100644 index 000000000..25fc9c258 --- /dev/null +++ b/arch/arm/mach-s3c/dma-s3c24xx.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2003-2006 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung S3C24XX DMA support + */ + +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H __FILE__ + +#include <linux/device.h> + +/* 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 */ +}; + +#endif /* __ASM_ARCH_DMA_H */ diff --git a/arch/arm/mach-s3c/dma-s3c64xx.h b/arch/arm/mach-s3c/dma-s3c64xx.h new file mode 100644 index 000000000..40ca8de21 --- /dev/null +++ b/arch/arm/mach-s3c/dma-s3c64xx.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* linux/arch/arm/mach-s3c6400/include/mach/dma.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C6400 - DMA support + */ + +#ifndef __ASM_ARCH_DMA_H +#define __ASM_ARCH_DMA_H __FILE__ + +#define S3C64XX_DMA_CHAN(name) ((unsigned long)(name)) + +/* DMA0/SDMA0 */ +#define DMACH_UART0 "uart0_tx" +#define DMACH_UART0_SRC2 "uart0_rx" +#define DMACH_UART1 "uart1_tx" +#define DMACH_UART1_SRC2 "uart1_rx" +#define DMACH_UART2 "uart2_tx" +#define DMACH_UART2_SRC2 "uart2_rx" +#define DMACH_UART3 "uart3_tx" +#define DMACH_UART3_SRC2 "uart3_rx" +#define DMACH_PCM0_TX "pcm0_tx" +#define DMACH_PCM0_RX "pcm0_rx" +#define DMACH_I2S0_OUT "i2s0_tx" +#define DMACH_I2S0_IN "i2s0_rx" +#define DMACH_SPI0_TX S3C64XX_DMA_CHAN("spi0_tx") +#define DMACH_SPI0_RX S3C64XX_DMA_CHAN("spi0_rx") +#define DMACH_HSI_I2SV40_TX "i2s2_tx" +#define DMACH_HSI_I2SV40_RX "i2s2_rx" + +/* DMA1/SDMA1 */ +#define DMACH_PCM1_TX "pcm1_tx" +#define DMACH_PCM1_RX "pcm1_rx" +#define DMACH_I2S1_OUT "i2s1_tx" +#define DMACH_I2S1_IN "i2s1_rx" +#define DMACH_SPI1_TX S3C64XX_DMA_CHAN("spi1_tx") +#define DMACH_SPI1_RX S3C64XX_DMA_CHAN("spi1_rx") +#define DMACH_AC97_PCMOUT "ac97_out" +#define DMACH_AC97_PCMIN "ac97_in" +#define DMACH_AC97_MICIN "ac97_mic" +#define DMACH_PWM "pwm" +#define DMACH_IRDA "irda" +#define DMACH_EXTERNAL "external" +#define DMACH_SECURITY_RX "sec_rx" +#define DMACH_SECURITY_TX "sec_tx" + +enum dma_ch { + DMACH_MAX = 32 +}; + +#include <linux/amba/pl08x.h> + +#endif /* __ASM_ARCH_IRQ_H */ diff --git a/arch/arm/mach-s3c/dma.h b/arch/arm/mach-s3c/dma.h new file mode 100644 index 000000000..59a4578c5 --- /dev/null +++ b/arch/arm/mach-s3c/dma.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "dma-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "dma-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/fb-core-s3c24xx.h b/arch/arm/mach-s3c/fb-core-s3c24xx.h new file mode 100644 index 000000000..0e07f3ba4 --- /dev/null +++ b/arch/arm/mach-s3c/fb-core-s3c24xx.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2010 Samsung Electronics Co., Ltd. + * Pawel Osciak <p.osciak@samsung.com> + * + * Samsung framebuffer driver core functions + */ +#ifndef __ASM_PLAT_FB_CORE_S3C24XX_H +#define __ASM_PLAT_FB_CORE_S3C24XX_H __FILE__ + +/* + * These functions are only for use with the core support code, such as + * the CPU-specific initialization code. + */ + +/* Re-define device name depending on support. */ +static inline void s3c_fb_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_FB + s3c_device_fb.name = name; +#endif +} + +#endif /* __ASM_PLAT_FB_CORE_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/fb.h b/arch/arm/mach-s3c/fb.h new file mode 100644 index 000000000..615d381ae --- /dev/null +++ b/arch/arm/mach-s3c/fb.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - FB platform data definitions + */ + +#ifndef __PLAT_S3C_FB_H +#define __PLAT_S3C_FB_H __FILE__ + +#include <linux/platform_data/video_s3c.h> + +/** + * s3c_fb_set_platdata() - Setup the FB device with platform data. + * @pd: The platform data to set. The data is copied from the passed structure + * so the machine data can mark the data __initdata so that any unused + * machines will end up dumping their data at runtime. + */ +extern void s3c_fb_set_platdata(struct s3c_fb_platdata *pd); + +/** + * s3c64xx_fb_gpio_setup_24bpp() - S3C64XX setup function for 24bpp LCD + * + * Initialise the GPIO for an 24bpp LCD display on the RGB interface. + */ +extern void s3c64xx_fb_gpio_setup_24bpp(void); + +#endif /* __PLAT_S3C_FB_H */ diff --git a/arch/arm/mach-s3c/gpio-cfg-helpers.h b/arch/arm/mach-s3c/gpio-cfg-helpers.h new file mode 100644 index 000000000..db0c56f5c --- /dev/null +++ b/arch/arm/mach-s3c/gpio-cfg-helpers.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * Samsung Platform - GPIO pin configuration helper definitions + */ + +/* This is meant for core cpu support, machine or other driver files + * should not be including this header. + */ + +#ifndef __PLAT_GPIO_CFG_HELPERS_H +#define __PLAT_GPIO_CFG_HELPERS_H __FILE__ + +/* As a note, all gpio configuration functions are entered exclusively, either + * with the relevant lock held or the system prevented from doing anything else + * by disabling interrupts. +*/ + +static inline int samsung_gpio_do_setcfg(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int config) +{ + return (chip->config->set_config)(chip, off, config); +} + +static inline unsigned samsung_gpio_do_getcfg(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return (chip->config->get_config)(chip, off); +} + +static inline int samsung_gpio_do_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return (chip->config->set_pull)(chip, off, pull); +} + +static inline samsung_gpio_pull_t samsung_gpio_do_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return chip->config->get_pull(chip, off); +} + +/* Pull-{up,down} resistor controls. + * + * S3C2410,S3C2440 = Pull-UP, + * S3C2412,S3C2413 = Pull-Down + * S3C6400,S3C6410 = Pull-Both [None,Down,Up,Undef] + * S3C2443 = Pull-Both [not same as S3C6400] + */ + +/** + * s3c24xx_gpio_setpull_1up() - Pull configuration for choice of up or none. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @param: pull: The pull mode being requested. + * + * This is a helper function for the case where we have GPIOs with one + * bit configuring the presence of a pull-up resistor. + */ +extern int s3c24xx_gpio_setpull_1up(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * s3c24xx_gpio_setpull_1down() - Pull configuration for choice of down or none + * @chip: The gpio chip that is being configured + * @off: The offset for the GPIO being configured + * @param: pull: The pull mode being requested + * + * This is a helper function for the case where we have GPIOs with one + * bit configuring the presence of a pull-down resistor. + */ +extern int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * samsung_gpio_setpull_upown() - Pull configuration for choice of up, + * down or none + * + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @param: pull: The pull mode being requested. + * + * This is a helper function for the case where we have GPIOs with two + * bits configuring the presence of a pull resistor, in the following + * order: + * 00 = No pull resistor connected + * 01 = Pull-up resistor connected + * 10 = Pull-down resistor connected + */ +extern int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * samsung_gpio_getpull_updown() - Get configuration for choice of up, + * down or none + * + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-{up,down} resistor + * for the given GPIO in the same case as samsung_gpio_setpull_upown. +*/ +extern samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, + unsigned int off); + +/** + * s3c24xx_gpio_getpull_1up() - Get configuration for choice of up or none + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-up resistor for the + * given GPIO in the same case as s3c24xx_gpio_setpull_1up. +*/ +extern samsung_gpio_pull_t s3c24xx_gpio_getpull_1up(struct samsung_gpio_chip *chip, + unsigned int off); + +/** + * s3c24xx_gpio_getpull_1down() - Get configuration for choice of down or none + * @chip: The gpio chip that the GPIO pin belongs to + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-down resistor for the + * given GPIO in the same case as s3c24xx_gpio_setpull_1down. +*/ +extern samsung_gpio_pull_t s3c24xx_gpio_getpull_1down(struct samsung_gpio_chip *chip, + unsigned int off); + +/** + * s3c2443_gpio_setpull() - Pull configuration for s3c2443. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @param: pull: The pull mode being requested. + * + * This is a helper function for the case where we have GPIOs with two + * bits configuring the presence of a pull resistor, in the following + * order: + * 00 = Pull-up resistor connected + * 10 = Pull-down resistor connected + * x1 = No pull up resistor + */ +extern int s3c2443_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull); + +/** + * s3c2443_gpio_getpull() - Get configuration for s3c2443 pull resistors + * @chip: The gpio chip that the GPIO pin belongs to. + * @off: The offset to the pin to get the configuration of. + * + * This helper function reads the state of the pull-{up,down} resistor for the + * given GPIO in the same case as samsung_gpio_setpull_upown. +*/ +extern samsung_gpio_pull_t s3c2443_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off); + +#endif /* __PLAT_GPIO_CFG_HELPERS_H */ diff --git a/arch/arm/mach-s3c/gpio-cfg.h b/arch/arm/mach-s3c/gpio-cfg.h new file mode 100644 index 000000000..469c220e0 --- /dev/null +++ b/arch/arm/mach-s3c/gpio-cfg.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - GPIO pin configuration + */ + +/* This file contains the necessary definitions to get the basic gpio + * pin configuration done such as setting a pin to input or output or + * changing the pull-{up,down} configurations. + */ + +/* Note, this interface is being added to the s3c64xx arch first and will + * be added to the s3c24xx systems later. + */ + +#ifndef __PLAT_GPIO_CFG_H +#define __PLAT_GPIO_CFG_H __FILE__ + +#include <linux/types.h> + +typedef unsigned int __bitwise samsung_gpio_pull_t; + +/* forward declaration if gpio-core.h hasn't been included */ +struct samsung_gpio_chip; + +/** + * struct samsung_gpio_cfg GPIO configuration + * @cfg_eint: Configuration setting when used for external interrupt source + * @get_pull: Read the current pull configuration for the GPIO + * @set_pull: Set the current pull configuration for the GPIO + * @set_config: Set the current configuration for the GPIO + * @get_config: Read the current configuration for the GPIO + * + * Each chip can have more than one type of GPIO bank available and some + * have different capabilites even when they have the same control register + * layouts. Provide an point to vector control routine and provide any + * per-bank configuration information that other systems such as the + * external interrupt code will need. + * + * @sa samsung_gpio_cfgpin + * @sa s3c_gpio_getcfg + * @sa s3c_gpio_setpull + * @sa s3c_gpio_getpull + */ +struct samsung_gpio_cfg { + unsigned int cfg_eint; + + samsung_gpio_pull_t (*get_pull)(struct samsung_gpio_chip *chip, unsigned offs); + int (*set_pull)(struct samsung_gpio_chip *chip, unsigned offs, + samsung_gpio_pull_t pull); + + unsigned (*get_config)(struct samsung_gpio_chip *chip, unsigned offs); + int (*set_config)(struct samsung_gpio_chip *chip, unsigned offs, + unsigned config); +}; + +#define S3C_GPIO_SPECIAL_MARK (0xfffffff0) +#define S3C_GPIO_SPECIAL(x) (S3C_GPIO_SPECIAL_MARK | (x)) + +/* Defines for generic pin configurations */ +#define S3C_GPIO_INPUT (S3C_GPIO_SPECIAL(0)) +#define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1)) +#define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x)) + +#define samsung_gpio_is_cfg_special(_cfg) \ + (((_cfg) & S3C_GPIO_SPECIAL_MARK) == S3C_GPIO_SPECIAL_MARK) + +/** + * s3c_gpio_cfgpin() - Change the GPIO function of a pin. + * @pin pin The pin number to configure. + * @to to The configuration for the pin's function. + * + * Configure which function is actually connected to the external + * pin, such as an gpio input, output or some form of special function + * connected to an internal peripheral block. + * + * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT + * or S3C_GPIO_SFN() to indicate one of the possible values that the helper + * will then generate the correct bit mask and shift for the configuration. + * + * If a bank of GPIOs all needs to be set to special-function 2, then + * the following code will work: + * + * for (gpio = start; gpio < end; gpio++) + * s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + * + * The @to parameter can also be a specific value already shifted to the + * correct position in the control register, although these are discouraged + * in newer kernels and are only being kept for compatibility. + */ +extern int s3c_gpio_cfgpin(unsigned int pin, unsigned int to); + +/** + * s3c_gpio_getcfg - Read the current function for a GPIO pin + * @pin: The pin to read the configuration value for. + * + * Read the configuration state of the given @pin, returning a value that + * could be passed back to s3c_gpio_cfgpin(). + * + * @sa s3c_gpio_cfgpin + */ +extern unsigned s3c_gpio_getcfg(unsigned int pin); + +/** + * s3c_gpio_cfgpin_range() - Change the GPIO function for configuring pin range + * @start: The pin number to start at + * @nr: The number of pins to configure from @start. + * @cfg: The configuration for the pin's function + * + * Call s3c_gpio_cfgpin() for the @nr pins starting at @start. + * + * @sa s3c_gpio_cfgpin. + */ +extern int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, + unsigned int cfg); + +/* Define values for the pull-{up,down} available for each gpio pin. + * + * These values control the state of the weak pull-{up,down} resistors + * available on most pins on the S3C series. Not all chips support both + * up or down settings, and it may be dependent on the chip that is being + * used to whether the particular mode is available. + */ +#define S3C_GPIO_PULL_NONE ((__force samsung_gpio_pull_t)0x00) +#define S3C_GPIO_PULL_DOWN ((__force samsung_gpio_pull_t)0x01) +#define S3C_GPIO_PULL_UP ((__force samsung_gpio_pull_t)0x02) + +/** + * s3c_gpio_setpull() - set the state of a gpio pin pull resistor + * @pin: The pin number to configure the pull resistor. + * @pull: The configuration for the pull resistor. + * + * This function sets the state of the pull-{up,down} resistor for the + * specified pin. It will return 0 if successful, or a negative error + * code if the pin cannot support the requested pull setting. + * + * @pull is one of S3C_GPIO_PULL_NONE, S3C_GPIO_PULL_DOWN or S3C_GPIO_PULL_UP. +*/ +extern int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull); + +/** + * s3c_gpio_getpull() - get the pull resistor state of a gpio pin + * @pin: The pin number to get the settings for + * + * Read the pull resistor value for the specified pin. +*/ +extern samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin); + +/* configure `all` aspects of an gpio */ + +/** + * s3c_gpio_cfgall_range() - configure range of gpio functtion and pull. + * @start: The gpio number to start at. + * @nr: The number of gpio to configure from @start. + * @cfg: The configuration to use + * @pull: The pull setting to use. + * + * Run s3c_gpio_cfgpin() and s3c_gpio_setpull() over the gpio range starting + * @gpio and running for @size. + * + * @sa s3c_gpio_cfgpin + * @sa s3c_gpio_setpull + * @sa s3c_gpio_cfgpin_range + */ +extern int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, + unsigned int cfg, samsung_gpio_pull_t pull); + +static inline int s3c_gpio_cfgrange_nopull(unsigned int pin, unsigned int size, + unsigned int cfg) +{ + return s3c_gpio_cfgall_range(pin, size, cfg, S3C_GPIO_PULL_NONE); +} + +#endif /* __PLAT_GPIO_CFG_H */ diff --git a/arch/arm/mach-s3c/gpio-core.h b/arch/arm/mach-s3c/gpio-core.h new file mode 100644 index 000000000..b361c8c0d --- /dev/null +++ b/arch/arm/mach-s3c/gpio-core.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - GPIO core + */ + +#ifndef __PLAT_SAMSUNG_GPIO_CORE_H +#define __PLAT_SAMSUNG_GPIO_CORE_H + +/* Bring in machine-local definitions, especially S3C_GPIO_END */ +#include "gpio-samsung.h" +#include <linux/gpio/driver.h> + +#define GPIOCON_OFF (0x00) +#define GPIODAT_OFF (0x04) + +#define con_4bit_shift(__off) ((__off) * 4) + +/* Define the core gpiolib support functions that the s3c platforms may + * need to extend or change depending on the hardware and the s3c chip + * selected at build or found at run time. + * + * These definitions are not intended for driver inclusion, there is + * nothing here that should not live outside the platform and core + * specific code. +*/ + +struct samsung_gpio_chip; + +/** + * struct samsung_gpio_pm - power management (suspend/resume) information + * @save: Routine to save the state of the GPIO block + * @resume: Routine to resume the GPIO block. + */ +struct samsung_gpio_pm { + void (*save)(struct samsung_gpio_chip *chip); + void (*resume)(struct samsung_gpio_chip *chip); +}; + +struct samsung_gpio_cfg; + +/** + * struct samsung_gpio_chip - wrapper for specific implementation of gpio + * @chip: The chip structure to be exported via gpiolib. + * @base: The base pointer to the gpio configuration registers. + * @group: The group register number for gpio interrupt support. + * @irq_base: The base irq number. + * @config: special function and pull-resistor control information. + * @lock: Lock for exclusive access to this gpio bank. + * @pm_save: Save information for suspend/resume support. + * @bitmap_gpio_int: Bitmap for representing GPIO interrupt or not. + * + * This wrapper provides the necessary information for the Samsung + * specific gpios being registered with gpiolib. + * + * The lock protects each gpio bank from multiple access of the shared + * configuration registers, or from reading of data whilst another thread + * is writing to the register set. + * + * Each chip has its own lock to avoid any contention between different + * CPU cores trying to get one lock for different GPIO banks, where each + * bank of GPIO has its own register space and configuration registers. + */ +struct samsung_gpio_chip { + struct gpio_chip chip; + struct samsung_gpio_cfg *config; + struct samsung_gpio_pm *pm; + void __iomem *base; + int irq_base; + int group; + spinlock_t lock; +#ifdef CONFIG_PM + u32 pm_save[4]; +#endif + u32 bitmap_gpio_int; +}; + +static inline struct samsung_gpio_chip *to_samsung_gpio(struct gpio_chip *gpc) +{ + return container_of(gpc, struct samsung_gpio_chip, chip); +} + +/** + * samsung_gpiolib_to_irq - convert gpio pin to irq number + * @chip: The gpio chip that the pin belongs to. + * @offset: The offset of the pin in the chip. + * + * This helper returns the irq number calculated from the chip->irq_base and + * the provided offset. + */ +extern int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset); + +/* exported for core SoC support to change */ +extern struct samsung_gpio_cfg s3c24xx_gpiocfg_default; + +#ifdef CONFIG_S3C_GPIO_TRACK +extern struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; + +static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int chip) +{ + return (chip < S3C_GPIO_END) ? s3c_gpios[chip] : NULL; +} +#else +/* machine specific code should provide samsung_gpiolib_getchip */ + +extern struct samsung_gpio_chip s3c24xx_gpios[]; + +static inline struct samsung_gpio_chip *samsung_gpiolib_getchip(unsigned int pin) +{ + struct samsung_gpio_chip *chip; + + if (pin > S3C_GPIO_END) + return NULL; + + chip = &s3c24xx_gpios[pin/32]; + return ((pin - chip->chip.base) < chip->chip.ngpio) ? chip : NULL; +} + +static inline void s3c_gpiolib_track(struct samsung_gpio_chip *chip) { } +#endif + +#ifdef CONFIG_PM +extern struct samsung_gpio_pm samsung_gpio_pm_1bit; +extern struct samsung_gpio_pm samsung_gpio_pm_2bit; +extern struct samsung_gpio_pm samsung_gpio_pm_4bit; +#define __gpio_pm(x) x +#else +#define samsung_gpio_pm_1bit NULL +#define samsung_gpio_pm_2bit NULL +#define samsung_gpio_pm_4bit NULL +#define __gpio_pm(x) NULL + +#endif /* CONFIG_PM */ + +/* locking wrappers to deal with multiple access to the same gpio bank */ +#define samsung_gpio_lock(_oc, _fl) spin_lock_irqsave(&(_oc)->lock, _fl) +#define samsung_gpio_unlock(_oc, _fl) spin_unlock_irqrestore(&(_oc)->lock, _fl) + +#endif /* __PLAT_SAMSUNG_GPIO_CORE_H */ diff --git a/arch/arm/mach-s3c/gpio-samsung-s3c24xx.h b/arch/arm/mach-s3c/gpio-samsung-s3c24xx.h new file mode 100644 index 000000000..c29fdc95f --- /dev/null +++ b/arch/arm/mach-s3c/gpio-samsung-s3c24xx.h @@ -0,0 +1,103 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - GPIO lib support + */ + +/* some boards require extra gpio capacity to support external + * devices that need GPIO. + */ + +#ifndef GPIO_SAMSUNG_S3C24XX_H +#define GPIO_SAMSUNG_S3C24XX_H + +#include "map.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-s3c/gpio-samsung-s3c64xx.h b/arch/arm/mach-s3c/gpio-samsung-s3c64xx.h new file mode 100644 index 000000000..8ed144a0d --- /dev/null +++ b/arch/arm/mach-s3c/gpio-samsung-s3c64xx.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C6400 - GPIO lib support + */ + +#ifndef GPIO_SAMSUNG_S3C64XX_H +#define GPIO_SAMSUNG_S3C64XX_H + +#ifdef CONFIG_GPIO_SAMSUNG + +/* GPIO bank sizes */ +#define S3C64XX_GPIO_A_NR (8) +#define S3C64XX_GPIO_B_NR (7) +#define S3C64XX_GPIO_C_NR (8) +#define S3C64XX_GPIO_D_NR (5) +#define S3C64XX_GPIO_E_NR (5) +#define S3C64XX_GPIO_F_NR (16) +#define S3C64XX_GPIO_G_NR (7) +#define S3C64XX_GPIO_H_NR (10) +#define S3C64XX_GPIO_I_NR (16) +#define S3C64XX_GPIO_J_NR (12) +#define S3C64XX_GPIO_K_NR (16) +#define S3C64XX_GPIO_L_NR (15) +#define S3C64XX_GPIO_M_NR (6) +#define S3C64XX_GPIO_N_NR (16) +#define S3C64XX_GPIO_O_NR (16) +#define S3C64XX_GPIO_P_NR (15) +#define S3C64XX_GPIO_Q_NR (9) + +/* GPIO bank numbes */ + +/* CONFIG_S3C_GPIO_SPACE allows the user to select extra + * space for debugging purposes so that any accidental + * change from one gpio bank to another can be caught. +*/ + +#define S3C64XX_GPIO_NEXT(__gpio) \ + ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1) + +enum s3c_gpio_number { + S3C64XX_GPIO_A_START = 0, + S3C64XX_GPIO_B_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_A), + S3C64XX_GPIO_C_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_B), + S3C64XX_GPIO_D_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_C), + S3C64XX_GPIO_E_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_D), + S3C64XX_GPIO_F_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_E), + S3C64XX_GPIO_G_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_F), + S3C64XX_GPIO_H_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_G), + S3C64XX_GPIO_I_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_H), + S3C64XX_GPIO_J_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_I), + S3C64XX_GPIO_K_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_J), + S3C64XX_GPIO_L_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_K), + S3C64XX_GPIO_M_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_L), + S3C64XX_GPIO_N_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_M), + S3C64XX_GPIO_O_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_N), + S3C64XX_GPIO_P_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_O), + S3C64XX_GPIO_Q_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_P), +}; + +/* S3C64XX GPIO number definitions. */ + +#define S3C64XX_GPA(_nr) (S3C64XX_GPIO_A_START + (_nr)) +#define S3C64XX_GPB(_nr) (S3C64XX_GPIO_B_START + (_nr)) +#define S3C64XX_GPC(_nr) (S3C64XX_GPIO_C_START + (_nr)) +#define S3C64XX_GPD(_nr) (S3C64XX_GPIO_D_START + (_nr)) +#define S3C64XX_GPE(_nr) (S3C64XX_GPIO_E_START + (_nr)) +#define S3C64XX_GPF(_nr) (S3C64XX_GPIO_F_START + (_nr)) +#define S3C64XX_GPG(_nr) (S3C64XX_GPIO_G_START + (_nr)) +#define S3C64XX_GPH(_nr) (S3C64XX_GPIO_H_START + (_nr)) +#define S3C64XX_GPI(_nr) (S3C64XX_GPIO_I_START + (_nr)) +#define S3C64XX_GPJ(_nr) (S3C64XX_GPIO_J_START + (_nr)) +#define S3C64XX_GPK(_nr) (S3C64XX_GPIO_K_START + (_nr)) +#define S3C64XX_GPL(_nr) (S3C64XX_GPIO_L_START + (_nr)) +#define S3C64XX_GPM(_nr) (S3C64XX_GPIO_M_START + (_nr)) +#define S3C64XX_GPN(_nr) (S3C64XX_GPIO_N_START + (_nr)) +#define S3C64XX_GPO(_nr) (S3C64XX_GPIO_O_START + (_nr)) +#define S3C64XX_GPP(_nr) (S3C64XX_GPIO_P_START + (_nr)) +#define S3C64XX_GPQ(_nr) (S3C64XX_GPIO_Q_START + (_nr)) + +/* the end of the S3C64XX specific gpios */ +#define S3C64XX_GPIO_END (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1) +#define S3C_GPIO_END S3C64XX_GPIO_END + +/* define the number of gpios we need to the one after the GPQ() range */ +#define GPIO_BOARD_START (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1) + +#endif /* GPIO_SAMSUNG */ +#endif /* GPIO_SAMSUNG_S3C64XX_H */ + diff --git a/arch/arm/mach-s3c/gpio-samsung.c b/arch/arm/mach-s3c/gpio-samsung.c new file mode 100644 index 000000000..b7fc7c413 --- /dev/null +++ b/arch/arm/mach-s3c/gpio-samsung.c @@ -0,0 +1,1325 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2009-2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com/ +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Samsung - GPIOlib support + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/ioport.h> +#include <linux/of.h> +#include <linux/slab.h> +#include <linux/of_address.h> + +#include <asm/irq.h> + +#include "irqs.h" +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "gpio-core.h" +#include "gpio-cfg.h" +#include "gpio-cfg-helpers.h" +#include "hardware-s3c24xx.h" +#include "pm.h" + +int samsung_gpio_setpull_updown(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + void __iomem *reg = chip->base + 0x08; + int shift = off * 2; + u32 pup; + + pup = __raw_readl(reg); + pup &= ~(3 << shift); + pup |= pull << shift; + __raw_writel(pup, reg); + + return 0; +} + +samsung_gpio_pull_t samsung_gpio_getpull_updown(struct samsung_gpio_chip *chip, + unsigned int off) +{ + void __iomem *reg = chip->base + 0x08; + int shift = off * 2; + u32 pup = __raw_readl(reg); + + pup >>= shift; + pup &= 0x3; + + return (__force samsung_gpio_pull_t)pup; +} + +int s3c2443_gpio_setpull(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + switch (pull) { + case S3C_GPIO_PULL_NONE: + pull = 0x01; + break; + case S3C_GPIO_PULL_UP: + pull = 0x00; + break; + case S3C_GPIO_PULL_DOWN: + pull = 0x02; + break; + } + return samsung_gpio_setpull_updown(chip, off, pull); +} + +samsung_gpio_pull_t s3c2443_gpio_getpull(struct samsung_gpio_chip *chip, + unsigned int off) +{ + samsung_gpio_pull_t pull; + + pull = samsung_gpio_getpull_updown(chip, off); + + switch (pull) { + case 0x00: + pull = S3C_GPIO_PULL_UP; + break; + case 0x01: + case 0x03: + pull = S3C_GPIO_PULL_NONE; + break; + case 0x02: + pull = S3C_GPIO_PULL_DOWN; + break; + } + + return pull; +} + +static int s3c24xx_gpio_setpull_1(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull, + samsung_gpio_pull_t updown) +{ + void __iomem *reg = chip->base + 0x08; + u32 pup = __raw_readl(reg); + + if (pull == updown) + pup &= ~(1 << off); + else if (pull == S3C_GPIO_PULL_NONE) + pup |= (1 << off); + else + return -EINVAL; + + __raw_writel(pup, reg); + return 0; +} + +static samsung_gpio_pull_t s3c24xx_gpio_getpull_1(struct samsung_gpio_chip *chip, + unsigned int off, + samsung_gpio_pull_t updown) +{ + void __iomem *reg = chip->base + 0x08; + u32 pup = __raw_readl(reg); + + pup &= (1 << off); + return pup ? S3C_GPIO_PULL_NONE : updown; +} + +samsung_gpio_pull_t s3c24xx_gpio_getpull_1up(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return s3c24xx_gpio_getpull_1(chip, off, S3C_GPIO_PULL_UP); +} + +int s3c24xx_gpio_setpull_1up(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_UP); +} + +samsung_gpio_pull_t s3c24xx_gpio_getpull_1down(struct samsung_gpio_chip *chip, + unsigned int off) +{ + return s3c24xx_gpio_getpull_1(chip, off, S3C_GPIO_PULL_DOWN); +} + +int s3c24xx_gpio_setpull_1down(struct samsung_gpio_chip *chip, + unsigned int off, samsung_gpio_pull_t pull) +{ + return s3c24xx_gpio_setpull_1(chip, off, pull, S3C_GPIO_PULL_DOWN); +} + +/* + * samsung_gpio_setcfg_2bit - Samsung 2bit style GPIO configuration. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register + * has two bits of configuration per gpio, which have the following + * functions: + * 00 = input + * 01 = output + * 1x = special function + */ + +static int samsung_gpio_setcfg_2bit(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = off * 2; + u32 con; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + if (cfg > 3) + return -EINVAL; + + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0x3 << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * samsung_gpio_getcfg_2bit - Samsung 2bit style GPIO configuration read. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of samsung_gpio_setcfg_2bit(). Will return a value which + * could be directly passed back to samsung_gpio_setcfg_2bit(), from the + * S3C_GPIO_SPECIAL() macro. + */ + +static unsigned int samsung_gpio_getcfg_2bit(struct samsung_gpio_chip *chip, + unsigned int off) +{ + u32 con; + + con = __raw_readl(chip->base); + con >>= off * 2; + con &= 3; + + /* this conversion works for IN and OUT as well as special mode */ + return S3C_GPIO_SPECIAL(con); +} + +/* + * samsung_gpio_setcfg_4bit - Samsung 4bit single register GPIO config. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register has 4 bits + * of control per GPIO, generally in the form of: + * 0000 = Input + * 0001 = Output + * others = Special functions (dependent on bank) + * + * Note, since the code to deal with the case where there are two control + * registers instead of one, we do not have a separate set of functions for + * each case. + */ + +static int samsung_gpio_setcfg_4bit(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = (off & 7) * 4; + u32 con; + + if (off < 8 && chip->chip.ngpio > 8) + reg -= 4; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0xf << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * samsung_gpio_getcfg_4bit - Samsung 4bit single register GPIO config read. + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of samsung_gpio_setcfg_4bit(), turning a gpio configuration + * register setting into a value the software can use, such as could be passed + * to samsung_gpio_setcfg_4bit(). + * + * @sa samsung_gpio_getcfg_2bit + */ + +static unsigned samsung_gpio_getcfg_4bit(struct samsung_gpio_chip *chip, + unsigned int off) +{ + void __iomem *reg = chip->base; + unsigned int shift = (off & 7) * 4; + u32 con; + + if (off < 8 && chip->chip.ngpio > 8) + reg -= 4; + + con = __raw_readl(reg); + con >>= shift; + con &= 0xf; + + /* this conversion works for IN and OUT as well as special mode */ + return S3C_GPIO_SPECIAL(con); +} + +#ifdef CONFIG_PLAT_S3C24XX +/* + * s3c24xx_gpio_setcfg_abank - S3C24XX style GPIO configuration (Bank A) + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * @cfg: The configuration value to set. + * + * This helper deal with the GPIO cases where the control register + * has one bit of configuration for the gpio, where setting the bit + * means the pin is in special function mode and unset means output. + */ + +static int s3c24xx_gpio_setcfg_abank(struct samsung_gpio_chip *chip, + unsigned int off, unsigned int cfg) +{ + void __iomem *reg = chip->base; + unsigned int shift = off; + u32 con; + + if (samsung_gpio_is_cfg_special(cfg)) { + cfg &= 0xf; + + /* Map output to 0, and SFN2 to 1 */ + cfg -= 1; + if (cfg > 1) + return -EINVAL; + + cfg <<= shift; + } + + con = __raw_readl(reg); + con &= ~(0x1 << shift); + con |= cfg; + __raw_writel(con, reg); + + return 0; +} + +/* + * s3c24xx_gpio_getcfg_abank - S3C24XX style GPIO configuration read (Bank A) + * @chip: The gpio chip that is being configured. + * @off: The offset for the GPIO being configured. + * + * The reverse of s3c24xx_gpio_setcfg_abank() turning an GPIO into a usable + * GPIO configuration value. + * + * @sa samsung_gpio_getcfg_2bit + * @sa samsung_gpio_getcfg_4bit + */ + +static unsigned s3c24xx_gpio_getcfg_abank(struct samsung_gpio_chip *chip, + unsigned int off) +{ + u32 con; + + con = __raw_readl(chip->base); + con >>= off; + con &= 1; + con++; + + return S3C_GPIO_SFN(con); +} +#endif + +static void __init samsung_gpiolib_set_cfg(struct samsung_gpio_cfg *chipcfg, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chipcfg++) { + if (!chipcfg->set_config) + chipcfg->set_config = samsung_gpio_setcfg_4bit; + if (!chipcfg->get_config) + chipcfg->get_config = samsung_gpio_getcfg_4bit; + if (!chipcfg->set_pull) + chipcfg->set_pull = samsung_gpio_setpull_updown; + if (!chipcfg->get_pull) + chipcfg->get_pull = samsung_gpio_getpull_updown; + } +} + +struct samsung_gpio_cfg s3c24xx_gpiocfg_default = { + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, +}; + +#ifdef CONFIG_PLAT_S3C24XX +static struct samsung_gpio_cfg s3c24xx_gpiocfg_banka = { + .set_config = s3c24xx_gpio_setcfg_abank, + .get_config = s3c24xx_gpio_getcfg_abank, +}; +#endif + +static struct samsung_gpio_cfg samsung_gpio_cfgs[] = { + [0] = { + .cfg_eint = 0x0, + }, + [1] = { + .cfg_eint = 0x3, + }, + [2] = { + .cfg_eint = 0x7, + }, + [3] = { + .cfg_eint = 0xF, + }, + [4] = { + .cfg_eint = 0x0, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, + [5] = { + .cfg_eint = 0x2, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, + [6] = { + .cfg_eint = 0x3, + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, + [7] = { + .set_config = samsung_gpio_setcfg_2bit, + .get_config = samsung_gpio_getcfg_2bit, + }, +}; + +/* + * Default routines for controlling GPIO, based on the original S3C24XX + * GPIO functions which deal with the case where each gpio bank of the + * chip is as following: + * + * base + 0x00: Control register, 2 bits per gpio + * gpio n: 2 bits starting at (2*n) + * 00 = input, 01 = output, others mean special-function + * base + 0x04: Data register, 1 bit per gpio + * bit n: data bit n +*/ + +static int samsung_gpiolib_2bit_input(struct gpio_chip *chip, unsigned offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long con; + + samsung_gpio_lock(ourchip, flags); + + con = __raw_readl(base + 0x00); + con &= ~(3 << (offset * 2)); + + __raw_writel(con, base + 0x00); + + samsung_gpio_unlock(ourchip, flags); + return 0; +} + +static int samsung_gpiolib_2bit_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + unsigned long con; + + samsung_gpio_lock(ourchip, flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + __raw_writel(dat, base + 0x04); + + con = __raw_readl(base + 0x00); + con &= ~(3 << (offset * 2)); + con |= 1 << (offset * 2); + + __raw_writel(con, base + 0x00); + __raw_writel(dat, base + 0x04); + + samsung_gpio_unlock(ourchip, flags); + return 0; +} + +/* + * The samsung_gpiolib_4bit routines are to control the gpio banks where + * the gpio configuration register (GPxCON) has 4 bits per GPIO, as the + * following example: + * + * base + 0x00: Control register, 4 bits per gpio + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x04: Data register, 1 bit per gpio + * bit n: data bit n + * + * Note, since the data register is one bit per gpio and is at base + 0x4 + * we can use samsung_gpiolib_get and samsung_gpiolib_set to change the + * state of the output. + */ + +static int samsung_gpiolib_4bit_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + + con = __raw_readl(base + GPIOCON_OFF); + if (ourchip->bitmap_gpio_int & BIT(offset)) + con |= 0xf << con_4bit_shift(offset); + else + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, base + GPIOCON_OFF); + + pr_debug("%s: %p: CON now %08lx\n", __func__, base, con); + + return 0; +} + +static int samsung_gpiolib_4bit_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + unsigned long dat; + + con = __raw_readl(base + GPIOCON_OFF); + con &= ~(0xf << con_4bit_shift(offset)); + con |= 0x1 << con_4bit_shift(offset); + + dat = __raw_readl(base + GPIODAT_OFF); + + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + GPIODAT_OFF); + __raw_writel(con, base + GPIOCON_OFF); + __raw_writel(dat, base + GPIODAT_OFF); + + pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +/* + * The next set of routines are for the case where the GPIO configuration + * registers are 4 bits per GPIO but there is more than one register (the + * bank has more than 8 GPIOs. + * + * This case is the similar to the 4 bit case, but the registers are as + * follows: + * + * base + 0x00: Control register, 4 bits per gpio (lower 8 GPIOs) + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x04: Control register, 4 bits per gpio (up to 8 additions GPIOs) + * gpio n: 4 bits starting at (4*n) + * 0000 = input, 0001 = output, others mean special-function + * base + 0x08: Data register, 1 bit per gpio + * bit n: data bit n + * + * To allow us to use the samsung_gpiolib_get and samsung_gpiolib_set + * routines we store the 'base + 0x4' address so that these routines see + * the data register at ourchip->base + 0x04. + */ + +static int samsung_gpiolib_4bit2_input(struct gpio_chip *chip, + unsigned int offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + + if (offset > 7) + offset -= 8; + else + regcon -= 4; + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, regcon); + + pr_debug("%s: %p: CON %08lx\n", __func__, base, con); + + return 0; +} + +static int samsung_gpiolib_4bit2_output(struct gpio_chip *chip, + unsigned int offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + void __iomem *regcon = base; + unsigned long con; + unsigned long dat; + unsigned con_offset = offset; + + if (con_offset > 7) + con_offset -= 8; + else + regcon -= 4; + + con = __raw_readl(regcon); + con &= ~(0xf << con_4bit_shift(con_offset)); + con |= 0x1 << con_4bit_shift(con_offset); + + dat = __raw_readl(base + GPIODAT_OFF); + + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + GPIODAT_OFF); + __raw_writel(con, regcon); + __raw_writel(dat, base + GPIODAT_OFF); + + pr_debug("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +#ifdef CONFIG_PLAT_S3C24XX +/* The next set of routines are for the case of s3c24xx bank a */ + +static int s3c24xx_gpiolib_banka_input(struct gpio_chip *chip, unsigned offset) +{ + return -EINVAL; +} + +static int s3c24xx_gpiolib_banka_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + unsigned long con; + + local_irq_save(flags); + + con = __raw_readl(base + 0x00); + dat = __raw_readl(base + 0x04); + + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + + __raw_writel(dat, base + 0x04); + + con &= ~(1 << offset); + + __raw_writel(con, base + 0x00); + __raw_writel(dat, base + 0x04); + + local_irq_restore(flags); + return 0; +} +#endif + +static void samsung_gpiolib_set(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long flags; + unsigned long dat; + + samsung_gpio_lock(ourchip, flags); + + dat = __raw_readl(base + 0x04); + dat &= ~(1 << offset); + if (value) + dat |= 1 << offset; + __raw_writel(dat, base + 0x04); + + samsung_gpio_unlock(ourchip, flags); +} + +static int samsung_gpiolib_get(struct gpio_chip *chip, unsigned offset) +{ + struct samsung_gpio_chip *ourchip = to_samsung_gpio(chip); + unsigned long val; + + val = __raw_readl(ourchip->base + 0x04); + val >>= offset; + val &= 1; + + return val; +} + +/* + * CONFIG_S3C_GPIO_TRACK enables the tracking of the s3c specific gpios + * for use with the configuration calls, and other parts of the s3c gpiolib + * support code. + * + * Not all s3c support code will need this, as some configurations of cpu + * may only support one or two different configuration options and have an + * easy gpio to samsung_gpio_chip mapping function. If this is the case, then + * the machine support file should provide its own samsung_gpiolib_getchip() + * and any other necessary functions. + */ + +#ifdef CONFIG_S3C_GPIO_TRACK +struct samsung_gpio_chip *s3c_gpios[S3C_GPIO_END]; + +static __init void s3c_gpiolib_track(struct samsung_gpio_chip *chip) +{ + unsigned int gpn; + int i; + + gpn = chip->chip.base; + for (i = 0; i < chip->chip.ngpio; i++, gpn++) { + BUG_ON(gpn >= ARRAY_SIZE(s3c_gpios)); + s3c_gpios[gpn] = chip; + } +} +#endif /* CONFIG_S3C_GPIO_TRACK */ + +/* + * samsung_gpiolib_add() - add the Samsung gpio_chip. + * @chip: The chip to register + * + * This is a wrapper to gpiochip_add() that takes our specific gpio chip + * information and makes the necessary alterations for the platform and + * notes the information for use with the configuration systems and any + * other parts of the system. + */ + +static void __init samsung_gpiolib_add(struct samsung_gpio_chip *chip) +{ + struct gpio_chip *gc = &chip->chip; + int ret; + + BUG_ON(!chip->base); + BUG_ON(!gc->label); + BUG_ON(!gc->ngpio); + + spin_lock_init(&chip->lock); + + if (!gc->direction_input) + gc->direction_input = samsung_gpiolib_2bit_input; + if (!gc->direction_output) + gc->direction_output = samsung_gpiolib_2bit_output; + if (!gc->set) + gc->set = samsung_gpiolib_set; + if (!gc->get) + gc->get = samsung_gpiolib_get; + +#ifdef CONFIG_PM + if (chip->pm != NULL) { + if (!chip->pm->save || !chip->pm->resume) + pr_err("gpio: %s has missing PM functions\n", + gc->label); + } else + pr_err("gpio: %s has no PM function\n", gc->label); +#endif + + /* gpiochip_add() prints own failure message on error. */ + ret = gpiochip_add_data(gc, chip); + if (ret >= 0) + s3c_gpiolib_track(chip); +} + +static void __init s3c24xx_gpiolib_add_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base) +{ + int i; + struct gpio_chip *gc = &chip->chip; + + for (i = 0 ; i < nr_chips; i++, chip++) { + /* skip banks not present on SoC */ + if (chip->chip.base >= S3C_GPIO_END) + continue; + + if (!chip->config) + chip->config = &s3c24xx_gpiocfg_default; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * 0x10); + + if (!gc->direction_input) + gc->direction_input = samsung_gpiolib_2bit_input; + if (!gc->direction_output) + gc->direction_output = samsung_gpiolib_2bit_output; + + samsung_gpiolib_add(chip); + } +} + +static void __init samsung_gpiolib_add_2bit_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base, + unsigned int offset) +{ + int i; + + for (i = 0 ; i < nr_chips; i++, chip++) { + chip->chip.direction_input = samsung_gpiolib_2bit_input; + chip->chip.direction_output = samsung_gpiolib_2bit_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[7]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_2bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * offset); + + samsung_gpiolib_add(chip); + } +} + +/* + * samsung_gpiolib_add_4bit_chips - 4bit single register GPIO config. + * @chip: The gpio chip that is being configured. + * @nr_chips: The no of chips (gpio ports) for the GPIO being configured. + * + * This helper deal with the GPIO cases where the control register has 4 bits + * of control per GPIO, generally in the form of: + * 0000 = Input + * 0001 = Output + * others = Special functions (dependent on bank) + * + * Note, since the code to deal with the case where there are two control + * registers instead of one, we do not have a separate set of function + * (samsung_gpiolib_add_4bit2_chips)for each case. + */ + +static void __init samsung_gpiolib_add_4bit_chips(struct samsung_gpio_chip *chip, + int nr_chips, void __iomem *base) +{ + int i; + + for (i = 0 ; i < nr_chips; i++, chip++) { + chip->chip.direction_input = samsung_gpiolib_4bit_input; + chip->chip.direction_output = samsung_gpiolib_4bit_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[2]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + if ((base != NULL) && (chip->base == NULL)) + chip->base = base + ((i) * 0x20); + + chip->bitmap_gpio_int = 0; + + samsung_gpiolib_add(chip); + } +} + +static void __init samsung_gpiolib_add_4bit2_chips(struct samsung_gpio_chip *chip, + int nr_chips) +{ + for (; nr_chips > 0; nr_chips--, chip++) { + chip->chip.direction_input = samsung_gpiolib_4bit2_input; + chip->chip.direction_output = samsung_gpiolib_4bit2_output; + + if (!chip->config) + chip->config = &samsung_gpio_cfgs[2]; + if (!chip->pm) + chip->pm = __gpio_pm(&samsung_gpio_pm_4bit); + + samsung_gpiolib_add(chip); + } +} + +int samsung_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + struct samsung_gpio_chip *samsung_chip = gpiochip_get_data(chip); + + return samsung_chip->irq_base + offset; +} + +#ifdef CONFIG_PLAT_S3C24XX +static int s3c24xx_gpiolib_fbank_to_irq(struct gpio_chip *chip, unsigned offset) +{ + if (offset < 4) { + if (soc_is_s3c2412()) + return IRQ_EINT0_2412 + offset; + else + return IRQ_EINT0 + offset; + } + + if (offset < 8) + return IRQ_EINT4 + offset - 4; + + return -EINVAL; +} +#endif + +#ifdef CONFIG_ARCH_S3C64XX +static int s3c64xx_gpiolib_mbank_to_irq(struct gpio_chip *chip, unsigned pin) +{ + return pin < 5 ? IRQ_EINT(23) + pin : -ENXIO; +} + +static int s3c64xx_gpiolib_lbank_to_irq(struct gpio_chip *chip, unsigned pin) +{ + return pin >= 8 ? IRQ_EINT(16) + pin - 8 : -ENXIO; +} +#endif + +struct samsung_gpio_chip s3c24xx_gpios[] = { +#ifdef CONFIG_PLAT_S3C24XX + { + .config = &s3c24xx_gpiocfg_banka, + .chip = { + .base = S3C2410_GPA(0), + .owner = THIS_MODULE, + .label = "GPIOA", + .ngpio = 27, + .direction_input = s3c24xx_gpiolib_banka_input, + .direction_output = s3c24xx_gpiolib_banka_output, + }, + }, { + .chip = { + .base = S3C2410_GPB(0), + .owner = THIS_MODULE, + .label = "GPIOB", + .ngpio = 11, + }, + }, { + .chip = { + .base = S3C2410_GPC(0), + .owner = THIS_MODULE, + .label = "GPIOC", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPD(0), + .owner = THIS_MODULE, + .label = "GPIOD", + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPE(0), + .label = "GPIOE", + .owner = THIS_MODULE, + .ngpio = 16, + }, + }, { + .chip = { + .base = S3C2410_GPF(0), + .owner = THIS_MODULE, + .label = "GPIOF", + .ngpio = 8, + .to_irq = s3c24xx_gpiolib_fbank_to_irq, + }, + }, { + .irq_base = IRQ_EINT8, + .chip = { + .base = S3C2410_GPG(0), + .owner = THIS_MODULE, + .label = "GPIOG", + .ngpio = 16, + .to_irq = samsung_gpiolib_to_irq, + }, + }, { + .chip = { + .base = S3C2410_GPH(0), + .owner = THIS_MODULE, + .label = "GPIOH", + .ngpio = 15, + }, + }, + /* GPIOS for the S3C2443 and later devices. */ + { + .base = S3C2440_GPJCON, + .chip = { + .base = S3C2410_GPJ(0), + .owner = THIS_MODULE, + .label = "GPIOJ", + .ngpio = 16, + }, + }, { + .base = S3C2443_GPKCON, + .chip = { + .base = S3C2410_GPK(0), + .owner = THIS_MODULE, + .label = "GPIOK", + .ngpio = 16, + }, + }, { + .base = S3C2443_GPLCON, + .chip = { + .base = S3C2410_GPL(0), + .owner = THIS_MODULE, + .label = "GPIOL", + .ngpio = 15, + }, + }, { + .base = S3C2443_GPMCON, + .chip = { + .base = S3C2410_GPM(0), + .owner = THIS_MODULE, + .label = "GPIOM", + .ngpio = 2, + }, + }, +#endif +}; + +/* + * GPIO bank summary: + * + * Bank GPIOs Style SlpCon ExtInt Group + * A 8 4Bit Yes 1 + * B 7 4Bit Yes 1 + * C 8 4Bit Yes 2 + * D 5 4Bit Yes 3 + * E 5 4Bit Yes None + * F 16 2Bit Yes 4 [1] + * G 7 4Bit Yes 5 + * H 10 4Bit[2] Yes 6 + * I 16 2Bit Yes None + * J 12 2Bit Yes None + * K 16 4Bit[2] No None + * L 15 4Bit[2] No None + * M 6 4Bit No IRQ_EINT + * N 16 2Bit No IRQ_EINT + * O 16 2Bit Yes 7 + * P 15 2Bit Yes 8 + * Q 9 2Bit Yes 9 + * + * [1] BANKF pins 14,15 do not form part of the external interrupt sources + * [2] BANK has two control registers, GPxCON0 and GPxCON1 + */ + +static struct samsung_gpio_chip s3c64xx_gpios_4bit[] = { +#ifdef CONFIG_ARCH_S3C64XX + { + .chip = { + .base = S3C64XX_GPA(0), + .ngpio = S3C64XX_GPIO_A_NR, + .label = "GPA", + }, + }, { + .chip = { + .base = S3C64XX_GPB(0), + .ngpio = S3C64XX_GPIO_B_NR, + .label = "GPB", + }, + }, { + .chip = { + .base = S3C64XX_GPC(0), + .ngpio = S3C64XX_GPIO_C_NR, + .label = "GPC", + }, + }, { + .chip = { + .base = S3C64XX_GPD(0), + .ngpio = S3C64XX_GPIO_D_NR, + .label = "GPD", + }, + }, { + .config = &samsung_gpio_cfgs[0], + .chip = { + .base = S3C64XX_GPE(0), + .ngpio = S3C64XX_GPIO_E_NR, + .label = "GPE", + }, + }, { + .base = S3C64XX_GPG_BASE, + .chip = { + .base = S3C64XX_GPG(0), + .ngpio = S3C64XX_GPIO_G_NR, + .label = "GPG", + }, + }, { + .base = S3C64XX_GPM_BASE, + .config = &samsung_gpio_cfgs[1], + .chip = { + .base = S3C64XX_GPM(0), + .ngpio = S3C64XX_GPIO_M_NR, + .label = "GPM", + .to_irq = s3c64xx_gpiolib_mbank_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip s3c64xx_gpios_4bit2[] = { +#ifdef CONFIG_ARCH_S3C64XX + { + .base = S3C64XX_GPH_BASE + 0x4, + .chip = { + .base = S3C64XX_GPH(0), + .ngpio = S3C64XX_GPIO_H_NR, + .label = "GPH", + }, + }, { + .base = S3C64XX_GPK_BASE + 0x4, + .config = &samsung_gpio_cfgs[0], + .chip = { + .base = S3C64XX_GPK(0), + .ngpio = S3C64XX_GPIO_K_NR, + .label = "GPK", + }, + }, { + .base = S3C64XX_GPL_BASE + 0x4, + .config = &samsung_gpio_cfgs[1], + .chip = { + .base = S3C64XX_GPL(0), + .ngpio = S3C64XX_GPIO_L_NR, + .label = "GPL", + .to_irq = s3c64xx_gpiolib_lbank_to_irq, + }, + }, +#endif +}; + +static struct samsung_gpio_chip s3c64xx_gpios_2bit[] = { +#ifdef CONFIG_ARCH_S3C64XX + { + .base = S3C64XX_GPF_BASE, + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPF(0), + .ngpio = S3C64XX_GPIO_F_NR, + .label = "GPF", + }, + }, { + .config = &samsung_gpio_cfgs[7], + .chip = { + .base = S3C64XX_GPI(0), + .ngpio = S3C64XX_GPIO_I_NR, + .label = "GPI", + }, + }, { + .config = &samsung_gpio_cfgs[7], + .chip = { + .base = S3C64XX_GPJ(0), + .ngpio = S3C64XX_GPIO_J_NR, + .label = "GPJ", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPO(0), + .ngpio = S3C64XX_GPIO_O_NR, + .label = "GPO", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPP(0), + .ngpio = S3C64XX_GPIO_P_NR, + .label = "GPP", + }, + }, { + .config = &samsung_gpio_cfgs[6], + .chip = { + .base = S3C64XX_GPQ(0), + .ngpio = S3C64XX_GPIO_Q_NR, + .label = "GPQ", + }, + }, { + .base = S3C64XX_GPN_BASE, + .irq_base = IRQ_EINT(0), + .config = &samsung_gpio_cfgs[5], + .chip = { + .base = S3C64XX_GPN(0), + .ngpio = S3C64XX_GPIO_N_NR, + .label = "GPN", + .to_irq = samsung_gpiolib_to_irq, + }, + }, +#endif +}; + +/* TODO: cleanup soc_is_* */ +static __init int samsung_gpiolib_init(void) +{ + /* + * Currently there are two drivers that can provide GPIO support for + * Samsung SoCs. For device tree enabled platforms, the new + * pinctrl-samsung driver is used, providing both GPIO and pin control + * interfaces. For legacy (non-DT) platforms this driver is used. + */ + if (of_have_populated_dt()) + return 0; + + if (soc_is_s3c24xx()) { + samsung_gpiolib_set_cfg(samsung_gpio_cfgs, + ARRAY_SIZE(samsung_gpio_cfgs)); + s3c24xx_gpiolib_add_chips(s3c24xx_gpios, + ARRAY_SIZE(s3c24xx_gpios), S3C24XX_VA_GPIO); + } else if (soc_is_s3c64xx()) { + samsung_gpiolib_set_cfg(samsung_gpio_cfgs, + ARRAY_SIZE(samsung_gpio_cfgs)); + samsung_gpiolib_add_2bit_chips(s3c64xx_gpios_2bit, + ARRAY_SIZE(s3c64xx_gpios_2bit), + S3C64XX_VA_GPIO + 0xE0, 0x20); + samsung_gpiolib_add_4bit_chips(s3c64xx_gpios_4bit, + ARRAY_SIZE(s3c64xx_gpios_4bit), + S3C64XX_VA_GPIO); + samsung_gpiolib_add_4bit2_chips(s3c64xx_gpios_4bit2, + ARRAY_SIZE(s3c64xx_gpios_4bit2)); + } + + return 0; +} +core_initcall(samsung_gpiolib_init); + +int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset; + int ret; + + if (!chip) + return -EINVAL; + + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_setcfg(chip, offset, config); + samsung_gpio_unlock(chip, flags); + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_cfgpin); + +int s3c_gpio_cfgpin_range(unsigned int start, unsigned int nr, + unsigned int cfg) +{ + int ret; + + for (; nr > 0; nr--, start++) { + ret = s3c_gpio_cfgpin(start, cfg); + if (ret != 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_gpio_cfgpin_range); + +int s3c_gpio_cfgall_range(unsigned int start, unsigned int nr, + unsigned int cfg, samsung_gpio_pull_t pull) +{ + int ret; + + for (; nr > 0; nr--, start++) { + s3c_gpio_setpull(start, pull); + ret = s3c_gpio_cfgpin(start, cfg); + if (ret != 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(s3c_gpio_cfgall_range); + +unsigned s3c_gpio_getcfg(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + unsigned ret = 0; + int offset; + + if (chip) { + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_getcfg(chip, offset); + samsung_gpio_unlock(chip, flags); + } + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_getcfg); + +int s3c_gpio_setpull(unsigned int pin, samsung_gpio_pull_t pull) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset, ret; + + if (!chip) + return -EINVAL; + + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + ret = samsung_gpio_do_setpull(chip, offset, pull); + samsung_gpio_unlock(chip, flags); + + return ret; +} +EXPORT_SYMBOL(s3c_gpio_setpull); + +samsung_gpio_pull_t s3c_gpio_getpull(unsigned int pin) +{ + struct samsung_gpio_chip *chip = samsung_gpiolib_getchip(pin); + unsigned long flags; + int offset; + u32 pup = 0; + + if (chip) { + offset = pin - chip->chip.base; + + samsung_gpio_lock(chip, flags); + pup = samsung_gpio_do_getpull(chip, offset); + samsung_gpio_unlock(chip, flags); + } + + return (__force samsung_gpio_pull_t)pup; +} +EXPORT_SYMBOL(s3c_gpio_getpull); + +#ifdef CONFIG_PLAT_S3C24XX +unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change) +{ + unsigned long flags; + unsigned long misccr; + + local_irq_save(flags); + misccr = __raw_readl(S3C24XX_MISCCR); + misccr &= ~clear; + misccr ^= change; + __raw_writel(misccr, S3C24XX_MISCCR); + local_irq_restore(flags); + + return misccr; +} +EXPORT_SYMBOL(s3c2410_modify_misccr); +#endif diff --git a/arch/arm/mach-s3c/gpio-samsung.h b/arch/arm/mach-s3c/gpio-samsung.h new file mode 100644 index 000000000..02f6f4a96 --- /dev/null +++ b/arch/arm/mach-s3c/gpio-samsung.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "gpio-samsung-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "gpio-samsung-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/gta02.h b/arch/arm/mach-s3c/gta02.h new file mode 100644 index 000000000..043ae382b --- /dev/null +++ b/arch/arm/mach-s3c/gta02.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * GTA02 header + */ + +#ifndef __MACH_S3C24XX_GTA02_H +#define __MACH_S3C24XX_GTA02_H __FILE__ + +#include "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-s3c/h1940-bluetooth.c b/arch/arm/mach-s3c/h1940-bluetooth.c new file mode 100644 index 000000000..59edcf8a6 --- /dev/null +++ b/arch/arm/mach-s3c/h1940-bluetooth.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-1.0+ +// +// Copyright (c) Arnaud Patard <arnaud.patard@rtp-net.org> +// +// 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 "gpio-cfg.h" +#include "regs-gpio.h" +#include "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(NULL, 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(NULL, 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-s3c/h1940.h b/arch/arm/mach-s3c/h1940.h new file mode 100644 index 000000000..5dfe9d10c --- /dev/null +++ b/arch/arm/mach-s3c/h1940.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 + */ + +#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) + +struct gpio_desc; + +extern void h1940_pm_return(void); +extern int h1940_led_blink_set(struct gpio_desc *desc, 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-s3c/hardware-s3c24xx.h b/arch/arm/mach-s3c/hardware-s3c24xx.h new file mode 100644 index 000000000..33b37467d --- /dev/null +++ b/arch/arm/mach-s3c/hardware-s3c24xx.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - hardware + */ + +#ifndef __ASM_ARCH_HARDWARE_S3C24XX_H +#define __ASM_ARCH_HARDWARE_S3C24XX_H + +extern unsigned int s3c2410_modify_misccr(unsigned int clr, unsigned int chg); + +#endif /* __ASM_ARCH_HARDWARE_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/iic-core.h b/arch/arm/mach-s3c/iic-core.h new file mode 100644 index 000000000..c5cfd5af3 --- /dev/null +++ b/arch/arm/mach-s3c/iic-core.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - I2C Controller core functions + */ + +#ifndef __ASM_ARCH_IIC_CORE_H +#define __ASM_ARCH_IIC_CORE_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_i2c0_setname(char *name) +{ + /* currently this device is always compiled in */ + s3c_device_i2c0.name = name; +} + +static inline void s3c_i2c1_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_I2C1 + s3c_device_i2c1.name = name; +#endif +} + +static inline void s3c_i2c2_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_I2C2 + s3c_device_i2c2.name = name; +#endif +} + +#endif /* __ASM_ARCH_IIC_H */ diff --git a/arch/arm/mach-s3c/init.c b/arch/arm/mach-s3c/init.c new file mode 100644 index 000000000..bf513616f --- /dev/null +++ b/arch/arm/mach-s3c/init.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C series CPU initialisation + +/* + * NOTE: Code in this file is not used on S3C64xx when booting with + * Device Tree support. + */ + +#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 <linux/platform_device.h> +#include <linux/of.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include "cpu.h" +#include "devs.h" + +static struct cpu_table *cpu; + +static struct cpu_table * __init s3c_lookup_cpu(unsigned long idcode, + struct cpu_table *tab, + unsigned int count) +{ + for (; count != 0; count--, tab++) { + if ((idcode & tab->idmask) == (tab->idcode & tab->idmask)) + return tab; + } + + return NULL; +} + +void __init s3c_init_cpu(unsigned long idcode, + struct cpu_table *cputab, unsigned int cputab_size) +{ + cpu = s3c_lookup_cpu(idcode, cputab, cputab_size); + + if (cpu == NULL) { + printk(KERN_ERR "Unknown CPU type 0x%08lx\n", idcode); + panic("Unknown S3C24XX CPU"); + } + + printk("CPU %s (id 0x%08lx)\n", cpu->name, idcode); + + if (cpu->init == NULL) { + printk(KERN_ERR "CPU %s support not enabled\n", cpu->name); + panic("Unsupported Samsung CPU"); + } + + if (cpu->map_io) + cpu->map_io(); + + pr_err("The platform is deprecated and scheduled for removal. Please reach to the maintainers of the platform and linux-samsung-soc@vger.kernel.org if you still use it. Without such feedback, the platform will be removed after 2022.\n"); +} + +/* s3c24xx_init_clocks + * + * Initialise the clock subsystem and associated information from the + * given master crystal value. + * + * xtal = 0 -> use default PLL crystal value (normally 12MHz) + * != 0 -> PLL crystal value in Hz +*/ + +void __init s3c24xx_init_clocks(int xtal) +{ + if (xtal == 0) + xtal = 12*1000*1000; + + if (cpu == NULL) + panic("s3c24xx_init_clocks: no cpu setup?\n"); + + if (cpu->init_clocks == NULL) + panic("s3c24xx_init_clocks: cpu has no clock init\n"); + else + (cpu->init_clocks)(xtal); +} + +/* uart management */ +#if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) +static int nr_uarts __initdata = 0; + +#ifdef CONFIG_SERIAL_SAMSUNG_UARTS +static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS]; +#endif + +/* s3c24xx_init_uartdevs + * + * copy the specified platform data and configuration into our central + * set of devices, before the data is thrown away after the init process. + * + * This also fills in the array passed to the serial driver for the + * early initialisation of the console. +*/ + +void __init s3c24xx_init_uartdevs(char *name, + struct s3c24xx_uart_resources *res, + struct s3c2410_uartcfg *cfg, int no) +{ +#ifdef CONFIG_SERIAL_SAMSUNG_UARTS + struct platform_device *platdev; + struct s3c2410_uartcfg *cfgptr = uart_cfgs; + struct s3c24xx_uart_resources *resp; + int uart; + + memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no); + + for (uart = 0; uart < no; uart++, cfg++, cfgptr++) { + platdev = s3c24xx_uart_src[cfgptr->hwport]; + + resp = res + cfgptr->hwport; + + s3c24xx_uart_devs[uart] = platdev; + + platdev->name = name; + platdev->resource = resp->resources; + platdev->num_resources = resp->nr_resources; + + platdev->dev.platform_data = cfgptr; + } + + nr_uarts = no; +#endif +} + +void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + if (cpu == NULL) + return; + + if (cpu->init_uarts == NULL && IS_ENABLED(CONFIG_SAMSUNG_ATAGS)) { + printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n"); + } else + (cpu->init_uarts)(cfg, no); +} +#endif + +static int __init s3c_arch_init(void) +{ + int ret; + + /* init is only needed for ATAGS based platforms */ + if (!IS_ENABLED(CONFIG_ATAGS) || + (!soc_is_s3c24xx() && !soc_is_s3c64xx())) + return 0; + + // do the correct init for cpu + + if (cpu == NULL) { + /* Not needed when booting with device tree. */ + if (of_have_populated_dt()) + return 0; + panic("s3c_arch_init: NULL cpu\n"); + } + + ret = (cpu->init)(); + if (ret != 0) + return ret; +#if IS_ENABLED(CONFIG_SAMSUNG_ATAGS) + ret = platform_add_devices(s3c24xx_uart_devs, nr_uarts); +#endif + return ret; +} + +arch_initcall(s3c_arch_init); diff --git a/arch/arm/mach-s3c/iotiming-s3c2410.c b/arch/arm/mach-s3c/iotiming-s3c2410.c new file mode 100644 index 000000000..09f388d8f --- /dev/null +++ b/arch/arm/mach-s3c/iotiming-s3c2410.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 + +#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 "map.h" +#include "regs-clock.h" + +#include <linux/soc/samsung/s3c-cpufreq-core.h> + +#include "regs-mem-s3c24xx.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; +} + +static 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 information + * @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 const 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, shifted 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. + */ +static 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 configuration + * 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(*bt), GFP_KERNEL); + if (!bt) + 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-s3c/iotiming-s3c2412.c b/arch/arm/mach-s3c/iotiming-s3c2412.c new file mode 100644 index 000000000..003f89c4d --- /dev/null +++ b/arch/arm/mach-s3c/iotiming-s3c2412.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2006-2008 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk> +// +// S3C2412/S3C2443 (PL093 based) IO timing support + +#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 "cpu.h" +#include <linux/soc/samsung/s3c-cpufreq-core.h> + +#include "s3c2412.h" + +#define print_ns(x) ((x) / 10), ((x) % 10) + +/** + * s3c2412_print_timing - print timing information 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(*bt), GFP_KERNEL); + if (!bt) + 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-s3c/irq-pm-s3c24xx.c b/arch/arm/mach-s3c/irq-pm-s3c24xx.c new file mode 100644 index 000000000..55f41135a --- /dev/null +++ b/arch/arm/mach-s3c/irq-pm-s3c24xx.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2003-2004 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C24XX - IRQ PM code + +#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 "cpu.h" +#include "pm.h" +#include "map-base.h" +#include "map-s3c.h" + +#include "regs-irq.h" +#include "regs-gpio.h" +#include "pm-core.h" + +#include <asm/irq.h> + +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-s3c/irq-pm-s3c64xx.c b/arch/arm/mach-s3c/irq-pm-s3c64xx.c new file mode 100644 index 000000000..4a1e935ba --- /dev/null +++ b/arch/arm/mach-s3c/irq-pm-s3c64xx.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C64XX - Interrupt handling Power Management + +/* + * NOTE: Code in this file is not used when booting with Device Tree support. + */ + +#include <linux/kernel.h> +#include <linux/syscore_ops.h> +#include <linux/interrupt.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/of.h> + +#include "map.h" + +#include "regs-gpio.h" +#include "cpu.h" +#include "pm.h" + +/* We handled all the IRQ types in this code, to save having to make several + * small files to handle each different type separately. Having the EINT_GRP + * code here shouldn't be as much bloat as the IRQ table space needed when + * they are enabled. The added benefit is we ensure that these registers are + * in the same state as we suspended. + */ + +static struct sleep_save irq_save[] = { + SAVE_ITEM(S3C64XX_PRIORITY), + SAVE_ITEM(S3C64XX_EINT0CON0), + SAVE_ITEM(S3C64XX_EINT0CON1), + SAVE_ITEM(S3C64XX_EINT0FLTCON0), + SAVE_ITEM(S3C64XX_EINT0FLTCON1), + SAVE_ITEM(S3C64XX_EINT0FLTCON2), + SAVE_ITEM(S3C64XX_EINT0FLTCON3), + SAVE_ITEM(S3C64XX_EINT0MASK), +}; + +static struct irq_grp_save { + u32 fltcon; + u32 con; + u32 mask; +} eint_grp_save[5]; + +#ifndef CONFIG_SERIAL_SAMSUNG_UARTS +#define SERIAL_SAMSUNG_UARTS 0 +#else +#define SERIAL_SAMSUNG_UARTS CONFIG_SERIAL_SAMSUNG_UARTS +#endif + +static u32 irq_uart_mask[SERIAL_SAMSUNG_UARTS]; + +static int s3c64xx_irq_pm_suspend(void) +{ + struct irq_grp_save *grp = eint_grp_save; + int i; + + S3C_PMDBG("%s: suspending IRQs\n", __func__); + + s3c_pm_do_save(irq_save, ARRAY_SIZE(irq_save)); + + for (i = 0; i < SERIAL_SAMSUNG_UARTS; i++) + irq_uart_mask[i] = __raw_readl(S3C_VA_UARTx(i) + S3C64XX_UINTM); + + for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { + grp->con = __raw_readl(S3C64XX_EINT12CON + (i * 4)); + grp->mask = __raw_readl(S3C64XX_EINT12MASK + (i * 4)); + grp->fltcon = __raw_readl(S3C64XX_EINT12FLTCON + (i * 4)); + } + + return 0; +} + +static void s3c64xx_irq_pm_resume(void) +{ + struct irq_grp_save *grp = eint_grp_save; + int i; + + S3C_PMDBG("%s: resuming IRQs\n", __func__); + + s3c_pm_do_restore(irq_save, ARRAY_SIZE(irq_save)); + + for (i = 0; i < SERIAL_SAMSUNG_UARTS; i++) + __raw_writel(irq_uart_mask[i], S3C_VA_UARTx(i) + S3C64XX_UINTM); + + for (i = 0; i < ARRAY_SIZE(eint_grp_save); i++, grp++) { + __raw_writel(grp->con, S3C64XX_EINT12CON + (i * 4)); + __raw_writel(grp->mask, S3C64XX_EINT12MASK + (i * 4)); + __raw_writel(grp->fltcon, S3C64XX_EINT12FLTCON + (i * 4)); + } + + S3C_PMDBG("%s: IRQ configuration restored\n", __func__); +} + +static struct syscore_ops s3c64xx_irq_syscore_ops = { + .suspend = s3c64xx_irq_pm_suspend, + .resume = s3c64xx_irq_pm_resume, +}; + +static __init int s3c64xx_syscore_init(void) +{ + /* Appropriate drivers (pinctrl, uart) handle this when using DT. */ + if (of_have_populated_dt() || !soc_is_s3c64xx()) + return 0; + + register_syscore_ops(&s3c64xx_irq_syscore_ops); + + return 0; +} + +core_initcall(s3c64xx_syscore_init); diff --git a/arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c b/arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c new file mode 100644 index 000000000..84cf86376 --- /dev/null +++ b/arch/arm/mach-s3c/irq-s3c24xx-fiq-exports.c @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/stddef.h> +#include <linux/export.h> +#include <linux/spi/s3c24xx-fiq.h> + +EXPORT_SYMBOL(s3c24xx_spi_fiq_rx); +EXPORT_SYMBOL(s3c24xx_spi_fiq_txrx); +EXPORT_SYMBOL(s3c24xx_spi_fiq_tx); diff --git a/arch/arm/mach-s3c/irq-s3c24xx-fiq.S b/arch/arm/mach-s3c/irq-s3c24xx-fiq.S new file mode 100644 index 000000000..5d238d9a7 --- /dev/null +++ b/arch/arm/mach-s3c/irq-s3c24xx-fiq.S @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* linux/drivers/spi/spi_s3c24xx_fiq.S + * + * Copyright 2009 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX SPI - FIQ pseudo-DMA transfer code +*/ + +#include <linux/linkage.h> +#include <asm/assembler.h> + +#include "map.h" +#include "regs-irq.h" + +#include <linux/spi/s3c24xx-fiq.h> + +#define S3C2410_SPTDAT (0x10) +#define S3C2410_SPRDAT (0x14) + + .text + + @ entry to these routines is as follows, with the register names + @ defined in fiq.h so that they can be shared with the C files which + @ setup the calling registers. + @ + @ fiq_rirq The base of the IRQ registers to find S3C2410_SRCPND + @ fiq_rtmp Temporary register to hold tx/rx data + @ fiq_rspi The base of the SPI register block + @ fiq_rtx The tx buffer pointer + @ fiq_rrx The rx buffer pointer + @ fiq_rcount The number of bytes to move + + @ each entry starts with a word entry of how long it is + @ and an offset to the irq acknowledgment word + +ENTRY(s3c24xx_spi_fiq_rx) + .word fiq_rx_end - fiq_rx_start + .word fiq_rx_irq_ack - fiq_rx_start +fiq_rx_start: + ldr fiq_rtmp, fiq_rx_irq_ack + str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] + + ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] + strb fiq_rtmp, [ fiq_rrx ], #1 + + mov fiq_rtmp, #0xff + strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] + + subs fiq_rcount, fiq_rcount, #1 + subsne pc, lr, #4 @@ return, still have work to do + + @@ set IRQ controller so that next op will trigger IRQ + mov fiq_rtmp, #0 + str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] + subs pc, lr, #4 + +fiq_rx_irq_ack: + .word 0 +fiq_rx_end: + +ENTRY(s3c24xx_spi_fiq_txrx) + .word fiq_txrx_end - fiq_txrx_start + .word fiq_txrx_irq_ack - fiq_txrx_start +fiq_txrx_start: + + ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] + strb fiq_rtmp, [ fiq_rrx ], #1 + + ldr fiq_rtmp, fiq_txrx_irq_ack + str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] + + ldrb fiq_rtmp, [ fiq_rtx ], #1 + strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] + + subs fiq_rcount, fiq_rcount, #1 + subsne pc, lr, #4 @@ return, still have work to do + + mov fiq_rtmp, #0 + str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] + subs pc, lr, #4 + +fiq_txrx_irq_ack: + .word 0 + +fiq_txrx_end: + +ENTRY(s3c24xx_spi_fiq_tx) + .word fiq_tx_end - fiq_tx_start + .word fiq_tx_irq_ack - fiq_tx_start +fiq_tx_start: + ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] + + ldr fiq_rtmp, fiq_tx_irq_ack + str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] + + ldrb fiq_rtmp, [ fiq_rtx ], #1 + strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] + + subs fiq_rcount, fiq_rcount, #1 + subsne pc, lr, #4 @@ return, still have work to do + + mov fiq_rtmp, #0 + str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] + subs pc, lr, #4 + +fiq_tx_irq_ack: + .word 0 + +fiq_tx_end: + + .end diff --git a/arch/arm/mach-s3c/irq-s3c24xx.c b/arch/arm/mach-s3c/irq-s3c24xx.c new file mode 100644 index 000000000..088cc04b7 --- /dev/null +++ b/arch/arm/mach-s3c/irq-s3c24xx.c @@ -0,0 +1,1352 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * S3C24XX IRQ handling + * + * Copyright (c) 2003-2004 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de> +*/ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/irqdomain.h> +#include <linux/irqchip.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/of.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> +#include <linux/spi/s3c24xx.h> + +#include <asm/exception.h> +#include <asm/mach/irq.h> + +#include "irqs.h" +#include "regs-irq.h" +#include "regs-gpio.h" + +#include "cpu.h" +#include "regs-irqtype.h" +#include "pm.h" +#include "s3c24xx.h" + +#define S3C_IRQTYPE_NONE 0 +#define S3C_IRQTYPE_EINT 1 +#define S3C_IRQTYPE_EDGE 2 +#define S3C_IRQTYPE_LEVEL 3 + +struct s3c_irq_data { + unsigned int type; + unsigned long offset; + unsigned long parent_irq; + + /* data gets filled during init */ + struct s3c_irq_intc *intc; + unsigned long sub_bits; + struct s3c_irq_intc *sub_intc; +}; + +/* + * Structure holding the controller data + * @reg_pending register holding pending irqs + * @reg_intpnd special register intpnd in main intc + * @reg_mask mask register + * @domain irq_domain of the controller + * @parent parent controller for ext and sub irqs + * @irqs irq-data, always s3c_irq_data[32] + */ +struct s3c_irq_intc { + void __iomem *reg_pending; + void __iomem *reg_intpnd; + void __iomem *reg_mask; + struct irq_domain *domain; + struct s3c_irq_intc *parent; + struct s3c_irq_data *irqs; +}; + +/* + * Array holding pointers to the global controller structs + * [0] ... main_intc + * [1] ... sub_intc + * [2] ... main_intc2 on s3c2416 + */ +static struct s3c_irq_intc *s3c_intc[3]; + +static void s3c_irq_mask(struct irq_data *data) +{ + struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); + struct s3c_irq_intc *intc = irq_data->intc; + struct s3c_irq_intc *parent_intc = intc->parent; + struct s3c_irq_data *parent_data; + unsigned long mask; + unsigned int irqno; + + mask = readl_relaxed(intc->reg_mask); + mask |= (1UL << irq_data->offset); + writel_relaxed(mask, intc->reg_mask); + + if (parent_intc) { + parent_data = &parent_intc->irqs[irq_data->parent_irq]; + + /* check to see if we need to mask the parent IRQ + * The parent_irq is always in main_intc, so the hwirq + * for find_mapping does not need an offset in any case. + */ + if ((mask & parent_data->sub_bits) == parent_data->sub_bits) { + irqno = irq_find_mapping(parent_intc->domain, + irq_data->parent_irq); + s3c_irq_mask(irq_get_irq_data(irqno)); + } + } +} + +static void s3c_irq_unmask(struct irq_data *data) +{ + struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); + struct s3c_irq_intc *intc = irq_data->intc; + struct s3c_irq_intc *parent_intc = intc->parent; + unsigned long mask; + unsigned int irqno; + + mask = readl_relaxed(intc->reg_mask); + mask &= ~(1UL << irq_data->offset); + writel_relaxed(mask, intc->reg_mask); + + if (parent_intc) { + irqno = irq_find_mapping(parent_intc->domain, + irq_data->parent_irq); + s3c_irq_unmask(irq_get_irq_data(irqno)); + } +} + +static inline void s3c_irq_ack(struct irq_data *data) +{ + struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); + struct s3c_irq_intc *intc = irq_data->intc; + unsigned long bitval = 1UL << irq_data->offset; + + writel_relaxed(bitval, intc->reg_pending); + if (intc->reg_intpnd) + writel_relaxed(bitval, intc->reg_intpnd); +} + +static int s3c_irq_type(struct irq_data *data, unsigned int type) +{ + switch (type) { + case IRQ_TYPE_NONE: + break; + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_EDGE_BOTH: + irq_set_handler(data->irq, handle_edge_irq); + break; + case IRQ_TYPE_LEVEL_LOW: + case IRQ_TYPE_LEVEL_HIGH: + irq_set_handler(data->irq, handle_level_irq); + break; + default: + pr_err("No such irq type %d\n", type); + return -EINVAL; + } + + return 0; +} + +static int s3c_irqext_type_set(void __iomem *gpcon_reg, + void __iomem *extint_reg, + unsigned long gpcon_offset, + unsigned long extint_offset, + unsigned int type) +{ + unsigned long newvalue = 0, value; + + /* Set the GPIO to external interrupt mode */ + value = readl_relaxed(gpcon_reg); + value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); + writel_relaxed(value, gpcon_reg); + + /* Set the external interrupt to pointed trigger type */ + switch (type) + { + case IRQ_TYPE_NONE: + pr_warn("No edge setting!\n"); + break; + + case IRQ_TYPE_EDGE_RISING: + newvalue = S3C2410_EXTINT_RISEEDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + newvalue = S3C2410_EXTINT_FALLEDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + newvalue = S3C2410_EXTINT_BOTHEDGE; + break; + + case IRQ_TYPE_LEVEL_LOW: + newvalue = S3C2410_EXTINT_LOWLEV; + break; + + case IRQ_TYPE_LEVEL_HIGH: + newvalue = S3C2410_EXTINT_HILEV; + break; + + default: + pr_err("No such irq type %d\n", type); + return -EINVAL; + } + + value = readl_relaxed(extint_reg); + value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); + writel_relaxed(value, extint_reg); + + return 0; +} + +static int s3c_irqext_type(struct irq_data *data, unsigned int type) +{ + void __iomem *extint_reg; + void __iomem *gpcon_reg; + unsigned long gpcon_offset, extint_offset; + + if ((data->hwirq >= 4) && (data->hwirq <= 7)) { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C24XX_EXTINT0; + gpcon_offset = (data->hwirq) * 2; + extint_offset = (data->hwirq) * 4; + } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C24XX_EXTINT1; + gpcon_offset = (data->hwirq - 8) * 2; + extint_offset = (data->hwirq - 8) * 4; + } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) { + gpcon_reg = S3C2410_GPGCON; + extint_reg = S3C24XX_EXTINT2; + gpcon_offset = (data->hwirq - 8) * 2; + extint_offset = (data->hwirq - 16) * 4; + } else { + return -EINVAL; + } + + return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset, + extint_offset, type); +} + +static int s3c_irqext0_type(struct irq_data *data, unsigned int type) +{ + void __iomem *extint_reg; + void __iomem *gpcon_reg; + unsigned long gpcon_offset, extint_offset; + + if (data->hwirq <= 3) { + gpcon_reg = S3C2410_GPFCON; + extint_reg = S3C24XX_EXTINT0; + gpcon_offset = (data->hwirq) * 2; + extint_offset = (data->hwirq) * 4; + } else { + return -EINVAL; + } + + return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset, + extint_offset, type); +} + +static struct irq_chip s3c_irq_chip = { + .name = "s3c", + .irq_ack = s3c_irq_ack, + .irq_mask = s3c_irq_mask, + .irq_unmask = s3c_irq_unmask, + .irq_set_type = s3c_irq_type, + .irq_set_wake = s3c_irq_wake +}; + +static struct irq_chip s3c_irq_level_chip = { + .name = "s3c-level", + .irq_mask = s3c_irq_mask, + .irq_unmask = s3c_irq_unmask, + .irq_ack = s3c_irq_ack, + .irq_set_type = s3c_irq_type, +}; + +static struct irq_chip s3c_irqext_chip = { + .name = "s3c-ext", + .irq_mask = s3c_irq_mask, + .irq_unmask = s3c_irq_unmask, + .irq_ack = s3c_irq_ack, + .irq_set_type = s3c_irqext_type, + .irq_set_wake = s3c_irqext_wake +}; + +static struct irq_chip s3c_irq_eint0t4 = { + .name = "s3c-ext0", + .irq_ack = s3c_irq_ack, + .irq_mask = s3c_irq_mask, + .irq_unmask = s3c_irq_unmask, + .irq_set_wake = s3c_irq_wake, + .irq_set_type = s3c_irqext0_type, +}; + +static void s3c_irq_demux(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc); + struct s3c_irq_intc *intc = irq_data->intc; + struct s3c_irq_intc *sub_intc = irq_data->sub_intc; + unsigned int n, offset; + unsigned long src, msk; + + /* we're using individual domains for the non-dt case + * and one big domain for the dt case where the subintc + * starts at hwirq number 32. + */ + offset = irq_domain_get_of_node(intc->domain) ? 32 : 0; + + chained_irq_enter(chip, desc); + + src = readl_relaxed(sub_intc->reg_pending); + msk = readl_relaxed(sub_intc->reg_mask); + + src &= ~msk; + src &= irq_data->sub_bits; + + while (src) { + n = __ffs(src); + src &= ~(1 << n); + generic_handle_domain_irq(sub_intc->domain, offset + n); + } + + chained_irq_exit(chip, desc); +} + +static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, + struct pt_regs *regs, int intc_offset) +{ + int pnd; + int offset; + + pnd = readl_relaxed(intc->reg_intpnd); + if (!pnd) + return false; + + /* non-dt machines use individual domains */ + if (!irq_domain_get_of_node(intc->domain)) + intc_offset = 0; + + /* We have a problem that the INTOFFSET register does not always + * show one interrupt. Occasionally we get two interrupts through + * the prioritiser, and this causes the INTOFFSET register to show + * what looks like the logical-or of the two interrupt numbers. + * + * Thanks to Klaus, Shannon, et al for helping to debug this problem + */ + offset = readl_relaxed(intc->reg_intpnd + 4); + + /* Find the bit manually, when the offset is wrong. + * The pending register only ever contains the one bit of the next + * interrupt to handle. + */ + if (!(pnd & (1 << offset))) + offset = __ffs(pnd); + + generic_handle_domain_irq(intc->domain, intc_offset + offset); + return true; +} + +static asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs) +{ + do { + /* + * For platform based machines, neither ERR nor NULL can happen here. + * The s3c24xx_handle_irq() will be set as IRQ handler iff this succeeds: + * + * s3c_intc[0] = s3c24xx_init_intc() + * + * If this fails, the next calls to s3c24xx_init_intc() won't be executed. + * + * For DT machine, s3c_init_intc_of() could set the IRQ handler without + * setting s3c_intc[0] only if it was called with num_ctrl=0. There is no + * such code path, so again the s3c_intc[0] will have a valid pointer if + * set_handle_irq() is called. + * + * Therefore in s3c24xx_handle_irq(), the s3c_intc[0] is always something. + */ + if (s3c24xx_handle_intc(s3c_intc[0], regs, 0)) + continue; + + if (!IS_ERR_OR_NULL(s3c_intc[2])) + if (s3c24xx_handle_intc(s3c_intc[2], regs, 64)) + continue; + + break; + } while (1); +} + +#ifdef CONFIG_FIQ +/** + * s3c24xx_set_fiq - set the FIQ routing + * @irq: IRQ number to route to FIQ on processor. + * @ack_ptr: pointer to a location for storing the bit mask + * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing. + * + * Change the state of the IRQ to FIQ routing depending on @irq and @on. If + * @on is true, the @irq is checked to see if it can be routed and the + * interrupt controller updated to route the IRQ. If @on is false, the FIQ + * routing is cleared, regardless of which @irq is specified. + * + * returns the mask value for the register. + */ +int s3c24xx_set_fiq(unsigned int irq, u32 *ack_ptr, bool on) +{ + u32 intmod; + unsigned offs; + + if (on) { + offs = irq - FIQ_START; + if (offs > 31) + return 0; + + intmod = 1 << offs; + } else { + intmod = 0; + } + + if (ack_ptr) + *ack_ptr = intmod; + writel_relaxed(intmod, S3C2410_INTMOD); + + return intmod; +} + +EXPORT_SYMBOL_GPL(s3c24xx_set_fiq); +#endif + +static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct s3c_irq_intc *intc = h->host_data; + struct s3c_irq_data *irq_data = &intc->irqs[hw]; + struct s3c_irq_intc *parent_intc; + struct s3c_irq_data *parent_irq_data; + unsigned int irqno; + + /* attach controller pointer to irq_data */ + irq_data->intc = intc; + irq_data->offset = hw; + + parent_intc = intc->parent; + + /* set handler and flags */ + switch (irq_data->type) { + case S3C_IRQTYPE_NONE: + return 0; + case S3C_IRQTYPE_EINT: + /* On the S3C2412, the EINT0to3 have a parent irq + * but need the s3c_irq_eint0t4 chip + */ + if (parent_intc && (!soc_is_s3c2412() || hw >= 4)) + irq_set_chip_and_handler(virq, &s3c_irqext_chip, + handle_edge_irq); + else + irq_set_chip_and_handler(virq, &s3c_irq_eint0t4, + handle_edge_irq); + break; + case S3C_IRQTYPE_EDGE: + if (parent_intc || intc->reg_pending == S3C2416_SRCPND2) + irq_set_chip_and_handler(virq, &s3c_irq_level_chip, + handle_edge_irq); + else + irq_set_chip_and_handler(virq, &s3c_irq_chip, + handle_edge_irq); + break; + case S3C_IRQTYPE_LEVEL: + if (parent_intc) + irq_set_chip_and_handler(virq, &s3c_irq_level_chip, + handle_level_irq); + else + irq_set_chip_and_handler(virq, &s3c_irq_chip, + handle_level_irq); + break; + default: + pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type); + return -EINVAL; + } + + irq_set_chip_data(virq, irq_data); + + if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) { + if (irq_data->parent_irq > 31) { + pr_err("irq-s3c24xx: parent irq %lu is out of range\n", + irq_data->parent_irq); + return -EINVAL; + } + + parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; + parent_irq_data->sub_intc = intc; + parent_irq_data->sub_bits |= (1UL << hw); + + /* attach the demuxer to the parent irq */ + irqno = irq_find_mapping(parent_intc->domain, + irq_data->parent_irq); + if (!irqno) { + pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n", + irq_data->parent_irq); + return -EINVAL; + } + irq_set_chained_handler(irqno, s3c_irq_demux); + } + + return 0; +} + +static const struct irq_domain_ops s3c24xx_irq_ops = { + .map = s3c24xx_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void s3c24xx_clear_intc(struct s3c_irq_intc *intc) +{ + void __iomem *reg_source; + unsigned long pend; + unsigned long last; + int i; + + /* if intpnd is set, read the next pending irq from there */ + reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending; + + last = 0; + for (i = 0; i < 4; i++) { + pend = readl_relaxed(reg_source); + + if (pend == 0 || pend == last) + break; + + writel_relaxed(pend, intc->reg_pending); + if (intc->reg_intpnd) + writel_relaxed(pend, intc->reg_intpnd); + + pr_info("irq: clearing pending status %08x\n", (int)pend); + last = pend; + } +} + +static struct s3c_irq_intc * __init s3c24xx_init_intc(struct device_node *np, + struct s3c_irq_data *irq_data, + struct s3c_irq_intc *parent, + unsigned long address) +{ + struct s3c_irq_intc *intc; + void __iomem *base = (void *)0xf6000000; /* static mapping */ + int irq_num; + int irq_start; + int ret; + + intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); + if (!intc) + return ERR_PTR(-ENOMEM); + + intc->irqs = irq_data; + + if (parent) + intc->parent = parent; + + /* select the correct data for the controller. + * Need to hard code the irq num start and offset + * to preserve the static mapping for now + */ + switch (address) { + case 0x4a000000: + pr_debug("irq: found main intc\n"); + intc->reg_pending = base; + intc->reg_mask = base + 0x08; + intc->reg_intpnd = base + 0x10; + irq_num = 32; + irq_start = S3C2410_IRQ(0); + break; + case 0x4a000018: + pr_debug("irq: found subintc\n"); + intc->reg_pending = base + 0x18; + intc->reg_mask = base + 0x1c; + irq_num = 29; + irq_start = S3C2410_IRQSUB(0); + break; + case 0x4a000040: + pr_debug("irq: found intc2\n"); + intc->reg_pending = base + 0x40; + intc->reg_mask = base + 0x48; + intc->reg_intpnd = base + 0x50; + irq_num = 8; + irq_start = S3C2416_IRQ(0); + break; + case 0x560000a4: + pr_debug("irq: found eintc\n"); + base = (void *)0xfd000000; + + intc->reg_mask = base + 0xa4; + intc->reg_pending = base + 0xa8; + irq_num = 24; + irq_start = S3C2410_IRQ(32); + break; + default: + pr_err("irq: unsupported controller address\n"); + ret = -EINVAL; + goto err; + } + + /* now that all the data is complete, init the irq-domain */ + s3c24xx_clear_intc(intc); + intc->domain = irq_domain_add_legacy(np, irq_num, irq_start, + 0, &s3c24xx_irq_ops, + intc); + if (!intc->domain) { + pr_err("irq: could not create irq-domain\n"); + ret = -EINVAL; + goto err; + } + + set_handle_irq(s3c24xx_handle_irq); + + return intc; + +err: + kfree(intc); + return ERR_PTR(ret); +} + +static struct s3c_irq_data __maybe_unused init_eint[32] = { + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ +}; + +#ifdef CONFIG_CPU_S3C2410 +static struct s3c_irq_data init_s3c2410base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2410subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ +}; + +void __init s3c2410_init_irq(void) +{ +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0], + s3c_intc[0], 0x4a000018); + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); +} +#endif + +#ifdef CONFIG_CPU_S3C2412 +static struct s3c_irq_data init_s3c2412base[32] = { + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2412eint[32] = { + { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ + { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ +}; + +static struct s3c_irq_data init_s3c2412subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_NONE, }, + { .type = S3C_IRQTYPE_NONE, }, + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */ +}; + +void __init s3c2412_init_irq(void) +{ + pr_info("S3C2412: IRQ Support\n"); + +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0], + s3c_intc[0], 0x4a000018); +} +#endif + +#ifdef CONFIG_CPU_S3C2416 +static struct s3c_irq_data init_s3c2416base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */ + { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */ + { .type = S3C_IRQTYPE_NONE, }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* NAND */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_NONE, }, + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2416subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ +}; + +static struct s3c_irq_data init_s3c2416_second[32] = { + { .type = S3C_IRQTYPE_EDGE }, /* 2D */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */ +}; + +void __init s3c2416_init_irq(void) +{ + pr_info("S3C2416: IRQ Support\n"); + +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0], + s3c_intc[0], 0x4a000018); + + s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0], + NULL, 0x4a000040); +} + +#endif + +#ifdef CONFIG_CPU_S3C2440 +static struct s3c_irq_data init_s3c2440base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2440subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ +}; + +void __init s3c2440_init_irq(void) +{ + pr_info("S3C2440: IRQ Support\n"); + +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0], + s3c_intc[0], 0x4a000018); +} +#endif + +#ifdef CONFIG_CPU_S3C2442 +static struct s3c_irq_data init_s3c2442base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + +static struct s3c_irq_data init_s3c2442subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ +}; + +void __init s3c2442_init_irq(void) +{ + pr_info("S3C2442: IRQ Support\n"); + +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0], + s3c_intc[0], 0x4a000018); +} +#endif + +#ifdef CONFIG_CPU_S3C2443 +static struct s3c_irq_data init_s3c2443base[32] = { + { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ + { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ + { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ + { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ + { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */ + { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */ + { .type = S3C_IRQTYPE_EDGE, }, /* CFON */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* NAND */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ + { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ + { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ + { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ + { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ + { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ +}; + + +static struct s3c_irq_data init_s3c2443subint[32] = { + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ + { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ + { .type = S3C_IRQTYPE_NONE }, /* reserved */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ + { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ +}; + +void __init s3c2443_init_irq(void) +{ + pr_info("S3C2443: IRQ Support\n"); + +#ifdef CONFIG_FIQ + init_FIQ(FIQ_START); +#endif + + s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, + 0x4a000000); + if (IS_ERR(s3c_intc[0])) { + pr_err("irq: could not create main interrupt controller\n"); + return; + } + + s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); + s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0], + s3c_intc[0], 0x4a000018); +} +#endif + +#ifdef CONFIG_OF +static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + unsigned int ctrl_num = hw / 32; + unsigned int intc_hw = hw % 32; + struct s3c_irq_intc *intc = s3c_intc[ctrl_num]; + struct s3c_irq_intc *parent_intc = intc->parent; + struct s3c_irq_data *irq_data = &intc->irqs[intc_hw]; + + /* attach controller pointer to irq_data */ + irq_data->intc = intc; + irq_data->offset = intc_hw; + + if (!parent_intc) + irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq); + else + irq_set_chip_and_handler(virq, &s3c_irq_level_chip, + handle_edge_irq); + + irq_set_chip_data(virq, irq_data); + + return 0; +} + +/* Translate our of irq notation + * format: <ctrl_num ctrl_irq parent_irq type> + */ +static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n, + const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + struct s3c_irq_intc *intc; + struct s3c_irq_intc *parent_intc; + struct s3c_irq_data *irq_data; + struct s3c_irq_data *parent_irq_data; + int irqno; + + if (WARN_ON(intsize < 4)) + return -EINVAL; + + if (intspec[0] > 2 || !s3c_intc[intspec[0]]) { + pr_err("controller number %d invalid\n", intspec[0]); + return -EINVAL; + } + intc = s3c_intc[intspec[0]]; + + *out_hwirq = intspec[0] * 32 + intspec[2]; + *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; + + parent_intc = intc->parent; + if (parent_intc) { + irq_data = &intc->irqs[intspec[2]]; + irq_data->parent_irq = intspec[1]; + parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; + parent_irq_data->sub_intc = intc; + parent_irq_data->sub_bits |= (1UL << intspec[2]); + + /* parent_intc is always s3c_intc[0], so no offset */ + irqno = irq_create_mapping(parent_intc->domain, intspec[1]); + if (irqno < 0) { + pr_err("irq: could not map parent interrupt\n"); + return irqno; + } + + irq_set_chained_handler(irqno, s3c_irq_demux); + } + + return 0; +} + +static const struct irq_domain_ops s3c24xx_irq_ops_of = { + .map = s3c24xx_irq_map_of, + .xlate = s3c24xx_irq_xlate_of, +}; + +struct s3c24xx_irq_of_ctrl { + char *name; + unsigned long offset; + struct s3c_irq_intc **handle; + struct s3c_irq_intc **parent; + struct irq_domain_ops *ops; +}; + +static int __init s3c_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent, + struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl) +{ + struct s3c_irq_intc *intc; + struct s3c24xx_irq_of_ctrl *ctrl; + struct irq_domain *domain; + void __iomem *reg_base; + int i; + + reg_base = of_iomap(np, 0); + if (!reg_base) { + pr_err("irq-s3c24xx: could not map irq registers\n"); + return -EINVAL; + } + + domain = irq_domain_add_linear(np, num_ctrl * 32, + &s3c24xx_irq_ops_of, NULL); + if (!domain) { + pr_err("irq: could not create irq-domain\n"); + return -EINVAL; + } + + for (i = 0; i < num_ctrl; i++) { + ctrl = &s3c_ctrl[i]; + + pr_debug("irq: found controller %s\n", ctrl->name); + + intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); + if (!intc) + return -ENOMEM; + + intc->domain = domain; + intc->irqs = kcalloc(32, sizeof(struct s3c_irq_data), + GFP_KERNEL); + if (!intc->irqs) { + kfree(intc); + return -ENOMEM; + } + + if (ctrl->parent) { + intc->reg_pending = reg_base + ctrl->offset; + intc->reg_mask = reg_base + ctrl->offset + 0x4; + + if (*(ctrl->parent)) { + intc->parent = *(ctrl->parent); + } else { + pr_warn("irq: parent of %s missing\n", + ctrl->name); + kfree(intc->irqs); + kfree(intc); + continue; + } + } else { + intc->reg_pending = reg_base + ctrl->offset; + intc->reg_mask = reg_base + ctrl->offset + 0x08; + intc->reg_intpnd = reg_base + ctrl->offset + 0x10; + } + + s3c24xx_clear_intc(intc); + s3c_intc[i] = intc; + } + + set_handle_irq(s3c24xx_handle_irq); + + return 0; +} + +static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = { + { + .name = "intc", + .offset = 0, + }, { + .name = "subintc", + .offset = 0x18, + .parent = &s3c_intc[0], + } +}; + +static int __init s3c2410_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent) +{ + return s3c_init_intc_of(np, interrupt_parent, + s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl)); +} +IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of); + +static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = { + { + .name = "intc", + .offset = 0, + }, { + .name = "subintc", + .offset = 0x18, + .parent = &s3c_intc[0], + }, { + .name = "intc2", + .offset = 0x40, + } +}; + +static int __init s3c2416_init_intc_of(struct device_node *np, + struct device_node *interrupt_parent) +{ + return s3c_init_intc_of(np, interrupt_parent, + s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl)); +} +IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of); +#endif diff --git a/arch/arm/mach-s3c/irq-uart-s3c64xx.h b/arch/arm/mach-s3c/irq-uart-s3c64xx.h new file mode 100644 index 000000000..78eccdce9 --- /dev/null +++ b/arch/arm/mach-s3c/irq-uart-s3c64xx.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Header file for Samsung SoC UART IRQ demux for S3C64XX and later + */ + +struct s3c_uart_irq { + void __iomem *regs; + unsigned int base_irq; + unsigned int parent_irq; +}; + +extern void s3c_init_uart_irqs(struct s3c_uart_irq *irq, unsigned int nr_irqs); + diff --git a/arch/arm/mach-s3c/irqs-s3c24xx.h b/arch/arm/mach-s3c/irqs-s3c24xx.h new file mode 100644 index 000000000..fecbf7e44 --- /dev/null +++ b/arch/arm/mach-s3c/irqs-s3c24xx.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003-2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + */ + + +#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) + +#define NR_IRQS_S3C2410 (S3C2410_IRQSUB(10) + 1) + +/* 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 NR_IRQS_S3C2412 (S3C2410_IRQSUB(14) + 1) + +#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) + +#define NR_IRQS_S3C2416 (S3C2416_IRQ(7) + 1) + +/* extra irqs for s3c2440/s3c2442 */ + +#define IRQ_S3C2440_CAM_C S3C2410_IRQSUB(11) /* S3C2443 too */ +#define IRQ_S3C2440_CAM_P S3C2410_IRQSUB(12) /* S3C2443 too */ + +#define NR_IRQS_S3C2442 (S3C2410_IRQSUB(12) + 1) + +#define IRQ_S3C2440_WDT S3C2410_IRQSUB(13) +#define IRQ_S3C2440_AC97 S3C2410_IRQSUB(14) + +#define NR_IRQS_S3C2440 (S3C2410_IRQSUB(14) + 1) + +/* 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) + +#define NR_IRQS_S3C2443 (S3C2410_IRQSUB(28) + 1) + +/* 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-s3c/irqs-s3c64xx.h b/arch/arm/mach-s3c/irqs-s3c64xx.h new file mode 100644 index 000000000..c244e480e --- /dev/null +++ b/arch/arm/mach-s3c/irqs-s3c64xx.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* linux/arch/arm/mach-s3c64xx/include/mach/irqs.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - IRQ support + */ + +#ifndef __ASM_MACH_S3C64XX_IRQS_H +#define __ASM_MACH_S3C64XX_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.... + * + * note, since we're using the VICs, our start must be a + * mulitple of 32 to allow the common code to work + */ + +#define S3C_IRQ_OFFSET (32) + +#define S3C_IRQ(x) ((x) + S3C_IRQ_OFFSET) + +#define IRQ_VIC0_BASE S3C_IRQ(0) +#define IRQ_VIC1_BASE S3C_IRQ(32) + +/* VIC based IRQs */ + +#define S3C64XX_IRQ_VIC0(x) (IRQ_VIC0_BASE + (x)) +#define S3C64XX_IRQ_VIC1(x) (IRQ_VIC1_BASE + (x)) + +/* VIC0 */ + +#define IRQ_EINT0_3 S3C64XX_IRQ_VIC0(0) +#define IRQ_EINT4_11 S3C64XX_IRQ_VIC0(1) +#define IRQ_RTC_TIC S3C64XX_IRQ_VIC0(2) +#define IRQ_CAMIF_C S3C64XX_IRQ_VIC0(3) +#define IRQ_CAMIF_P S3C64XX_IRQ_VIC0(4) +#define IRQ_CAMIF_MC S3C64XX_IRQ_VIC0(5) +#define IRQ_S3C6410_IIC1 S3C64XX_IRQ_VIC0(5) +#define IRQ_S3C6410_IIS S3C64XX_IRQ_VIC0(6) +#define IRQ_S3C6400_CAMIF_MP S3C64XX_IRQ_VIC0(6) +#define IRQ_CAMIF_WE_C S3C64XX_IRQ_VIC0(7) +#define IRQ_S3C6410_G3D S3C64XX_IRQ_VIC0(8) +#define IRQ_S3C6400_CAMIF_WE_P S3C64XX_IRQ_VIC0(8) +#define IRQ_POST0 S3C64XX_IRQ_VIC0(9) +#define IRQ_ROTATOR S3C64XX_IRQ_VIC0(10) +#define IRQ_2D S3C64XX_IRQ_VIC0(11) +#define IRQ_TVENC S3C64XX_IRQ_VIC0(12) +#define IRQ_SCALER S3C64XX_IRQ_VIC0(13) +#define IRQ_BATF S3C64XX_IRQ_VIC0(14) +#define IRQ_JPEG S3C64XX_IRQ_VIC0(15) +#define IRQ_MFC S3C64XX_IRQ_VIC0(16) +#define IRQ_SDMA0 S3C64XX_IRQ_VIC0(17) +#define IRQ_SDMA1 S3C64XX_IRQ_VIC0(18) +#define IRQ_ARM_DMAERR S3C64XX_IRQ_VIC0(19) +#define IRQ_ARM_DMA S3C64XX_IRQ_VIC0(20) +#define IRQ_ARM_DMAS S3C64XX_IRQ_VIC0(21) +#define IRQ_KEYPAD S3C64XX_IRQ_VIC0(22) +#define IRQ_TIMER0_VIC S3C64XX_IRQ_VIC0(23) +#define IRQ_TIMER1_VIC S3C64XX_IRQ_VIC0(24) +#define IRQ_TIMER2_VIC S3C64XX_IRQ_VIC0(25) +#define IRQ_WDT S3C64XX_IRQ_VIC0(26) +#define IRQ_TIMER3_VIC S3C64XX_IRQ_VIC0(27) +#define IRQ_TIMER4_VIC S3C64XX_IRQ_VIC0(28) +#define IRQ_LCD_FIFO S3C64XX_IRQ_VIC0(29) +#define IRQ_LCD_VSYNC S3C64XX_IRQ_VIC0(30) +#define IRQ_LCD_SYSTEM S3C64XX_IRQ_VIC0(31) + +/* VIC1 */ + +#define IRQ_EINT12_19 S3C64XX_IRQ_VIC1(0) +#define IRQ_EINT20_27 S3C64XX_IRQ_VIC1(1) +#define IRQ_PCM0 S3C64XX_IRQ_VIC1(2) +#define IRQ_PCM1 S3C64XX_IRQ_VIC1(3) +#define IRQ_AC97 S3C64XX_IRQ_VIC1(4) +#define IRQ_UART0 S3C64XX_IRQ_VIC1(5) +#define IRQ_UART1 S3C64XX_IRQ_VIC1(6) +#define IRQ_UART2 S3C64XX_IRQ_VIC1(7) +#define IRQ_UART3 S3C64XX_IRQ_VIC1(8) +#define IRQ_DMA0 S3C64XX_IRQ_VIC1(9) +#define IRQ_DMA1 S3C64XX_IRQ_VIC1(10) +#define IRQ_ONENAND0 S3C64XX_IRQ_VIC1(11) +#define IRQ_ONENAND1 S3C64XX_IRQ_VIC1(12) +#define IRQ_NFC S3C64XX_IRQ_VIC1(13) +#define IRQ_CFCON S3C64XX_IRQ_VIC1(14) +#define IRQ_USBH S3C64XX_IRQ_VIC1(15) +#define IRQ_SPI0 S3C64XX_IRQ_VIC1(16) +#define IRQ_SPI1 S3C64XX_IRQ_VIC1(17) +#define IRQ_IIC S3C64XX_IRQ_VIC1(18) +#define IRQ_HSItx S3C64XX_IRQ_VIC1(19) +#define IRQ_HSIrx S3C64XX_IRQ_VIC1(20) +#define IRQ_RESERVED S3C64XX_IRQ_VIC1(21) +#define IRQ_MSM S3C64XX_IRQ_VIC1(22) +#define IRQ_HOSTIF S3C64XX_IRQ_VIC1(23) +#define IRQ_HSMMC0 S3C64XX_IRQ_VIC1(24) +#define IRQ_HSMMC1 S3C64XX_IRQ_VIC1(25) +#define IRQ_HSMMC2 IRQ_SPI1 /* shared with SPI1 */ +#define IRQ_OTG S3C64XX_IRQ_VIC1(26) +#define IRQ_IRDA S3C64XX_IRQ_VIC1(27) +#define IRQ_RTC_ALARM S3C64XX_IRQ_VIC1(28) +#define IRQ_SEC S3C64XX_IRQ_VIC1(29) +#define IRQ_PENDN S3C64XX_IRQ_VIC1(30) +#define IRQ_TC IRQ_PENDN +#define IRQ_ADC S3C64XX_IRQ_VIC1(31) + +/* compatibility for device defines */ + +#define IRQ_IIC1 IRQ_S3C6410_IIC1 + +/* Since the IRQ_EINT(x) are a linear mapping on current s3c64xx series + * we just defined them as an IRQ_EINT(x) macro from S3C_IRQ_EINT_BASE + * which we place after the pair of VICs. */ + +#define S3C_IRQ_EINT_BASE S3C_IRQ(64+5) + +#define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE) +#define IRQ_EINT(x) S3C_EINT(x) +#define IRQ_EINT_BIT(x) ((x) - S3C_EINT(0)) + +/* Next the external interrupt groups. These are similar to the IRQ_EINT(x) + * that they are sourced from the GPIO pins but with a different scheme for + * priority and source indication. + * + * The IRQ_EINT(x) can be thought of as 'group 0' of the available GPIO + * interrupts, but for historical reasons they are kept apart from these + * next interrupts. + * + * Use IRQ_EINT_GROUP(group, offset) to get the number for use in the + * machine specific support files. + */ + +#define IRQ_EINT_GROUP1_NR (15) +#define IRQ_EINT_GROUP2_NR (8) +#define IRQ_EINT_GROUP3_NR (5) +#define IRQ_EINT_GROUP4_NR (14) +#define IRQ_EINT_GROUP5_NR (7) +#define IRQ_EINT_GROUP6_NR (10) +#define IRQ_EINT_GROUP7_NR (16) +#define IRQ_EINT_GROUP8_NR (15) +#define IRQ_EINT_GROUP9_NR (9) + +#define IRQ_EINT_GROUP_BASE S3C_EINT(28) +#define IRQ_EINT_GROUP1_BASE (IRQ_EINT_GROUP_BASE + 0x00) +#define IRQ_EINT_GROUP2_BASE (IRQ_EINT_GROUP1_BASE + IRQ_EINT_GROUP1_NR) +#define IRQ_EINT_GROUP3_BASE (IRQ_EINT_GROUP2_BASE + IRQ_EINT_GROUP2_NR) +#define IRQ_EINT_GROUP4_BASE (IRQ_EINT_GROUP3_BASE + IRQ_EINT_GROUP3_NR) +#define IRQ_EINT_GROUP5_BASE (IRQ_EINT_GROUP4_BASE + IRQ_EINT_GROUP4_NR) +#define IRQ_EINT_GROUP6_BASE (IRQ_EINT_GROUP5_BASE + IRQ_EINT_GROUP5_NR) +#define IRQ_EINT_GROUP7_BASE (IRQ_EINT_GROUP6_BASE + IRQ_EINT_GROUP6_NR) +#define IRQ_EINT_GROUP8_BASE (IRQ_EINT_GROUP7_BASE + IRQ_EINT_GROUP7_NR) +#define IRQ_EINT_GROUP9_BASE (IRQ_EINT_GROUP8_BASE + IRQ_EINT_GROUP8_NR) + +#define IRQ_EINT_GROUP(group, no) (IRQ_EINT_GROUP##group##_BASE + (no)) + +/* Some boards have their own IRQs behind this */ +#define IRQ_BOARD_START (IRQ_EINT_GROUP9_BASE + IRQ_EINT_GROUP9_NR + 1) + +/* Set the default nr_irqs, boards can override if necessary */ +#define S3C64XX_NR_IRQS IRQ_BOARD_START + +/* Compatibility */ + +#define IRQ_ONENAND IRQ_ONENAND0 +#define IRQ_I2S0 IRQ_S3C6410_IIS + +#endif /* __ASM_MACH_S3C64XX_IRQS_H */ + diff --git a/arch/arm/mach-s3c/irqs.h b/arch/arm/mach-s3c/irqs.h new file mode 100644 index 000000000..0bff1c1c8 --- /dev/null +++ b/arch/arm/mach-s3c/irqs.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "irqs-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "irqs-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/keypad.h b/arch/arm/mach-s3c/keypad.h new file mode 100644 index 000000000..9754b9a29 --- /dev/null +++ b/arch/arm/mach-s3c/keypad.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Samsung Platform - Keypad platform data definitions + * + * Copyright (C) 2010 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + */ + +#ifndef __PLAT_SAMSUNG_KEYPAD_H +#define __PLAT_SAMSUNG_KEYPAD_H + +#include <linux/input/samsung-keypad.h> + +/** + * samsung_keypad_set_platdata - Set platform data for Samsung Keypad device. + * @pd: Platform data to register to device. + * + * Register the given platform data for use with Samsung Keypad device. + * The call will copy the platform data, so the board definitions can + * make the structure itself __initdata. + */ +extern void samsung_keypad_set_platdata(struct samsung_keypad_platdata *pd); + +/* defined by architecture to configure gpio. */ +extern void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols); + +#endif /* __PLAT_SAMSUNG_KEYPAD_H */ diff --git a/arch/arm/mach-s3c/mach-amlm5900.c b/arch/arm/mach-s3c/mach-amlm5900.c new file mode 100644 index 000000000..f85e5885e --- /dev/null +++ b/arch/arm/mach-s3c/mach-amlm5900.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2006 American Microsystems Limited +// David Anders <danders@amltd.com> +// +// @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/machine.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 <asm/irq.h> +#include <asm/mach-types.h> +#include <linux/platform_data/fb-s3c2410.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include <linux/platform_data/i2c-s3c2410.h> +#include "devs.h" +#include "cpu.h" +#include "gpio-cfg.h" + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> + +#include "s3c24xx.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 gpiod_lookup_table amlm5900_mmc_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init amlm5900_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_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, + .gpccon_reg = S3C2410_GPCCON, + .gpcup = 0x0000ffff, + .gpcup_mask = 0xffffffff, + .gpcup_reg = S3C2410_GPCUP, + + .gpdcon = 0xaaaaaaaa, + .gpdcon_mask = 0xffffffff, + .gpdcon_reg = S3C2410_GPDCON, + .gpdup = 0x0000ffff, + .gpdup_mask = 0xffffffff, + .gpdup_reg = S3C2410_GPDUP, +}; +#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); + gpiod_add_lookup_table(&amlm5900_mmc_gpio_table); + platform_add_devices(amlm5900_devices, ARRAY_SIZE(amlm5900_devices)); +} + +MACHINE_START(AML_M5900, "AML_M5900") + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = amlm5900_map_io, + .nr_irqs = NR_IRQS_S3C2410, + .init_irq = s3c2410_init_irq, + .init_machine = amlm5900_init, + .init_time = amlm5900_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-anubis.c b/arch/arm/mach-s3c/mach-anubis.c new file mode 100644 index 000000000..4536f3e66 --- /dev/null +++ b/arch/arm/mach-s3c/mach-anubis.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2003-2009 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// 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/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 <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include "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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.h> +#include <linux/mtd/partitions.h> + +#include <net/ax88796.h> + +#include "devs.h" +#include "cpu.h" +#include <linux/platform_data/asoc-s3c24xx_simtec.h> + +#include "anubis.h" +#include "s3c24xx.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, + }, + + /* 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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +/* 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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_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); + s3c24xx_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, + .nr_irqs = NR_IRQS_S3C2440, + .map_io = anubis_map_io, + .init_machine = anubis_init, + .init_irq = s3c2440_init_irq, + .init_time = anubis_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-anw6410.c b/arch/arm/mach-s3c/mach-anw6410.c new file mode 100644 index 000000000..b67eae43e --- /dev/null +++ b/arch/arm/mach-s3c/mach-anw6410.c @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// Copyright 2009 Kwangwoo Lee +// Kwangwoo Lee <kwangwoo.lee@gmail.com> + +#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/i2c.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/dm9000.h> + +#include <video/platform_lcd.h> +#include <video/samsung_fimd.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include "map.h" + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include "fb.h" + +#include "devs.h" +#include "cpu.h" +#include "irqs.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "s3c64xx.h" +#include "regs-modem-s3c64xx.h" + +/* DM9000 */ +#define ANW6410_PA_DM9000 (0x18000000) + +/* A hardware buffer to control external devices is mapped at 0x30000000. + * It can not be read. So current status must be kept in anw6410_extdev_status. + */ +#define ANW6410_VA_EXTDEV S3C_ADDR(0x02000000) +#define ANW6410_PA_EXTDEV (0x30000000) + +#define ANW6410_EN_DM9000 (1<<11) +#define ANW6410_EN_LCD (1<<14) + +static __u32 anw6410_extdev_status; + +static struct s3c2410_uartcfg anw6410_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, +}; + +/* framebuffer and LCD setup. */ +static void __init anw6410_lcd_mode_set(void) +{ + u32 tmp; + + /* set the LCD type */ + tmp = __raw_readl(S3C64XX_SPCON); + tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; + tmp |= S3C64XX_SPCON_LCD_SEL_RGB; + __raw_writel(tmp, S3C64XX_SPCON); + + /* remove the LCD bypass */ + tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); + tmp &= ~MIFPCON_LCD_BYPASS; + __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); +} + +/* GPF1 = LCD panel power + * GPF4 = LCD backlight control + */ +static void anw6410_lcd_power_set(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) { + anw6410_extdev_status |= (ANW6410_EN_LCD << 16); + __raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV); + + gpio_direction_output(S3C64XX_GPF(1), 1); + gpio_direction_output(S3C64XX_GPF(4), 1); + } else { + anw6410_extdev_status &= ~(ANW6410_EN_LCD << 16); + __raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV); + + gpio_direction_output(S3C64XX_GPF(1), 0); + gpio_direction_output(S3C64XX_GPF(4), 0); + } +} + +static struct plat_lcd_data anw6410_lcd_power_data = { + .set_power = anw6410_lcd_power_set, +}; + +static struct platform_device anw6410_lcd_powerdev = { + .name = "platform-lcd", + .dev.parent = &s3c_device_fb.dev, + .dev.platform_data = &anw6410_lcd_power_data, +}; + +static struct s3c_fb_pd_win anw6410_fb_win0 = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, +}; + +static struct fb_videomode anw6410_lcd_timing = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, +}; + +/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ +static struct s3c_fb_platdata anw6410_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &anw6410_lcd_timing, + .win[0] = &anw6410_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, +}; + +/* DM9000AEP 10/100 ethernet controller */ +static void __init anw6410_dm9000_enable(void) +{ + anw6410_extdev_status |= (ANW6410_EN_DM9000 << 16); + __raw_writel(anw6410_extdev_status, ANW6410_VA_EXTDEV); +} + +static struct resource anw6410_dm9000_resource[] = { + [0] = DEFINE_RES_MEM(ANW6410_PA_DM9000, 4), + [1] = DEFINE_RES_MEM(ANW6410_PA_DM9000 + 4, 501), + [2] = DEFINE_RES_NAMED(IRQ_EINT(15), 1, NULL, IORESOURCE_IRQ \ + | IRQF_TRIGGER_HIGH), +}; + +static struct dm9000_plat_data anw6410_dm9000_pdata = { + .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), + /* dev_addr can be set to provide hwaddr. */ +}; + +static struct platform_device anw6410_device_eth = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(anw6410_dm9000_resource), + .resource = anw6410_dm9000_resource, + .dev = { + .platform_data = &anw6410_dm9000_pdata, + }, +}; + +static struct map_desc anw6410_iodesc[] __initdata = { + { + .virtual = (unsigned long)ANW6410_VA_EXTDEV, + .pfn = __phys_to_pfn(ANW6410_PA_EXTDEV), + .length = SZ_64K, + .type = MT_DEVICE, + }, +}; + +static struct platform_device *anw6410_devices[] __initdata = { + &s3c_device_fb, + &anw6410_lcd_powerdev, + &anw6410_device_eth, +}; + +static void __init anw6410_map_io(void) +{ + s3c64xx_init_io(anw6410_iodesc, ARRAY_SIZE(anw6410_iodesc)); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(anw6410_uartcfgs, ARRAY_SIZE(anw6410_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); + + anw6410_lcd_mode_set(); +} + +static void __init anw6410_machine_init(void) +{ + s3c_fb_set_platdata(&anw6410_lcd_pdata); + + gpio_request(S3C64XX_GPF(1), "panel power"); + gpio_request(S3C64XX_GPF(4), "LCD backlight"); + + anw6410_dm9000_enable(); + + platform_add_devices(anw6410_devices, ARRAY_SIZE(anw6410_devices)); +} + +MACHINE_START(ANW6410, "A&W6410") + /* Maintainer: Kwangwoo Lee <kwangwoo.lee@gmail.com> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = anw6410_map_io, + .init_machine = anw6410_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-at2440evb.c b/arch/arm/mach-s3c/mach-at2440evb.c new file mode 100644 index 000000000..743403d87 --- /dev/null +++ b/arch/arm/mach-s3c/mach-at2440evb.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/gpio/machine.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 <linux/platform_data/fb-s3c2410.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include "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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.h> +#include <linux/mtd/partitions.h> + +#include "devs.h" +#include "cpu.h" +#include <linux/platform_data/mmc-s3cmci.h> + +#include "s3c24xx.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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +/* 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 = { + .set_power = s3c24xx_mci_def_set_power, +}; + +static struct gpiod_lookup_table at2440evb_mci_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* Card detect S3C2410_GPG(10) */ + GPIO_LOOKUP("GPIOG", 10, "cd", GPIO_ACTIVE_LOW), + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + + +/* 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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init at2440evb_init_time(void) +{ + s3c2440_init_clocks(16934400); + s3c24xx_timer_init(); +} + +static void __init at2440evb_init(void) +{ + s3c24xx_fb_set_platdata(&at2440evb_fb_info); + gpiod_add_lookup_table(&at2440evb_mci_gpio_table); + 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, + .nr_irqs = NR_IRQS_S3C2440, + .map_io = at2440evb_map_io, + .init_machine = at2440evb_init, + .init_irq = s3c2440_init_irq, + .init_time = at2440evb_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-bast.c b/arch/arm/mach-s3c/mach-bast.c new file mode 100644 index 000000000..a33ceab81 --- /dev/null +++ b/arch/arm/mach-s3c/mach-bast.c @@ -0,0 +1,583 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2003-2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://www.simtec.co.uk/products/EB2410ITX/ + +#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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.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 <linux/platform_data/fb-s3c2410.h> +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include <linux/soc/samsung/s3c-cpu-freq.h> +#include "devs.h" +#include "gpio-cfg.h" + +#include "bast.h" +#include "s3c24xx.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, + }, + /* 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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +/* 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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init bast_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_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, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = bast_map_io, + .init_irq = s3c2410_init_irq, + .init_machine = bast_init, + .init_time = bast_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-crag6410-module.c b/arch/arm/mach-s3c/mach-crag6410-module.c new file mode 100644 index 000000000..4edde13b8 --- /dev/null +++ b/arch/arm/mach-s3c/mach-crag6410-module.c @@ -0,0 +1,432 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Speyside modules for Cragganmore - board data probing +// +// Copyright 2011 Wolfson Microelectronics plc +// Mark Brown <broonie@opensource.wolfsonmicro.com> + +#include <linux/export.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/gpio/machine.h> + +#include <linux/mfd/wm831x/irq.h> +#include <linux/mfd/wm831x/gpio.h> +#include <linux/mfd/wm8994/pdata.h> +#include <linux/mfd/arizona/pdata.h> + +#include <linux/regulator/machine.h> + +#include <sound/wm0010.h> +#include <sound/wm2200.h> +#include <sound/wm5100.h> +#include <sound/wm8996.h> +#include <sound/wm8962.h> +#include <sound/wm9081.h> + +#include <linux/platform_data/spi-s3c64xx.h> + +#include "cpu.h" +#include "irqs.h" + +#include "crag6410.h" + +static struct wm0010_pdata wm0010_pdata = { + .gpio_reset = S3C64XX_GPN(6), + .reset_active_high = 1, /* Active high for Glenfarclas Rev 2 */ +}; + +static struct spi_board_info wm1253_devs[] = { + [0] = { + .modalias = "wm0010", + .max_speed_hz = 26 * 1000 * 1000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + .irq = S3C_EINT(4), + .platform_data = &wm0010_pdata, + }, +}; + +static struct spi_board_info balblair_devs[] = { + [0] = { + .modalias = "wm0010", + .max_speed_hz = 26 * 1000 * 1000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_0, + .irq = S3C_EINT(4), + .platform_data = &wm0010_pdata, + }, +}; + +static struct wm5100_pdata wm5100_pdata = { + .ldo_ena = S3C64XX_GPN(7), + .irq_flags = IRQF_TRIGGER_HIGH, + .gpio_base = CODEC_GPIO_BASE, + + .in_mode = { + WM5100_IN_DIFF, + WM5100_IN_DIFF, + WM5100_IN_DIFF, + WM5100_IN_SE, + }, + + .hp_pol = CODEC_GPIO_BASE + 3, + .jack_modes = { + { WM5100_MICDET_MICBIAS3, 0, 0 }, + { WM5100_MICDET_MICBIAS2, 1, 1 }, + }, + + .gpio_defaults = { + 0, + 0, + 0, + 0, + 0x2, /* IRQ: CMOS output */ + 0x3, /* CLKOUT: CMOS output */ + }, +}; + +static struct wm8996_retune_mobile_config wm8996_retune[] = { + { + .name = "Sub LPF", + .rate = 48000, + .regs = { + 0x6318, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, + 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, + 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 + }, + }, + { + .name = "Sub HPF", + .rate = 48000, + .regs = { + 0x000A, 0x6300, 0x1000, 0x0000, 0x0004, 0x2000, 0xF000, + 0x0000, 0x0004, 0x2000, 0xF000, 0x0000, 0x0004, 0x2000, + 0xF000, 0x0000, 0x0004, 0x1000, 0x0800, 0x4000 + }, + }, +}; + +static struct wm8996_pdata wm8996_pdata __initdata = { + .ldo_ena = S3C64XX_GPN(7), + .gpio_base = CODEC_GPIO_BASE, + .micdet_def = 1, + .inl_mode = WM8996_DIFFERRENTIAL_1, + .inr_mode = WM8996_DIFFERRENTIAL_1, + + .irq_flags = IRQF_TRIGGER_RISING, + + .gpio_default = { + 0x8001, /* GPIO1 == ADCLRCLK1 */ + 0x8001, /* GPIO2 == ADCLRCLK2, input due to CPU */ + 0x0141, /* GPIO3 == HP_SEL */ + 0x0002, /* GPIO4 == IRQ */ + 0x020e, /* GPIO5 == CLKOUT */ + }, + + .retune_mobile_cfgs = wm8996_retune, + .num_retune_mobile_cfgs = ARRAY_SIZE(wm8996_retune), +}; + +static struct wm8962_pdata wm8962_pdata __initdata = { + .gpio_init = { + 0, + WM8962_GPIO_FN_OPCLK, + WM8962_GPIO_FN_DMICCLK, + 0, + 0x8000 | WM8962_GPIO_FN_DMICDAT, + WM8962_GPIO_FN_IRQ, /* Open drain mode */ + }, + .in4_dc_measure = true, +}; + +static struct wm9081_pdata wm9081_pdata __initdata = { + .irq_high = false, + .irq_cmos = false, +}; + +static const struct i2c_board_info wm1254_devs[] = { + { I2C_BOARD_INFO("wm8996", 0x1a), + .platform_data = &wm8996_pdata, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + }, + { I2C_BOARD_INFO("wm9081", 0x6c), + .platform_data = &wm9081_pdata, }, +}; + +static const struct i2c_board_info wm1255_devs[] = { + { I2C_BOARD_INFO("wm5100", 0x1a), + .platform_data = &wm5100_pdata, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + }, + { I2C_BOARD_INFO("wm9081", 0x6c), + .platform_data = &wm9081_pdata, }, +}; + +static const struct i2c_board_info wm1259_devs[] = { + { I2C_BOARD_INFO("wm8962", 0x1a), + .platform_data = &wm8962_pdata, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + }, +}; + +static struct regulator_init_data wm8994_ldo1 = { + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data wm8994_ldo2 = { + .supply_regulator = "WALLVDD", +}; + +static struct wm8994_pdata wm8994_pdata = { + .gpio_base = CODEC_GPIO_BASE, + .micb2_delay = 150, + .gpio_defaults = { + 0x3, /* IRQ out, active high, CMOS */ + }, + .ldo = { + { .init_data = &wm8994_ldo1, }, + { .init_data = &wm8994_ldo2, }, + }, +}; + +static const struct i2c_board_info wm1277_devs[] = { + { I2C_BOARD_INFO("wm8958", 0x1a), /* WM8958 is the superset */ + .platform_data = &wm8994_pdata, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + WM831X_IRQ_GPIO_2, + .dev_name = "wm8958", + }, +}; + +static struct gpiod_lookup_table wm8994_gpiod_table = { + .dev_id = "i2c-wm8958", /* I2C device name */ + .table = { + GPIO_LOOKUP("GPION", 6, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPION", 4, + "wlf,ldo2ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct arizona_pdata wm5102_reva_pdata = { + .gpio_base = CODEC_GPIO_BASE, + .irq_flags = IRQF_TRIGGER_HIGH, + .micd_pol_gpio = CODEC_GPIO_BASE + 4, + .micd_rate = 6, + .gpio_defaults = { + [2] = 0x10000, /* AIF3TXLRCLK */ + [3] = 0x4, /* OPCLK */ + }, +}; + +static struct spi_board_info wm5102_reva_spi_devs[] = { + [0] = { + .modalias = "wm5102", + .max_speed_hz = 10 * 1000 * 1000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + + WM831X_IRQ_GPIO_2, + .platform_data = &wm5102_reva_pdata, + }, +}; + +static struct gpiod_lookup_table wm5102_reva_gpiod_table = { + .dev_id = "spi0.1", /* SPI device name */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldoena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct arizona_pdata wm5102_pdata = { + .gpio_base = CODEC_GPIO_BASE, + .irq_flags = IRQF_TRIGGER_HIGH, + .micd_pol_gpio = CODEC_GPIO_BASE + 2, + .gpio_defaults = { + [2] = 0x10000, /* AIF3TXLRCLK */ + [3] = 0x4, /* OPCLK */ + }, +}; + +static struct spi_board_info wm5102_spi_devs[] = { + [0] = { + .modalias = "wm5102", + .max_speed_hz = 10 * 1000 * 1000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + + WM831X_IRQ_GPIO_2, + .platform_data = &wm5102_pdata, + }, +}; + +static struct gpiod_lookup_table wm5102_gpiod_table = { + .dev_id = "spi0.1", /* SPI device name */ + .table = { + GPIO_LOOKUP("GPION", 7, + "wlf,ldo1ena", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct spi_board_info wm5110_spi_devs[] = { + [0] = { + .modalias = "wm5110", + .max_speed_hz = 10 * 1000 * 1000, + .bus_num = 0, + .chip_select = 1, + .mode = SPI_MODE_0, + .irq = GLENFARCLAS_PMIC_IRQ_BASE + + WM831X_IRQ_GPIO_2, + .platform_data = &wm5102_reva_pdata, + }, +}; + +static const struct i2c_board_info wm6230_i2c_devs[] = { + { I2C_BOARD_INFO("wm9081", 0x6c), + .platform_data = &wm9081_pdata, }, +}; + +static struct wm2200_pdata wm2200_pdata = { + .ldo_ena = S3C64XX_GPN(7), + .gpio_defaults = { + [2] = 0x0005, /* GPIO3 24.576MHz output clock */ + }, +}; + +static const struct i2c_board_info wm2200_i2c[] = { + { I2C_BOARD_INFO("wm2200", 0x3a), + .platform_data = &wm2200_pdata, }, +}; + +static const struct { + u8 id; + u8 rev; + const char *name; + const struct i2c_board_info *i2c_devs; + int num_i2c_devs; + const struct spi_board_info *spi_devs; + int num_spi_devs; + + struct gpiod_lookup_table *gpiod_table; +} gf_mods[] = { + { .id = 0x01, .rev = 0xff, .name = "1250-EV1 Springbank" }, + { .id = 0x02, .rev = 0xff, .name = "1251-EV1 Jura" }, + { .id = 0x03, .rev = 0xff, .name = "1252-EV1 Glenlivet" }, + { .id = 0x06, .rev = 0xff, .name = "WM8997-6721-CS96-EV1 Lapraoig" }, + { .id = 0x07, .rev = 0xff, .name = "WM5110-6271 Deanston", + .spi_devs = wm5110_spi_devs, + .num_spi_devs = ARRAY_SIZE(wm5110_spi_devs) }, + { .id = 0x08, .rev = 0xff, .name = "WM8903-6102 Tamdhu" }, + { .id = 0x09, .rev = 0xff, .name = "WM1811A-6305 Adelphi" }, + { .id = 0x0a, .rev = 0xff, .name = "WM8996-6272 Blackadder" }, + { .id = 0x0b, .rev = 0xff, .name = "WM8994-6235 Benromach" }, + { .id = 0x11, .rev = 0xff, .name = "6249-EV2 Glenfarclas", }, + { .id = 0x14, .rev = 0xff, .name = "6271-EV1 Lochnagar" }, + { .id = 0x15, .rev = 0xff, .name = "6320-EV1 Bells", + .i2c_devs = wm6230_i2c_devs, + .num_i2c_devs = ARRAY_SIZE(wm6230_i2c_devs) }, + { .id = 0x21, .rev = 0xff, .name = "1275-EV1 Mortlach" }, + { .id = 0x25, .rev = 0xff, .name = "1274-EV1 Glencadam" }, + { .id = 0x31, .rev = 0xff, .name = "1253-EV1 Tomatin", + .spi_devs = wm1253_devs, .num_spi_devs = ARRAY_SIZE(wm1253_devs) }, + { .id = 0x32, .rev = 0xff, .name = "XXXX-EV1 Caol Illa" }, + { .id = 0x33, .rev = 0xff, .name = "XXXX-EV1 Oban" }, + { .id = 0x34, .rev = 0xff, .name = "WM0010-6320-CS42 Balblair", + .spi_devs = balblair_devs, + .num_spi_devs = ARRAY_SIZE(balblair_devs) }, + { .id = 0x39, .rev = 0xff, .name = "1254-EV1 Dallas Dhu", + .i2c_devs = wm1254_devs, .num_i2c_devs = ARRAY_SIZE(wm1254_devs) }, + { .id = 0x3a, .rev = 0xff, .name = "1259-EV1 Tobermory", + .i2c_devs = wm1259_devs, .num_i2c_devs = ARRAY_SIZE(wm1259_devs) }, + { .id = 0x3b, .rev = 0xff, .name = "1255-EV1 Kilchoman", + .i2c_devs = wm1255_devs, .num_i2c_devs = ARRAY_SIZE(wm1255_devs) }, + { .id = 0x3c, .rev = 0xff, .name = "1273-EV1 Longmorn" }, + { .id = 0x3d, .rev = 0xff, .name = "1277-EV1 Littlemill", + .i2c_devs = wm1277_devs, .num_i2c_devs = ARRAY_SIZE(wm1277_devs), + .gpiod_table = &wm8994_gpiod_table }, + { .id = 0x3e, .rev = 0, .name = "WM5102-6271-EV1-CS127 Amrut", + .spi_devs = wm5102_reva_spi_devs, + .num_spi_devs = ARRAY_SIZE(wm5102_reva_spi_devs), + .gpiod_table = &wm5102_reva_gpiod_table }, + { .id = 0x3e, .rev = -1, .name = "WM5102-6271-EV1-CS127 Amrut", + .spi_devs = wm5102_spi_devs, + .num_spi_devs = ARRAY_SIZE(wm5102_spi_devs), + .gpiod_table = &wm5102_gpiod_table }, + { .id = 0x3f, .rev = -1, .name = "WM2200-6271-CS90-M-REV1", + .i2c_devs = wm2200_i2c, .num_i2c_devs = ARRAY_SIZE(wm2200_i2c) }, +}; + +static int wlf_gf_module_probe(struct i2c_client *i2c) +{ + int ret, i, j, id, rev; + + ret = i2c_smbus_read_byte_data(i2c, 0); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read ID: %d\n", ret); + return ret; + } + + id = (ret & 0xfe) >> 2; + rev = ret & 0x3; + for (i = 0; i < ARRAY_SIZE(gf_mods); i++) + if (id == gf_mods[i].id && (gf_mods[i].rev == 0xff || + rev == gf_mods[i].rev)) + break; + + gpiod_add_lookup_table(&wm5102_reva_gpiod_table); + gpiod_add_lookup_table(&wm5102_gpiod_table); + gpiod_add_lookup_table(&wm8994_gpiod_table); + + if (i < ARRAY_SIZE(gf_mods)) { + dev_info(&i2c->dev, "%s revision %d\n", + gf_mods[i].name, rev + 1); + + for (j = 0; j < gf_mods[i].num_i2c_devs; j++) { + if (IS_ERR(i2c_new_client_device(i2c->adapter, + &(gf_mods[i].i2c_devs[j])))) + dev_err(&i2c->dev, "Failed to register\n"); + } + + spi_register_board_info(gf_mods[i].spi_devs, + gf_mods[i].num_spi_devs); + + if (gf_mods[i].gpiod_table) + gpiod_add_lookup_table(gf_mods[i].gpiod_table); + } else { + dev_warn(&i2c->dev, "Unknown module ID 0x%x revision %d\n", + id, rev + 1); + } + + return 0; +} + +static const struct i2c_device_id wlf_gf_module_id[] = { + { "wlf-gf-module", 0 }, + { } +}; + +static struct i2c_driver wlf_gf_module_driver = { + .driver = { + .name = "wlf-gf-module" + }, + .probe_new = wlf_gf_module_probe, + .id_table = wlf_gf_module_id, +}; + +static int __init wlf_gf_module_register(void) +{ + if (!soc_is_s3c64xx()) + return 0; + + return i2c_add_driver(&wlf_gf_module_driver); +} +device_initcall(wlf_gf_module_register); diff --git a/arch/arm/mach-s3c/mach-crag6410.c b/arch/arm/mach-s3c/mach-crag6410.c new file mode 100644 index 000000000..9a45474d1 --- /dev/null +++ b/arch/arm/mach-s3c/mach-crag6410.c @@ -0,0 +1,890 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2011 Wolfson Microelectronics plc +// Mark Brown <broonie@opensource.wolfsonmicro.com> +// +// Copyright 2011 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> + +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/fb.h> +#include <linux/io.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/gpio/machine.h> +#include <linux/leds.h> +#include <linux/delay.h> +#include <linux/mmc/host.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/fixed.h> +#include <linux/pwm.h> +#include <linux/pwm_backlight.h> +#include <linux/dm9000.h> +#include <linux/gpio_keys.h> +#include <linux/gpio/driver.h> +#include <linux/spi/spi.h> + +#include <linux/platform_data/pca953x.h> +#include <linux/platform_data/s3c-hsotg.h> + +#include <video/platform_lcd.h> + +#include <linux/mfd/wm831x/core.h> +#include <linux/mfd/wm831x/pdata.h> +#include <linux/mfd/wm831x/irq.h> +#include <linux/mfd/wm831x/gpio.h> + +#include <sound/wm1250-ev1.h> + +#include <asm/mach/arch.h> +#include <asm/mach-types.h> + +#include <video/samsung_fimd.h> +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "irqs.h" + +#include "fb.h" +#include "sdhci.h" +#include "gpio-cfg.h" +#include <linux/platform_data/spi-s3c64xx.h> + +#include "keypad.h" +#include "devs.h" +#include "cpu.h" +#include <linux/soc/samsung/s3c-adc.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include "pm.h" + +#include "s3c64xx.h" +#include "crag6410.h" +#include "regs-gpio-memport-s3c64xx.h" +#include "regs-modem-s3c64xx.h" +#include "regs-sys-s3c64xx.h" + +/* serial port setup */ + +#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 crag6410_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, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, +}; + +static struct pwm_lookup crag6410_pwm_lookup[] = { + PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 100000, + PWM_POLARITY_NORMAL), +}; + +static struct platform_pwm_backlight_data crag6410_backlight_data = { + .max_brightness = 1000, + .dft_brightness = 600, +}; + +static struct platform_device crag6410_backlight_device = { + .name = "pwm-backlight", + .id = -1, + .dev = { + .parent = &samsung_device_pwm.dev, + .platform_data = &crag6410_backlight_data, + }, +}; + +static void crag6410_lcd_power_set(struct plat_lcd_data *pd, unsigned int power) +{ + pr_debug("%s: setting power %d\n", __func__, power); + + if (power) { + gpio_set_value(S3C64XX_GPB(0), 1); + msleep(1); + s3c_gpio_cfgpin(S3C64XX_GPF(14), S3C_GPIO_SFN(2)); + } else { + gpio_direction_output(S3C64XX_GPF(14), 0); + gpio_set_value(S3C64XX_GPB(0), 0); + } +} + +static struct platform_device crag6410_lcd_powerdev = { + .name = "platform-lcd", + .id = -1, + .dev.parent = &s3c_device_fb.dev, + .dev.platform_data = &(struct plat_lcd_data) { + .set_power = crag6410_lcd_power_set, + }, +}; + +/* 640x480 URT */ +static struct s3c_fb_pd_win crag6410_fb_win0 = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 640, + .yres = 480, + .virtual_y = 480 * 2, + .virtual_x = 640, +}; + +static struct fb_videomode crag6410_lcd_timing = { + .left_margin = 150, + .right_margin = 80, + .upper_margin = 40, + .lower_margin = 5, + .hsync_len = 40, + .vsync_len = 5, + .xres = 640, + .yres = 480, +}; + +/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ +static struct s3c_fb_platdata crag6410_lcd_pdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &crag6410_lcd_timing, + .win[0] = &crag6410_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, +}; + +/* 2x6 keypad */ + +static uint32_t crag6410_keymap[] = { + /* KEY(row, col, keycode) */ + KEY(0, 0, KEY_VOLUMEUP), + KEY(0, 1, KEY_HOME), + KEY(0, 2, KEY_VOLUMEDOWN), + KEY(0, 3, KEY_HELP), + KEY(0, 4, KEY_MENU), + KEY(0, 5, KEY_MEDIA), + KEY(1, 0, 232), + KEY(1, 1, KEY_DOWN), + KEY(1, 2, KEY_LEFT), + KEY(1, 3, KEY_UP), + KEY(1, 4, KEY_RIGHT), + KEY(1, 5, KEY_CAMERA), +}; + +static struct matrix_keymap_data crag6410_keymap_data = { + .keymap = crag6410_keymap, + .keymap_size = ARRAY_SIZE(crag6410_keymap), +}; + +static struct samsung_keypad_platdata crag6410_keypad_data = { + .keymap_data = &crag6410_keymap_data, + .rows = 2, + .cols = 6, +}; + +static struct gpio_keys_button crag6410_gpio_keys[] = { + [0] = { + .code = KEY_SUSPEND, + .gpio = S3C64XX_GPL(10), /* EINT 18 */ + .type = EV_KEY, + .wakeup = 1, + .active_low = 1, + }, + [1] = { + .code = SW_FRONT_PROXIMITY, + .gpio = S3C64XX_GPN(11), /* EINT 11 */ + .type = EV_SW, + }, +}; + +static struct gpio_keys_platform_data crag6410_gpio_keydata = { + .buttons = crag6410_gpio_keys, + .nbuttons = ARRAY_SIZE(crag6410_gpio_keys), +}; + +static struct platform_device crag6410_gpio_keydev = { + .name = "gpio-keys", + .id = 0, + .dev.platform_data = &crag6410_gpio_keydata, +}; + +static struct resource crag6410_dm9k_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN5, 2), + [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN5 + (1 << 8), 2), + [2] = DEFINE_RES_NAMED(S3C_EINT(17), 1, NULL, IORESOURCE_IRQ \ + | IORESOURCE_IRQ_HIGHLEVEL), +}; + +static struct dm9000_plat_data mini6410_dm9k_pdata = { + .flags = DM9000_PLATF_16BITONLY, +}; + +static struct platform_device crag6410_dm9k_device = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(crag6410_dm9k_resource), + .resource = crag6410_dm9k_resource, + .dev.platform_data = &mini6410_dm9k_pdata, +}; + +static struct resource crag6410_mmgpio_resource[] = { + [0] = DEFINE_RES_MEM_NAMED(S3C64XX_PA_XM0CSN4, 1, "dat"), +}; + +static struct platform_device crag6410_mmgpio = { + .name = "basic-mmio-gpio", + .id = -1, + .resource = crag6410_mmgpio_resource, + .num_resources = ARRAY_SIZE(crag6410_mmgpio_resource), + .dev.platform_data = &(struct bgpio_pdata) { + .base = MMGPIO_GPIO_BASE, + }, +}; + +static struct platform_device speyside_device = { + .name = "speyside", + .id = -1, +}; + +static struct platform_device lowland_device = { + .name = "lowland", + .id = -1, +}; + +static struct platform_device tobermory_device = { + .name = "tobermory", + .id = -1, +}; + +static struct platform_device littlemill_device = { + .name = "littlemill", + .id = -1, +}; + +static struct platform_device bells_wm2200_device = { + .name = "bells", + .id = 0, +}; + +static struct platform_device bells_wm5102_device = { + .name = "bells", + .id = 1, +}; + +static struct platform_device bells_wm5110_device = { + .name = "bells", + .id = 2, +}; + +static struct regulator_consumer_supply wallvdd_consumers[] = { + REGULATOR_SUPPLY("SPKVDD", "1-001a"), + REGULATOR_SUPPLY("SPKVDD1", "1-001a"), + REGULATOR_SUPPLY("SPKVDD2", "1-001a"), + REGULATOR_SUPPLY("SPKVDDL", "1-001a"), + REGULATOR_SUPPLY("SPKVDDR", "1-001a"), + + REGULATOR_SUPPLY("SPKVDDL", "spi0.1"), + REGULATOR_SUPPLY("SPKVDDR", "spi0.1"), + + REGULATOR_SUPPLY("DC1VDD", "0-0034"), + REGULATOR_SUPPLY("DC2VDD", "0-0034"), + REGULATOR_SUPPLY("DC3VDD", "0-0034"), + REGULATOR_SUPPLY("LDO1VDD", "0-0034"), + REGULATOR_SUPPLY("LDO2VDD", "0-0034"), + REGULATOR_SUPPLY("LDO4VDD", "0-0034"), + REGULATOR_SUPPLY("LDO5VDD", "0-0034"), + REGULATOR_SUPPLY("LDO6VDD", "0-0034"), + REGULATOR_SUPPLY("LDO7VDD", "0-0034"), + REGULATOR_SUPPLY("LDO8VDD", "0-0034"), + REGULATOR_SUPPLY("LDO9VDD", "0-0034"), + REGULATOR_SUPPLY("LDO10VDD", "0-0034"), + REGULATOR_SUPPLY("LDO11VDD", "0-0034"), + + REGULATOR_SUPPLY("DC1VDD", "1-0034"), + REGULATOR_SUPPLY("DC2VDD", "1-0034"), + REGULATOR_SUPPLY("DC3VDD", "1-0034"), + REGULATOR_SUPPLY("LDO1VDD", "1-0034"), + REGULATOR_SUPPLY("LDO2VDD", "1-0034"), + REGULATOR_SUPPLY("LDO4VDD", "1-0034"), + REGULATOR_SUPPLY("LDO5VDD", "1-0034"), + REGULATOR_SUPPLY("LDO6VDD", "1-0034"), + REGULATOR_SUPPLY("LDO7VDD", "1-0034"), + REGULATOR_SUPPLY("LDO8VDD", "1-0034"), + REGULATOR_SUPPLY("LDO9VDD", "1-0034"), + REGULATOR_SUPPLY("LDO10VDD", "1-0034"), + REGULATOR_SUPPLY("LDO11VDD", "1-0034"), +}; + +static struct regulator_init_data wallvdd_data = { + .constraints = { + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(wallvdd_consumers), + .consumer_supplies = wallvdd_consumers, +}; + +static struct fixed_voltage_config wallvdd_pdata = { + .supply_name = "WALLVDD", + .microvolts = 5000000, + .init_data = &wallvdd_data, +}; + +static struct platform_device wallvdd_device = { + .name = "reg-fixed-voltage", + .id = -1, + .dev = { + .platform_data = &wallvdd_pdata, + }, +}; + +static struct platform_device *crag6410_devices[] __initdata = { + &s3c_device_hsmmc0, + &s3c_device_hsmmc2, + &s3c_device_i2c0, + &s3c_device_i2c1, + &s3c_device_fb, + &s3c_device_ohci, + &s3c_device_usb_hsotg, + &samsung_device_pwm, + &s3c64xx_device_iis0, + &s3c64xx_device_iis1, + &samsung_device_keypad, + &crag6410_gpio_keydev, + &crag6410_dm9k_device, + &s3c64xx_device_spi0, + &crag6410_mmgpio, + &crag6410_lcd_powerdev, + &crag6410_backlight_device, + &speyside_device, + &tobermory_device, + &littlemill_device, + &lowland_device, + &bells_wm2200_device, + &bells_wm5102_device, + &bells_wm5110_device, + &wallvdd_device, +}; + +static struct pca953x_platform_data crag6410_pca_data = { + .gpio_base = PCA935X_GPIO_BASE, + .irq_base = -1, +}; + +/* VDDARM is controlled by DVS1 connected to GPK(0) */ +static struct wm831x_buckv_pdata vddarm_pdata = { + .dvs_control_src = 1, +}; + +static struct regulator_consumer_supply vddarm_consumers[] = { + REGULATOR_SUPPLY("vddarm", NULL), +}; + +static struct regulator_init_data vddarm = { + .constraints = { + .name = "VDDARM", + .min_uV = 1000000, + .max_uV = 1300000, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(vddarm_consumers), + .consumer_supplies = vddarm_consumers, + .supply_regulator = "WALLVDD", + .driver_data = &vddarm_pdata, +}; + +static struct regulator_consumer_supply vddint_consumers[] = { + REGULATOR_SUPPLY("vddint", NULL), +}; + +static struct regulator_init_data vddint = { + .constraints = { + .name = "VDDINT", + .min_uV = 1000000, + .max_uV = 1200000, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(vddint_consumers), + .consumer_supplies = vddint_consumers, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddmem = { + .constraints = { + .name = "VDDMEM", + .always_on = 1, + }, +}; + +static struct regulator_init_data vddsys = { + .constraints = { + .name = "VDDSYS,VDDEXT,VDDPCM,VDDSS", + .always_on = 1, + }, +}; + +static struct regulator_consumer_supply vddmmc_consumers[] = { + REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"), + REGULATOR_SUPPLY("vmmc", "s3c-sdhci.1"), + REGULATOR_SUPPLY("vmmc", "s3c-sdhci.2"), +}; + +static struct regulator_init_data vddmmc = { + .constraints = { + .name = "VDDMMC,UH", + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(vddmmc_consumers), + .consumer_supplies = vddmmc_consumers, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddotgi = { + .constraints = { + .name = "VDDOTGi", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddotg = { + .constraints = { + .name = "VDDOTG", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddhi = { + .constraints = { + .name = "VDDHI", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddadc = { + .constraints = { + .name = "VDDADC,VDDDAC", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddmem0 = { + .constraints = { + .name = "VDDMEM0", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddpll = { + .constraints = { + .name = "VDDPLL", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddlcd = { + .constraints = { + .name = "VDDLCD", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct regulator_init_data vddalive = { + .constraints = { + .name = "VDDALIVE", + .always_on = 1, + }, + .supply_regulator = "WALLVDD", +}; + +static struct wm831x_backup_pdata banff_backup_pdata = { + .charger_enable = 1, + .vlim = 2500, /* mV */ + .ilim = 200, /* uA */ +}; + +static struct wm831x_status_pdata banff_red_led = { + .name = "banff:red:", + .default_src = WM831X_STATUS_MANUAL, +}; + +static struct wm831x_status_pdata banff_green_led = { + .name = "banff:green:", + .default_src = WM831X_STATUS_MANUAL, +}; + +static struct wm831x_touch_pdata touch_pdata = { + .data_irq = S3C_EINT(26), + .pd_irq = S3C_EINT(27), +}; + +static struct wm831x_pdata crag_pmic_pdata = { + .wm831x_num = 1, + .irq_base = BANFF_PMIC_IRQ_BASE, + .gpio_base = BANFF_PMIC_GPIO_BASE, + .soft_shutdown = true, + + .backup = &banff_backup_pdata, + + .gpio_defaults = { + /* GPIO5: DVS1_REQ - CMOS, DBVDD, active high */ + [4] = WM831X_GPN_DIR | WM831X_GPN_POL | WM831X_GPN_ENA | 0x8, + /* GPIO11: Touchscreen data - CMOS, DBVDD, active high*/ + [10] = WM831X_GPN_POL | WM831X_GPN_ENA | 0x6, + /* GPIO12: Touchscreen pen down - CMOS, DBVDD, active high*/ + [11] = WM831X_GPN_POL | WM831X_GPN_ENA | 0x7, + }, + + .dcdc = { + &vddarm, /* DCDC1 */ + &vddint, /* DCDC2 */ + &vddmem, /* DCDC3 */ + }, + + .ldo = { + &vddsys, /* LDO1 */ + &vddmmc, /* LDO2 */ + NULL, /* LDO3 */ + &vddotgi, /* LDO4 */ + &vddotg, /* LDO5 */ + &vddhi, /* LDO6 */ + &vddadc, /* LDO7 */ + &vddmem0, /* LDO8 */ + &vddpll, /* LDO9 */ + &vddlcd, /* LDO10 */ + &vddalive, /* LDO11 */ + }, + + .status = { + &banff_green_led, + &banff_red_led, + }, + + .touch = &touch_pdata, +}; + +/* + * VDDARM is eventually ending up as a regulator hanging on the MFD cell device + * "wm831x-buckv.1" spawn from drivers/mfd/wm831x-core.c. + * + * From the note on the platform data we can see that this is clearly DVS1 + * and assigned as dcdc1 resource to the MFD core which sets .id of the cell + * spawning the DVS1 platform device to 1, then the cell platform device + * name is calculated from 10*instance + id resulting in the device name + * "wm831x-buckv.11" + */ +static struct gpiod_lookup_table crag_pmic_gpiod_table = { + .dev_id = "wm831x-buckv.11", + .table = { + GPIO_LOOKUP("GPIOK", 0, "dvs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct i2c_board_info i2c_devs0[] = { + { I2C_BOARD_INFO("24c08", 0x50), }, + { I2C_BOARD_INFO("tca6408", 0x20), + .platform_data = &crag6410_pca_data, + }, + { I2C_BOARD_INFO("wm8312", 0x34), + .platform_data = &crag_pmic_pdata, + .irq = S3C_EINT(23), + }, +}; + +static struct s3c2410_platform_i2c i2c0_pdata = { + .frequency = 400000, +}; + +static struct regulator_consumer_supply pvdd_1v2_consumers[] = { + REGULATOR_SUPPLY("DCVDD", "spi0.0"), + REGULATOR_SUPPLY("AVDD", "spi0.0"), + REGULATOR_SUPPLY("AVDD", "spi0.1"), +}; + +static struct regulator_init_data pvdd_1v2 = { + .constraints = { + .name = "PVDD_1V2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + + .consumer_supplies = pvdd_1v2_consumers, + .num_consumer_supplies = ARRAY_SIZE(pvdd_1v2_consumers), +}; + +static struct regulator_consumer_supply pvdd_1v8_consumers[] = { + REGULATOR_SUPPLY("LDOVDD", "1-001a"), + REGULATOR_SUPPLY("PLLVDD", "1-001a"), + REGULATOR_SUPPLY("DBVDD", "1-001a"), + REGULATOR_SUPPLY("DBVDD1", "1-001a"), + REGULATOR_SUPPLY("DBVDD2", "1-001a"), + REGULATOR_SUPPLY("DBVDD3", "1-001a"), + REGULATOR_SUPPLY("CPVDD", "1-001a"), + REGULATOR_SUPPLY("AVDD2", "1-001a"), + REGULATOR_SUPPLY("DCVDD", "1-001a"), + REGULATOR_SUPPLY("AVDD", "1-001a"), + REGULATOR_SUPPLY("DBVDD", "spi0.0"), + + REGULATOR_SUPPLY("DBVDD", "1-003a"), + REGULATOR_SUPPLY("LDOVDD", "1-003a"), + REGULATOR_SUPPLY("CPVDD", "1-003a"), + REGULATOR_SUPPLY("AVDD", "1-003a"), + REGULATOR_SUPPLY("DBVDD1", "spi0.1"), + REGULATOR_SUPPLY("DBVDD2", "spi0.1"), + REGULATOR_SUPPLY("DBVDD3", "spi0.1"), + REGULATOR_SUPPLY("LDOVDD", "spi0.1"), + REGULATOR_SUPPLY("CPVDD", "spi0.1"), +}; + +static struct regulator_init_data pvdd_1v8 = { + .constraints = { + .name = "PVDD_1V8", + .always_on = 1, + }, + + .consumer_supplies = pvdd_1v8_consumers, + .num_consumer_supplies = ARRAY_SIZE(pvdd_1v8_consumers), +}; + +static struct regulator_consumer_supply pvdd_3v3_consumers[] = { + REGULATOR_SUPPLY("MICVDD", "1-001a"), + REGULATOR_SUPPLY("AVDD1", "1-001a"), +}; + +static struct regulator_init_data pvdd_3v3 = { + .constraints = { + .name = "PVDD_3V3", + .always_on = 1, + }, + + .consumer_supplies = pvdd_3v3_consumers, + .num_consumer_supplies = ARRAY_SIZE(pvdd_3v3_consumers), +}; + +static struct wm831x_pdata glenfarclas_pmic_pdata = { + .wm831x_num = 2, + .irq_base = GLENFARCLAS_PMIC_IRQ_BASE, + .gpio_base = GLENFARCLAS_PMIC_GPIO_BASE, + .soft_shutdown = true, + + .gpio_defaults = { + /* GPIO1-3: IRQ inputs, rising edge triggered, CMOS */ + [0] = WM831X_GPN_DIR | WM831X_GPN_POL | WM831X_GPN_ENA, + [1] = WM831X_GPN_DIR | WM831X_GPN_POL | WM831X_GPN_ENA, + [2] = WM831X_GPN_DIR | WM831X_GPN_POL | WM831X_GPN_ENA, + }, + + .dcdc = { + &pvdd_1v2, /* DCDC1 */ + &pvdd_1v8, /* DCDC2 */ + &pvdd_3v3, /* DCDC3 */ + }, + + .disable_touch = true, +}; + +static struct wm1250_ev1_pdata wm1250_ev1_pdata = { + .gpios = { + [WM1250_EV1_GPIO_CLK_ENA] = S3C64XX_GPN(12), + [WM1250_EV1_GPIO_CLK_SEL0] = S3C64XX_GPL(12), + [WM1250_EV1_GPIO_CLK_SEL1] = S3C64XX_GPL(13), + [WM1250_EV1_GPIO_OSR] = S3C64XX_GPL(14), + [WM1250_EV1_GPIO_MASTER] = S3C64XX_GPL(8), + }, +}; + +static struct i2c_board_info i2c_devs1[] = { + { I2C_BOARD_INFO("wm8311", 0x34), + .irq = S3C_EINT(0), + .platform_data = &glenfarclas_pmic_pdata }, + + { I2C_BOARD_INFO("wlf-gf-module", 0x20) }, + { I2C_BOARD_INFO("wlf-gf-module", 0x22) }, + { I2C_BOARD_INFO("wlf-gf-module", 0x24) }, + { I2C_BOARD_INFO("wlf-gf-module", 0x25) }, + { I2C_BOARD_INFO("wlf-gf-module", 0x26) }, + + { I2C_BOARD_INFO("wm1250-ev1", 0x27), + .platform_data = &wm1250_ev1_pdata }, +}; + +static struct s3c2410_platform_i2c i2c1_pdata = { + .frequency = 400000, + .bus_num = 1, +}; + +static void __init crag6410_map_io(void) +{ + s3c64xx_init_io(NULL, 0); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(crag6410_uartcfgs, ARRAY_SIZE(crag6410_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); + + /* LCD type and Bypass set by bootloader */ +} + +static struct s3c_sdhci_platdata crag6410_hsmmc2_pdata = { + .max_width = 4, + .cd_type = S3C_SDHCI_CD_PERMANENT, + .host_caps = MMC_CAP_POWER_OFF_CARD, +}; + +static void crag6410_cfg_sdhci0(struct platform_device *dev, int width) +{ + /* Set all the necessary GPG pins to special-function 2 */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPG(0), 2 + width, S3C_GPIO_SFN(2)); + + /* force card-detected for prototype 0 */ + s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_DOWN); +} + +static struct s3c_sdhci_platdata crag6410_hsmmc0_pdata = { + .max_width = 4, + .cd_type = S3C_SDHCI_CD_INTERNAL, + .cfg_gpio = crag6410_cfg_sdhci0, + .host_caps = MMC_CAP_POWER_OFF_CARD, +}; + +static const struct gpio_led gpio_leds[] = { + { + .name = "d13:green:", + .gpio = MMGPIO_GPIO_BASE + 0, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d14:green:", + .gpio = MMGPIO_GPIO_BASE + 1, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d15:green:", + .gpio = MMGPIO_GPIO_BASE + 2, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d16:green:", + .gpio = MMGPIO_GPIO_BASE + 3, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d17:green:", + .gpio = MMGPIO_GPIO_BASE + 4, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d18:green:", + .gpio = MMGPIO_GPIO_BASE + 5, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d19:green:", + .gpio = MMGPIO_GPIO_BASE + 6, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, + { + .name = "d20:green:", + .gpio = MMGPIO_GPIO_BASE + 7, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, +}; + +static const struct gpio_led_platform_data gpio_leds_pdata = { + .leds = gpio_leds, + .num_leds = ARRAY_SIZE(gpio_leds), +}; + +static struct dwc2_hsotg_plat crag6410_hsotg_pdata; + +static struct gpiod_lookup_table crag_spi0_gpiod_table = { + .dev_id = "s3c6410-spi.0", + .table = { + GPIO_LOOKUP_IDX("GPIOC", 3, "cs", 0, GPIO_ACTIVE_LOW), + GPIO_LOOKUP_IDX("GPION", 5, "cs", 1, GPIO_ACTIVE_LOW), + { }, + }, +}; + +static void __init crag6410_machine_init(void) +{ + /* Open drain IRQs need pullups */ + s3c_gpio_setpull(S3C64XX_GPM(0), S3C_GPIO_PULL_UP); + s3c_gpio_setpull(S3C64XX_GPN(0), S3C_GPIO_PULL_UP); + + gpio_request(S3C64XX_GPB(0), "LCD power"); + gpio_direction_output(S3C64XX_GPB(0), 0); + + gpio_request(S3C64XX_GPF(14), "LCD PWM"); + gpio_direction_output(S3C64XX_GPF(14), 0); /* turn off */ + + gpio_request(S3C64XX_GPB(1), "SD power"); + gpio_direction_output(S3C64XX_GPB(1), 0); + + gpio_request(S3C64XX_GPF(10), "nRESETSEL"); + gpio_direction_output(S3C64XX_GPF(10), 1); + + s3c_sdhci0_set_platdata(&crag6410_hsmmc0_pdata); + s3c_sdhci2_set_platdata(&crag6410_hsmmc2_pdata); + + s3c_i2c0_set_platdata(&i2c0_pdata); + s3c_i2c1_set_platdata(&i2c1_pdata); + s3c_fb_set_platdata(&crag6410_lcd_pdata); + dwc2_hsotg_set_platdata(&crag6410_hsotg_pdata); + + gpiod_add_lookup_table(&crag_pmic_gpiod_table); + i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); + i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); + + samsung_keypad_set_platdata(&crag6410_keypad_data); + + gpiod_add_lookup_table(&crag_spi0_gpiod_table); + s3c64xx_spi0_set_platdata(0, 2); + + pwm_add_table(crag6410_pwm_lookup, ARRAY_SIZE(crag6410_pwm_lookup)); + platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices)); + + gpio_led_register_device(-1, &gpio_leds_pdata); + + regulator_has_full_constraints(); + + s3c64xx_pm_init(); +} + +MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") + /* Maintainer: Mark Brown <broonie@opensource.wolfsonmicro.com> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = crag6410_map_io, + .init_machine = crag6410_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-gta02.c b/arch/arm/mach-s3c/mach-gta02.c new file mode 100644 index 000000000..d50a81d85 --- /dev/null +++ b/arch/arm/mach-s3c/mach-gta02.c @@ -0,0 +1,588 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// 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. + +#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/machine.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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.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 <linux/platform_data/fb-s3c2410.h> + +#include "regs-gpio.h" +#include "regs-irq.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include "gpio-cfg.h" +#include "pm.h" + +#include "s3c24xx.h" +#include "gta02.h" + +static struct pcf50633 *gta02_pcf; + +/* + * This gets called frequently when we paniced. + */ + +static long gta02_panic_blink(int state) +{ + char led; + + led = (state) ? 1 : 0; + gpio_direction_output(GTA02_GPIO_AUX_LED, led); + + return 0; +} + + +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 + +#ifdef CONFIG_PCF50633_ADC +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); +} +#endif + +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 + +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, + }, + }, + + }, + .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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + + +/* Get PMU to set USB current limit accordingly. */ +static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = { + .vbus_draw = gta02_udc_vbus_draw, +}; + +static struct gpiod_lookup_table gta02_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOB", 9, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* 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 struct gpiod_lookup_table gta02_audio_gpio_table = { + .dev_id = "neo1973-audio", + .table = { + GPIO_LOOKUP("GPIOJ", 2, "amp-shut", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOJ", 1, "hp", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct platform_device gta02_audio = { + .name = "neo1973-audio", + .id = -1, +}; + +static struct gpiod_lookup_table gta02_mmc_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_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, + >a02_audio, +}; + +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)); + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + + gpiod_add_lookup_table(>a02_udc_gpio_table); + gpiod_add_lookup_table(>a02_audio_gpio_table); + gpiod_add_lookup_table(>a02_mmc_gpio_table); + 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); + s3c24xx_timer_init(); +} + +MACHINE_START(NEO1973_GTA02, "GTA02") + /* Maintainer: Nelson Castillo <arhuaco@freaks-unidos.net> */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2442, + .map_io = gta02_map_io, + .init_irq = s3c2442_init_irq, + .init_machine = gta02_machine_init, + .init_time = gta02_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-h1940.c b/arch/arm/mach-s3c/mach-h1940.c new file mode 100644 index 000000000..83ac6cfdb --- /dev/null +++ b/arch/arm/mach-s3c/mach-h1940.c @@ -0,0 +1,809 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2003-2005 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// https://www.handhelds.org/projects/h1940.html + +#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/gpio/machine.h> +#include <linux/input.h> +#include <linux/gpio_keys.h> +#include <linux/pwm.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 <linux/platform_data/fb-s3c2410.h> +#include "map.h" +#include "hardware-s3c24xx.h" +#include "regs-clock.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include "gpio-cfg.h" +#include "pm.h" + +#include "s3c24xx.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)) + +#define S3C24XX_PLL_MDIV_SHIFT (12) +#define S3C24XX_PLL_PDIV_SHIFT (4) +#define S3C24XX_PLL_SDIV_SHIFT (0) + +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 = { +}; + +static struct gpiod_lookup_table h1940_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 5, "vbus", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("H1940_LATCH", 7, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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, + .gpccon_reg = S3C2410_GPCCON, + .gpcup = 0x0000ffff, + .gpcup_mask = 0xffffffff, + .gpcup_reg = S3C2410_GPCUP, + .gpdcon = 0xaa84aaa0, + .gpdcon_mask = 0xffffffff, + .gpdcon_reg = S3C2410_GPDCON, + .gpdup = 0x0000faff, + .gpdup_mask = 0xffffffff, + .gpdup_reg = S3C2410_GPDUP, +}; + +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 struct gpiod_lookup_table h1940_bat_gpio_table = { + .dev_id = "s3c-adc-battery", + .table = { + /* Charge status S3C2410_GPF(3) */ + GPIO_LOOKUP("GPIOF", 3, "charge-status", GPIO_ACTIVE_LOW), + { }, + }, +}; + +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, + .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(struct gpio_desc *desc, int state, + unsigned long *delay_on, unsigned long *delay_off) +{ + int blink_gpio, check_gpio1, check_gpio2; + int gpio = desc ? desc_to_gpio(desc) : -EINVAL; + + 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) +{ + s3c24xx_mci_def_set_power(power_mode, 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 = { + .set_power = h1940_set_mmc_power, + .ocr_avail = MMC_VDD_32_33, +}; + +static struct gpiod_lookup_table h1940_mmc_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* Card detect S3C2410_GPF(5) */ + GPIO_LOOKUP("GPIOF", 5, "cd", GPIO_ACTIVE_LOW), + /* Write protect S3C2410_GPH(8) */ + GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_LOW), + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table h1940_audio_gpio_table = { + .dev_id = "h1940-audio", + .table = { + GPIO_LOOKUP("H1940_LATCH", + H1940_LATCH_AUDIO_POWER - H1940_LATCH_GPIO(0), + "speaker-power", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOG", 4, "hp", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct platform_device h1940_audio = { + .name = "h1940-audio", + .id = -1, +}; + +static struct pwm_lookup h1940_pwm_lookup[] = { + PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 36296, + PWM_POLARITY_NORMAL), +}; + +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 = { + .max_brightness = 100, + .dft_brightness = 50, + .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, + &h1940_audio, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_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_data(&h1940_latch_gpiochip, NULL)); +} + +static void __init h1940_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_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); + gpiod_add_lookup_table(&h1940_udc_gpio_table); + gpiod_add_lookup_table(&h1940_mmc_gpio_table); + gpiod_add_lookup_table(&h1940_audio_gpio_table); + gpiod_add_lookup_table(&h1940_bat_gpio_table); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + 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); + + pwm_add_table(h1940_pwm_lookup, ARRAY_SIZE(h1940_pwm_lookup)); + 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, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = h1940_map_io, + .reserve = h1940_reserve, + .init_irq = s3c2410_init_irq, + .init_machine = h1940_init, + .init_time = h1940_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-hmt.c b/arch/arm/mach-s3c/mach-hmt.c new file mode 100644 index 000000000..49ba16c44 --- /dev/null +++ b/arch/arm/mach-s3c/mach-hmt.c @@ -0,0 +1,282 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// mach-hmt.c - Platform code for Airgoo HMT +// +// Copyright 2009 Peter Korsgaard <jacmet@sunsite.dk> + +#include <linux/kernel.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/i2c.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/leds.h> +#include <linux/pwm.h> +#include <linux/pwm_backlight.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <video/samsung_fimd.h> +#include "map.h" +#include "irqs.h" + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include "gpio-samsung.h" +#include "fb.h" +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include "devs.h" +#include "cpu.h" + +#include "s3c64xx.h" + +#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 hmt_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 pwm_lookup hmt_pwm_lookup[] = { + PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL, + 1000000000 / (100 * 256 * 20), PWM_POLARITY_NORMAL), +}; + +static int hmt_bl_init(struct device *dev) +{ + int ret; + + ret = gpio_request(S3C64XX_GPB(4), "lcd backlight enable"); + if (!ret) + ret = gpio_direction_output(S3C64XX_GPB(4), 0); + + return ret; +} + +static int hmt_bl_notify(struct device *dev, int brightness) +{ + /* + * translate from CIELUV/CIELAB L*->brightness, E.G. from + * perceived luminance to light output. Assumes range 0..25600 + */ + if (brightness < 0x800) { + /* Y = Yn * L / 903.3 */ + brightness = (100*256 * brightness + 231245/2) / 231245; + } else { + /* Y = Yn * ((L + 16) / 116 )^3 */ + int t = (brightness*4 + 16*1024 + 58)/116; + brightness = 25 * ((t * t * t + 0x100000/2) / 0x100000); + } + + gpio_set_value(S3C64XX_GPB(4), brightness); + + return brightness; +} + +static void hmt_bl_exit(struct device *dev) +{ + gpio_free(S3C64XX_GPB(4)); +} + +static struct platform_pwm_backlight_data hmt_backlight_data = { + .max_brightness = 100 * 256, + .dft_brightness = 40 * 256, + .init = hmt_bl_init, + .notify = hmt_bl_notify, + .exit = hmt_bl_exit, + +}; + +static struct platform_device hmt_backlight_device = { + .name = "pwm-backlight", + .dev = { + .parent = &samsung_device_pwm.dev, + .platform_data = &hmt_backlight_data, + }, +}; + +static struct s3c_fb_pd_win hmt_fb_win0 = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, +}; + +static struct fb_videomode hmt_lcd_timing = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, +}; + +/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ +static struct s3c_fb_platdata hmt_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &hmt_lcd_timing, + .win[0] = &hmt_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, +}; + +static struct mtd_partition hmt_nand_part[] = { + [0] = { + .name = "uboot", + .size = SZ_512K, + .offset = 0, + }, + [1] = { + .name = "uboot-env1", + .size = SZ_256K, + .offset = SZ_512K, + }, + [2] = { + .name = "uboot-env2", + .size = SZ_256K, + .offset = SZ_512K + SZ_256K, + }, + [3] = { + .name = "kernel", + .size = SZ_2M, + .offset = SZ_1M, + }, + [4] = { + .name = "rootfs", + .size = MTDPART_SIZ_FULL, + .offset = SZ_1M + SZ_2M, + }, +}; + +static struct s3c2410_nand_set hmt_nand_sets[] = { + [0] = { + .name = "nand", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(hmt_nand_part), + .partitions = hmt_nand_part, + }, +}; + +static struct s3c2410_platform_nand hmt_nand_info = { + .tacls = 25, + .twrph0 = 55, + .twrph1 = 40, + .nr_sets = ARRAY_SIZE(hmt_nand_sets), + .sets = hmt_nand_sets, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +static struct gpio_led hmt_leds[] = { + { /* left function keys */ + .name = "left:blue", + .gpio = S3C64XX_GPO(12), + .default_trigger = "default-on", + }, + { /* right function keys - red */ + .name = "right:red", + .gpio = S3C64XX_GPO(13), + }, + { /* right function keys - green */ + .name = "right:green", + .gpio = S3C64XX_GPO(14), + }, + { /* right function keys - blue */ + .name = "right:blue", + .gpio = S3C64XX_GPO(15), + .default_trigger = "default-on", + }, +}; + +static struct gpio_led_platform_data hmt_led_data = { + .num_leds = ARRAY_SIZE(hmt_leds), + .leds = hmt_leds, +}; + +static struct platform_device hmt_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &hmt_led_data, +}; + +static struct map_desc hmt_iodesc[] = {}; + +static struct platform_device *hmt_devices[] __initdata = { + &s3c_device_i2c0, + &s3c_device_nand, + &s3c_device_fb, + &s3c_device_ohci, + &samsung_device_pwm, + &hmt_backlight_device, + &hmt_leds_device, +}; + +static void __init hmt_map_io(void) +{ + s3c64xx_init_io(hmt_iodesc, ARRAY_SIZE(hmt_iodesc)); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(hmt_uartcfgs, ARRAY_SIZE(hmt_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); +} + +static void __init hmt_machine_init(void) +{ + s3c_i2c0_set_platdata(NULL); + s3c_fb_set_platdata(&hmt_lcd_pdata); + s3c_nand_set_platdata(&hmt_nand_info); + + gpio_request(S3C64XX_GPC(7), "usb power"); + gpio_direction_output(S3C64XX_GPC(7), 0); + gpio_request(S3C64XX_GPM(0), "usb power"); + gpio_direction_output(S3C64XX_GPM(0), 1); + gpio_request(S3C64XX_GPK(7), "usb power"); + gpio_direction_output(S3C64XX_GPK(7), 1); + gpio_request(S3C64XX_GPF(13), "usb power"); + gpio_direction_output(S3C64XX_GPF(13), 1); + + pwm_add_table(hmt_pwm_lookup, ARRAY_SIZE(hmt_pwm_lookup)); + platform_add_devices(hmt_devices, ARRAY_SIZE(hmt_devices)); +} + +MACHINE_START(HMT, "Airgoo-HMT") + /* Maintainer: Peter Korsgaard <jacmet@sunsite.dk> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = hmt_map_io, + .init_machine = hmt_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-jive.c b/arch/arm/mach-s3c/mach-jive.c new file mode 100644 index 000000000..16859bb3b --- /dev/null +++ b/arch/arm/mach-s3c/mach-jive.c @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2007 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://armlinux.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/gpio/machine.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 "hardware-s3c24xx.h" +#include "regs-gpio.h" +#include <linux/platform_data/fb-s3c2410.h> +#include "gpio-samsung.h" + +#include <asm/mach-types.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.h> +#include <linux/mtd/partitions.h> + +#include "gpio-cfg.h" +#include "devs.h" +#include "cpu.h" +#include "pm.h" +#include <linux/platform_data/usb-s3c2410_udc.h> + +#include "s3c24xx.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), + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +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 1; + + if (kstrtoul(options, 10, &set)) { + printk(KERN_ERR "failed to parse mtdset=%s\n", options); + return 1; + } + + switch (set) { + case 1: + nand->nr_partitions = ARRAY_SIZE(jive_imageB_nand_part); + nand->partitions = jive_imageB_nand_part; + break; + case 0: + /* this is already setup in the nand info */ + break; + default: + printk(KERN_ERR "Unknown mtd set %ld specified," + "using default.", set); + } + + return 1; +} + +/* 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), + .gpcup_reg = S3C2410_GPCUP, + + .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)), + + .gpccon_reg = S3C2410_GPCCON, + + .gpdup = (0x3f << 2) | (0x3f << 10), + + .gpdup_reg = S3C2410_GPDUP, + + .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)), + + .gpdcon_reg = S3C2410_GPDCON, +}; + +/* 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 = { + .num_chipselect = 1, +}; + +static struct platform_device jive_device_lcdspi = { + .name = "spi_gpio", + .id = 1, + .dev.platform_data = &jive_lcd_spi, +}; + +static struct gpiod_lookup_table jive_lcdspi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOG", 8, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 8, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 7, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* WM8750 audio code SPI definition */ + +static struct spi_gpio_platform_data jive_wm8750_spi = { + .num_chipselect = 1, +}; + +static struct platform_device jive_device_wm8750 = { + .name = "spi_gpio", + .id = 2, + .dev.platform_data = &jive_wm8750_spi, +}; + +static struct gpiod_lookup_table jive_wm8750_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOB", 4, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 9, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOH", 10, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* 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, + }, { + .modalias = "WM8750", + .bus_num = 2, + .chip_select = 0, + .mode = SPI_MODE_0, /* CPOL=0, CPHA=0 */ + .max_speed_hz = 100000, + }, +}; + +/* 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 = { +}; + +static struct gpiod_lookup_table jive_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 1, "vbus", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* 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(__pa_symbol(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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init jive_init_time(void) +{ + s3c2412_init_clocks(12000000); + s3c24xx_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); + + gpio_request(S3C2410_GPG(13), "lcm reset"); + gpio_direction_output(S3C2410_GPG(13), 0); + + gpio_request_one(S3C2410_GPB(6), GPIOF_OUT_INIT_LOW, NULL); + gpio_free(S3C2410_GPB(6)); + + /* 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; + + gpiod_add_lookup_table(&jive_udc_gpio_table); + gpiod_add_lookup_table(&jive_lcdspi_gpiod_table); + gpiod_add_lookup_table(&jive_wm8750_gpiod_table); + platform_add_devices(jive_devices, ARRAY_SIZE(jive_devices)); +} + +MACHINE_START(JIVE, "JIVE") + /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2412, + .init_irq = s3c2412_init_irq, + .map_io = jive_map_io, + .init_machine = jive_machine_init, + .init_time = jive_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-mini2440.c b/arch/arm/mach-s3c/mach-mini2440.c new file mode 100644 index 000000000..283be70ca --- /dev/null +++ b/arch/arm/mach-s3c/mach-mini2440.c @@ -0,0 +1,804 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 https://code.google.com/p/mini2440/ + +#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/gpio/machine.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/property.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 <linux/platform_data/fb-s3c2410.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include <linux/platform_data/leds-s3c24xx.h> +#include "irqs.h" +#include "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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.h> +#include <linux/mtd/partitions.h> + +#include "gpio-cfg.h" +#include "devs.h" +#include "cpu.h" + +#include <sound/s3c24xx_uda134x.h> + +#include "s3c24xx.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 = { +}; + +static struct gpiod_lookup_table mini2440_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOC", 5, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* 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)), + + .gpccon_reg = S3C2410_GPCCON, + .gpcup_reg = S3C2410_GPCUP, + + .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)), + + .gpdcon_reg = S3C2410_GPDCON, + .gpdup_reg = S3C2410_GPDUP, +}; + +/* MMC/SD */ + +static struct s3c24xx_mci_pdata mini2440_mmc_cfg __initdata = { + .wprotect_invert = 1, + .set_power = s3c24xx_mci_def_set_power, + .ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34, +}; + +static struct gpiod_lookup_table mini2440_mmc_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* Card detect S3C2410_GPG(8) */ + GPIO_LOOKUP("GPIOG", 8, "cd", GPIO_ACTIVE_LOW), + /* Write protect S3C2410_GPH(8) */ + GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_HIGH), + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* 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, + .engine_type = NAND_ECC_ENGINE_TYPE_ON_HOST, +}; + +/* 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 gpiod_lookup_table mini2440_led1_gpio_table = { + .dev_id = "s3c24xx_led.1", + .table = { + GPIO_LOOKUP("GPB", 5, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table mini2440_led2_gpio_table = { + .dev_id = "s3c24xx_led.2", + .table = { + GPIO_LOOKUP("GPB", 6, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table mini2440_led3_gpio_table = { + .dev_id = "s3c24xx_led.3", + .table = { + GPIO_LOOKUP("GPB", 7, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table mini2440_led4_gpio_table = { + .dev_id = "s3c24xx_led.4", + .table = { + GPIO_LOOKUP("GPB", 8, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct gpiod_lookup_table mini2440_backlight_gpio_table = { + .dev_id = "s3c24xx_led.5", + .table = { + GPIO_LOOKUP("GPG", 4, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct s3c24xx_led_platdata mini2440_led1_pdata = { + .name = "led1", + .def_trigger = "heartbeat", +}; + +static struct s3c24xx_led_platdata mini2440_led2_pdata = { + .name = "led2", + .def_trigger = "nand-disk", +}; + +static struct s3c24xx_led_platdata mini2440_led3_pdata = { + .name = "led3", + .def_trigger = "mmc0", +}; + +static struct s3c24xx_led_platdata mini2440_led4_pdata = { + .name = "led4", + .def_trigger = "", +}; + +static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = { + .name = "backlight", + .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 const struct property_entry mini2440_at24_properties[] = { + PROPERTY_ENTRY_U32("pagesize", 16), + { } +}; + +static const struct software_node mini2440_at24_node = { + .properties = mini2440_at24_properties, +}; + +static struct i2c_board_info mini2440_i2c_devs[] __initdata = { + { + I2C_BOARD_INFO("24c08", 0x50), + .swnode = &mini2440_at24_node, + }, +}; + +static struct uda134x_platform_data s3c24xx_uda134x = { + .l3 = { + .gpio_clk = S3C2410_GPB(4), + .gpio_data = S3C2410_GPB(3), + .gpio_mode = S3C2410_GPB(2), + .use_gpios = 1, + .data_hold = 1, + .data_setup = 1, + .clock_high = 1, + .mode_hold = 1, + .mode = 1, + .mode_setup = 1, + }, + .model = UDA134X_UDA1341, +}; + +static struct platform_device uda1340_codec = { + .name = "uda134x-codec", + .id = -1, + .dev = { + .platform_data = &s3c24xx_uda134x, + }, +}; + +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, + &s3c2440_device_dma, + &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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init mini2440_init_time(void) +{ + s3c2440_init_clocks(12000000); + s3c24xx_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) + strscpy(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) { + pr_info("MINI2440: '%c' ignored, screen type already set\n", + f); + } else { + int li = f - '0'; + + if (li >= ARRAY_SIZE(mini2440_lcd_cfg)) + pr_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) + pr_info("MINI2440: '%c' ignored, backlight already set\n", + f); + else { + features->optional[features->count++] = + &mini2440_led_backlight; + } + features->done |= FEATURE_BACKLIGHT; + break; + case 't': + pr_info("MINI2440: '%c' ignored, touchscreen not compiled in\n", + f); + break; + case 'c': + if (features->done & FEATURE_CAMERA) + pr_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; + + pr_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); + } + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + + if (features.lcd_index != -1) { + int li; + + mini2440_fb_info.displays = + &mini2440_lcd_cfg[features.lcd_index]; + + pr_info("MINI2440: LCD"); + for (li = 0; li < ARRAY_SIZE(mini2440_lcd_cfg); li++) + if (li == features.lcd_index) + pr_cont(" [%d:%dx%d]", li, + mini2440_lcd_cfg[li].width, + mini2440_lcd_cfg[li].height); + else + pr_cont(" %d:%dx%d", li, + mini2440_lcd_cfg[li].width, + mini2440_lcd_cfg[li].height); + pr_cont("\n"); + s3c24xx_fb_set_platdata(&mini2440_fb_info); + } + + gpiod_add_lookup_table(&mini2440_udc_gpio_table); + s3c24xx_udc_set_platdata(&mini2440_udc_cfg); + gpiod_add_lookup_table(&mini2440_mmc_gpio_table); + 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)); + + /* Disable pull-up on the LED lines */ + s3c_gpio_setpull(S3C2410_GPB(5), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPB(6), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPB(7), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPB(8), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPG(4), S3C_GPIO_PULL_NONE); + + /* Add lookups for the lines */ + gpiod_add_lookup_table(&mini2440_led1_gpio_table); + gpiod_add_lookup_table(&mini2440_led2_gpio_table); + gpiod_add_lookup_table(&mini2440_led3_gpio_table); + gpiod_add_lookup_table(&mini2440_led4_gpio_table); + gpiod_add_lookup_table(&mini2440_backlight_gpio_table); + + 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, + .nr_irqs = NR_IRQS_S3C2440, + .map_io = mini2440_map_io, + .init_machine = mini2440_init, + .init_irq = s3c2440_init_irq, + .init_time = mini2440_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-mini6410.c b/arch/arm/mach-s3c/mach-mini6410.c new file mode 100644 index 000000000..058ae9e8b --- /dev/null +++ b/arch/arm/mach-s3c/mach-mini6410.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2010 Darius Augulis <augulis.darius@gmail.com> +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/dm9000.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/types.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include <linux/soc/samsung/s3c-adc.h> +#include "cpu.h" +#include "devs.h" +#include "fb.h" +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/mmc-sdhci-s3c.h> +#include "sdhci.h" +#include <linux/platform_data/touchscreen-s3c2410.h> +#include "irqs.h" + +#include <video/platform_lcd.h> +#include <video/samsung_fimd.h> + +#include "s3c64xx.h" +#include "regs-modem-s3c64xx.h" +#include "regs-srom-s3c64xx.h" + +#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 mini6410_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, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, +}; + +/* DM9000AEP 10/100 ethernet controller */ + +static struct resource mini6410_dm9k_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2), + [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2), + [2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \ + | IORESOURCE_IRQ_HIGHLEVEL), +}; + +static struct dm9000_plat_data mini6410_dm9k_pdata = { + .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), +}; + +static struct platform_device mini6410_device_eth = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(mini6410_dm9k_resource), + .resource = mini6410_dm9k_resource, + .dev = { + .platform_data = &mini6410_dm9k_pdata, + }, +}; + +static struct mtd_partition mini6410_nand_part[] = { + [0] = { + .name = "uboot", + .size = SZ_1M, + .offset = 0, + }, + [1] = { + .name = "kernel", + .size = SZ_2M, + .offset = SZ_1M, + }, + [2] = { + .name = "rootfs", + .size = MTDPART_SIZ_FULL, + .offset = SZ_1M + SZ_2M, + }, +}; + +static struct s3c2410_nand_set mini6410_nand_sets[] = { + [0] = { + .name = "nand", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(mini6410_nand_part), + .partitions = mini6410_nand_part, + }, +}; + +static struct s3c2410_platform_nand mini6410_nand_info = { + .tacls = 25, + .twrph0 = 55, + .twrph1 = 40, + .nr_sets = ARRAY_SIZE(mini6410_nand_sets), + .sets = mini6410_nand_sets, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 480, + .yres = 272, +}; + +static struct fb_videomode mini6410_lcd_type0_timing = { + /* 4.3" 480x272 */ + .left_margin = 3, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 1, + .hsync_len = 40, + .vsync_len = 1, + .xres = 480, + .yres = 272, +}; + +static struct s3c_fb_pd_win mini6410_lcd_type1_fb_win = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, +}; + +static struct fb_videomode mini6410_lcd_type1_timing = { + /* 7.0" 800x480 */ + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, +}; + +static struct s3c_fb_platdata mini6410_lcd_pdata[] __initdata = { + { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &mini6410_lcd_type0_timing, + .win[0] = &mini6410_lcd_type0_fb_win, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + }, { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &mini6410_lcd_type1_timing, + .win[0] = &mini6410_lcd_type1_fb_win, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + }, + { }, +}; + +static void mini6410_lcd_power_set(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) + gpio_direction_output(S3C64XX_GPE(0), 1); + else + gpio_direction_output(S3C64XX_GPE(0), 0); +} + +static struct plat_lcd_data mini6410_lcd_power_data = { + .set_power = mini6410_lcd_power_set, +}; + +static struct platform_device mini6410_lcd_powerdev = { + .name = "platform-lcd", + .dev.parent = &s3c_device_fb.dev, + .dev.platform_data = &mini6410_lcd_power_data, +}; + +static struct s3c_sdhci_platdata mini6410_hsmmc1_pdata = { + .max_width = 4, + .cd_type = S3C_SDHCI_CD_GPIO, + .ext_cd_gpio = S3C64XX_GPN(10), + .ext_cd_gpio_invert = true, +}; + +static struct platform_device *mini6410_devices[] __initdata = { + &mini6410_device_eth, + &s3c_device_hsmmc0, + &s3c_device_hsmmc1, + &s3c_device_ohci, + &s3c_device_nand, + &s3c_device_fb, + &mini6410_lcd_powerdev, + &s3c_device_adc, +}; + +static void __init mini6410_map_io(void) +{ + u32 tmp; + + s3c64xx_init_io(NULL, 0); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(mini6410_uartcfgs, ARRAY_SIZE(mini6410_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); + + /* set the LCD type */ + tmp = __raw_readl(S3C64XX_SPCON); + tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; + tmp |= S3C64XX_SPCON_LCD_SEL_RGB; + __raw_writel(tmp, S3C64XX_SPCON); + + /* remove the LCD bypass */ + tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); + tmp &= ~MIFPCON_LCD_BYPASS; + __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); +} + +/* + * mini6410_features string + * + * 0-9 LCD configuration + * + */ +static char mini6410_features_str[12] __initdata = "0"; + +static int __init mini6410_features_setup(char *str) +{ + if (str) + strscpy(mini6410_features_str, str, + sizeof(mini6410_features_str)); + return 1; +} + +__setup("mini6410=", mini6410_features_setup); + +#define FEATURE_SCREEN (1 << 0) + +struct mini6410_features_t { + int done; + int lcd_index; +}; + +static void mini6410_parse_features( + struct mini6410_features_t *features, + const char *features_str) +{ + const char *fp = features_str; + + features->done = 0; + features->lcd_index = 0; + + while (*fp) { + char f = *fp++; + + switch (f) { + case '0'...'9': /* tft screen */ + if (features->done & FEATURE_SCREEN) { + printk(KERN_INFO "MINI6410: '%c' ignored, " + "screen type already set\n", f); + } else { + int li = f - '0'; + if (li >= ARRAY_SIZE(mini6410_lcd_pdata)) + printk(KERN_INFO "MINI6410: '%c' out " + "of range LCD mode\n", f); + else { + features->lcd_index = li; + } + } + features->done |= FEATURE_SCREEN; + break; + } + } +} + +static void __init mini6410_machine_init(void) +{ + u32 cs1; + struct mini6410_features_t features = { 0 }; + + printk(KERN_INFO "MINI6410: Option string mini6410=%s\n", + mini6410_features_str); + + /* Parse the feature string */ + mini6410_parse_features(&features, mini6410_features_str); + + printk(KERN_INFO "MINI6410: selected LCD display is %dx%d\n", + mini6410_lcd_pdata[features.lcd_index].win[0]->xres, + mini6410_lcd_pdata[features.lcd_index].win[0]->yres); + + s3c_nand_set_platdata(&mini6410_nand_info); + s3c_fb_set_platdata(&mini6410_lcd_pdata[features.lcd_index]); + s3c_sdhci1_set_platdata(&mini6410_hsmmc1_pdata); + s3c64xx_ts_set_platdata(NULL); + + /* configure nCS1 width to 16 bits */ + + cs1 = __raw_readl(S3C64XX_SROM_BW) & + ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT); + cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) | + (1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) | + (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) << + S3C64XX_SROM_BW__NCS1__SHIFT; + __raw_writel(cs1, S3C64XX_SROM_BW); + + /* set timing for nCS1 suitable for ethernet chip */ + + __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) | + (6 << S3C64XX_SROM_BCX__TACP__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) | + (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) | + (13 << S3C64XX_SROM_BCX__TACC__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | + (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); + + gpio_request(S3C64XX_GPF(15), "LCD power"); + gpio_request(S3C64XX_GPE(0), "LCD power"); + + platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices)); +} + +MACHINE_START(MINI6410, "MINI6410") + /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = mini6410_map_io, + .init_machine = mini6410_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-n30.c b/arch/arm/mach-s3c/mach-n30.c new file mode 100644 index 000000000..90122fc6b --- /dev/null +++ b/arch/arm/mach-s3c/mach-n30.c @@ -0,0 +1,682 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 +// https://handhelds.org/moin/moin.cgi/AcerN30Documentation . + +#include <linux/kernel.h> +#include <linux/types.h> + +#include <linux/gpio_keys.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/gpio/machine.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 "hardware-s3c24xx.h" +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/fb-s3c2410.h> +#include <linux/platform_data/leds-s3c24xx.h> +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> + +#include <linux/platform_data/i2c-s3c2410.h> + +#include "cpu.h" +#include "devs.h" +#include <linux/platform_data/mmc-s3cmci.h> +#include <linux/platform_data/usb-s3c2410_udc.h> + +#include "s3c24xx.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 = { +}; + +static struct gpiod_lookup_table n30_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 1, "vbus", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 3, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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 gpiod_lookup_table n30_blue_led_gpio_table = { + .dev_id = "s3c24xx_led.1", + .table = { + GPIO_LOOKUP("GPG", 6, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct s3c24xx_led_platdata n30_blue_led_pdata = { + .name = "blue_led", + .def_trigger = "", +}; + +/* This is the blue LED on the device. Originally used to indicate GPS activity + * by flashing. */ + +static struct gpiod_lookup_table n35_blue_led_gpio_table = { + .dev_id = "s3c24xx_led.1", + .table = { + GPIO_LOOKUP("GPD", 8, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct s3c24xx_led_platdata n35_blue_led_pdata = { + .name = "blue_led", + .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 gpiod_lookup_table n30_warning_led_gpio_table = { + .dev_id = "s3c24xx_led.2", + .table = { + GPIO_LOOKUP("GPD", 9, NULL, GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct s3c24xx_led_platdata n30_warning_led_pdata = { + .name = "warning_led", + .def_trigger = "", +}; + +static struct gpiod_lookup_table n35_warning_led_gpio_table = { + .dev_id = "s3c24xx_led.2", + .table = { + GPIO_LOOKUP("GPD", 9, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct s3c24xx_led_platdata n35_warning_led_pdata = { + .name = "warning_led", + .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) +{ + s3c24xx_mci_def_set_power(power_mode, 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 = { + .ocr_avail = MMC_VDD_32_33, + .set_power = n30_sdi_set_power, +}; + +static struct gpiod_lookup_table n30_mci_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* Card detect S3C2410_GPF(1) */ + GPIO_LOOKUP("GPIOF", 1, "cd", GPIO_ACTIVE_LOW), + /* Write protect S3C2410_GPG(10) */ + GPIO_LOOKUP("GPIOG", 10, "wp", GPIO_ACTIVE_LOW), + { }, + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + }, +}; + +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 bluetooth. 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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init n30_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_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); + gpiod_add_lookup_table(&n30_udc_gpio_table); + s3c24xx_udc_set_platdata(&n30_udc_cfg); + gpiod_add_lookup_table(&n30_mci_gpio_table); + 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); + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + + 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); + + /* Disable pull-up and add GPIO tables */ + s3c_gpio_setpull(S3C2410_GPG(6), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE); + gpiod_add_lookup_table(&n30_blue_led_gpio_table); + gpiod_add_lookup_table(&n30_warning_led_gpio_table); + + 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); + + /* Disable pull-up and add GPIO tables */ + s3c_gpio_setpull(S3C2410_GPD(8), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPD(9), S3C_GPIO_PULL_NONE); + gpiod_add_lookup_table(&n35_blue_led_gpio_table); + gpiod_add_lookup_table(&n35_warning_led_gpio_table); + + 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, + .nr_irqs = NR_IRQS_S3C2410, + .init_time = n30_init_time, + .init_machine = n30_init, + .init_irq = s3c2410_init_irq, + .map_io = n30_map_io, +MACHINE_END + +MACHINE_START(N35, "Acer-N35") + /* Maintainer: Christer Weinigel <christer@weinigel.se> + */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2410, + .init_time = n30_init_time, + .init_machine = n30_init, + .init_irq = s3c2410_init_irq, + .map_io = n30_map_io, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-ncp.c b/arch/arm/mach-s3c/mach-ncp.c new file mode 100644 index 000000000..1e65f8bce --- /dev/null +++ b/arch/arm/mach-s3c/mach-ncp.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2008-2009 Samsung Electronics + +#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/i2c.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/delay.h> + +#include <video/platform_lcd.h> +#include <video/samsung_fimd.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include "irqs.h" +#include "map.h" + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include "fb.h" + +#include "devs.h" +#include "cpu.h" + +#include "s3c64xx.h" + +#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 ncp_uartcfgs[] __initdata = { + /* REVISIT: NCP uses only serial 1, 2 */ + [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 *ncp_devices[] __initdata = { + &s3c_device_hsmmc1, + &s3c_device_i2c0, +}; + +static struct map_desc ncp_iodesc[] __initdata = {}; + +static void __init ncp_map_io(void) +{ + s3c64xx_init_io(ncp_iodesc, ARRAY_SIZE(ncp_iodesc)); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(ncp_uartcfgs, ARRAY_SIZE(ncp_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); +} + +static void __init ncp_machine_init(void) +{ + s3c_i2c0_set_platdata(NULL); + + platform_add_devices(ncp_devices, ARRAY_SIZE(ncp_devices)); +} + +MACHINE_START(NCP, "NCP") + /* Maintainer: Samsung Electronics */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = ncp_map_io, + .init_machine = ncp_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-nexcoder.c b/arch/arm/mach-s3c/mach-nexcoder.c new file mode 100644 index 000000000..d17a3fcb7 --- /dev/null +++ b/arch/arm/mach-s3c/mach-nexcoder.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0 +// linux/arch/arm/mach-s3c2440/mach-nexcoder.c +// +// Copyright (c) 2004 Nex Vision +// Guillaume GOURAT <guillaume.gourat@nexvision.tv> +// +// 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 <asm/irq.h> +#include <asm/mach-types.h> + +//#include <asm/debug-ll.h> +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include <linux/platform_data/i2c-s3c2410.h> + +#include "gpio-cfg.h" +#include "devs.h" +#include "cpu.h" + +#include "s3c24xx.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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); + + nexcoder_sensorboard_init(); +} + +static void __init nexcoder_init_time(void) +{ + s3c2440_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init nexcoder_init(void) +{ + s3c_i2c0_set_platdata(NULL); + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + + 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, + .nr_irqs = NR_IRQS_S3C2440, + .map_io = nexcoder_map_io, + .init_machine = nexcoder_init, + .init_irq = s3c2440_init_irq, + .init_time = nexcoder_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-osiris-dvs.c b/arch/arm/mach-s3c/mach-osiris-dvs.c new file mode 100644 index 000000000..2e283aeda --- /dev/null +++ b/arch/arm/mach-s3c/mach-osiris-dvs.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2009 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk> +// +// Simtec Osiris Dynamic Voltage Scaling support. + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/cpufreq.h> +#include <linux/gpio.h> + +#include <linux/mfd/tps65010.h> + +#include <linux/soc/samsung/s3c-cpu-freq.h> +#include "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 actually 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", + .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-s3c/mach-osiris.c b/arch/arm/mach-s3c/mach-osiris.c new file mode 100644 index 000000000..d900d1354 --- /dev/null +++ b/arch/arm/mach-s3c/mach-osiris.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2005-2008 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// 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/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/mfd/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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.h> +#include <linux/mtd/partitions.h> + +#include "cpu.h" +#include <linux/soc/samsung/s3c-cpu-freq.h> +#include "devs.h" +#include "gpio-cfg.h" + +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "s3c24xx.h" +#include "osiris.h" +#include "regs-mem-s3c24xx.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, + }, + + /* 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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +/* 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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_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); + s3c24xx_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, + .nr_irqs = NR_IRQS_S3C2440, + .map_io = osiris_map_io, + .init_irq = s3c2440_init_irq, + .init_machine = osiris_init, + .init_time = osiris_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-otom.c b/arch/arm/mach-s3c/mach-otom.c new file mode 100644 index 000000000..3a2db2f58 --- /dev/null +++ b/arch/arm/mach-s3c/mach-otom.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2004 Nex Vision +// Guillaume GOURAT <guillaume.gourat@nexvision.fr> + +#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 "gpio-samsung.h" +#include "gpio-cfg.h" + +#include "cpu.h" +#include "devs.h" + +#include "s3c24xx.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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init otom11_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init otom11_init(void) +{ + s3c_i2c0_set_platdata(NULL); + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + 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, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = otom11_map_io, + .init_machine = otom11_init, + .init_irq = s3c2410_init_irq, + .init_time = otom11_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-qt2410.c b/arch/arm/mach-s3c/mach-qt2410.c new file mode 100644 index 000000000..36fe0684a --- /dev/null +++ b/arch/arm/mach-s3c/mach-qt2410.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2006 by OpenMoko, Inc. +// Author: Harald Welte <laforge@openmoko.org> +// All rights reserved. + +#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/gpio/machine.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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.h> +#include <linux/mtd/partitions.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/fb-s3c2410.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 "gpio-samsung.h" + +#include "gpio-cfg.h" +#include "devs.h" +#include "cpu.h" +#include "pm.h" + +#include "s3c24xx.h" +#include "common-smdk-s3c24xx.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 gpiod_lookup_table qt2410_led_gpio_table = { + .dev_id = "s3c24xx_led.0", + .table = { + GPIO_LOOKUP("GPB", 0, NULL, GPIO_ACTIVE_LOW | GPIO_OPEN_DRAIN), + { }, + }, +}; + +static struct s3c24xx_led_platdata qt2410_pdata_led = { + .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 = { + .num_chipselect = 1, +}; + +static struct platform_device qt2410_spi = { + .name = "spi_gpio", + .id = 1, + .dev.platform_data = &spi_gpio_cfg, +}; + +static struct gpiod_lookup_table qt2410_spi_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOG", 7, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOG", 6, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOG", 5, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOB", 5, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table qt2410_mmc_gpiod_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +/* 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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +/* 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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init qt2410_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_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); + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + gpiod_add_lookup_table(&qt2410_spi_gpiod_table); + s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE); + gpiod_add_lookup_table(&qt2410_led_gpio_table); + gpiod_add_lookup_table(&qt2410_mmc_gpiod_table); + platform_add_devices(qt2410_devices, ARRAY_SIZE(qt2410_devices)); + s3c_pm_init(); +} + +MACHINE_START(QT2410, "QT2410") + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = qt2410_map_io, + .init_irq = s3c2410_init_irq, + .init_machine = qt2410_machine_init, + .init_time = qt2410_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-real6410.c b/arch/arm/mach-s3c/mach-real6410.c new file mode 100644 index 000000000..8c10ebc38 --- /dev/null +++ b/arch/arm/mach-s3c/mach-real6410.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2010 Darius Augulis <augulis.darius@gmail.com> +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/dm9000.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/platform_device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/types.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "irqs.h" + +#include <linux/soc/samsung/s3c-adc.h> +#include "cpu.h" +#include "devs.h" +#include "fb.h" +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include <linux/platform_data/touchscreen-s3c2410.h> + +#include <video/platform_lcd.h> +#include <video/samsung_fimd.h> + +#include "s3c64xx.h" +#include "regs-modem-s3c64xx.h" +#include "regs-srom-s3c64xx.h" + +#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 real6410_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, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, +}; + +/* DM9000AEP 10/100 ethernet controller */ + +static struct resource real6410_dm9k_resource[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, 2), + [1] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1 + 4, 2), + [2] = DEFINE_RES_NAMED(S3C_EINT(7), 1, NULL, IORESOURCE_IRQ \ + | IORESOURCE_IRQ_HIGHLEVEL), +}; + +static struct dm9000_plat_data real6410_dm9k_pdata = { + .flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM), +}; + +static struct platform_device real6410_device_eth = { + .name = "dm9000", + .id = -1, + .num_resources = ARRAY_SIZE(real6410_dm9k_resource), + .resource = real6410_dm9k_resource, + .dev = { + .platform_data = &real6410_dm9k_pdata, + }, +}; + +static struct s3c_fb_pd_win real6410_lcd_type0_fb_win = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 480, + .yres = 272, +}; + +static struct fb_videomode real6410_lcd_type0_timing = { + /* 4.3" 480x272 */ + .left_margin = 3, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 1, + .hsync_len = 40, + .vsync_len = 1, +}; + +static struct s3c_fb_pd_win real6410_lcd_type1_fb_win = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, +}; + +static struct fb_videomode real6410_lcd_type1_timing = { + /* 7.0" 800x480 */ + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, +}; + +static struct s3c_fb_platdata real6410_lcd_pdata[] __initdata = { + { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &real6410_lcd_type0_timing, + .win[0] = &real6410_lcd_type0_fb_win, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + }, { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &real6410_lcd_type1_timing, + .win[0] = &real6410_lcd_type1_fb_win, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, + }, + { }, +}; + +static struct mtd_partition real6410_nand_part[] = { + [0] = { + .name = "uboot", + .size = SZ_1M, + .offset = 0, + }, + [1] = { + .name = "kernel", + .size = SZ_2M, + .offset = SZ_1M, + }, + [2] = { + .name = "rootfs", + .size = MTDPART_SIZ_FULL, + .offset = SZ_1M + SZ_2M, + }, +}; + +static struct s3c2410_nand_set real6410_nand_sets[] = { + [0] = { + .name = "nand", + .nr_chips = 1, + .nr_partitions = ARRAY_SIZE(real6410_nand_part), + .partitions = real6410_nand_part, + }, +}; + +static struct s3c2410_platform_nand real6410_nand_info = { + .tacls = 25, + .twrph0 = 55, + .twrph1 = 40, + .nr_sets = ARRAY_SIZE(real6410_nand_sets), + .sets = real6410_nand_sets, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +static struct platform_device *real6410_devices[] __initdata = { + &real6410_device_eth, + &s3c_device_hsmmc0, + &s3c_device_hsmmc1, + &s3c_device_fb, + &s3c_device_nand, + &s3c_device_adc, + &s3c_device_ohci, +}; + +static void __init real6410_map_io(void) +{ + u32 tmp; + + s3c64xx_init_io(NULL, 0); + s3c24xx_init_clocks(12000000); + s3c24xx_init_uarts(real6410_uartcfgs, ARRAY_SIZE(real6410_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); + + /* set the LCD type */ + tmp = __raw_readl(S3C64XX_SPCON); + tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; + tmp |= S3C64XX_SPCON_LCD_SEL_RGB; + __raw_writel(tmp, S3C64XX_SPCON); + + /* remove the LCD bypass */ + tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); + tmp &= ~MIFPCON_LCD_BYPASS; + __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); +} + +/* + * real6410_features string + * + * 0-9 LCD configuration + * + */ +static char real6410_features_str[12] __initdata = "0"; + +static int __init real6410_features_setup(char *str) +{ + if (str) + strlcpy(real6410_features_str, str, + sizeof(real6410_features_str)); + return 1; +} + +__setup("real6410=", real6410_features_setup); + +#define FEATURE_SCREEN (1 << 0) + +struct real6410_features_t { + int done; + int lcd_index; +}; + +static void real6410_parse_features( + struct real6410_features_t *features, + const char *features_str) +{ + const char *fp = features_str; + + features->done = 0; + features->lcd_index = 0; + + while (*fp) { + char f = *fp++; + + switch (f) { + case '0'...'9': /* tft screen */ + if (features->done & FEATURE_SCREEN) { + printk(KERN_INFO "REAL6410: '%c' ignored, " + "screen type already set\n", f); + } else { + int li = f - '0'; + if (li >= ARRAY_SIZE(real6410_lcd_pdata)) + printk(KERN_INFO "REAL6410: '%c' out " + "of range LCD mode\n", f); + else { + features->lcd_index = li; + } + } + features->done |= FEATURE_SCREEN; + break; + } + } +} + +static void __init real6410_machine_init(void) +{ + u32 cs1; + struct real6410_features_t features = { 0 }; + + printk(KERN_INFO "REAL6410: Option string real6410=%s\n", + real6410_features_str); + + /* Parse the feature string */ + real6410_parse_features(&features, real6410_features_str); + + printk(KERN_INFO "REAL6410: selected LCD display is %dx%d\n", + real6410_lcd_pdata[features.lcd_index].win[0]->xres, + real6410_lcd_pdata[features.lcd_index].win[0]->yres); + + s3c_fb_set_platdata(&real6410_lcd_pdata[features.lcd_index]); + s3c_nand_set_platdata(&real6410_nand_info); + s3c64xx_ts_set_platdata(NULL); + + /* configure nCS1 width to 16 bits */ + + cs1 = __raw_readl(S3C64XX_SROM_BW) & + ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT); + cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) | + (1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) | + (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) << + S3C64XX_SROM_BW__NCS1__SHIFT; + __raw_writel(cs1, S3C64XX_SROM_BW); + + /* set timing for nCS1 suitable for ethernet chip */ + + __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) | + (6 << S3C64XX_SROM_BCX__TACP__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) | + (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) | + (13 << S3C64XX_SROM_BCX__TACC__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | + (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); + + gpio_request(S3C64XX_GPF(15), "LCD power"); + + platform_add_devices(real6410_devices, ARRAY_SIZE(real6410_devices)); +} + +MACHINE_START(REAL6410, "REAL6410") + /* Maintainer: Darius Augulis <augulis.darius@gmail.com> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = real6410_map_io, + .init_machine = real6410_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-rx1950.c b/arch/arm/mach-s3c/mach-rx1950.c new file mode 100644 index 000000000..d8c49e562 --- /dev/null +++ b/arch/arm/mach-s3c/mach-rx1950.c @@ -0,0 +1,884 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2006-2009 Victor Chukhantsev, Denis Grigoriev, +// Copyright (c) 2007-2010 Vasily Khoruzhick +// +// based on smdk2440 written by Ben Dooks + +#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/gpio/machine.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 <linux/platform_data/fb-s3c2410.h> + +#include <sound/uda1380.h> + +#include "hardware-s3c24xx.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include "pm.h" +#include "gpio-cfg.h" + +#include "s3c24xx.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 struct gpiod_lookup_table rx1950_bat_gpio_table = { + .dev_id = "s3c-adc-battery", + .table = { + /* Charge status S3C2410_GPF(3) */ + GPIO_LOOKUP("GPIOF", 3, "charge-status", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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(struct gpio_desc *desc, int state, + unsigned long *delay_on, unsigned long *delay_off) +{ + int gpio = desc_to_gpio(desc); + 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; + } + + 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, + .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, + .gpccon_reg = S3C2410_GPCCON, + .gpcup = 0x0000ffff, + .gpcup_mask = 0xffffffff, + .gpcup_reg = S3C2410_GPCUP, + + .gpdcon = 0xaa90aaa1, + .gpdcon_mask = 0xffc0fff0, + .gpdcon_reg = S3C2410_GPDCON, + .gpdup = 0x0000fcfd, + .gpdup_mask = 0xffffffff, + .gpdup_reg = S3C2410_GPDUP, +}; + +static struct pwm_lookup rx1950_pwm_lookup[] = { + PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight.0", NULL, 48000, + PWM_POLARITY_NORMAL), + PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", "RX1950 LCD", LCD_PWM_PERIOD, + PWM_POLARITY_NORMAL), +}; + +static struct pwm_device *lcd_pwm; +static struct pwm_state lcd_pwm_state; + +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); + + lcd_pwm_state.enabled = false; + pwm_apply_state(lcd_pwm, &lcd_pwm_state); + + /* GPC0->0, GPC10->0 */ + gpio_direction_output(S3C2410_GPC(0), 0); + gpio_direction_output(S3C2410_GPC(10), 0); + } else { + lcd_pwm_state.enabled = true; + pwm_apply_state(lcd_pwm, &lcd_pwm_state); + + 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_get(dev, "RX1950 LCD"); + if (IS_ERR(lcd_pwm)) { + dev_err(dev, "Unable to request PWM for LCD power!\n"); + return PTR_ERR(lcd_pwm); + } + + /* + * Call pwm_init_state to initialize .polarity and .period. The other + * values are fixed in this driver. + */ + pwm_init_state(lcd_pwm, &lcd_pwm_state); + + lcd_pwm_state.duty_cycle = LCD_PWM_DUTY; + + 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_put(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 = { + .max_brightness = 24, + .dft_brightness = 4, + .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) +{ + s3c24xx_mci_def_set_power(power_mode, 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 = { + .set_power = rx1950_set_mmc_power, + .ocr_avail = MMC_VDD_32_33, +}; + +static struct gpiod_lookup_table rx1950_mmc_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* Card detect S3C2410_GPF(5) */ + GPIO_LOOKUP("GPIOF", 5, "cd", GPIO_ACTIVE_LOW), + /* Write protect S3C2410_GPH(8) */ + GPIO_LOOKUP("GPIOH", 8, "wp", GPIO_ACTIVE_LOW), + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = { +}; + +static struct gpiod_lookup_table rx1950_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOG", 5, "vbus", GPIO_ACTIVE_LOW), + GPIO_LOOKUP("GPIOJ", 5, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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 gpiod_lookup_table rx1950_audio_gpio_table = { + .dev_id = "rx1950-audio", + .table = { + GPIO_LOOKUP("GPIOG", 12, "hp-gpio", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOA", 1, "speaker-power", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct platform_device rx1950_audio = { + .name = "rx1950-audio", + .id = -1, +}; + +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, + &rx1950_audio, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_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); + s3c24xx_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); + gpiod_add_lookup_table(&rx1950_mmc_gpio_table); + 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); + + pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup)); + gpiod_add_lookup_table(&rx1950_udc_gpio_table); + gpiod_add_lookup_table(&rx1950_audio_gpio_table); + gpiod_add_lookup_table(&rx1950_bat_gpio_table); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + 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, + .nr_irqs = NR_IRQS_S3C2442, + .map_io = rx1950_map_io, + .reserve = rx1950_reserve, + .init_irq = s3c2442_init_irq, + .init_machine = rx1950_init_machine, + .init_time = rx1950_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-rx3715.c b/arch/arm/mach-s3c/mach-rx3715.c new file mode 100644 index 000000000..52b3c38ac --- /dev/null +++ b/arch/arm/mach-s3c/mach-rx3715.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2003-2004 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// https://www.handhelds.org/projects/rx3715.html + +#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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.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 <linux/platform_data/fb-s3c2410.h> + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include "cpu.h" +#include "devs.h" +#include "pm.h" + +#include "s3c24xx.h" +#include "h1940.h" + +static struct map_desc rx3715_iodesc[] __initdata = { + /* dump ISA space somewhere unused */ + { + .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, + .gpccon_reg = S3C2410_GPCCON, + .gpcup = 0x0000ffff, + .gpcup_mask = 0xffffffff, + .gpcup_reg = S3C2410_GPCUP, + + .gpdcon = 0xaa95aaa1, + .gpdcon_mask = 0xffc0fff0, + .gpdcon_reg = S3C2410_GPDCON, + .gpdup = 0x0000faff, + .gpdup_mask = 0xffffffff, + .gpdup_reg = S3C2410_GPDUP, +}; + +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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init rx3715_init_time(void) +{ + s3c2440_init_clocks(16934000); + s3c24xx_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); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + platform_add_devices(rx3715_devices, ARRAY_SIZE(rx3715_devices)); +} + +MACHINE_START(RX3715, "IPAQ-RX3715") + /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2440, + .map_io = rx3715_map_io, + .reserve = rx3715_reserve, + .init_irq = s3c2440_init_irq, + .init_machine = rx3715_init_machine, + .init_time = rx3715_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-s3c2416-dt.c b/arch/arm/mach-s3c/mach-s3c2416-dt.c new file mode 100644 index 000000000..418544d30 --- /dev/null +++ b/arch/arm/mach-s3c/mach-s3c2416-dt.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 + +#include <linux/clocksource.h> +#include <linux/irqchip.h> +#include <linux/serial_s3c.h> + +#include <asm/mach/arch.h> +#include "map.h" + +#include "cpu.h" +#include "pm.h" + +#include "s3c24xx.h" + +static void __init s3c2416_dt_map_io(void) +{ + s3c24xx_init_io(NULL, 0); +} + +static void __init s3c2416_dt_machine_init(void) +{ + s3c_pm_init(); +} + +static const char *const s3c2416_dt_compat[] __initconst = { + "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, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-s3c64xx-dt.c b/arch/arm/mach-s3c/mach-s3c64xx-dt.c new file mode 100644 index 000000000..00169c103 --- /dev/null +++ b/arch/arm/mach-s3c/mach-s3c64xx-dt.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Samsung's S3C64XX flattened device tree enabled machine +// +// Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/system_misc.h> + +#include "cpu.h" +#include "map.h" + +#include "s3c64xx.h" + +/* + * IO mapping for shared system controller IP. + * + * FIXME: Make remaining drivers use dynamic mapping. + */ +static struct map_desc s3c64xx_dt_iodesc[] __initdata = { + { + .virtual = (unsigned long)S3C_VA_SYS, + .pfn = __phys_to_pfn(S3C64XX_PA_SYSCON), + .length = SZ_4K, + .type = MT_DEVICE, + }, +}; + +static void __init s3c64xx_dt_map_io(void) +{ + debug_ll_io_init(); + iotable_init(s3c64xx_dt_iodesc, ARRAY_SIZE(s3c64xx_dt_iodesc)); + + s3c64xx_init_cpu(); + + if (!soc_is_s3c64xx()) + panic("SoC is not S3C64xx!"); +} + +static const char *const s3c64xx_dt_compat[] __initconst = { + "samsung,s3c6400", + "samsung,s3c6410", + NULL +}; + +DT_MACHINE_START(S3C6400_DT, "Samsung S3C64xx (Flattened Device Tree)") + /* Maintainer: Tomasz Figa <tomasz.figa@gmail.com> */ + .dt_compat = s3c64xx_dt_compat, + .map_io = s3c64xx_dt_map_io, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smartq.c b/arch/arm/mach-s3c/mach-smartq.c new file mode 100644 index 000000000..5b6e7c2a8 --- /dev/null +++ b/arch/arm/mach-s3c/mach-smartq.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2010 Maurus Cuelenaere + +#include <linux/delay.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/gpio/machine.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/pwm_backlight.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/spi/spi_gpio.h> +#include <linux/platform_data/s3c-hsotg.h> + +#include <asm/mach-types.h> +#include <asm/mach/map.h> + +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include <linux/platform_data/i2c-s3c2410.h> +#include "gpio-cfg.h" +#include <linux/platform_data/hwmon-s3c.h> +#include <linux/platform_data/usb-ohci-s3c2410.h> +#include "sdhci.h" +#include <linux/platform_data/touchscreen-s3c2410.h> + +#include <video/platform_lcd.h> + +#include "s3c64xx.h" +#include "mach-smartq.h" +#include "regs-modem-s3c64xx.h" + +#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 smartq_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 void smartq_usb_host_powercontrol(int port, int to) +{ + pr_debug("%s(%d, %d)\n", __func__, port, to); + + if (port == 0) { + gpio_set_value(S3C64XX_GPL(0), to); + gpio_set_value(S3C64XX_GPL(1), to); + } +} + +static irqreturn_t smartq_usb_host_ocirq(int irq, void *pw) +{ + struct s3c2410_hcd_info *info = pw; + + if (gpio_get_value(S3C64XX_GPL(10)) == 0) { + pr_debug("%s: over-current irq (oc detected)\n", __func__); + s3c2410_usb_report_oc(info, 3); + } else { + pr_debug("%s: over-current irq (oc cleared)\n", __func__); + s3c2410_usb_report_oc(info, 0); + } + + return IRQ_HANDLED; +} + +static void smartq_usb_host_enableoc(struct s3c2410_hcd_info *info, int on) +{ + int ret; + + /* This isn't present on a SmartQ 5 board */ + if (machine_is_smartq5()) + return; + + if (on) { + ret = request_irq(gpio_to_irq(S3C64XX_GPL(10)), + smartq_usb_host_ocirq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "USB host overcurrent", info); + if (ret != 0) + pr_err("failed to request usb oc irq: %d\n", ret); + } else { + free_irq(gpio_to_irq(S3C64XX_GPL(10)), info); + } +} + +static struct s3c2410_hcd_info smartq_usb_host_info = { + .port[0] = { + .flags = S3C_HCDFLG_USED + }, + .port[1] = { + .flags = 0 + }, + + .power_control = smartq_usb_host_powercontrol, + .enable_oc = smartq_usb_host_enableoc, +}; + +static struct gpiod_lookup_table smartq_usb_otg_vbus_gpiod_table = { + .dev_id = "gpio-vbus", + .table = { + GPIO_LOOKUP("GPL", 9, "vbus", GPIO_ACTIVE_LOW), + { }, + }, +}; + +static struct platform_device smartq_usb_otg_vbus_dev = { + .name = "gpio-vbus", +}; + +static struct pwm_lookup smartq_pwm_lookup[] = { + PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL, + 1000000000 / (1000 * 20), PWM_POLARITY_NORMAL), +}; + +static int smartq_bl_init(struct device *dev) +{ + s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2)); + + return 0; +} + +static struct platform_pwm_backlight_data smartq_backlight_data = { + .max_brightness = 1000, + .dft_brightness = 600, + .init = smartq_bl_init, +}; + +static struct platform_device smartq_backlight_device = { + .name = "pwm-backlight", + .dev = { + .parent = &samsung_device_pwm.dev, + .platform_data = &smartq_backlight_data, + }, +}; + +static struct s3c2410_ts_mach_info smartq_touchscreen_pdata __initdata = { + .delay = 65535, + .presc = 99, + .oversampling_shift = 4, +}; + +static struct s3c_sdhci_platdata smartq_internal_hsmmc_pdata = { + .max_width = 4, + .cd_type = S3C_SDHCI_CD_PERMANENT, +}; + +static struct s3c_hwmon_pdata smartq_hwmon_pdata __initdata = { + /* Battery voltage (?-4.2V) */ + .in[0] = &(struct s3c_hwmon_chcfg) { + .name = "smartq:battery-voltage", + .mult = 3300, + .div = 2048, + }, + /* Reference voltage (1.2V) */ + .in[1] = &(struct s3c_hwmon_chcfg) { + .name = "smartq:reference-voltage", + .mult = 3300, + .div = 4096, + }, +}; + +static struct dwc2_hsotg_plat smartq_hsotg_pdata; + +static int __init smartq_lcd_setup_gpio(void) +{ + int ret; + + ret = gpio_request(S3C64XX_GPM(3), "LCD power"); + if (ret < 0) + return ret; + + /* turn power off */ + gpio_direction_output(S3C64XX_GPM(3), 0); + + return 0; +} + +/* GPM0 -> CS */ +static struct spi_gpio_platform_data smartq_lcd_control = { + .num_chipselect = 1, +}; + +static struct platform_device smartq_lcd_control_device = { + .name = "spi_gpio", + .id = 1, + .dev.platform_data = &smartq_lcd_control, +}; + +static struct gpiod_lookup_table smartq_lcd_control_gpiod_table = { + .dev_id = "spi_gpio", + .table = { + GPIO_LOOKUP("GPIOM", 1, + "sck", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOM", 2, + "mosi", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOM", 3, + "miso", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("GPIOM", 0, + "cs", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static void smartq_lcd_power_set(struct plat_lcd_data *pd, unsigned int power) +{ + gpio_direction_output(S3C64XX_GPM(3), power); +} + +static struct plat_lcd_data smartq_lcd_power_data = { + .set_power = smartq_lcd_power_set, +}; + +static struct platform_device smartq_lcd_power_device = { + .name = "platform-lcd", + .dev.parent = &s3c_device_fb.dev, + .dev.platform_data = &smartq_lcd_power_data, +}; + +static struct i2c_board_info smartq_i2c_devs[] __initdata = { + { I2C_BOARD_INFO("wm8987", 0x1a), }, +}; + +static struct platform_device *smartq_devices[] __initdata = { + &s3c_device_hsmmc1, /* Init iNAND first, ... */ + &s3c_device_hsmmc0, /* ... then the external SD card */ + &s3c_device_hsmmc2, + &s3c_device_adc, + &s3c_device_fb, + &s3c_device_hwmon, + &s3c_device_i2c0, + &s3c_device_ohci, + &s3c_device_rtc, + &samsung_device_pwm, + &s3c_device_usb_hsotg, + &s3c64xx_device_iis0, + &smartq_backlight_device, + &smartq_lcd_control_device, + &smartq_lcd_power_device, + &smartq_usb_otg_vbus_dev, +}; + +static void __init smartq_lcd_mode_set(void) +{ + u32 tmp; + + /* set the LCD type */ + tmp = __raw_readl(S3C64XX_SPCON); + tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; + tmp |= S3C64XX_SPCON_LCD_SEL_RGB; + __raw_writel(tmp, S3C64XX_SPCON); + + /* remove the LCD bypass */ + tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); + tmp &= ~MIFPCON_LCD_BYPASS; + __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); +} + +static void smartq_power_off(void) +{ + gpio_direction_output(S3C64XX_GPK(15), 1); +} + +static int __init smartq_power_off_init(void) +{ + int ret; + + ret = gpio_request(S3C64XX_GPK(15), "Power control"); + if (ret < 0) { + pr_err("%s: failed to get GPK15\n", __func__); + return ret; + } + + /* leave power on */ + gpio_direction_output(S3C64XX_GPK(15), 0); + + pm_power_off = smartq_power_off; + + return ret; +} + +static int __init smartq_usb_host_init(void) +{ + int ret; + + ret = gpio_request(S3C64XX_GPL(0), "USB power control"); + if (ret < 0) { + pr_err("%s: failed to get GPL0\n", __func__); + return ret; + } + + ret = gpio_request(S3C64XX_GPL(1), "USB host power control"); + if (ret < 0) { + pr_err("%s: failed to get GPL1\n", __func__); + goto err; + } + + if (!machine_is_smartq5()) { + /* This isn't present on a SmartQ 5 board */ + ret = gpio_request(S3C64XX_GPL(10), "USB host overcurrent"); + if (ret < 0) { + pr_err("%s: failed to get GPL10\n", __func__); + goto err2; + } + } + + /* turn power off */ + gpio_direction_output(S3C64XX_GPL(0), 0); + gpio_direction_output(S3C64XX_GPL(1), 0); + if (!machine_is_smartq5()) + gpio_direction_input(S3C64XX_GPL(10)); + + s3c_device_ohci.dev.platform_data = &smartq_usb_host_info; + + return 0; + +err2: + gpio_free(S3C64XX_GPL(1)); +err: + gpio_free(S3C64XX_GPL(0)); + return ret; +} + +static int __init smartq_wifi_init(void) +{ + int ret; + + ret = gpio_request(S3C64XX_GPK(1), "wifi control"); + if (ret < 0) { + pr_err("%s: failed to get GPK1\n", __func__); + return ret; + } + + ret = gpio_request(S3C64XX_GPK(2), "wifi reset"); + if (ret < 0) { + pr_err("%s: failed to get GPK2\n", __func__); + gpio_free(S3C64XX_GPK(1)); + return ret; + } + + /* turn power on */ + gpio_direction_output(S3C64XX_GPK(1), 1); + + /* reset device */ + gpio_direction_output(S3C64XX_GPK(2), 0); + mdelay(100); + gpio_set_value(S3C64XX_GPK(2), 1); + gpio_direction_input(S3C64XX_GPK(2)); + + return 0; +} + +static struct map_desc smartq_iodesc[] __initdata = {}; +void __init smartq_map_io(void) +{ + s3c64xx_init_io(smartq_iodesc, ARRAY_SIZE(smartq_iodesc)); + s3c64xx_set_xtal_freq(12000000); + s3c64xx_set_xusbxti_freq(12000000); + s3c24xx_init_uarts(smartq_uartcfgs, ARRAY_SIZE(smartq_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); + + smartq_lcd_mode_set(); +} + +static struct gpiod_lookup_table smartq_audio_gpios = { + .dev_id = "smartq-audio", + .table = { + GPIO_LOOKUP("GPL", 12, "headphone detect", 0), + GPIO_LOOKUP("GPK", 12, "amplifiers shutdown", 0), + { }, + }, +}; + +void __init smartq_machine_init(void) +{ + s3c_i2c0_set_platdata(NULL); + dwc2_hsotg_set_platdata(&smartq_hsotg_pdata); + s3c_hwmon_set_platdata(&smartq_hwmon_pdata); + s3c_sdhci1_set_platdata(&smartq_internal_hsmmc_pdata); + s3c_sdhci2_set_platdata(&smartq_internal_hsmmc_pdata); + s3c64xx_ts_set_platdata(&smartq_touchscreen_pdata); + + i2c_register_board_info(0, smartq_i2c_devs, + ARRAY_SIZE(smartq_i2c_devs)); + + WARN_ON(smartq_lcd_setup_gpio()); + WARN_ON(smartq_power_off_init()); + WARN_ON(smartq_usb_host_init()); + WARN_ON(smartq_wifi_init()); + + pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup)); + gpiod_add_lookup_table(&smartq_lcd_control_gpiod_table); + gpiod_add_lookup_table(&smartq_usb_otg_vbus_gpiod_table); + platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices)); + + gpiod_add_lookup_table(&smartq_audio_gpios); + platform_device_register_simple("smartq-audio", -1, NULL, 0); +} diff --git a/arch/arm/mach-s3c/mach-smartq.h b/arch/arm/mach-s3c/mach-smartq.h new file mode 100644 index 000000000..f98132f4f --- /dev/null +++ b/arch/arm/mach-s3c/mach-smartq.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * linux/arch/arm/mach-s3c64xx/mach-smartq.h + * + * Copyright (C) 2010 Maurus Cuelenaere + */ + +#ifndef __MACH_SMARTQ_H +#define __MACH_SMARTQ_H __FILE__ + +#include <linux/init.h> + +extern void __init smartq_map_io(void); +extern void __init smartq_machine_init(void); + +#endif /* __MACH_SMARTQ_H */ diff --git a/arch/arm/mach-s3c/mach-smartq5.c b/arch/arm/mach-s3c/mach-smartq5.c new file mode 100644 index 000000000..ce3fce0bb --- /dev/null +++ b/arch/arm/mach-s3c/mach-smartq5.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2010 Maurus Cuelenaere + +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/leds.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include <video/samsung_fimd.h> +#include "irqs.h" +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include "fb.h" +#include "gpio-cfg.h" + +#include "s3c64xx.h" +#include "mach-smartq.h" + +static struct gpio_led smartq5_leds[] = { + { + .name = "smartq5:green", + .active_low = 1, + .gpio = S3C64XX_GPN(8), + }, + { + .name = "smartq5:red", + .active_low = 1, + .gpio = S3C64XX_GPN(9), + }, +}; + +static struct gpio_led_platform_data smartq5_led_data = { + .num_leds = ARRAY_SIZE(smartq5_leds), + .leds = smartq5_leds, +}; + +static struct platform_device smartq5_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &smartq5_led_data, +}; + +/* Labels according to the SmartQ manual */ +static struct gpio_keys_button smartq5_buttons[] = { + { + .gpio = S3C64XX_GPL(14), + .code = KEY_POWER, + .desc = "Power", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(2), + .code = KEY_KPMINUS, + .desc = "Minus", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(12), + .code = KEY_KPPLUS, + .desc = "Plus", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(15), + .code = KEY_ENTER, + .desc = "Move", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, +}; + +static struct gpio_keys_platform_data smartq5_buttons_data = { + .buttons = smartq5_buttons, + .nbuttons = ARRAY_SIZE(smartq5_buttons), +}; + +static struct platform_device smartq5_buttons_device = { + .name = "gpio-keys", + .id = 0, + .num_resources = 0, + .dev = { + .platform_data = &smartq5_buttons_data, + } +}; + +static struct s3c_fb_pd_win smartq5_fb_win0 = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, +}; + +static struct fb_videomode smartq5_lcd_timing = { + .left_margin = 216, + .right_margin = 40, + .upper_margin = 35, + .lower_margin = 10, + .hsync_len = 1, + .vsync_len = 1, + .xres = 800, + .yres = 480, + .refresh = 80, +}; + +static struct s3c_fb_platdata smartq5_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &smartq5_lcd_timing, + .win[0] = &smartq5_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | + VIDCON1_INV_VDEN, +}; + +static struct platform_device *smartq5_devices[] __initdata = { + &smartq5_leds_device, + &smartq5_buttons_device, +}; + +static void __init smartq5_machine_init(void) +{ + s3c_fb_set_platdata(&smartq5_lcd_pdata); + + smartq_machine_init(); + + platform_add_devices(smartq5_devices, ARRAY_SIZE(smartq5_devices)); +} + +MACHINE_START(SMARTQ5, "SmartQ 5") + /* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = smartq_map_io, + .init_machine = smartq5_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smartq7.c b/arch/arm/mach-s3c/mach-smartq7.c new file mode 100644 index 000000000..78ca0e704 --- /dev/null +++ b/arch/arm/mach-s3c/mach-smartq7.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2010 Maurus Cuelenaere + +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/gpio_keys.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/leds.h> +#include <linux/platform_device.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> + +#include <video/samsung_fimd.h> +#include "irqs.h" +#include "map.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include "fb.h" +#include "gpio-cfg.h" + +#include "s3c64xx.h" +#include "mach-smartq.h" + +static struct gpio_led smartq7_leds[] = { + { + .name = "smartq7:red", + .active_low = 1, + .gpio = S3C64XX_GPN(8), + }, + { + .name = "smartq7:green", + .active_low = 1, + .gpio = S3C64XX_GPN(9), + }, +}; + +static struct gpio_led_platform_data smartq7_led_data = { + .num_leds = ARRAY_SIZE(smartq7_leds), + .leds = smartq7_leds, +}; + +static struct platform_device smartq7_leds_device = { + .name = "leds-gpio", + .id = -1, + .dev.platform_data = &smartq7_led_data, +}; + +/* Labels according to the SmartQ manual */ +static struct gpio_keys_button smartq7_buttons[] = { + { + .gpio = S3C64XX_GPL(14), + .code = KEY_POWER, + .desc = "Power", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(2), + .code = KEY_FN, + .desc = "Function", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(3), + .code = KEY_KPMINUS, + .desc = "Minus", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(4), + .code = KEY_KPPLUS, + .desc = "Plus", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(12), + .code = KEY_ENTER, + .desc = "Enter", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, + { + .gpio = S3C64XX_GPN(15), + .code = KEY_ESC, + .desc = "Cancel", + .active_low = 1, + .debounce_interval = 5, + .type = EV_KEY, + }, +}; + +static struct gpio_keys_platform_data smartq7_buttons_data = { + .buttons = smartq7_buttons, + .nbuttons = ARRAY_SIZE(smartq7_buttons), +}; + +static struct platform_device smartq7_buttons_device = { + .name = "gpio-keys", + .id = 0, + .num_resources = 0, + .dev = { + .platform_data = &smartq7_buttons_data, + } +}; + +static struct s3c_fb_pd_win smartq7_fb_win0 = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, +}; + +static struct fb_videomode smartq7_lcd_timing = { + .left_margin = 3, + .right_margin = 5, + .upper_margin = 1, + .lower_margin = 20, + .hsync_len = 10, + .vsync_len = 3, + .xres = 800, + .yres = 480, + .refresh = 80, +}; + +static struct s3c_fb_platdata smartq7_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &smartq7_lcd_timing, + .win[0] = &smartq7_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC | + VIDCON1_INV_VCLK, +}; + +static struct platform_device *smartq7_devices[] __initdata = { + &smartq7_leds_device, + &smartq7_buttons_device, +}; + +static void __init smartq7_machine_init(void) +{ + s3c_fb_set_platdata(&smartq7_lcd_pdata); + + smartq_machine_init(); + + platform_add_devices(smartq7_devices, ARRAY_SIZE(smartq7_devices)); +} + +MACHINE_START(SMARTQ7, "SmartQ 7") + /* Maintainer: Maurus Cuelenaere <mcuelenaere AT gmail DOT com> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = smartq_map_io, + .init_machine = smartq7_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk2410.c b/arch/arm/mach-s3c/mach-smdk2410.c new file mode 100644 index 000000000..76b0a8846 --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk2410.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2004 by FS Forth-Systeme GmbH +// All rights reserved. +// +// @Author: Jonas Dietsche +// +// @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 "gpio-samsung.h" +#include "gpio-cfg.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/i2c-s3c2410.h> + +#include "devs.h" +#include "cpu.h" + +#include "s3c24xx.h" +#include "common-smdk-s3c24xx.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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init smdk2410_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init smdk2410_init(void) +{ + s3c_i2c0_set_platdata(NULL); + platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices)); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + smdk_machine_init(); +} + +MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch + * to SMDK2410 */ + /* Maintainer: Jonas Dietsche */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = smdk2410_map_io, + .init_irq = s3c2410_init_irq, + .init_machine = smdk2410_init, + .init_time = smdk2410_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk2413.c b/arch/arm/mach-s3c/mach-smdk2413.c new file mode 100644 index 000000000..2b4e20aaa --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk2413.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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. + +#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/machine.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 <asm/hardware/iomd.h> +#include <asm/setup.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +//#include <asm/debug-ll.h> +#include "hardware-s3c24xx.h" +#include "regs-gpio.h" + +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/fb-s3c2410.h> +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include "devs.h" +#include "cpu.h" + +#include "s3c24xx.h" +#include "common-smdk-s3c24xx.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 = { +}; + +static struct gpiod_lookup_table smdk2413_udc_gpio_table = { + .dev_id = "s3c2410-usbgadget", + .table = { + GPIO_LOOKUP("GPIOF", 2, "pullup", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init smdk2413_init_time(void) +{ + s3c2412_init_clocks(12000000); + s3c24xx_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); + + gpiod_add_lookup_table(&smdk2413_udc_gpio_table); + s3c24xx_udc_set_platdata(&smdk2413_udc_cfg); + s3c_i2c0_set_platdata(NULL); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + + 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, + .nr_irqs = NR_IRQS_S3C2412, + + .fixup = smdk2413_fixup, + .init_irq = s3c2412_init_irq, + .map_io = smdk2413_map_io, + .init_machine = smdk2413_machine_init, + .init_time = s3c24xx_timer_init, +MACHINE_END + +MACHINE_START(SMDK2412, "SMDK2412") + /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2412, + + .fixup = smdk2413_fixup, + .init_irq = s3c2412_init_irq, + .map_io = smdk2413_map_io, + .init_machine = smdk2413_machine_init, + .init_time = s3c24xx_timer_init, +MACHINE_END + +MACHINE_START(SMDK2413, "SMDK2413") + /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2412, + + .fixup = smdk2413_fixup, + .init_irq = s3c2412_init_irq, + .map_io = smdk2413_map_io, + .init_machine = smdk2413_machine_init, + .init_time = smdk2413_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk2416.c b/arch/arm/mach-s3c/mach-smdk2416.c new file mode 100644 index 000000000..329fe26be --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk2416.c @@ -0,0 +1,248 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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> + +#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 <asm/irq.h> +#include <asm/mach-types.h> + +#include "hardware-s3c24xx.h" +#include "regs-gpio.h" +#include "regs-s3c2443-clock.h" +#include "gpio-samsung.h" + +#include <linux/platform_data/leds-s3c24xx.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include "gpio-cfg.h" +#include "devs.h" +#include "cpu.h" +#include <linux/platform_data/mtd-nand-s3c2410.h> +#include "sdhci.h" +#include <linux/platform_data/usb-s3c2410_udc.h> +#include <linux/platform_data/s3c-hsudc.h> + +#include "fb.h" + +#include "s3c24xx.h" +#include "common-smdk-s3c24xx.h" + +static struct map_desc smdk2416_iodesc[] __initdata = { + /* ISA IO Space map (memory space selected by A24) */ + + { + .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); + s3c24xx_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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_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, + .nr_irqs = NR_IRQS_S3C2416, + + .init_irq = s3c2416_init_irq, + .map_io = smdk2416_map_io, + .init_machine = smdk2416_machine_init, + .init_time = smdk2416_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk2440.c b/arch/arm/mach-s3c/mach-smdk2440.c new file mode 100644 index 000000000..6aea769eb --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk2440.c @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: GPL-2.0 +// 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. + +#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 <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include <linux/platform_data/fb-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include "devs.h" +#include "cpu.h" + +#include "s3c24xx.h" +#include "common-smdk-s3c24xx.h" + +static struct map_desc smdk2440_iodesc[] __initdata = { + /* ISA IO Space map (memory space selected by A24) */ + + { + .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, + + .gpccon_reg = S3C2410_GPCCON, + .gpcup_reg = S3C2410_GPCUP, + .gpdcon_reg = S3C2410_GPDCON, + .gpdup_reg = S3C2410_GPDUP, +#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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init smdk2440_init_time(void) +{ + s3c2440_init_clocks(16934400); + s3c24xx_timer_init(); +} + +static void __init smdk2440_machine_init(void) +{ + s3c24xx_fb_set_platdata(&smdk2440_fb_info); + s3c_i2c0_set_platdata(NULL); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + 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, + .nr_irqs = NR_IRQS_S3C2440, + + .init_irq = s3c2440_init_irq, + .map_io = smdk2440_map_io, + .init_machine = smdk2440_machine_init, + .init_time = smdk2440_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk2443.c b/arch/arm/mach-s3c/mach-smdk2443.c new file mode 100644 index 000000000..075140f8f --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk2443.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 + +#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 <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" + +#include <linux/platform_data/fb-s3c2410.h> +#include <linux/platform_data/i2c-s3c2410.h> + +#include "devs.h" +#include "cpu.h" + +#include "s3c24xx.h" +#include "common-smdk-s3c24xx.h" + +static struct map_desc smdk2443_iodesc[] __initdata = { + /* ISA IO Space map (memory space selected by A24) */ + + { + .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, + &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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init smdk2443_init_time(void) +{ + s3c2443_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init smdk2443_machine_init(void) +{ + s3c_i2c0_set_platdata(NULL); + 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, + .nr_irqs = NR_IRQS_S3C2443, + .init_irq = s3c2443_init_irq, + .map_io = smdk2443_map_io, + .init_machine = smdk2443_machine_init, + .init_time = smdk2443_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk6400.c b/arch/arm/mach-s3c/mach-smdk6400.c new file mode 100644 index 000000000..a3c1b2a82 --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk6400.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.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/i2c.h> +#include <linux/io.h> + +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include "irqs.h" +#include "map.h" + +#include "devs.h" +#include "cpu.h" +#include <linux/platform_data/i2c-s3c2410.h> +#include "gpio-samsung.h" + +#include "s3c64xx.h" + +#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 smdk6400_uartcfgs[] __initdata = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = 0x3c5, + .ulcon = 0x03, + .ufcon = 0x51, + }, +}; + +static struct map_desc smdk6400_iodesc[] = {}; + +static void __init smdk6400_map_io(void) +{ + s3c64xx_init_io(smdk6400_iodesc, ARRAY_SIZE(smdk6400_iodesc)); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(smdk6400_uartcfgs, ARRAY_SIZE(smdk6400_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); +} + +static struct platform_device *smdk6400_devices[] __initdata = { + &s3c_device_hsmmc1, + &s3c_device_i2c0, +}; + +static struct i2c_board_info i2c_devs[] __initdata = { + { I2C_BOARD_INFO("wm8753", 0x1A), }, + { I2C_BOARD_INFO("24c08", 0x50), }, +}; + +static void __init smdk6400_machine_init(void) +{ + i2c_register_board_info(0, i2c_devs, ARRAY_SIZE(i2c_devs)); + platform_add_devices(smdk6400_devices, ARRAY_SIZE(smdk6400_devices)); +} + +MACHINE_START(SMDK6400, "SMDK6400") + /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6400_init_irq, + .map_io = smdk6400_map_io, + .init_machine = smdk6400_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-smdk6410.c b/arch/arm/mach-s3c/mach-smdk6410.c new file mode 100644 index 000000000..e57b2bb61 --- /dev/null +++ b/arch/arm/mach-s3c/mach-smdk6410.c @@ -0,0 +1,706 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.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/input.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/leds.h> +#include <linux/fb.h> +#include <linux/gpio.h> +#include <linux/delay.h> +#include <linux/smsc911x.h> +#include <linux/regulator/fixed.h> +#include <linux/regulator/machine.h> +#include <linux/pwm.h> +#include <linux/pwm_backlight.h> +#include <linux/platform_data/s3c-hsotg.h> + +#ifdef CONFIG_SMDK6410_WM1190_EV1 +#include <linux/mfd/wm8350/core.h> +#include <linux/mfd/wm8350/pmic.h> +#endif + +#ifdef CONFIG_SMDK6410_WM1192_EV1 +#include <linux/mfd/wm831x/core.h> +#include <linux/mfd/wm831x/pdata.h> +#endif + +#include <video/platform_lcd.h> +#include <video/samsung_fimd.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include "irqs.h" +#include "map.h" + +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include <linux/platform_data/ata-samsung_cf.h> +#include <linux/platform_data/i2c-s3c2410.h> +#include "fb.h" +#include "gpio-cfg.h" + +#include "devs.h" +#include "cpu.h" +#include <linux/soc/samsung/s3c-adc.h> +#include <linux/platform_data/touchscreen-s3c2410.h> +#include "keypad.h" + +#include "backlight-s3c64xx.h" +#include "s3c64xx.h" +#include "regs-modem-s3c64xx.h" +#include "regs-srom-s3c64xx.h" +#include "regs-sys-s3c64xx.h" + +#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 smdk6410_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, + }, + [3] = { + .hwport = 3, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, +}; + +/* framebuffer and LCD setup. */ + +/* GPF15 = LCD backlight control + * GPF13 => Panel power + * GPN5 = LCD nRESET signal + * PWM_TOUT1 => backlight brightness + */ + +static void smdk6410_lcd_power_set(struct plat_lcd_data *pd, + unsigned int power) +{ + if (power) { + gpio_direction_output(S3C64XX_GPF(13), 1); + + /* fire nRESET on power up */ + gpio_direction_output(S3C64XX_GPN(5), 0); + msleep(10); + gpio_direction_output(S3C64XX_GPN(5), 1); + msleep(1); + } else { + gpio_direction_output(S3C64XX_GPF(13), 0); + } +} + +static struct plat_lcd_data smdk6410_lcd_power_data = { + .set_power = smdk6410_lcd_power_set, +}; + +static struct platform_device smdk6410_lcd_powerdev = { + .name = "platform-lcd", + .dev.parent = &s3c_device_fb.dev, + .dev.platform_data = &smdk6410_lcd_power_data, +}; + +static struct s3c_fb_pd_win smdk6410_fb_win0 = { + .max_bpp = 32, + .default_bpp = 16, + .xres = 800, + .yres = 480, + .virtual_y = 480 * 2, + .virtual_x = 800, +}; + +static struct fb_videomode smdk6410_lcd_timing = { + .left_margin = 8, + .right_margin = 13, + .upper_margin = 7, + .lower_margin = 5, + .hsync_len = 3, + .vsync_len = 1, + .xres = 800, + .yres = 480, +}; + +/* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */ +static struct s3c_fb_platdata smdk6410_lcd_pdata __initdata = { + .setup_gpio = s3c64xx_fb_gpio_setup_24bpp, + .vtiming = &smdk6410_lcd_timing, + .win[0] = &smdk6410_fb_win0, + .vidcon0 = VIDCON0_VIDOUT_RGB | VIDCON0_PNRMODE_RGB, + .vidcon1 = VIDCON1_INV_HSYNC | VIDCON1_INV_VSYNC, +}; + +/* + * Configuring Ethernet on SMDK6410 + * + * Both CS8900A and LAN9115 chips share one chip select mediated by CFG6. + * The constant address below corresponds to nCS1 + * + * 1) Set CFGB2 p3 ON others off, no other CFGB selects "ethernet" + * 2) CFG6 needs to be switched to "LAN9115" side + */ + +static struct resource smdk6410_smsc911x_resources[] = { + [0] = DEFINE_RES_MEM(S3C64XX_PA_XM0CSN1, SZ_64K), + [1] = DEFINE_RES_NAMED(S3C_EINT(10), 1, NULL, IORESOURCE_IRQ \ + | IRQ_TYPE_LEVEL_LOW), +}; + +static struct smsc911x_platform_config smdk6410_smsc911x_pdata = { + .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW, + .irq_type = SMSC911X_IRQ_TYPE_OPEN_DRAIN, + .flags = SMSC911X_USE_32BIT | SMSC911X_FORCE_INTERNAL_PHY, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + + +static struct platform_device smdk6410_smsc911x = { + .name = "smsc911x", + .id = -1, + .num_resources = ARRAY_SIZE(smdk6410_smsc911x_resources), + .resource = &smdk6410_smsc911x_resources[0], + .dev = { + .platform_data = &smdk6410_smsc911x_pdata, + }, +}; + +#ifdef CONFIG_REGULATOR +static struct regulator_consumer_supply smdk6410_b_pwr_5v_consumers[] = { + REGULATOR_SUPPLY("PVDD", "0-001b"), + REGULATOR_SUPPLY("AVDD", "0-001b"), +}; + +static struct regulator_init_data __maybe_unused smdk6410_b_pwr_5v_data = { + .constraints = { + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(smdk6410_b_pwr_5v_consumers), + .consumer_supplies = smdk6410_b_pwr_5v_consumers, +}; + +static struct fixed_voltage_config smdk6410_b_pwr_5v_pdata = { + .supply_name = "B_PWR_5V", + .microvolts = 5000000, + .init_data = &smdk6410_b_pwr_5v_data, +}; + +static struct platform_device smdk6410_b_pwr_5v = { + .name = "reg-fixed-voltage", + .id = -1, + .dev = { + .platform_data = &smdk6410_b_pwr_5v_pdata, + }, +}; +#endif + +static struct s3c_ide_platdata smdk6410_ide_pdata __initdata = { + .setup_gpio = s3c64xx_ide_setup_gpio, +}; + +static uint32_t smdk6410_keymap[] __initdata = { + /* KEY(row, col, keycode) */ + KEY(0, 3, KEY_1), KEY(0, 4, KEY_2), KEY(0, 5, KEY_3), + KEY(0, 6, KEY_4), KEY(0, 7, KEY_5), + KEY(1, 3, KEY_A), KEY(1, 4, KEY_B), KEY(1, 5, KEY_C), + KEY(1, 6, KEY_D), KEY(1, 7, KEY_E) +}; + +static struct matrix_keymap_data smdk6410_keymap_data __initdata = { + .keymap = smdk6410_keymap, + .keymap_size = ARRAY_SIZE(smdk6410_keymap), +}; + +static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = { + .keymap_data = &smdk6410_keymap_data, + .rows = 2, + .cols = 8, +}; + +static struct map_desc smdk6410_iodesc[] = {}; + +static struct platform_device *smdk6410_devices[] __initdata = { +#ifdef CONFIG_SMDK6410_SD_CH0 + &s3c_device_hsmmc0, +#endif +#ifdef CONFIG_SMDK6410_SD_CH1 + &s3c_device_hsmmc1, +#endif + &s3c_device_i2c0, + &s3c_device_i2c1, + &s3c_device_fb, + &s3c_device_ohci, + &samsung_device_pwm, + &s3c_device_usb_hsotg, + &s3c64xx_device_iisv4, + &samsung_device_keypad, + +#ifdef CONFIG_REGULATOR + &smdk6410_b_pwr_5v, +#endif + &smdk6410_lcd_powerdev, + + &smdk6410_smsc911x, + &s3c_device_adc, + &s3c_device_cfcon, + &s3c_device_rtc, + &s3c_device_wdt, +}; + +#ifdef CONFIG_REGULATOR +/* ARM core */ +static struct regulator_consumer_supply smdk6410_vddarm_consumers[] = { + REGULATOR_SUPPLY("vddarm", NULL), +}; + +/* VDDARM, BUCK1 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddarm = { + .constraints = { + .name = "PVDD_ARM", + .min_uV = 1000000, + .max_uV = 1300000, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, + .num_consumer_supplies = ARRAY_SIZE(smdk6410_vddarm_consumers), + .consumer_supplies = smdk6410_vddarm_consumers, +}; + +/* VDD_INT, BUCK2 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddint = { + .constraints = { + .name = "PVDD_INT", + .min_uV = 1000000, + .max_uV = 1200000, + .always_on = 1, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE, + }, +}; + +/* VDD_HI, LDO3 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddhi = { + .constraints = { + .name = "PVDD_HI", + .always_on = 1, + }, +}; + +/* VDD_PLL, LDO2 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddpll = { + .constraints = { + .name = "PVDD_PLL", + .always_on = 1, + }, +}; + +/* VDD_UH_MMC, LDO5 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vdduh_mmc = { + .constraints = { + .name = "PVDD_UH+PVDD_MMC", + .always_on = 1, + }, +}; + +/* VCCM3BT, LDO8 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vccmc3bt = { + .constraints = { + .name = "PVCCM3BT", + .always_on = 1, + }, +}; + +/* VCCM2MTV, LDO11 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vccm2mtv = { + .constraints = { + .name = "PVCCM2MTV", + .always_on = 1, + }, +}; + +/* VDD_LCD, LDO12 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddlcd = { + .constraints = { + .name = "PVDD_LCD", + .always_on = 1, + }, +}; + +/* VDD_OTGI, LDO9 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddotgi = { + .constraints = { + .name = "PVDD_OTGI", + .always_on = 1, + }, +}; + +/* VDD_OTG, LDO14 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddotg = { + .constraints = { + .name = "PVDD_OTG", + .always_on = 1, + }, +}; + +/* VDD_ALIVE, LDO15 on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddalive = { + .constraints = { + .name = "PVDD_ALIVE", + .always_on = 1, + }, +}; + +/* VDD_AUDIO, VLDO_AUDIO on J5 */ +static struct regulator_init_data __maybe_unused smdk6410_vddaudio = { + .constraints = { + .name = "PVDD_AUDIO", + .always_on = 1, + }, +}; +#endif + +#ifdef CONFIG_SMDK6410_WM1190_EV1 +/* S3C64xx internal logic & PLL */ +static struct regulator_init_data __maybe_unused wm8350_dcdc1_data = { + .constraints = { + .name = "PVDD_INT+PVDD_PLL", + .min_uV = 1200000, + .max_uV = 1200000, + .always_on = 1, + .apply_uV = 1, + }, +}; + +/* Memory */ +static struct regulator_init_data __maybe_unused wm8350_dcdc3_data = { + .constraints = { + .name = "PVDD_MEM", + .min_uV = 1800000, + .max_uV = 1800000, + .always_on = 1, + .state_mem = { + .uV = 1800000, + .mode = REGULATOR_MODE_NORMAL, + .enabled = 1, + }, + .initial_state = PM_SUSPEND_MEM, + }, +}; + +/* USB, EXT, PCM, ADC/DAC, USB, MMC */ +static struct regulator_consumer_supply wm8350_dcdc4_consumers[] = { + REGULATOR_SUPPLY("DVDD", "0-001b"), +}; + +static struct regulator_init_data __maybe_unused wm8350_dcdc4_data = { + .constraints = { + .name = "PVDD_HI+PVDD_EXT+PVDD_SYS+PVCCM2MTV", + .min_uV = 3000000, + .max_uV = 3000000, + .always_on = 1, + }, + .num_consumer_supplies = ARRAY_SIZE(wm8350_dcdc4_consumers), + .consumer_supplies = wm8350_dcdc4_consumers, +}; + +/* OTGi/1190-EV1 HPVDD & AVDD */ +static struct regulator_init_data __maybe_unused wm8350_ldo4_data = { + .constraints = { + .name = "PVDD_OTGI+HPVDD+AVDD", + .min_uV = 1200000, + .max_uV = 1200000, + .apply_uV = 1, + .always_on = 1, + }, +}; + +static struct { + int regulator; + struct regulator_init_data *initdata; +} wm1190_regulators[] = { + { WM8350_DCDC_1, &wm8350_dcdc1_data }, + { WM8350_DCDC_3, &wm8350_dcdc3_data }, + { WM8350_DCDC_4, &wm8350_dcdc4_data }, + { WM8350_DCDC_6, &smdk6410_vddarm }, + { WM8350_LDO_1, &smdk6410_vddalive }, + { WM8350_LDO_2, &smdk6410_vddotg }, + { WM8350_LDO_3, &smdk6410_vddlcd }, + { WM8350_LDO_4, &wm8350_ldo4_data }, +}; + +static int __init smdk6410_wm8350_init(struct wm8350 *wm8350) +{ + int i; + + /* Configure the IRQ line */ + s3c_gpio_setpull(S3C64XX_GPN(12), S3C_GPIO_PULL_UP); + + /* Instantiate the regulators */ + for (i = 0; i < ARRAY_SIZE(wm1190_regulators); i++) + wm8350_register_regulator(wm8350, + wm1190_regulators[i].regulator, + wm1190_regulators[i].initdata); + + return 0; +} + +static struct wm8350_platform_data __initdata smdk6410_wm8350_pdata = { + .init = smdk6410_wm8350_init, + .irq_high = 1, + .irq_base = IRQ_BOARD_START, +}; +#endif + +#ifdef CONFIG_SMDK6410_WM1192_EV1 +static struct gpio_led wm1192_pmic_leds[] = { + { + .name = "PMIC:red:power", + .gpio = GPIO_BOARD_START + 3, + .default_state = LEDS_GPIO_DEFSTATE_ON, + }, +}; + +static struct gpio_led_platform_data wm1192_pmic_led = { + .num_leds = ARRAY_SIZE(wm1192_pmic_leds), + .leds = wm1192_pmic_leds, +}; + +static struct platform_device wm1192_pmic_led_dev = { + .name = "leds-gpio", + .id = -1, + .dev = { + .platform_data = &wm1192_pmic_led, + }, +}; + +static int wm1192_pre_init(struct wm831x *wm831x) +{ + int ret; + + /* Configure the IRQ line */ + s3c_gpio_setpull(S3C64XX_GPN(12), S3C_GPIO_PULL_UP); + + ret = platform_device_register(&wm1192_pmic_led_dev); + if (ret != 0) + dev_err(wm831x->dev, "Failed to add PMIC LED: %d\n", ret); + + return 0; +} + +static struct wm831x_backlight_pdata wm1192_backlight_pdata = { + .isink = 1, + .max_uA = 27554, +}; + +static struct regulator_init_data __maybe_unused wm1192_dcdc3 = { + .constraints = { + .name = "PVDD_MEM+PVDD_GPS", + .always_on = 1, + }, +}; + +static struct regulator_consumer_supply wm1192_ldo1_consumers[] = { + REGULATOR_SUPPLY("DVDD", "0-001b"), /* WM8580 */ +}; + +static struct regulator_init_data __maybe_unused wm1192_ldo1 = { + .constraints = { + .name = "PVDD_LCD+PVDD_EXT", + .always_on = 1, + }, + .consumer_supplies = wm1192_ldo1_consumers, + .num_consumer_supplies = ARRAY_SIZE(wm1192_ldo1_consumers), +}; + +static struct wm831x_status_pdata wm1192_led7_pdata = { + .name = "LED7:green:", +}; + +static struct wm831x_status_pdata wm1192_led8_pdata = { + .name = "LED8:green:", +}; + +static struct wm831x_pdata smdk6410_wm1192_pdata = { + .pre_init = wm1192_pre_init, + + .backlight = &wm1192_backlight_pdata, + .dcdc = { + &smdk6410_vddarm, /* DCDC1 */ + &smdk6410_vddint, /* DCDC2 */ + &wm1192_dcdc3, + }, + .gpio_base = GPIO_BOARD_START, + .ldo = { + &wm1192_ldo1, /* LDO1 */ + &smdk6410_vdduh_mmc, /* LDO2 */ + NULL, /* LDO3 NC */ + &smdk6410_vddotgi, /* LDO4 */ + &smdk6410_vddotg, /* LDO5 */ + &smdk6410_vddhi, /* LDO6 */ + &smdk6410_vddaudio, /* LDO7 */ + &smdk6410_vccm2mtv, /* LDO8 */ + &smdk6410_vddpll, /* LDO9 */ + &smdk6410_vccmc3bt, /* LDO10 */ + &smdk6410_vddalive, /* LDO11 */ + }, + .status = { + &wm1192_led7_pdata, + &wm1192_led8_pdata, + }, +}; +#endif + +static struct i2c_board_info i2c_devs0[] __initdata = { + { I2C_BOARD_INFO("24c08", 0x50), }, + { I2C_BOARD_INFO("wm8580", 0x1b), }, + +#ifdef CONFIG_SMDK6410_WM1192_EV1 + { I2C_BOARD_INFO("wm8312", 0x34), + .platform_data = &smdk6410_wm1192_pdata, + .irq = S3C_EINT(12), + }, +#endif + +#ifdef CONFIG_SMDK6410_WM1190_EV1 + { I2C_BOARD_INFO("wm8350", 0x1a), + .platform_data = &smdk6410_wm8350_pdata, + .irq = S3C_EINT(12), + }, +#endif +}; + +static struct i2c_board_info i2c_devs1[] __initdata = { + { I2C_BOARD_INFO("24c128", 0x57), }, /* Samsung S524AD0XD1 */ +}; + +/* LCD Backlight data */ +static struct samsung_bl_gpio_info smdk6410_bl_gpio_info = { + .no = S3C64XX_GPF(15), + .func = S3C_GPIO_SFN(2), +}; + +static struct pwm_lookup smdk6410_pwm_lookup[] = { + PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL, 78770, + PWM_POLARITY_NORMAL), +}; + +static struct platform_pwm_backlight_data smdk6410_bl_data = { + /* Intentionally blank */ +}; + +static struct dwc2_hsotg_plat smdk6410_hsotg_pdata; + +static void __init smdk6410_map_io(void) +{ + u32 tmp; + + s3c64xx_init_io(smdk6410_iodesc, ARRAY_SIZE(smdk6410_iodesc)); + s3c64xx_set_xtal_freq(12000000); + s3c24xx_init_uarts(smdk6410_uartcfgs, ARRAY_SIZE(smdk6410_uartcfgs)); + s3c64xx_set_timer_source(S3C64XX_PWM3, S3C64XX_PWM4); + + /* set the LCD type */ + + tmp = __raw_readl(S3C64XX_SPCON); + tmp &= ~S3C64XX_SPCON_LCD_SEL_MASK; + tmp |= S3C64XX_SPCON_LCD_SEL_RGB; + __raw_writel(tmp, S3C64XX_SPCON); + + /* remove the lcd bypass */ + tmp = __raw_readl(S3C64XX_MODEM_MIFPCON); + tmp &= ~MIFPCON_LCD_BYPASS; + __raw_writel(tmp, S3C64XX_MODEM_MIFPCON); +} + +static void __init smdk6410_machine_init(void) +{ + u32 cs1; + + s3c_i2c0_set_platdata(NULL); + s3c_i2c1_set_platdata(NULL); + s3c_fb_set_platdata(&smdk6410_lcd_pdata); + dwc2_hsotg_set_platdata(&smdk6410_hsotg_pdata); + + samsung_keypad_set_platdata(&smdk6410_keypad_data); + + s3c64xx_ts_set_platdata(NULL); + + /* configure nCS1 width to 16 bits */ + + cs1 = __raw_readl(S3C64XX_SROM_BW) & + ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT); + cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) | + (1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) | + (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) << + S3C64XX_SROM_BW__NCS1__SHIFT; + __raw_writel(cs1, S3C64XX_SROM_BW); + + /* set timing for nCS1 suitable for ethernet chip */ + + __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) | + (6 << S3C64XX_SROM_BCX__TACP__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) | + (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) | + (0xe << S3C64XX_SROM_BCX__TACC__SHIFT) | + (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) | + (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1); + + gpio_request(S3C64XX_GPN(5), "LCD power"); + gpio_request(S3C64XX_GPF(13), "LCD power"); + + i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0)); + i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1)); + + s3c_ide_set_platdata(&smdk6410_ide_pdata); + + platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices)); + + pwm_add_table(smdk6410_pwm_lookup, ARRAY_SIZE(smdk6410_pwm_lookup)); + samsung_bl_set(&smdk6410_bl_gpio_info, &smdk6410_bl_data); +} + +MACHINE_START(SMDK6410, "SMDK6410") + /* Maintainer: Ben Dooks <ben-linux@fluff.org> */ + .atag_offset = 0x100, + .nr_irqs = S3C64XX_NR_IRQS, + .init_irq = s3c6410_init_irq, + .map_io = smdk6410_map_io, + .init_machine = smdk6410_machine_init, + .init_time = s3c64xx_timer_init, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-tct_hammer.c b/arch/arm/mach-s3c/mach-tct_hammer.c new file mode 100644 index 000000000..93ab1abd8 --- /dev/null +++ b/arch/arm/mach-s3c/mach-tct_hammer.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2007 TinCanTools +// David Anders <danders@amltd.com> +// +// @History: +// derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by +// Ben Dooks <ben@simtec.co.uk> + +#include <linux/gpio/machine.h> +#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 <asm/irq.h> +#include <asm/mach-types.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include "devs.h" +#include "cpu.h" + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/map.h> +#include <linux/mtd/physmap.h> + +#include "s3c24xx.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 gpiod_lookup_table tct_hammer_mmc_gpio_table = { + .dev_id = "s3c2410-sdi", + .table = { + /* bus pins */ + GPIO_LOOKUP_IDX("GPIOE", 5, "bus", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 6, "bus", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 7, "bus", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 8, "bus", 3, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 9, "bus", 4, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("GPIOE", 10, "bus", 5, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init tct_hammer_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init tct_hammer_init(void) +{ + s3c_i2c0_set_platdata(NULL); + gpiod_add_lookup_table(&tct_hammer_mmc_gpio_table); + platform_add_devices(tct_hammer_devices, ARRAY_SIZE(tct_hammer_devices)); +} + +MACHINE_START(TCT_HAMMER, "TCT_HAMMER") + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = tct_hammer_map_io, + .init_irq = s3c2410_init_irq, + .init_machine = tct_hammer_init, + .init_time = tct_hammer_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-vr1000.c b/arch/arm/mach-s3c/mach-vr1000.c new file mode 100644 index 000000000..c85033e6e --- /dev/null +++ b/arch/arm/mach-s3c/mach-vr1000.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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/ + +#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/gpio/machine.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 "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include "cpu.h" +#include "devs.h" + +#include "bast.h" +#include "s3c24xx.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, + }, + + /* 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 gpiod_lookup_table vr1000_led1_gpio_table = { + .dev_id = "s3c24xx_led.1", + .table = { + GPIO_LOOKUP("GPB", 0, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table vr1000_led2_gpio_table = { + .dev_id = "s3c24xx_led.2", + .table = { + GPIO_LOOKUP("GPB", 1, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct gpiod_lookup_table vr1000_led3_gpio_table = { + .dev_id = "s3c24xx_led.3", + .table = { + GPIO_LOOKUP("GPB", 2, NULL, GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static struct s3c24xx_led_platdata vr1000_led1_pdata = { + .name = "led1", + .def_trigger = "", +}; + +static struct s3c24xx_led_platdata vr1000_led2_pdata = { + .name = "led2", + .def_trigger = "", +}; + +static struct s3c24xx_led_platdata vr1000_led3_pdata = { + .name = "led3", + .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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init vr1000_init_time(void) +{ + s3c2410_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init vr1000_init(void) +{ + s3c_i2c0_set_platdata(NULL); + + /* Disable pull-up on LED lines and register GPIO lookups */ + s3c_gpio_setpull(S3C2410_GPB(0), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPB(1), S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(S3C2410_GPB(2), S3C_GPIO_PULL_NONE); + gpiod_add_lookup_table(&vr1000_led1_gpio_table); + gpiod_add_lookup_table(&vr1000_led2_gpio_table); + gpiod_add_lookup_table(&vr1000_led3_gpio_table); + + 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, + .nr_irqs = NR_IRQS_S3C2410, + .map_io = vr1000_map_io, + .init_machine = vr1000_init, + .init_irq = s3c2410_init_irq, + .init_time = vr1000_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/mach-vstms.c b/arch/arm/mach-s3c/mach-vstms.c new file mode 100644 index 000000000..6f878418b --- /dev/null +++ b/arch/arm/mach-s3c/mach-vstms.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// (C) 2006 Thomas Gleixner <tglx@linutronix.de> +// +// Derived from mach-smdk2413.c - (C) 2006 Simtec Electronics + +#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/rawnand.h> +#include <linux/mtd/nand-ecc-sw-hamming.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 <asm/setup.h> +#include <asm/irq.h> +#include <asm/mach-types.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include <linux/platform_data/fb-s3c2410.h> + +#include <linux/platform_data/i2c-s3c2410.h> +#include <linux/platform_data/mtd-nand-s3c2410.h> + +#include "devs.h" +#include "cpu.h" + +#include "s3c24xx.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, + .engine_type = NAND_ECC_ENGINE_TYPE_SOFT, +}; + +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)); + s3c24xx_set_timer_source(S3C24XX_PWM3, S3C24XX_PWM4); +} + +static void __init vstms_init_time(void) +{ + s3c2412_init_clocks(12000000); + s3c24xx_timer_init(); +} + +static void __init vstms_init(void) +{ + s3c_i2c0_set_platdata(NULL); + s3c_nand_set_platdata(&vstms_nand_info); + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + platform_add_devices(vstms_devices, ARRAY_SIZE(vstms_devices)); +} + +MACHINE_START(VSTMS, "VSTMS") + .atag_offset = 0x100, + .nr_irqs = NR_IRQS_S3C2412, + + .fixup = vstms_fixup, + .init_irq = s3c2412_init_irq, + .init_machine = vstms_init, + .map_io = vstms_map_io, + .init_time = vstms_init_time, +MACHINE_END diff --git a/arch/arm/mach-s3c/map-base.h b/arch/arm/mach-s3c/map-base.h new file mode 100644 index 000000000..463a995b3 --- /dev/null +++ b/arch/arm/mach-s3c/map-base.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2003, 2007 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - Memory map definitions (virtual addresses) + */ + +#ifndef __ASM_PLAT_MAP_H +#define __ASM_PLAT_MAP_H __FILE__ + +/* Fit all our registers in at 0xF6000000 upwards, trying to use as + * little of the VA space as possible so vmalloc and friends have a + * better chance of getting memory. + * + * we try to ensure stuff like the IRQ registers are available for + * an single MOVS instruction (ie, only 8 bits of set data) + */ + +#define S3C_ADDR_BASE 0xF6000000 + +#ifndef __ASSEMBLY__ +#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x)) +#else +#define S3C_ADDR(x) (S3C_ADDR_BASE + (x)) +#endif + +#define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */ +#define S3C_VA_SYS S3C_ADDR(0x00100000) /* system control */ +#define S3C_VA_MEM S3C_ADDR(0x00200000) /* memory control */ +#define S3C_VA_TIMER S3C_ADDR(0x00300000) /* timer block */ +#define S3C_VA_WATCHDOG S3C_ADDR(0x00400000) /* watchdog */ +#define S3C_VA_UART S3C_ADDR(0x01000000) /* UART */ + +/* ISA device mapping for BAST to use with inb()/outb() on 8-bit I/O. + * 16-bit I/O on BAST now requires driver modifications to manually + * ioremap CS3. + */ +#define S3C24XX_VA_ISA_BYTE PCI_IOBASE + +/* This is used for the CPU specific mappings that may be needed, so that + * they do not need to directly used S3C_ADDR() and thus make it easier to + * modify the space for mapping. + */ +#define S3C_ADDR_CPU(x) S3C_ADDR(0x00500000 + (x)) + +#endif /* __ASM_PLAT_MAP_H */ diff --git a/arch/arm/mach-s3c/map-s3c.h b/arch/arm/mach-s3c/map-s3c.h new file mode 100644 index 000000000..a18fdd3d6 --- /dev/null +++ b/arch/arm/mach-s3c/map-s3c.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C24XX - Memory map definitions + */ + +#ifndef __ASM_PLAT_MAP_S3C_H +#define __ASM_PLAT_MAP_S3C_H __FILE__ + +#include "map.h" + +#define S3C24XX_VA_IRQ S3C_VA_IRQ +#define S3C24XX_VA_MEMCTRL S3C_VA_MEM +#define S3C24XX_VA_UART S3C_VA_UART + +#define S3C24XX_VA_TIMER S3C_VA_TIMER +#define S3C24XX_VA_CLKPWR S3C_VA_SYS +#define S3C24XX_VA_WATCHDOG S3C_VA_WATCHDOG + +#define S3C2412_VA_SSMC S3C_ADDR_CPU(0x00000000) +#define S3C2412_VA_EBI S3C_ADDR_CPU(0x00100000) + +#define S3C2410_PA_UART (0x50000000) +#define S3C24XX_PA_UART S3C2410_PA_UART + +/* + * GPIO ports + * + * the calculation for the VA of this must ensure that + * it is the same distance apart from the UART in the + * phsyical address space, as the initial mapping for the IO + * is done as a 1:1 mapping. This puts it (currently) at + * 0xFA800000, which is not in the way of any current mapping + * by the base system. +*/ + +#define S3C2410_PA_GPIO (0x56000000) +#define S3C24XX_PA_GPIO S3C2410_PA_GPIO + +#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART) +#define S3C64XX_VA_GPIO S3C_ADDR_CPU(0x00000000) + +#define S3C64XX_VA_MODEM S3C_ADDR_CPU(0x00100000) +#define S3C64XX_VA_USB_HSPHY S3C_ADDR_CPU(0x00200000) + +#define S3C_VA_USB_HSPHY S3C64XX_VA_USB_HSPHY + +#define S3C2410_ADDR(x) S3C_ADDR(x) + +/* deal with the registers that move under the 2412/2413 */ + +#if defined(CONFIG_CPU_S3C2412) +#ifndef __ASSEMBLY__ +extern void __iomem *s3c24xx_va_gpio2; +#endif +#ifdef CONFIG_CPU_S3C2412_ONLY +#define S3C24XX_VA_GPIO2 (S3C24XX_VA_GPIO + 0x10) +#else +#define S3C24XX_VA_GPIO2 s3c24xx_va_gpio2 +#endif +#else +#define s3c24xx_va_gpio2 S3C24XX_VA_GPIO +#define S3C24XX_VA_GPIO2 S3C24XX_VA_GPIO +#endif + +#include "map-s5p.h" + +#endif /* __ASM_PLAT_MAP_S3C_H */ diff --git a/arch/arm/mach-s3c/map-s3c24xx.h b/arch/arm/mach-s3c/map-s3c24xx.h new file mode 100644 index 000000000..f8d075b11 --- /dev/null +++ b/arch/arm/mach-s3c/map-s3c24xx.h @@ -0,0 +1,159 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2410 - Memory map definitions + */ + +#ifndef __ASM_ARCH_MAP_H +#define __ASM_ARCH_MAP_H + +#include "map-base.h" +#include "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 + +/* 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 +#define S3C2410_SPI1 (0x20) +#define S3C2412_SPI1 (0x100) + +/* 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_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-s3c/map-s3c64xx.h b/arch/arm/mach-s3c/map-s3c64xx.h new file mode 100644 index 000000000..9de1c58bc --- /dev/null +++ b/arch/arm/mach-s3c/map-s3c64xx.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C64XX - Memory map definitions + */ + +#ifndef __ASM_ARCH_MAP_H +#define __ASM_ARCH_MAP_H __FILE__ + +#include "map-base.h" +#include "map-s3c.h" + +/* + * Post-mux Chip Select Regions Xm0CSn_ + * These may be used by SROM, NAND or CF depending on settings + */ + +#define S3C64XX_PA_XM0CSN0 (0x10000000) +#define S3C64XX_PA_XM0CSN1 (0x18000000) +#define S3C64XX_PA_XM0CSN2 (0x20000000) +#define S3C64XX_PA_XM0CSN3 (0x28000000) +#define S3C64XX_PA_XM0CSN4 (0x30000000) +#define S3C64XX_PA_XM0CSN5 (0x38000000) + +/* HSMMC units */ +#define S3C64XX_PA_HSMMC(x) (0x7C200000 + ((x) * 0x100000)) +#define S3C64XX_PA_HSMMC0 S3C64XX_PA_HSMMC(0) +#define S3C64XX_PA_HSMMC1 S3C64XX_PA_HSMMC(1) +#define S3C64XX_PA_HSMMC2 S3C64XX_PA_HSMMC(2) + +#define S3C_PA_UART (0x7F005000) +#define S3C_PA_UART0 (S3C_PA_UART + 0x00) +#define S3C_PA_UART1 (S3C_PA_UART + 0x400) +#define S3C_PA_UART2 (S3C_PA_UART + 0x800) +#define S3C_PA_UART3 (S3C_PA_UART + 0xC00) +#define S3C_UART_OFFSET (0x400) + +/* See notes on UART VA mapping in debug-macro.S */ +#define S3C_VA_UARTx(x) (S3C_VA_UART + (S3C_PA_UART & 0xfffff) + ((x) * S3C_UART_OFFSET)) + +#define S3C_VA_UART0 S3C_VA_UARTx(0) +#define S3C_VA_UART1 S3C_VA_UARTx(1) +#define S3C_VA_UART2 S3C_VA_UARTx(2) +#define S3C_VA_UART3 S3C_VA_UARTx(3) + +#define S3C64XX_PA_SROM (0x70000000) + +#define S3C64XX_PA_ONENAND0 (0x70100000) +#define S3C64XX_PA_ONENAND0_BUF (0x20000000) +#define S3C64XX_SZ_ONENAND0_BUF (SZ_64M) + +/* NAND and OneNAND1 controllers occupy the same register region + (depending on SoC POP version) */ +#define S3C64XX_PA_ONENAND1 (0x70200000) +#define S3C64XX_PA_ONENAND1_BUF (0x28000000) +#define S3C64XX_SZ_ONENAND1_BUF (SZ_64M) + +#define S3C64XX_PA_NAND (0x70200000) +#define S3C64XX_PA_FB (0x77100000) +#define S3C64XX_PA_USB_HSOTG (0x7C000000) +#define S3C64XX_PA_WATCHDOG (0x7E004000) +#define S3C64XX_PA_RTC (0x7E005000) +#define S3C64XX_PA_KEYPAD (0x7E00A000) +#define S3C64XX_PA_ADC (0x7E00B000) +#define S3C64XX_PA_SYSCON (0x7E00F000) +#define S3C64XX_PA_AC97 (0x7F001000) +#define S3C64XX_PA_IIS0 (0x7F002000) +#define S3C64XX_PA_IIS1 (0x7F003000) +#define S3C64XX_PA_TIMER (0x7F006000) +#define S3C64XX_PA_IIC0 (0x7F004000) +#define S3C64XX_PA_SPI0 (0x7F00B000) +#define S3C64XX_PA_SPI1 (0x7F00C000) +#define S3C64XX_PA_PCM0 (0x7F009000) +#define S3C64XX_PA_PCM1 (0x7F00A000) +#define S3C64XX_PA_IISV4 (0x7F00D000) +#define S3C64XX_PA_IIC1 (0x7F00F000) + +#define S3C64XX_PA_GPIO (0x7F008000) +#define S3C64XX_SZ_GPIO SZ_4K + +#define S3C64XX_PA_SDRAM (0x50000000) + +#define S3C64XX_PA_CFCON (0x70300000) + +#define S3C64XX_PA_VIC0 (0x71200000) +#define S3C64XX_PA_VIC1 (0x71300000) + +#define S3C64XX_PA_MODEM (0x74108000) + +#define S3C64XX_PA_USBHOST (0x74300000) + +#define S3C64XX_PA_USB_HSPHY (0x7C100000) + +/* compatibility defines. */ +#define S3C_PA_TIMER S3C64XX_PA_TIMER +#define S3C_PA_HSMMC0 S3C64XX_PA_HSMMC0 +#define S3C_PA_HSMMC1 S3C64XX_PA_HSMMC1 +#define S3C_PA_HSMMC2 S3C64XX_PA_HSMMC2 +#define S3C_PA_IIC S3C64XX_PA_IIC0 +#define S3C_PA_IIC1 S3C64XX_PA_IIC1 +#define S3C_PA_NAND S3C64XX_PA_NAND +#define S3C_PA_ONENAND S3C64XX_PA_ONENAND0 +#define S3C_PA_ONENAND_BUF S3C64XX_PA_ONENAND0_BUF +#define S3C_SZ_ONENAND_BUF S3C64XX_SZ_ONENAND0_BUF +#define S3C_PA_FB S3C64XX_PA_FB +#define S3C_PA_USBHOST S3C64XX_PA_USBHOST +#define S3C_PA_USB_HSOTG S3C64XX_PA_USB_HSOTG +#define S3C_PA_RTC S3C64XX_PA_RTC +#define S3C_PA_WDT S3C64XX_PA_WATCHDOG +#define S3C_PA_SPI0 S3C64XX_PA_SPI0 +#define S3C_PA_SPI1 S3C64XX_PA_SPI1 + +#define SAMSUNG_PA_ADC S3C64XX_PA_ADC +#define SAMSUNG_PA_CFCON S3C64XX_PA_CFCON +#define SAMSUNG_PA_KEYPAD S3C64XX_PA_KEYPAD +#define SAMSUNG_PA_TIMER S3C64XX_PA_TIMER + +#endif /* __ASM_ARCH_6400_MAP_H */ diff --git a/arch/arm/mach-s3c/map-s5p.h b/arch/arm/mach-s3c/map-s5p.h new file mode 100644 index 000000000..cd237924e --- /dev/null +++ b/arch/arm/mach-s3c/map-s5p.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S5P - Memory map definitions + */ + +#ifndef __ASM_PLAT_MAP_S5P_H +#define __ASM_PLAT_MAP_S5P_H __FILE__ + +#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000)) +#define VA_VIC0 VA_VIC(0) +#define VA_VIC1 VA_VIC(1) +#define VA_VIC2 VA_VIC(2) +#define VA_VIC3 VA_VIC(3) + +#include "map-s3c.h" + +#endif /* __ASM_PLAT_MAP_S5P_H */ diff --git a/arch/arm/mach-s3c/map.h b/arch/arm/mach-s3c/map.h new file mode 100644 index 000000000..7cfb517d4 --- /dev/null +++ b/arch/arm/mach-s3c/map.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "map-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "map-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/nand-core-s3c24xx.h b/arch/arm/mach-s3c/nand-core-s3c24xx.h new file mode 100644 index 000000000..a14316729 --- /dev/null +++ b/arch/arm/mach-s3c/nand-core-s3c24xx.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * S3C - Nand Controller core functions + */ + +#ifndef __ASM_ARCH_NAND_CORE_S3C24XX_H +#define __ASM_ARCH_NAND_CORE_S3C24XX_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_nand_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_NAND + s3c_device_nand.name = name; +#endif +} + +#endif /* __ASM_ARCH_NAND_CORE_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/onenand-core-s3c64xx.h b/arch/arm/mach-s3c/onenand-core-s3c64xx.h new file mode 100644 index 000000000..e2dfdd1fe --- /dev/null +++ b/arch/arm/mach-s3c/onenand-core-s3c64xx.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2010 Samsung Electronics + * Kyungmin Park <kyungmin.park@samsung.com> + * Marek Szyprowski <m.szyprowski@samsung.com> + * + * Samsung OneNAD Controller core functions + */ + +#ifndef __ASM_ARCH_ONENAND_CORE_S3C64XX_H +#define __ASM_ARCH_ONENAND_CORE_S3C64XX_H __FILE__ + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c_onenand_setname(char *name) +{ +#ifdef CONFIG_S3C_DEV_ONENAND + s3c_device_onenand.name = name; +#endif +} + +static inline void s3c64xx_onenand1_setname(char *name) +{ +#ifdef CONFIG_S3C64XX_DEV_ONENAND1 + s3c64xx_device_onenand1.name = name; +#endif +} + +#endif /* __ASM_ARCH_ONENAND_CORE_S3C64XX_H */ diff --git a/arch/arm/mach-s3c/osiris.h b/arch/arm/mach-s3c/osiris.h new file mode 100644 index 000000000..b6c9c5ed2 --- /dev/null +++ b/arch/arm/mach-s3c/osiris.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2005 Simtec Electronics + * http://www.simtec.co.uk/products/ + * Ben Dooks <ben@simtec.co.uk> + * + * OSIRIS - CPLD control constants + * OSIRIS - Memory map definitions + */ + +#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-s3c/otom.h b/arch/arm/mach-s3c/otom.h new file mode 100644 index 000000000..c800f67d0 --- /dev/null +++ b/arch/arm/mach-s3c/otom.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * (c) 2005 Guillaume GOURAT / NexVision + * guillaume.gourat@nexvision.fr + * + * NexVision OTOM board memory map definitions + */ + +/* + * 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-s3c/pl080.c b/arch/arm/mach-s3c/pl080.c new file mode 100644 index 000000000..0a14f77b2 --- /dev/null +++ b/arch/arm/mach-s3c/pl080.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Samsung's S3C64XX generic DMA support using amba-pl08x driver. +// +// Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com> + +#include <linux/kernel.h> +#include <linux/amba/bus.h> +#include <linux/amba/pl080.h> +#include <linux/amba/pl08x.h> +#include <linux/of.h> + +#include "cpu.h" +#include "irqs.h" +#include "map.h" + +#include "regs-sys-s3c64xx.h" + +static int pl08x_get_xfer_signal(const struct pl08x_channel_data *cd) +{ + return cd->min_signal; +} + +static void pl08x_put_xfer_signal(const struct pl08x_channel_data *cd, int ch) +{ +} + +/* + * DMA0 + */ + +static struct pl08x_channel_data s3c64xx_dma0_info[] = { + { + .bus_id = "uart0_tx", + .min_signal = 0, + .max_signal = 0, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart0_rx", + .min_signal = 1, + .max_signal = 1, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart1_tx", + .min_signal = 2, + .max_signal = 2, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart1_rx", + .min_signal = 3, + .max_signal = 3, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart2_tx", + .min_signal = 4, + .max_signal = 4, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart2_rx", + .min_signal = 5, + .max_signal = 5, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart3_tx", + .min_signal = 6, + .max_signal = 6, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "uart3_rx", + .min_signal = 7, + .max_signal = 7, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pcm0_tx", + .min_signal = 8, + .max_signal = 8, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pcm0_rx", + .min_signal = 9, + .max_signal = 9, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s0_tx", + .min_signal = 10, + .max_signal = 10, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s0_rx", + .min_signal = 11, + .max_signal = 11, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi0_tx", + .min_signal = 12, + .max_signal = 12, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi0_rx", + .min_signal = 13, + .max_signal = 13, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s2_tx", + .min_signal = 14, + .max_signal = 14, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s2_rx", + .min_signal = 15, + .max_signal = 15, + .periph_buses = PL08X_AHB2, + } +}; + +static const struct dma_slave_map s3c64xx_dma0_slave_map[] = { + { "s3c6400-uart.0", "tx", &s3c64xx_dma0_info[0] }, + { "s3c6400-uart.0", "rx", &s3c64xx_dma0_info[1] }, + { "s3c6400-uart.1", "tx", &s3c64xx_dma0_info[2] }, + { "s3c6400-uart.1", "rx", &s3c64xx_dma0_info[3] }, + { "s3c6400-uart.2", "tx", &s3c64xx_dma0_info[4] }, + { "s3c6400-uart.2", "rx", &s3c64xx_dma0_info[5] }, + { "s3c6400-uart.3", "tx", &s3c64xx_dma0_info[6] }, + { "s3c6400-uart.3", "rx", &s3c64xx_dma0_info[7] }, + { "samsung-pcm.0", "tx", &s3c64xx_dma0_info[8] }, + { "samsung-pcm.0", "rx", &s3c64xx_dma0_info[9] }, + { "samsung-i2s.0", "tx", &s3c64xx_dma0_info[10] }, + { "samsung-i2s.0", "rx", &s3c64xx_dma0_info[11] }, + { "s3c6410-spi.0", "tx", &s3c64xx_dma0_info[12] }, + { "s3c6410-spi.0", "rx", &s3c64xx_dma0_info[13] }, + { "samsung-i2s.2", "tx", &s3c64xx_dma0_info[14] }, + { "samsung-i2s.2", "rx", &s3c64xx_dma0_info[15] }, +}; + +struct pl08x_platform_data s3c64xx_dma0_plat_data = { + .memcpy_burst_size = PL08X_BURST_SZ_4, + .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS, + .memcpy_prot_buff = true, + .memcpy_prot_cache = true, + .lli_buses = PL08X_AHB1, + .mem_buses = PL08X_AHB1, + .get_xfer_signal = pl08x_get_xfer_signal, + .put_xfer_signal = pl08x_put_xfer_signal, + .slave_channels = s3c64xx_dma0_info, + .num_slave_channels = ARRAY_SIZE(s3c64xx_dma0_info), + .slave_map = s3c64xx_dma0_slave_map, + .slave_map_len = ARRAY_SIZE(s3c64xx_dma0_slave_map), +}; + +static AMBA_AHB_DEVICE(s3c64xx_dma0, "dma-pl080s.0", 0, + 0x75000000, {IRQ_DMA0}, &s3c64xx_dma0_plat_data); + +/* + * DMA1 + */ + +static struct pl08x_channel_data s3c64xx_dma1_info[] = { + { + .bus_id = "pcm1_tx", + .min_signal = 0, + .max_signal = 0, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pcm1_rx", + .min_signal = 1, + .max_signal = 1, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s1_tx", + .min_signal = 2, + .max_signal = 2, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "i2s1_rx", + .min_signal = 3, + .max_signal = 3, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi1_tx", + .min_signal = 4, + .max_signal = 4, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "spi1_rx", + .min_signal = 5, + .max_signal = 5, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "ac97_out", + .min_signal = 6, + .max_signal = 6, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "ac97_in", + .min_signal = 7, + .max_signal = 7, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "ac97_mic", + .min_signal = 8, + .max_signal = 8, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "pwm", + .min_signal = 9, + .max_signal = 9, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "irda", + .min_signal = 10, + .max_signal = 10, + .periph_buses = PL08X_AHB2, + }, { + .bus_id = "external", + .min_signal = 11, + .max_signal = 11, + .periph_buses = PL08X_AHB2, + }, +}; + +static const struct dma_slave_map s3c64xx_dma1_slave_map[] = { + { "samsung-pcm.1", "tx", &s3c64xx_dma1_info[0] }, + { "samsung-pcm.1", "rx", &s3c64xx_dma1_info[1] }, + { "samsung-i2s.1", "tx", &s3c64xx_dma1_info[2] }, + { "samsung-i2s.1", "rx", &s3c64xx_dma1_info[3] }, + { "s3c6410-spi.1", "tx", &s3c64xx_dma1_info[4] }, + { "s3c6410-spi.1", "rx", &s3c64xx_dma1_info[5] }, +}; + +struct pl08x_platform_data s3c64xx_dma1_plat_data = { + .memcpy_burst_size = PL08X_BURST_SZ_4, + .memcpy_bus_width = PL08X_BUS_WIDTH_32_BITS, + .memcpy_prot_buff = true, + .memcpy_prot_cache = true, + .lli_buses = PL08X_AHB1, + .mem_buses = PL08X_AHB1, + .get_xfer_signal = pl08x_get_xfer_signal, + .put_xfer_signal = pl08x_put_xfer_signal, + .slave_channels = s3c64xx_dma1_info, + .num_slave_channels = ARRAY_SIZE(s3c64xx_dma1_info), + .slave_map = s3c64xx_dma1_slave_map, + .slave_map_len = ARRAY_SIZE(s3c64xx_dma1_slave_map), +}; + +static AMBA_AHB_DEVICE(s3c64xx_dma1, "dma-pl080s.1", 0, + 0x75100000, {IRQ_DMA1}, &s3c64xx_dma1_plat_data); + +static int __init s3c64xx_pl080_init(void) +{ + if (!soc_is_s3c64xx()) + return 0; + + /* Set all DMA configuration to be DMA, not SDMA */ + writel(0xffffff, S3C64XX_SDMA_SEL); + + if (of_have_populated_dt()) + return 0; + + amba_device_register(&s3c64xx_dma0_device, &iomem_resource); + amba_device_register(&s3c64xx_dma1_device, &iomem_resource); + + return 0; +} +arch_initcall(s3c64xx_pl080_init); diff --git a/arch/arm/mach-s3c/platformdata.c b/arch/arm/mach-s3c/platformdata.c new file mode 100644 index 000000000..e643c81ae --- /dev/null +++ b/arch/arm/mach-s3c/platformdata.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2010 Ben Dooks <ben-linux <at> fluff.org> +// +// Helper for platform data setting + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/platform_device.h> + +#include "devs.h" +#include "sdhci.h" + +void __init *s3c_set_platdata(void *pd, size_t pdsize, + struct platform_device *pdev) +{ + void *npd; + + if (!pd) { + /* too early to use dev_name(), may not be registered */ + printk(KERN_ERR "%s: no platform data supplied\n", pdev->name); + return NULL; + } + + npd = kmemdup(pd, pdsize, GFP_KERNEL); + if (!npd) + return NULL; + + pdev->dev.platform_data = npd; + return npd; +} + +void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd, + struct s3c_sdhci_platdata *set) +{ + set->cd_type = pd->cd_type; + set->ext_cd_init = pd->ext_cd_init; + set->ext_cd_cleanup = pd->ext_cd_cleanup; + set->ext_cd_gpio = pd->ext_cd_gpio; + set->ext_cd_gpio_invert = pd->ext_cd_gpio_invert; + + if (pd->max_width) + set->max_width = pd->max_width; + if (pd->cfg_gpio) + set->cfg_gpio = pd->cfg_gpio; + if (pd->host_caps) + set->host_caps |= pd->host_caps; + if (pd->host_caps2) + set->host_caps2 |= pd->host_caps2; + if (pd->pm_caps) + set->pm_caps |= pd->pm_caps; +} diff --git a/arch/arm/mach-s3c/pll-s3c2410.c b/arch/arm/mach-s3c/pll-s3c2410.c new file mode 100644 index 000000000..3fbc99eaa --- /dev/null +++ b/arch/arm/mach-s3c/pll-s3c2410.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// 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 + +#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 <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> + +/* This array should be sorted in ascending order of the frequencies */ +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 = 48000000, .driver_data = PLLVAL(120, 2, 3), }, + { .frequency = 51000000, .driver_data = PLLVAL(161, 3, 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-s3c/pll-s3c2440-12000000.c b/arch/arm/mach-s3c/pll-s3c2440-12000000.c new file mode 100644 index 000000000..fdb8e8c2f --- /dev/null +++ b/arch/arm/mach-s3c/pll-s3c2440-12000000.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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) + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> + +/* This array should be sorted in ascending order of the frequencies */ +static struct cpufreq_frequency_table s3c2440_plls_12[] = { + { .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-s3c/pll-s3c2440-16934400.c b/arch/arm/mach-s3c/pll-s3c2440-16934400.c new file mode 100644 index 000000000..438b6fc09 --- /dev/null +++ b/arch/arm/mach-s3c/pll-s3c2440-16934400.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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) + +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/err.h> + +#include <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> + +/* This array should be sorted in ascending order of the frequencies */ +static struct cpufreq_frequency_table s3c2440_plls_169344[] = { + { .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-s3c/pm-common.c b/arch/arm/mach-s3c/pm-common.c new file mode 100644 index 000000000..618bd4499 --- /dev/null +++ b/arch/arm/mach-s3c/pm-common.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2013 Samsung Electronics Co., Ltd. +// Tomasz Figa <t.figa@samsung.com> +// Copyright (C) 2008 Openmoko, Inc. +// Copyright (C) 2004-2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Samsung common power management helper functions. + +#include <linux/io.h> +#include <linux/kernel.h> + +#include "pm-common.h" + +/* helper functions to save and restore register state */ + +/** + * s3c_pm_do_save() - save a set of registers for restoration on resume. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Run through the list of registers given, saving their contents in the + * array for later restoration when we wakeup. + */ +void s3c_pm_do_save(struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + ptr->val = readl_relaxed(ptr->reg); + S3C_PMDBG("saved %p value %08lx\n", ptr->reg, ptr->val); + } +} + +/** + * s3c_pm_do_restore() - restore register values from the save list. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * Restore the register values saved from s3c_pm_do_save(). + * + * Note, we do not use S3C_PMDBG() in here, as the system may not have + * restore the UARTs state yet +*/ + +void s3c_pm_do_restore(const struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) { + pr_debug("restore %p (restore %08lx, was %08x)\n", + ptr->reg, ptr->val, readl_relaxed(ptr->reg)); + + writel_relaxed(ptr->val, ptr->reg); + } +} + +/** + * s3c_pm_do_restore_core() - early restore register values from save list. + * @ptr: Pointer to an array of registers. + * @count: Size of the ptr array. + * + * This is similar to s3c_pm_do_restore() except we try and minimise the + * side effects of the function in case registers that hardware might need + * to work has been restored. + * + * WARNING: Do not put any debug in here that may effect memory or use + * peripherals, as things may be changing! +*/ + +void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count) +{ + for (; count > 0; count--, ptr++) + writel_relaxed(ptr->val, ptr->reg); +} diff --git a/arch/arm/mach-s3c/pm-common.h b/arch/arm/mach-s3c/pm-common.h new file mode 100644 index 000000000..18b9607e1 --- /dev/null +++ b/arch/arm/mach-s3c/pm-common.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2013 Samsung Electronics Co., Ltd. + * Tomasz Figa <t.figa@samsung.com> + * Copyright (c) 2004 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Written by Ben Dooks, <ben@simtec.co.uk> + */ + +#ifndef __PLAT_SAMSUNG_PM_COMMON_H +#define __PLAT_SAMSUNG_PM_COMMON_H __FILE__ + +#include <linux/irq.h> +#include <linux/soc/samsung/s3c-pm.h> + +/* sleep save info */ + +/** + * struct sleep_save - save information for shared peripherals. + * @reg: Pointer to the register to save. + * @val: Holder for the value saved from reg. + * + * This describes a list of registers which is used by the pm core and + * other subsystem to save and restore register values over suspend. + */ +struct sleep_save { + void __iomem *reg; + unsigned long val; +}; + +#define SAVE_ITEM(x) \ + { .reg = (x) } + +/* helper functions to save/restore lists of registers. */ + +extern void s3c_pm_do_save(struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore(const struct sleep_save *ptr, int count); +extern void s3c_pm_do_restore_core(const struct sleep_save *ptr, int count); + +#endif diff --git a/arch/arm/mach-s3c/pm-core-s3c24xx.h b/arch/arm/mach-s3c/pm-core-s3c24xx.h new file mode 100644 index 000000000..a71ed5711 --- /dev/null +++ b/arch/arm/mach-s3c/pm-core-s3c24xx.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 + */ + +#include <linux/delay.h> +#include <linux/io.h> + +#include "regs-clock.h" +#include "regs-irq-s3c24xx.h" +#include "irqs.h" + +static inline void s3c_pm_debug_init_uart(void) +{ +#ifdef CONFIG_SAMSUNG_PM_DEBUG + 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); +#endif +} + +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 */ +} + +/* s3c2410_pm_show_resume_irqs + * + * print any IRQs asserted at resume time (ie, we woke from) +*/ +static inline void s3c_pm_show_resume_irqs(int start, unsigned long which, + unsigned long mask) +{ + int i; + + which &= ~mask; + + for (i = 0; i <= 31; i++) { + if (which & (1L<<i)) { + S3C_PMDBG("IRQ %d asserted at resume\n", start+i); + } + } +} + +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_restored_gpios(void) { } +static inline void samsung_pm_saved_gpios(void) { } + +/* 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 +*/ +#ifdef CONFIG_PM_SLEEP +#define s3c_irqwake_intallow (1L << 30 | 0xfL) +#define s3c_irqwake_eintallow (0x0000fff0L) +#else +#define s3c_irqwake_eintallow 0 +#define s3c_irqwake_intallow 0 +#endif diff --git a/arch/arm/mach-s3c/pm-core-s3c64xx.h b/arch/arm/mach-s3c/pm-core-s3c64xx.h new file mode 100644 index 000000000..06f564e5c --- /dev/null +++ b/arch/arm/mach-s3c/pm-core-s3c64xx.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - PM core support for arch/arm/plat-s3c/pm.c + */ + +#ifndef __MACH_S3C64XX_PM_CORE_H +#define __MACH_S3C64XX_PM_CORE_H __FILE__ + +#include <linux/serial_s3c.h> +#include <linux/delay.h> + +#include "regs-gpio.h" +#include "regs-clock.h" +#include "map.h" + +static inline void s3c_pm_debug_init_uart(void) +{ +#ifdef CONFIG_SAMSUNG_PM_DEBUG + u32 tmp = __raw_readl(S3C_PCLK_GATE); + + /* As a note, since the S3C64XX UARTs generally have multiple + * clock sources, we simply enable PCLK at the moment and hope + * that the resume settings for the UART are suitable for the + * use with PCLK. + */ + + tmp |= S3C_CLKCON_PCLK_UART0; + tmp |= S3C_CLKCON_PCLK_UART1; + tmp |= S3C_CLKCON_PCLK_UART2; + tmp |= S3C_CLKCON_PCLK_UART3; + + __raw_writel(tmp, S3C_PCLK_GATE); + udelay(10); +#endif +} + +static inline void s3c_pm_arch_prepare_irqs(void) +{ + /* VIC should have already been taken care of */ + + /* clear any pending EINT0 interrupts */ + __raw_writel(__raw_readl(S3C64XX_EINT0PEND), S3C64XX_EINT0PEND); +} + +static inline void s3c_pm_arch_stop_clocks(void) +{ +} + +static inline void s3c_pm_arch_show_resume_irqs(void) +{ +} + +/* make these defines, we currently do not have any need to change + * the IRQ wake controls depending on the CPU we are running on */ +#ifdef CONFIG_PM_SLEEP +#define s3c_irqwake_eintallow ((1 << 28) - 1) +#define s3c_irqwake_intallow (~0) +#else +#define s3c_irqwake_eintallow 0 +#define s3c_irqwake_intallow 0 +#endif + +static inline void s3c_pm_restored_gpios(void) +{ + /* ensure sleep mode has been cleared from the system */ + + __raw_writel(0, S3C64XX_SLPEN); +} + +static inline void samsung_pm_saved_gpios(void) +{ + /* turn on the sleep mode and keep it there, as it seems that during + * suspend the xCON registers get re-set and thus you can end up with + * problems between going to sleep and resuming. + */ + + __raw_writel(S3C64XX_SLPEN_USE_xSLP, S3C64XX_SLPEN); +} +#endif /* __MACH_S3C64XX_PM_CORE_H */ diff --git a/arch/arm/mach-s3c/pm-core.h b/arch/arm/mach-s3c/pm-core.h new file mode 100644 index 000000000..b0e1d277f --- /dev/null +++ b/arch/arm/mach-s3c/pm-core.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "pm-core-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "pm-core-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/pm-gpio.c b/arch/arm/mach-s3c/pm-gpio.c new file mode 100644 index 000000000..cfdbc2337 --- /dev/null +++ b/arch/arm/mach-s3c/pm-gpio.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C series GPIO PM code + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include "gpio-samsung.h" + +#include "gpio-core.h" +#include "pm.h" + +/* PM GPIO helpers */ + +#define OFFS_CON (0x00) +#define OFFS_DAT (0x04) +#define OFFS_UP (0x08) + +static void samsung_gpio_pm_1bit_save(struct samsung_gpio_chip *chip) +{ + chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); +} + +static void samsung_gpio_pm_1bit_resume(struct samsung_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon = __raw_readl(base + OFFS_CON); + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpcon = chip->pm_save[0]; + u32 gps_gpdat = chip->pm_save[1]; + u32 gpcon; + + /* GPACON only has one bit per control / data and no PULLUPs. + * GPACON[x] = 0 => Output, 1 => SFN */ + + /* first set all SFN bits to SFN */ + + gpcon = old_gpcon | gps_gpcon; + __raw_writel(gpcon, base + OFFS_CON); + + /* now set all the other bits */ + + __raw_writel(gps_gpdat, base + OFFS_DAT); + __raw_writel(gps_gpcon, base + OFFS_CON); + + S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); +} + +struct samsung_gpio_pm samsung_gpio_pm_1bit = { + .save = samsung_gpio_pm_1bit_save, + .resume = samsung_gpio_pm_1bit_resume, +}; + +static void samsung_gpio_pm_2bit_save(struct samsung_gpio_chip *chip) +{ + chip->pm_save[0] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[1] = __raw_readl(chip->base + OFFS_DAT); + chip->pm_save[2] = __raw_readl(chip->base + OFFS_UP); +} + +/* Test whether the given masked+shifted bits of an GPIO configuration + * are one of the SFN (special function) modes. */ + +static inline int is_sfn(unsigned long con) +{ + return con >= 2; +} + +/* Test if the given masked+shifted GPIO configuration is an input */ + +static inline int is_in(unsigned long con) +{ + return con == 0; +} + +/* Test if the given masked+shifted GPIO configuration is an output */ + +static inline int is_out(unsigned long con) +{ + return con == 1; +} + +/** + * samsung_gpio_pm_2bit_resume() - restore the given GPIO bank + * @chip: The chip information to resume. + * + * Restore one of the GPIO banks that was saved during suspend. This is + * not as simple as once thought, due to the possibility of glitches + * from the order that the CON and DAT registers are set in. + * + * The three states the pin can be are {IN,OUT,SFN} which gives us 9 + * combinations of changes to check. Three of these, if the pin stays + * in the same configuration can be discounted. This leaves us with + * the following: + * + * { IN => OUT } Change DAT first + * { IN => SFN } Change CON first + * { OUT => SFN } Change CON first, so new data will not glitch + * { OUT => IN } Change CON first, so new data will not glitch + * { SFN => IN } Change CON first + * { SFN => OUT } Change DAT first, so new data will not glitch [1] + * + * We do not currently deal with the UP registers as these control + * weak resistors, so a small delay in change should not need to bring + * these into the calculations. + * + * [1] this assumes that writing to a pin DAT whilst in SFN will set the + * state for when it is next output. + */ +static void samsung_gpio_pm_2bit_resume(struct samsung_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon = __raw_readl(base + OFFS_CON); + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpcon = chip->pm_save[0]; + u32 gps_gpdat = chip->pm_save[1]; + u32 gpcon, old, new, mask; + u32 change_mask = 0x0; + int nr; + + /* restore GPIO pull-up settings */ + __raw_writel(chip->pm_save[2], base + OFFS_UP); + + /* Create a change_mask of all the items that need to have + * their CON value changed before their DAT value, so that + * we minimise the work between the two settings. + */ + + for (nr = 0, mask = 0x03; nr < 32; nr += 2, mask <<= 2) { + old = (old_gpcon & mask) >> nr; + new = (gps_gpcon & mask) >> nr; + + /* If there is no change, then skip */ + + if (old == new) + continue; + + /* If both are special function, then skip */ + + if (is_sfn(old) && is_sfn(new)) + continue; + + /* Change is IN => OUT, do not change now */ + + if (is_in(old) && is_out(new)) + continue; + + /* Change is SFN => OUT, do not change now */ + + if (is_sfn(old) && is_out(new)) + continue; + + /* We should now be at the case of IN=>SFN, + * OUT=>SFN, OUT=>IN, SFN=>IN. */ + + change_mask |= mask; + } + + + /* Write the new CON settings */ + + gpcon = old_gpcon & ~change_mask; + gpcon |= gps_gpcon & change_mask; + + __raw_writel(gpcon, base + OFFS_CON); + + /* Now change any items that require DAT,CON */ + + __raw_writel(gps_gpdat, base + OFFS_DAT); + __raw_writel(gps_gpcon, base + OFFS_CON); + + S3C_PMDBG("%s: CON %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon, gps_gpcon, old_gpdat, gps_gpdat); +} + +struct samsung_gpio_pm samsung_gpio_pm_2bit = { + .save = samsung_gpio_pm_2bit_save, + .resume = samsung_gpio_pm_2bit_resume, +}; + +#if defined(CONFIG_ARCH_S3C64XX) +static void samsung_gpio_pm_4bit_save(struct samsung_gpio_chip *chip) +{ + chip->pm_save[1] = __raw_readl(chip->base + OFFS_CON); + chip->pm_save[2] = __raw_readl(chip->base + OFFS_DAT); + chip->pm_save[3] = __raw_readl(chip->base + OFFS_UP); + + if (chip->chip.ngpio > 8) + chip->pm_save[0] = __raw_readl(chip->base - 4); +} + +static u32 samsung_gpio_pm_4bit_mask(u32 old_gpcon, u32 gps_gpcon) +{ + u32 old, new, mask; + u32 change_mask = 0x0; + int nr; + + for (nr = 0, mask = 0x0f; nr < 16; nr += 4, mask <<= 4) { + old = (old_gpcon & mask) >> nr; + new = (gps_gpcon & mask) >> nr; + + /* If there is no change, then skip */ + + if (old == new) + continue; + + /* If both are special function, then skip */ + + if (is_sfn(old) && is_sfn(new)) + continue; + + /* Change is IN => OUT, do not change now */ + + if (is_in(old) && is_out(new)) + continue; + + /* Change is SFN => OUT, do not change now */ + + if (is_sfn(old) && is_out(new)) + continue; + + /* We should now be at the case of IN=>SFN, + * OUT=>SFN, OUT=>IN, SFN=>IN. */ + + change_mask |= mask; + } + + return change_mask; +} + +static void samsung_gpio_pm_4bit_con(struct samsung_gpio_chip *chip, int index) +{ + void __iomem *con = chip->base + (index * 4); + u32 old_gpcon = __raw_readl(con); + u32 gps_gpcon = chip->pm_save[index + 1]; + u32 gpcon, mask; + + mask = samsung_gpio_pm_4bit_mask(old_gpcon, gps_gpcon); + + gpcon = old_gpcon & ~mask; + gpcon |= gps_gpcon & mask; + + __raw_writel(gpcon, con); +} + +static void samsung_gpio_pm_4bit_resume(struct samsung_gpio_chip *chip) +{ + void __iomem *base = chip->base; + u32 old_gpcon[2]; + u32 old_gpdat = __raw_readl(base + OFFS_DAT); + u32 gps_gpdat = chip->pm_save[2]; + + /* First, modify the CON settings */ + + old_gpcon[0] = 0; + old_gpcon[1] = __raw_readl(base + OFFS_CON); + + samsung_gpio_pm_4bit_con(chip, 0); + if (chip->chip.ngpio > 8) { + old_gpcon[0] = __raw_readl(base - 4); + samsung_gpio_pm_4bit_con(chip, -1); + } + + /* Now change the configurations that require DAT,CON */ + + __raw_writel(chip->pm_save[2], base + OFFS_DAT); + __raw_writel(chip->pm_save[1], base + OFFS_CON); + if (chip->chip.ngpio > 8) + __raw_writel(chip->pm_save[0], base - 4); + + __raw_writel(chip->pm_save[2], base + OFFS_DAT); + __raw_writel(chip->pm_save[3], base + OFFS_UP); + + if (chip->chip.ngpio > 8) { + S3C_PMDBG("%s: CON4 %08x,%08x => %08x,%08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon[0], old_gpcon[1], + __raw_readl(base - 4), + __raw_readl(base + OFFS_CON), + old_gpdat, gps_gpdat); + } else + S3C_PMDBG("%s: CON4 %08x => %08x, DAT %08x => %08x\n", + chip->chip.label, old_gpcon[1], + __raw_readl(base + OFFS_CON), + old_gpdat, gps_gpdat); +} + +struct samsung_gpio_pm samsung_gpio_pm_4bit = { + .save = samsung_gpio_pm_4bit_save, + .resume = samsung_gpio_pm_4bit_resume, +}; +#endif /* CONFIG_ARCH_S3C64XX */ + +/** + * samsung_pm_save_gpio() - save gpio chip data for suspend + * @ourchip: The chip for suspend. + */ +static void samsung_pm_save_gpio(struct samsung_gpio_chip *ourchip) +{ + struct samsung_gpio_pm *pm = ourchip->pm; + + if (pm == NULL || pm->save == NULL) + S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); + else + pm->save(ourchip); +} + +/** + * samsung_pm_save_gpios() - Save the state of the GPIO banks. + * + * For all the GPIO banks, save the state of each one ready for going + * into a suspend mode. + */ +void samsung_pm_save_gpios(void) +{ + struct samsung_gpio_chip *ourchip; + unsigned int gpio_nr; + + for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) { + ourchip = samsung_gpiolib_getchip(gpio_nr); + if (!ourchip) { + gpio_nr++; + continue; + } + + samsung_pm_save_gpio(ourchip); + + S3C_PMDBG("%s: save %08x,%08x,%08x,%08x\n", + ourchip->chip.label, + ourchip->pm_save[0], + ourchip->pm_save[1], + ourchip->pm_save[2], + ourchip->pm_save[3]); + + gpio_nr += ourchip->chip.ngpio; + gpio_nr += CONFIG_S3C_GPIO_SPACE; + } +} + +/** + * samsung_pm_resume_gpio() - restore gpio chip data after suspend + * @ourchip: The suspended chip. + */ +static void samsung_pm_resume_gpio(struct samsung_gpio_chip *ourchip) +{ + struct samsung_gpio_pm *pm = ourchip->pm; + + if (pm == NULL || pm->resume == NULL) + S3C_PMDBG("%s: no pm for %s\n", __func__, ourchip->chip.label); + else + pm->resume(ourchip); +} + +void samsung_pm_restore_gpios(void) +{ + struct samsung_gpio_chip *ourchip; + unsigned int gpio_nr; + + for (gpio_nr = 0; gpio_nr < S3C_GPIO_END;) { + ourchip = samsung_gpiolib_getchip(gpio_nr); + if (!ourchip) { + gpio_nr++; + continue; + } + + samsung_pm_resume_gpio(ourchip); + + gpio_nr += ourchip->chip.ngpio; + gpio_nr += CONFIG_S3C_GPIO_SPACE; + } +} diff --git a/arch/arm/mach-s3c/pm-h1940.S b/arch/arm/mach-s3c/pm-h1940.S new file mode 100644 index 000000000..3bf668512 --- /dev/null +++ b/arch/arm/mach-s3c/pm-h1940.S @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2006 Ben Dooks <ben-linux@fluff.org> + * + * H1940 Suspend to RAM + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include "map.h" + +#include "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-s3c/pm-s3c2410.c b/arch/arm/mach-s3c/pm-s3c2410.c new file mode 100644 index 000000000..a66419883 --- /dev/null +++ b/arch/arm/mach-s3c/pm-s3c2410.c @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2006 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support + +#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 "regs-gpio.h" +#include "gpio-samsung.h" + +#include "gpio-cfg.h" +#include "cpu.h" +#include "pm.h" + +#include "h1940.h" + +static void s3c2410_pm_prepare(void) +{ + /* ensure at least GSTATUS3 has the resume address */ + + __raw_writel(__pa_symbol(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-s3c/pm-s3c2412.c b/arch/arm/mach-s3c/pm-s3c2412.c new file mode 100644 index 000000000..ed3b4cfc7 --- /dev/null +++ b/arch/arm/mach-s3c/pm-s3c2412.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2006 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://armlinux.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/syscore_ops.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/irq.h> + +#include "irqs.h" +#include "regs-gpio.h" + +#include "cpu.h" +#include "pm.h" +#include "wakeup-mask.h" + +#include "regs-dsc-s3c24xx.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 const 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-s3c/pm-s3c2416.c b/arch/arm/mach-s3c/pm-s3c2416.c new file mode 100644 index 000000000..f69ad84cf --- /dev/null +++ b/arch/arm/mach-s3c/pm-s3c2416.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2010 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// S3C2416 - PM support (Based on Ben Dooks' S3C2412 PM support) + +#include <linux/device.h> +#include <linux/syscore_ops.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> + +#include "regs-s3c2443-clock.h" + +#include "cpu.h" +#include "pm.h" + +#include "s3c2412-power.h" + +#ifdef CONFIG_PM_SLEEP +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(__pa_symbol(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); +#endif + +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-s3c/pm-s3c24xx.c b/arch/arm/mach-s3c/pm-s3c24xx.c new file mode 100644 index 000000000..3a8f5c388 --- /dev/null +++ b/arch/arm/mach-s3c/pm-s3c24xx.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// 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.rst for more information +// +// 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 "regs-clock.h" +#include "regs-gpio.h" +#include "regs-irq.h" +#include "gpio-samsung.h" + +#include <asm/mach/time.h> + +#include "gpio-cfg.h" +#include "pm.h" + +#include "regs-mem-s3c24xx.h" + +#define PFX "s3c24xx-pm: " + +#ifdef CONFIG_PM_SLEEP +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), +}; +#endif + +/* 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); + } +} + +#ifdef CONFIG_PM_SLEEP +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)); +} +#endif diff --git a/arch/arm/mach-s3c/pm-s3c64xx.c b/arch/arm/mach-s3c/pm-s3c64xx.c new file mode 100644 index 000000000..7bc7417fd --- /dev/null +++ b/arch/arm/mach-s3c/pm-s3c64xx.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C64XX CPU PM support. + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/serial_core.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/pm_domain.h> + +#include "map.h" +#include "irqs.h" + +#include "cpu.h" +#include "devs.h" +#include "pm.h" +#include "wakeup-mask.h" + +#include "regs-gpio.h" +#include "regs-clock.h" +#include "gpio-samsung.h" + +#include "regs-gpio-memport-s3c64xx.h" +#include "regs-modem-s3c64xx.h" +#include "regs-sys-s3c64xx.h" +#include "regs-syscon-power-s3c64xx.h" + +struct s3c64xx_pm_domain { + char *const name; + u32 ena; + u32 pwr_stat; + struct generic_pm_domain pd; +}; + +static int s3c64xx_pd_off(struct generic_pm_domain *domain) +{ + struct s3c64xx_pm_domain *pd; + u32 val; + + pd = container_of(domain, struct s3c64xx_pm_domain, pd); + + val = __raw_readl(S3C64XX_NORMAL_CFG); + val &= ~(pd->ena); + __raw_writel(val, S3C64XX_NORMAL_CFG); + + return 0; +} + +static int s3c64xx_pd_on(struct generic_pm_domain *domain) +{ + struct s3c64xx_pm_domain *pd; + u32 val; + long retry = 1000000L; + + pd = container_of(domain, struct s3c64xx_pm_domain, pd); + + val = __raw_readl(S3C64XX_NORMAL_CFG); + val |= pd->ena; + __raw_writel(val, S3C64XX_NORMAL_CFG); + + /* Not all domains provide power status readback */ + if (pd->pwr_stat) { + do { + cpu_relax(); + if (__raw_readl(S3C64XX_BLK_PWR_STAT) & pd->pwr_stat) + break; + } while (retry--); + + if (!retry) { + pr_err("Failed to start domain %s\n", pd->name); + return -EBUSY; + } + } + + return 0; +} + +static struct s3c64xx_pm_domain s3c64xx_pm_irom = { + .name = "IROM", + .ena = S3C64XX_NORMALCFG_IROM_ON, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_etm = { + .name = "ETM", + .ena = S3C64XX_NORMALCFG_DOMAIN_ETM_ON, + .pwr_stat = S3C64XX_BLKPWRSTAT_ETM, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_s = { + .name = "S", + .ena = S3C64XX_NORMALCFG_DOMAIN_S_ON, + .pwr_stat = S3C64XX_BLKPWRSTAT_S, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_f = { + .name = "F", + .ena = S3C64XX_NORMALCFG_DOMAIN_F_ON, + .pwr_stat = S3C64XX_BLKPWRSTAT_F, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_p = { + .name = "P", + .ena = S3C64XX_NORMALCFG_DOMAIN_P_ON, + .pwr_stat = S3C64XX_BLKPWRSTAT_P, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_i = { + .name = "I", + .ena = S3C64XX_NORMALCFG_DOMAIN_I_ON, + .pwr_stat = S3C64XX_BLKPWRSTAT_I, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_g = { + .name = "G", + .ena = S3C64XX_NORMALCFG_DOMAIN_G_ON, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain s3c64xx_pm_v = { + .name = "V", + .ena = S3C64XX_NORMALCFG_DOMAIN_V_ON, + .pwr_stat = S3C64XX_BLKPWRSTAT_V, + .pd = { + .power_off = s3c64xx_pd_off, + .power_on = s3c64xx_pd_on, + }, +}; + +static struct s3c64xx_pm_domain *s3c64xx_always_on_pm_domains[] = { + &s3c64xx_pm_irom, +}; + +static struct s3c64xx_pm_domain *s3c64xx_pm_domains[] = { + &s3c64xx_pm_etm, + &s3c64xx_pm_g, + &s3c64xx_pm_v, + &s3c64xx_pm_i, + &s3c64xx_pm_p, + &s3c64xx_pm_s, + &s3c64xx_pm_f, +}; + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK +void s3c_pm_debug_smdkled(u32 set, u32 clear) +{ + unsigned long flags; + int i; + + local_irq_save(flags); + for (i = 0; i < 4; i++) { + if (clear & (1 << i)) + gpio_set_value(S3C64XX_GPN(12 + i), 0); + if (set & (1 << i)) + gpio_set_value(S3C64XX_GPN(12 + i), 1); + } + local_irq_restore(flags); +} +#endif + +#ifdef CONFIG_PM_SLEEP +static struct sleep_save core_save[] = { + SAVE_ITEM(S3C64XX_MEM0DRVCON), + SAVE_ITEM(S3C64XX_MEM1DRVCON), +}; + +static struct sleep_save misc_save[] = { + SAVE_ITEM(S3C64XX_AHB_CON0), + SAVE_ITEM(S3C64XX_AHB_CON1), + SAVE_ITEM(S3C64XX_AHB_CON2), + + SAVE_ITEM(S3C64XX_SPCON), + + SAVE_ITEM(S3C64XX_MEM0CONSTOP), + SAVE_ITEM(S3C64XX_MEM1CONSTOP), + SAVE_ITEM(S3C64XX_MEM0CONSLP0), + SAVE_ITEM(S3C64XX_MEM0CONSLP1), + SAVE_ITEM(S3C64XX_MEM1CONSLP), + + SAVE_ITEM(S3C64XX_SDMA_SEL), + SAVE_ITEM(S3C64XX_MODEM_MIFPCON), + + SAVE_ITEM(S3C64XX_NORMAL_CFG), +}; + +void s3c_pm_configure_extint(void) +{ + __raw_writel(s3c_irqwake_eintmask, S3C64XX_EINT_MASK); +} + +void s3c_pm_restore_core(void) +{ + __raw_writel(0, S3C64XX_EINT_MASK); + + s3c_pm_debug_smdkled(1 << 2, 0); + + s3c_pm_do_restore_core(core_save, ARRAY_SIZE(core_save)); + s3c_pm_do_restore(misc_save, ARRAY_SIZE(misc_save)); +} + +void s3c_pm_save_core(void) +{ + s3c_pm_do_save(misc_save, ARRAY_SIZE(misc_save)); + s3c_pm_do_save(core_save, ARRAY_SIZE(core_save)); +} +#endif + +/* since both s3c6400 and s3c6410 share the same sleep pm calls, we + * put the per-cpu code in here until any new cpu comes along and changes + * this. + */ + +static int s3c64xx_cpu_suspend(unsigned long arg) +{ + unsigned long tmp; + + /* set our standby method to sleep */ + + tmp = __raw_readl(S3C64XX_PWR_CFG); + tmp &= ~S3C64XX_PWRCFG_CFG_WFI_MASK; + tmp |= S3C64XX_PWRCFG_CFG_WFI_SLEEP; + __raw_writel(tmp, S3C64XX_PWR_CFG); + + /* clear any old wakeup */ + + __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), + S3C64XX_WAKEUP_STAT); + + /* set the LED state to 0110 over sleep */ + s3c_pm_debug_smdkled(3 << 1, 0xf); + + /* issue the standby signal into the pm unit. Note, we + * issue a write-buffer drain just in case */ + + tmp = 0; + + asm("b 1f\n\t" + ".align 5\n\t" + "1:\n\t" + "mcr p15, 0, %0, c7, c10, 5\n\t" + "mcr p15, 0, %0, c7, c10, 4\n\t" + "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp)); + + /* we should never get past here */ + + pr_info("Failed to suspend the system\n"); + return 1; /* Aborting suspend */ +} + +/* mapping of interrupts to parts of the wakeup mask */ +static const struct samsung_wakeup_mask wake_irqs[] = { + { .irq = IRQ_RTC_ALARM, .bit = S3C64XX_PWRCFG_RTC_ALARM_DISABLE, }, + { .irq = IRQ_RTC_TIC, .bit = S3C64XX_PWRCFG_RTC_TICK_DISABLE, }, + { .irq = IRQ_PENDN, .bit = S3C64XX_PWRCFG_TS_DISABLE, }, + { .irq = IRQ_HSMMC0, .bit = S3C64XX_PWRCFG_MMC0_DISABLE, }, + { .irq = IRQ_HSMMC1, .bit = S3C64XX_PWRCFG_MMC1_DISABLE, }, + { .irq = IRQ_HSMMC2, .bit = S3C64XX_PWRCFG_MMC2_DISABLE, }, + { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_BATF_DISABLE}, + { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_MSM_DISABLE }, + { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_HSI_DISABLE }, + { .irq = NO_WAKEUP_IRQ, .bit = S3C64XX_PWRCFG_MSM_DISABLE }, +}; + +static void s3c64xx_pm_prepare(void) +{ + samsung_sync_wakemask(S3C64XX_PWR_CFG, + wake_irqs, ARRAY_SIZE(wake_irqs)); + + /* store address of resume. */ + __raw_writel(__pa_symbol(s3c_cpu_resume), S3C64XX_INFORM0); + + /* ensure previous wakeup state is cleared before sleeping */ + __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); +} + +#ifdef CONFIG_SAMSUNG_PM_DEBUG +void s3c_pm_arch_update_uart(void __iomem *regs, struct pm_uart_save *save) +{ + u32 ucon; + u32 ucon_clk + u32 save_clk; + u32 new_ucon; + u32 delta; + + if (!soc_is_s3c64xx()) + return; + + ucon = __raw_readl(regs + S3C2410_UCON); + ucon_clk = ucon & S3C6400_UCON_CLKMASK; + sav_clk = save->ucon & S3C6400_UCON_CLKMASK; + + /* S3C64XX UART blocks only support level interrupts, so ensure that + * when we restore unused UART blocks we force the level interrupt + * settings. */ + save->ucon |= S3C2410_UCON_TXILEVEL | S3C2410_UCON_RXILEVEL; + + /* We have a constraint on changing the clock type of the UART + * between UCLKx and PCLK, so ensure that when we restore UCON + * that the CLK field is correctly modified if the bootloader + * has changed anything. + */ + if (ucon_clk != save_clk) { + new_ucon = save->ucon; + delta = ucon_clk ^ save_clk; + + /* change from UCLKx => wrong PCLK, + * either UCLK can be tested for by a bit-test + * with UCLK0 */ + if (ucon_clk & S3C6400_UCON_UCLK0 && + !(save_clk & S3C6400_UCON_UCLK0) && + delta & S3C6400_UCON_PCLK2) { + new_ucon &= ~S3C6400_UCON_UCLK0; + } else if (delta == S3C6400_UCON_PCLK2) { + /* as an precaution, don't change from + * PCLK2 => PCLK or vice-versa */ + new_ucon ^= S3C6400_UCON_PCLK2; + } + + S3C_PMDBG("ucon change %04x => %04x (save=%04x)\n", + ucon, new_ucon, save->ucon); + save->ucon = new_ucon; + } +} +#endif + +int __init s3c64xx_pm_init(void) +{ + int i; + + s3c_pm_init(); + + for (i = 0; i < ARRAY_SIZE(s3c64xx_always_on_pm_domains); i++) + pm_genpd_init(&s3c64xx_always_on_pm_domains[i]->pd, + &pm_domain_always_on_gov, false); + + for (i = 0; i < ARRAY_SIZE(s3c64xx_pm_domains); i++) + pm_genpd_init(&s3c64xx_pm_domains[i]->pd, NULL, false); + +#ifdef CONFIG_S3C_DEV_FB + if (dev_get_platdata(&s3c_device_fb.dev)) + pm_genpd_add_device(&s3c64xx_pm_f.pd, &s3c_device_fb.dev); +#endif + + return 0; +} + +static __init int s3c64xx_pm_initcall(void) +{ + if (!soc_is_s3c64xx()) + return 0; + + pm_cpu_prep = s3c64xx_pm_prepare; + pm_cpu_sleep = s3c64xx_cpu_suspend; + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK + gpio_request(S3C64XX_GPN(12), "DEBUG_LED0"); + gpio_request(S3C64XX_GPN(13), "DEBUG_LED1"); + gpio_request(S3C64XX_GPN(14), "DEBUG_LED2"); + gpio_request(S3C64XX_GPN(15), "DEBUG_LED3"); + gpio_direction_output(S3C64XX_GPN(12), 0); + gpio_direction_output(S3C64XX_GPN(13), 0); + gpio_direction_output(S3C64XX_GPN(14), 0); + gpio_direction_output(S3C64XX_GPN(15), 0); +#endif + + return 0; +} +arch_initcall(s3c64xx_pm_initcall); diff --git a/arch/arm/mach-s3c/pm.c b/arch/arm/mach-s3c/pm.c new file mode 100644 index 000000000..06f019690 --- /dev/null +++ b/arch/arm/mach-s3c/pm.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2004-2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C common power management (suspend to ram) support. + +#include <linux/init.h> +#include <linux/suspend.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/of.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <asm/cacheflush.h> +#include <asm/suspend.h> + +#include "map.h" +#include "regs-clock.h" +#include "regs-irq.h" +#include "irqs.h" + +#include <asm/irq.h> + +#include "cpu.h" +#include "pm.h" +#include "pm-core.h" + +/* for external use */ + +unsigned long s3c_pm_flags; + +/* The IRQ ext-int code goes here, it is too small to currently bother + * with its own file. */ + +unsigned long s3c_irqwake_intmask = 0xffffffffL; +unsigned long s3c_irqwake_eintmask = 0xffffffffL; + +int s3c_irqext_wake(struct irq_data *data, unsigned int state) +{ + unsigned long bit = 1L << IRQ_EINT_BIT(data->irq); + + if (!(s3c_irqwake_eintallow & bit)) + return -ENOENT; + + printk(KERN_INFO "wake %s for irq %d\n", + state ? "enabled" : "disabled", data->irq); + + if (!state) + s3c_irqwake_eintmask |= bit; + else + s3c_irqwake_eintmask &= ~bit; + + return 0; +} + +void (*pm_cpu_prep)(void); +int (*pm_cpu_sleep)(unsigned long); + +#define any_allowed(mask, allow) (((mask) & (allow)) != (allow)) + +/* s3c_pm_enter + * + * central control for sleep/resume process +*/ + +static int s3c_pm_enter(suspend_state_t state) +{ + int ret; + /* ensure the debug is initialised (if enabled) */ + s3c_pm_debug_init_uart(); + + S3C_PMDBG("%s(%d)\n", __func__, state); + + if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) { + printk(KERN_ERR "%s: error: no cpu sleep function\n", __func__); + return -EINVAL; + } + + /* check if we have anything to wake-up with... bad things seem + * to happen if you suspend with no wakeup (system will often + * require a full power-cycle) + */ + + if (!of_have_populated_dt() && + !any_allowed(s3c_irqwake_intmask, s3c_irqwake_intallow) && + !any_allowed(s3c_irqwake_eintmask, s3c_irqwake_eintallow)) { + printk(KERN_ERR "%s: No wake-up sources!\n", __func__); + printk(KERN_ERR "%s: Aborting sleep\n", __func__); + return -EINVAL; + } + + /* save all necessary core registers not covered by the drivers */ + + if (!of_have_populated_dt()) { + samsung_pm_save_gpios(); + samsung_pm_saved_gpios(); + } + + s3c_pm_save_uarts(soc_is_s3c2410()); + s3c_pm_save_core(); + + /* set the irq configuration for wake */ + + s3c_pm_configure_extint(); + + S3C_PMDBG("sleep: irq wakeup masks: %08lx,%08lx\n", + s3c_irqwake_intmask, s3c_irqwake_eintmask); + + s3c_pm_arch_prepare_irqs(); + + /* call cpu specific preparation */ + + pm_cpu_prep(); + + /* flush cache back to ram */ + + flush_cache_all(); + + s3c_pm_check_store(); + + /* send the cpu to sleep... */ + + s3c_pm_arch_stop_clocks(); + + /* this will also act as our return point from when + * we resume as it saves its own register state and restores it + * during the resume. */ + + ret = cpu_suspend(0, pm_cpu_sleep); + if (ret) + return ret; + + /* restore the system state */ + + s3c_pm_restore_core(); + s3c_pm_restore_uarts(soc_is_s3c2410()); + + if (!of_have_populated_dt()) { + samsung_pm_restore_gpios(); + s3c_pm_restored_gpios(); + } + + s3c_pm_debug_init_uart(); + + /* check what irq (if any) restored the system */ + + s3c_pm_arch_show_resume_irqs(); + + S3C_PMDBG("%s: post sleep, preparing to return\n", __func__); + + /* LEDs should now be 1110 */ + s3c_pm_debug_smdkled(1 << 1, 0); + + s3c_pm_check_restore(); + + /* ok, let's return from sleep */ + + S3C_PMDBG("S3C PM Resume (post-restore)\n"); + return 0; +} + +static int s3c_pm_prepare(void) +{ + /* prepare check area if configured */ + + s3c_pm_check_prepare(); + return 0; +} + +static void s3c_pm_finish(void) +{ + s3c_pm_check_cleanup(); +} + +static const struct platform_suspend_ops s3c_pm_ops = { + .enter = s3c_pm_enter, + .prepare = s3c_pm_prepare, + .finish = s3c_pm_finish, + .valid = suspend_valid_only_mem, +}; + +/* s3c_pm_init + * + * Attach the power management functions. This should be called + * from the board specific initialisation if the board supports + * it. +*/ + +int __init s3c_pm_init(void) +{ + printk("S3C Power Management, Copyright 2004 Simtec Electronics\n"); + + suspend_set_ops(&s3c_pm_ops); + return 0; +} diff --git a/arch/arm/mach-s3c/pm.h b/arch/arm/mach-s3c/pm.h new file mode 100644 index 000000000..eed61e585 --- /dev/null +++ b/arch/arm/mach-s3c/pm.h @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2004 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Written by Ben Dooks, <ben@simtec.co.uk> + */ + +/* s3c_pm_init + * + * called from board at initialisation time to setup the power + * management +*/ + +#include "pm-common.h" + +struct device; + +#ifdef CONFIG_SAMSUNG_PM + +extern __init int s3c_pm_init(void); +extern __init int s3c64xx_pm_init(void); + +#else + +static inline int s3c_pm_init(void) +{ + return 0; +} + +static inline int s3c64xx_pm_init(void) +{ + return 0; +} +#endif + +/* configuration for the IRQ mask over sleep */ +extern unsigned long s3c_irqwake_intmask; +extern unsigned long s3c_irqwake_eintmask; + +/* per-cpu sleep functions */ + +extern void (*pm_cpu_prep)(void); +extern int (*pm_cpu_sleep)(unsigned long); + +/* Flags for PM Control */ + +extern unsigned long s3c_pm_flags; + +/* from sleep.S */ + +extern int s3c2410_cpu_suspend(unsigned long); + +#ifdef CONFIG_PM_SLEEP +extern int s3c_irq_wake(struct irq_data *data, unsigned int state); +extern void s3c_cpu_resume(void); +#else +#define s3c_irq_wake NULL +#define s3c_cpu_resume NULL +#endif + +#ifdef CONFIG_SAMSUNG_PM +extern int s3c_irqext_wake(struct irq_data *data, unsigned int state); +#else +#define s3c_irqext_wake NULL +#endif + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK +/** + * s3c_pm_debug_smdkled() - Debug PM suspend/resume via SMDK Board LEDs + * @set: set bits for the state of the LEDs + * @clear: clear bits for the state of the LEDs. + */ +extern void s3c_pm_debug_smdkled(u32 set, u32 clear); + +#else +static inline void s3c_pm_debug_smdkled(u32 set, u32 clear) { } +#endif /* CONFIG_S3C_PM_DEBUG_LED_SMDK */ + +/** + * s3c_pm_configure_extint() - ensure pins are correctly set for IRQ + * + * Setup all the necessary GPIO pins for waking the system on external + * interrupt. + */ +extern void s3c_pm_configure_extint(void); + +#ifdef CONFIG_GPIO_SAMSUNG +/** + * samsung_pm_restore_gpios() - restore the state of the gpios after sleep. + * + * Restore the state of the GPIO pins after sleep, which may involve ensuring + * that we do not glitch the state of the pins from that the bootloader's + * resume code has done. +*/ +extern void samsung_pm_restore_gpios(void); + +/** + * samsung_pm_save_gpios() - save the state of the GPIOs for restoring after sleep. + * + * Save the GPIO states for resotration on resume. See samsung_pm_restore_gpios(). + */ +extern void samsung_pm_save_gpios(void); +#else +static inline void samsung_pm_restore_gpios(void) {} +static inline void samsung_pm_save_gpios(void) {} +#endif + +extern void s3c_pm_save_core(void); +extern void s3c_pm_restore_core(void); diff --git a/arch/arm/mach-s3c/pwm-core.h b/arch/arm/mach-s3c/pwm-core.h new file mode 100644 index 000000000..05e344864 --- /dev/null +++ b/arch/arm/mach-s3c/pwm-core.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2013 Tomasz Figa <tomasz.figa@gmail.com> + * + * Samsung PWM controller platform data helpers. + */ + +#ifndef __ASM_ARCH_PWM_CORE_H +#define __ASM_ARCH_PWM_CORE_H __FILE__ + +#include <clocksource/samsung_pwm.h> + +#ifdef CONFIG_SAMSUNG_DEV_PWM +extern void samsung_pwm_set_platdata(struct samsung_pwm_variant *pd); +#else +static inline void samsung_pwm_set_platdata(struct samsung_pwm_variant *pd) { } +#endif + +#endif /* __ASM_ARCH_PWM_CORE_H */ diff --git a/arch/arm/mach-s3c/regs-adc.h b/arch/arm/mach-s3c/regs-adc.h new file mode 100644 index 000000000..58953c738 --- /dev/null +++ b/arch/arm/mach-s3c/regs-adc.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2004 Shannon Holland <holland@loser.net> + * + * S3C2410 ADC registers + */ + +#ifndef __ASM_ARCH_REGS_ADC_H +#define __ASM_ARCH_REGS_ADC_H "regs-adc.h" + +#define S3C2410_ADCREG(x) (x) + +#define S3C2410_ADCCON S3C2410_ADCREG(0x00) +#define S3C2410_ADCTSC S3C2410_ADCREG(0x04) +#define S3C2410_ADCDLY S3C2410_ADCREG(0x08) +#define S3C2410_ADCDAT0 S3C2410_ADCREG(0x0C) +#define S3C2410_ADCDAT1 S3C2410_ADCREG(0x10) +#define S3C64XX_ADCUPDN S3C2410_ADCREG(0x14) +#define S3C2443_ADCMUX S3C2410_ADCREG(0x18) +#define S3C64XX_ADCCLRINT S3C2410_ADCREG(0x18) +#define S5P_ADCMUX S3C2410_ADCREG(0x1C) +#define S3C64XX_ADCCLRINTPNDNUP S3C2410_ADCREG(0x20) + + +/* ADCCON Register Bits */ +#define S3C64XX_ADCCON_RESSEL (1<<16) +#define S3C2410_ADCCON_ECFLG (1<<15) +#define S3C2410_ADCCON_PRSCEN (1<<14) +#define S3C2410_ADCCON_PRSCVL(x) (((x)&0xFF)<<6) +#define S3C2410_ADCCON_PRSCVLMASK (0xFF<<6) +#define S3C2410_ADCCON_SELMUX(x) (((x)&0x7)<<3) +#define S3C2410_ADCCON_MUXMASK (0x7<<3) +#define S3C2416_ADCCON_RESSEL (1 << 3) +#define S3C2410_ADCCON_STDBM (1<<2) +#define S3C2410_ADCCON_READ_START (1<<1) +#define S3C2410_ADCCON_ENABLE_START (1<<0) +#define S3C2410_ADCCON_STARTMASK (0x3<<0) + + +/* ADCTSC Register Bits */ +#define S3C2443_ADCTSC_UD_SEN (1 << 8) +#define S3C2410_ADCTSC_YM_SEN (1<<7) +#define S3C2410_ADCTSC_YP_SEN (1<<6) +#define S3C2410_ADCTSC_XM_SEN (1<<5) +#define S3C2410_ADCTSC_XP_SEN (1<<4) +#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) +#define S3C2410_ADCTSC_AUTO_PST (1<<2) +#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) + +/* ADCDAT0 Bits */ +#define S3C2410_ADCDAT0_UPDOWN (1<<15) +#define S3C2410_ADCDAT0_AUTO_PST (1<<14) +#define S3C2410_ADCDAT0_XY_PST (0x3<<12) +#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF) + +/* ADCDAT1 Bits */ +#define S3C2410_ADCDAT1_UPDOWN (1<<15) +#define S3C2410_ADCDAT1_AUTO_PST (1<<14) +#define S3C2410_ADCDAT1_XY_PST (0x3<<12) +#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF) + +#endif /* __ASM_ARCH_REGS_ADC_H */ + + diff --git a/arch/arm/mach-s3c/regs-clock-s3c24xx.h b/arch/arm/mach-s3c/regs-clock-s3c24xx.h new file mode 100644 index 000000000..933ddb5ee --- /dev/null +++ b/arch/arm/mach-s3c/regs-clock-s3c24xx.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C2410 clock register definitions + */ + +#ifndef __ASM_ARM_REGS_CLOCK +#define __ASM_ARM_REGS_CLOCK + +#include "map.h" + +#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) + +#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 */ + +#define S3C2416_CLKDIV2 S3C2410_CLKREG(0x28) + +#endif /* __ASM_ARM_REGS_CLOCK */ diff --git a/arch/arm/mach-s3c/regs-clock-s3c64xx.h b/arch/arm/mach-s3c/regs-clock-s3c64xx.h new file mode 100644 index 000000000..35a68767b --- /dev/null +++ b/arch/arm/mach-s3c/regs-clock-s3c64xx.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX clock register definitions + */ + +#ifndef __PLAT_REGS_CLOCK_H +#define __PLAT_REGS_CLOCK_H __FILE__ + +/* + * FIXME: Remove remaining definitions + */ + +#define S3C_CLKREG(x) (S3C_VA_SYS + (x)) + +#define S3C_PCLK_GATE S3C_CLKREG(0x34) +#define S3C6410_CLK_SRC2 S3C_CLKREG(0x10C) +#define S3C_MEM_SYS_CFG S3C_CLKREG(0x120) + +/* PCLK GATE Registers */ +#define S3C_CLKCON_PCLK_UART3 (1<<4) +#define S3C_CLKCON_PCLK_UART2 (1<<3) +#define S3C_CLKCON_PCLK_UART1 (1<<2) +#define S3C_CLKCON_PCLK_UART0 (1<<1) + +/* MEM_SYS_CFG */ +#define MEM_SYS_CFG_INDEP_CF 0x4000 +#define MEM_SYS_CFG_EBI_FIX_PRI_CFCON 0x30 + +#endif /* _PLAT_REGS_CLOCK_H */ diff --git a/arch/arm/mach-s3c/regs-clock.h b/arch/arm/mach-s3c/regs-clock.h new file mode 100644 index 000000000..7df31f203 --- /dev/null +++ b/arch/arm/mach-s3c/regs-clock.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "regs-clock-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "regs-clock-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/regs-dsc-s3c24xx.h b/arch/arm/mach-s3c/regs-dsc-s3c24xx.h new file mode 100644 index 000000000..8b8b572ae --- /dev/null +++ b/arch/arm/mach-s3c/regs-dsc-s3c24xx.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + * + * S3C2440/S3C2412 Signal Drive Strength Control + */ + + +#ifndef __ASM_ARCH_REGS_DSC_S3C24XX_H +#define __ASM_ARCH_REGS_DSC_S3C24XX_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_S3C24XX_H */ + diff --git a/arch/arm/mach-s3c/regs-gpio-memport-s3c64xx.h b/arch/arm/mach-s3c/regs-gpio-memport-s3c64xx.h new file mode 100644 index 000000000..589afe113 --- /dev/null +++ b/arch/arm/mach-s3c/regs-gpio-memport-s3c64xx.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - GPIO memory port register definitions + */ + +#ifndef __MACH_S3C64XX_REGS_GPIO_MEMPORT_H +#define __MACH_S3C64XX_REGS_GPIO_MEMPORT_H __FILE__ + +#define S3C64XX_MEM0CONSTOP S3C64XX_GPIOREG(0x1B0) +#define S3C64XX_MEM1CONSTOP S3C64XX_GPIOREG(0x1B4) + +#define S3C64XX_MEM0CONSLP0 S3C64XX_GPIOREG(0x1C0) +#define S3C64XX_MEM0CONSLP1 S3C64XX_GPIOREG(0x1C4) +#define S3C64XX_MEM1CONSLP S3C64XX_GPIOREG(0x1C8) + +#define S3C64XX_MEM0DRVCON S3C64XX_GPIOREG(0x1D0) +#define S3C64XX_MEM1DRVCON S3C64XX_GPIOREG(0x1D4) + +#endif /* __MACH_S3C64XX_REGS_GPIO_MEMPORT_H */ + diff --git a/arch/arm/mach-s3c/regs-gpio-s3c24xx.h b/arch/arm/mach-s3c/regs-gpio-s3c24xx.h new file mode 100644 index 000000000..9a7e26226 --- /dev/null +++ b/arch/arm/mach-s3c/regs-gpio-s3c24xx.h @@ -0,0 +1,608 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003-2004 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + * + * S3C2410 GPIO register definitions + */ + + +#ifndef __ASM_ARCH_REGS_GPIO_H +#define __ASM_ARCH_REGS_GPIO_H + +#include "map-s3c.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 control 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-s3c/regs-gpio-s3c64xx.h b/arch/arm/mach-s3c/regs-gpio-s3c64xx.h new file mode 100644 index 000000000..592a2be3d --- /dev/null +++ b/arch/arm/mach-s3c/regs-gpio-s3c64xx.h @@ -0,0 +1,188 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* linux/arch/arm/plat-s3c64xx/include/mach/regs-gpio.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX - GPIO register definitions + */ + +#ifndef __ASM_PLAT_S3C64XX_REGS_GPIO_H +#define __ASM_PLAT_S3C64XX_REGS_GPIO_H __FILE__ + +/* Base addresses for each of the banks */ + +#define S3C64XX_GPIOREG(reg) (S3C64XX_VA_GPIO + (reg)) + +#define S3C64XX_GPA_BASE S3C64XX_GPIOREG(0x0000) +#define S3C64XX_GPB_BASE S3C64XX_GPIOREG(0x0020) +#define S3C64XX_GPC_BASE S3C64XX_GPIOREG(0x0040) +#define S3C64XX_GPD_BASE S3C64XX_GPIOREG(0x0060) +#define S3C64XX_GPE_BASE S3C64XX_GPIOREG(0x0080) +#define S3C64XX_GPF_BASE S3C64XX_GPIOREG(0x00A0) +#define S3C64XX_GPG_BASE S3C64XX_GPIOREG(0x00C0) +#define S3C64XX_GPH_BASE S3C64XX_GPIOREG(0x00E0) +#define S3C64XX_GPI_BASE S3C64XX_GPIOREG(0x0100) +#define S3C64XX_GPJ_BASE S3C64XX_GPIOREG(0x0120) +#define S3C64XX_GPK_BASE S3C64XX_GPIOREG(0x0800) +#define S3C64XX_GPL_BASE S3C64XX_GPIOREG(0x0810) +#define S3C64XX_GPM_BASE S3C64XX_GPIOREG(0x0820) +#define S3C64XX_GPN_BASE S3C64XX_GPIOREG(0x0830) +#define S3C64XX_GPO_BASE S3C64XX_GPIOREG(0x0140) +#define S3C64XX_GPP_BASE S3C64XX_GPIOREG(0x0160) +#define S3C64XX_GPQ_BASE S3C64XX_GPIOREG(0x0180) + +/* SPCON */ + +#define S3C64XX_SPCON S3C64XX_GPIOREG(0x1A0) + +#define S3C64XX_SPCON_DRVCON_CAM_MASK (0x3 << 30) +#define S3C64XX_SPCON_DRVCON_CAM_SHIFT (30) +#define S3C64XX_SPCON_DRVCON_CAM_2mA (0x0 << 30) +#define S3C64XX_SPCON_DRVCON_CAM_4mA (0x1 << 30) +#define S3C64XX_SPCON_DRVCON_CAM_7mA (0x2 << 30) +#define S3C64XX_SPCON_DRVCON_CAM_9mA (0x3 << 30) + +#define S3C64XX_SPCON_DRVCON_HSSPI_MASK (0x3 << 28) +#define S3C64XX_SPCON_DRVCON_HSSPI_SHIFT (28) +#define S3C64XX_SPCON_DRVCON_HSSPI_2mA (0x0 << 28) +#define S3C64XX_SPCON_DRVCON_HSSPI_4mA (0x1 << 28) +#define S3C64XX_SPCON_DRVCON_HSSPI_7mA (0x2 << 28) +#define S3C64XX_SPCON_DRVCON_HSSPI_9mA (0x3 << 28) + +#define S3C64XX_SPCON_DRVCON_HSMMC_MASK (0x3 << 26) +#define S3C64XX_SPCON_DRVCON_HSMMC_SHIFT (26) +#define S3C64XX_SPCON_DRVCON_HSMMC_2mA (0x0 << 26) +#define S3C64XX_SPCON_DRVCON_HSMMC_4mA (0x1 << 26) +#define S3C64XX_SPCON_DRVCON_HSMMC_7mA (0x2 << 26) +#define S3C64XX_SPCON_DRVCON_HSMMC_9mA (0x3 << 26) + +#define S3C64XX_SPCON_DRVCON_LCD_MASK (0x3 << 24) +#define S3C64XX_SPCON_DRVCON_LCD_SHIFT (24) +#define S3C64XX_SPCON_DRVCON_LCD_2mA (0x0 << 24) +#define S3C64XX_SPCON_DRVCON_LCD_4mA (0x1 << 24) +#define S3C64XX_SPCON_DRVCON_LCD_7mA (0x2 << 24) +#define S3C64XX_SPCON_DRVCON_LCD_9mA (0x3 << 24) + +#define S3C64XX_SPCON_DRVCON_MODEM_MASK (0x3 << 22) +#define S3C64XX_SPCON_DRVCON_MODEM_SHIFT (22) +#define S3C64XX_SPCON_DRVCON_MODEM_2mA (0x0 << 22) +#define S3C64XX_SPCON_DRVCON_MODEM_4mA (0x1 << 22) +#define S3C64XX_SPCON_DRVCON_MODEM_7mA (0x2 << 22) +#define S3C64XX_SPCON_DRVCON_MODEM_9mA (0x3 << 22) + +#define S3C64XX_SPCON_nRSTOUT_OEN (1 << 21) + +#define S3C64XX_SPCON_DRVCON_SPICLK1_MASK (0x3 << 18) +#define S3C64XX_SPCON_DRVCON_SPICLK1_SHIFT (18) +#define S3C64XX_SPCON_DRVCON_SPICLK1_2mA (0x0 << 18) +#define S3C64XX_SPCON_DRVCON_SPICLK1_4mA (0x1 << 18) +#define S3C64XX_SPCON_DRVCON_SPICLK1_7mA (0x2 << 18) +#define S3C64XX_SPCON_DRVCON_SPICLK1_9mA (0x3 << 18) + +#define S3C64XX_SPCON_MEM1_DQS_PUD_MASK (0x3 << 16) +#define S3C64XX_SPCON_MEM1_DQS_PUD_SHIFT (16) +#define S3C64XX_SPCON_MEM1_DQS_PUD_DISABLED (0x0 << 16) +#define S3C64XX_SPCON_MEM1_DQS_PUD_DOWN (0x1 << 16) +#define S3C64XX_SPCON_MEM1_DQS_PUD_UP (0x2 << 16) + +#define S3C64XX_SPCON_MEM1_D_PUD1_MASK (0x3 << 14) +#define S3C64XX_SPCON_MEM1_D_PUD1_SHIFT (14) +#define S3C64XX_SPCON_MEM1_D_PUD1_DISABLED (0x0 << 14) +#define S3C64XX_SPCON_MEM1_D_PUD1_DOWN (0x1 << 14) +#define S3C64XX_SPCON_MEM1_D_PUD1_UP (0x2 << 14) + +#define S3C64XX_SPCON_MEM1_D_PUD0_MASK (0x3 << 12) +#define S3C64XX_SPCON_MEM1_D_PUD0_SHIFT (12) +#define S3C64XX_SPCON_MEM1_D_PUD0_DISABLED (0x0 << 12) +#define S3C64XX_SPCON_MEM1_D_PUD0_DOWN (0x1 << 12) +#define S3C64XX_SPCON_MEM1_D_PUD0_UP (0x2 << 12) + +#define S3C64XX_SPCON_MEM0_D_PUD_MASK (0x3 << 8) +#define S3C64XX_SPCON_MEM0_D_PUD_SHIFT (8) +#define S3C64XX_SPCON_MEM0_D_PUD_DISABLED (0x0 << 8) +#define S3C64XX_SPCON_MEM0_D_PUD_DOWN (0x1 << 8) +#define S3C64XX_SPCON_MEM0_D_PUD_UP (0x2 << 8) + +#define S3C64XX_SPCON_USBH_DMPD (1 << 7) +#define S3C64XX_SPCON_USBH_DPPD (1 << 6) +#define S3C64XX_SPCON_USBH_PUSW2 (1 << 5) +#define S3C64XX_SPCON_USBH_PUSW1 (1 << 4) +#define S3C64XX_SPCON_USBH_SUSPND (1 << 3) + +#define S3C64XX_SPCON_LCD_SEL_MASK (0x3 << 0) +#define S3C64XX_SPCON_LCD_SEL_SHIFT (0) +#define S3C64XX_SPCON_LCD_SEL_HOST (0x0 << 0) +#define S3C64XX_SPCON_LCD_SEL_RGB (0x1 << 0) +#define S3C64XX_SPCON_LCD_SEL_606_656 (0x2 << 0) + + +/* External interrupt registers */ + +#define S3C64XX_EINT12CON S3C64XX_GPIOREG(0x200) +#define S3C64XX_EINT34CON S3C64XX_GPIOREG(0x204) +#define S3C64XX_EINT56CON S3C64XX_GPIOREG(0x208) +#define S3C64XX_EINT78CON S3C64XX_GPIOREG(0x20C) +#define S3C64XX_EINT9CON S3C64XX_GPIOREG(0x210) + +#define S3C64XX_EINT12FLTCON S3C64XX_GPIOREG(0x220) +#define S3C64XX_EINT34FLTCON S3C64XX_GPIOREG(0x224) +#define S3C64XX_EINT56FLTCON S3C64XX_GPIOREG(0x228) +#define S3C64XX_EINT78FLTCON S3C64XX_GPIOREG(0x22C) +#define S3C64XX_EINT9FLTCON S3C64XX_GPIOREG(0x230) + +#define S3C64XX_EINT12MASK S3C64XX_GPIOREG(0x240) +#define S3C64XX_EINT34MASK S3C64XX_GPIOREG(0x244) +#define S3C64XX_EINT56MASK S3C64XX_GPIOREG(0x248) +#define S3C64XX_EINT78MASK S3C64XX_GPIOREG(0x24C) +#define S3C64XX_EINT9MASK S3C64XX_GPIOREG(0x250) + +#define S3C64XX_EINT12PEND S3C64XX_GPIOREG(0x260) +#define S3C64XX_EINT34PEND S3C64XX_GPIOREG(0x264) +#define S3C64XX_EINT56PEND S3C64XX_GPIOREG(0x268) +#define S3C64XX_EINT78PEND S3C64XX_GPIOREG(0x26C) +#define S3C64XX_EINT9PEND S3C64XX_GPIOREG(0x270) + +#define S3C64XX_PRIORITY S3C64XX_GPIOREG(0x280) +#define S3C64XX_PRIORITY_ARB(x) (1 << (x)) + +#define S3C64XX_SERVICE S3C64XX_GPIOREG(0x284) +#define S3C64XX_SERVICEPEND S3C64XX_GPIOREG(0x288) + +#define S3C64XX_EINT0CON0 S3C64XX_GPIOREG(0x900) +#define S3C64XX_EINT0CON1 S3C64XX_GPIOREG(0x904) +#define S3C64XX_EINT0FLTCON0 S3C64XX_GPIOREG(0x910) +#define S3C64XX_EINT0FLTCON1 S3C64XX_GPIOREG(0x914) +#define S3C64XX_EINT0FLTCON2 S3C64XX_GPIOREG(0x918) +#define S3C64XX_EINT0FLTCON3 S3C64XX_GPIOREG(0x91C) + +#define S3C64XX_EINT0MASK S3C64XX_GPIOREG(0x920) +#define S3C64XX_EINT0PEND S3C64XX_GPIOREG(0x924) + +/* GPIO sleep configuration */ + +#define S3C64XX_SPCONSLP S3C64XX_GPIOREG(0x880) + +#define S3C64XX_SPCONSLP_TDO_PULLDOWN (1 << 14) +#define S3C64XX_SPCONSLP_CKE1INIT (1 << 5) + +#define S3C64XX_SPCONSLP_RSTOUT_MASK (0x3 << 12) +#define S3C64XX_SPCONSLP_RSTOUT_OUT0 (0x0 << 12) +#define S3C64XX_SPCONSLP_RSTOUT_OUT1 (0x1 << 12) +#define S3C64XX_SPCONSLP_RSTOUT_HIZ (0x2 << 12) + +#define S3C64XX_SPCONSLP_KPCOL_MASK (0x3 << 0) +#define S3C64XX_SPCONSLP_KPCOL_OUT0 (0x0 << 0) +#define S3C64XX_SPCONSLP_KPCOL_OUT1 (0x1 << 0) +#define S3C64XX_SPCONSLP_KPCOL_INP (0x2 << 0) + + +#define S3C64XX_SLPEN S3C64XX_GPIOREG(0x930) + +#define S3C64XX_SLPEN_USE_xSLP (1 << 0) +#define S3C64XX_SLPEN_CFG_BYSLPEN (1 << 1) + +#endif /* __ASM_PLAT_S3C64XX_REGS_GPIO_H */ + diff --git a/arch/arm/mach-s3c/regs-gpio.h b/arch/arm/mach-s3c/regs-gpio.h new file mode 100644 index 000000000..0d41cb76d --- /dev/null +++ b/arch/arm/mach-s3c/regs-gpio.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "regs-gpio-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "regs-gpio-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/regs-irq-s3c24xx.h b/arch/arm/mach-s3c/regs-irq-s3c24xx.h new file mode 100644 index 000000000..c0b97b203 --- /dev/null +++ b/arch/arm/mach-s3c/regs-irq-s3c24xx.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + */ + + +#ifndef ___ASM_ARCH_REGS_IRQ_H +#define ___ASM_ARCH_REGS_IRQ_H + +#include "map-s3c.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-s3c/regs-irq-s3c64xx.h b/arch/arm/mach-s3c/regs-irq-s3c64xx.h new file mode 100644 index 000000000..b18c7bcb6 --- /dev/null +++ b/arch/arm/mach-s3c/regs-irq-s3c64xx.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C64XX - IRQ register definitions + */ + +#ifndef __ASM_ARCH_REGS_IRQ_H +#define __ASM_ARCH_REGS_IRQ_H __FILE__ + + +#endif /* __ASM_ARCH_6400_REGS_IRQ_H */ diff --git a/arch/arm/mach-s3c/regs-irq.h b/arch/arm/mach-s3c/regs-irq.h new file mode 100644 index 000000000..57f0dda8d --- /dev/null +++ b/arch/arm/mach-s3c/regs-irq.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifdef CONFIG_ARCH_S3C24XX +#include "regs-irq-s3c24xx.h" +#endif + +#ifdef CONFIG_ARCH_S3C64XX +#include "regs-irq-s3c64xx.h" +#endif diff --git a/arch/arm/mach-s3c/regs-irqtype.h b/arch/arm/mach-s3c/regs-irqtype.h new file mode 100644 index 000000000..ec5c4c5fd --- /dev/null +++ b/arch/arm/mach-s3c/regs-irqtype.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C - IRQ detection types. + */ + +/* values for S3C2410_EXTINT0/1/2 and other cpus in the series, including + * the S3C64XX +*/ +#define S3C2410_EXTINT_LOWLEV (0x00) +#define S3C2410_EXTINT_HILEV (0x01) +#define S3C2410_EXTINT_FALLEDGE (0x02) +#define S3C2410_EXTINT_RISEEDGE (0x04) +#define S3C2410_EXTINT_BOTHEDGE (0x06) diff --git a/arch/arm/mach-s3c/regs-mem-s3c24xx.h b/arch/arm/mach-s3c/regs-mem-s3c24xx.h new file mode 100644 index 000000000..8fed34a16 --- /dev/null +++ b/arch/arm/mach-s3c/regs-mem-s3c24xx.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + * + * S3C2410 Memory Control register definitions + */ + +#ifndef __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H +#define __ARCH_ARM_MACH_S3C24XX_REGS_MEM_H __FILE__ + +#include "map-s3c.h" + +#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-s3c/regs-modem-s3c64xx.h b/arch/arm/mach-s3c/regs-modem-s3c64xx.h new file mode 100644 index 000000000..136ad4429 --- /dev/null +++ b/arch/arm/mach-s3c/regs-modem-s3c64xx.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C64XX - modem block registers + */ + +#ifndef __MACH_S3C64XX_REGS_MODEM_H +#define __MACH_S3C64XX_REGS_MODEM_H __FILE__ + +#define S3C64XX_MODEMREG(x) (S3C64XX_VA_MODEM + (x)) + +#define S3C64XX_MODEM_INT2AP S3C64XX_MODEMREG(0x0) +#define S3C64XX_MODEM_INT2MODEM S3C64XX_MODEMREG(0x4) +#define S3C64XX_MODEM_MIFCON S3C64XX_MODEMREG(0x8) +#define S3C64XX_MODEM_MIFPCON S3C64XX_MODEMREG(0xC) +#define S3C64XX_MODEM_INTCLR S3C64XX_MODEMREG(0x10) +#define S3C64XX_MODEM_DMA_TXADDR S3C64XX_MODEMREG(0x14) +#define S3C64XX_MODEM_DMA_RXADDR S3C64XX_MODEMREG(0x18) + +#define MIFPCON_INT2M_LEVEL (1 << 4) +#define MIFPCON_LCD_BYPASS (1 << 3) + +#endif /* __MACH_S3C64XX_REGS_MODEM_H */ diff --git a/arch/arm/mach-s3c/regs-s3c2443-clock.h b/arch/arm/mach-s3c/regs-s3c2443-clock.h new file mode 100644 index 000000000..b3b670d46 --- /dev/null +++ b/arch/arm/mach-s3c/regs-s3c2443-clock.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C2443 clock register definitions + */ + +#ifndef __ASM_ARM_REGS_S3C2443_CLOCK +#define __ASM_ARM_REGS_S3C2443_CLOCK + +#include <linux/delay.h> +#include "map-s3c.h" + +#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_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; +} + +static inline void s3c_hsudc_init_phy(void) +{ + u32 cfg; + + cfg = readl(S3C2443_PWRCFG) | S3C2443_PWRCFG_USBPHY; + writel(cfg, S3C2443_PWRCFG); + + cfg = readl(S3C2443_URSTCON); + cfg |= (S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); + writel(cfg, S3C2443_URSTCON); + mdelay(1); + + cfg = readl(S3C2443_URSTCON); + cfg &= ~(S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); + writel(cfg, S3C2443_URSTCON); + + cfg = readl(S3C2443_PHYCTRL); + cfg &= ~(S3C2443_PHYCTRL_CLKSEL | S3C2443_PHYCTRL_DSPORT); + cfg |= (S3C2443_PHYCTRL_EXTCLK | S3C2443_PHYCTRL_PLLSEL); + writel(cfg, S3C2443_PHYCTRL); + + cfg = readl(S3C2443_PHYPWR); + cfg &= ~(S3C2443_PHYPWR_FSUSPEND | S3C2443_PHYPWR_PLL_PWRDN | + S3C2443_PHYPWR_XO_ON | S3C2443_PHYPWR_PLL_REFCLK | + S3C2443_PHYPWR_ANALOG_PD); + cfg |= S3C2443_PHYPWR_COMMON_ON; + writel(cfg, S3C2443_PHYPWR); + + cfg = readl(S3C2443_UCLKCON); + cfg |= (S3C2443_UCLKCON_DETECT_VBUS | S3C2443_UCLKCON_FUNC_CLKEN | + S3C2443_UCLKCON_TCLKEN); + writel(cfg, S3C2443_UCLKCON); +} + +static inline void s3c_hsudc_uninit_phy(void) +{ + u32 cfg; + + cfg = readl(S3C2443_PWRCFG) & ~S3C2443_PWRCFG_USBPHY; + writel(cfg, S3C2443_PWRCFG); + + writel(S3C2443_PHYPWR_FSUSPEND, S3C2443_PHYPWR); + + cfg = readl(S3C2443_UCLKCON) & ~S3C2443_UCLKCON_FUNC_CLKEN; + writel(cfg, S3C2443_UCLKCON); +} + +#endif /* __ASM_ARM_REGS_S3C2443_CLOCK */ + diff --git a/arch/arm/mach-s3c/regs-srom-s3c64xx.h b/arch/arm/mach-s3c/regs-srom-s3c64xx.h new file mode 100644 index 000000000..2b37988bd --- /dev/null +++ b/arch/arm/mach-s3c/regs-srom-s3c64xx.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2009 Andy Green <andy@warmcat.com> + * + * S3C64XX SROM definitions + */ + +#ifndef __MACH_S3C64XX_REGS_SROM_H +#define __MACH_S3C64XX_REGS_SROM_H __FILE__ + +#define S3C64XX_SROMREG(x) (S3C_VA_MEM + (x)) + +#define S3C64XX_SROM_BW S3C64XX_SROMREG(0) +#define S3C64XX_SROM_BC0 S3C64XX_SROMREG(4) +#define S3C64XX_SROM_BC1 S3C64XX_SROMREG(8) +#define S3C64XX_SROM_BC2 S3C64XX_SROMREG(0xc) +#define S3C64XX_SROM_BC3 S3C64XX_SROMREG(0x10) +#define S3C64XX_SROM_BC4 S3C64XX_SROMREG(0x14) +#define S3C64XX_SROM_BC5 S3C64XX_SROMREG(0x18) + +/* + * one register BW holds 5 x 4-bit packed settings for NCS0 - NCS4 + */ + +#define S3C64XX_SROM_BW__DATAWIDTH__SHIFT 0 +#define S3C64XX_SROM_BW__WAITENABLE__SHIFT 2 +#define S3C64XX_SROM_BW__BYTEENABLE__SHIFT 3 +#define S3C64XX_SROM_BW__CS_MASK 0xf + +#define S3C64XX_SROM_BW__NCS0__SHIFT 0 +#define S3C64XX_SROM_BW__NCS1__SHIFT 4 +#define S3C64XX_SROM_BW__NCS2__SHIFT 8 +#define S3C64XX_SROM_BW__NCS3__SHIFT 0xc +#define S3C64XX_SROM_BW__NCS4__SHIFT 0x10 + +/* + * applies to same to BCS0 - BCS4 + */ + +#define S3C64XX_SROM_BCX__PMC__SHIFT 0 +#define S3C64XX_SROM_BCX__PMC__MASK 3 +#define S3C64XX_SROM_BCX__TACP__SHIFT 4 +#define S3C64XX_SROM_BCX__TACP__MASK 0xf +#define S3C64XX_SROM_BCX__TCAH__SHIFT 8 +#define S3C64XX_SROM_BCX__TCAH__MASK 0xf +#define S3C64XX_SROM_BCX__TCOH__SHIFT 12 +#define S3C64XX_SROM_BCX__TCOH__MASK 0xf +#define S3C64XX_SROM_BCX__TACC__SHIFT 16 +#define S3C64XX_SROM_BCX__TACC__MASK 0x1f +#define S3C64XX_SROM_BCX__TCOS__SHIFT 24 +#define S3C64XX_SROM_BCX__TCOS__MASK 0xf +#define S3C64XX_SROM_BCX__TACS__SHIFT 28 +#define S3C64XX_SROM_BCX__TACS__MASK 0xf + +#endif /* __MACH_S3C64XX_REGS_SROM_H */ diff --git a/arch/arm/mach-s3c/regs-sys-s3c64xx.h b/arch/arm/mach-s3c/regs-sys-s3c64xx.h new file mode 100644 index 000000000..3687325e2 --- /dev/null +++ b/arch/arm/mach-s3c/regs-sys-s3c64xx.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX system register definitions +*/ + +#ifndef __MACH_S3C64XX_REGS_SYS_H +#define __MACH_S3C64XX_REGS_SYS_H __FILE__ + +#define S3C_SYSREG(x) (S3C_VA_SYS + (x)) + +#define S3C64XX_AHB_CON0 S3C_SYSREG(0x100) +#define S3C64XX_AHB_CON1 S3C_SYSREG(0x104) +#define S3C64XX_AHB_CON2 S3C_SYSREG(0x108) + +#define S3C64XX_SDMA_SEL S3C_SYSREG(0x110) + +#define S3C64XX_OTHERS S3C_SYSREG(0x900) + +#define S3C64XX_OTHERS_USBMASK (1 << 16) +#define S3C64XX_OTHERS_SYNCMUXSEL (1 << 6) + +#endif /* __MACH_S3C64XX_REGS_SYS_H */ diff --git a/arch/arm/mach-s3c/regs-syscon-power-s3c64xx.h b/arch/arm/mach-s3c/regs-syscon-power-s3c64xx.h new file mode 100644 index 000000000..a35811cc6 --- /dev/null +++ b/arch/arm/mach-s3c/regs-syscon-power-s3c64xx.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C64XX - syscon power and sleep control registers +*/ + +#ifndef __MACH_S3C64XX_REGS_SYSCON_POWER_H +#define __MACH_S3C64XX_REGS_SYSCON_POWER_H __FILE__ + +#define S3C64XX_PWR_CFG S3C_SYSREG(0x804) + +#define S3C64XX_PWRCFG_OSC_OTG_DISABLE (1 << 17) +#define S3C64XX_PWRCFG_MMC2_DISABLE (1 << 16) +#define S3C64XX_PWRCFG_MMC1_DISABLE (1 << 15) +#define S3C64XX_PWRCFG_MMC0_DISABLE (1 << 14) +#define S3C64XX_PWRCFG_HSI_DISABLE (1 << 13) +#define S3C64XX_PWRCFG_TS_DISABLE (1 << 12) +#define S3C64XX_PWRCFG_RTC_TICK_DISABLE (1 << 11) +#define S3C64XX_PWRCFG_RTC_ALARM_DISABLE (1 << 10) +#define S3C64XX_PWRCFG_MSM_DISABLE (1 << 9) +#define S3C64XX_PWRCFG_KEY_DISABLE (1 << 8) +#define S3C64XX_PWRCFG_BATF_DISABLE (1 << 7) + +#define S3C64XX_PWRCFG_CFG_WFI_MASK (0x3 << 5) +#define S3C64XX_PWRCFG_CFG_WFI_SHIFT (5) +#define S3C64XX_PWRCFG_CFG_WFI_IGNORE (0x0 << 5) +#define S3C64XX_PWRCFG_CFG_WFI_IDLE (0x1 << 5) +#define S3C64XX_PWRCFG_CFG_WFI_STOP (0x2 << 5) +#define S3C64XX_PWRCFG_CFG_WFI_SLEEP (0x3 << 5) + +#define S3C64XX_PWRCFG_CFG_BATFLT_MASK (0x3 << 3) +#define S3C64XX_PWRCFG_CFG_BATFLT_SHIFT (3) +#define S3C64XX_PWRCFG_CFG_BATFLT_IGNORE (0x0 << 3) +#define S3C64XX_PWRCFG_CFG_BATFLT_IRQ (0x1 << 3) +#define S3C64XX_PWRCFG_CFG_BATFLT_SLEEP (0x3 << 3) + +#define S3C64XX_PWRCFG_CFG_BAT_WAKE (1 << 2) +#define S3C64XX_PWRCFG_OSC27_EN (1 << 0) + +#define S3C64XX_EINT_MASK S3C_SYSREG(0x808) + +#define S3C64XX_NORMAL_CFG S3C_SYSREG(0x810) + +#define S3C64XX_NORMALCFG_IROM_ON (1 << 30) +#define S3C64XX_NORMALCFG_DOMAIN_ETM_ON (1 << 16) +#define S3C64XX_NORMALCFG_DOMAIN_S_ON (1 << 15) +#define S3C64XX_NORMALCFG_DOMAIN_F_ON (1 << 14) +#define S3C64XX_NORMALCFG_DOMAIN_P_ON (1 << 13) +#define S3C64XX_NORMALCFG_DOMAIN_I_ON (1 << 12) +#define S3C64XX_NORMALCFG_DOMAIN_G_ON (1 << 10) +#define S3C64XX_NORMALCFG_DOMAIN_V_ON (1 << 9) + +#define S3C64XX_STOP_CFG S3C_SYSREG(0x814) + +#define S3C64XX_STOPCFG_MEMORY_ARM_ON (1 << 29) +#define S3C64XX_STOPCFG_TOP_MEMORY_ON (1 << 20) +#define S3C64XX_STOPCFG_ARM_LOGIC_ON (1 << 17) +#define S3C64XX_STOPCFG_TOP_LOGIC_ON (1 << 8) +#define S3C64XX_STOPCFG_OSC_EN (1 << 0) + +#define S3C64XX_SLEEP_CFG S3C_SYSREG(0x818) + +#define S3C64XX_SLEEPCFG_OSC_EN (1 << 0) + +#define S3C64XX_STOP_MEM_CFG S3C_SYSREG(0x81c) + +#define S3C64XX_STOPMEMCFG_MODEMIF_RETAIN (1 << 6) +#define S3C64XX_STOPMEMCFG_HOSTIF_RETAIN (1 << 5) +#define S3C64XX_STOPMEMCFG_OTG_RETAIN (1 << 4) +#define S3C64XX_STOPMEMCFG_HSMCC_RETAIN (1 << 3) +#define S3C64XX_STOPMEMCFG_IROM_RETAIN (1 << 2) +#define S3C64XX_STOPMEMCFG_IRDA_RETAIN (1 << 1) +#define S3C64XX_STOPMEMCFG_NFCON_RETAIN (1 << 0) + +#define S3C64XX_OSC_STABLE S3C_SYSREG(0x824) +#define S3C64XX_PWR_STABLE S3C_SYSREG(0x828) + +#define S3C64XX_WAKEUP_STAT S3C_SYSREG(0x908) + +#define S3C64XX_WAKEUPSTAT_MMC2 (1 << 11) +#define S3C64XX_WAKEUPSTAT_MMC1 (1 << 10) +#define S3C64XX_WAKEUPSTAT_MMC0 (1 << 9) +#define S3C64XX_WAKEUPSTAT_HSI (1 << 8) +#define S3C64XX_WAKEUPSTAT_BATFLT (1 << 6) +#define S3C64XX_WAKEUPSTAT_MSM (1 << 5) +#define S3C64XX_WAKEUPSTAT_KEY (1 << 4) +#define S3C64XX_WAKEUPSTAT_TS (1 << 3) +#define S3C64XX_WAKEUPSTAT_RTC_TICK (1 << 2) +#define S3C64XX_WAKEUPSTAT_RTC_ALARM (1 << 1) +#define S3C64XX_WAKEUPSTAT_EINT (1 << 0) + +#define S3C64XX_BLK_PWR_STAT S3C_SYSREG(0x90c) + +#define S3C64XX_BLKPWRSTAT_G (1 << 7) +#define S3C64XX_BLKPWRSTAT_ETM (1 << 6) +#define S3C64XX_BLKPWRSTAT_S (1 << 5) +#define S3C64XX_BLKPWRSTAT_F (1 << 4) +#define S3C64XX_BLKPWRSTAT_P (1 << 3) +#define S3C64XX_BLKPWRSTAT_I (1 << 2) +#define S3C64XX_BLKPWRSTAT_V (1 << 1) +#define S3C64XX_BLKPWRSTAT_TOP (1 << 0) + +#define S3C64XX_INFORM0 S3C_SYSREG(0xA00) +#define S3C64XX_INFORM1 S3C_SYSREG(0xA04) +#define S3C64XX_INFORM2 S3C_SYSREG(0xA08) +#define S3C64XX_INFORM3 S3C_SYSREG(0xA0C) + +#endif /* __MACH_S3C64XX_REGS_SYSCON_POWER_H */ diff --git a/arch/arm/mach-s3c/regs-usb-hsotg-phy-s3c64xx.h b/arch/arm/mach-s3c/regs-usb-hsotg-phy-s3c64xx.h new file mode 100644 index 000000000..deb1dd2d9 --- /dev/null +++ b/arch/arm/mach-s3c/regs-usb-hsotg-phy-s3c64xx.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C - USB2.0 Highspeed/OtG device PHY registers +*/ + +/* Note, this is a separate header file as some of the clock framework + * needs to touch this if the clk_48m is used as the USB OHCI or other + * peripheral source. +*/ + +#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H +#define __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H __FILE__ + +/* S3C64XX_PA_USB_HSPHY */ + +#define S3C_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY) + +#define S3C_PHYPWR S3C_HSOTG_PHYREG(0x00) +#define S3C_PHYPWR_NORMAL_MASK (0x19 << 0) +#define S3C_PHYPWR_OTG_DISABLE (1 << 4) +#define S3C_PHYPWR_ANALOG_POWERDOWN (1 << 3) +#define SRC_PHYPWR_FORCE_SUSPEND (1 << 1) + +#define S3C_PHYCLK S3C_HSOTG_PHYREG(0x04) +#define S3C_PHYCLK_MODE_USB11 (1 << 6) +#define S3C_PHYCLK_EXT_OSC (1 << 5) +#define S3C_PHYCLK_CLK_FORCE (1 << 4) +#define S3C_PHYCLK_ID_PULL (1 << 2) +#define S3C_PHYCLK_CLKSEL_MASK (0x3 << 0) +#define S3C_PHYCLK_CLKSEL_SHIFT (0) +#define S3C_PHYCLK_CLKSEL_48M (0x0 << 0) +#define S3C_PHYCLK_CLKSEL_12M (0x2 << 0) +#define S3C_PHYCLK_CLKSEL_24M (0x3 << 0) + +#define S3C_RSTCON S3C_HSOTG_PHYREG(0x08) +#define S3C_RSTCON_PHYCLK (1 << 2) +#define S3C_RSTCON_HCLK (1 << 1) +#define S3C_RSTCON_PHY (1 << 0) + +#define S3C_PHYTUNE S3C_HSOTG_PHYREG(0x20) + +#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H */ diff --git a/arch/arm/mach-s3c/rtc-core-s3c24xx.h b/arch/arm/mach-s3c/rtc-core-s3c24xx.h new file mode 100644 index 000000000..e7258b242 --- /dev/null +++ b/arch/arm/mach-s3c/rtc-core-s3c24xx.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011 Heiko Stuebner <heiko@sntech.de> + * + * Samsung RTC Controller core functions + */ + +#ifndef __RTC_CORE_S3C24XX_H +#define __RTC_CORE_S3C24XX_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_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/s3c2410.c b/arch/arm/mach-s3c/s3c2410.c new file mode 100644 index 000000000..4d39d9939 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2410.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2003-2005 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://www.simtec.co.uk/products/EB2410ITX/ + +#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 "map.h" +#include "gpio-samsung.h" +#include <asm/irq.h> +#include <asm/system_misc.h> + + +#include "regs-clock.h" + +#include "cpu.h" +#include "devs.h" +#include "pm.h" + +#include "gpio-core.h" +#include "gpio-cfg.h" +#include "gpio-cfg-helpers.h" + +#include "s3c24xx.h" + +/* Initial IO mappings */ + +static struct map_desc s3c2410_iodesc[] __initdata __maybe_unused = { + 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)); +} + +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_SLEEP + 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(); +} diff --git a/arch/arm/mach-s3c/s3c2412-power.h b/arch/arm/mach-s3c/s3c2412-power.h new file mode 100644 index 000000000..0031cfaa1 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2412-power.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003-2006 Simtec Electronics <linux@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + */ + +#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-s3c/s3c2412.c b/arch/arm/mach-s3c/s3c2412.c new file mode 100644 index 000000000..0b1ca78c9 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2412.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2006 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://armlinux.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/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 "map.h" +#include "regs-clock.h" +#include "regs-gpio.h" + +#include "cpu.h" +#include "devs.h" +#include "pm.h" + +#include "s3c24xx.h" +#include "nand-core-s3c24xx.h" +#include "regs-dsc-s3c24xx.h" +#include "s3c2412-power.h" + +#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 __maybe_unused = { + 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(); +} + +/* 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)); +} + +/* 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_SLEEP + 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-s3c/s3c2412.h b/arch/arm/mach-s3c/s3c2412.h new file mode 100644 index 000000000..ed09a0e13 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2412.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + */ + +#ifndef __ARCH_ARM_MACH_S3C24XX_S3C2412_H +#define __ARCH_ARM_MACH_S3C24XX_S3C2412_H __FILE__ + +#include "map-s3c.h" + +#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-s3c/s3c2416.c b/arch/arm/mach-s3c/s3c2416.c new file mode 100644 index 000000000..126e6ed29 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2416.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// 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 + +#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 "map.h" +#include "gpio-samsung.h" +#include <asm/proc-fns.h> +#include <asm/irq.h> +#include <asm/system_misc.h> + +#include "regs-s3c2443-clock.h" +#include "rtc-core-s3c24xx.h" + +#include "gpio-core.h" +#include "gpio-cfg.h" +#include "gpio-cfg-helpers.h" +#include "devs.h" +#include "cpu.h" +#include "sdhci.h" +#include "pm.h" + +#include "iic-core.h" +#include "adc-core.h" + +#include "s3c24xx.h" +#include "fb-core-s3c24xx.h" +#include "nand-core-s3c24xx.h" +#include "spi-core-s3c24xx.h" + +static struct map_desc s3c2416_iodesc[] __initdata __maybe_unused = { + 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, +}; + +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_SLEEP + 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(); + s3c24xx_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-s3c/s3c2440.c b/arch/arm/mach-s3c/s3c2440.c new file mode 100644 index 000000000..c6cdee498 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2440.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2004-2006 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// Samsung S3C2440 Mobile CPU support + +#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 <asm/irq.h> + +#include "devs.h" +#include "cpu.h" +#include "pm.h" + +#include "gpio-core.h" +#include "gpio-cfg.h" +#include "gpio-cfg-helpers.h" +#include "gpio-samsung.h" + +#include "s3c24xx.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_SLEEP + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + register_syscore_ops(&s3c244x_pm_syscore_ops); +#endif + + /* 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-s3c/s3c2442.c b/arch/arm/mach-s3c/s3c2442.c new file mode 100644 index 000000000..0c0e30b66 --- /dev/null +++ b/arch/arm/mach-s3c/s3c2442.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2004-2005 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk> +// +// S3C2442 core and lock support + +#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 <linux/atomic.h> +#include <asm/irq.h> + +#include "regs-clock.h" + +#include "cpu.h" +#include "pm.h" + +#include "gpio-core.h" +#include "gpio-cfg.h" +#include "gpio-cfg-helpers.h" +#include "gpio-samsung.h" + +#include "s3c24xx.h" + +static struct device s3c2442_dev = { + .bus = &s3c2442_subsys, +}; + +int __init s3c2442_init(void) +{ + printk("S3C2442: Initialising architecture\n"); + +#ifdef CONFIG_PM_SLEEP + register_syscore_ops(&s3c2410_pm_syscore_ops); + register_syscore_ops(&s3c24xx_irq_syscore_ops); + register_syscore_ops(&s3c244x_pm_syscore_ops); +#endif + + 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-s3c/s3c2443.c b/arch/arm/mach-s3c/s3c2443.c new file mode 100644 index 000000000..05c3c298b --- /dev/null +++ b/arch/arm/mach-s3c/s3c2443.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2007 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// Samsung S3C2443 Mobile CPU support + +#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 "map.h" +#include "gpio-samsung.h" +#include "irqs.h" +#include <asm/irq.h> +#include <asm/system_misc.h> + +#include "regs-s3c2443-clock.h" +#include "rtc-core-s3c24xx.h" + +#include "gpio-core.h" +#include "gpio-cfg.h" +#include "gpio-cfg-helpers.h" +#include "devs.h" +#include "cpu.h" +#include "adc-core.h" + +#include "s3c24xx.h" +#include "fb-core-s3c24xx.h" +#include "nand-core-s3c24xx.h" +#include "spi-core-s3c24xx.h" + +static struct map_desc s3c2443_iodesc[] __initdata __maybe_unused = { + 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, +}; + +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 */ + s3c24xx_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-s3c/s3c244x.c b/arch/arm/mach-s3c/s3c244x.c new file mode 100644 index 000000000..95df3491e --- /dev/null +++ b/arch/arm/mach-s3c/s3c244x.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2004-2006 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// Samsung S3C2440 and S3C2442 Mobile CPU support (not S3C2443) + +#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 "map.h" +#include <asm/irq.h> + +#include "regs-clock.h" +#include "regs-gpio.h" + +#include "devs.h" +#include "cpu.h" +#include "pm.h" + +#include "s3c24xx.h" +#include "nand-core-s3c24xx.h" +#include "regs-dsc-s3c24xx.h" + +static struct map_desc s3c244x_iodesc[] __initdata __maybe_unused = { + 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"; +} + +/* 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_SLEEP +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)); +} + +struct syscore_ops s3c244x_pm_syscore_ops = { + .suspend = s3c244x_suspend, + .resume = s3c244x_resume, +}; +#endif diff --git a/arch/arm/mach-s3c/s3c24xx.c b/arch/arm/mach-s3c/s3c24xx.c new file mode 100644 index 000000000..819a95364 --- /dev/null +++ b/arch/arm/mach-s3c/s3c24xx.c @@ -0,0 +1,687 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (c) 2004-2005 Simtec Electronics +// http://www.simtec.co.uk/products/SWLINUX/ +// Ben Dooks <ben@simtec.co.uk> +// +// Common code for S3C24XX machines + +#include <linux/dma-mapping.h> +#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/clk-s3c2410.h> +#include <linux/platform_data/dma-s3c24xx.h> +#include <linux/dmaengine.h> +#include <linux/clk/samsung.h> + +#include "hardware-s3c24xx.h" +#include "map.h" +#include "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 "regs-gpio.h" +#include "dma-s3c24xx.h" + +#include "cpu.h" +#include "devs.h" +#include "pwm-core.h" + +#include "s3c24xx.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 __maybe_unused = { + IODESC_ENT(GPIO), + IODESC_ENT(IRQ), + IODESC_ENT(MEMCTRL), + IODESC_ENT(UART) +}; + +/* read cpu identification 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) + 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 s3c24xx_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 s3c24xx_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), + }, +}; + +#define s3c24xx_device_dma_mask (*((u64[]) { DMA_BIT_MASK(32) })) + +#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 const struct dma_slave_map s3c2410_dma_slave_map[] = { + { "s3c2410-sdi", "rx-tx", (void *)DMACH_SDI }, + { "s3c2410-spi.0", "rx", (void *)DMACH_SPI0_RX }, + { "s3c2410-spi.0", "tx", (void *)DMACH_SPI0_TX }, + { "s3c2410-spi.1", "rx", (void *)DMACH_SPI1_RX }, + { "s3c2410-spi.1", "tx", (void *)DMACH_SPI1_TX }, + /* + * The DMA request source[1] (DMACH_UARTx_SRC2) are + * not used in the UART driver. + */ + { "s3c2410-uart.0", "rx", (void *)DMACH_UART0 }, + { "s3c2410-uart.0", "tx", (void *)DMACH_UART0 }, + { "s3c2410-uart.1", "rx", (void *)DMACH_UART1 }, + { "s3c2410-uart.1", "tx", (void *)DMACH_UART1 }, + { "s3c2410-uart.2", "rx", (void *)DMACH_UART2 }, + { "s3c2410-uart.2", "tx", (void *)DMACH_UART2 }, + { "s3c24xx-iis", "rx", (void *)DMACH_I2S_IN }, + { "s3c24xx-iis", "tx", (void *)DMACH_I2S_OUT }, + { "s3c-hsudc", "rx0", (void *)DMACH_USB_EP1 }, + { "s3c-hsudc", "tx0", (void *)DMACH_USB_EP1 }, + { "s3c-hsudc", "rx1", (void *)DMACH_USB_EP2 }, + { "s3c-hsudc", "tx1", (void *)DMACH_USB_EP2 }, + { "s3c-hsudc", "rx2", (void *)DMACH_USB_EP3 }, + { "s3c-hsudc", "tx2", (void *)DMACH_USB_EP3 }, + { "s3c-hsudc", "rx3", (void *)DMACH_USB_EP4 }, + { "s3c-hsudc", "tx3", (void *)DMACH_USB_EP4 } +}; + +static struct s3c24xx_dma_platdata s3c2410_dma_platdata = { + .num_phy_channels = 4, + .channels = s3c2410_dma_channels, + .num_channels = DMACH_MAX, + .slave_map = s3c2410_dma_slave_map, + .slavecnt = ARRAY_SIZE(s3c2410_dma_slave_map), +}; + +struct platform_device s3c2410_device_dma = { + .name = "s3c2410-dma", + .id = 0, + .num_resources = ARRAY_SIZE(s3c2410_dma_resource), + .resource = s3c2410_dma_resource, + .dev = { + .dma_mask = &s3c24xx_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .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 const struct dma_slave_map s3c2412_dma_slave_map[] = { + { "s3c2412-sdi", "rx-tx", (void *)DMACH_SDI }, + { "s3c2412-spi.0", "rx", (void *)DMACH_SPI0_RX }, + { "s3c2412-spi.0", "tx", (void *)DMACH_SPI0_TX }, + { "s3c2412-spi.1", "rx", (void *)DMACH_SPI1_RX }, + { "s3c2412-spi.1", "tx", (void *)DMACH_SPI1_TX }, + { "s3c2440-uart.0", "rx", (void *)DMACH_UART0 }, + { "s3c2440-uart.0", "tx", (void *)DMACH_UART0 }, + { "s3c2440-uart.1", "rx", (void *)DMACH_UART1 }, + { "s3c2440-uart.1", "tx", (void *)DMACH_UART1 }, + { "s3c2440-uart.2", "rx", (void *)DMACH_UART2 }, + { "s3c2440-uart.2", "tx", (void *)DMACH_UART2 }, + { "s3c2412-iis", "rx", (void *)DMACH_I2S_IN }, + { "s3c2412-iis", "tx", (void *)DMACH_I2S_OUT }, + { "s3c-hsudc", "rx0", (void *)DMACH_USB_EP1 }, + { "s3c-hsudc", "tx0", (void *)DMACH_USB_EP1 }, + { "s3c-hsudc", "rx1", (void *)DMACH_USB_EP2 }, + { "s3c-hsudc", "tx1", (void *)DMACH_USB_EP2 }, + { "s3c-hsudc", "rx2", (void *)DMACH_USB_EP3 }, + { "s3c-hsudc", "tx2", (void *)DMACH_USB_EP3 }, + { "s3c-hsudc", "rx3", (void *)DMACH_USB_EP4 }, + { "s3c-hsudc", "tx3", (void *)DMACH_USB_EP4 } +}; + +static struct s3c24xx_dma_platdata s3c2412_dma_platdata = { + .num_phy_channels = 4, + .channels = s3c2412_dma_channels, + .num_channels = DMACH_MAX, + .slave_map = s3c2412_dma_slave_map, + .slavecnt = ARRAY_SIZE(s3c2412_dma_slave_map), +}; + +struct platform_device s3c2412_device_dma = { + .name = "s3c2412-dma", + .id = 0, + .num_resources = ARRAY_SIZE(s3c2410_dma_resource), + .resource = s3c2410_dma_resource, + .dev = { + .dma_mask = &s3c24xx_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .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 const struct dma_slave_map s3c2440_dma_slave_map[] = { + /* TODO: DMACH_XD0 */ + /* TODO: DMACH_XD1 */ + { "s3c2440-sdi", "rx-tx", (void *)DMACH_SDI }, + { "s3c2410-spi.0", "rx", (void *)DMACH_SPI0 }, + { "s3c2410-spi.0", "tx", (void *)DMACH_SPI0 }, + { "s3c2410-spi.1", "rx", (void *)DMACH_SPI1 }, + { "s3c2410-spi.1", "tx", (void *)DMACH_SPI1 }, + { "s3c2440-uart.0", "rx", (void *)DMACH_UART0 }, + { "s3c2440-uart.0", "tx", (void *)DMACH_UART0 }, + { "s3c2440-uart.1", "rx", (void *)DMACH_UART1 }, + { "s3c2440-uart.1", "tx", (void *)DMACH_UART1 }, + { "s3c2440-uart.2", "rx", (void *)DMACH_UART2 }, + { "s3c2440-uart.2", "tx", (void *)DMACH_UART2 }, + { "s3c2440-uart.3", "rx", (void *)DMACH_UART3 }, + { "s3c2440-uart.3", "tx", (void *)DMACH_UART3 }, + /* TODO: DMACH_TIMER */ + { "s3c24xx-iis", "rx", (void *)DMACH_I2S_IN }, + { "s3c24xx-iis", "tx", (void *)DMACH_I2S_OUT }, + { "samsung-ac97", "rx", (void *)DMACH_PCM_IN }, + { "samsung-ac97", "tx", (void *)DMACH_PCM_OUT }, + { "samsung-ac97", "rx", (void *)DMACH_MIC_IN }, + { "s3c-hsudc", "rx0", (void *)DMACH_USB_EP1 }, + { "s3c-hsudc", "rx1", (void *)DMACH_USB_EP2 }, + { "s3c-hsudc", "rx2", (void *)DMACH_USB_EP3 }, + { "s3c-hsudc", "rx3", (void *)DMACH_USB_EP4 }, + { "s3c-hsudc", "tx0", (void *)DMACH_USB_EP1 }, + { "s3c-hsudc", "tx1", (void *)DMACH_USB_EP2 }, + { "s3c-hsudc", "tx2", (void *)DMACH_USB_EP3 }, + { "s3c-hsudc", "tx3", (void *)DMACH_USB_EP4 } +}; + +static struct s3c24xx_dma_platdata s3c2440_dma_platdata = { + .num_phy_channels = 4, + .channels = s3c2440_dma_channels, + .num_channels = DMACH_MAX, + .slave_map = s3c2440_dma_slave_map, + .slavecnt = ARRAY_SIZE(s3c2440_dma_slave_map), +}; + +struct platform_device s3c2440_device_dma = { + .name = "s3c2410-dma", + .id = 0, + .num_resources = ARRAY_SIZE(s3c2410_dma_resource), + .resource = s3c2410_dma_resource, + .dev = { + .dma_mask = &s3c24xx_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .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 const struct dma_slave_map s3c2443_dma_slave_map[] = { + { "s3c2440-sdi", "rx-tx", (void *)DMACH_SDI }, + { "s3c2443-spi.0", "rx", (void *)DMACH_SPI0_RX }, + { "s3c2443-spi.0", "tx", (void *)DMACH_SPI0_TX }, + { "s3c2443-spi.1", "rx", (void *)DMACH_SPI1_RX }, + { "s3c2443-spi.1", "tx", (void *)DMACH_SPI1_TX }, + { "s3c2440-uart.0", "rx", (void *)DMACH_UART0 }, + { "s3c2440-uart.0", "tx", (void *)DMACH_UART0 }, + { "s3c2440-uart.1", "rx", (void *)DMACH_UART1 }, + { "s3c2440-uart.1", "tx", (void *)DMACH_UART1 }, + { "s3c2440-uart.2", "rx", (void *)DMACH_UART2 }, + { "s3c2440-uart.2", "tx", (void *)DMACH_UART2 }, + { "s3c2440-uart.3", "rx", (void *)DMACH_UART3 }, + { "s3c2440-uart.3", "tx", (void *)DMACH_UART3 }, + { "s3c24xx-iis", "rx", (void *)DMACH_I2S_IN }, + { "s3c24xx-iis", "tx", (void *)DMACH_I2S_OUT }, +}; + +static struct s3c24xx_dma_platdata s3c2443_dma_platdata = { + .num_phy_channels = 6, + .channels = s3c2443_dma_channels, + .num_channels = DMACH_MAX, + .slave_map = s3c2443_dma_slave_map, + .slavecnt = ARRAY_SIZE(s3c2443_dma_slave_map), +}; + +struct platform_device s3c2443_device_dma = { + .name = "s3c2443-dma", + .id = 0, + .num_resources = ARRAY_SIZE(s3c2443_dma_resource), + .resource = s3c2443_dma_resource, + .dev = { + .dma_mask = &s3c24xx_device_dma_mask, + .coherent_dma_mask = DMA_BIT_MASK(32), + .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); +} +#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); +} +#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); +} +#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), +}; + +static struct s3c2410_clk_platform_data s3c_clk_platform_data = { + .modify_misccr = s3c2410_modify_misccr, +}; + +struct platform_device s3c2410_device_dclk = { + .name = "s3c2410-dclk", + .id = 0, + .num_resources = ARRAY_SIZE(s3c2410_dclk_resource), + .resource = s3c2410_dclk_resource, + .dev = { + .platform_data = &s3c_clk_platform_data, + }, +}; +#endif + +#ifndef CONFIG_COMPILE_TEST +#pragma message "The platform is deprecated and scheduled for removal. " \ + "Please reach to the maintainers of the platform " \ + "and linux-samsung-soc@vger.kernel.org if you still use it." \ + "Without such feedback, the platform will be removed after 2022." +#endif diff --git a/arch/arm/mach-s3c/s3c24xx.h b/arch/arm/mach-s3c/s3c24xx.h new file mode 100644 index 000000000..34dd4ac50 --- /dev/null +++ b/arch/arm/mach-s3c/s3c24xx.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Common Header for S3C24XX SoCs + */ + +#ifndef __ARCH_ARM_MACH_S3C24XX_COMMON_H +#define __ARCH_ARM_MACH_S3C24XX_COMMON_H __FILE__ + +#include <linux/reboot.h> +#include "irqs.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_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_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_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); +#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_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; + +enum s3c24xx_timer_mode { + S3C24XX_PWM0, + S3C24XX_PWM1, + S3C24XX_PWM2, + S3C24XX_PWM3, + S3C24XX_PWM4, +}; + +extern void __init s3c24xx_set_timer_source(enum s3c24xx_timer_mode event, + enum s3c24xx_timer_mode source); +extern void __init s3c24xx_timer_init(void); + +#endif /* __ARCH_ARM_MACH_S3C24XX_COMMON_H */ diff --git a/arch/arm/mach-s3c/s3c6400.c b/arch/arm/mach-s3c/s3c6400.c new file mode 100644 index 000000000..802f4fb74 --- /dev/null +++ b/arch/arm/mach-s3c/s3c6400.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2009 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ + +/* + * NOTE: Code in this file is not used when booting with Device Tree support. + */ + +#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/io.h> +#include <linux/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/irq.h> + +#include "regs-clock.h" + +#include "cpu.h" +#include "devs.h" +#include "sdhci.h" +#include "iic-core.h" + +#include "s3c64xx.h" +#include "onenand-core-s3c64xx.h" + +void __init s3c6400_map_io(void) +{ + /* setup SDHCI */ + + s3c6400_default_sdhci0(); + s3c6400_default_sdhci1(); + s3c6400_default_sdhci2(); + + /* the i2c devices are directly compatible with s3c2440 */ + s3c_i2c0_setname("s3c2440-i2c"); + + s3c_device_nand.name = "s3c6400-nand"; + + s3c_onenand_setname("s3c6400-onenand"); + s3c64xx_onenand1_setname("s3c6400-onenand"); +} + +void __init s3c6400_init_irq(void) +{ + /* VIC0 does not have IRQS 5..7, + * VIC1 is fully populated. */ + s3c64xx_init_irq(~0 & ~(0xf << 5), ~0); +} + +static struct bus_type s3c6400_subsys = { + .name = "s3c6400-core", + .dev_name = "s3c6400-core", +}; + +static struct device s3c6400_dev = { + .bus = &s3c6400_subsys, +}; + +static int __init s3c6400_core_init(void) +{ + /* Not applicable when using DT. */ + if (of_have_populated_dt() || soc_is_s3c64xx()) + return 0; + + return subsys_system_register(&s3c6400_subsys, NULL); +} + +core_initcall(s3c6400_core_init); + +int __init s3c6400_init(void) +{ + printk("S3C6400: Initialising architecture\n"); + + return device_register(&s3c6400_dev); +} diff --git a/arch/arm/mach-s3c/s3c6410.c b/arch/arm/mach-s3c/s3c6410.c new file mode 100644 index 000000000..dae17d5fd --- /dev/null +++ b/arch/arm/mach-s3c/s3c6410.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Simtec Electronics +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ + +/* + * NOTE: Code in this file is not used when booting with Device Tree support. + */ + +#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/io.h> +#include <linux/device.h> +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/irq.h> + +#include <linux/soc/samsung/s3c-pm.h> +#include "regs-clock.h" + +#include "cpu.h" +#include "devs.h" +#include "sdhci.h" +#include "adc-core.h" +#include "iic-core.h" + +#include "ata-core-s3c64xx.h" +#include "s3c64xx.h" +#include "onenand-core-s3c64xx.h" + +void __init s3c6410_map_io(void) +{ + /* initialise device information early */ + s3c6410_default_sdhci0(); + s3c6410_default_sdhci1(); + s3c6410_default_sdhci2(); + + /* the i2c devices are directly compatible with s3c2440 */ + s3c_i2c0_setname("s3c2440-i2c"); + s3c_i2c1_setname("s3c2440-i2c"); + + s3c_adc_setname("s3c64xx-adc"); + s3c_device_nand.name = "s3c6400-nand"; + s3c_onenand_setname("s3c6410-onenand"); + s3c64xx_onenand1_setname("s3c6410-onenand"); + s3c_cfcon_setname("s3c64xx-pata"); +} + +void __init s3c6410_init_irq(void) +{ + /* VIC0 is missing IRQ7, VIC1 is fully populated. */ + s3c64xx_init_irq(~0 & ~(1 << 7), ~0); +} + +struct bus_type s3c6410_subsys = { + .name = "s3c6410-core", + .dev_name = "s3c6410-core", +}; + +static struct device s3c6410_dev = { + .bus = &s3c6410_subsys, +}; + +static int __init s3c6410_core_init(void) +{ + /* Not applicable when using DT. */ + if (of_have_populated_dt() || !soc_is_s3c64xx()) + return 0; + + return subsys_system_register(&s3c6410_subsys, NULL); +} + +core_initcall(s3c6410_core_init); + +int __init s3c6410_init(void) +{ + printk("S3C6410: Initialising architecture\n"); + + return device_register(&s3c6410_dev); +} diff --git a/arch/arm/mach-s3c/s3c64xx.c b/arch/arm/mach-s3c/s3c64xx.c new file mode 100644 index 000000000..dce2b0e95 --- /dev/null +++ b/arch/arm/mach-s3c/s3c64xx.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2011 Samsung Electronics Co., Ltd. +// http://www.samsung.com +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Common Codes for S3C64XX machines + +/* + * NOTE: Code in this file is not used when booting with Device Tree support. + */ + +#include <linux/kernel.h> +#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 <linux/platform_device.h> +#include <linux/reboot.h> +#include <linux/io.h> +#include <linux/clk/samsung.h> +#include <linux/dma-mapping.h> +#include <linux/irq.h> +#include <linux/gpio.h> +#include <linux/irqchip/arm-vic.h> +#include <clocksource/samsung_pwm.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/system_misc.h> + +#include "map.h" +#include "irqs.h" +#include "regs-gpio.h" +#include "gpio-samsung.h" + +#include "cpu.h" +#include "devs.h" +#include "pm.h" +#include "gpio-cfg.h" +#include "pwm-core.h" +#include "regs-irqtype.h" +#include "s3c64xx.h" +#include "irq-uart-s3c64xx.h" + +/* External clock frequency */ +static unsigned long xtal_f __ro_after_init = 12000000; +static unsigned long xusbxti_f __ro_after_init = 48000000; + +void __init s3c64xx_set_xtal_freq(unsigned long freq) +{ + xtal_f = freq; +} + +void __init s3c64xx_set_xusbxti_freq(unsigned long freq) +{ + xusbxti_f = freq; +} + +/* uart registration process */ + +static void __init s3c64xx_init_uarts(struct s3c2410_uartcfg *cfg, int no) +{ + s3c24xx_init_uartdevs("s3c6400-uart", s3c64xx_uart_resources, cfg, no); +} + +/* table of supported CPUs */ + +static const char name_s3c6400[] = "S3C6400"; +static const char name_s3c6410[] = "S3C6410"; + +static struct cpu_table cpu_ids[] __initdata = { + { + .idcode = S3C6400_CPU_ID, + .idmask = S3C64XX_CPU_MASK, + .map_io = s3c6400_map_io, + .init_uarts = s3c64xx_init_uarts, + .init = s3c6400_init, + .name = name_s3c6400, + }, { + .idcode = S3C6410_CPU_ID, + .idmask = S3C64XX_CPU_MASK, + .map_io = s3c6410_map_io, + .init_uarts = s3c64xx_init_uarts, + .init = s3c6410_init, + .name = name_s3c6410, + }, +}; + +/* minimal IO mapping */ + +/* + * note, for the boot process to work we have to keep the UART + * virtual address aligned to an 1MiB boundary for the L1 + * mapping the head code makes. We keep the UART virtual address + * aligned and add in the offset when we load the value here. + */ +#define UART_OFFS (S3C_PA_UART & 0xfffff) + +static struct map_desc s3c_iodesc[] __initdata = { + { + .virtual = (unsigned long)S3C_VA_SYS, + .pfn = __phys_to_pfn(S3C64XX_PA_SYSCON), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_MEM, + .pfn = __phys_to_pfn(S3C64XX_PA_SROM), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)(S3C_VA_UART + UART_OFFS), + .pfn = __phys_to_pfn(S3C_PA_UART), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)VA_VIC0, + .pfn = __phys_to_pfn(S3C64XX_PA_VIC0), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)VA_VIC1, + .pfn = __phys_to_pfn(S3C64XX_PA_VIC1), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_TIMER, + .pfn = __phys_to_pfn(S3C_PA_TIMER), + .length = SZ_16K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C64XX_VA_GPIO, + .pfn = __phys_to_pfn(S3C64XX_PA_GPIO), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C64XX_VA_MODEM, + .pfn = __phys_to_pfn(S3C64XX_PA_MODEM), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_WATCHDOG, + .pfn = __phys_to_pfn(S3C64XX_PA_WATCHDOG), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S3C_VA_USB_HSPHY, + .pfn = __phys_to_pfn(S3C64XX_PA_USB_HSPHY), + .length = SZ_1K, + .type = MT_DEVICE, + }, +}; + +static struct bus_type s3c64xx_subsys = { + .name = "s3c64xx-core", + .dev_name = "s3c64xx-core", +}; + +static struct device s3c64xx_dev = { + .bus = &s3c64xx_subsys, +}; + +static struct samsung_pwm_variant s3c64xx_pwm_variant = { + .bits = 32, + .div_base = 0, + .has_tint_cstat = true, + .tclk_mask = (1 << 7) | (1 << 6) | (1 << 5), +}; + +void __init s3c64xx_set_timer_source(enum s3c64xx_timer_mode event, + enum s3c64xx_timer_mode source) +{ + s3c64xx_pwm_variant.output_mask = BIT(SAMSUNG_PWM_NUM) - 1; + s3c64xx_pwm_variant.output_mask &= ~(BIT(event) | BIT(source)); +} + +void __init s3c64xx_timer_init(void) +{ + unsigned int timer_irqs[SAMSUNG_PWM_NUM] = { + IRQ_TIMER0_VIC, IRQ_TIMER1_VIC, IRQ_TIMER2_VIC, + IRQ_TIMER3_VIC, IRQ_TIMER4_VIC, + }; + + samsung_pwm_clocksource_init(S3C_VA_TIMER, + timer_irqs, &s3c64xx_pwm_variant); +} + +/* read cpu identification code */ + +void __init s3c64xx_init_io(struct map_desc *mach_desc, int size) +{ + /* initialise the io descriptors we need for initialisation */ + iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc)); + iotable_init(mach_desc, size); + + /* detect cpu id */ + s3c64xx_init_cpu(); + + s3c_init_cpu(samsung_cpu_id, cpu_ids, ARRAY_SIZE(cpu_ids)); + + samsung_pwm_set_platdata(&s3c64xx_pwm_variant); +} + +static __init int s3c64xx_dev_init(void) +{ + /* Not applicable when using DT. */ + if (of_have_populated_dt() || !soc_is_s3c64xx()) + return 0; + + subsys_system_register(&s3c64xx_subsys, NULL); + return device_register(&s3c64xx_dev); +} +core_initcall(s3c64xx_dev_init); + +/* + * setup the sources the vic should advertise resume + * for, even though it is not doing the wake + * (set_irq_wake needs to be valid) + */ +#define IRQ_VIC0_RESUME (1 << (IRQ_RTC_TIC - IRQ_VIC0_BASE)) +#define IRQ_VIC1_RESUME (1 << (IRQ_RTC_ALARM - IRQ_VIC1_BASE) | \ + 1 << (IRQ_PENDN - IRQ_VIC1_BASE) | \ + 1 << (IRQ_HSMMC0 - IRQ_VIC1_BASE) | \ + 1 << (IRQ_HSMMC1 - IRQ_VIC1_BASE) | \ + 1 << (IRQ_HSMMC2 - IRQ_VIC1_BASE)) + +void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid) +{ + s3c64xx_clk_init(NULL, xtal_f, xusbxti_f, soc_is_s3c6400(), S3C_VA_SYS); + + printk(KERN_DEBUG "%s: initialising interrupts\n", __func__); + + /* initialise the pair of VICs */ + vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, IRQ_VIC0_RESUME); + vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, IRQ_VIC1_RESUME); +} + +#define eint_offset(irq) ((irq) - IRQ_EINT(0)) +#define eint_irq_to_bit(irq) ((u32)(1 << eint_offset(irq))) + +static inline void s3c_irq_eint_mask(struct irq_data *data) +{ + u32 mask; + + mask = __raw_readl(S3C64XX_EINT0MASK); + mask |= (u32)data->chip_data; + __raw_writel(mask, S3C64XX_EINT0MASK); +} + +static void s3c_irq_eint_unmask(struct irq_data *data) +{ + u32 mask; + + mask = __raw_readl(S3C64XX_EINT0MASK); + mask &= ~((u32)data->chip_data); + __raw_writel(mask, S3C64XX_EINT0MASK); +} + +static inline void s3c_irq_eint_ack(struct irq_data *data) +{ + __raw_writel((u32)data->chip_data, S3C64XX_EINT0PEND); +} + +static void s3c_irq_eint_maskack(struct irq_data *data) +{ + /* compiler should in-line these */ + s3c_irq_eint_mask(data); + s3c_irq_eint_ack(data); +} + +static int s3c_irq_eint_set_type(struct irq_data *data, unsigned int type) +{ + int offs = eint_offset(data->irq); + int pin, pin_val; + int shift; + u32 ctrl, mask; + u32 newvalue = 0; + void __iomem *reg; + + if (offs > 27) + return -EINVAL; + + if (offs <= 15) + reg = S3C64XX_EINT0CON0; + else + reg = S3C64XX_EINT0CON1; + + switch (type) { + case IRQ_TYPE_NONE: + printk(KERN_WARNING "No edge setting!\n"); + break; + + case IRQ_TYPE_EDGE_RISING: + newvalue = S3C2410_EXTINT_RISEEDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + newvalue = S3C2410_EXTINT_FALLEDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + newvalue = S3C2410_EXTINT_BOTHEDGE; + break; + + case IRQ_TYPE_LEVEL_LOW: + newvalue = S3C2410_EXTINT_LOWLEV; + break; + + case IRQ_TYPE_LEVEL_HIGH: + newvalue = S3C2410_EXTINT_HILEV; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -1; + } + + if (offs <= 15) + shift = (offs / 2) * 4; + else + shift = ((offs - 16) / 2) * 4; + mask = 0x7 << shift; + + ctrl = __raw_readl(reg); + ctrl &= ~mask; + ctrl |= newvalue << shift; + __raw_writel(ctrl, reg); + + /* set the GPIO pin appropriately */ + + if (offs < 16) { + pin = S3C64XX_GPN(offs); + pin_val = S3C_GPIO_SFN(2); + } else if (offs < 23) { + pin = S3C64XX_GPL(offs + 8 - 16); + pin_val = S3C_GPIO_SFN(3); + } else { + pin = S3C64XX_GPM(offs - 23); + pin_val = S3C_GPIO_SFN(3); + } + + s3c_gpio_cfgpin(pin, pin_val); + + return 0; +} + +static struct irq_chip s3c_irq_eint = { + .name = "s3c-eint", + .irq_mask = s3c_irq_eint_mask, + .irq_unmask = s3c_irq_eint_unmask, + .irq_mask_ack = s3c_irq_eint_maskack, + .irq_ack = s3c_irq_eint_ack, + .irq_set_type = s3c_irq_eint_set_type, + .irq_set_wake = s3c_irqext_wake, +}; + +/* s3c_irq_demux_eint + * + * This function demuxes the IRQ from the group0 external interrupts, + * from IRQ_EINT(0) to IRQ_EINT(27). It is designed to be inlined into + * the specific handlers s3c_irq_demux_eintX_Y. + */ +static inline void s3c_irq_demux_eint(unsigned int start, unsigned int end) +{ + u32 status = __raw_readl(S3C64XX_EINT0PEND); + u32 mask = __raw_readl(S3C64XX_EINT0MASK); + unsigned int irq; + + status &= ~mask; + status >>= start; + status &= (1 << (end - start + 1)) - 1; + + for (irq = IRQ_EINT(start); irq <= IRQ_EINT(end); irq++) { + if (status & 1) + generic_handle_irq(irq); + + status >>= 1; + } +} + +static void s3c_irq_demux_eint0_3(struct irq_desc *desc) +{ + s3c_irq_demux_eint(0, 3); +} + +static void s3c_irq_demux_eint4_11(struct irq_desc *desc) +{ + s3c_irq_demux_eint(4, 11); +} + +static void s3c_irq_demux_eint12_19(struct irq_desc *desc) +{ + s3c_irq_demux_eint(12, 19); +} + +static void s3c_irq_demux_eint20_27(struct irq_desc *desc) +{ + s3c_irq_demux_eint(20, 27); +} + +static int __init s3c64xx_init_irq_eint(void) +{ + int irq; + + /* On DT-enabled systems EINTs are handled by pinctrl-s3c64xx driver. */ + if (of_have_populated_dt() || !soc_is_s3c64xx()) + return -ENODEV; + + for (irq = IRQ_EINT(0); irq <= IRQ_EINT(27); irq++) { + irq_set_chip_and_handler(irq, &s3c_irq_eint, handle_level_irq); + irq_set_chip_data(irq, (void *)eint_irq_to_bit(irq)); + irq_clear_status_flags(irq, IRQ_NOREQUEST); + } + + irq_set_chained_handler(IRQ_EINT0_3, s3c_irq_demux_eint0_3); + irq_set_chained_handler(IRQ_EINT4_11, s3c_irq_demux_eint4_11); + irq_set_chained_handler(IRQ_EINT12_19, s3c_irq_demux_eint12_19); + irq_set_chained_handler(IRQ_EINT20_27, s3c_irq_demux_eint20_27); + + return 0; +} +arch_initcall(s3c64xx_init_irq_eint); + +#ifndef CONFIG_COMPILE_TEST +#pragma message "The platform is deprecated and scheduled for removal. " \ + "Please reach to the maintainers of the platform " \ + "and linux-samsung-soc@vger.kernel.org if you still use it." \ + "Without such feedback, the platform will be removed after 2024." +#endif diff --git a/arch/arm/mach-s3c/s3c64xx.h b/arch/arm/mach-s3c/s3c64xx.h new file mode 100644 index 000000000..92258e4f6 --- /dev/null +++ b/arch/arm/mach-s3c/s3c64xx.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * Common Header for S3C64XX machines + */ + +#ifndef __ARCH_ARM_MACH_S3C64XX_COMMON_H +#define __ARCH_ARM_MACH_S3C64XX_COMMON_H + +#include <linux/reboot.h> + +void s3c64xx_init_irq(u32 vic0, u32 vic1); +void s3c64xx_init_io(struct map_desc *mach_desc, int size); + +struct device_node; +void s3c64xx_set_xtal_freq(unsigned long freq); +void s3c64xx_set_xusbxti_freq(unsigned long freq); + +#ifdef CONFIG_CPU_S3C6400 + +extern int s3c6400_init(void); +extern void s3c6400_init_irq(void); +extern void s3c6400_map_io(void); + +#else +#define s3c6400_map_io NULL +#define s3c6400_init NULL +#endif + +#ifdef CONFIG_CPU_S3C6410 + +extern int s3c6410_init(void); +extern void s3c6410_init_irq(void); +extern void s3c6410_map_io(void); + +#else +#define s3c6410_map_io NULL +#define s3c6410_init NULL +#endif + +#ifdef CONFIG_S3C64XX_PL080 +extern struct pl08x_platform_data s3c64xx_dma0_plat_data; +extern struct pl08x_platform_data s3c64xx_dma1_plat_data; +#endif + +/* Samsung HR-Timer Clock mode */ +enum s3c64xx_timer_mode { + S3C64XX_PWM0, + S3C64XX_PWM1, + S3C64XX_PWM2, + S3C64XX_PWM3, + S3C64XX_PWM4, +}; + +extern void __init s3c64xx_set_timer_source(enum s3c64xx_timer_mode event, + enum s3c64xx_timer_mode source); +extern void __init s3c64xx_timer_init(void); + +#endif /* __ARCH_ARM_MACH_S3C64XX_COMMON_H */ diff --git a/arch/arm/mach-s3c/sdhci.h b/arch/arm/mach-s3c/sdhci.h new file mode 100644 index 000000000..9f9d419e5 --- /dev/null +++ b/arch/arm/mach-s3c/sdhci.h @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * http://www.samsung.com + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * S3C Platform - SDHCI (HSMMC) platform data definitions + */ + +#ifndef __PLAT_S3C_SDHCI_H +#define __PLAT_S3C_SDHCI_H __FILE__ + +#include <linux/platform_data/mmc-sdhci-s3c.h> +#include "devs.h" + +/* s3c_sdhci_set_platdata() - common helper for setting SDHCI platform data + * @pd: The default platform data for this device. + * @set: Pointer to the platform data to fill in. + */ +extern void s3c_sdhci_set_platdata(struct s3c_sdhci_platdata *pd, + struct s3c_sdhci_platdata *set); + +/** + * s3c_sdhci0_set_platdata - Set platform data for S3C SDHCI device. + * @pd: Platform data to register to device. + * + * Register the given platform data for use withe S3C SDHCI device. + * The call will copy the platform data, so the board definitions can + * make the structure itself __initdata. + */ +extern void s3c_sdhci0_set_platdata(struct s3c_sdhci_platdata *pd); +extern void s3c_sdhci1_set_platdata(struct s3c_sdhci_platdata *pd); +extern void s3c_sdhci2_set_platdata(struct s3c_sdhci_platdata *pd); +extern void s3c_sdhci3_set_platdata(struct s3c_sdhci_platdata *pd); + +/* Default platform data, exported so that per-cpu initialisation can + * set the correct one when there are more than one cpu type selected. +*/ + +extern struct s3c_sdhci_platdata s3c_hsmmc0_def_platdata; +extern struct s3c_sdhci_platdata s3c_hsmmc1_def_platdata; +extern struct s3c_sdhci_platdata s3c_hsmmc2_def_platdata; +extern struct s3c_sdhci_platdata s3c_hsmmc3_def_platdata; + +/* Helper function availability */ + +extern void s3c2416_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s3c2416_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *, int w); +extern void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *, int w); + +/* S3C2416 SDHCI setup */ + +#ifdef CONFIG_S3C2416_SETUP_SDHCI +static inline void s3c2416_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s3c2416_setup_sdhci0_cfg_gpio; +#endif /* CONFIG_S3C_DEV_HSMMC */ +} + +static inline void s3c2416_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s3c2416_setup_sdhci1_cfg_gpio; +#endif /* CONFIG_S3C_DEV_HSMMC1 */ +} + +#else +static inline void s3c2416_default_sdhci0(void) { } +static inline void s3c2416_default_sdhci1(void) { } + +#endif /* CONFIG_S3C2416_SETUP_SDHCI */ + +/* S3C64XX SDHCI setup */ + +#ifdef CONFIG_S3C64XX_SETUP_SDHCI +static inline void s3c6400_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s3c6400_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s3c6400_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio; +#endif +} + +static inline void s3c6410_default_sdhci0(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC + s3c_hsmmc0_def_platdata.cfg_gpio = s3c64xx_setup_sdhci0_cfg_gpio; +#endif +} + +static inline void s3c6410_default_sdhci1(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC1 + s3c_hsmmc1_def_platdata.cfg_gpio = s3c64xx_setup_sdhci1_cfg_gpio; +#endif +} + +static inline void s3c6410_default_sdhci2(void) +{ +#ifdef CONFIG_S3C_DEV_HSMMC2 + s3c_hsmmc2_def_platdata.cfg_gpio = s3c64xx_setup_sdhci2_cfg_gpio; +#endif +} + +#else +static inline void s3c6410_default_sdhci0(void) { } +static inline void s3c6410_default_sdhci1(void) { } +static inline void s3c6410_default_sdhci2(void) { } +static inline void s3c6400_default_sdhci0(void) { } +static inline void s3c6400_default_sdhci1(void) { } +static inline void s3c6400_default_sdhci2(void) { } + +#endif /* CONFIG_S3C64XX_SETUP_SDHCI */ + +static inline void s3c_sdhci_setname(int id, char *name) +{ + switch (id) { +#ifdef CONFIG_S3C_DEV_HSMMC + case 0: + s3c_device_hsmmc0.name = name; + break; +#endif +#ifdef CONFIG_S3C_DEV_HSMMC1 + case 1: + s3c_device_hsmmc1.name = name; + break; +#endif +#ifdef CONFIG_S3C_DEV_HSMMC2 + case 2: + s3c_device_hsmmc2.name = name; + break; +#endif +#ifdef CONFIG_S3C_DEV_HSMMC3 + case 3: + s3c_device_hsmmc3.name = name; + break; +#endif + default: + break; + } +} +#endif /* __PLAT_S3C_SDHCI_H */ diff --git a/arch/arm/mach-s3c/setup-fb-24bpp-s3c64xx.c b/arch/arm/mach-s3c/setup-fb-24bpp-s3c64xx.c new file mode 100644 index 000000000..cfa34b55c --- /dev/null +++ b/arch/arm/mach-s3c/setup-fb-24bpp-s3c64xx.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Base S3C64XX setup information for 24bpp LCD framebuffer + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/fb.h> +#include <linux/gpio.h> + +#include "fb.h" +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +void s3c64xx_fb_gpio_setup_24bpp(void) +{ + s3c_gpio_cfgrange_nopull(S3C64XX_GPI(0), 16, S3C_GPIO_SFN(2)); + s3c_gpio_cfgrange_nopull(S3C64XX_GPJ(0), 12, S3C_GPIO_SFN(2)); +} diff --git a/arch/arm/mach-s3c/setup-i2c-s3c24xx.c b/arch/arm/mach-s3c/setup-i2c-s3c24xx.c new file mode 100644 index 000000000..0d88366b2 --- /dev/null +++ b/arch/arm/mach-s3c/setup-i2c-s3c24xx.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// S3C24XX Base setup for i2c device + +#include <linux/kernel.h> +#include <linux/gpio.h> + +struct platform_device; + +#include <linux/platform_data/i2c-s3c2410.h> + +#include "gpio-cfg.h" +#include "regs-gpio.h" +#include "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-s3c/setup-i2c0-s3c64xx.c b/arch/arm/mach-s3c/setup-i2c0-s3c64xx.c new file mode 100644 index 000000000..a6ef8d2bc --- /dev/null +++ b/arch/arm/mach-s3c/setup-i2c0-s3c64xx.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Base S3C64XX I2C bus 0 gpio configuration + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/gpio.h> + +struct platform_device; /* don't need the contents */ + +#include <linux/platform_data/i2c-s3c2410.h> +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +void s3c_i2c0_cfg_gpio(struct platform_device *dev) +{ + s3c_gpio_cfgall_range(S3C64XX_GPB(5), 2, + S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); +} diff --git a/arch/arm/mach-s3c/setup-i2c1-s3c64xx.c b/arch/arm/mach-s3c/setup-i2c1-s3c64xx.c new file mode 100644 index 000000000..0fe37363d --- /dev/null +++ b/arch/arm/mach-s3c/setup-i2c1-s3c64xx.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Openmoko, Inc. +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Base S3C64XX I2C bus 1 gpio configuration + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/gpio.h> + +struct platform_device; /* don't need the contents */ + +#include <linux/platform_data/i2c-s3c2410.h> +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +void s3c_i2c1_cfg_gpio(struct platform_device *dev) +{ + s3c_gpio_cfgall_range(S3C64XX_GPB(2), 2, + S3C_GPIO_SFN(6), S3C_GPIO_PULL_UP); +} diff --git a/arch/arm/mach-s3c/setup-ide-s3c64xx.c b/arch/arm/mach-s3c/setup-ide-s3c64xx.c new file mode 100644 index 000000000..f11f2b02e --- /dev/null +++ b/arch/arm/mach-s3c/setup-ide-s3c64xx.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2010 Samsung Electronics Co., Ltd. +// http://www.samsung.com/ +// +// S3C64XX setup information for IDE + +#include <linux/kernel.h> +#include <linux/gpio.h> +#include <linux/io.h> + +#include <linux/platform_data/ata-samsung_cf.h> + +#include "map.h" +#include "regs-clock.h" +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +void s3c64xx_ide_setup_gpio(void) +{ + u32 reg; + + reg = readl(S3C_MEM_SYS_CFG) & (~0x3f); + + /* Independent CF interface, CF chip select configuration */ + writel(reg | MEM_SYS_CFG_INDEP_CF | + MEM_SYS_CFG_EBI_FIX_PRI_CFCON, S3C_MEM_SYS_CFG); + + s3c_gpio_cfgpin(S3C64XX_GPB(4), S3C_GPIO_SFN(4)); + + /* Set XhiDATA[15:0] pins as CF Data[15:0] */ + s3c_gpio_cfgpin_range(S3C64XX_GPK(0), 16, S3C_GPIO_SFN(5)); + + /* Set XhiADDR[2:0] pins as CF ADDR[2:0] */ + s3c_gpio_cfgpin_range(S3C64XX_GPL(0), 3, S3C_GPIO_SFN(6)); + + /* Set Xhi ctrl pins as CF ctrl pins(IORDY, IOWR, IORD, CE[0:1]) */ + s3c_gpio_cfgpin(S3C64XX_GPM(5), S3C_GPIO_SFN(1)); + s3c_gpio_cfgpin_range(S3C64XX_GPM(0), 5, S3C_GPIO_SFN(6)); +} diff --git a/arch/arm/mach-s3c/setup-keypad-s3c64xx.c b/arch/arm/mach-s3c/setup-keypad-s3c64xx.c new file mode 100644 index 000000000..8463ad37c --- /dev/null +++ b/arch/arm/mach-s3c/setup-keypad-s3c64xx.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2010 Samsung Electronics Co., Ltd. +// http://www.samsung.com/ +// +// GPIO configuration for S3C64XX KeyPad device + +#include <linux/gpio.h> +#include "gpio-cfg.h" +#include "keypad.h" +#include "gpio-samsung.h" + +void samsung_keypad_cfg_gpio(unsigned int rows, unsigned int cols) +{ + /* Set all the necessary GPK pins to special-function 3: KP_ROW[x] */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPK(8), rows, S3C_GPIO_SFN(3)); + + /* Set all the necessary GPL pins to special-function 3: KP_COL[x] */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPL(0), cols, S3C_GPIO_SFN(3)); +} diff --git a/arch/arm/mach-s3c/setup-sdhci-gpio-s3c24xx.c b/arch/arm/mach-s3c/setup-sdhci-gpio-s3c24xx.c new file mode 100644 index 000000000..02131b3a7 --- /dev/null +++ b/arch/arm/mach-s3c/setup-sdhci-gpio-s3c24xx.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 + +#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 "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" +#include "sdhci.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-s3c/setup-sdhci-gpio-s3c64xx.c b/arch/arm/mach-s3c/setup-sdhci-gpio-s3c64xx.c new file mode 100644 index 000000000..646ff949a --- /dev/null +++ b/arch/arm/mach-s3c/setup-sdhci-gpio-s3c64xx.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// S3C64XX - Helper functions for setting up SDHCI device(s) GPIO (HSMMC) + +#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 "gpio-cfg.h" +#include "sdhci.h" +#include "gpio-samsung.h" + +void s3c64xx_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) +{ + struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; + + /* Set all the necessary GPG pins to special-function 2 */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPG(0), 2 + width, S3C_GPIO_SFN(2)); + + if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { + s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(2)); + } +} + +void s3c64xx_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) +{ + struct s3c_sdhci_platdata *pdata = dev->dev.platform_data; + + /* Set all the necessary GPH pins to special-function 2 */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPH(0), 2 + width, S3C_GPIO_SFN(2)); + + if (pdata->cd_type == S3C_SDHCI_CD_INTERNAL) { + s3c_gpio_setpull(S3C64XX_GPG(6), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S3C64XX_GPG(6), S3C_GPIO_SFN(3)); + } +} + +void s3c64xx_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) +{ + /* Set all the necessary GPH pins to special-function 3 */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPH(6), width, S3C_GPIO_SFN(3)); + + /* Set all the necessary GPC pins to special-function 3 */ + s3c_gpio_cfgrange_nopull(S3C64XX_GPC(4), 2, S3C_GPIO_SFN(3)); +} diff --git a/arch/arm/mach-s3c/setup-spi-s3c24xx.c b/arch/arm/mach-s3c/setup-spi-s3c24xx.c new file mode 100644 index 000000000..93fa1bbc9 --- /dev/null +++ b/arch/arm/mach-s3c/setup-spi-s3c24xx.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// HS-SPI device setup for S3C2443/S3C2416 +// +// Copyright (C) 2011 Samsung Electronics Ltd. +// http://www.samsung.com/ + +#include <linux/gpio.h> +#include <linux/platform_device.h> + +#include "gpio-cfg.h" + +#include "hardware-s3c24xx.h" +#include "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-s3c/setup-spi-s3c64xx.c b/arch/arm/mach-s3c/setup-spi-s3c64xx.c new file mode 100644 index 000000000..497aff71c --- /dev/null +++ b/arch/arm/mach-s3c/setup-spi-s3c64xx.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2011 Samsung Electronics Ltd. +// http://www.samsung.com/ + +#include <linux/gpio.h> +#include <linux/platform_data/spi-s3c64xx.h> +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +#ifdef CONFIG_S3C64XX_DEV_SPI0 +int s3c64xx_spi0_cfg_gpio(void) +{ + s3c_gpio_cfgall_range(S3C64XX_GPC(0), 3, + S3C_GPIO_SFN(2), S3C_GPIO_PULL_UP); + return 0; +} +#endif diff --git a/arch/arm/mach-s3c/setup-ts-s3c24xx.c b/arch/arm/mach-s3c/setup-ts-s3c24xx.c new file mode 100644 index 000000000..57363eaeb --- /dev/null +++ b/arch/arm/mach-s3c/setup-ts-s3c24xx.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2010 Samsung Electronics Co., Ltd. +// http://www.samsung.com/ +// +// Based on S3C24XX setup for i2c device + +#include <linux/kernel.h> +#include <linux/gpio.h> + +struct platform_device; /* don't need the contents */ + +#include <linux/platform_data/touchscreen-s3c2410.h> + +#include "gpio-cfg.h" +#include "gpio-samsung.h" + +/** + * s3c24xx_ts_cfg_gpio - configure gpio for s3c2410 systems + * @dev: Device to configure GPIO for (ignored) + * + * 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-s3c/setup-usb-phy-s3c64xx.c b/arch/arm/mach-s3c/setup-usb-phy-s3c64xx.c new file mode 100644 index 000000000..500d105af --- /dev/null +++ b/arch/arm/mach-s3c/setup-usb-phy-s3c64xx.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright (C) 2011 Samsung Electronics Co.Ltd +// Author: Joonyoung Shim <jy0922.shim@samsung.com> + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include "map.h" +#include "cpu.h" +#include "usb-phy.h" + +#include "regs-sys-s3c64xx.h" +#include "regs-usb-hsotg-phy-s3c64xx.h" + +enum samsung_usb_phy_type { + USB_PHY_TYPE_DEVICE, + USB_PHY_TYPE_HOST, +}; + +static int s3c_usb_otgphy_init(struct platform_device *pdev) +{ + struct clk *xusbxti; + u32 phyclk; + + writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS); + + /* set clock frequency for PLL */ + phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK; + + xusbxti = clk_get(&pdev->dev, "xusbxti"); + if (!IS_ERR(xusbxti)) { + switch (clk_get_rate(xusbxti)) { + case 12 * MHZ: + phyclk |= S3C_PHYCLK_CLKSEL_12M; + break; + case 24 * MHZ: + phyclk |= S3C_PHYCLK_CLKSEL_24M; + break; + default: + case 48 * MHZ: + /* default reference clock */ + break; + } + clk_put(xusbxti); + } + + /* TODO: select external clock/oscillator */ + writel(phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK); + + /* set to normal OTG PHY */ + writel((readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR); + mdelay(1); + + /* reset OTG PHY and Link */ + writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK, + S3C_RSTCON); + udelay(20); /* at-least 10uS */ + writel(0, S3C_RSTCON); + + return 0; +} + +static int s3c_usb_otgphy_exit(struct platform_device *pdev) +{ + writel((readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN | + S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR); + + writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS); + + return 0; +} + +int s3c_usb_phy_init(struct platform_device *pdev, int type) +{ + if (type == USB_PHY_TYPE_DEVICE) + return s3c_usb_otgphy_init(pdev); + + return -EINVAL; +} + +int s3c_usb_phy_exit(struct platform_device *pdev, int type) +{ + if (type == USB_PHY_TYPE_DEVICE) + return s3c_usb_otgphy_exit(pdev); + + return -EINVAL; +} diff --git a/arch/arm/mach-s3c/simtec-audio.c b/arch/arm/mach-s3c/simtec-audio.c new file mode 100644 index 000000000..487485bcc --- /dev/null +++ b/arch/arm/mach-s3c/simtec-audio.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2009 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk> +// +// Audio setup for various Simtec S3C24XX implementations + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/io.h> + +#include "regs-gpio.h" +#include "gpio-samsung.h" +#include "gpio-cfg.h" + +#include <linux/platform_data/asoc-s3c24xx_simtec.h> +#include "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; + + /* Configure the I2S pins (GPE0...GPE4) in correct mode */ + s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), + S3C_GPIO_PULL_NONE); + + platform_device_register(&s3c_device_iis); + platform_device_register(&simtec_audio_dev); + return 0; +} diff --git a/arch/arm/mach-s3c/simtec-nor.c b/arch/arm/mach-s3c/simtec-nor.c new file mode 100644 index 000000000..a6fba056a --- /dev/null +++ b/arch/arm/mach-s3c/simtec-nor.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2008 Simtec Electronics +// http://armlinux.simtec.co.uk/ +// Ben Dooks <ben@simtec.co.uk> +// +// Simtec NOR mapping + +#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 "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-s3c/simtec-pm.c b/arch/arm/mach-s3c/simtec-pm.c new file mode 100644 index 000000000..490256a76 --- /dev/null +++ b/arch/arm/mach-s3c/simtec-pm.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2004 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// +// http://armlinux.simtec.co.uk/ +// +// Power Management helpers for Simtec S3C24XX implementations + +#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 "map.h" +#include "regs-gpio.h" + +#include <asm/mach-types.h> + +#include "pm.h" + +#include "regs-mem-s3c24xx.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-s3c/simtec-usb.c b/arch/arm/mach-s3c/simtec-usb.c new file mode 100644 index 000000000..76cedb5c7 --- /dev/null +++ b/arch/arm/mach-s3c/simtec-usb.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// 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 + +#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 "gpio-samsung.h" +#include "irqs.h" +#include <asm/irq.h> + +#include <linux/platform_data/usb-ohci-s3c2410.h> +#include "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-s3c/simtec.h b/arch/arm/mach-s3c/simtec.h new file mode 100644 index 000000000..d96bd6087 --- /dev/null +++ b/arch/arm/mach-s3c/simtec.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * Simtec common functions + */ + +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-s3c/sleep-s3c2410.S b/arch/arm/mach-s3c/sleep-s3c2410.S new file mode 100644 index 000000000..04aded987 --- /dev/null +++ b/arch/arm/mach-s3c/sleep-s3c2410.S @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 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 + */ + +#include <linux/linkage.h> +#include <linux/serial_s3c.h> +#include <asm/assembler.h> +#include "map.h" + +#include "regs-gpio.h" +#include "regs-clock.h" + +#include "regs-mem-s3c24xx.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 + ret lr diff --git a/arch/arm/mach-s3c/sleep-s3c2412.S b/arch/arm/mach-s3c/sleep-s3c2412.S new file mode 100644 index 000000000..b4b61737f --- /dev/null +++ b/arch/arm/mach-s3c/sleep-s3c2412.S @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * S3C2412 Power Manager low-level sleep support + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include "map.h" + +#include "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 + + ret lr diff --git a/arch/arm/mach-s3c/sleep-s3c24xx.S b/arch/arm/mach-s3c/sleep-s3c24xx.S new file mode 100644 index 000000000..4b2af91f3 --- /dev/null +++ b/arch/arm/mach-s3c/sleep-s3c24xx.S @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * 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 + */ + +#include <linux/linkage.h> +#include <linux/serial_s3c.h> +#include <asm/assembler.h> +#include "map.h" + +#include "regs-gpio.h" +#include "regs-clock.h" + +/* + * S3C24XX_DEBUG_RESUME is dangerous if your bootloader does not + * reset the UART configuration, only enable if you really need this! + */ +//#define S3C24XX_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 S3C24XX_DEBUG_RESUME + mov r3, #'L' + strb r3, [ r2, #S3C2410_UTXH ] +1001: + ldrb r14, [ r3, #S3C2410_UTRSTAT ] + tst r14, #S3C2410_UTRSTAT_TXE + beq 1001b +#endif /* S3C24XX_DEBUG_RESUME */ + + b cpu_resume diff --git a/arch/arm/mach-s3c/sleep-s3c64xx.S b/arch/arm/mach-s3c/sleep-s3c64xx.S new file mode 100644 index 000000000..739e53fbc --- /dev/null +++ b/arch/arm/mach-s3c/sleep-s3c64xx.S @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* linux/arch/arm/plat-s3c64xx/sleep.S + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * http://armlinux.simtec.co.uk/ + * + * S3C64XX CPU sleep code + */ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include "map.h" + +#undef S3C64XX_VA_GPIO +#define S3C64XX_VA_GPIO (0x0) + +#include "regs-gpio.h" + +#define LL_UART (S3C_PA_UART + (0x400 * CONFIG_S3C_LOWLEVEL_UART_PORT)) + + .text + + /* Sleep magic, the word before the resume entry point so that the + * bootloader can check for a resumeable image. */ + + .word 0x2bedf00d + + /* s3c_cpu_reusme + * + * This is the entry point, stored by whatever method the bootloader + * requires to get the kernel runnign again. This code expects to be + * entered with no caches live and the MMU disabled. It will then + * restore the MMU and other basic CP registers saved and restart + * the kernel C code to finish the resume code. + */ + +ENTRY(s3c_cpu_resume) + msr cpsr_c, #PSR_I_BIT | PSR_F_BIT | SVC_MODE + ldr r2, =LL_UART /* for debug */ + +#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK + +#define S3C64XX_GPNCON (S3C64XX_GPN_BASE + 0x00) +#define S3C64XX_GPNDAT (S3C64XX_GPN_BASE + 0x04) + +#define S3C64XX_GPN_CONMASK(__gpio) (0x3 << ((__gpio) * 2)) +#define S3C64XX_GPN_OUTPUT(__gpio) (0x1 << ((__gpio) * 2)) + + /* Initialise the GPIO state if we are debugging via the SMDK LEDs, + * as the uboot version supplied resets these to inputs during the + * resume checks. + */ + + ldr r3, =S3C64XX_PA_GPIO + ldr r0, [ r3, #S3C64XX_GPNCON ] + bic r0, r0, #(S3C64XX_GPN_CONMASK(12) | S3C64XX_GPN_CONMASK(13) | \ + S3C64XX_GPN_CONMASK(14) | S3C64XX_GPN_CONMASK(15)) + orr r0, r0, #(S3C64XX_GPN_OUTPUT(12) | S3C64XX_GPN_OUTPUT(13) | \ + S3C64XX_GPN_OUTPUT(14) | S3C64XX_GPN_OUTPUT(15)) + str r0, [ r3, #S3C64XX_GPNCON ] + + ldr r0, [ r3, #S3C64XX_GPNDAT ] + bic r0, r0, #0xf << 12 @ GPN12..15 + orr r0, r0, #1 << 15 @ GPN15 + str r0, [ r3, #S3C64XX_GPNDAT ] +#endif + b cpu_resume diff --git a/arch/arm/mach-s3c/spi-core-s3c24xx.h b/arch/arm/mach-s3c/spi-core-s3c24xx.h new file mode 100644 index 000000000..919c5fd0c --- /dev/null +++ b/arch/arm/mach-s3c/spi-core-s3c24xx.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de> + */ + +#ifndef __PLAT_S3C_SPI_CORE_S3C24XX_H +#define __PLAT_S3C_SPI_CORE_S3C24XX_H + +/* These functions are only for use with the core support code, such as + * the cpu specific initialisation code + */ + +/* re-define device name depending on support. */ +static inline void s3c24xx_spi_setname(char *name) +{ +#ifdef CONFIG_S3C64XX_DEV_SPI0 + s3c64xx_device_spi0.name = name; +#endif +} + +#endif /* __PLAT_S3C_SPI_CORE_S3C24XX_H */ diff --git a/arch/arm/mach-s3c/usb-phy.h b/arch/arm/mach-s3c/usb-phy.h new file mode 100644 index 000000000..759d66a07 --- /dev/null +++ b/arch/arm/mach-s3c/usb-phy.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + */ + +#ifndef __PLAT_SAMSUNG_USB_PHY_H +#define __PLAT_SAMSUNG_USB_PHY_H __FILE__ + +extern int s3c_usb_phy_init(struct platform_device *pdev, int type); +extern int s3c_usb_phy_exit(struct platform_device *pdev, int type); + +#endif /* __PLAT_SAMSUNG_USB_PHY_H */ diff --git a/arch/arm/mach-s3c/vr1000.h b/arch/arm/mach-s3c/vr1000.h new file mode 100644 index 000000000..3cfa296be --- /dev/null +++ b/arch/arm/mach-s3c/vr1000.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * 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 + */ + +#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 */ diff --git a/arch/arm/mach-s3c/wakeup-mask.c b/arch/arm/mach-s3c/wakeup-mask.c new file mode 100644 index 000000000..b490e7527 --- /dev/null +++ b/arch/arm/mach-s3c/wakeup-mask.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2010 Ben Dooks <ben-linux@fluff.org> +// +// Support for wakeup mask interrupts on newer SoCs + +#include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/irq.h> +#include <linux/io.h> + +#include "wakeup-mask.h" +#include "pm.h" + +void samsung_sync_wakemask(void __iomem *reg, + const struct samsung_wakeup_mask *mask, int nr_mask) +{ + struct irq_data *data; + u32 val; + + val = __raw_readl(reg); + + for (; nr_mask > 0; nr_mask--, mask++) { + if (mask->irq == NO_WAKEUP_IRQ) { + val |= mask->bit; + continue; + } + + data = irq_get_irq_data(mask->irq); + + /* bit of a liberty to read this directly from irq_data. */ + if (irqd_is_wakeup_set(data)) + val &= ~mask->bit; + else + val |= mask->bit; + } + + printk(KERN_INFO "wakemask %08x => %08x\n", __raw_readl(reg), val); + __raw_writel(val, reg); +} diff --git a/arch/arm/mach-s3c/wakeup-mask.h b/arch/arm/mach-s3c/wakeup-mask.h new file mode 100644 index 000000000..630909e66 --- /dev/null +++ b/arch/arm/mach-s3c/wakeup-mask.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2010 Ben Dooks <ben-linux@fluff.org> + * + * Support for wakeup mask interrupts on newer SoCs + */ + +#ifndef __PLAT_WAKEUP_MASK_H +#define __PLAT_WAKEUP_MASK_H __file__ + +/* if no irq yet defined, but still want to mask */ +#define NO_WAKEUP_IRQ (0x90000000) + +/** + * struct samsung_wakeup_mask - wakeup mask information + * @irq: The interrupt associated with this wakeup. + * @bit: The bit, as a (1 << bitno) controlling this source. + */ +struct samsung_wakeup_mask { + unsigned int irq; + u32 bit; +}; + +/** + * samsung_sync_wakemask - sync wakeup mask information for pm + * @reg: The register that is used. + * @masks: The list of masks to use. + * @nr_masks: The number of entries pointed to buy @masks. + * + * Synchronise the wakeup mask information at suspend time from the list + * of interrupts and control bits in @masks. We do this at suspend time + * as overriding the relevant irq chips is harder and the register is only + * required to be correct before we enter sleep. + */ +extern void samsung_sync_wakemask(void __iomem *reg, + const struct samsung_wakeup_mask *masks, + int nr_masks); + +#endif /* __PLAT_WAKEUP_MASK_H */ |