From: Olof Johansson Date: Thu, 8 Mar 2012 16:53:14 +0000 (-0800) Subject: Merge branch 'next/cleanup-s3c24xx' of git://git.kernel.org/pub/scm/linux/kernel... X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=d60d506e6baaf423148c458df3ece0c1d440dce4;p=GitHub%2Fexynos8895%2Fandroid_kernel_samsung_universal8895.git Merge branch 'next/cleanup-s3c24xx' of git://git./linux/kernel/git/kgene/linux-samsung into next/cleanup * 'next/cleanup-s3c24xx' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung: (24 commits) ARM: S3C24XX: remove call to s3c24xx_setup_clocks ARM: S3C24XX: add get_rate for clk_p on S3C2416/2443 ARM: S3C24XX: add get_rate for clk_h on S3C2416/2443 ARM: S3C24XX: remove XXX_setup_clocks method from S3C2443 ARM: S3C24XX: remove obsolete S3C2416_DMA option ARM: S3C24XX: Reuse S3C2443 dma for S3C2416 ARM: S3C24XX: Fix indentation of dma-s3c2443 ARM: S3C24XX: Move device setup files to mach directory ARM: S3C24XX: Consolidate Simtec extensions ARM: S3C24XX: move simtec-specific code to mach directory ARM: S3C24XX: Move common-smdk code to mach directory ARM: S3C24XX: Move s3c2443-clock.c to mach-s3c24xx ARM: s3c2410_defconfig: update s3c2410_defconfig ARM: S3C2443: move mach-s3c2443/* into mach-s3c24xx/ ARM: S3C2440: move mach-s3c2440/* into mach-s3c24xx/ ARM: S3C2416: move mach-s3c2416/* into mach-s3c24xx/ ARM: S3C2412: move mach-s3c2412/* into mach-s3c24xx/ ARM: S3C2410: move mach-s3c2410/* into mach-s3c24xx/ ARM: S3C24XX: change the ARCH_S3C2410 to ARCH_S3C24XX ARM: S3C2410: move s3c2410_baseclk_add to clock.h ... --- d60d506e6baaf423148c458df3ece0c1d440dce4 diff --cc arch/arm/mach-s3c24xx/clock-s3c2416.c index 000000000000,5e36905eb7fc..dbc9ab4aaca2 mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2416.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2416.c @@@ -1,0 -1,178 +1,172 @@@ + /* linux/arch/arm/mach-s3c2416/clock.c + * + * Copyright (c) 2010 Simtec Electronics + * Copyright (c) 2010 Ben Dooks + * + * S3C2416 Clock control support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + #include + #include + + #include + #include + #include + #include + + #include + #include + + #include + + #include + #include + + /* armdiv + * + * this clock is sourced from msysclk and can have a number of + * divider values applied to it to then be fed into armclk. + * The real clock definition is done in s3c2443-clock.c, + * only the armdiv divisor table must be defined here. + */ + + static unsigned int armdiv[8] = { + [0] = 1, + [1] = 2, + [2] = 3, + [3] = 4, + [5] = 6, + [7] = 8, + }; + + static struct clksrc_clk hsspi_eplldiv = { + .clk = { + .name = "hsspi-eplldiv", + .parent = &clk_esysclk.clk, + .ctrlbit = (1 << 14), + .enable = s3c2443_clkcon_enable_s, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 24 }, + }; + + static struct clk *hsspi_sources[] = { + [0] = &hsspi_eplldiv.clk, + [1] = NULL, /* to fix */ + }; + + static struct clksrc_clk hsspi_mux = { + .clk = { + .name = "hsspi-if", + }, + .sources = &(struct clksrc_sources) { + .sources = hsspi_sources, + .nr_sources = ARRAY_SIZE(hsspi_sources), + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 18 }, + }; + + static struct clksrc_clk hsmmc_div[] = { + [0] = { + .clk = { + .name = "hsmmc-div", + .devname = "s3c-sdhci.0", + .parent = &clk_esysclk.clk, + }, + .reg_div = { .reg = S3C2416_CLKDIV2, .size = 2, .shift = 6 }, + }, + [1] = { + .clk = { + .name = "hsmmc-div", + .devname = "s3c-sdhci.1", + .parent = &clk_esysclk.clk, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, + }, + }; + + static struct clksrc_clk hsmmc_mux0 = { + .clk = { + .name = "hsmmc-if", + .devname = "s3c-sdhci.0", + .ctrlbit = (1 << 6), + .enable = s3c2443_clkcon_enable_s, + }, + .sources = &(struct clksrc_sources) { + .nr_sources = 2, + .sources = (struct clk * []) { + [0] = &hsmmc_div[0].clk, + [1] = NULL, /* to fix */ + }, + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 16 }, + }; + + static struct clksrc_clk hsmmc_mux1 = { + .clk = { + .name = "hsmmc-if", + .devname = "s3c-sdhci.1", + .ctrlbit = (1 << 12), + .enable = s3c2443_clkcon_enable_s, + }, + .sources = &(struct clksrc_sources) { + .nr_sources = 2, + .sources = (struct clk * []) { + [0] = &hsmmc_div[1].clk, + [1] = NULL, /* to fix */ + }, + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 17 }, + }; + + static struct clk hsmmc0_clk = { + .name = "hsmmc", + .devname = "s3c-sdhci.0", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2416_HCLKCON_HSMMC0, + }; + -void __init_or_cpufreq s3c2416_setup_clocks(void) -{ - s3c2443_common_setup_clocks(s3c2416_get_pll); -} - - + static struct clksrc_clk *clksrcs[] __initdata = { + &hsspi_eplldiv, + &hsspi_mux, + &hsmmc_div[0], + &hsmmc_div[1], + &hsmmc_mux0, + &hsmmc_mux1, + }; + + static struct clk_lookup s3c2416_clk_lookup[] = { + CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.0", &hsmmc0_clk), + CLKDEV_INIT("s3c-sdhci.0", "mmc_busclk.2", &hsmmc_mux0.clk), + CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.2", &hsmmc_mux1.clk), + }; + + void __init s3c2416_init_clocks(int xtal) + { + u32 epllcon = __raw_readl(S3C2443_EPLLCON); + u32 epllcon1 = __raw_readl(S3C2443_EPLLCON+4); + int ptr; + + /* s3c2416 EPLL compatible with s3c64xx */ + clk_epll.rate = s3c_get_pll6553x(xtal, epllcon, epllcon1); + + clk_epll.parent = &clk_epllref.clk; + + s3c2443_common_init_clocks(xtal, s3c2416_get_pll, + armdiv, ARRAY_SIZE(armdiv), + S3C2416_CLKDIV0_ARMDIV_MASK); + + for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) + s3c_register_clksrc(clksrcs[ptr], 1); + + s3c24xx_register_clock(&hsmmc0_clk); + clkdev_add_table(s3c2416_clk_lookup, ARRAY_SIZE(s3c2416_clk_lookup)); + + s3c_pwmclk_init(); + + } diff --cc arch/arm/mach-s3c24xx/clock-s3c2440.c index 000000000000,bedbc87a3426..414364eb426c mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/clock-s3c2440.c +++ b/arch/arm/mach-s3c24xx/clock-s3c2440.c @@@ -1,0 -1,194 +1,194 @@@ + /* linux/arch/arm/mach-s3c2440/clock.c + * + * Copyright (c) 2004-2005 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * S3C2440 Clock support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + + #include + #include + #include + + /* S3C2440 extended clock support */ + + static unsigned long s3c2440_camif_upll_round(struct clk *clk, + unsigned long rate) + { + unsigned long parent_rate = clk_get_rate(clk->parent); + int div; + + if (rate > parent_rate) + return parent_rate; + + /* note, we remove the +/- 1 calculations for the divisor */ + + div = (parent_rate / rate) / 2; + + if (div < 1) + div = 1; + else if (div > 16) + div = 16; + + return parent_rate / (div * 2); + } + + static int s3c2440_camif_upll_setrate(struct clk *clk, unsigned long rate) + { + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN); + + rate = s3c2440_camif_upll_round(clk, rate); + + camdivn &= ~(S3C2440_CAMDIVN_CAMCLK_SEL | S3C2440_CAMDIVN_CAMCLK_MASK); + + if (rate != parent_rate) { + camdivn |= S3C2440_CAMDIVN_CAMCLK_SEL; + camdivn |= (((parent_rate / rate) / 2) - 1); + } + + __raw_writel(camdivn, S3C2440_CAMDIVN); + + return 0; + } + + /* Extra S3C2440 clocks */ + + static struct clk s3c2440_clk_cam = { + .name = "camif", + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2440_CLKCON_CAMERA, + }; + + static struct clk s3c2440_clk_cam_upll = { + .name = "camif-upll", + .ops = &(struct clk_ops) { + .set_rate = s3c2440_camif_upll_setrate, + .round_rate = s3c2440_camif_upll_round, + }, + }; + + static struct clk s3c2440_clk_ac97 = { + .name = "ac97", + .enable = s3c2410_clkcon_enable, + .ctrlbit = S3C2440_CLKCON_CAMERA, + }; + + static unsigned long s3c2440_fclk_n_getrate(struct clk *clk) + { + unsigned long ucon0, ucon1, ucon2, divisor; + + /* the fun of calculating the uart divisors on the s3c2440 */ + ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON); + ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON); + ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON); + + ucon0 &= S3C2440_UCON0_DIVMASK; + ucon1 &= S3C2440_UCON1_DIVMASK; + ucon2 &= S3C2440_UCON2_DIVMASK; + + if (ucon0 != 0) + divisor = (ucon0 >> S3C2440_UCON_DIVSHIFT) + 6; + else if (ucon1 != 0) + divisor = (ucon1 >> S3C2440_UCON_DIVSHIFT) + 21; + else if (ucon2 != 0) + divisor = (ucon2 >> S3C2440_UCON_DIVSHIFT) + 36; + else + /* manual calims 44, seems to be 9 */ + divisor = 9; + + return clk_get_rate(clk->parent) / divisor; + } + + static struct clk s3c2440_clk_fclk_n = { + .name = "fclk_n", + .parent = &clk_f, + .ops = &(struct clk_ops) { + .get_rate = s3c2440_fclk_n_getrate, + }, + }; + + static struct clk_lookup s3c2440_clk_lookup[] = { + CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), + CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), + CLKDEV_INIT(NULL, "clk_uart_baud3", &s3c2440_clk_fclk_n), + }; + -static int s3c2440_clk_add(struct device *dev) ++static int s3c2440_clk_add(struct device *dev, struct subsys_interface *sif) + { + struct clk *clock_upll; + struct clk *clock_h; + struct clk *clock_p; + + clock_p = clk_get(NULL, "pclk"); + clock_h = clk_get(NULL, "hclk"); + clock_upll = clk_get(NULL, "upll"); + + if (IS_ERR(clock_p) || IS_ERR(clock_h) || IS_ERR(clock_upll)) { + printk(KERN_ERR "S3C2440: Failed to get parent clocks\n"); + return -EINVAL; + } + + s3c2440_clk_cam.parent = clock_h; + s3c2440_clk_ac97.parent = clock_p; + s3c2440_clk_cam_upll.parent = clock_upll; + s3c24xx_register_clock(&s3c2440_clk_fclk_n); + + s3c24xx_register_clock(&s3c2440_clk_ac97); + s3c24xx_register_clock(&s3c2440_clk_cam); + s3c24xx_register_clock(&s3c2440_clk_cam_upll); + clkdev_add_table(s3c2440_clk_lookup, ARRAY_SIZE(s3c2440_clk_lookup)); + + clk_disable(&s3c2440_clk_ac97); + clk_disable(&s3c2440_clk_cam); + + return 0; + } + + static struct subsys_interface s3c2440_clk_interface = { + .name = "s3c2440_clk", + .subsys = &s3c2440_subsys, + .add_dev = s3c2440_clk_add, + }; + + static __init int s3c24xx_clk_init(void) + { + return subsys_interface_register(&s3c2440_clk_interface); + } + + arch_initcall(s3c24xx_clk_init); diff --cc arch/arm/mach-s3c24xx/clock-s3c244x.c index 000000000000,b3fdbdda3d5f..6d9b688c442b mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/clock-s3c244x.c +++ b/arch/arm/mach-s3c24xx/clock-s3c244x.c @@@ -1,0 -1,141 +1,141 @@@ + /* linux/arch/arm/plat-s3c24xx/s3c24xx-clock.c + * + * Copyright (c) 2004-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * S3C2440/S3C2442 Common clock support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + #include + + #include + #include + + static int s3c2440_setparent_armclk(struct clk *clk, struct clk *parent) + { + unsigned long camdivn; + unsigned long dvs; + + if (parent == &clk_f) + dvs = 0; + else if (parent == &clk_h) + dvs = S3C2440_CAMDIVN_DVSEN; + else + return -EINVAL; + + clk->parent = parent; + + camdivn = __raw_readl(S3C2440_CAMDIVN); + camdivn &= ~S3C2440_CAMDIVN_DVSEN; + camdivn |= dvs; + __raw_writel(camdivn, S3C2440_CAMDIVN); + + return 0; + } + + static struct clk clk_arm = { + .name = "armclk", + .id = -1, + .ops = &(struct clk_ops) { + .set_parent = s3c2440_setparent_armclk, + }, + }; + -static int s3c244x_clk_add(struct device *dev) ++static int s3c244x_clk_add(struct device *dev, struct subsys_interface *sif) + { + unsigned long camdivn = __raw_readl(S3C2440_CAMDIVN); + unsigned long clkdivn; + struct clk *clock_upll; + int ret; + + printk("S3C244X: Clock Support, DVS %s\n", + (camdivn & S3C2440_CAMDIVN_DVSEN) ? "on" : "off"); + + clk_arm.parent = (camdivn & S3C2440_CAMDIVN_DVSEN) ? &clk_h : &clk_f; + + ret = s3c24xx_register_clock(&clk_arm); + if (ret < 0) { + printk(KERN_ERR "S3C24XX: Failed to add armclk (%d)\n", ret); + return ret; + } + + clock_upll = clk_get(NULL, "upll"); + if (IS_ERR(clock_upll)) { + printk(KERN_ERR "S3C244X: Failed to get upll clock\n"); + return -ENOENT; + } + + /* check rate of UPLL, and if it is near 96MHz, then change + * to using half the UPLL rate for the system */ + + if (clk_get_rate(clock_upll) > (94 * MHZ)) { + clk_usb_bus.rate = clk_get_rate(clock_upll) / 2; + + spin_lock(&clocks_lock); + + clkdivn = __raw_readl(S3C2410_CLKDIVN); + clkdivn |= S3C2440_CLKDIVN_UCLK; + __raw_writel(clkdivn, S3C2410_CLKDIVN); + + spin_unlock(&clocks_lock); + } + + return 0; + } + + static struct subsys_interface s3c2440_clk_interface = { + .name = "s3c2440_clk", + .subsys = &s3c2440_subsys, + .add_dev = s3c244x_clk_add, + }; + + static int s3c2440_clk_init(void) + { + return subsys_interface_register(&s3c2440_clk_interface); + } + + arch_initcall(s3c2440_clk_init); + + static struct subsys_interface s3c2442_clk_interface = { + .name = "s3c2442_clk", + .subsys = &s3c2442_subsys, + .add_dev = s3c244x_clk_add, + }; + + static int s3c2442_clk_init(void) + { + return subsys_interface_register(&s3c2442_clk_interface); + } + + arch_initcall(s3c2442_clk_init); diff --cc arch/arm/mach-s3c24xx/common-s3c2443.c index 000000000000,7414890e6ee8..460431589f39 mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/common-s3c2443.c +++ b/arch/arm/mach-s3c24xx/common-s3c2443.c @@@ -1,0 -1,670 +1,670 @@@ + /* + * Common code for SoCs starting with the S3C2443 + * + * Copyright (c) 2007, 2010 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + #include + #include + #include + + #include + + #include + #include + #include + + #include + + + static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable) + { + u32 ctrlbit = clk->ctrlbit; + u32 con = __raw_readl(reg); + + if (enable) + con |= ctrlbit; + else + con &= ~ctrlbit; + + __raw_writel(con, reg); + return 0; + } + + int s3c2443_clkcon_enable_h(struct clk *clk, int enable) + { + return s3c2443_gate(S3C2443_HCLKCON, clk, enable); + } + + int s3c2443_clkcon_enable_p(struct clk *clk, int enable) + { + return s3c2443_gate(S3C2443_PCLKCON, clk, enable); + } + + int s3c2443_clkcon_enable_s(struct clk *clk, int enable) + { + return s3c2443_gate(S3C2443_SCLKCON, clk, enable); + } + + /* mpllref is a direct descendant of clk_xtal by default, but it is not + * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as + * such directly equating the two source clocks is impossible. + */ -struct clk clk_mpllref = { ++static struct clk clk_mpllref = { + .name = "mpllref", + .parent = &clk_xtal, + }; + + static struct clk *clk_epllref_sources[] = { + [0] = &clk_mpllref, + [1] = &clk_mpllref, + [2] = &clk_xtal, + [3] = &clk_ext, + }; + + struct clksrc_clk clk_epllref = { + .clk = { + .name = "epllref", + }, + .sources = &(struct clksrc_sources) { + .sources = clk_epllref_sources, + .nr_sources = ARRAY_SIZE(clk_epllref_sources), + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 }, + }; + + /* esysclk + * + * this is sourced from either the EPLL or the EPLLref clock + */ + + static struct clk *clk_sysclk_sources[] = { + [0] = &clk_epllref.clk, + [1] = &clk_epll, + }; + + struct clksrc_clk clk_esysclk = { + .clk = { + .name = "esysclk", + .parent = &clk_epll, + }, + .sources = &(struct clksrc_sources) { + .sources = clk_sysclk_sources, + .nr_sources = ARRAY_SIZE(clk_sysclk_sources), + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 }, + }; + + static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) + { + unsigned long parent_rate = clk_get_rate(clk->parent); + unsigned long div = __raw_readl(S3C2443_CLKDIV0); + + div &= S3C2443_CLKDIV0_EXTDIV_MASK; + div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ + + return parent_rate / (div + 1); + } + + static struct clk clk_mdivclk = { + .name = "mdivclk", + .parent = &clk_mpllref, + .ops = &(struct clk_ops) { + .get_rate = s3c2443_getrate_mdivclk, + }, + }; + + static struct clk *clk_msysclk_sources[] = { + [0] = &clk_mpllref, + [1] = &clk_mpll, + [2] = &clk_mdivclk, + [3] = &clk_mpllref, + }; + + struct clksrc_clk clk_msysclk = { + .clk = { + .name = "msysclk", + .parent = &clk_xtal, + }, + .sources = &(struct clksrc_sources) { + .sources = clk_msysclk_sources, + .nr_sources = ARRAY_SIZE(clk_msysclk_sources), + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 }, + }; + + /* prediv + * + * this divides the msysclk down to pass to h/p/etc. + */ + + static unsigned long s3c2443_prediv_getrate(struct clk *clk) + { + unsigned long rate = clk_get_rate(clk->parent); + unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); + + clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK; + clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; + + return rate / (clkdiv0 + 1); + } + + static struct clk clk_prediv = { + .name = "prediv", + .parent = &clk_msysclk.clk, + .ops = &(struct clk_ops) { + .get_rate = s3c2443_prediv_getrate, + }, + }; + + /* hclk divider + * + * divides the prediv and provides the hclk. + */ + + static unsigned long s3c2443_hclkdiv_getrate(struct clk *clk) + { + unsigned long rate = clk_get_rate(clk->parent); + unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); + + clkdiv0 &= S3C2443_CLKDIV0_HCLKDIV_MASK; + + return rate / (clkdiv0 + 1); + } + + static struct clk_ops clk_h_ops = { + .get_rate = s3c2443_hclkdiv_getrate, + }; + + /* pclk divider + * + * divides the hclk and provides the pclk. + */ + + static unsigned long s3c2443_pclkdiv_getrate(struct clk *clk) + { + unsigned long rate = clk_get_rate(clk->parent); + unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); + + clkdiv0 = ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 1 : 0); + + return rate / (clkdiv0 + 1); + } + + static struct clk_ops clk_p_ops = { + .get_rate = s3c2443_pclkdiv_getrate, + }; + + /* armdiv + * + * this clock is sourced from msysclk and can have a number of + * divider values applied to it to then be fed into armclk. + */ + + static unsigned int *armdiv; + static int nr_armdiv; + static int armdivmask; + + static unsigned long s3c2443_armclk_roundrate(struct clk *clk, + unsigned long rate) + { + unsigned long parent = clk_get_rate(clk->parent); + unsigned long calc; + unsigned best = 256; /* bigger than any value */ + unsigned div; + int ptr; + + if (!nr_armdiv) + return -EINVAL; + + for (ptr = 0; ptr < nr_armdiv; ptr++) { + div = armdiv[ptr]; + if (div) { + /* cpufreq provides 266mhz as 266666000 not 266666666 */ + calc = (parent / div / 1000) * 1000; + if (calc <= rate && div < best) + best = div; + } + } + + return parent / best; + } + + static unsigned long s3c2443_armclk_getrate(struct clk *clk) + { + unsigned long rate = clk_get_rate(clk->parent); + unsigned long clkcon0; + int val; + + if (!nr_armdiv || !armdivmask) + return -EINVAL; + + clkcon0 = __raw_readl(S3C2443_CLKDIV0); + clkcon0 &= armdivmask; + val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT; + + return rate / armdiv[val]; + } + + static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate) + { + unsigned long parent = clk_get_rate(clk->parent); + unsigned long calc; + unsigned div; + unsigned best = 256; /* bigger than any value */ + int ptr; + int val = -1; + + if (!nr_armdiv || !armdivmask) + return -EINVAL; + + for (ptr = 0; ptr < nr_armdiv; ptr++) { + div = armdiv[ptr]; + if (div) { + /* cpufreq provides 266mhz as 266666000 not 266666666 */ + calc = (parent / div / 1000) * 1000; + if (calc <= rate && div < best) { + best = div; + val = ptr; + } + } + } + + if (val >= 0) { + unsigned long clkcon0; + + clkcon0 = __raw_readl(S3C2443_CLKDIV0); + clkcon0 &= ~armdivmask; + clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT; + __raw_writel(clkcon0, S3C2443_CLKDIV0); + } + + return (val == -1) ? -EINVAL : 0; + } + + static struct clk clk_armdiv = { + .name = "armdiv", + .parent = &clk_msysclk.clk, + .ops = &(struct clk_ops) { + .round_rate = s3c2443_armclk_roundrate, + .get_rate = s3c2443_armclk_getrate, + .set_rate = s3c2443_armclk_setrate, + }, + }; + + /* armclk + * + * this is the clock fed into the ARM core itself, from armdiv or from hclk. + */ + + static struct clk *clk_arm_sources[] = { + [0] = &clk_armdiv, + [1] = &clk_h, + }; + + static struct clksrc_clk clk_arm = { + .clk = { + .name = "armclk", + }, + .sources = &(struct clksrc_sources) { + .sources = clk_arm_sources, + .nr_sources = ARRAY_SIZE(clk_arm_sources), + }, + .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 }, + }; + + /* usbhost + * + * usb host bus-clock, usually 48MHz to provide USB bus clock timing + */ + + static struct clksrc_clk clk_usb_bus_host = { + .clk = { + .name = "usb-bus-host-parent", + .parent = &clk_esysclk.clk, + .ctrlbit = S3C2443_SCLKCON_USBHOST, + .enable = s3c2443_clkcon_enable_s, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, + }; + + /* common clksrc clocks */ + + static struct clksrc_clk clksrc_clks[] = { + { + /* camera interface bus-clock, divided down from esysclk */ + .clk = { + .name = "camif-upll", /* same as 2440 name */ + .parent = &clk_esysclk.clk, + .ctrlbit = S3C2443_SCLKCON_CAMCLK, + .enable = s3c2443_clkcon_enable_s, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 }, + }, { + .clk = { + .name = "display-if", + .parent = &clk_esysclk.clk, + .ctrlbit = S3C2443_SCLKCON_DISPCLK, + .enable = s3c2443_clkcon_enable_s, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 }, + }, + }; + + static struct clksrc_clk clk_esys_uart = { + /* ART baud-rate clock sourced from esysclk via a divisor */ + .clk = { + .name = "uartclk", + .parent = &clk_esysclk.clk, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, + }; + + static struct clk clk_i2s_ext = { + .name = "i2s-ext", + }; + + /* i2s_eplldiv + * + * This clock is the output from the I2S divisor of ESYSCLK, and is separate + * from the mux that comes after it (cannot merge into one single clock) + */ + + static struct clksrc_clk clk_i2s_eplldiv = { + .clk = { + .name = "i2s-eplldiv", + .parent = &clk_esysclk.clk, + }, + .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, + }; + + /* i2s-ref + * + * i2s bus reference clock, selectable from external, esysclk or epllref + * + * Note, this used to be two clocks, but was compressed into one. + */ + + static struct clk *clk_i2s_srclist[] = { + [0] = &clk_i2s_eplldiv.clk, + [1] = &clk_i2s_ext, + [2] = &clk_epllref.clk, + [3] = &clk_epllref.clk, + }; + + static struct clksrc_clk clk_i2s = { + .clk = { + .name = "i2s-if", + .ctrlbit = S3C2443_SCLKCON_I2SCLK, + .enable = s3c2443_clkcon_enable_s, + + }, + .sources = &(struct clksrc_sources) { + .sources = clk_i2s_srclist, + .nr_sources = ARRAY_SIZE(clk_i2s_srclist), + }, + .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, + }; + + static struct clk init_clocks_off[] = { + { + .name = "iis", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_IIS, + }, { + .name = "hsspi", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_HSSPI, + }, { + .name = "adc", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_ADC, + }, { + .name = "i2c", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_IIC, + } + }; + + static struct clk init_clocks[] = { + { + .name = "dma", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA0, + }, { + .name = "dma", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA1, + }, { + .name = "dma", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA2, + }, { + .name = "dma", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA3, + }, { + .name = "dma", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA4, + }, { + .name = "dma", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_DMA5, + }, { + .name = "gpio", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_GPIO, + }, { + .name = "usb-host", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_USBH, + }, { + .name = "usb-device", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_USBD, + }, { + .name = "lcd", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_LCDC, + + }, { + .name = "timers", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_PWMT, + }, { + .name = "cfc", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_CFC, + }, { + .name = "ssmc", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_SSMC, + }, { + .name = "uart", + .devname = "s3c2440-uart.0", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART0, + }, { + .name = "uart", + .devname = "s3c2440-uart.1", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART1, + }, { + .name = "uart", + .devname = "s3c2440-uart.2", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART2, + }, { + .name = "uart", + .devname = "s3c2440-uart.3", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_UART3, + }, { + .name = "rtc", + .parent = &clk_p, + .enable = s3c2443_clkcon_enable_p, + .ctrlbit = S3C2443_PCLKCON_RTC, + }, { + .name = "watchdog", + .parent = &clk_p, + .ctrlbit = S3C2443_PCLKCON_WDT, + }, { + .name = "ac97", + .parent = &clk_p, + .ctrlbit = S3C2443_PCLKCON_AC97, + }, { + .name = "nand", + .parent = &clk_h, + }, { + .name = "usb-bus-host", + .parent = &clk_usb_bus_host.clk, + } + }; + + static struct clk hsmmc1_clk = { + .name = "hsmmc", + .devname = "s3c-sdhci.1", + .parent = &clk_h, + .enable = s3c2443_clkcon_enable_h, + .ctrlbit = S3C2443_HCLKCON_HSMMC, + }; + + /* EPLLCON compatible enough to get on/off information */ + + void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll) + { + unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); + unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); + struct clk *xtal_clk; + unsigned long xtal; + unsigned long pll; + int ptr; + + xtal_clk = clk_get(NULL, "xtal"); + xtal = clk_get_rate(xtal_clk); + clk_put(xtal_clk); + + pll = get_mpll(mpllcon, xtal); + clk_msysclk.clk.rate = pll; + clk_mpll.rate = pll; + + printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", + (mpllcon & S3C2443_PLLCON_OFF) ? "off" : "on", + print_mhz(pll), print_mhz(clk_get_rate(&clk_armdiv)), + print_mhz(clk_get_rate(&clk_h)), + print_mhz(clk_get_rate(&clk_p))); + + for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++) + s3c_set_clksrc(&clksrc_clks[ptr], true); + + /* ensure usb bus clock is within correct rate of 48MHz */ + + if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) { + printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); + clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000); + } + + printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", + (epllcon & S3C2443_PLLCON_OFF) ? "off" : "on", + print_mhz(clk_get_rate(&clk_epll)), + print_mhz(clk_get_rate(&clk_usb_bus))); + } + + static struct clk *clks[] __initdata = { + &clk_prediv, + &clk_mpllref, + &clk_mdivclk, + &clk_ext, + &clk_epll, + &clk_usb_bus, + &clk_armdiv, + &hsmmc1_clk, + }; + + static struct clksrc_clk *clksrcs[] __initdata = { + &clk_i2s_eplldiv, + &clk_i2s, + &clk_usb_bus_host, + &clk_epllref, + &clk_esysclk, + &clk_msysclk, + &clk_arm, + }; + + static struct clk_lookup s3c2443_clk_lookup[] = { + CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk), + CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p), + CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_esys_uart.clk), + CLKDEV_INIT("s3c-sdhci.1", "mmc_busclk.0", &hsmmc1_clk), + }; + + void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll, + unsigned int *divs, int nr_divs, + int divmask) + { + int ptr; + + armdiv = divs; + nr_armdiv = nr_divs; + armdivmask = divmask; + + /* s3c2443 parents h clock from prediv */ + clk_h.parent = &clk_prediv; + clk_h.ops = &clk_h_ops; + + /* and p clock from h clock */ + clk_p.parent = &clk_h; + clk_p.ops = &clk_p_ops; + + clk_usb_bus.parent = &clk_usb_bus_host.clk; + clk_epll.parent = &clk_epllref.clk; + + s3c24xx_register_baseclocks(xtal); + s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); + + for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) + s3c_register_clksrc(clksrcs[ptr], 1); + + s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks)); + s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); + + /* See s3c2443/etc notes on disabling clocks at init time */ + s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off)); + clkdev_add_table(s3c2443_clk_lookup, ARRAY_SIZE(s3c2443_clk_lookup)); + + s3c2443_common_setup_clocks(get_mpll); + } diff --cc arch/arm/mach-s3c24xx/dma-s3c2410.c index 000000000000,2afd00014a77..4803338cf56e mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2410.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2410.c @@@ -1,0 -1,185 +1,186 @@@ + /* linux/arch/arm/mach-s3c2410/dma.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2410 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + #include + #include + #include + #include + + #include + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = { + [DMACH_XD0] = { + .name = "xdreq0", + .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, + }, + [DMACH_XD1] = { + .name = "xdreq1", + .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, + }, + [DMACH_SDI] = { + .name = "sdi", + .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID, + .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID, + }, + [DMACH_SPI0] = { + .name = "spi0", + .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID, + }, + [DMACH_SPI1] = { + .name = "spi1", + .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID, + }, + [DMACH_UART0] = { + .name = "uart0", + .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, + }, + [DMACH_UART1] = { + .name = "uart1", + .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, + }, + [DMACH_UART2] = { + .name = "uart2", + .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, + }, + [DMACH_TIMER] = { + .name = "timer", + .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, + .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, + }, + [DMACH_I2S_IN] = { + .name = "i2s-sdi", + .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, + }, + [DMACH_I2S_OUT] = { + .name = "i2s-sdo", + .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, + }, + [DMACH_USB_EP1] = { + .name = "usb-ep1", + .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, + }, + [DMACH_USB_EP2] = { + .name = "usb-ep2", + .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, + }, + [DMACH_USB_EP3] = { + .name = "usb-ep3", + .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, + }, + [DMACH_USB_EP4] = { + .name = "usb-ep4", + .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, + }, + }; + + static void s3c2410_dma_select(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map) + { + chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; + } + + static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = { + .select = s3c2410_dma_select, + .dcon_mask = 7 << 24, + .map = s3c2410_dma_mappings, + .map_size = ARRAY_SIZE(s3c2410_dma_mappings), + }; + + static struct s3c24xx_dma_order __initdata s3c2410_dma_order = { + .channels = { + [DMACH_SDI] = { + .list = { + [0] = 3 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + [2] = 0 | DMA_CH_VALID, + }, + }, + [DMACH_I2S_IN] = { + .list = { + [0] = 1 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + }, + }, + }, + }; + -static int __init s3c2410_dma_add(struct device *dev) ++static int __init s3c2410_dma_add(struct device *dev, ++ struct subsys_interface *sif) + { + s3c2410_dma_init(); + s3c24xx_dma_order_set(&s3c2410_dma_order); + return s3c24xx_dma_init_map(&s3c2410_dma_sel); + } + + #if defined(CONFIG_CPU_S3C2410) + static struct subsys_interface s3c2410_dma_interface = { + .name = "s3c2410_dma", + .subsys = &s3c2410_subsys, + .add_dev = s3c2410_dma_add, + }; + + static int __init s3c2410_dma_drvinit(void) + { - return subsys_interface_register(&s3c2410_interface); ++ return subsys_interface_register(&s3c2410_dma_interface); + } + + arch_initcall(s3c2410_dma_drvinit); + + static struct subsys_interface s3c2410a_dma_interface = { + .name = "s3c2410a_dma", + .subsys = &s3c2410a_subsys, + .add_dev = s3c2410_dma_add, + }; + + static int __init s3c2410a_dma_drvinit(void) + { + return subsys_interface_register(&s3c2410a_dma_interface); + } + + arch_initcall(s3c2410a_dma_drvinit); + #endif + + #if defined(CONFIG_CPU_S3C2442) + /* S3C2442 DMA contains the same selection table as the S3C2410 */ + static struct subsys_interface s3c2442_dma_interface = { + .name = "s3c2442_dma", + .subsys = &s3c2442_subsys, + .add_dev = s3c2410_dma_add, + }; + + static int __init s3c2442_dma_drvinit(void) + { + return subsys_interface_register(&s3c2442_dma_interface); + } + + arch_initcall(s3c2442_dma_drvinit); + #endif + diff --cc arch/arm/mach-s3c24xx/dma-s3c2412.c index 000000000000,142acd3b5e15..38472ac920ff mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2412.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2412.c @@@ -1,0 -1,179 +1,180 @@@ + /* linux/arch/arm/mach-s3c2412/dma.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2412 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + #include + #include + #include + #include + #include + + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID } + + static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = { + [DMACH_XD0] = { + .name = "xdreq0", + .channels = MAP(S3C2412_DMAREQSEL_XDREQ0), + .channels_rx = MAP(S3C2412_DMAREQSEL_XDREQ0), + }, + [DMACH_XD1] = { + .name = "xdreq1", + .channels = MAP(S3C2412_DMAREQSEL_XDREQ1), + .channels_rx = MAP(S3C2412_DMAREQSEL_XDREQ1), + }, + [DMACH_SDI] = { + .name = "sdi", + .channels = MAP(S3C2412_DMAREQSEL_SDI), + .channels_rx = MAP(S3C2412_DMAREQSEL_SDI), + }, + [DMACH_SPI0] = { + .name = "spi0", + .channels = MAP(S3C2412_DMAREQSEL_SPI0TX), + .channels_rx = MAP(S3C2412_DMAREQSEL_SPI0RX), + }, + [DMACH_SPI1] = { + .name = "spi1", + .channels = MAP(S3C2412_DMAREQSEL_SPI1TX), + .channels_rx = MAP(S3C2412_DMAREQSEL_SPI1RX), + }, + [DMACH_UART0] = { + .name = "uart0", + .channels = MAP(S3C2412_DMAREQSEL_UART0_0), + .channels_rx = MAP(S3C2412_DMAREQSEL_UART0_0), + }, + [DMACH_UART1] = { + .name = "uart1", + .channels = MAP(S3C2412_DMAREQSEL_UART1_0), + .channels_rx = MAP(S3C2412_DMAREQSEL_UART1_0), + }, + [DMACH_UART2] = { + .name = "uart2", + .channels = MAP(S3C2412_DMAREQSEL_UART2_0), + .channels_rx = MAP(S3C2412_DMAREQSEL_UART2_0), + }, + [DMACH_UART0_SRC2] = { + .name = "uart0", + .channels = MAP(S3C2412_DMAREQSEL_UART0_1), + .channels_rx = MAP(S3C2412_DMAREQSEL_UART0_1), + }, + [DMACH_UART1_SRC2] = { + .name = "uart1", + .channels = MAP(S3C2412_DMAREQSEL_UART1_1), + .channels_rx = MAP(S3C2412_DMAREQSEL_UART1_1), + }, + [DMACH_UART2_SRC2] = { + .name = "uart2", + .channels = MAP(S3C2412_DMAREQSEL_UART2_1), + .channels_rx = MAP(S3C2412_DMAREQSEL_UART2_1), + }, + [DMACH_TIMER] = { + .name = "timer", + .channels = MAP(S3C2412_DMAREQSEL_TIMER), + .channels_rx = MAP(S3C2412_DMAREQSEL_TIMER), + }, + [DMACH_I2S_IN] = { + .name = "i2s-sdi", + .channels = MAP(S3C2412_DMAREQSEL_I2SRX), + .channels_rx = MAP(S3C2412_DMAREQSEL_I2SRX), + }, + [DMACH_I2S_OUT] = { + .name = "i2s-sdo", + .channels = MAP(S3C2412_DMAREQSEL_I2STX), + .channels_rx = MAP(S3C2412_DMAREQSEL_I2STX), + }, + [DMACH_USB_EP1] = { + .name = "usb-ep1", + .channels = MAP(S3C2412_DMAREQSEL_USBEP1), + .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP1), + }, + [DMACH_USB_EP2] = { + .name = "usb-ep2", + .channels = MAP(S3C2412_DMAREQSEL_USBEP2), + .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP2), + }, + [DMACH_USB_EP3] = { + .name = "usb-ep3", + .channels = MAP(S3C2412_DMAREQSEL_USBEP3), + .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP3), + }, + [DMACH_USB_EP4] = { + .name = "usb-ep4", + .channels = MAP(S3C2412_DMAREQSEL_USBEP4), + .channels_rx = MAP(S3C2412_DMAREQSEL_USBEP4), + }, + }; + + static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map, + enum dma_data_direction dir) + { + unsigned long chsel; + + if (dir == DMA_FROM_DEVICE) + chsel = map->channels_rx[0]; + else + chsel = map->channels[0]; + + chsel &= ~DMA_CH_VALID; + chsel |= S3C2412_DMAREQSEL_HW; + + writel(chsel, chan->regs + S3C2412_DMA_DMAREQSEL); + } + + static void s3c2412_dma_select(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map) + { + s3c2412_dma_direction(chan, map, chan->source); + } + + static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = { + .select = s3c2412_dma_select, + .direction = s3c2412_dma_direction, + .dcon_mask = 0, + .map = s3c2412_dma_mappings, + .map_size = ARRAY_SIZE(s3c2412_dma_mappings), + }; + -static int __init s3c2412_dma_add(struct device *dev) ++static int __init s3c2412_dma_add(struct device *dev, ++ struct subsys_interface *sif) + { + s3c2410_dma_init(); + return s3c24xx_dma_init_map(&s3c2412_dma_sel); + } + + static struct subsys_interface s3c2412_dma_interface = { + .name = "s3c2412_dma", + .subsys = &s3c2412_subsys, + .add_dev = s3c2412_dma_add, + }; + + static int __init s3c2412_dma_init(void) + { + return subsys_interface_register(&s3c2412_dma_interface); + } + + arch_initcall(s3c2412_dma_init); diff --cc arch/arm/mach-s3c24xx/dma-s3c2440.c index 000000000000,15b1ddf8f626..5f0a0c8ef84f mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2440.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2440.c @@@ -1,0 -1,196 +1,197 @@@ + /* linux/arch/arm/mach-s3c2440/dma.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * S3C2440 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + #include + #include + #include + #include + + #include + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = { + [DMACH_XD0] = { + .name = "xdreq0", + .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID, + }, + [DMACH_XD1] = { + .name = "xdreq1", + .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID, + }, + [DMACH_SDI] = { + .name = "sdi", + .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID, + .channels[1] = S3C2440_DCON_CH1_SDI | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID, + .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID, + }, + [DMACH_SPI0] = { + .name = "spi0", + .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID, + }, + [DMACH_SPI1] = { + .name = "spi1", + .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID, + }, + [DMACH_UART0] = { + .name = "uart0", + .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID, + }, + [DMACH_UART1] = { + .name = "uart1", + .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID, + }, + [DMACH_UART2] = { + .name = "uart2", + .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID, + }, + [DMACH_TIMER] = { + .name = "timer", + .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID, + .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID, + }, + [DMACH_I2S_IN] = { + .name = "i2s-sdi", + .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID, + }, + [DMACH_I2S_OUT] = { + .name = "i2s-sdo", + .channels[0] = S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID, + .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID, + }, + [DMACH_PCM_IN] = { + .name = "pcm-in", + .channels[0] = S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID, + .channels[2] = S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID, + }, + [DMACH_PCM_OUT] = { + .name = "pcm-out", + .channels[1] = S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID, + .channels[3] = S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID, + }, + [DMACH_MIC_IN] = { + .name = "mic-in", + .channels[2] = S3C2440_DCON_CH2_MICIN | DMA_CH_VALID, + .channels[3] = S3C2440_DCON_CH3_MICIN | DMA_CH_VALID, + }, + [DMACH_USB_EP1] = { + .name = "usb-ep1", + .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID, + }, + [DMACH_USB_EP2] = { + .name = "usb-ep2", + .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID, + }, + [DMACH_USB_EP3] = { + .name = "usb-ep3", + .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID, + }, + [DMACH_USB_EP4] = { + .name = "usb-ep4", + .channels[3] = S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID, + }, + }; + + static void s3c2440_dma_select(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map) + { + chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID; + } + + static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = { + .select = s3c2440_dma_select, + .dcon_mask = 7 << 24, + .map = s3c2440_dma_mappings, + .map_size = ARRAY_SIZE(s3c2440_dma_mappings), + }; + + static struct s3c24xx_dma_order __initdata s3c2440_dma_order = { + .channels = { + [DMACH_SDI] = { + .list = { + [0] = 3 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + [2] = 1 | DMA_CH_VALID, + [3] = 0 | DMA_CH_VALID, + }, + }, + [DMACH_I2S_IN] = { + .list = { + [0] = 1 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + }, + }, + [DMACH_I2S_OUT] = { + .list = { + [0] = 2 | DMA_CH_VALID, + [1] = 1 | DMA_CH_VALID, + }, + }, + [DMACH_PCM_IN] = { + .list = { + [0] = 2 | DMA_CH_VALID, + [1] = 1 | DMA_CH_VALID, + }, + }, + [DMACH_PCM_OUT] = { + .list = { + [0] = 1 | DMA_CH_VALID, + [1] = 3 | DMA_CH_VALID, + }, + }, + [DMACH_MIC_IN] = { + .list = { + [0] = 3 | DMA_CH_VALID, + [1] = 2 | DMA_CH_VALID, + }, + }, + }, + }; + -static int __init s3c2440_dma_add(struct device *dev) ++static int __init s3c2440_dma_add(struct device *dev, ++ struct subsys_interface *sif) + { + s3c2410_dma_init(); + s3c24xx_dma_order_set(&s3c2440_dma_order); + return s3c24xx_dma_init_map(&s3c2440_dma_sel); + } + + static struct subsys_interface s3c2440_dma_interface = { + .name = "s3c2440_dma", + .subsys = &s3c2440_subsys, + .add_dev = s3c2440_dma_add, + }; + + static int __init s3c2440_dma_init(void) + { + return subsys_interface_register(&s3c2440_dma_interface); + } + + arch_initcall(s3c2440_dma_init); + diff --cc arch/arm/mach-s3c24xx/dma-s3c2443.c index 000000000000,2504474389de..e227c472a40a mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/dma-s3c2443.c +++ b/arch/arm/mach-s3c24xx/dma-s3c2443.c @@@ -1,0 -1,173 +1,174 @@@ + /* linux/arch/arm/mach-s3c2443/dma.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks + * + * S3C2443 DMA selection + * + * http://armlinux.simtec.co.uk/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + + #include + #include + #include + #include + #include + + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define MAP(x) { \ + [0] = (x) | DMA_CH_VALID, \ + [1] = (x) | DMA_CH_VALID, \ + [2] = (x) | DMA_CH_VALID, \ + [3] = (x) | DMA_CH_VALID, \ + [4] = (x) | DMA_CH_VALID, \ + [5] = (x) | DMA_CH_VALID, \ + } + + static struct s3c24xx_dma_map __initdata s3c2443_dma_mappings[] = { + [DMACH_XD0] = { + .name = "xdreq0", + .channels = MAP(S3C2443_DMAREQSEL_XDREQ0), + }, + [DMACH_XD1] = { + .name = "xdreq1", + .channels = MAP(S3C2443_DMAREQSEL_XDREQ1), + }, + [DMACH_SDI] = { /* only on S3C2443 */ + .name = "sdi", + .channels = MAP(S3C2443_DMAREQSEL_SDI), + }, + [DMACH_SPI0] = { + .name = "spi0", + .channels = MAP(S3C2443_DMAREQSEL_SPI0TX), + }, + [DMACH_SPI1] = { /* only on S3C2443/S3C2450 */ + .name = "spi1", + .channels = MAP(S3C2443_DMAREQSEL_SPI1TX), + }, + [DMACH_UART0] = { + .name = "uart0", + .channels = MAP(S3C2443_DMAREQSEL_UART0_0), + }, + [DMACH_UART1] = { + .name = "uart1", + .channels = MAP(S3C2443_DMAREQSEL_UART1_0), + }, + [DMACH_UART2] = { + .name = "uart2", + .channels = MAP(S3C2443_DMAREQSEL_UART2_0), + }, + [DMACH_UART3] = { + .name = "uart3", + .channels = MAP(S3C2443_DMAREQSEL_UART3_0), + }, + [DMACH_UART0_SRC2] = { + .name = "uart0", + .channels = MAP(S3C2443_DMAREQSEL_UART0_1), + }, + [DMACH_UART1_SRC2] = { + .name = "uart1", + .channels = MAP(S3C2443_DMAREQSEL_UART1_1), + }, + [DMACH_UART2_SRC2] = { + .name = "uart2", + .channels = MAP(S3C2443_DMAREQSEL_UART2_1), + }, + [DMACH_UART3_SRC2] = { + .name = "uart3", + .channels = MAP(S3C2443_DMAREQSEL_UART3_1), + }, + [DMACH_TIMER] = { + .name = "timer", + .channels = MAP(S3C2443_DMAREQSEL_TIMER), + }, + [DMACH_I2S_IN] = { + .name = "i2s-sdi", + .channels = MAP(S3C2443_DMAREQSEL_I2SRX), + }, + [DMACH_I2S_OUT] = { + .name = "i2s-sdo", + .channels = MAP(S3C2443_DMAREQSEL_I2STX), + }, + [DMACH_PCM_IN] = { + .name = "pcm-in", + .channels = MAP(S3C2443_DMAREQSEL_PCMIN), + }, + [DMACH_PCM_OUT] = { + .name = "pcm-out", + .channels = MAP(S3C2443_DMAREQSEL_PCMOUT), + }, + [DMACH_MIC_IN] = { + .name = "mic-in", + .channels = MAP(S3C2443_DMAREQSEL_MICIN), + }, + }; + + static void s3c2443_dma_select(struct s3c2410_dma_chan *chan, + struct s3c24xx_dma_map *map) + { + writel(map->channels[0] | S3C2443_DMAREQSEL_HW, + chan->regs + S3C2443_DMA_DMAREQSEL); + } + + static struct s3c24xx_dma_selection __initdata s3c2443_dma_sel = { + .select = s3c2443_dma_select, + .dcon_mask = 0, + .map = s3c2443_dma_mappings, + .map_size = ARRAY_SIZE(s3c2443_dma_mappings), + }; + -static int __init s3c2443_dma_add(struct device *dev) ++static int __init s3c2443_dma_add(struct device *dev, ++ struct subsys_interface *sif) + { + s3c24xx_dma_init(6, IRQ_S3C2443_DMA0, 0x100); + return s3c24xx_dma_init_map(&s3c2443_dma_sel); + } + + #ifdef CONFIG_CPU_S3C2416 + /* S3C2416 DMA contains the same selection table as the S3C2443 */ + static struct subsys_interface s3c2416_dma_interface = { + .name = "s3c2416_dma", + .subsys = &s3c2416_subsys, + .add_dev = s3c2443_dma_add, + }; + + static int __init s3c2416_dma_init(void) + { + return subsys_interface_register(&s3c2416_dma_interface); + } + + arch_initcall(s3c2416_dma_init); + #endif + + #ifdef CONFIG_CPU_S3C2443 + static struct subsys_interface s3c2443_dma_interface = { + .name = "s3c2443_dma", + .subsys = &s3c2443_subsys, + .add_dev = s3c2443_dma_add, + }; + + static int __init s3c2443_dma_init(void) + { + return subsys_interface_register(&s3c2443_dma_interface); + } + + arch_initcall(s3c2443_dma_init); + #endif diff --cc arch/arm/mach-s3c24xx/include/mach/entry-macro.S index 000000000000,473b3cd37d9b..7615a14773fa mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/include/mach/entry-macro.S +++ b/arch/arm/mach-s3c24xx/include/mach/entry-macro.S @@@ -1,0 -1,78 +1,70 @@@ + /* + * arch/arm/mach-s3c2410/include/mach/entry-macro.S + * + * Low-level IRQ helper macros for S3C2410-based platforms + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + + /* We have a problem that the INTOFFSET register does not always + * show one interrupt. Occasionally we get two interrupts through + * the prioritiser, and this causes the INTOFFSET register to show + * what looks like the logical-or of the two interrupt numbers. + * + * Thanks to Klaus, Shannon, et al for helping to debug this problem + */ + + #define INTPND (0x10) + #define INTOFFSET (0x14) + + #include + #include + + .macro get_irqnr_preamble, base, tmp + .endm + - .macro arch_ret_to_user, tmp1, tmp2 - .endm - + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + + mov \base, #S3C24XX_VA_IRQ + + @@ try the interrupt offset register, since it is there + + ldr \irqstat, [ \base, #INTPND ] + teq \irqstat, #0 + beq 1002f + ldr \irqnr, [ \base, #INTOFFSET ] + mov \tmp, #1 + tst \irqstat, \tmp, lsl \irqnr + bne 1001f + + @@ the number specified is not a valid irq, so try + @@ and work it out for ourselves + + mov \irqnr, #0 @@ start here + + @@ work out which irq (if any) we got + + movs \tmp, \irqstat, lsl#16 + addeq \irqnr, \irqnr, #16 + moveq \irqstat, \irqstat, lsr#16 + tst \irqstat, #0xff + addeq \irqnr, \irqnr, #8 + moveq \irqstat, \irqstat, lsr#8 + tst \irqstat, #0xf + addeq \irqnr, \irqnr, #4 + moveq \irqstat, \irqstat, lsr#4 + tst \irqstat, #0x3 + addeq \irqnr, \irqnr, #2 + moveq \irqstat, \irqstat, lsr#2 + tst \irqstat, #0x1 + addeq \irqnr, \irqnr, #1 + + @@ we have the value + 1001: + adds \irqnr, \irqnr, #IRQ_EINT0 + 1002: + @@ exit here, Z flag unset if IRQ + + .endm - - /* currently don't need an disable_fiq macro */ - - .macro disable_fiq - .endm diff --cc arch/arm/mach-s3c24xx/irq-s3c2412.c index 000000000000,a8a46c1644f4..e65619ddbccc mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/irq-s3c2412.c +++ b/arch/arm/mach-s3c24xx/irq-s3c2412.c @@@ -1,0 -1,214 +1,214 @@@ + /* linux/arch/arm/mach-s3c2412/irq.c + * + * Copyright (c) 2006 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + #include + #include + #include + + #include + #include + #include + + #define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) + #define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0)))) + + /* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by + * having them turn up in both the INT* and the EINT* registers. Whilst + * both show the status, they both now need to be acked when the IRQs + * go off. + */ + + static void + s3c2412_irq_mask(struct irq_data *data) + { + unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); + unsigned long mask; + + mask = __raw_readl(S3C2410_INTMSK); + __raw_writel(mask | bitval, S3C2410_INTMSK); + + mask = __raw_readl(S3C2412_EINTMASK); + __raw_writel(mask | bitval, S3C2412_EINTMASK); + } + + static inline void + s3c2412_irq_ack(struct irq_data *data) + { + unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); + + __raw_writel(bitval, S3C2412_EINTPEND); + __raw_writel(bitval, S3C2410_SRCPND); + __raw_writel(bitval, S3C2410_INTPND); + } + + static inline void + s3c2412_irq_maskack(struct irq_data *data) + { + unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); + unsigned long mask; + + mask = __raw_readl(S3C2410_INTMSK); + __raw_writel(mask|bitval, S3C2410_INTMSK); + + mask = __raw_readl(S3C2412_EINTMASK); + __raw_writel(mask | bitval, S3C2412_EINTMASK); + + __raw_writel(bitval, S3C2412_EINTPEND); + __raw_writel(bitval, S3C2410_SRCPND); + __raw_writel(bitval, S3C2410_INTPND); + } + + static void + s3c2412_irq_unmask(struct irq_data *data) + { + unsigned long bitval = 1UL << (data->irq - IRQ_EINT0); + unsigned long mask; + + mask = __raw_readl(S3C2412_EINTMASK); + __raw_writel(mask & ~bitval, S3C2412_EINTMASK); + + mask = __raw_readl(S3C2410_INTMSK); + __raw_writel(mask & ~bitval, S3C2410_INTMSK); + } + + static struct irq_chip s3c2412_irq_eint0t4 = { + .irq_ack = s3c2412_irq_ack, + .irq_mask = s3c2412_irq_mask, + .irq_unmask = s3c2412_irq_unmask, + .irq_set_wake = s3c_irq_wake, + .irq_set_type = s3c_irqext_type, + }; + + #define INTBIT(x) (1 << ((x) - S3C2410_IRQSUB(0))) + + /* CF and SDI sub interrupts */ + + static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc) + { + unsigned int subsrc, submsk; + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + + if (subsrc & INTBIT(IRQ_S3C2412_SDI)) + generic_handle_irq(IRQ_S3C2412_SDI); + + if (subsrc & INTBIT(IRQ_S3C2412_CF)) + generic_handle_irq(IRQ_S3C2412_CF); + } + + #define INTMSK_CFSDI (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0)) + #define SUBMSK_CFSDI INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF) + + static void s3c2412_irq_cfsdi_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI); + } + + static void s3c2412_irq_cfsdi_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_CFSDI); + } + + static void s3c2412_irq_cfsdi_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_CFSDI, SUBMSK_CFSDI); + } + + static struct irq_chip s3c2412_irq_cfsdi = { + .name = "s3c2412-cfsdi", + .irq_ack = s3c2412_irq_cfsdi_ack, + .irq_mask = s3c2412_irq_cfsdi_mask, + .irq_unmask = s3c2412_irq_cfsdi_unmask, + }; + + static int s3c2412_irq_rtc_wake(struct irq_data *data, unsigned int state) + { + unsigned long pwrcfg; + + pwrcfg = __raw_readl(S3C2412_PWRCFG); + if (state) + pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ; + else + pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ; + __raw_writel(pwrcfg, S3C2412_PWRCFG); + + return s3c_irq_chip.irq_set_wake(data, state); + } + + static struct irq_chip s3c2412_irq_rtc_chip; + -static int s3c2412_irq_add(struct device *dev) ++static int s3c2412_irq_add(struct device *dev, struct subsys_interface *sif) + { + unsigned int irqno; + + for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { + irq_set_chip_and_handler(irqno, &s3c2412_irq_eint0t4, + handle_edge_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + /* add demux support for CF/SDI */ + + irq_set_chained_handler(IRQ_S3C2412_CFSDI, s3c2412_irq_demux_cfsdi); + + for (irqno = IRQ_S3C2412_SDI; irqno <= IRQ_S3C2412_CF; irqno++) { + irq_set_chip_and_handler(irqno, &s3c2412_irq_cfsdi, + handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + /* change RTC IRQ's set wake method */ + + s3c2412_irq_rtc_chip = s3c_irq_chip; + s3c2412_irq_rtc_chip.irq_set_wake = s3c2412_irq_rtc_wake; + + irq_set_chip(IRQ_RTC, &s3c2412_irq_rtc_chip); + + return 0; + } + + static struct subsys_interface s3c2412_irq_interface = { + .name = "s3c2412_irq", + .subsys = &s3c2412_subsys, + .add_dev = s3c2412_irq_add, + }; + + static int s3c2412_irq_init(void) + { + return subsys_interface_register(&s3c2412_irq_interface); + } + + arch_initcall(s3c2412_irq_init); diff --cc arch/arm/mach-s3c24xx/irq-s3c2416.c index 000000000000,36df761061de..fd49f35e448e mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/irq-s3c2416.c +++ b/arch/arm/mach-s3c24xx/irq-s3c2416.c @@@ -1,0 -1,249 +1,250 @@@ + /* linux/arch/arm/mach-s3c2416/irq.c + * + * Copyright (c) 2009 Yauhen Kharuzhy , + * as part of OpenInkpot project + * Copyright (c) 2009 Promwad Innovation Company + * Yauhen Kharuzhy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + #include + #include + + #include + #include + #include + + #define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) + + static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len) + { + unsigned int subsrc, submsk; + unsigned int end; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= (irq - S3C2410_IRQSUB(0)); + subsrc &= (1 << len)-1; + + end = len + irq; + + for (; irq < end && subsrc; irq++) { + if (subsrc & 1) + generic_handle_irq(irq); + + subsrc >>= 1; + } + } + + /* WDT/AC97 sub interrupts */ + + static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc) + { + s3c2416_irq_demux(IRQ_S3C2443_WDT, 4); + } + + #define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0)) + #define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97) + + static void s3c2416_irq_wdtac97_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97); + } + + static void s3c2416_irq_wdtac97_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97); + } + + static void s3c2416_irq_wdtac97_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97); + } + + static struct irq_chip s3c2416_irq_wdtac97 = { + .irq_mask = s3c2416_irq_wdtac97_mask, + .irq_unmask = s3c2416_irq_wdtac97_unmask, + .irq_ack = s3c2416_irq_wdtac97_ack, + }; + + /* LCD sub interrupts */ + + static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc) + { + s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4); + } + + #define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) + #define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4) + + static void s3c2416_irq_lcd_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD); + } + + static void s3c2416_irq_lcd_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_LCD); + } + + static void s3c2416_irq_lcd_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD); + } + + static struct irq_chip s3c2416_irq_lcd = { + .irq_mask = s3c2416_irq_lcd_mask, + .irq_unmask = s3c2416_irq_lcd_unmask, + .irq_ack = s3c2416_irq_lcd_ack, + }; + + /* DMA sub interrupts */ + + static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc) + { + s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6); + } + + #define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0)) + #define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5) + + + static void s3c2416_irq_dma_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA); + } + + static void s3c2416_irq_dma_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_DMA); + } + + static void s3c2416_irq_dma_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA); + } + + static struct irq_chip s3c2416_irq_dma = { + .irq_mask = s3c2416_irq_dma_mask, + .irq_unmask = s3c2416_irq_dma_unmask, + .irq_ack = s3c2416_irq_dma_ack, + }; + + /* UART3 sub interrupts */ + + static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) + { + s3c2416_irq_demux(IRQ_S3C2443_RX3, 3); + } + + #define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) + #define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) + + static void s3c2416_irq_uart3_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3); + } + + static void s3c2416_irq_uart3_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_UART3); + } + + static void s3c2416_irq_uart3_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3); + } + + static struct irq_chip s3c2416_irq_uart3 = { + .irq_mask = s3c2416_irq_uart3_mask, + .irq_unmask = s3c2416_irq_uart3_unmask, + .irq_ack = s3c2416_irq_uart3_ack, + }; + + /* IRQ initialisation code */ + + static int __init s3c2416_add_sub(unsigned int base, + void (*demux)(unsigned int, + struct irq_desc *), + struct irq_chip *chip, + unsigned int start, unsigned int end) + { + unsigned int irqno; + + irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq); + irq_set_chained_handler(base, demux); + + for (irqno = start; irqno <= end; irqno++) { + irq_set_chip_and_handler(irqno, chip, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + return 0; + } + -static int __init s3c2416_irq_add(struct device *dev) ++static int __init s3c2416_irq_add(struct device *dev, ++ struct subsys_interface *sif) + { + printk(KERN_INFO "S3C2416: IRQ Support\n"); + + s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd, + IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4); + + s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma, + &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5); + + s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3, + &s3c2416_irq_uart3, + IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3); + + s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97, + &s3c2416_irq_wdtac97, + IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); + + return 0; + } + + static struct subsys_interface s3c2416_irq_interface = { + .name = "s3c2416_irq", + .subsys = &s3c2416_subsys, + .add_dev = s3c2416_irq_add, + }; + + static int __init s3c2416_irq_init(void) + { + return subsys_interface_register(&s3c2416_irq_interface); + } + + arch_initcall(s3c2416_irq_init); + diff --cc arch/arm/mach-s3c24xx/irq-s3c2440.c index 000000000000,4fee9bc6bcb5..4a18cde439cc mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/irq-s3c2440.c +++ b/arch/arm/mach-s3c24xx/irq-s3c2440.c @@@ -1,0 -1,128 +1,128 @@@ + /* linux/arch/arm/mach-s3c2440/irq.c + * + * Copyright (c) 2003-2004 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + #include + #include + + #include + #include + #include + + /* WDT/AC97 */ + + static void s3c_irq_demux_wdtac97(unsigned int irq, + struct irq_desc *desc) + { + unsigned int subsrc, submsk; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= 13; + subsrc &= 3; + + if (subsrc != 0) { + if (subsrc & 1) { + generic_handle_irq(IRQ_S3C2440_WDT); + } + if (subsrc & 2) { + generic_handle_irq(IRQ_S3C2440_AC97); + } + } + } + + + #define INTMSK_WDT (1UL << (IRQ_WDT - IRQ_EINT0)) + + static void + s3c_irq_wdtac97_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_WDT, 3 << 13); + } + + static void + s3c_irq_wdtac97_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_WDT); + } + + static void + s3c_irq_wdtac97_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_WDT, 3 << 13); + } + + static struct irq_chip s3c_irq_wdtac97 = { + .irq_mask = s3c_irq_wdtac97_mask, + .irq_unmask = s3c_irq_wdtac97_unmask, + .irq_ack = s3c_irq_wdtac97_ack, + }; + -static int s3c2440_irq_add(struct device *dev) ++static int s3c2440_irq_add(struct device *dev, struct subsys_interface *sif) + { + unsigned int irqno; + + printk("S3C2440: IRQ Support\n"); + + /* add new chained handler for wdt, ac7 */ + + irq_set_chip_and_handler(IRQ_WDT, &s3c_irq_level_chip, + handle_level_irq); + irq_set_chained_handler(IRQ_WDT, s3c_irq_demux_wdtac97); + + for (irqno = IRQ_S3C2440_WDT; irqno <= IRQ_S3C2440_AC97; irqno++) { + irq_set_chip_and_handler(irqno, &s3c_irq_wdtac97, + handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + return 0; + } + + static struct subsys_interface s3c2440_irq_interface = { + .name = "s3c2440_irq", + .subsys = &s3c2440_subsys, + .add_dev = s3c2440_irq_add, + }; + + static int s3c2440_irq_init(void) + { + return subsys_interface_register(&s3c2440_irq_interface); + } + + arch_initcall(s3c2440_irq_init); + diff --cc arch/arm/mach-s3c24xx/irq-s3c2443.c index 000000000000,35e4ff24fb43..ac2829f56d12 mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/irq-s3c2443.c +++ b/arch/arm/mach-s3c24xx/irq-s3c2443.c @@@ -1,0 -1,280 +1,281 @@@ + /* linux/arch/arm/mach-s3c2443/irq.c + * + * Copyright (c) 2007 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + #include + #include + + #include + #include + #include + + #define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) + + static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len) + { + unsigned int subsrc, submsk; + unsigned int end; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= (irq - S3C2410_IRQSUB(0)); + subsrc &= (1 << len)-1; + + end = len + irq; + + for (; irq < end && subsrc; irq++) { + if (subsrc & 1) + generic_handle_irq(irq); + + subsrc >>= 1; + } + } + + /* WDT/AC97 sub interrupts */ + + static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc) + { + s3c2443_irq_demux(IRQ_S3C2443_WDT, 4); + } + + #define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0)) + #define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97) + + static void s3c2443_irq_wdtac97_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97); + } + + static void s3c2443_irq_wdtac97_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97); + } + + static void s3c2443_irq_wdtac97_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97); + } + + static struct irq_chip s3c2443_irq_wdtac97 = { + .irq_mask = s3c2443_irq_wdtac97_mask, + .irq_unmask = s3c2443_irq_wdtac97_unmask, + .irq_ack = s3c2443_irq_wdtac97_ack, + }; + + /* LCD sub interrupts */ + + static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc) + { + s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4); + } + + #define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) + #define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4) + + static void s3c2443_irq_lcd_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD); + } + + static void s3c2443_irq_lcd_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_LCD); + } + + static void s3c2443_irq_lcd_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD); + } + + static struct irq_chip s3c2443_irq_lcd = { + .irq_mask = s3c2443_irq_lcd_mask, + .irq_unmask = s3c2443_irq_lcd_unmask, + .irq_ack = s3c2443_irq_lcd_ack, + }; + + /* DMA sub interrupts */ + + static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc) + { + s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6); + } + + #define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0)) + #define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5) + + static void s3c2443_irq_dma_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA); + } + + static void s3c2443_irq_dma_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_DMA); + } + + static void s3c2443_irq_dma_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA); + } + + static struct irq_chip s3c2443_irq_dma = { + .irq_mask = s3c2443_irq_dma_mask, + .irq_unmask = s3c2443_irq_dma_unmask, + .irq_ack = s3c2443_irq_dma_ack, + }; + + /* UART3 sub interrupts */ + + static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) + { + s3c2443_irq_demux(IRQ_S3C2443_RX3, 3); + } + + #define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) + #define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) + + static void s3c2443_irq_uart3_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3); + } + + static void s3c2443_irq_uart3_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_UART3); + } + + static void s3c2443_irq_uart3_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3); + } + + static struct irq_chip s3c2443_irq_uart3 = { + .irq_mask = s3c2443_irq_uart3_mask, + .irq_unmask = s3c2443_irq_uart3_unmask, + .irq_ack = s3c2443_irq_uart3_ack, + }; + + /* CAM sub interrupts */ + + static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc) + { + s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4); + } + + #define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) + #define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P) + + static void s3c2443_irq_cam_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_CAM, SUBMSK_CAM); + } + + static void s3c2443_irq_cam_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_CAM); + } + + static void s3c2443_irq_cam_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_CAM, SUBMSK_CAM); + } + + static struct irq_chip s3c2443_irq_cam = { + .irq_mask = s3c2443_irq_cam_mask, + .irq_unmask = s3c2443_irq_cam_unmask, + .irq_ack = s3c2443_irq_cam_ack, + }; + + /* IRQ initialisation code */ + + static int __init s3c2443_add_sub(unsigned int base, + void (*demux)(unsigned int, + struct irq_desc *), + struct irq_chip *chip, + unsigned int start, unsigned int end) + { + unsigned int irqno; + + irq_set_chip_and_handler(base, &s3c_irq_level_chip, handle_level_irq); + irq_set_chained_handler(base, demux); + + for (irqno = start; irqno <= end; irqno++) { + irq_set_chip_and_handler(irqno, chip, handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + return 0; + } + -static int __init s3c2443_irq_add(struct device *dev) ++static int __init s3c2443_irq_add(struct device *dev, ++ struct subsys_interface *sif) + { + printk("S3C2443: IRQ Support\n"); + + s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam, + IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P); + + s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd, + IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4); + + s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma, + &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5); + + s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3, + &s3c2443_irq_uart3, + IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3); + + s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97, + &s3c2443_irq_wdtac97, + IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); + + return 0; + } + + static struct subsys_interface s3c2443_irq_interface = { + .name = "s3c2443_irq", + .subsys = &s3c2443_subsys, + .add_dev = s3c2443_irq_add, + }; + + static int __init s3c2443_irq_init(void) + { + return subsys_interface_register(&s3c2443_irq_interface); + } + + arch_initcall(s3c2443_irq_init); + diff --cc arch/arm/mach-s3c24xx/irq-s3c244x.c index 000000000000,74d3dcf46a48..5fe8e58d3afd mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/irq-s3c244x.c +++ b/arch/arm/mach-s3c24xx/irq-s3c244x.c @@@ -1,0 -1,142 +1,142 @@@ + /* linux/arch/arm/plat-s3c24xx/s3c244x-irq.c + * + * Copyright (c) 2003-2004 Simtec Electronics + * Ben Dooks + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + #include + #include + + #include + #include + #include + + /* camera irq */ + + static void s3c_irq_demux_cam(unsigned int irq, + struct irq_desc *desc) + { + unsigned int subsrc, submsk; + + /* read the current pending interrupts, and the mask + * for what it is available */ + + subsrc = __raw_readl(S3C2410_SUBSRCPND); + submsk = __raw_readl(S3C2410_INTSUBMSK); + + subsrc &= ~submsk; + subsrc >>= 11; + subsrc &= 3; + + if (subsrc != 0) { + if (subsrc & 1) { + generic_handle_irq(IRQ_S3C2440_CAM_C); + } + if (subsrc & 2) { + generic_handle_irq(IRQ_S3C2440_CAM_P); + } + } + } + + #define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) + + static void + s3c_irq_cam_mask(struct irq_data *data) + { + s3c_irqsub_mask(data->irq, INTMSK_CAM, 3 << 11); + } + + static void + s3c_irq_cam_unmask(struct irq_data *data) + { + s3c_irqsub_unmask(data->irq, INTMSK_CAM); + } + + static void + s3c_irq_cam_ack(struct irq_data *data) + { + s3c_irqsub_maskack(data->irq, INTMSK_CAM, 3 << 11); + } + + static struct irq_chip s3c_irq_cam = { + .irq_mask = s3c_irq_cam_mask, + .irq_unmask = s3c_irq_cam_unmask, + .irq_ack = s3c_irq_cam_ack, + }; + -static int s3c244x_irq_add(struct device *dev) ++static int s3c244x_irq_add(struct device *dev, struct subsys_interface *sif) + { + unsigned int irqno; + + irq_set_chip_and_handler(IRQ_NFCON, &s3c_irq_level_chip, + handle_level_irq); + set_irq_flags(IRQ_NFCON, IRQF_VALID); + + /* add chained handler for camera */ + + irq_set_chip_and_handler(IRQ_CAM, &s3c_irq_level_chip, + handle_level_irq); + irq_set_chained_handler(IRQ_CAM, s3c_irq_demux_cam); + + for (irqno = IRQ_S3C2440_CAM_C; irqno <= IRQ_S3C2440_CAM_P; irqno++) { + irq_set_chip_and_handler(irqno, &s3c_irq_cam, + handle_level_irq); + set_irq_flags(irqno, IRQF_VALID); + } + + return 0; + } + + static struct subsys_interface s3c2440_irq_interface = { + .name = "s3c2440_irq", + .subsys = &s3c2440_subsys, + .add_dev = s3c244x_irq_add, + }; + + static int s3c2440_irq_init(void) + { + return subsys_interface_register(&s3c2440_irq_interface); + } + + arch_initcall(s3c2440_irq_init); + + static struct subsys_interface s3c2442_irq_interface = { + .name = "s3c2442_irq", + .subsys = &s3c2442_subsys, + .add_dev = s3c244x_irq_add, + }; + + + static int s3c2442_irq_init(void) + { + return subsys_interface_register(&s3c2442_irq_interface); + } + + arch_initcall(s3c2442_irq_init); diff --cc arch/arm/mach-s3c24xx/mach-gta02.c index 000000000000,cf270f51d149..d0e0ad4e6598 mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@@ -1,0 -1,605 +1,605 @@@ + /* + * linux/arch/arm/mach-s3c2442/mach-gta02.c + * + * S3C2442 Machine Support for Openmoko GTA02 / FreeRunner. + * + * Copyright (C) 2006-2009 by Openmoko, Inc. + * Authors: Harald Welte + * Andy Green + * Werner Almesberger + * All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + #include + #include + + #include + #include + + #include + #include + #include + #include + + #include + #include + #include + + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include "common.h" + + static struct pcf50633 *gta02_pcf; + + /* + * This gets called frequently when we paniced. + */ + + static long gta02_panic_blink(int state) + { + long delay = 0; + char led; + + led = (state) ? 1 : 0; + gpio_direction_output(GTA02_GPIO_AUX_LED, led); + + return delay; + } + + + static struct map_desc gta02_iodesc[] __initdata = { + { + .virtual = 0xe0000000, + .pfn = __phys_to_pfn(S3C2410_CS3 + 0x01000000), + .length = SZ_1M, + .type = MT_DEVICE + }, + }; + + #define UCON (S3C2410_UCON_DEFAULT | S3C2443_UCON_RXERR_IRQEN) + #define ULCON (S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB) + #define UFCON (S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE) + + static struct s3c2410_uartcfg gta02_uartcfgs[] = { + [0] = { + .hwport = 0, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + [1] = { + .hwport = 1, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + [2] = { + .hwport = 2, + .flags = 0, + .ucon = UCON, + .ulcon = ULCON, + .ufcon = UFCON, + }, + }; + + #ifdef CONFIG_CHARGER_PCF50633 + /* + * On GTA02 the 1A charger features a 48K resistor to 0V on the ID pin. + * We use this to recognize that we can pull 1A from the USB socket. + * + * These constants are the measured pcf50633 ADC levels with the 1A + * charger / 48K resistor, and with no pulldown resistor. + */ + + #define ADC_NOM_CHG_DETECT_1A 6 + #define ADC_NOM_CHG_DETECT_USB 43 + + static void + gta02_configure_pmu_for_charger(struct pcf50633 *pcf, void *unused, int res) + { + int ma; + + /* Interpret charger type */ + if (res < ((ADC_NOM_CHG_DETECT_USB + ADC_NOM_CHG_DETECT_1A) / 2)) { + + /* + * Sanity - stop GPO driving out now that we have a 1A charger + * GPO controls USB Host power generation on GTA02 + */ + pcf50633_gpio_set(pcf, PCF50633_GPO, 0); + + ma = 1000; + } else + ma = 100; + + pcf50633_mbc_usb_curlim_set(pcf, ma); + } + + static struct delayed_work gta02_charger_work; + static int gta02_usb_vbus_draw; + + static void gta02_charger_worker(struct work_struct *work) + { + if (gta02_usb_vbus_draw) { + pcf50633_mbc_usb_curlim_set(gta02_pcf, gta02_usb_vbus_draw); + return; + } + + #ifdef CONFIG_PCF50633_ADC + pcf50633_adc_async_read(gta02_pcf, + PCF50633_ADCC1_MUX_ADCIN1, + PCF50633_ADCC1_AVERAGE_16, + gta02_configure_pmu_for_charger, + NULL); + #else + /* + * If the PCF50633 ADC is disabled we fallback to a + * 100mA limit for safety. + */ + pcf50633_mbc_usb_curlim_set(pcf, 100); + #endif + } + + #define GTA02_CHARGER_CONFIGURE_TIMEOUT ((3000 * HZ) / 1000) + + static void gta02_pmu_event_callback(struct pcf50633 *pcf, int irq) + { + if (irq == PCF50633_IRQ_USBINS) { + schedule_delayed_work(>a02_charger_work, + GTA02_CHARGER_CONFIGURE_TIMEOUT); + + return; + } + + if (irq == PCF50633_IRQ_USBREM) { + cancel_delayed_work_sync(>a02_charger_work); + gta02_usb_vbus_draw = 0; + } + } + + static void gta02_udc_vbus_draw(unsigned int ma) + { + if (!gta02_pcf) + return; + + gta02_usb_vbus_draw = ma; + + schedule_delayed_work(>a02_charger_work, + GTA02_CHARGER_CONFIGURE_TIMEOUT); + } + #else /* !CONFIG_CHARGER_PCF50633 */ + #define gta02_pmu_event_callback NULL + #define gta02_udc_vbus_draw NULL + #endif + + /* + * This is called when pc50633 is probed, unfortunately quite late in the + * day since it is an I2C bus device. Here we can belatedly define some + * platform devices with the advantage that we can mark the pcf50633 as the + * parent. This makes them get suspended and resumed with their parent + * the pcf50633 still around. + */ + + static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf); + + + static char *gta02_batteries[] = { + "battery", + }; + + static struct pcf50633_bl_platform_data gta02_backlight_data = { + .default_brightness = 0x3f, + .default_brightness_limit = 0, + .ramp_time = 5, + }; + -struct pcf50633_platform_data gta02_pcf_pdata = { ++static struct pcf50633_platform_data gta02_pcf_pdata = { + .resumers = { + [0] = PCF50633_INT1_USBINS | + PCF50633_INT1_USBREM | + PCF50633_INT1_ALARM, + [1] = PCF50633_INT2_ONKEYF, + [2] = PCF50633_INT3_ONKEY1S, + [3] = PCF50633_INT4_LOWSYS | + PCF50633_INT4_LOWBAT | + PCF50633_INT4_HIGHTMP, + }, + + .batteries = gta02_batteries, + .num_batteries = ARRAY_SIZE(gta02_batteries), + + .charger_reference_current_ma = 1000, + + .backlight_data = >a02_backlight_data, + + .reg_init_data = { + [PCF50633_REGULATOR_AUTO] = { + .constraints = { + .min_uV = 3300000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .always_on = 1, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_DOWN1] = { + .constraints = { + .min_uV = 1300000, + .max_uV = 1600000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .always_on = 1, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_DOWN2] = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + .always_on = 1, + }, + }, + [PCF50633_REGULATOR_HCLDO] = { + .constraints = { + .min_uV = 2000000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, + }, + [PCF50633_REGULATOR_LDO1] = { + .constraints = { + .min_uV = 3300000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_LDO2] = { + .constraints = { + .min_uV = 3300000, + .max_uV = 3300000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_LDO3] = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_LDO4] = { + .constraints = { + .min_uV = 3200000, + .max_uV = 3200000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_LDO5] = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + .apply_uV = 1, + }, + }, + [PCF50633_REGULATOR_LDO6] = { + .constraints = { + .min_uV = 3000000, + .max_uV = 3000000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + }, + }, + [PCF50633_REGULATOR_MEMLDO] = { + .constraints = { + .min_uV = 1800000, + .max_uV = 1800000, + .valid_modes_mask = REGULATOR_MODE_NORMAL, + }, + }, + + }, + .probe_done = gta02_pmu_attach_child_devices, + .mbc_event_callback = gta02_pmu_event_callback, + }; + + + /* NOR Flash. */ + + #define GTA02_FLASH_BASE 0x18000000 /* GCS3 */ + #define GTA02_FLASH_SIZE 0x200000 /* 2MBytes */ + + static struct physmap_flash_data gta02_nor_flash_data = { + .width = 2, + }; + + static struct resource gta02_nor_flash_resource = { + .start = GTA02_FLASH_BASE, + .end = GTA02_FLASH_BASE + GTA02_FLASH_SIZE - 1, + .flags = IORESOURCE_MEM, + }; + + static struct platform_device gta02_nor_flash = { + .name = "physmap-flash", + .id = 0, + .dev = { + .platform_data = >a02_nor_flash_data, + }, + .resource = >a02_nor_flash_resource, + .num_resources = 1, + }; + + -struct platform_device s3c24xx_pwm_device = { ++static struct platform_device s3c24xx_pwm_device = { + .name = "s3c24xx_pwm", + .num_resources = 0, + }; + + static struct platform_device gta02_dfbmcs320_device = { + .name = "dfbmcs320", + }; + + static struct i2c_board_info gta02_i2c_devs[] __initdata = { + { + I2C_BOARD_INFO("pcf50633", 0x73), + .irq = GTA02_IRQ_PCF50633, + .platform_data = >a02_pcf_pdata, + }, + { + I2C_BOARD_INFO("wm8753", 0x1a), + }, + }; + + static struct s3c2410_nand_set __initdata gta02_nand_sets[] = { + [0] = { + /* + * This name is also hard-coded in the boot loaders, so + * changing it would would require all users to upgrade + * their boot loaders, some of which are stored in a NOR + * that is considered to be immutable. + */ + .name = "neo1973-nand", + .nr_chips = 1, + .flash_bbt = 1, + }, + }; + + /* + * Choose a set of timings derived from S3C@2442B MCP54 + * data sheet (K5D2G13ACM-D075 MCP Memory). + */ + + static struct s3c2410_platform_nand __initdata gta02_nand_info = { + .tacls = 0, + .twrph0 = 25, + .twrph1 = 15, + .nr_sets = ARRAY_SIZE(gta02_nand_sets), + .sets = gta02_nand_sets, + }; + + + /* Get PMU to set USB current limit accordingly. */ + static struct s3c2410_udc_mach_info gta02_udc_cfg __initdata = { + .vbus_draw = gta02_udc_vbus_draw, + .pullup_pin = GTA02_GPIO_USB_PULLUP, + }; + + /* USB */ + static struct s3c2410_hcd_info gta02_usb_info __initdata = { + .port[0] = { + .flags = S3C_HCDFLG_USED, + }, + .port[1] = { + .flags = 0, + }, + }; + + /* Touchscreen */ + static struct s3c2410_ts_mach_info gta02_ts_info = { + .delay = 10000, + .presc = 0xff, /* slow as we can go */ + .oversampling_shift = 2, + }; + + /* Buttons */ + static struct gpio_keys_button gta02_buttons[] = { + { + .gpio = GTA02_GPIO_AUX_KEY, + .code = KEY_PHONE, + .desc = "Aux", + .type = EV_KEY, + .debounce_interval = 100, + }, + { + .gpio = GTA02_GPIO_HOLD_KEY, + .code = KEY_PAUSE, + .desc = "Hold", + .type = EV_KEY, + .debounce_interval = 100, + }, + }; + + static struct gpio_keys_platform_data gta02_buttons_pdata = { + .buttons = gta02_buttons, + .nbuttons = ARRAY_SIZE(gta02_buttons), + }; + + static struct platform_device gta02_buttons_device = { + .name = "gpio-keys", + .id = -1, + .dev = { + .platform_data = >a02_buttons_pdata, + }, + }; + + static void __init gta02_map_io(void) + { + s3c24xx_init_io(gta02_iodesc, ARRAY_SIZE(gta02_iodesc)); + s3c24xx_init_clocks(12000000); + s3c24xx_init_uarts(gta02_uartcfgs, ARRAY_SIZE(gta02_uartcfgs)); + } + + + /* These are the guys that don't need to be children of PMU. */ + + static struct platform_device *gta02_devices[] __initdata = { + &s3c_device_ohci, + &s3c_device_wdt, + &s3c_device_sdi, + &s3c_device_usbgadget, + &s3c_device_nand, + >a02_nor_flash, + &s3c24xx_pwm_device, + &s3c_device_iis, + &samsung_asoc_dma, + &s3c_device_i2c0, + >a02_dfbmcs320_device, + >a02_buttons_device, + &s3c_device_adc, + &s3c_device_ts, + }; + + /* These guys DO need to be children of PMU. */ + + static struct platform_device *gta02_devices_pmu_children[] = { + }; + + + /* + * This is called when pc50633 is probed, quite late in the day since it is an + * I2C bus device. Here we can define platform devices with the advantage that + * we can mark the pcf50633 as the parent. This makes them get suspended and + * resumed with their parent the pcf50633 still around. All devices whose + * operation depends on something from pcf50633 must have this relationship + * made explicit like this, or suspend and resume will become an unreliable + * hellworld. + */ + + static void gta02_pmu_attach_child_devices(struct pcf50633 *pcf) + { + int n; + + /* Grab a copy of the now probed PMU pointer. */ + gta02_pcf = pcf; + + for (n = 0; n < ARRAY_SIZE(gta02_devices_pmu_children); n++) + gta02_devices_pmu_children[n]->dev.parent = pcf->dev; + + platform_add_devices(gta02_devices_pmu_children, + ARRAY_SIZE(gta02_devices_pmu_children)); + } + + static void gta02_poweroff(void) + { + pcf50633_reg_set_bit_mask(gta02_pcf, PCF50633_REG_OOCSHDWN, 1, 1); + } + + static void __init gta02_machine_init(void) + { + /* Set the panic callback to turn AUX LED on or off. */ + panic_blink = gta02_panic_blink; + + s3c_pm_init(); + + #ifdef CONFIG_CHARGER_PCF50633 + INIT_DELAYED_WORK(>a02_charger_work, gta02_charger_worker); + #endif + + s3c24xx_udc_set_platdata(>a02_udc_cfg); + s3c24xx_ts_set_platdata(>a02_ts_info); + s3c_ohci_set_platdata(>a02_usb_info); + s3c_nand_set_platdata(>a02_nand_info); + s3c_i2c0_set_platdata(NULL); + + i2c_register_board_info(0, gta02_i2c_devs, ARRAY_SIZE(gta02_i2c_devs)); + + platform_add_devices(gta02_devices, ARRAY_SIZE(gta02_devices)); + pm_power_off = gta02_poweroff; + + regulator_has_full_constraints(); + } + + + MACHINE_START(NEO1973_GTA02, "GTA02") + /* Maintainer: Nelson Castillo */ + .atag_offset = 0x100, + .map_io = gta02_map_io, + .init_irq = s3c24xx_init_irq, + .init_machine = gta02_machine_init, + .timer = &s3c24xx_timer, + .restart = s3c2440_restart, + MACHINE_END diff --cc arch/arm/mach-s3c24xx/mach-h1940.c index 000000000000,41245a603981..6b21ba107eab mode 000000,100644..100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@@ -1,0 -1,757 +1,757 @@@ + /* linux/arch/arm/mach-s3c2410/mach-h1940.c + * + * Copyright (c) 2003-2005 Simtec Electronics + * Ben Dooks + * + * http://www.handhelds.org/projects/h1940.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #include