diff options
Diffstat (limited to 'arch/arm/plat-s5pc1xx')
21 files changed, 3121 insertions, 926 deletions
diff --git a/arch/arm/plat-s5pc1xx/Kconfig b/arch/arm/plat-s5pc1xx/Kconfig index a8a711c3c06..1608e62b0c9 100644 --- a/arch/arm/plat-s5pc1xx/Kconfig +++ b/arch/arm/plat-s5pc1xx/Kconfig @@ -15,6 +15,9 @@ config PLAT_S5PC1XX select ARCH_REQUIRE_GPIOLIB select S3C_GPIO_TRACK select S3C_GPIO_PULL_UPDOWN + select S3C_GPIO_CFG_S3C24XX + select S3C_GPIO_CFG_S3C64XX + select S5P_GPIO_CFG_S5PC1XX help Base platform code for any Samsung S5PC1XX device @@ -34,7 +37,12 @@ config CPU_S5PC100_CLOCK # platform specific device setup -config S5PC100_SETUP_I2C0 +config S5PC1XX_SETUP_FB_24BPP + bool + help + Common setup code for S5PC1XX with an 24bpp RGB display helper. + +config S5PC1XX_SETUP_I2C0 bool default y help @@ -43,8 +51,14 @@ config S5PC100_SETUP_I2C0 Note, currently since i2c0 is always compiled, this setup helper is always compiled with it. -config S5PC100_SETUP_I2C1 +config S5PC1XX_SETUP_I2C1 bool help Common setup code for i2c bus 1. + +config S5PC1XX_SETUP_SDHCI_GPIO + bool + help + Common setup code for SDHCI gpio. + endif diff --git a/arch/arm/plat-s5pc1xx/Makefile b/arch/arm/plat-s5pc1xx/Makefile index f1ecb2c37ee..278f2680608 100644 --- a/arch/arm/plat-s5pc1xx/Makefile +++ b/arch/arm/plat-s5pc1xx/Makefile @@ -13,7 +13,9 @@ obj- := obj-y += dev-uart.o obj-y += cpu.o -obj-y += irq.o +obj-y += irq.o irq-gpio.o irq-eint.o +obj-y += clock.o +obj-y += gpiolib.o # CPU support @@ -22,5 +24,8 @@ obj-$(CONFIG_CPU_S5PC100_CLOCK) += s5pc100-clock.o # Device setup -obj-$(CONFIG_S5PC100_SETUP_I2C0) += setup-i2c0.o -obj-$(CONFIG_S5PC100_SETUP_I2C1) += setup-i2c1.o +obj-$(CONFIG_S5P_GPIO_CFG_S5PC1XX) += gpio-config.o +obj-$(CONFIG_S5PC1XX_SETUP_FB_24BPP) += setup-fb-24bpp.o +obj-$(CONFIG_S5PC1XX_SETUP_I2C0) += setup-i2c0.o +obj-$(CONFIG_S5PC1XX_SETUP_I2C1) += setup-i2c1.o +obj-$(CONFIG_S5PC1XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o diff --git a/arch/arm/plat-s5pc1xx/clock.c b/arch/arm/plat-s5pc1xx/clock.c new file mode 100644 index 00000000000..26c21d84979 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/clock.c @@ -0,0 +1,728 @@ +/* linux/arch/arm/plat-s5pc1xx/clock.c + * + * Copyright 2009 Samsung Electronics Co. + * + * S5PC1XX Base clock support + * + * Based on plat-s3c64xx/clock.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/ioport.h> +#include <linux/clk.h> +#include <linux/io.h> + +#include <mach/hardware.h> +#include <mach/map.h> + +#include <plat/regs-clock.h> +#include <plat/devs.h> +#include <plat/clock.h> + +struct clk clk_27m = { + .name = "clk_27m", + .id = -1, + .rate = 27000000, +}; + +static int clk_48m_ctrl(struct clk *clk, int enable) +{ + unsigned long flags; + u32 val; + + /* can't rely on clock lock, this register has other usages */ + local_irq_save(flags); + + val = __raw_readl(S5PC100_CLKSRC1); + if (enable) + val |= S5PC100_CLKSRC1_CLK48M_MASK; + else + val &= ~S5PC100_CLKSRC1_CLK48M_MASK; + + __raw_writel(val, S5PC100_CLKSRC1); + local_irq_restore(flags); + + return 0; +} + +struct clk clk_48m = { + .name = "clk_48m", + .id = -1, + .rate = 48000000, + .enable = clk_48m_ctrl, +}; + +struct clk clk_54m = { + .name = "clk_54m", + .id = -1, + .rate = 54000000, +}; + +static int clk_default_setrate(struct clk *clk, unsigned long rate) +{ + clk->rate = rate; + return 0; +} + +static int clk_dummy_enable(struct clk *clk, int enable) +{ + return 0; +} + +struct clk clk_hd0 = { + .name = "hclkd0", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, + .set_rate = clk_default_setrate, + .enable = clk_dummy_enable, +}; + +struct clk clk_pd0 = { + .name = "pclkd0", + .id = -1, + .rate = 0, + .parent = NULL, + .ctrlbit = 0, + .set_rate = clk_default_setrate, + .enable = clk_dummy_enable, +}; + +static int s5pc1xx_clk_gate(void __iomem *reg, struct clk *clk, int enable) +{ + unsigned int ctrlbit = clk->ctrlbit; + u32 con; + + con = __raw_readl(reg); + if (enable) + con |= ctrlbit; + else + con &= ~ctrlbit; + __raw_writel(con, reg); + + return 0; +} + +static int s5pc100_clk_d00_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D00, clk, enable); +} + +static int s5pc100_clk_d01_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D01, clk, enable); +} + +static int s5pc100_clk_d02_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D02, clk, enable); +} + +static int s5pc100_clk_d10_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D10, clk, enable); +} + +static int s5pc100_clk_d11_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D11, clk, enable); +} + +static int s5pc100_clk_d12_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D12, clk, enable); +} + +static int s5pc100_clk_d13_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D13, clk, enable); +} + +static int s5pc100_clk_d14_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D14, clk, enable); +} + +static int s5pc100_clk_d15_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D15, clk, enable); +} + +static int s5pc100_clk_d20_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_CLKGATE_D20, clk, enable); +} + +int s5pc100_sclk0_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_SCLKGATE0, clk, enable); +} + +int s5pc100_sclk1_ctrl(struct clk *clk, int enable) +{ + return s5pc1xx_clk_gate(S5PC100_SCLKGATE1, clk, enable); +} + +static struct clk s5pc100_init_clocks_disable[] = { + { + .name = "dsi", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_DSI, + }, { + .name = "csi", + .id = -1, + .parent = &clk_h, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_CSI, + }, { + .name = "ccan", + .id = 0, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_CCAN0, + }, { + .name = "ccan", + .id = 1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_CCAN1, + }, { + .name = "keypad", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_KEYIF, + }, { + .name = "hclkd2", + .id = -1, + .parent = NULL, + .enable = s5pc100_clk_d20_ctrl, + .ctrlbit = S5PC100_CLKGATE_D20_HCLKD2, + }, { + .name = "iis-d2", + .id = -1, + .parent = NULL, + .enable = s5pc100_clk_d20_ctrl, + .ctrlbit = S5PC100_CLKGATE_D20_I2SD2, + }, +}; + +static struct clk s5pc100_init_clocks[] = { + /* System1 (D0_0) devices */ + { + .name = "intc", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_INTC, + }, { + .name = "tzic", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_TZIC, + }, { + .name = "cf-ata", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_CFCON, + }, { + .name = "mdma", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_MDMA, + }, { + .name = "g2d", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_G2D, + }, { + .name = "secss", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_SECSS, + }, { + .name = "cssys", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d00_ctrl, + .ctrlbit = S5PC100_CLKGATE_D00_CSSYS, + }, + + /* Memory (D0_1) devices */ + { + .name = "dmc", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d01_ctrl, + .ctrlbit = S5PC100_CLKGATE_D01_DMC, + }, { + .name = "sromc", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d01_ctrl, + .ctrlbit = S5PC100_CLKGATE_D01_SROMC, + }, { + .name = "onenand", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d01_ctrl, + .ctrlbit = S5PC100_CLKGATE_D01_ONENAND, + }, { + .name = "nand", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d01_ctrl, + .ctrlbit = S5PC100_CLKGATE_D01_NFCON, + }, { + .name = "intmem", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d01_ctrl, + .ctrlbit = S5PC100_CLKGATE_D01_INTMEM, + }, { + .name = "ebi", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d01_ctrl, + .ctrlbit = S5PC100_CLKGATE_D01_EBI, + }, + + /* System2 (D0_2) devices */ + { + .name = "seckey", + .id = -1, + .parent = &clk_pd0, + .enable = s5pc100_clk_d02_ctrl, + .ctrlbit = S5PC100_CLKGATE_D02_SECKEY, + }, { + .name = "sdm", + .id = -1, + .parent = &clk_hd0, + .enable = s5pc100_clk_d02_ctrl, + .ctrlbit = S5PC100_CLKGATE_D02_SDM, + }, + + /* File (D1_0) devices */ + { + .name = "pdma", + .id = 0, + .parent = &clk_h, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_PDMA0, + }, { + .name = "pdma", + .id = 1, + .parent = &clk_h, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_PDMA1, + }, { + .name = "usb-host", + .id = -1, + .parent = &clk_h, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_USBHOST, + }, { + .name = "otg", + .id = -1, + .parent = &clk_h, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_USBOTG, + }, { + .name = "modem", + .id = -1, + .parent = &clk_h, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_MODEMIF, + }, { + .name = "hsmmc", + .id = 0, + .parent = &clk_48m, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_HSMMC0, + }, { + .name = "hsmmc", + .id = 1, + .parent = &clk_48m, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_HSMMC1, + }, { + .name = "hsmmc", + .id = 2, + .parent = &clk_48m, + .enable = s5pc100_clk_d10_ctrl, + .ctrlbit = S5PC100_CLKGATE_D10_HSMMC2, + }, + + /* Multimedia1 (D1_1) devices */ + { + .name = "lcd", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_LCD, + }, { + .name = "rotator", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_ROTATOR, + }, { + .name = "fimc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_FIMC0, + }, { + .name = "fimc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_FIMC1, + }, { + .name = "fimc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_FIMC2, + }, { + .name = "jpeg", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_JPEG, + }, { + .name = "g3d", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d11_ctrl, + .ctrlbit = S5PC100_CLKGATE_D11_G3D, + }, + + /* Multimedia2 (D1_2) devices */ + { + .name = "tv", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d12_ctrl, + .ctrlbit = S5PC100_CLKGATE_D12_TV, + }, { + .name = "vp", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d12_ctrl, + .ctrlbit = S5PC100_CLKGATE_D12_VP, + }, { + .name = "mixer", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d12_ctrl, + .ctrlbit = S5PC100_CLKGATE_D12_MIXER, + }, { + .name = "hdmi", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d12_ctrl, + .ctrlbit = S5PC100_CLKGATE_D12_HDMI, + }, { + .name = "mfc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d12_ctrl, + .ctrlbit = S5PC100_CLKGATE_D12_MFC, + }, + + /* System (D1_3) devices */ + { + .name = "chipid", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_CHIPID, + }, { + .name = "gpio", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_GPIO, + }, { + .name = "apc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_APC, + }, { + .name = "iec", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_IEC, + }, { + .name = "timers", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_PWM, + }, { + .name = "systimer", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_SYSTIMER, + }, { + .name = "watchdog", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_WDT, + }, { + .name = "rtc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d13_ctrl, + .ctrlbit = S5PC100_CLKGATE_D13_RTC, + }, + + /* Connectivity (D1_4) devices */ + { + .name = "uart", + .id = 0, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_UART0, + }, { + .name = "uart", + .id = 1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_UART1, + }, { + .name = "uart", + .id = 2, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_UART2, + }, { + .name = "uart", + .id = 3, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_UART3, + }, { + .name = "i2c", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_IIC, + }, { + .name = "hdmi-i2c", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_HDMI_IIC, + }, { + .name = "spi", + .id = 0, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_SPI0, + }, { + .name = "spi", + .id = 1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_SPI1, + }, { + .name = "spi", + .id = 2, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_SPI2, + }, { + .name = "irda", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_IRDA, + }, { + .name = "hsitx", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_HSITX, + }, { + .name = "hsirx", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d14_ctrl, + .ctrlbit = S5PC100_CLKGATE_D14_HSIRX, + }, + + /* Audio (D1_5) devices */ + { + .name = "iis", + .id = 0, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_IIS0, + }, { + .name = "iis", + .id = 1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_IIS1, + }, { + .name = "iis", + .id = 2, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_IIS2, + }, { + .name = "ac97", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_AC97, + }, { + .name = "pcm", + .id = 0, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_PCM0, + }, { + .name = "pcm", + .id = 1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_PCM1, + }, { + .name = "spdif", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_SPDIF, + }, { + .name = "adc", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_TSADC, + }, { + .name = "cg", + .id = -1, + .parent = &clk_p, + .enable = s5pc100_clk_d15_ctrl, + .ctrlbit = S5PC100_CLKGATE_D15_CG, + }, + + /* Audio (D2_0) devices: all disabled */ + + /* Special Clocks 0 */ + { + .name = "sclk_hpm", + .id = -1, + .parent = NULL, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_HPM, + }, { + .name = "sclk_onenand", + .id = -1, + .parent = NULL, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_ONENAND, + }, { + .name = "spi_48", + .id = 0, + .parent = &clk_48m, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0_48, + }, { + .name = "spi_48", + .id = 1, + .parent = &clk_48m, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1_48, + }, { + .name = "spi_48", + .id = 2, + .parent = &clk_48m, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2_48, + }, { + .name = "mmc_48", + .id = 0, + .parent = &clk_48m, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0_48, + }, { + .name = "mmc_48", + .id = 1, + .parent = &clk_48m, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1_48, + }, { + .name = "mmc_48", + .id = 2, + .parent = &clk_48m, + .enable = s5pc100_sclk0_ctrl, + .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2_48, + }, + /* Special Clocks 1 */ +}; + +static struct clk *clks[] __initdata = { + &clk_ext, + &clk_epll, + &clk_27m, + &clk_48m, + &clk_54m, +}; + +void __init s5pc1xx_register_clocks(void) +{ + struct clk *clkp; + int ret; + int ptr; + int size; + + s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); + + clkp = s5pc100_init_clocks; + size = ARRAY_SIZE(s5pc100_init_clocks); + + for (ptr = 0; ptr < size; ptr++, clkp++) { + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + } + + clkp = s5pc100_init_clocks_disable; + size = ARRAY_SIZE(s5pc100_init_clocks_disable); + + for (ptr = 0; ptr < size; ptr++, clkp++) { + ret = s3c24xx_register_clock(clkp); + if (ret < 0) { + printk(KERN_ERR "Failed to register clock %s (%d)\n", + clkp->name, ret); + } + + (clkp->enable)(clkp, 0); + } + + s3c_pwmclk_init(); +} diff --git a/arch/arm/plat-s5pc1xx/cpu.c b/arch/arm/plat-s5pc1xx/cpu.c index 715a7330794..02baeaa2a12 100644 --- a/arch/arm/plat-s5pc1xx/cpu.c +++ b/arch/arm/plat-s5pc1xx/cpu.c @@ -55,6 +55,16 @@ static struct cpu_table cpu_ids[] __initdata = { static struct map_desc s5pc1xx_iodesc[] __initdata = { { + .virtual = (unsigned long)S5PC1XX_VA_CLK_OTHER, + .pfn = __phys_to_pfn(S5PC1XX_PA_CLK_OTHER), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = (unsigned long)S5PC1XX_VA_GPIO, + .pfn = __phys_to_pfn(S5PC100_PA_GPIO), + .length = SZ_4K, + .type = MT_DEVICE, + }, { .virtual = (unsigned long)S5PC1XX_VA_CHIPID, .pfn = __phys_to_pfn(S5PC1XX_PA_CHIPID), .length = SZ_16, diff --git a/arch/arm/plat-s5pc1xx/gpio-config.c b/arch/arm/plat-s5pc1xx/gpio-config.c new file mode 100644 index 00000000000..bba675df9c7 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/gpio-config.c @@ -0,0 +1,62 @@ +/* linux/arch/arm/plat-s5pc1xx/gpio-config.c + * + * Copyright 2009 Samsung Electronics + * + * S5PC1XX GPIO Configuration. + * + * Based on plat-s3c64xx/gpio-config.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/gpio.h> +#include <linux/io.h> + +#include <mach/gpio-core.h> +#include <plat/gpio-cfg-s5pc1xx.h> + +s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin, unsigned int off) +{ + struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); + void __iomem *reg; + int shift = off * 2; + u32 drvstr; + + if (!chip) + return -EINVAL; + + reg = chip->base + 0x0C; + + drvstr = __raw_readl(reg); + drvstr = 0xffff & (0x3 << shift); + drvstr = drvstr >> shift; + + return (__force s5p_gpio_drvstr_t)drvstr; +} +EXPORT_SYMBOL(s5p_gpio_get_drvstr); + +int s5p_gpio_set_drvstr(unsigned int pin, unsigned int off, + s5p_gpio_drvstr_t drvstr) +{ + struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); + void __iomem *reg; + int shift = off * 2; + u32 tmp; + + if (!chip) + return -EINVAL; + + reg = chip->base + 0x0C; + + tmp = __raw_readl(reg); + tmp |= drvstr << shift; + + __raw_writel(tmp, reg); + + return 0; +} +EXPORT_SYMBOL(s5p_gpio_set_drvstr); diff --git a/arch/arm/plat-s5pc1xx/gpiolib.c b/arch/arm/plat-s5pc1xx/gpiolib.c new file mode 100644 index 00000000000..facb410e7a7 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/gpiolib.c @@ -0,0 +1,503 @@ +/* + * arch/arm/plat-s5pc1xx/gpiolib.c + * + * Copyright 2009 Samsung Electronics Co + * Kyungmin Park <kyungmin.park@samsung.com> + * + * S5PC1XX - GPIOlib support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <mach/map.h> +#include <mach/gpio-core.h> + +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-helpers.h> +#include <plat/regs-gpio.h> + +/* S5PC100 GPIO bank summary: + * + * Bank GPIOs Style INT Type + * A0 8 4Bit GPIO_INT0 + * A1 5 4Bit GPIO_INT1 + * B 8 4Bit GPIO_INT2 + * C 5 4Bit GPIO_INT3 + * D 7 4Bit GPIO_INT4 + * E0 8 4Bit GPIO_INT5 + * E1 6 4Bit GPIO_INT6 + * F0 8 4Bit GPIO_INT7 + * F1 8 4Bit GPIO_INT8 + * F2 8 4Bit GPIO_INT9 + * F3 4 4Bit GPIO_INT10 + * G0 8 4Bit GPIO_INT11 + * G1 3 4Bit GPIO_INT12 + * G2 7 4Bit GPIO_INT13 + * G3 7 4Bit GPIO_INT14 + * H0 8 4Bit WKUP_INT + * H1 8 4Bit WKUP_INT + * H2 8 4Bit WKUP_INT + * H3 8 4Bit WKUP_INT + * I 8 4Bit GPIO_INT15 + * J0 8 4Bit GPIO_INT16 + * J1 5 4Bit GPIO_INT17 + * J2 8 4Bit GPIO_INT18 + * J3 8 4Bit GPIO_INT19 + * J4 4 4Bit GPIO_INT20 + * K0 8 4Bit None + * K1 6 4Bit None + * K2 8 4Bit None + * K3 8 4Bit None + * L0 8 4Bit None + * L1 8 4Bit None + * L2 8 4Bit None + * L3 8 4Bit None + */ + +#define OFF_GPCON (0x00) +#define OFF_GPDAT (0x04) + +#define con_4bit_shift(__off) ((__off) * 4) + +#if 1 +#define gpio_dbg(x...) do { } while (0) +#else +#define gpio_dbg(x...) printk(KERN_DEBUG x) +#endif + +/* The s5pc1xx_gpiolib 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 s3c_gpiolib_get and s3c_gpiolib_set to change the state of + * the output. + */ + +static int s5pc1xx_gpiolib_input(struct gpio_chip *chip, unsigned offset) +{ + struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + + con = __raw_readl(base + OFF_GPCON); + con &= ~(0xf << con_4bit_shift(offset)); + __raw_writel(con, base + OFF_GPCON); + + gpio_dbg("%s: %p: CON now %08lx\n", __func__, base, con); + + return 0; +} + +static int s5pc1xx_gpiolib_output(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct s3c_gpio_chip *ourchip = to_s3c_gpio(chip); + void __iomem *base = ourchip->base; + unsigned long con; + unsigned long dat; + + con = __raw_readl(base + OFF_GPCON); + con &= ~(0xf << con_4bit_shift(offset)); + con |= 0x1 << con_4bit_shift(offset); + + dat = __raw_readl(base + OFF_GPDAT); + if (value) + dat |= 1 << offset; + else + dat &= ~(1 << offset); + + __raw_writel(dat, base + OFF_GPDAT); + __raw_writel(con, base + OFF_GPCON); + __raw_writel(dat, base + OFF_GPDAT); + + gpio_dbg("%s: %p: CON %08lx, DAT %08lx\n", __func__, base, con, dat); + + return 0; +} + +static int s5pc1xx_gpiolib_to_irq(struct gpio_chip *chip, unsigned int offset) +{ + return S3C_IRQ_GPIO(chip->base + offset); +} + +static int s5pc1xx_gpiolib_to_eint(struct gpio_chip *chip, unsigned int offset) +{ + int base; + + base = chip->base - S5PC100_GPH0(0); + if (base == 0) + return IRQ_EINT(offset); + base = chip->base - S5PC100_GPH1(0); + if (base == 0) + return IRQ_EINT(8 + offset); + base = chip->base - S5PC100_GPH2(0); + if (base == 0) + return IRQ_EINT(16 + offset); + base = chip->base - S5PC100_GPH3(0); + if (base == 0) + return IRQ_EINT(24 + offset); + return -EINVAL; +} + +static struct s3c_gpio_cfg gpio_cfg = { + .set_config = s3c_gpio_setcfg_s3c64xx_4bit, + .set_pull = s3c_gpio_setpull_updown, + .get_pull = s3c_gpio_getpull_updown, +}; + +static struct s3c_gpio_cfg gpio_cfg_eint = { + .cfg_eint = 0xf, + .set_config = s3c_gpio_setcfg_s3c64xx_4bit, + .set_pull = s3c_gpio_setpull_updown, + .get_pull = s3c_gpio_getpull_updown, +}; + +static struct s3c_gpio_cfg gpio_cfg_noint = { + .set_config = s3c_gpio_setcfg_s3c64xx_4bit, + .set_pull = s3c_gpio_setpull_updown, + .get_pull = s3c_gpio_getpull_updown, +}; + +static struct s3c_gpio_chip s5pc100_gpio_chips[] = { + { + .base = S5PC100_GPA0_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPA0(0), + .ngpio = S5PC100_GPIO_A0_NR, + .label = "GPA0", + }, + }, { + .base = S5PC100_GPA1_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPA1(0), + .ngpio = S5PC100_GPIO_A1_NR, + .label = "GPA1", + }, + }, { + .base = S5PC100_GPB_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPB(0), + .ngpio = S5PC100_GPIO_B_NR, + .label = "GPB", + }, + }, { + .base = S5PC100_GPC_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPC(0), + .ngpio = S5PC100_GPIO_C_NR, + .label = "GPC", + }, + }, { + .base = S5PC100_GPD_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPD(0), + .ngpio = S5PC100_GPIO_D_NR, + .label = "GPD", + }, + }, { + .base = S5PC100_GPE0_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPE0(0), + .ngpio = S5PC100_GPIO_E0_NR, + .label = "GPE0", + }, + }, { + .base = S5PC100_GPE1_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPE1(0), + .ngpio = S5PC100_GPIO_E1_NR, + .label = "GPE1", + }, + }, { + .base = S5PC100_GPF0_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPF0(0), + .ngpio = S5PC100_GPIO_F0_NR, + .label = "GPF0", + }, + }, { + .base = S5PC100_GPF1_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPF1(0), + .ngpio = S5PC100_GPIO_F1_NR, + .label = "GPF1", + }, + }, { + .base = S5PC100_GPF2_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPF2(0), + .ngpio = S5PC100_GPIO_F2_NR, + .label = "GPF2", + }, + }, { + .base = S5PC100_GPF3_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPF3(0), + .ngpio = S5PC100_GPIO_F3_NR, + .label = "GPF3", + }, + }, { + .base = S5PC100_GPG0_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPG0(0), + .ngpio = S5PC100_GPIO_G0_NR, + .label = "GPG0", + }, + }, { + .base = S5PC100_GPG1_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPG1(0), + .ngpio = S5PC100_GPIO_G1_NR, + .label = "GPG1", + }, + }, { + .base = S5PC100_GPG2_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPG2(0), + .ngpio = S5PC100_GPIO_G2_NR, + .label = "GPG2", + }, + }, { + .base = S5PC100_GPG3_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPG3(0), + .ngpio = S5PC100_GPIO_G3_NR, + .label = "GPG3", + }, + }, { + .base = S5PC100_GPH0_BASE, + .config = &gpio_cfg_eint, + .chip = { + .base = S5PC100_GPH0(0), + .ngpio = S5PC100_GPIO_H0_NR, + .label = "GPH0", + }, + }, { + .base = S5PC100_GPH1_BASE, + .config = &gpio_cfg_eint, + .chip = { + .base = S5PC100_GPH1(0), + .ngpio = S5PC100_GPIO_H1_NR, + .label = "GPH1", + }, + }, { + .base = S5PC100_GPH2_BASE, + .config = &gpio_cfg_eint, + .chip = { + .base = S5PC100_GPH2(0), + .ngpio = S5PC100_GPIO_H2_NR, + .label = "GPH2", + }, + }, { + .base = S5PC100_GPH3_BASE, + .config = &gpio_cfg_eint, + .chip = { + .base = S5PC100_GPH3(0), + .ngpio = S5PC100_GPIO_H3_NR, + .label = "GPH3", + }, + }, { + .base = S5PC100_GPI_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPI(0), + .ngpio = S5PC100_GPIO_I_NR, + .label = "GPI", + }, + }, { + .base = S5PC100_GPJ0_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPJ0(0), + .ngpio = S5PC100_GPIO_J0_NR, + .label = "GPJ0", + }, + }, { + .base = S5PC100_GPJ1_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPJ1(0), + .ngpio = S5PC100_GPIO_J1_NR, + .label = "GPJ1", + }, + }, { + .base = S5PC100_GPJ2_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPJ2(0), + .ngpio = S5PC100_GPIO_J2_NR, + .label = "GPJ2", + }, + }, { + .base = S5PC100_GPJ3_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPJ3(0), + .ngpio = S5PC100_GPIO_J3_NR, + .label = "GPJ3", + }, + }, { + .base = S5PC100_GPJ4_BASE, + .config = &gpio_cfg, + .chip = { + .base = S5PC100_GPJ4(0), + .ngpio = S5PC100_GPIO_J4_NR, + .label = "GPJ4", + }, + }, { + .base = S5PC100_GPK0_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPK0(0), + .ngpio = S5PC100_GPIO_K0_NR, + .label = "GPK0", + }, + }, { + .base = S5PC100_GPK1_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPK1(0), + .ngpio = S5PC100_GPIO_K1_NR, + .label = "GPK1", + }, + }, { + .base = S5PC100_GPK2_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPK2(0), + .ngpio = S5PC100_GPIO_K2_NR, + .label = "GPK2", + }, + }, { + .base = S5PC100_GPK3_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPK3(0), + .ngpio = S5PC100_GPIO_K3_NR, + .label = "GPK3", + }, + }, { + .base = S5PC100_GPL0_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPL0(0), + .ngpio = S5PC100_GPIO_L0_NR, + .label = "GPL0", + }, + }, { + .base = S5PC100_GPL1_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPL1(0), + .ngpio = S5PC100_GPIO_L1_NR, + .label = "GPL1", + }, + }, { + .base = S5PC100_GPL2_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPL2(0), + .ngpio = S5PC100_GPIO_L2_NR, + .label = "GPL2", + }, + }, { + .base = S5PC100_GPL3_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPL3(0), + .ngpio = S5PC100_GPIO_L3_NR, + .label = "GPL3", + }, + }, { + .base = S5PC100_GPL4_BASE, + .config = &gpio_cfg_noint, + .chip = { + .base = S5PC100_GPL4(0), + .ngpio = S5PC100_GPIO_L4_NR, + .label = "GPL4", + }, + }, +}; + +/* FIXME move from irq-gpio.c */ +extern struct irq_chip s5pc1xx_gpioint; +extern void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc); + +static __init void s5pc1xx_gpiolib_link(struct s3c_gpio_chip *chip) +{ + chip->chip.direction_input = s5pc1xx_gpiolib_input; + chip->chip.direction_output = s5pc1xx_gpiolib_output; + chip->pm = __gpio_pm(&s3c_gpio_pm_4bit); + + /* Interrupt */ + if (chip->config == &gpio_cfg) { + int i, irq; + + chip->chip.to_irq = s5pc1xx_gpiolib_to_irq; + + for (i = 0; i < chip->chip.ngpio; i++) { + irq = S3C_IRQ_GPIO_BASE + chip->chip.base + i; + set_irq_chip(irq, &s5pc1xx_gpioint); + set_irq_data(irq, &chip->chip); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + } else if (chip->config == &gpio_cfg_eint) + chip->chip.to_irq = s5pc1xx_gpiolib_to_eint; +} + +static __init void s5pc1xx_gpiolib_add(struct s3c_gpio_chip *chips, + int nr_chips, + void (*fn)(struct s3c_gpio_chip *)) +{ + for (; nr_chips > 0; nr_chips--, chips++) { + if (fn) + (fn)(chips); + s3c_gpiolib_add(chips); + } +} + +static __init int s5pc1xx_gpiolib_init(void) +{ + struct s3c_gpio_chip *chips; + int nr_chips; + + chips = s5pc100_gpio_chips; + nr_chips = ARRAY_SIZE(s5pc100_gpio_chips); + + s5pc1xx_gpiolib_add(chips, nr_chips, s5pc1xx_gpiolib_link); + /* Interrupt */ + set_irq_chained_handler(IRQ_GPIOINT, s5pc1xx_irq_gpioint_handler); + + return 0; +} +core_initcall(s5pc1xx_gpiolib_init); diff --git a/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg-s5pc1xx.h b/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg-s5pc1xx.h new file mode 100644 index 00000000000..72ad59f61ef --- /dev/null +++ b/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg-s5pc1xx.h @@ -0,0 +1,32 @@ +/* linux/arch/arm/plat-s5pc1xx/include/plat/gpio-cfg.h + * + * Copyright 2009 Samsung Electronic + * + * S5PC1XX Platform - GPIO pin configuration + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +/* This 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. + */ + +#ifndef __GPIO_CFG_S5PC1XX_H +#define __GPIO_CFG_S5PC1XX_H __FILE__ + +typedef unsigned int __bitwise__ s5p_gpio_drvstr_t; + +#define S5P_GPIO_DRVSTR_LV1 0x00 +#define S5P_GPIO_DRVSTR_LV2 0x01 +#define S5P_GPIO_DRVSTR_LV3 0x10 +#define S5P_GPIO_DRVSTR_LV4 0x11 + +extern s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin, unsigned int off); + +extern int s5p_gpio_set_drvstr(unsigned int pin, unsigned int off, + s5p_gpio_drvstr_t drvstr); + +#endif /* __GPIO_CFG_S5PC1XX_H */ diff --git a/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h b/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h new file mode 100644 index 00000000000..33ad267e847 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/include/plat/gpio-ext.h @@ -0,0 +1,44 @@ +/* linux/arch/arm/plat-s5pc1xx/include/plat/gpio-eint.h + * + * Copyright 2009 Samsung Electronics Co. + * + * External Interrupt (GPH0 ~ GPH3) control register definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#define S5PC1XX_WKUP_INT_CON0_7 (S5PC1XX_EINT_BASE + 0x0) +#define S5PC1XX_WKUP_INT_CON8_15 (S5PC1XX_EINT_BASE + 0x4) +#define S5PC1XX_WKUP_INT_CON16_23 (S5PC1XX_EINT_BASE + 0x8) +#define S5PC1XX_WKUP_INT_CON24_31 (S5PC1XX_EINT_BASE + 0xC) +#define S5PC1XX_WKUP_INT_CON(x) (S5PC1XX_WKUP_INT_CON0_7 + (x * 0x4)) + +#define S5PC1XX_WKUP_INT_FLTCON0_3 (S5PC1XX_EINT_BASE + 0x80) +#define S5PC1XX_WKUP_INT_FLTCON4_7 (S5PC1XX_EINT_BASE + 0x84) +#define S5PC1XX_WKUP_INT_FLTCON8_11 (S5PC1XX_EINT_BASE + 0x88) +#define S5PC1XX_WKUP_INT_FLTCON12_15 (S5PC1XX_EINT_BASE + 0x8C) +#define S5PC1XX_WKUP_INT_FLTCON16_19 (S5PC1XX_EINT_BASE + 0x90) +#define S5PC1XX_WKUP_INT_FLTCON20_23 (S5PC1XX_EINT_BASE + 0x94) +#define S5PC1XX_WKUP_INT_FLTCON24_27 (S5PC1XX_EINT_BASE + 0x98) +#define S5PC1XX_WKUP_INT_FLTCON28_31 (S5PC1XX_EINT_BASE + 0x9C) +#define S5PC1XX_WKUP_INT_FLTCON(x) (S5PC1XX_WKUP_INT_FLTCON0_3 + (x * 0x4)) + +#define S5PC1XX_WKUP_INT_MASK0_7 (S5PC1XX_EINT_BASE + 0x100) +#define S5PC1XX_WKUP_INT_MASK8_15 (S5PC1XX_EINT_BASE + 0x104) +#define S5PC1XX_WKUP_INT_MASK16_23 (S5PC1XX_EINT_BASE + 0x108) +#define S5PC1XX_WKUP_INT_MASK24_31 (S5PC1XX_EINT_BASE + 0x10C) +#define S5PC1XX_WKUP_INT_MASK(x) (S5PC1XX_WKUP_INT_MASK0_7 + (x * 0x4)) + +#define S5PC1XX_WKUP_INT_PEND0_7 (S5PC1XX_EINT_BASE + 0x140) +#define S5PC1XX_WKUP_INT_PEND8_15 (S5PC1XX_EINT_BASE + 0x144) +#define S5PC1XX_WKUP_INT_PEND16_23 (S5PC1XX_EINT_BASE + 0x148) +#define S5PC1XX_WKUP_INT_PEND24_31 (S5PC1XX_EINT_BASE + 0x14C) +#define S5PC1XX_WKUP_INT_PEND(x) (S5PC1XX_WKUP_INT_PEND0_7 + (x * 0x4)) + +#define S5PC1XX_WKUP_INT_LOWLEV (0x00) +#define S5PC1XX_WKUP_INT_HILEV (0x01) +#define S5PC1XX_WKUP_INT_FALLEDGE (0x02) +#define S5PC1XX_WKUP_INT_RISEEDGE (0x03) +#define S5PC1XX_WKUP_INT_BOTHEDGE (0x04) diff --git a/arch/arm/plat-s5pc1xx/include/plat/irqs.h b/arch/arm/plat-s5pc1xx/include/plat/irqs.h index f07d8c3b25d..ef8736366f0 100644 --- a/arch/arm/plat-s5pc1xx/include/plat/irqs.h +++ b/arch/arm/plat-s5pc1xx/include/plat/irqs.h @@ -171,12 +171,21 @@ #define IRQ_SDMIRQ S5PC1XX_IRQ_VIC2(30) #define IRQ_SDMFIQ S5PC1XX_IRQ_VIC2(31) +/* External interrupt */ #define S3C_IRQ_EINT_BASE (IRQ_SDMFIQ + 1) -#define S3C_EINT(x) ((x) + S3C_IRQ_EINT_BASE) -#define IRQ_EINT(x) S3C_EINT(x) +#define S3C_EINT(x) (S3C_IRQ_EINT_BASE + (x - 16)) +#define IRQ_EINT(x) (x < 16 ? IRQ_EINT0 + x : S3C_EINT(x)) +#define IRQ_EINT_BIT(x) (x < IRQ_EINT16_31 ? x - IRQ_EINT0 : x - S3C_EINT(0)) -#define NR_IRQS (IRQ_EINT(31)+1) +/* GPIO interrupt */ +#define S3C_IRQ_GPIO_BASE (IRQ_EINT(31) + 1) +#define S3C_IRQ_GPIO(x) (S3C_IRQ_GPIO_BASE + (x)) + +/* + * Until MP04 Groups -> 40 (exactly 39) Groups * 8 ~= 320 GPIOs + */ +#define NR_IRQS (S3C_IRQ_GPIO(320) + 1) #endif /* __ASM_PLAT_S5PC1XX_IRQS_H */ diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-clock.h b/arch/arm/plat-s5pc1xx/include/plat/regs-clock.h index 75c8390cb82..c5cc86e92d6 100644 --- a/arch/arm/plat-s5pc1xx/include/plat/regs-clock.h +++ b/arch/arm/plat-s5pc1xx/include/plat/regs-clock.h @@ -13,68 +13,69 @@ #ifndef __PLAT_REGS_CLOCK_H #define __PLAT_REGS_CLOCK_H __FILE__ -#define S5PC1XX_CLKREG(x) (S5PC1XX_VA_CLK + (x)) - -#define S5PC1XX_APLL_LOCK S5PC1XX_CLKREG(0x00) -#define S5PC1XX_MPLL_LOCK S5PC1XX_CLKREG(0x04) -#define S5PC1XX_EPLL_LOCK S5PC1XX_CLKREG(0x08) -#define S5PC100_HPLL_LOCK S5PC1XX_CLKREG(0x0C) - -#define S5PC1XX_APLL_CON S5PC1XX_CLKREG(0x100) -#define S5PC1XX_MPLL_CON S5PC1XX_CLKREG(0x104) -#define S5PC1XX_EPLL_CON S5PC1XX_CLKREG(0x108) -#define S5PC100_HPLL_CON S5PC1XX_CLKREG(0x10C) - -#define S5PC1XX_CLK_SRC0 S5PC1XX_CLKREG(0x200) -#define S5PC1XX_CLK_SRC1 S5PC1XX_CLKREG(0x204) -#define S5PC1XX_CLK_SRC2 S5PC1XX_CLKREG(0x208) -#define S5PC1XX_CLK_SRC3 S5PC1XX_CLKREG(0x20C) - -#define S5PC1XX_CLK_DIV0 S5PC1XX_CLKREG(0x300) -#define S5PC1XX_CLK_DIV1 S5PC1XX_CLKREG(0x304) -#define S5PC1XX_CLK_DIV2 S5PC1XX_CLKREG(0x308) -#define S5PC1XX_CLK_DIV3 S5PC1XX_CLKREG(0x30C) -#define S5PC1XX_CLK_DIV4 S5PC1XX_CLKREG(0x310) - -#define S5PC100_CLK_OUT S5PC1XX_CLKREG(0x400) - -#define S5PC100_CLKGATE_D00 S5PC1XX_CLKREG(0x500) -#define S5PC100_CLKGATE_D01 S5PC1XX_CLKREG(0x504) -#define S5PC100_CLKGATE_D02 S5PC1XX_CLKREG(0x508) - -#define S5PC100_CLKGATE_D10 S5PC1XX_CLKREG(0x520) -#define S5PC100_CLKGATE_D11 S5PC1XX_CLKREG(0x524) -#define S5PC100_CLKGATE_D12 S5PC1XX_CLKREG(0x528) -#define S5PC100_CLKGATE_D13 S5PC1XX_CLKREG(0x52C) -#define S5PC100_CLKGATE_D14 S5PC1XX_CLKREG(0x530) -#define S5PC100_CLKGATE_D15 S5PC1XX_CLKREG(0x534) - -#define S5PC100_CLKGATE_D20 S5PC1XX_CLKREG(0x540) - -#define S5PC100_SCLKGATE0 S5PC1XX_CLKREG(0x560) -#define S5PC100_SCLKGATE1 S5PC1XX_CLKREG(0x564) - -#define S5PC100_OTHERS S5PC1XX_CLKREG(0x8200) - -#define S5PC1XX_EPLL_EN (1<<31) -#define S5PC1XX_EPLL_MASK 0xffffffff -#define S5PC1XX_EPLLVAL(_m, _p, _s) ((_m) << 16 | ((_p) << 8) | ((_s))) +#define S5PC100_CLKREG(x) (S5PC1XX_VA_CLK + (x)) +#define S5PC100_CLKREG_OTHER(x) (S5PC1XX_VA_CLK_OTHER + (x)) + +/* s5pc100 register for clock */ +#define S5PC100_APLL_LOCK S5PC100_CLKREG(0x00) +#define S5PC100_MPLL_LOCK S5PC100_CLKREG(0x04) +#define S5PC100_EPLL_LOCK S5PC100_CLKREG(0x08) +#define S5PC100_HPLL_LOCK S5PC100_CLKREG(0x0C) + +#define S5PC100_APLL_CON S5PC100_CLKREG(0x100) +#define S5PC100_MPLL_CON S5PC100_CLKREG(0x104) +#define S5PC100_EPLL_CON S5PC100_CLKREG(0x108) +#define S5PC100_HPLL_CON S5PC100_CLKREG(0x10C) + +#define S5PC100_CLKSRC0 S5PC100_CLKREG(0x200) +#define S5PC100_CLKSRC1 S5PC100_CLKREG(0x204) +#define S5PC100_CLKSRC2 S5PC100_CLKREG(0x208) +#define S5PC100_CLKSRC3 S5PC100_CLKREG(0x20C) + +#define S5PC100_CLKDIV0 S5PC100_CLKREG(0x300) +#define S5PC100_CLKDIV1 S5PC100_CLKREG(0x304) +#define S5PC100_CLKDIV2 S5PC100_CLKREG(0x308) +#define S5PC100_CLKDIV3 S5PC100_CLKREG(0x30C) +#define S5PC100_CLKDIV4 S5PC100_CLKREG(0x310) + +#define S5PC100_CLK_OUT S5PC100_CLKREG(0x400) + +#define S5PC100_CLKGATE_D00 S5PC100_CLKREG(0x500) +#define S5PC100_CLKGATE_D01 S5PC100_CLKREG(0x504) +#define S5PC100_CLKGATE_D02 S5PC100_CLKREG(0x508) + +#define S5PC100_CLKGATE_D10 S5PC100_CLKREG(0x520) +#define S5PC100_CLKGATE_D11 S5PC100_CLKREG(0x524) +#define S5PC100_CLKGATE_D12 S5PC100_CLKREG(0x528) +#define S5PC100_CLKGATE_D13 S5PC100_CLKREG(0x52C) +#define S5PC100_CLKGATE_D14 S5PC100_CLKREG(0x530) +#define S5PC100_CLKGATE_D15 S5PC100_CLKREG(0x534) + +#define S5PC100_CLKGATE_D20 S5PC100_CLKREG(0x540) + +#define S5PC100_SCLKGATE0 S5PC100_CLKREG(0x560) +#define S5PC100_SCLKGATE1 S5PC100_CLKREG(0x564) + +/* EPLL_CON */ +#define S5PC100_EPLL_EN (1<<31) +#define S5PC100_EPLL_MASK 0xffffffff +#define S5PC100_EPLLVAL(_m, _p, _s) ((_m) << 16 | ((_p) << 8) | ((_s))) /* CLKSRC0 */ -#define S5PC1XX_CLKSRC0_APLL_MASK (0x1<<0) -#define S5PC1XX_CLKSRC0_APLL_SHIFT (0) -#define S5PC1XX_CLKSRC0_MPLL_MASK (0x1<<4) -#define S5PC1XX_CLKSRC0_MPLL_SHIFT (4) -#define S5PC1XX_CLKSRC0_EPLL_MASK (0x1<<8) -#define S5PC1XX_CLKSRC0_EPLL_SHIFT (8) +#define S5PC100_CLKSRC0_APLL_MASK (0x1<<0) +#define S5PC100_CLKSRC0_APLL_SHIFT (0) +#define S5PC100_CLKSRC0_MPLL_MASK (0x1<<4) +#define S5PC100_CLKSRC0_MPLL_SHIFT (4) +#define S5PC100_CLKSRC0_EPLL_MASK (0x1<<8) +#define S5PC100_CLKSRC0_EPLL_SHIFT (8) #define S5PC100_CLKSRC0_HPLL_MASK (0x1<<12) #define S5PC100_CLKSRC0_HPLL_SHIFT (12) #define S5PC100_CLKSRC0_AMMUX_MASK (0x1<<16) #define S5PC100_CLKSRC0_AMMUX_SHIFT (16) #define S5PC100_CLKSRC0_HREF_MASK (0x1<<20) #define S5PC100_CLKSRC0_HREF_SHIFT (20) -#define S5PC1XX_CLKSRC0_ONENAND_MASK (0x1<<24) -#define S5PC1XX_CLKSRC0_ONENAND_SHIFT (24) +#define S5PC100_CLKSRC0_ONENAND_MASK (0x1<<24) +#define S5PC100_CLKSRC0_ONENAND_SHIFT (24) /* CLKSRC1 */ @@ -127,10 +128,9 @@ #define S5PC100_CLKSRC3_SPDIF_MASK (0x3<<24) #define S5PC100_CLKSRC3_SPDIF_SHIFT (24) - /* CLKDIV0 */ -#define S5PC1XX_CLKDIV0_APLL_MASK (0x1<<0) -#define S5PC1XX_CLKDIV0_APLL_SHIFT (0) +#define S5PC100_CLKDIV0_APLL_MASK (0x1<<0) +#define S5PC100_CLKDIV0_APLL_SHIFT (0) #define S5PC100_CLKDIV0_ARM_MASK (0x7<<4) #define S5PC100_CLKDIV0_ARM_SHIFT (4) #define S5PC100_CLKDIV0_D0_MASK (0x7<<8) @@ -141,8 +141,8 @@ #define S5PC100_CLKDIV0_SECSS_SHIFT (16) /* CLKDIV1 */ -#define S5PC100_CLKDIV1_AM_MASK (0x7<<0) -#define S5PC100_CLKDIV1_AM_SHIFT (0) +#define S5PC100_CLKDIV1_APLL2_MASK (0x7<<0) +#define S5PC100_CLKDIV1_APLL2_SHIFT (0) #define S5PC100_CLKDIV1_MPLL_MASK (0x3<<4) #define S5PC100_CLKDIV1_MPLL_SHIFT (4) #define S5PC100_CLKDIV1_MPLL2_MASK (0x1<<8) @@ -202,7 +202,6 @@ #define S5PC100_CLKDIV4_AUDIO2_MASK (0xf<<20) #define S5PC100_CLKDIV4_AUDIO2_SHIFT (20) - /* HCLKD0/PCLKD0 Clock Gate 0 Registers */ #define S5PC100_CLKGATE_D00_INTC (1<<0) #define S5PC100_CLKGATE_D00_TZIC (1<<1) @@ -295,8 +294,8 @@ #define S5PC100_CLKGATE_D20_I2SD2 (1<<1) /* Special Clock Gate 0 Registers */ -#define S5PC1XX_CLKGATE_SCLK0_HPM (1<<0) -#define S5PC1XX_CLKGATE_SCLK0_PWI (1<<1) +#define S5PC100_CLKGATE_SCLK0_HPM (1<<0) +#define S5PC100_CLKGATE_SCLK0_PWI (1<<1) #define S5PC100_CLKGATE_SCLK0_ONENAND (1<<2) #define S5PC100_CLKGATE_SCLK0_UART (1<<3) #define S5PC100_CLKGATE_SCLK0_SPI0 (1<<4) @@ -329,89 +328,28 @@ #define S5PC100_CLKGATE_SCLK1_SPDIF (1<<11) #define S5PC100_CLKGATE_SCLK1_CAM (1<<12) -/* register for power management */ -#define S5PC100_PWR_CFG S5PC1XX_CLKREG(0x8000) -#define S5PC100_EINT_WAKEUP_MASK S5PC1XX_CLKREG(0x8004) -#define S5PC100_NORMAL_CFG S5PC1XX_CLKREG(0x8010) -#define S5PC100_STOP_CFG S5PC1XX_CLKREG(0x8014) -#define S5PC100_SLEEP_CFG S5PC1XX_CLKREG(0x8018) -#define S5PC100_STOP_MEM_CFG S5PC1XX_CLKREG(0x801C) -#define S5PC100_OSC_FREQ S5PC1XX_CLKREG(0x8100) -#define S5PC100_OSC_STABLE S5PC1XX_CLKREG(0x8104) -#define S5PC100_PWR_STABLE S5PC1XX_CLKREG(0x8108) -#define S5PC100_MTC_STABLE S5PC1XX_CLKREG(0x8110) -#define S5PC100_CLAMP_STABLE S5PC1XX_CLKREG(0x8114) -#define S5PC100_OTHERS S5PC1XX_CLKREG(0x8200) -#define S5PC100_RST_STAT S5PC1XX_CLKREG(0x8300) -#define S5PC100_WAKEUP_STAT S5PC1XX_CLKREG(0x8304) -#define S5PC100_BLK_PWR_STAT S5PC1XX_CLKREG(0x8308) -#define S5PC100_INFORM0 S5PC1XX_CLKREG(0x8400) -#define S5PC100_INFORM1 S5PC1XX_CLKREG(0x8404) -#define S5PC100_INFORM2 S5PC1XX_CLKREG(0x8408) -#define S5PC100_INFORM3 S5PC1XX_CLKREG(0x840C) -#define S5PC100_INFORM4 S5PC1XX_CLKREG(0x8410) -#define S5PC100_INFORM5 S5PC1XX_CLKREG(0x8414) -#define S5PC100_INFORM6 S5PC1XX_CLKREG(0x8418) -#define S5PC100_INFORM7 S5PC1XX_CLKREG(0x841C) -#define S5PC100_DCGIDX_MAP0 S5PC1XX_CLKREG(0x8500) -#define S5PC100_DCGIDX_MAP1 S5PC1XX_CLKREG(0x8504) -#define S5PC100_DCGIDX_MAP2 S5PC1XX_CLKREG(0x8508) -#define S5PC100_DCGPERF_MAP0 S5PC1XX_CLKREG(0x850C) -#define S5PC100_DCGPERF_MAP1 S5PC1XX_CLKREG(0x8510) -#define S5PC100_DVCIDX_MAP S5PC1XX_CLKREG(0x8514) -#define S5PC100_FREQ_CPU S5PC1XX_CLKREG(0x8518) -#define S5PC100_FREQ_DPM S5PC1XX_CLKREG(0x851C) -#define S5PC100_DVSEMCLK_EN S5PC1XX_CLKREG(0x8520) -#define S5PC100_APLL_CON_L8 S5PC1XX_CLKREG(0x8600) -#define S5PC100_APLL_CON_L7 S5PC1XX_CLKREG(0x8604) -#define S5PC100_APLL_CON_L6 S5PC1XX_CLKREG(0x8608) -#define S5PC100_APLL_CON_L5 S5PC1XX_CLKREG(0x860C) -#define S5PC100_APLL_CON_L4 S5PC1XX_CLKREG(0x8610) -#define S5PC100_APLL_CON_L3 S5PC1XX_CLKREG(0x8614) -#define S5PC100_APLL_CON_L2 S5PC1XX_CLKREG(0x8618) -#define S5PC100_APLL_CON_L1 S5PC1XX_CLKREG(0x861C) -#define S5PC100_IEM_CONTROL S5PC1XX_CLKREG(0x8620) -#define S5PC100_CLKDIV_IEM_L8 S5PC1XX_CLKREG(0x8700) -#define S5PC100_CLKDIV_IEM_L7 S5PC1XX_CLKREG(0x8704) -#define S5PC100_CLKDIV_IEM_L6 S5PC1XX_CLKREG(0x8708) -#define S5PC100_CLKDIV_IEM_L5 S5PC1XX_CLKREG(0x870C) -#define S5PC100_CLKDIV_IEM_L4 S5PC1XX_CLKREG(0x8710) -#define S5PC100_CLKDIV_IEM_L3 S5PC1XX_CLKREG(0x8714) -#define S5PC100_CLKDIV_IEM_L2 S5PC1XX_CLKREG(0x8718) -#define S5PC100_CLKDIV_IEM_L1 S5PC1XX_CLKREG(0x871C) -#define S5PC100_IEM_HPMCLK_DIV S5PC1XX_CLKREG(0x8724) - -#define S5PC100_SWRESET S5PC1XX_CLKREG(0x100000) -#define S5PC100_OND_SWRESET S5PC1XX_CLKREG(0x100008) -#define S5PC100_GEN_CTRL S5PC1XX_CLKREG(0x100100) -#define S5PC100_GEN_STATUS S5PC1XX_CLKREG(0x100104) -#define S5PC100_MEM_SYS_CFG S5PC1XX_CLKREG(0x100200) -#define S5PC100_CAM_MUX_SEL S5PC1XX_CLKREG(0x100300) -#define S5PC100_MIXER_OUT_SEL S5PC1XX_CLKREG(0x100304) -#define S5PC100_LPMP_MODE_SEL S5PC1XX_CLKREG(0x100308) -#define S5PC100_MIPI_PHY_CON0 S5PC1XX_CLKREG(0x100400) -#define S5PC100_MIPI_PHY_CON1 S5PC1XX_CLKREG(0x100414) -#define S5PC100_HDMI_PHY_CON0 S5PC1XX_CLKREG(0x100420) - -#define S5PC100_CFG_WFI_CLEAN (~(3<<5)) -#define S5PC100_CFG_WFI_IDLE (1<<5) -#define S5PC100_CFG_WFI_STOP (2<<5) -#define S5PC100_CFG_WFI_SLEEP (3<<5) - +#define S5PC100_SWRESET S5PC100_CLKREG_OTHER(0x000) +#define S5PC100_OND_SWRESET S5PC100_CLKREG_OTHER(0x008) +#define S5PC100_GEN_CTRL S5PC100_CLKREG_OTHER(0x100) +#define S5PC100_GEN_STATUS S5PC100_CLKREG_OTHER(0x104) +#define S5PC100_MEM_SYS_CFG S5PC100_CLKREG_OTHER(0x200) +#define S5PC100_CAM_MUX_SEL S5PC100_CLKREG_OTHER(0x300) +#define S5PC100_MIXER_OUT_SEL S5PC100_CLKREG_OTHER(0x304) +#define S5PC100_LPMP_MODE_SEL S5PC100_CLKREG_OTHER(0x308) +#define S5PC100_MIPI_PHY_CON0 S5PC100_CLKREG_OTHER(0x400) +#define S5PC100_MIPI_PHY_CON1 S5PC100_CLKREG_OTHER(0x414) +#define S5PC100_HDMI_PHY_CON0 S5PC100_CLKREG_OTHER(0x420) + +#define S5PC100_SWRESET_RESETVAL 0xc100 #define S5PC100_OTHER_SYS_INT 24 #define S5PC100_OTHER_STA_TYPE 23 #define STA_TYPE_EXPON 0 #define STA_TYPE_SFR 1 -#define S5PC100_PWR_STA_EXP_SCALE 0 -#define S5PC100_PWR_STA_CNT 4 - -#define S5PC100_PWR_STABLE_COUNT 85500 - #define S5PC100_SLEEP_CFG_OSC_EN 0 /* OTHERS Resgister */ -#define S5PC100_OTHERS_USB_SIG_MASK (1 << 16) +#define S5PC100_OTHERS_USB_SIG_MASK (1 << 16) #define S5PC100_OTHERS_MIPI_DPHY_EN (1 << 28) /* MIPI D-PHY Control Register 0 */ diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h b/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h new file mode 100644 index 00000000000..43c7bc8bf78 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h @@ -0,0 +1,70 @@ +/* linux/arch/arm/plat-s5pc1xx/include/plat/regs-gpio.h + * + * Copyright 2009 Samsung Electronics Co. + * Byungho Min <bhmin@samsung.com> + * + * S5PC1XX - GPIO register definitions + */ + +#ifndef __ASM_PLAT_S5PC1XX_REGS_GPIO_H +#define __ASM_PLAT_S5PC1XX_REGS_GPIO_H __FILE__ + +#include <mach/map.h> + +/* S5PC100 */ +#define S5PC100_GPIO_BASE S5PC1XX_VA_GPIO +#define S5PC100_GPA0_BASE (S5PC100_GPIO_BASE + 0x0000) +#define S5PC100_GPA1_BASE (S5PC100_GPIO_BASE + 0x0020) +#define S5PC100_GPB_BASE (S5PC100_GPIO_BASE + 0x0040) +#define S5PC100_GPC_BASE (S5PC100_GPIO_BASE + 0x0060) +#define S5PC100_GPD_BASE (S5PC100_GPIO_BASE + 0x0080) +#define S5PC100_GPE0_BASE (S5PC100_GPIO_BASE + 0x00A0) +#define S5PC100_GPE1_BASE (S5PC100_GPIO_BASE + 0x00C0) +#define S5PC100_GPF0_BASE (S5PC100_GPIO_BASE + 0x00E0) +#define S5PC100_GPF1_BASE (S5PC100_GPIO_BASE + 0x0100) +#define S5PC100_GPF2_BASE (S5PC100_GPIO_BASE + 0x0120) +#define S5PC100_GPF3_BASE (S5PC100_GPIO_BASE + 0x0140) +#define S5PC100_GPG0_BASE (S5PC100_GPIO_BASE + 0x0160) +#define S5PC100_GPG1_BASE (S5PC100_GPIO_BASE + 0x0180) +#define S5PC100_GPG2_BASE (S5PC100_GPIO_BASE + 0x01A0) +#define S5PC100_GPG3_BASE (S5PC100_GPIO_BASE + 0x01C0) +#define S5PC100_GPH0_BASE (S5PC100_GPIO_BASE + 0x0C00) +#define S5PC100_GPH1_BASE (S5PC100_GPIO_BASE + 0x0C20) +#define S5PC100_GPH2_BASE (S5PC100_GPIO_BASE + 0x0C40) +#define S5PC100_GPH3_BASE (S5PC100_GPIO_BASE + 0x0C60) +#define S5PC100_GPI_BASE (S5PC100_GPIO_BASE + 0x01E0) +#define S5PC100_GPJ0_BASE (S5PC100_GPIO_BASE + 0x0200) +#define S5PC100_GPJ1_BASE (S5PC100_GPIO_BASE + 0x0220) +#define S5PC100_GPJ2_BASE (S5PC100_GPIO_BASE + 0x0240) +#define S5PC100_GPJ3_BASE (S5PC100_GPIO_BASE + 0x0260) +#define S5PC100_GPJ4_BASE (S5PC100_GPIO_BASE + 0x0280) +#define S5PC100_GPK0_BASE (S5PC100_GPIO_BASE + 0x02A0) +#define S5PC100_GPK1_BASE (S5PC100_GPIO_BASE + 0x02C0) +#define S5PC100_GPK2_BASE (S5PC100_GPIO_BASE + 0x02E0) +#define S5PC100_GPK3_BASE (S5PC100_GPIO_BASE + 0x0300) +#define S5PC100_GPL0_BASE (S5PC100_GPIO_BASE + 0x0320) +#define S5PC100_GPL1_BASE (S5PC100_GPIO_BASE + 0x0340) +#define S5PC100_GPL2_BASE (S5PC100_GPIO_BASE + 0x0360) +#define S5PC100_GPL3_BASE (S5PC100_GPIO_BASE + 0x0380) +#define S5PC100_GPL4_BASE (S5PC100_GPIO_BASE + 0x03A0) +#define S5PC100_EINT_BASE (S5PC100_GPIO_BASE + 0x0E00) + +#define S5PC100_UHOST (S5PC100_GPIO_BASE + 0x0B68) +#define S5PC100_PDNEN (S5PC100_GPIO_BASE + 0x0F80) + +/* PDNEN */ +#define S5PC100_PDNEN_CFG_PDNEN (1 << 1) +#define S5PC100_PDNEN_CFG_AUTO (0 << 1) +#define S5PC100_PDNEN_POWERDOWN (1 << 0) +#define S5PC100_PDNEN_NORMAL (0 << 0) + +/* Common part */ +/* External interrupt base is same at both s5pc100 and s5pc110 */ +#define S5PC1XX_EINT_BASE (S5PC100_EINT_BASE) + +#define S5PC100_GPx_INPUT(__gpio) (0x0 << ((__gpio) * 4)) +#define S5PC100_GPx_OUTPUT(__gpio) (0x1 << ((__gpio) * 4)) +#define S5PC100_GPx_CONMASK(__gpio) (0xf << ((__gpio) * 4)) + +#endif /* __ASM_PLAT_S5PC1XX_REGS_GPIO_H */ + diff --git a/arch/arm/plat-s5pc1xx/include/plat/regs-power.h b/arch/arm/plat-s5pc1xx/include/plat/regs-power.h new file mode 100644 index 00000000000..02ffa491b53 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/include/plat/regs-power.h @@ -0,0 +1,84 @@ +/* arch/arm/plat-s5pc1xx/include/plat/regs-clock.h + * + * Copyright 2009 Samsung Electronics Co. + * Jongse Won <jongse.won@samsung.com> + * + * S5PC1XX clock register definitions + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef __ASM_ARM_REGS_PWR +#define __ASM_ARM_REGS_PWR __FILE__ + +#define S5PC1XX_PWRREG(x) (S5PC1XX_VA_PWR + (x)) + +/* s5pc100 (0xE0108000) register for power management */ +#define S5PC100_PWR_CFG S5PC1XX_PWRREG(0x0) +#define S5PC100_EINT_WAKEUP_MASK S5PC1XX_PWRREG(0x4) +#define S5PC100_NORMAL_CFG S5PC1XX_PWRREG(0x10) +#define S5PC100_STOP_CFG S5PC1XX_PWRREG(0x14) +#define S5PC100_SLEEP_CFG S5PC1XX_PWRREG(0x18) +#define S5PC100_STOP_MEM_CFG S5PC1XX_PWRREG(0x1C) +#define S5PC100_OSC_FREQ S5PC1XX_PWRREG(0x100) +#define S5PC100_OSC_STABLE S5PC1XX_PWRREG(0x104) +#define S5PC100_PWR_STABLE S5PC1XX_PWRREG(0x108) +#define S5PC100_MTC_STABLE S5PC1XX_PWRREG(0x110) +#define S5PC100_CLAMP_STABLE S5PC1XX_PWRREG(0x114) +#define S5PC100_OTHERS S5PC1XX_PWRREG(0x200) +#define S5PC100_RST_STAT S5PC1XX_PWRREG(0x300) +#define S5PC100_WAKEUP_STAT S5PC1XX_PWRREG(0x304) +#define S5PC100_BLK_PWR_STAT S5PC1XX_PWRREG(0x308) +#define S5PC100_INFORM0 S5PC1XX_PWRREG(0x400) +#define S5PC100_INFORM1 S5PC1XX_PWRREG(0x404) +#define S5PC100_INFORM2 S5PC1XX_PWRREG(0x408) +#define S5PC100_INFORM3 S5PC1XX_PWRREG(0x40C) +#define S5PC100_INFORM4 S5PC1XX_PWRREG(0x410) +#define S5PC100_INFORM5 S5PC1XX_PWRREG(0x414) +#define S5PC100_INFORM6 S5PC1XX_PWRREG(0x418) +#define S5PC100_INFORM7 S5PC1XX_PWRREG(0x41C) +#define S5PC100_DCGIDX_MAP0 S5PC1XX_PWRREG(0x500) +#define S5PC100_DCGIDX_MAP1 S5PC1XX_PWRREG(0x504) +#define S5PC100_DCGIDX_MAP2 S5PC1XX_PWRREG(0x508) +#define S5PC100_DCGPERF_MAP0 S5PC1XX_PWRREG(0x50C) +#define S5PC100_DCGPERF_MAP1 S5PC1XX_PWRREG(0x510) +#define S5PC100_DVCIDX_MAP S5PC1XX_PWRREG(0x514) +#define S5PC100_FREQ_CPU S5PC1XX_PWRREG(0x518) +#define S5PC100_FREQ_DPM S5PC1XX_PWRREG(0x51C) +#define S5PC100_DVSEMCLK_EN S5PC1XX_PWRREG(0x520) +#define S5PC100_APLL_CON_L8 S5PC1XX_PWRREG(0x600) +#define S5PC100_APLL_CON_L7 S5PC1XX_PWRREG(0x604) +#define S5PC100_APLL_CON_L6 S5PC1XX_PWRREG(0x608) +#define S5PC100_APLL_CON_L5 S5PC1XX_PWRREG(0x60C) +#define S5PC100_APLL_CON_L4 S5PC1XX_PWRREG(0x610) +#define S5PC100_APLL_CON_L3 S5PC1XX_PWRREG(0x614) +#define S5PC100_APLL_CON_L2 S5PC1XX_PWRREG(0x618) +#define S5PC100_APLL_CON_L1 S5PC1XX_PWRREG(0x61C) +#define S5PC100_IEM_CONTROL S5PC1XX_PWRREG(0x620) +#define S5PC100_CLKDIV_IEM_L8 S5PC1XX_PWRREG(0x700) +#define S5PC100_CLKDIV_IEM_L7 S5PC1XX_PWRREG(0x704) +#define S5PC100_CLKDIV_IEM_L6 S5PC1XX_PWRREG(0x708) +#define S5PC100_CLKDIV_IEM_L5 S5PC1XX_PWRREG(0x70C) +#define S5PC100_CLKDIV_IEM_L4 S5PC1XX_PWRREG(0x710) +#define S5PC100_CLKDIV_IEM_L3 S5PC1XX_PWRREG(0x714) +#define S5PC100_CLKDIV_IEM_L2 S5PC1XX_PWRREG(0x718) +#define S5PC100_CLKDIV_IEM_L1 S5PC1XX_PWRREG(0x71C) +#define S5PC100_IEM_HPMCLK_DIV S5PC1XX_PWRREG(0x724) + +/* PWR_CFG */ +#define S5PC100_PWRCFG_CFG_DEEP_IDLE (1 << 31) +#define S5PC100_PWRCFG_CFG_WFI_MASK (3 << 5) +#define S5PC100_PWRCFG_CFG_WFI_IDLE (0 << 5) +#define S5PC100_PWRCFG_CFG_WFI_DEEP_IDLE (1 << 5) +#define S5PC100_PWRCFG_CFG_WFI_STOP (2 << 5) +#define S5PC100_PWRCFG_CFG_WFI_SLEEP (3 << 5) + +/* SLEEP_CFG */ +#define S5PC100_SLEEP_OSC_EN_SLEEP (1 << 0) + +/* OTHERS */ +#define S5PC100_PMU_INT_DISABLE (1 << 24) + +#endif /* __ASM_ARM_REGS_PWR */ diff --git a/arch/arm/plat-s5pc1xx/include/plat/s5pc100.h b/arch/arm/plat-s5pc1xx/include/plat/s5pc100.h index 45e27513166..2531f34a56f 100644 --- a/arch/arm/plat-s5pc1xx/include/plat/s5pc100.h +++ b/arch/arm/plat-s5pc1xx/include/plat/s5pc100.h @@ -35,10 +35,9 @@ extern struct clk clk_hpll; extern struct clk clk_hd0; extern struct clk clk_pd0; extern struct clk clk_54m; -extern struct clk clk_dout_mpll2; extern void s5pc1xx_register_clocks(void); -extern int s5pc1xx_sclk0_ctrl(struct clk *clk, int enable); -extern int s5pc1xx_sclk1_ctrl(struct clk *clk, int enable); +extern int s5pc100_sclk0_ctrl(struct clk *clk, int enable); +extern int s5pc100_sclk1_ctrl(struct clk *clk, int enable); /* Some day, belows will be moved to plat-s5pc/include/plat/devs.h */ extern struct s3c24xx_uart_resources s5pc1xx_uart_resources[]; diff --git a/arch/arm/plat-s5pc1xx/irq-eint.c b/arch/arm/plat-s5pc1xx/irq-eint.c new file mode 100644 index 00000000000..373122f57d5 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/irq-eint.c @@ -0,0 +1,281 @@ +/* + * linux/arch/arm/plat-s5pc1xx/irq-eint.c + * + * Copyright 2009 Samsung Electronics Co. + * Byungho Min <bhmin@samsung.com> + * Kyungin Park <kyungmin.park@samsung.com> + * + * Based on plat-s3c64xx/irq-eint.c + * + * S5PC1XX - Interrupt handling for IRQ_EINT(x) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/sysdev.h> +#include <linux/pm.h> +#include <linux/gpio.h> + +#include <asm/hardware/vic.h> + +#include <mach/map.h> + +#include <plat/gpio-cfg.h> +#include <plat/gpio-ext.h> +#include <plat/pm.h> +#include <plat/regs-gpio.h> +#include <plat/regs-irqtype.h> + +/* + * bank is a group of external interrupt + * bank0 means EINT0 ... EINT7 + * bank1 means EINT8 ... EINT15 + * bank2 means EINT16 ... EINT23 + * bank3 means EINT24 ... EINT31 + */ + +static inline int s3c_get_eint(unsigned int irq) +{ + int real; + + if (irq < IRQ_EINT16_31) + real = (irq - IRQ_EINT0); + else + real = (irq - S3C_IRQ_EINT_BASE) + IRQ_EINT16_31 - IRQ_EINT0; + + return real; +} + +static inline int s3c_get_bank(unsigned int irq) +{ + return s3c_get_eint(irq) >> 3; +} + +static inline int s3c_eint_to_bit(unsigned int irq) +{ + int real, bit; + + real = s3c_get_eint(irq); + bit = 1 << (real & (8 - 1)); + + return bit; +} + +static inline void s3c_irq_eint_mask(unsigned int irq) +{ + u32 mask; + u32 bank = s3c_get_bank(irq); + + mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank)); + mask |= s3c_eint_to_bit(irq); + __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank)); +} + +static void s3c_irq_eint_unmask(unsigned int irq) +{ + u32 mask; + u32 bank = s3c_get_bank(irq); + + mask = __raw_readl(S5PC1XX_WKUP_INT_MASK(bank)); + mask &= ~(s3c_eint_to_bit(irq)); + __raw_writel(mask, S5PC1XX_WKUP_INT_MASK(bank)); +} + +static inline void s3c_irq_eint_ack(unsigned int irq) +{ + u32 bank = s3c_get_bank(irq); + + __raw_writel(s3c_eint_to_bit(irq), S5PC1XX_WKUP_INT_PEND(bank)); +} + +static void s3c_irq_eint_maskack(unsigned int irq) +{ + /* compiler should in-line these */ + s3c_irq_eint_mask(irq); + s3c_irq_eint_ack(irq); +} + +static int s3c_irq_eint_set_type(unsigned int irq, unsigned int type) +{ + u32 bank = s3c_get_bank(irq); + int real = s3c_get_eint(irq); + int gpio, shift, sfn; + u32 ctrl, con = 0; + + switch (type) { + case IRQ_TYPE_NONE: + printk(KERN_WARNING "No edge setting!\n"); + break; + + case IRQ_TYPE_EDGE_RISING: + con = S5PC1XX_WKUP_INT_RISEEDGE; + break; + + case IRQ_TYPE_EDGE_FALLING: + con = S5PC1XX_WKUP_INT_FALLEDGE; + break; + + case IRQ_TYPE_EDGE_BOTH: + con = S5PC1XX_WKUP_INT_BOTHEDGE; + break; + + case IRQ_TYPE_LEVEL_LOW: + con = S5PC1XX_WKUP_INT_LOWLEV; + break; + + case IRQ_TYPE_LEVEL_HIGH: + con = S5PC1XX_WKUP_INT_HILEV; + break; + + default: + printk(KERN_ERR "No such irq type %d", type); + return -EINVAL; + } + + gpio = real & (8 - 1); + shift = gpio << 2; + + ctrl = __raw_readl(S5PC1XX_WKUP_INT_CON(bank)); + ctrl &= ~(0x7 << shift); + ctrl |= con << shift; + __raw_writel(ctrl, S5PC1XX_WKUP_INT_CON(bank)); + + switch (real) { + case 0 ... 7: + gpio = S5PC100_GPH0(gpio); + break; + case 8 ... 15: + gpio = S5PC100_GPH1(gpio); + break; + case 16 ... 23: + gpio = S5PC100_GPH2(gpio); + break; + case 24 ... 31: + gpio = S5PC100_GPH3(gpio); + break; + default: + return -EINVAL; + } + + sfn = S3C_GPIO_SFN(0x2); + s3c_gpio_cfgpin(gpio, sfn); + + return 0; +} + +static struct irq_chip s3c_irq_eint = { + .name = "EINT", + .mask = s3c_irq_eint_mask, + .unmask = s3c_irq_eint_unmask, + .mask_ack = s3c_irq_eint_maskack, + .ack = s3c_irq_eint_ack, + .set_type = s3c_irq_eint_set_type, + .set_wake = s3c_irqext_wake, +}; + +/* s3c_irq_demux_eint + * + * This function demuxes the IRQ from external interrupts, + * from IRQ_EINT(16) to IRQ_EINT(31). 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(S5PC1XX_WKUP_INT_PEND((start >> 3))); + u32 mask = __raw_readl(S5PC1XX_WKUP_INT_MASK((start >> 3))); + unsigned int irq; + + status &= ~mask; + 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_eint16_31(unsigned int irq, struct irq_desc *desc) +{ + s3c_irq_demux_eint(16, 23); + s3c_irq_demux_eint(24, 31); +} + +/* + * Handle EINT0 ... EINT15 at VIC directly + */ +static void s3c_irq_vic_eint_mask(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + unsigned int real; + + s3c_irq_eint_mask(irq); + real = s3c_get_eint(irq); + writel(1 << real, base + VIC_INT_ENABLE_CLEAR); +} + +static void s3c_irq_vic_eint_unmask(unsigned int irq) +{ + void __iomem *base = get_irq_chip_data(irq); + unsigned int real; + + s3c_irq_eint_unmask(irq); + real = s3c_get_eint(irq); + writel(1 << real, base + VIC_INT_ENABLE); +} + +static inline void s3c_irq_vic_eint_ack(unsigned int irq) +{ + u32 bit; + u32 bank = s3c_get_bank(irq); + + bit = s3c_eint_to_bit(irq); + __raw_writel(bit, S5PC1XX_WKUP_INT_PEND(bank)); +} + +static void s3c_irq_vic_eint_maskack(unsigned int irq) +{ + /* compiler should in-line these */ + s3c_irq_vic_eint_mask(irq); + s3c_irq_vic_eint_ack(irq); +} + +static struct irq_chip s3c_irq_vic_eint = { + .name = "EINT", + .mask = s3c_irq_vic_eint_mask, + .unmask = s3c_irq_vic_eint_unmask, + .mask_ack = s3c_irq_vic_eint_maskack, + .ack = s3c_irq_vic_eint_ack, + .set_type = s3c_irq_eint_set_type, + .set_wake = s3c_irqext_wake, +}; + +static int __init s5pc1xx_init_irq_eint(void) +{ + int irq; + + for (irq = IRQ_EINT0; irq <= IRQ_EINT15; irq++) { + set_irq_chip(irq, &s3c_irq_vic_eint); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + + for (irq = IRQ_EINT(16); irq <= IRQ_EINT(31); irq++) { + set_irq_chip(irq, &s3c_irq_eint); + set_irq_handler(irq, handle_level_irq); + set_irq_flags(irq, IRQF_VALID); + } + + set_irq_chained_handler(IRQ_EINT16_31, s3c_irq_demux_eint16_31); + + return 0; +} + +arch_initcall(s5pc1xx_init_irq_eint); diff --git a/arch/arm/plat-s5pc1xx/irq-gpio.c b/arch/arm/plat-s5pc1xx/irq-gpio.c new file mode 100644 index 00000000000..fecca7a679b --- /dev/null +++ b/arch/arm/plat-s5pc1xx/irq-gpio.c @@ -0,0 +1,266 @@ +/* + * arch/arm/plat-s5pc1xx/irq-gpio.c + * + * Copyright (C) 2009 Samsung Electronics + * + * S5PC1XX - Interrupt handling for IRQ_GPIO${group}(x) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/gpio.h> + +#include <mach/map.h> +#include <plat/gpio-cfg.h> + +#define S5PC1XX_GPIOREG(x) (S5PC1XX_VA_GPIO + (x)) + +#define CON_OFFSET 0x700 +#define MASK_OFFSET 0x900 +#define PEND_OFFSET 0xA00 +#define CON_OFFSET_2 0xE00 +#define MASK_OFFSET_2 0xF00 +#define PEND_OFFSET_2 0xF40 + +#define GPIOINT_LEVEL_LOW 0x0 +#define GPIOINT_LEVEL_HIGH 0x1 +#define GPIOINT_EDGE_FALLING 0x2 +#define GPIOINT_EDGE_RISING 0x3 +#define GPIOINT_EDGE_BOTH 0x4 + +static int group_to_con_offset(int group) +{ + return group << 2; +} + +static int group_to_mask_offset(int group) +{ + return group << 2; +} + +static int group_to_pend_offset(int group) +{ + return group << 2; +} + +static int s5pc1xx_get_start(unsigned int group) +{ + switch (group) { + case 0: return S5PC100_GPIO_A0_START; + case 1: return S5PC100_GPIO_A1_START; + case 2: return S5PC100_GPIO_B_START; + case 3: return S5PC100_GPIO_C_START; + case 4: return S5PC100_GPIO_D_START; + case 5: return S5PC100_GPIO_E0_START; + case 6: return S5PC100_GPIO_E1_START; + case 7: return S5PC100_GPIO_F0_START; + case 8: return S5PC100_GPIO_F1_START; + case 9: return S5PC100_GPIO_F2_START; + case 10: return S5PC100_GPIO_F3_START; + case 11: return S5PC100_GPIO_G0_START; + case 12: return S5PC100_GPIO_G1_START; + case 13: return S5PC100_GPIO_G2_START; + case 14: return S5PC100_GPIO_G3_START; + case 15: return S5PC100_GPIO_I_START; + case 16: return S5PC100_GPIO_J0_START; + case 17: return S5PC100_GPIO_J1_START; + case 18: return S5PC100_GPIO_J2_START; + case 19: return S5PC100_GPIO_J3_START; + case 20: return S5PC100_GPIO_J4_START; + default: + BUG(); + } + + return -EINVAL; +} + +static int s5pc1xx_get_group(unsigned int irq) +{ + irq -= S3C_IRQ_GPIO(0); + + switch (irq) { + case S5PC100_GPIO_A0_START ... S5PC100_GPIO_A1_START - 1: + return 0; + case S5PC100_GPIO_A1_START ... S5PC100_GPIO_B_START - 1: + return 1; + case S5PC100_GPIO_B_START ... S5PC100_GPIO_C_START - 1: + return 2; + case S5PC100_GPIO_C_START ... S5PC100_GPIO_D_START - 1: + return 3; + case S5PC100_GPIO_D_START ... S5PC100_GPIO_E0_START - 1: + return 4; + case S5PC100_GPIO_E0_START ... S5PC100_GPIO_E1_START - 1: + return 5; + case S5PC100_GPIO_E1_START ... S5PC100_GPIO_F0_START - 1: + return 6; + case S5PC100_GPIO_F0_START ... S5PC100_GPIO_F1_START - 1: + return 7; + case S5PC100_GPIO_F1_START ... S5PC100_GPIO_F2_START - 1: + return 8; + case S5PC100_GPIO_F2_START ... S5PC100_GPIO_F3_START - 1: + return 9; + case S5PC100_GPIO_F3_START ... S5PC100_GPIO_G0_START - 1: + return 10; + case S5PC100_GPIO_G0_START ... S5PC100_GPIO_G1_START - 1: + return 11; + case S5PC100_GPIO_G1_START ... S5PC100_GPIO_G2_START - 1: + return 12; + case S5PC100_GPIO_G2_START ... S5PC100_GPIO_G3_START - 1: + return 13; + case S5PC100_GPIO_G3_START ... S5PC100_GPIO_H0_START - 1: + return 14; + case S5PC100_GPIO_I_START ... S5PC100_GPIO_J0_START - 1: + return 15; + case S5PC100_GPIO_J0_START ... S5PC100_GPIO_J1_START - 1: + return 16; + case S5PC100_GPIO_J1_START ... S5PC100_GPIO_J2_START - 1: + return 17; + case S5PC100_GPIO_J2_START ... S5PC100_GPIO_J3_START - 1: + return 18; + case S5PC100_GPIO_J3_START ... S5PC100_GPIO_J4_START - 1: + return 19; + case S5PC100_GPIO_J4_START ... S5PC100_GPIO_K0_START - 1: + return 20; + default: + BUG(); + } + + return -EINVAL; +} + +static int s5pc1xx_get_offset(unsigned int irq) +{ + struct gpio_chip *chip = get_irq_data(irq); + return irq - S3C_IRQ_GPIO(chip->base); +} + +static void s5pc1xx_gpioint_ack(unsigned int irq) +{ + int group, offset, pend_offset; + unsigned int value; + + group = s5pc1xx_get_group(irq); + offset = s5pc1xx_get_offset(irq); + pend_offset = group_to_pend_offset(group); + + value = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset); + value |= 1 << offset; + __raw_writel(value, S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset); +} + +static void s5pc1xx_gpioint_mask(unsigned int irq) +{ + int group, offset, mask_offset; + unsigned int value; + + group = s5pc1xx_get_group(irq); + offset = s5pc1xx_get_offset(irq); + mask_offset = group_to_mask_offset(group); + + value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset); + value |= 1 << offset; + __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset); +} + +static void s5pc1xx_gpioint_unmask(unsigned int irq) +{ + int group, offset, mask_offset; + unsigned int value; + + group = s5pc1xx_get_group(irq); + offset = s5pc1xx_get_offset(irq); + mask_offset = group_to_mask_offset(group); + + value = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset); + value &= ~(1 << offset); + __raw_writel(value, S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset); +} + +static void s5pc1xx_gpioint_mask_ack(unsigned int irq) +{ + s5pc1xx_gpioint_mask(irq); + s5pc1xx_gpioint_ack(irq); +} + +static int s5pc1xx_gpioint_set_type(unsigned int irq, unsigned int type) +{ + int group, offset, con_offset; + unsigned int value; + + group = s5pc1xx_get_group(irq); + offset = s5pc1xx_get_offset(irq); + con_offset = group_to_con_offset(group); + + switch (type) { + case IRQ_TYPE_NONE: + printk(KERN_WARNING "No irq type\n"); + return -EINVAL; + case IRQ_TYPE_EDGE_RISING: + type = GPIOINT_EDGE_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + type = GPIOINT_EDGE_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + type = GPIOINT_EDGE_BOTH; + break; + case IRQ_TYPE_LEVEL_HIGH: + type = GPIOINT_LEVEL_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + type = GPIOINT_LEVEL_LOW; + break; + default: + BUG(); + } + + + value = __raw_readl(S5PC1XX_GPIOREG(CON_OFFSET) + con_offset); + value &= ~(0xf << (offset * 0x4)); + value |= (type << (offset * 0x4)); + __raw_writel(value, S5PC1XX_GPIOREG(CON_OFFSET) + con_offset); + + return 0; +} + +struct irq_chip s5pc1xx_gpioint = { + .name = "GPIO", + .ack = s5pc1xx_gpioint_ack, + .mask = s5pc1xx_gpioint_mask, + .mask_ack = s5pc1xx_gpioint_mask_ack, + .unmask = s5pc1xx_gpioint_unmask, + .set_type = s5pc1xx_gpioint_set_type, +}; + +void s5pc1xx_irq_gpioint_handler(unsigned int irq, struct irq_desc *desc) +{ + int group, offset, pend_offset, mask_offset; + int real_irq, group_end; + unsigned int pend, mask; + + group_end = 21; + + for (group = 0; group < group_end; group++) { + pend_offset = group_to_pend_offset(group); + pend = __raw_readl(S5PC1XX_GPIOREG(PEND_OFFSET) + pend_offset); + if (!pend) + continue; + + mask_offset = group_to_mask_offset(group); + mask = __raw_readl(S5PC1XX_GPIOREG(MASK_OFFSET) + mask_offset); + pend &= ~mask; + + for (offset = 0; offset < 8; offset++) { + if (pend & (1 << offset)) { + real_irq = s5pc1xx_get_start(group) + offset; + generic_handle_irq(S3C_IRQ_GPIO(real_irq)); + } + } + } +} diff --git a/arch/arm/plat-s5pc1xx/irq.c b/arch/arm/plat-s5pc1xx/irq.c index 80d6dd942cb..e44fd04ef33 100644 --- a/arch/arm/plat-s5pc1xx/irq.c +++ b/arch/arm/plat-s5pc1xx/irq.c @@ -79,7 +79,7 @@ static void s3c_irq_timer_ack(unsigned int irq) { u32 reg = __raw_readl(S3C64XX_TINT_CSTAT); - reg &= 0x1f; + reg &= 0x1f; /* mask out pending interrupts */ reg |= (1 << 5) << (irq - IRQ_TIMER0); __raw_writel(reg, S3C64XX_TINT_CSTAT); } diff --git a/arch/arm/plat-s5pc1xx/s5pc100-clock.c b/arch/arm/plat-s5pc1xx/s5pc100-clock.c index 6b24035172f..b436d44510c 100644 --- a/arch/arm/plat-s5pc1xx/s5pc100-clock.c +++ b/arch/arm/plat-s5pc1xx/s5pc100-clock.c @@ -49,6 +49,7 @@ static struct clk clk_ext_xtal_mux = { #define clk_fin_hpll clk_ext_xtal_mux #define clk_fout_mpll clk_mpll +#define clk_vclk_54m clk_54m struct clk_sources { unsigned int nr_sources; @@ -67,746 +68,327 @@ struct clksrc_clk { void __iomem *reg_source; }; -static int clk_default_setrate(struct clk *clk, unsigned long rate) -{ - clk->rate = rate; - return 1; -} - -struct clk clk_27m = { - .name = "clk_27m", +/* APLL */ +static struct clk clk_fout_apll = { + .name = "fout_apll", .id = -1, .rate = 27000000, }; -static int clk_48m_ctrl(struct clk *clk, int enable) -{ - unsigned long flags; - u32 val; +static struct clk *clk_src_apll_list[] = { + [0] = &clk_fin_apll, + [1] = &clk_fout_apll, +}; + +static struct clk_sources clk_src_apll = { + .sources = clk_src_apll_list, + .nr_sources = ARRAY_SIZE(clk_src_apll_list), +}; - /* can't rely on clock lock, this register has other usages */ - local_irq_save(flags); +static struct clksrc_clk clk_mout_apll = { + .clk = { + .name = "mout_apll", + .id = -1, + }, + .shift = S5PC100_CLKSRC0_APLL_SHIFT, + .mask = S5PC100_CLKSRC0_APLL_MASK, + .sources = &clk_src_apll, + .reg_source = S5PC100_CLKSRC0, +}; - val = __raw_readl(S5PC1XX_CLK_SRC1); - if (enable) - val |= S5PC100_CLKSRC1_CLK48M_MASK; - else - val &= ~S5PC100_CLKSRC1_CLK48M_MASK; +static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; - __raw_writel(val, S5PC1XX_CLK_SRC1); - local_irq_restore(flags); + ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK; + ratio >>= S5PC100_CLKDIV0_APLL_SHIFT; - return 0; + return rate / (ratio + 1); } -struct clk clk_48m = { - .name = "clk_48m", +static struct clk clk_dout_apll = { + .name = "dout_apll", .id = -1, - .rate = 48000000, - .enable = clk_48m_ctrl, + .parent = &clk_mout_apll.clk, + .get_rate = s5pc100_clk_dout_apll_get_rate, }; -struct clk clk_54m = { - .name = "clk_54m", - .id = -1, - .rate = 54000000, -}; - -struct clk clk_hpll = { - .name = "hpll", - .id = -1, -}; +static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; -struct clk clk_hd0 = { - .name = "hclkd0", - .id = -1, - .rate = 0, - .parent = NULL, - .ctrlbit = 0, - .set_rate = clk_default_setrate, -}; + ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK; + ratio >>= S5PC100_CLKDIV0_ARM_SHIFT; -struct clk clk_pd0 = { - .name = "pclkd0", - .id = -1, - .rate = 0, - .parent = NULL, - .ctrlbit = 0, - .set_rate = clk_default_setrate, -}; + return rate / (ratio + 1); +} -static int s5pc1xx_clk_gate(void __iomem *reg, - struct clk *clk, - int enable) +static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk, + unsigned long rate) { - unsigned int ctrlbit = clk->ctrlbit; - u32 con; + unsigned long parent = clk_get_rate(clk->parent); + u32 div; - con = __raw_readl(reg); + if (parent < rate) + return rate; - if (enable) - con |= ctrlbit; - else - con &= ~ctrlbit; + div = (parent / rate) - 1; + if (div > S5PC100_CLKDIV0_ARM_MASK) + div = S5PC100_CLKDIV0_ARM_MASK; - __raw_writel(con, reg); - return 0; + return parent / (div + 1); } -static int s5pc1xx_clk_d00_ctrl(struct clk *clk, int enable) +static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate) { - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D00, clk, enable); -} + unsigned long parent = clk_get_rate(clk->parent); + u32 div; + u32 val; -static int s5pc1xx_clk_d01_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D01, clk, enable); -} + if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1)) + return -EINVAL; -static int s5pc1xx_clk_d02_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D02, clk, enable); -} + rate = clk_round_rate(clk, rate); + div = clk_get_rate(clk->parent) / rate; -static int s5pc1xx_clk_d10_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D10, clk, enable); -} + val = __raw_readl(S5PC100_CLKDIV0); + val &= S5PC100_CLKDIV0_ARM_MASK; + val |= (div - 1); + __raw_writel(val, S5PC100_CLKDIV0); -static int s5pc1xx_clk_d11_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D11, clk, enable); + return 0; } -static int s5pc1xx_clk_d12_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D12, clk, enable); -} +static struct clk clk_arm = { + .name = "armclk", + .id = -1, + .parent = &clk_dout_apll, + .get_rate = s5pc100_clk_arm_get_rate, + .set_rate = s5pc100_clk_arm_set_rate, + .round_rate = s5pc100_clk_arm_round_rate, +}; -static int s5pc1xx_clk_d13_ctrl(struct clk *clk, int enable) +static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk) { - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D13, clk, enable); -} + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; -static int s5pc1xx_clk_d14_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D14, clk, enable); -} + ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK; + ratio >>= S5PC100_CLKDIV0_D0_SHIFT; -static int s5pc1xx_clk_d15_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D15, clk, enable); + return rate / (ratio + 1); } -static int s5pc1xx_clk_d20_ctrl(struct clk *clk, int enable) -{ - return s5pc1xx_clk_gate(S5PC100_CLKGATE_D20, clk, enable); -} +static struct clk clk_dout_d0_bus = { + .name = "dout_d0_bus", + .id = -1, + .parent = &clk_arm, + .get_rate = s5pc100_clk_dout_d0_bus_get_rate, +}; -int s5pc1xx_sclk0_ctrl(struct clk *clk, int enable) +static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk) { - return s5pc1xx_clk_gate(S5PC100_SCLKGATE0, clk, enable); + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; + + ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK; + ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT; + + return rate / (ratio + 1); } -int s5pc1xx_sclk1_ctrl(struct clk *clk, int enable) +static struct clk clk_dout_pclkd0 = { + .name = "dout_pclkd0", + .id = -1, + .parent = &clk_dout_d0_bus, + .get_rate = s5pc100_clk_dout_pclkd0_get_rate, +}; + +static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk) { - return s5pc1xx_clk_gate(S5PC100_SCLKGATE1, clk, enable); + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; + + ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK; + ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT; + + return rate / (ratio + 1); } -static struct clk init_clocks_disable[] = { - { - .name = "dsi", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_DSI, - }, { - .name = "csi", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_CSI, - }, { - .name = "ccan0", - .id = 0, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_CCAN0, - }, { - .name = "ccan1", - .id = 1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_CCAN1, - }, { - .name = "keypad", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_KEYIF, - }, { - .name = "hclkd2", - .id = -1, - .parent = NULL, - .enable = s5pc1xx_clk_d20_ctrl, - .ctrlbit = S5PC100_CLKGATE_D20_HCLKD2, - }, { - .name = "iis-d2", - .id = -1, - .parent = NULL, - .enable = s5pc1xx_clk_d20_ctrl, - .ctrlbit = S5PC100_CLKGATE_D20_I2SD2, - }, { - .name = "otg", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_USBOTG, - }, +static struct clk clk_dout_apll2 = { + .name = "dout_apll2", + .id = -1, + .parent = &clk_mout_apll.clk, + .get_rate = s5pc100_clk_dout_apll2_get_rate, }; -static struct clk init_clocks[] = { - /* System1 (D0_0) devices */ - { - .name = "intc", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_INTC, - }, { - .name = "tzic", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_TZIC, - }, { - .name = "cf-ata", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_CFCON, - }, { - .name = "mdma", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_MDMA, - }, { - .name = "g2d", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_G2D, - }, { - .name = "secss", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_SECSS, - }, { - .name = "cssys", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d00_ctrl, - .ctrlbit = S5PC100_CLKGATE_D00_CSSYS, - }, +/* MPLL */ +static struct clk *clk_src_mpll_list[] = { + [0] = &clk_fin_mpll, + [1] = &clk_fout_mpll, +}; - /* Memory (D0_1) devices */ - { - .name = "dmc", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d01_ctrl, - .ctrlbit = S5PC100_CLKGATE_D01_DMC, - }, { - .name = "sromc", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d01_ctrl, - .ctrlbit = S5PC100_CLKGATE_D01_SROMC, - }, { - .name = "onenand", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d01_ctrl, - .ctrlbit = S5PC100_CLKGATE_D01_ONENAND, - }, { - .name = "nand", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d01_ctrl, - .ctrlbit = S5PC100_CLKGATE_D01_NFCON, - }, { - .name = "intmem", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d01_ctrl, - .ctrlbit = S5PC100_CLKGATE_D01_INTMEM, - }, { - .name = "ebi", - .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d01_ctrl, - .ctrlbit = S5PC100_CLKGATE_D01_EBI, - }, +static struct clk_sources clk_src_mpll = { + .sources = clk_src_mpll_list, + .nr_sources = ARRAY_SIZE(clk_src_mpll_list), +}; - /* System2 (D0_2) devices */ - { - .name = "seckey", - .id = -1, - .parent = &clk_pd0, - .enable = s5pc1xx_clk_d02_ctrl, - .ctrlbit = S5PC100_CLKGATE_D02_SECKEY, - }, { - .name = "sdm", +static struct clksrc_clk clk_mout_mpll = { + .clk = { + .name = "mout_mpll", .id = -1, - .parent = &clk_hd0, - .enable = s5pc1xx_clk_d02_ctrl, - .ctrlbit = S5PC100_CLKGATE_D02_SDM, }, + .shift = S5PC100_CLKSRC0_MPLL_SHIFT, + .mask = S5PC100_CLKSRC0_MPLL_MASK, + .sources = &clk_src_mpll, + .reg_source = S5PC100_CLKSRC0, +}; - /* File (D1_0) devices */ - { - .name = "pdma0", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_PDMA0, - }, { - .name = "pdma1", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_PDMA1, - }, { - .name = "usb-host", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_USBHOST, - }, { - .name = "modem", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_MODEMIF, - }, { - .name = "hsmmc", - .id = 0, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_HSMMC0, - }, { - .name = "hsmmc", - .id = 1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_HSMMC1, - }, { - .name = "hsmmc", - .id = 2, - .parent = &clk_h, - .enable = s5pc1xx_clk_d10_ctrl, - .ctrlbit = S5PC100_CLKGATE_D10_HSMMC2, - }, +static struct clk *clkset_am_list[] = { + [0] = &clk_mout_mpll.clk, + [1] = &clk_dout_apll2, +}; - /* Multimedia1 (D1_1) devices */ - { - .name = "lcd", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_LCD, - }, { - .name = "rotator", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_ROTATOR, - }, { - .name = "fimc", - .id = 0, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_FIMC0, - }, { - .name = "fimc", - .id = 1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_FIMC1, - }, { - .name = "fimc", - .id = 2, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_FIMC2, - }, { - .name = "jpeg", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_JPEG, - }, { - .name = "g3d", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d11_ctrl, - .ctrlbit = S5PC100_CLKGATE_D11_G3D, - }, +static struct clk_sources clk_src_am = { + .sources = clkset_am_list, + .nr_sources = ARRAY_SIZE(clkset_am_list), +}; - /* Multimedia2 (D1_2) devices */ - { - .name = "tv", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d12_ctrl, - .ctrlbit = S5PC100_CLKGATE_D12_TV, - }, { - .name = "vp", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d12_ctrl, - .ctrlbit = S5PC100_CLKGATE_D12_VP, - }, { - .name = "mixer", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d12_ctrl, - .ctrlbit = S5PC100_CLKGATE_D12_MIXER, - }, { - .name = "hdmi", - .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d12_ctrl, - .ctrlbit = S5PC100_CLKGATE_D12_HDMI, - }, { - .name = "mfc", +static struct clksrc_clk clk_mout_am = { + .clk = { + .name = "mout_am", .id = -1, - .parent = &clk_h, - .enable = s5pc1xx_clk_d12_ctrl, - .ctrlbit = S5PC100_CLKGATE_D12_MFC, }, + .shift = S5PC100_CLKSRC0_AMMUX_SHIFT, + .mask = S5PC100_CLKSRC0_AMMUX_MASK, + .sources = &clk_src_am, + .reg_source = S5PC100_CLKSRC0, +}; - /* System (D1_3) devices */ - { - .name = "chipid", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_CHIPID, - }, { - .name = "gpio", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_GPIO, - }, { - .name = "apc", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_APC, - }, { - .name = "iec", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_IEC, - }, { - .name = "timers", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_PWM, - }, { - .name = "systimer", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_SYSTIMER, - }, { - .name = "watchdog", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_WDT, - }, { - .name = "rtc", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d13_ctrl, - .ctrlbit = S5PC100_CLKGATE_D13_RTC, - }, +static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; - /* Connectivity (D1_4) devices */ - { - .name = "uart", - .id = 0, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_UART0, - }, { - .name = "uart", - .id = 1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_UART1, - }, { - .name = "uart", - .id = 2, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_UART2, - }, { - .name = "uart", - .id = 3, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_UART3, - }, { - .name = "i2c", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_IIC, - }, { - .name = "hdmi-i2c", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_HDMI_IIC, - }, { - .name = "spi", - .id = 0, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_SPI0, - }, { - .name = "spi", - .id = 1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_SPI1, - }, { - .name = "spi", - .id = 2, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_SPI2, - }, { - .name = "irda", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_IRDA, - }, { - .name = "hsitx", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_HSITX, - }, { - .name = "hsirx", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d14_ctrl, - .ctrlbit = S5PC100_CLKGATE_D14_HSIRX, - }, + printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); - /* Audio (D1_5) devices */ - { - .name = "iis", - .id = 0, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_IIS0, - }, { - .name = "iis", - .id = 1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_IIS1, - }, { - .name = "iis", - .id = 2, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_IIS2, - }, { - .name = "ac97", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_AC97, - }, { - .name = "pcm", - .id = 0, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_PCM0, - }, { - .name = "pcm", - .id = 1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_PCM1, - }, { - .name = "spdif", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_SPDIF, - }, { - .name = "adc", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_TSADC, - }, { - .name = "keyif", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_KEYIF, - }, { - .name = "cg", - .id = -1, - .parent = &clk_p, - .enable = s5pc1xx_clk_d15_ctrl, - .ctrlbit = S5PC100_CLKGATE_D15_CG, - }, + ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK; + ratio >>= S5PC100_CLKDIV1_D1_SHIFT; - /* Audio (D2_0) devices: all disabled */ + return rate / (ratio + 1); +} - /* Special Clocks 1 */ - { - .name = "sclk_hpm", - .id = -1, - .parent = NULL, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC1XX_CLKGATE_SCLK0_HPM, - }, { - .name = "sclk_onenand", - .id = -1, - .parent = NULL, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_ONENAND, - }, { - .name = "sclk_spi_48", - .id = 0, - .parent = &clk_48m, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0_48, - }, { - .name = "sclk_spi_48", - .id = 1, - .parent = &clk_48m, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1_48, - }, { - .name = "sclk_spi_48", - .id = 2, - .parent = &clk_48m, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2_48, - }, { - .name = "sclk_mmc_48", - .id = 0, - .parent = &clk_48m, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0_48, - }, { - .name = "sclk_mmc_48", - .id = 1, - .parent = &clk_48m, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1_48, - }, { - .name = "sclk_mmc_48", - .id = 2, - .parent = &clk_48m, - .enable = s5pc1xx_sclk0_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2_48, - }, +static struct clk clk_dout_d1_bus = { + .name = "dout_d1_bus", + .id = -1, + .parent = &clk_mout_am.clk, + .get_rate = s5pc100_clk_dout_d1_bus_get_rate, +}; - /* Special Clocks 2 */ - { - .name = "sclk_tv_54", - .id = -1, - .parent = &clk_54m, - .enable = s5pc1xx_sclk1_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK1_TV54, - }, { - .name = "sclk_vdac_54", - .id = -1, - .parent = &clk_54m, - .enable = s5pc1xx_sclk1_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK1_VDAC54, - }, { - .name = "sclk_spdif", +static struct clk *clkset_onenand_list[] = { + [0] = &clk_dout_d0_bus, + [1] = &clk_dout_d1_bus, +}; + +static struct clk_sources clk_src_onenand = { + .sources = clkset_onenand_list, + .nr_sources = ARRAY_SIZE(clkset_onenand_list), +}; + +static struct clksrc_clk clk_mout_onenand = { + .clk = { + .name = "mout_onenand", .id = -1, - .parent = NULL, - .enable = s5pc1xx_sclk1_ctrl, - .ctrlbit = S5PC100_CLKGATE_SCLK1_SPDIF, }, + .shift = S5PC100_CLKSRC0_ONENAND_SHIFT, + .mask = S5PC100_CLKSRC0_ONENAND_MASK, + .sources = &clk_src_onenand, + .reg_source = S5PC100_CLKSRC0, }; -void __init s5pc1xx_register_clocks(void) +static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk) { - struct clk *clkp; - int ret; - int ptr; + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; - clkp = init_clocks; - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } - } + printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); - clkp = init_clocks_disable; - for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { + ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK; + ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT; - ret = s3c24xx_register_clock(clkp); - if (ret < 0) { - printk(KERN_ERR "Failed to register clock %s (%d)\n", - clkp->name, ret); - } + return rate / (ratio + 1); +} - (clkp->enable)(clkp, 0); - } +static struct clk clk_dout_pclkd1 = { + .name = "dout_pclkd1", + .id = -1, + .parent = &clk_dout_d1_bus, + .get_rate = s5pc100_clk_dout_pclkd1_get_rate, +}; + +static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; + + printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); + + ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK; + ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT; - s3c_pwmclk_init(); + return rate / (ratio + 1); } -static struct clk clk_fout_apll = { - .name = "fout_apll", + +static struct clk clk_dout_mpll2 = { + .name = "dout_mpll2", .id = -1, + .parent = &clk_mout_am.clk, + .get_rate = s5pc100_clk_dout_mpll2_get_rate, }; -static struct clk *clk_src_apll_list[] = { - [0] = &clk_fin_apll, - [1] = &clk_fout_apll, -}; +static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; -static struct clk_sources clk_src_apll = { - .sources = clk_src_apll_list, - .nr_sources = ARRAY_SIZE(clk_src_apll_list), + printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); + + ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK; + ratio >>= S5PC100_CLKDIV1_CAM_SHIFT; + + return rate / (ratio + 1); +} + +static struct clk clk_dout_cam = { + .name = "dout_cam", + .id = -1, + .parent = &clk_dout_mpll2, + .get_rate = s5pc100_clk_dout_cam_get_rate, }; -static struct clksrc_clk clk_mout_apll = { - .clk = { - .name = "mout_apll", - .id = -1, - }, - .shift = S5PC1XX_CLKSRC0_APLL_SHIFT, - .mask = S5PC1XX_CLKSRC0_APLL_MASK, - .sources = &clk_src_apll, - .reg_source = S5PC1XX_CLK_SRC0, +static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + unsigned int ratio; + + printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); + + ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK; + ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT; + + return rate / (ratio + 1); +} + +static struct clk clk_dout_mpll = { + .name = "dout_mpll", + .id = -1, + .parent = &clk_mout_am.clk, + .get_rate = s5pc100_clk_dout_mpll_get_rate, }; +/* EPLL */ static struct clk clk_fout_epll = { .name = "fout_epll", .id = -1, @@ -827,91 +409,57 @@ static struct clksrc_clk clk_mout_epll = { .name = "mout_epll", .id = -1, }, - .shift = S5PC1XX_CLKSRC0_EPLL_SHIFT, - .mask = S5PC1XX_CLKSRC0_EPLL_MASK, + .shift = S5PC100_CLKSRC0_EPLL_SHIFT, + .mask = S5PC100_CLKSRC0_EPLL_MASK, .sources = &clk_src_epll, - .reg_source = S5PC1XX_CLK_SRC0, + .reg_source = S5PC100_CLKSRC0, }; -static struct clk *clk_src_mpll_list[] = { - [0] = &clk_fin_mpll, - [1] = &clk_fout_mpll, -}; - -static struct clk_sources clk_src_mpll = { - .sources = clk_src_mpll_list, - .nr_sources = ARRAY_SIZE(clk_src_mpll_list), -}; - -static struct clksrc_clk clk_mout_mpll = { - .clk = { - .name = "mout_mpll", - .id = -1, - }, - .shift = S5PC1XX_CLKSRC0_MPLL_SHIFT, - .mask = S5PC1XX_CLKSRC0_MPLL_MASK, - .sources = &clk_src_mpll, - .reg_source = S5PC1XX_CLK_SRC0, -}; - -static unsigned long s5pc1xx_clk_doutmpll_get_rate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - unsigned long clkdiv; - - printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); - - clkdiv = __raw_readl(S5PC1XX_CLK_DIV1) & S5PC100_CLKDIV1_MPLL_MASK; - rate /= (clkdiv >> S5PC100_CLKDIV1_MPLL_SHIFT) + 1; - - return rate; -} - -static struct clk clk_dout_mpll = { - .name = "dout_mpll", +/* HPLL */ +static struct clk clk_fout_hpll = { + .name = "fout_hpll", .id = -1, - .parent = &clk_mout_mpll.clk, - .get_rate = s5pc1xx_clk_doutmpll_get_rate, }; -static unsigned long s5pc1xx_clk_doutmpll2_get_rate(struct clk *clk) -{ - unsigned long rate = clk_get_rate(clk->parent); - unsigned long clkdiv; - - printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); - - clkdiv = __raw_readl(S5PC1XX_CLK_DIV1) & S5PC100_CLKDIV1_MPLL2_MASK; - rate /= (clkdiv >> S5PC100_CLKDIV1_MPLL2_SHIFT) + 1; - - return rate; -} - -struct clk clk_dout_mpll2 = { - .name = "dout_mpll2", - .id = -1, - .parent = &clk_mout_mpll.clk, - .get_rate = s5pc1xx_clk_doutmpll2_get_rate, +static struct clk *clk_src_hpll_list[] = { + [0] = &clk_27m, + [1] = &clk_fout_hpll, }; -static struct clk *clkset_uart_list[] = { - &clk_mout_epll.clk, - &clk_dout_mpll, - NULL, - NULL +static struct clk_sources clk_src_hpll = { + .sources = clk_src_hpll_list, + .nr_sources = ARRAY_SIZE(clk_src_hpll_list), }; -static struct clk_sources clkset_uart = { - .sources = clkset_uart_list, - .nr_sources = ARRAY_SIZE(clkset_uart_list), +static struct clksrc_clk clk_mout_hpll = { + .clk = { + .name = "mout_hpll", + .id = -1, + }, + .shift = S5PC100_CLKSRC0_HPLL_SHIFT, + .mask = S5PC100_CLKSRC0_HPLL_MASK, + .sources = &clk_src_hpll, + .reg_source = S5PC100_CLKSRC0, }; +/* Peripherals */ +/* + * The peripheral clocks are all controlled via clocksource followed + * by an optional divider and gate stage. We currently roll this into + * one clock which hides the intermediate clock from the mux. + * + * Note, the JPEG clock can only be an even divider... + * + * The scaler and LCD clocks depend on the S5PC100 version, and also + * have a common parent divisor so are not included here. + */ + static inline struct clksrc_clk *to_clksrc(struct clk *clk) { return container_of(clk, struct clksrc_clk, clk); } -static unsigned long s5pc1xx_getrate_clksrc(struct clk *clk) +static unsigned long s5pc100_getrate_clksrc(struct clk *clk) { struct clksrc_clk *sclk = to_clksrc(clk); unsigned long rate = clk_get_rate(clk->parent); @@ -925,7 +473,7 @@ static unsigned long s5pc1xx_getrate_clksrc(struct clk *clk) return rate; } -static int s5pc1xx_setrate_clksrc(struct clk *clk, unsigned long rate) +static int s5pc100_setrate_clksrc(struct clk *clk, unsigned long rate) { struct clksrc_clk *sclk = to_clksrc(clk); void __iomem *reg = sclk->reg_divider; @@ -938,14 +486,14 @@ static int s5pc1xx_setrate_clksrc(struct clk *clk, unsigned long rate) return -EINVAL; val = __raw_readl(reg); - val &= ~(0xf << sclk->shift); - val |= (div - 1) << sclk->shift; + val &= ~(0xf << sclk->divider_shift); + val |= (div - 1) << sclk->divider_shift; __raw_writel(val, reg); return 0; } -static int s5pc1xx_setparent_clksrc(struct clk *clk, struct clk *parent) +static int s5pc100_setparent_clksrc(struct clk *clk, struct clk *parent) { struct clksrc_clk *sclk = to_clksrc(clk); struct clk_sources *srcs = sclk->sources; @@ -970,7 +518,7 @@ static int s5pc1xx_setparent_clksrc(struct clk *clk, struct clk *parent) return -EINVAL; } -static unsigned long s5pc1xx_roundrate_clksrc(struct clk *clk, +static unsigned long s5pc100_roundrate_clksrc(struct clk *clk, unsigned long rate) { unsigned long parent_rate = clk_get_rate(clk->parent); @@ -992,35 +540,466 @@ static unsigned long s5pc1xx_roundrate_clksrc(struct clk *clk, return rate; } +static struct clk *clkset_spi_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll2, + &clk_fin_epll, + &clk_mout_hpll.clk, +}; + +static struct clk_sources clkset_spi = { + .sources = clkset_spi_list, + .nr_sources = ARRAY_SIZE(clkset_spi_list), +}; + +static struct clksrc_clk clk_spi0 = { + .clk = { + .name = "spi_bus", + .id = 0, + .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC1_SPI0_SHIFT, + .mask = S5PC100_CLKSRC1_SPI0_MASK, + .sources = &clkset_spi, + .divider_shift = S5PC100_CLKDIV2_SPI0_SHIFT, + .reg_divider = S5PC100_CLKDIV2, + .reg_source = S5PC100_CLKSRC1, +}; + +static struct clksrc_clk clk_spi1 = { + .clk = { + .name = "spi_bus", + .id = 1, + .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC1_SPI1_SHIFT, + .mask = S5PC100_CLKSRC1_SPI1_MASK, + .sources = &clkset_spi, + .divider_shift = S5PC100_CLKDIV2_SPI1_SHIFT, + .reg_divider = S5PC100_CLKDIV2, + .reg_source = S5PC100_CLKSRC1, +}; + +static struct clksrc_clk clk_spi2 = { + .clk = { + .name = "spi_bus", + .id = 2, + .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC1_SPI2_SHIFT, + .mask = S5PC100_CLKSRC1_SPI2_MASK, + .sources = &clkset_spi, + .divider_shift = S5PC100_CLKDIV2_SPI2_SHIFT, + .reg_divider = S5PC100_CLKDIV2, + .reg_source = S5PC100_CLKSRC1, +}; + +static struct clk *clkset_uart_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, +}; + +static struct clk_sources clkset_uart = { + .sources = clkset_uart_list, + .nr_sources = ARRAY_SIZE(clkset_uart_list), +}; + static struct clksrc_clk clk_uart_uclk1 = { .clk = { .name = "uclk1", .id = -1, .ctrlbit = S5PC100_CLKGATE_SCLK0_UART, - .enable = s5pc1xx_sclk0_ctrl, - .set_parent = s5pc1xx_setparent_clksrc, - .get_rate = s5pc1xx_getrate_clksrc, - .set_rate = s5pc1xx_setrate_clksrc, - .round_rate = s5pc1xx_roundrate_clksrc, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, }, .shift = S5PC100_CLKSRC1_UART_SHIFT, .mask = S5PC100_CLKSRC1_UART_MASK, .sources = &clkset_uart, .divider_shift = S5PC100_CLKDIV2_UART_SHIFT, - .reg_divider = S5PC1XX_CLK_DIV2, - .reg_source = S5PC1XX_CLK_SRC1, + .reg_divider = S5PC100_CLKDIV2, + .reg_source = S5PC100_CLKSRC1, +}; + +static struct clk clk_iis_cd0 = { + .name = "iis_cdclk0", + .id = -1, +}; + +static struct clk clk_iis_cd1 = { + .name = "iis_cdclk1", + .id = -1, +}; + +static struct clk clk_iis_cd2 = { + .name = "iis_cdclk2", + .id = -1, +}; + +static struct clk clk_pcm_cd0 = { + .name = "pcm_cdclk0", + .id = -1, +}; + +static struct clk clk_pcm_cd1 = { + .name = "pcm_cdclk1", + .id = -1, +}; + +static struct clk *clkset_audio0_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, + &clk_fin_epll, + &clk_iis_cd0, + &clk_pcm_cd0, + &clk_mout_hpll.clk, +}; + +static struct clk_sources clkset_audio0 = { + .sources = clkset_audio0_list, + .nr_sources = ARRAY_SIZE(clkset_audio0_list), +}; + +static struct clksrc_clk clk_audio0 = { + .clk = { + .name = "audio-bus", + .id = 0, + .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC3_AUDIO0_SHIFT, + .mask = S5PC100_CLKSRC3_AUDIO0_MASK, + .sources = &clkset_audio0, + .divider_shift = S5PC100_CLKDIV4_AUDIO0_SHIFT, + .reg_divider = S5PC100_CLKDIV4, + .reg_source = S5PC100_CLKSRC3, +}; + +static struct clk *clkset_audio1_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, + &clk_fin_epll, + &clk_iis_cd1, + &clk_pcm_cd1, + &clk_mout_hpll.clk, +}; + +static struct clk_sources clkset_audio1 = { + .sources = clkset_audio1_list, + .nr_sources = ARRAY_SIZE(clkset_audio1_list), +}; + +static struct clksrc_clk clk_audio1 = { + .clk = { + .name = "audio-bus", + .id = 1, + .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC3_AUDIO1_SHIFT, + .mask = S5PC100_CLKSRC3_AUDIO1_MASK, + .sources = &clkset_audio1, + .divider_shift = S5PC100_CLKDIV4_AUDIO1_SHIFT, + .reg_divider = S5PC100_CLKDIV4, + .reg_source = S5PC100_CLKSRC3, +}; + +static struct clk *clkset_audio2_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, + &clk_fin_epll, + &clk_iis_cd2, + &clk_mout_hpll.clk, +}; + +static struct clk_sources clkset_audio2 = { + .sources = clkset_audio2_list, + .nr_sources = ARRAY_SIZE(clkset_audio2_list), +}; + +static struct clksrc_clk clk_audio2 = { + .clk = { + .name = "audio-bus", + .id = 2, + .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC3_AUDIO2_SHIFT, + .mask = S5PC100_CLKSRC3_AUDIO2_MASK, + .sources = &clkset_audio2, + .divider_shift = S5PC100_CLKDIV4_AUDIO2_SHIFT, + .reg_divider = S5PC100_CLKDIV4, + .reg_source = S5PC100_CLKSRC3, +}; + +static struct clk *clkset_spdif_list[] = { + &clk_audio0.clk, + &clk_audio1.clk, + &clk_audio2.clk, +}; + +static struct clk_sources clkset_spdif = { + .sources = clkset_spdif_list, + .nr_sources = ARRAY_SIZE(clkset_spdif_list), +}; + +static struct clksrc_clk clk_spdif = { + .clk = { + .name = "spdif", + .id = -1, + }, + .shift = S5PC100_CLKSRC3_SPDIF_SHIFT, + .mask = S5PC100_CLKSRC3_SPDIF_MASK, + .sources = &clkset_spdif, + .reg_source = S5PC100_CLKSRC3, +}; + +static struct clk *clkset_lcd_fimc_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, + &clk_mout_hpll.clk, + &clk_vclk_54m, +}; + +static struct clk_sources clkset_lcd_fimc = { + .sources = clkset_lcd_fimc_list, + .nr_sources = ARRAY_SIZE(clkset_lcd_fimc_list), +}; + +static struct clksrc_clk clk_lcd = { + .clk = { + .name = "lcd", + .id = -1, + .ctrlbit = S5PC100_CLKGATE_SCLK1_LCD, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_LCD_SHIFT, + .mask = S5PC100_CLKSRC2_LCD_MASK, + .sources = &clkset_lcd_fimc, + .divider_shift = S5PC100_CLKDIV3_LCD_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + +static struct clksrc_clk clk_fimc0 = { + .clk = { + .name = "fimc", + .id = 0, + .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_FIMC0_SHIFT, + .mask = S5PC100_CLKSRC2_FIMC0_MASK, + .sources = &clkset_lcd_fimc, + .divider_shift = S5PC100_CLKDIV3_FIMC0_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + +static struct clksrc_clk clk_fimc1 = { + .clk = { + .name = "fimc", + .id = 1, + .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_FIMC1_SHIFT, + .mask = S5PC100_CLKSRC2_FIMC1_MASK, + .sources = &clkset_lcd_fimc, + .divider_shift = S5PC100_CLKDIV3_FIMC1_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + +static struct clksrc_clk clk_fimc2 = { + .clk = { + .name = "fimc", + .id = 2, + .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2, + .enable = s5pc100_sclk1_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_FIMC2_SHIFT, + .mask = S5PC100_CLKSRC2_FIMC2_MASK, + .sources = &clkset_lcd_fimc, + .divider_shift = S5PC100_CLKDIV3_FIMC2_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + +static struct clk *clkset_mmc_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, + &clk_fin_epll, + &clk_mout_hpll.clk , +}; + +static struct clk_sources clkset_mmc = { + .sources = clkset_mmc_list, + .nr_sources = ARRAY_SIZE(clkset_mmc_list), +}; + +static struct clksrc_clk clk_mmc0 = { + .clk = { + .name = "mmc_bus", + .id = 0, + .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_MMC0_SHIFT, + .mask = S5PC100_CLKSRC2_MMC0_MASK, + .sources = &clkset_mmc, + .divider_shift = S5PC100_CLKDIV3_MMC0_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + +static struct clksrc_clk clk_mmc1 = { + .clk = { + .name = "mmc_bus", + .id = 1, + .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_MMC1_SHIFT, + .mask = S5PC100_CLKSRC2_MMC1_MASK, + .sources = &clkset_mmc, + .divider_shift = S5PC100_CLKDIV3_MMC1_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + +static struct clksrc_clk clk_mmc2 = { + .clk = { + .name = "mmc_bus", + .id = 2, + .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC2_MMC2_SHIFT, + .mask = S5PC100_CLKSRC2_MMC2_MASK, + .sources = &clkset_mmc, + .divider_shift = S5PC100_CLKDIV3_MMC2_SHIFT, + .reg_divider = S5PC100_CLKDIV3, + .reg_source = S5PC100_CLKSRC2, +}; + + +static struct clk *clkset_usbhost_list[] = { + &clk_mout_epll.clk, + &clk_dout_mpll, + &clk_mout_hpll.clk, + &clk_48m, +}; + +static struct clk_sources clkset_usbhost = { + .sources = clkset_usbhost_list, + .nr_sources = ARRAY_SIZE(clkset_usbhost_list), +}; + +static struct clksrc_clk clk_usbhost = { + .clk = { + .name = "usbhost", + .id = -1, + .ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST, + .enable = s5pc100_sclk0_ctrl, + .set_parent = s5pc100_setparent_clksrc, + .get_rate = s5pc100_getrate_clksrc, + .set_rate = s5pc100_setrate_clksrc, + .round_rate = s5pc100_roundrate_clksrc, + }, + .shift = S5PC100_CLKSRC1_UHOST_SHIFT, + .mask = S5PC100_CLKSRC1_UHOST_MASK, + .sources = &clkset_usbhost, + .divider_shift = S5PC100_CLKDIV2_UHOST_SHIFT, + .reg_divider = S5PC100_CLKDIV2, + .reg_source = S5PC100_CLKSRC1, }; /* Clock initialisation code */ static struct clksrc_clk *init_parents[] = { &clk_mout_apll, - &clk_mout_epll, &clk_mout_mpll, + &clk_mout_am, + &clk_mout_onenand, + &clk_mout_epll, + &clk_mout_hpll, + &clk_spi0, + &clk_spi1, + &clk_spi2, &clk_uart_uclk1, + &clk_audio0, + &clk_audio1, + &clk_audio2, + &clk_spdif, + &clk_lcd, + &clk_fimc0, + &clk_fimc1, + &clk_fimc2, + &clk_mmc0, + &clk_mmc1, + &clk_mmc2, + &clk_usbhost, }; -static void __init_or_cpufreq s5pc1xx_set_clksrc(struct clksrc_clk *clk) +static void __init_or_cpufreq s5pc100_set_clksrc(struct clksrc_clk *clk) { struct clk_sources *srcs = clk->sources; u32 clksrc = __raw_readl(clk->reg_source); @@ -1036,9 +1015,9 @@ static void __init_or_cpufreq s5pc1xx_set_clksrc(struct clksrc_clk *clk) clk->clk.parent = srcs->sources[clksrc]; - printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n", - clk->clk.name, clk->clk.parent->name, clksrc, - clk_get_rate(&clk->clk)); + printk(KERN_INFO "%s: source is %s (%d), rate is %ld.%03ld MHz\n", + clk->clk.name, clk->clk.parent->name, clksrc, + print_mhz(clk_get_rate(&clk->clk))); } #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1) @@ -1052,20 +1031,16 @@ void __init_or_cpufreq s5pc100_setup_clocks(void) unsigned long hclk; unsigned long pclkd0; unsigned long pclk; - unsigned long apll; - unsigned long mpll; - unsigned long hpll; - unsigned long epll; + unsigned long apll, mpll, epll, hpll; unsigned int ptr; u32 clkdiv0, clkdiv1; printk(KERN_DEBUG "%s: registering clocks\n", __func__); - clkdiv0 = __raw_readl(S5PC1XX_CLK_DIV0); - clkdiv1 = __raw_readl(S5PC1XX_CLK_DIV1); + clkdiv0 = __raw_readl(S5PC100_CLKDIV0); + clkdiv1 = __raw_readl(S5PC100_CLKDIV1); - printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", - __func__, clkdiv0, clkdiv1); + printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1); xtal_clk = clk_get(NULL, "xtal"); BUG_ON(IS_ERR(xtal_clk)); @@ -1075,48 +1050,81 @@ void __init_or_cpufreq s5pc100_setup_clocks(void) printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); - apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_APLL_CON)); - mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_MPLL_CON)); - epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_EPLL_CON)); + apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON)); + mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON)); + epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON)); hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON)); - printk(KERN_INFO "S5PC100: PLL settings, A=%ld, M=%ld, E=%ld, H=%ld\n", - apll, mpll, epll, hpll); + printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz" + ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n", + print_mhz(apll), print_mhz(mpll), + print_mhz(epll), print_mhz(hpll)); - armclk = apll / GET_DIV(clkdiv0, S5PC1XX_CLKDIV0_APLL); + armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL); armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM); hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0); pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0); hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1); pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1); - printk(KERN_INFO "S5PC100: ARMCLK=%ld, HCLKD0=%ld, PCLKD0=%ld, HCLK=%ld, PCLK=%ld\n", - armclk, hclkd0, pclkd0, hclk, pclk); + printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz," + " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz," + " PCLK=%ld.%03ld MHz\n", + print_mhz(armclk), print_mhz(hclkd0), + print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk)); clk_fout_apll.rate = apll; clk_fout_mpll.rate = mpll; clk_fout_epll.rate = epll; - clk_fout_apll.rate = apll; + clk_fout_hpll.rate = hpll; clk_h.rate = hclk; clk_p.rate = pclk; + clk_f.rate = armclk; for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++) - s5pc1xx_set_clksrc(init_parents[ptr]); + s5pc100_set_clksrc(init_parents[ptr]); } static struct clk *clks[] __initdata = { &clk_ext_xtal_mux, - &clk_mout_epll.clk, - &clk_fout_epll, + &clk_mout_apll.clk, + &clk_dout_apll, + &clk_dout_d0_bus, + &clk_dout_pclkd0, + &clk_dout_apll2, &clk_mout_mpll.clk, + &clk_mout_am.clk, + &clk_dout_d1_bus, + &clk_mout_onenand.clk, + &clk_dout_pclkd1, + &clk_dout_mpll2, + &clk_dout_cam, &clk_dout_mpll, + &clk_mout_epll.clk, + &clk_fout_epll, + &clk_iis_cd0, + &clk_iis_cd1, + &clk_iis_cd2, + &clk_pcm_cd0, + &clk_pcm_cd1, + &clk_spi0.clk, + &clk_spi1.clk, + &clk_spi2.clk, &clk_uart_uclk1.clk, - &clk_ext, - &clk_epll, - &clk_27m, - &clk_48m, - &clk_54m, + &clk_audio0.clk, + &clk_audio1.clk, + &clk_audio2.clk, + &clk_spdif.clk, + &clk_lcd.clk, + &clk_fimc0.clk, + &clk_fimc1.clk, + &clk_fimc2.clk, + &clk_mmc0.clk, + &clk_mmc1.clk, + &clk_mmc2.clk, + &clk_usbhost.clk, + &clk_arm, }; void __init s5pc100_register_clocks(void) @@ -1133,7 +1141,4 @@ void __init s5pc100_register_clocks(void) clkp->name, ret); } } - - clk_mpll.parent = &clk_mout_mpll.clk; - clk_epll.parent = &clk_mout_epll.clk; } diff --git a/arch/arm/plat-s5pc1xx/setup-fb-24bpp.c b/arch/arm/plat-s5pc1xx/setup-fb-24bpp.c new file mode 100644 index 00000000000..1a63768a9a2 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/setup-fb-24bpp.c @@ -0,0 +1,49 @@ +/* + * linux/arch/arm/plat-s5pc100/setup-fb-24bpp.c + * + * Copyright 2009 Samsung Electronics + * + * Base S5PC1XX setup information for 24bpp LCD framebuffer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/fb.h> +#include <linux/gpio.h> + +#include <mach/regs-fb.h> +#include <mach/map.h> +#include <plat/fb.h> +#include <plat/gpio-cfg.h> +#include <plat/gpio-cfg-s5pc1xx.h> + +#define DISR_OFFSET 0x7008 + +void s5pc100_fb_gpio_setup_24bpp(void) +{ + unsigned int gpio = 0; + + for (gpio = S5PC100_GPF0(0); gpio <= S5PC100_GPF0(7); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + for (gpio = S5PC100_GPF1(0); gpio <= S5PC100_GPF1(7); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + for (gpio = S5PC100_GPF2(0); gpio <= S5PC100_GPF2(7); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + for (gpio = S5PC100_GPF3(0); gpio <= S5PC100_GPF3(3); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } +} diff --git a/arch/arm/plat-s5pc1xx/setup-i2c0.c b/arch/arm/plat-s5pc1xx/setup-i2c0.c index 3d00c025fff..5e4a7c3a231 100644 --- a/arch/arm/plat-s5pc1xx/setup-i2c0.c +++ b/arch/arm/plat-s5pc1xx/setup-i2c0.c @@ -17,9 +17,14 @@ struct platform_device; /* don't need the contents */ +#include <linux/gpio.h> #include <plat/iic.h> +#include <plat/gpio-cfg.h> void s3c_i2c0_cfg_gpio(struct platform_device *dev) { - /* Pin configuration would be needed */ + s3c_gpio_cfgpin(S5PC100_GPD(3), S3C_GPIO_SFN(2)); + s3c_gpio_setpull(S5PC100_GPD(3), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S5PC100_GPD(4), S3C_GPIO_SFN(2)); + s3c_gpio_setpull(S5PC100_GPD(4), S3C_GPIO_PULL_UP); } diff --git a/arch/arm/plat-s5pc1xx/setup-i2c1.c b/arch/arm/plat-s5pc1xx/setup-i2c1.c index c8f3ca42f51..a0a8b4ae6ad 100644 --- a/arch/arm/plat-s5pc1xx/setup-i2c1.c +++ b/arch/arm/plat-s5pc1xx/setup-i2c1.c @@ -17,9 +17,14 @@ struct platform_device; /* don't need the contents */ +#include <linux/gpio.h> #include <plat/iic.h> +#include <plat/gpio-cfg.h> void s3c_i2c1_cfg_gpio(struct platform_device *dev) { - /* Pin configuration would be needed */ + s3c_gpio_cfgpin(S5PC100_GPD(5), S3C_GPIO_SFN(2)); + s3c_gpio_setpull(S5PC100_GPD(5), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S5PC100_GPD(6), S3C_GPIO_SFN(2)); + s3c_gpio_setpull(S5PC100_GPD(6), S3C_GPIO_PULL_UP); } diff --git a/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c b/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c new file mode 100644 index 00000000000..185c8941e64 --- /dev/null +++ b/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c @@ -0,0 +1,86 @@ +/* linux/arch/arm/plat-s5pc1xx/setup-sdhci-gpio.c + * + * Copyright 2009 Samsung Eletronics + * + * S5PC1XX - Helper functions for setting up SDHCI device(s) GPIO (HSMMC) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/gpio.h> +#include <linux/mmc/host.h> +#include <linux/mmc/card.h> + +#include <plat/gpio-cfg.h> +#include <plat/regs-sdhci.h> + +void s5pc100_setup_sdhci0_cfg_gpio(struct platform_device *dev, int width) +{ + unsigned int gpio; + unsigned int end; + unsigned int num; + + num = width; + /* In case of 8 width, we should decrease the 2 */ + if (width == 8) + num = width - 2; + + end = S5PC100_GPG0(2 + num); + + /* Set all the necessary GPG0/GPG1 pins to special-function 0 */ + for (gpio = S5PC100_GPG0(0); gpio < end; gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + if (width == 8) { + for (gpio = S5PC100_GPG1(0); gpio <= S5PC100_GPG1(1); gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + } + + s3c_gpio_setpull(S5PC100_GPG1(2), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S5PC100_GPG1(2), S3C_GPIO_SFN(2)); +} + +void s5pc100_setup_sdhci1_cfg_gpio(struct platform_device *dev, int width) +{ + unsigned int gpio; + unsigned int end; + + end = S5PC100_GPG2(2 + width); + + /* Set all the necessary GPG2 pins to special-function 2 */ + for (gpio = S5PC100_GPG2(0); gpio < end; gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + s3c_gpio_setpull(S5PC100_GPG2(6), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S5PC100_GPG2(6), S3C_GPIO_SFN(2)); +} + +void s5pc100_setup_sdhci2_cfg_gpio(struct platform_device *dev, int width) +{ + unsigned int gpio; + unsigned int end; + + end = S5PC100_GPG3(2 + width); + + /* Set all the necessary GPG3 pins to special-function 2 */ + for (gpio = S5PC100_GPG3(0); gpio < end; gpio++) { + s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + } + + s3c_gpio_setpull(S5PC100_GPG3(6), S3C_GPIO_PULL_UP); + s3c_gpio_cfgpin(S5PC100_GPG3(6), S3C_GPIO_SFN(2)); +} |