From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933199Ab0LTUtV (ORCPT ); Mon, 20 Dec 2010 15:49:21 -0500 Received: from mail.bluewatersys.com ([202.124.120.130]:55817 "EHLO hayes.bluewaternz.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S932769Ab0LTUtT (ORCPT ); Mon, 20 Dec 2010 15:49:19 -0500 Message-ID: <4D0FC1AE.2050708@bluewatersys.com> Date: Tue, 21 Dec 2010 09:50:54 +1300 From: Ryan Mallon User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.12) Gecko/20100915 Thunderbird/3.0.8 MIME-Version: 1.0 To: Alexey Charkov CC: Russell King - ARM Linux , linux-arm-kernel@lists.infradead.org, vt8500-wm8505-linux-kernel@googlegroups.com, Eric Miao , =?ISO-8859-1?Q?Uwe_Kleine-K=F6nig?= , Albin Tonnerre , linux-kernel@vger.kernel.org Subject: Re: [PATCH 1/6 v9] ARM: Add basic architecture support for VIA/WonderMedia 85xx SoC's References: <1289147348-31969-1-git-send-email-alchark@gmail.com> <20101107165745.GB1759@n2100.arm.linux.org.uk> <20101107171726.GF1759@n2100.arm.linux.org.uk> <20101108171930.GA1471@alchark-u3s.lan> <20101111212322.GA15533@alchark-u3s.lan> <20101111234957.GA28735@n2100.arm.linux.org.uk> <20101219174017.GA31832@alchark-u3s> <20101220191549.GH28157@n2100.arm.linux.org.uk> <20101220195423.GA14509@alchark-u3s> In-Reply-To: <20101220195423.GA14509@alchark-u3s> X-Enigmail-Version: 1.0.1 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On 12/21/2010 08:54 AM, Alexey Charkov wrote: > This adds support for the family of Systems-on-Chip produced initially > by VIA and now its subsidiary WonderMedia that have recently become > widespread in lower-end Chinese ARM-based tablets and netbooks. > > Support is included for both VT8500 and WM8505, selectable by a > configuration switch at kernel build time. > > Included are basic machine initialization files, register and > interrupt definitions, support for the on-chip interrupt controller, > high-precision OS timer, GPIO lines, necessary macros for early debug, > pulse-width-modulated outputs control, as well as platform device > configurations for the specific drivers implemented elsewhere. > > Signed-off-by: Alexey Charkov Hi Alexey, Quick review below. ~Ryan > --- > > Dropped GENERIC_TIME selection from Kconfig. No further changes > compared to v8. > > This is against current Linus' 'master' branch. > > Best regards, > Alexey > > arch/arm/Kconfig | 12 + > arch/arm/Makefile | 1 + > arch/arm/boot/compressed/Makefile | 4 + > arch/arm/boot/compressed/head-vt8500.S | 46 +++ > arch/arm/mach-vt8500/Kconfig | 73 ++++ > arch/arm/mach-vt8500/Makefile | 6 + > arch/arm/mach-vt8500/Makefile.boot | 3 + > arch/arm/mach-vt8500/bv07.c | 82 ++++ > arch/arm/mach-vt8500/devices.c | 460 +++++++++++++++++++++++ > arch/arm/mach-vt8500/devices.h | 46 +++ > arch/arm/mach-vt8500/gpio.c | 230 +++++++++++ > arch/arm/mach-vt8500/include/mach/debug-macro.S | 31 ++ > arch/arm/mach-vt8500/include/mach/entry-macro.S | 32 ++ > arch/arm/mach-vt8500/include/mach/gpio.h | 6 + > arch/arm/mach-vt8500/include/mach/hardware.h | 12 + > arch/arm/mach-vt8500/include/mach/io.h | 28 ++ > arch/arm/mach-vt8500/include/mach/irq_defs.h | 124 ++++++ > arch/arm/mach-vt8500/include/mach/irqs.h | 22 ++ > arch/arm/mach-vt8500/include/mach/memory.h | 28 ++ > arch/arm/mach-vt8500/include/mach/mmio_regs.h | 90 +++++ > arch/arm/mach-vt8500/include/mach/system.h | 18 + > arch/arm/mach-vt8500/include/mach/timex.h | 26 ++ > arch/arm/mach-vt8500/include/mach/uncompress.h | 37 ++ > arch/arm/mach-vt8500/include/mach/vmalloc.h | 20 + > arch/arm/mach-vt8500/include/mach/vt8500fb.h | 31 ++ > arch/arm/mach-vt8500/irq.c | 179 +++++++++ > arch/arm/mach-vt8500/irq_defs.c | 173 +++++++++ > arch/arm/mach-vt8500/mmio_regs.c | 118 ++++++ > arch/arm/mach-vt8500/pwm.c | 254 +++++++++++++ > arch/arm/mach-vt8500/timer.c | 154 ++++++++ > arch/arm/mach-vt8500/wm8505_7in.c | 81 ++++ > 31 files changed, 2427 insertions(+), 0 deletions(-) > create mode 100644 arch/arm/boot/compressed/head-vt8500.S > create mode 100644 arch/arm/mach-vt8500/Kconfig > create mode 100644 arch/arm/mach-vt8500/Makefile > create mode 100644 arch/arm/mach-vt8500/Makefile.boot > create mode 100644 arch/arm/mach-vt8500/bv07.c > create mode 100644 arch/arm/mach-vt8500/devices.c > create mode 100644 arch/arm/mach-vt8500/devices.h > create mode 100644 arch/arm/mach-vt8500/gpio.c > create mode 100644 arch/arm/mach-vt8500/include/mach/debug-macro.S > create mode 100644 arch/arm/mach-vt8500/include/mach/entry-macro.S > create mode 100644 arch/arm/mach-vt8500/include/mach/gpio.h > create mode 100644 arch/arm/mach-vt8500/include/mach/hardware.h > create mode 100644 arch/arm/mach-vt8500/include/mach/io.h > create mode 100644 arch/arm/mach-vt8500/include/mach/irq_defs.h > create mode 100644 arch/arm/mach-vt8500/include/mach/irqs.h > create mode 100644 arch/arm/mach-vt8500/include/mach/memory.h > create mode 100644 arch/arm/mach-vt8500/include/mach/mmio_regs.h > create mode 100644 arch/arm/mach-vt8500/include/mach/system.h > create mode 100644 arch/arm/mach-vt8500/include/mach/timex.h > create mode 100644 arch/arm/mach-vt8500/include/mach/uncompress.h > create mode 100644 arch/arm/mach-vt8500/include/mach/vmalloc.h > create mode 100644 arch/arm/mach-vt8500/include/mach/vt8500fb.h > create mode 100644 arch/arm/mach-vt8500/irq.c > create mode 100644 arch/arm/mach-vt8500/irq_defs.c > create mode 100644 arch/arm/mach-vt8500/mmio_regs.c > create mode 100644 arch/arm/mach-vt8500/pwm.c > create mode 100644 arch/arm/mach-vt8500/timer.c > create mode 100644 arch/arm/mach-vt8500/wm8505_7in.c > > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig > index d56d21c..53052fa 100644 > --- a/arch/arm/Kconfig > +++ b/arch/arm/Kconfig > @@ -843,6 +843,16 @@ config PLAT_SPEAR > help > Support for ST's SPEAr platform (SPEAr3xx, SPEAr6xx and SPEAr13xx). > > +config ARCH_VT8500 > + bool "VIA/WonderMedia 85xx" > + select CPU_ARM926T > + select GENERIC_GPIO > + select ARCH_HAS_CPUFREQ > + select GENERIC_CLOCKEVENTS > + select ARCH_REQUIRE_GPIOLIB > + select HAVE_PWM > + help > + Support for VIA/WonderMedia VT8500/WM85xx System-on-Chip. > endchoice > > # > @@ -973,6 +983,8 @@ source "arch/arm/mach-versatile/Kconfig" > > source "arch/arm/mach-vexpress/Kconfig" > > +source "arch/arm/mach-vt8500/Kconfig" > + > source "arch/arm/mach-w90x900/Kconfig" > > # Definitions to make life easier > diff --git a/arch/arm/Makefile b/arch/arm/Makefile > index b87aed0..b0f219a 100644 > --- a/arch/arm/Makefile > +++ b/arch/arm/Makefile > @@ -189,6 +189,7 @@ machine-$(CONFIG_ARCH_U300) := u300 > machine-$(CONFIG_ARCH_U8500) := ux500 > machine-$(CONFIG_ARCH_VERSATILE) := versatile > machine-$(CONFIG_ARCH_VEXPRESS) := vexpress > +machine-$(CONFIG_ARCH_VT8500) := vt8500 > machine-$(CONFIG_ARCH_W90X900) := w90x900 > machine-$(CONFIG_ARCH_NUC93X) := nuc93x > machine-$(CONFIG_FOOTBRIDGE) := footbridge > diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile > index 65a7c1c..62cade4 100644 > --- a/arch/arm/boot/compressed/Makefile > +++ b/arch/arm/boot/compressed/Makefile > @@ -29,6 +29,10 @@ ifeq ($(CONFIG_ARCH_SA1100),y) > OBJS += head-sa1100.o > endif > > +ifeq ($(CONFIG_ARCH_VT8500),y) > +OBJS += head-vt8500.o > +endif > + > ifeq ($(CONFIG_CPU_XSCALE),y) > OBJS += head-xscale.o > endif > diff --git a/arch/arm/boot/compressed/head-vt8500.S b/arch/arm/boot/compressed/head-vt8500.S > new file mode 100644 > index 0000000..1dc1e21 > --- /dev/null > +++ b/arch/arm/boot/compressed/head-vt8500.S > @@ -0,0 +1,46 @@ > +/* > + * linux/arch/arm/boot/compressed/head-vt8500.S > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * VIA VT8500 specific tweaks. This is merged into head.S by the linker. > + * > + */ > + > +#include > +#include > + > + .section ".start", "ax" > + > +__VT8500_start: > + @ Compare the SCC ID register against a list of known values > + ldr r1, .SCCID > + ldr r3, [r1] > + > + @ VT8500 override > + ldr r4, .VT8500SCC > + cmp r3, r4 > + ldreq r7, .ID_BV07 > + beq .Lendvt8500 > + > + @ WM8505 override > + ldr r4, .WM8505SCC > + cmp r3, r4 > + ldreq r7, .ID_8505 > + beq .Lendvt8500 > + > + @ Otherwise, leave the bootloader's machine id untouched > + > +.SCCID: > + .word 0xd8120000 > +.VT8500SCC: > + .word 0x34000102 > +.WM8505SCC: > + .word 0x34260103 > + > +.ID_BV07: > + .word MACH_TYPE_BV07 > +.ID_8505: > + .word MACH_TYPE_WM8505_7IN_NETBOOK > + > +.Lendvt8500: > diff --git a/arch/arm/mach-vt8500/Kconfig b/arch/arm/mach-vt8500/Kconfig > new file mode 100644 > index 0000000..2c20a34 > --- /dev/null > +++ b/arch/arm/mach-vt8500/Kconfig > @@ -0,0 +1,73 @@ > +if ARCH_VT8500 > + > +config VTWM_VERSION_VT8500 > + bool > + > +config VTWM_VERSION_WM8505 > + bool > + > +config MACH_BV07 > + bool "Benign BV07-8500 Mini Netbook" > + depends on ARCH_VT8500 > + select VTWM_VERSION_VT8500 > + help > + Add support for the inexpensive 7-inch netbooks sold by many > + Chinese distributors under various names. Note that there are > + many hardware implementations in identical exterior, make sure > + that yours is indeed based on a VIA VT8500 chip. > + > +config MACH_WM8505_7IN_NETBOOK > + bool "WM8505 7-inch generic netbook" > + depends on ARCH_VT8500 > + select VTWM_VERSION_WM8505 > + help > + Add support for the inexpensive 7-inch netbooks sold by many > + Chinese distributors under various names. Note that there are > + many hardware implementations in identical exterior, make sure > + that yours is indeed based on a WonderMedia WM8505 chip. > + > +comment "LCD panel size" > + > +config WMT_PANEL_800X480 > + bool "7-inch with 800x480 resolution" > + depends on (FB_VT8500 || FB_WM8505) > + default y > + help > + These are found in most of the netbooks in generic cases, as > + well as in Eken M001 tablets and possibly elsewhere. > + > + To select this panel at runtime, say y here and append > + 'panel=800x480' to your kernel command line. Otherwise, the > + largest one available will be used. > + > +config WMT_PANEL_800X600 > + bool "8-inch with 800x600 resolution" > + depends on (FB_VT8500 || FB_WM8505) > + help > + These are found in Eken M003 tablets and possibly elsewhere. > + > + To select this panel at runtime, say y here and append > + 'panel=800x600' to your kernel command line. Otherwise, the > + largest one available will be used. > + > +config WMT_PANEL_1024X576 > + bool "10-inch with 1024x576 resolution" > + depends on (FB_VT8500 || FB_WM8505) > + help > + These are found in CherryPal netbooks and possibly elsewhere. > + > + To select this panel at runtime, say y here and append > + 'panel=1024x576' to your kernel command line. Otherwise, the > + largest one available will be used. > + > +config WMT_PANEL_1024X600 > + bool "10-inch with 1024x600 resolution" > + depends on (FB_VT8500 || FB_WM8505) > + help > + These are found in Eken M006 tablets and possibly elsewhere. > + > + To select this panel at runtime, say y here and append > + 'panel=1024x600' to your kernel command line. Otherwise, the > + largest one available will be used. > + > +endif > diff --git a/arch/arm/mach-vt8500/Makefile b/arch/arm/mach-vt8500/Makefile > new file mode 100644 > index 0000000..aff4159 > --- /dev/null > +++ b/arch/arm/mach-vt8500/Makefile > @@ -0,0 +1,6 @@ > +obj-y += devices.o gpio.o irq.o irq_defs.o mmio_regs.o timer.o > + > +obj-$(CONFIG_MACH_BV07) += bv07.o > +obj-$(CONFIG_MACH_WM8505_7IN_NETBOOK) += wm8505_7in.o > + > +obj-$(CONFIG_HAVE_PWM) += pwm.o > diff --git a/arch/arm/mach-vt8500/Makefile.boot b/arch/arm/mach-vt8500/Makefile.boot > new file mode 100644 > index 0000000..a8acc4e > --- /dev/null > +++ b/arch/arm/mach-vt8500/Makefile.boot > @@ -0,0 +1,3 @@ > + zreladdr-y := 0x00008000 > +params_phys-y := 0x00000100 > +initrd_phys-y := 0x01000000 > diff --git a/arch/arm/mach-vt8500/bv07.c b/arch/arm/mach-vt8500/bv07.c > new file mode 100644 > index 0000000..d2de5f9 > --- /dev/null > +++ b/arch/arm/mach-vt8500/bv07.c > @@ -0,0 +1,82 @@ > +/* > + * arch/arm/mach-vt8500/bv07.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 "devices.h" > + > +static void __iomem *pmc_hiber; > + > +static struct platform_device *devices[] __initdata = { > + &vt8500_device_uart0, > + &vt8500_device_lcdc, > + &vt8500_device_ehci, > + &vt8500_device_ge_rops, > + &vt8500_device_pwm, > + &vt8500_device_pwmbl, > + &vt8500_device_rtc, > +}; > + > +static void vt8500_power_off(void) > +{ > + local_irq_disable(); > + writew(5, pmc_hiber); > + asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0)); > +} > + > +void __init bv07_init(void) > +{ > +#ifdef CONFIG_FB_VT8500 > + void __iomem *gpio_mux_reg = ioremap(wmt_current_regs->gpio > + + 0x200, 4); > + if (gpio_mux_reg) { > + writel(readl(gpio_mux_reg) | 1, gpio_mux_reg); > + iounmap(gpio_mux_reg); > + } else { > + printk(KERN_ERR "Could not remap the GPIO mux register, " > + "display may not work properly!\n"); > + } > +#endif > + pmc_hiber = ioremap(wmt_current_regs->pmc + 0x12, 2); > + if (pmc_hiber) > + pm_power_off = &vt8500_power_off; > + else > + printk(KERN_ERR "PMC Hibernation register could not be " > + "remapped, not enabling power off!\n"); > + > + wmt_set_resources(); > + platform_add_devices(devices, ARRAY_SIZE(devices)); > + vt8500_gpio_init(); > +} > + > +MACHINE_START(BV07, "Benign BV07 Mini Netbook") > + .boot_params = 0x00000100, > + .reserve = vt8500_reserve_mem, > + .map_io = vt8500_map_io, > + .init_irq = vt8500_init_irq, > + .timer = &vt8500_timer, > + .init_machine = bv07_init, > +MACHINE_END > diff --git a/arch/arm/mach-vt8500/devices.c b/arch/arm/mach-vt8500/devices.c > new file mode 100644 > index 0000000..1ce577b > --- /dev/null > +++ b/arch/arm/mach-vt8500/devices.c > @@ -0,0 +1,460 @@ > +/* linux/arch/arm/mach-vt8500/devices.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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 > +#include > + > +#include > +#include > +#include > +#include "devices.h" > + > +static struct resource resources_lcdc[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static u64 fb_dma_mask = DMA_BIT_MASK(32); > + > +struct platform_device vt8500_device_lcdc = { > + .name = "vt8500-lcd", > + .id = 0, > + .dev = { > + .dma_mask = &fb_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > + .num_resources = ARRAY_SIZE(resources_lcdc), > + .resource = resources_lcdc, > +}; > + > +static struct resource resources_wm8505_fb[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + } > +}; > + > +struct platform_device vt8500_device_wm8505_fb = { > + .name = "wm8505-fb", > + .id = 0, > + .num_resources = ARRAY_SIZE(resources_wm8505_fb), > + .resource = resources_wm8505_fb, > +}; > + > +/* Smallest to largest */ > +static struct vt8500fb_platform_data panels[] = { > +#ifdef CONFIG_WMT_PANEL_800X480 > +{ > + .xres_virtual = 800, > + .yres_virtual = 480 * 2, > + .mode = { > + .name = "800x480", > + .xres = 800, > + .yres = 480, > + .left_margin = 88, > + .right_margin = 40, > + .upper_margin = 32, > + .lower_margin = 11, > + .hsync_len = 0, > + .vsync_len = 1, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}, > +#endif > +#ifdef CONFIG_WMT_PANEL_800X600 > +{ > + .xres_virtual = 800, > + .yres_virtual = 600 * 2, > + .mode = { > + .name = "800x600", > + .xres = 800, > + .yres = 600, > + .left_margin = 88, > + .right_margin = 40, > + .upper_margin = 32, > + .lower_margin = 11, > + .hsync_len = 0, > + .vsync_len = 1, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}, > +#endif > +#ifdef CONFIG_WMT_PANEL_1024X576 > +{ > + .xres_virtual = 1024, > + .yres_virtual = 576 * 2, > + .mode = { > + .name = "1024x576", > + .xres = 1024, > + .yres = 576, > + .left_margin = 40, > + .right_margin = 24, > + .upper_margin = 32, > + .lower_margin = 11, > + .hsync_len = 96, > + .vsync_len = 2, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}, > +#endif > +#ifdef CONFIG_WMT_PANEL_1024X600 > +{ > + .xres_virtual = 1024, > + .yres_virtual = 600 * 2, > + .mode = { > + .name = "1024x600", > + .xres = 1024, > + .yres = 600, > + .left_margin = 66, > + .right_margin = 2, > + .upper_margin = 19, > + .lower_margin = 1, > + .hsync_len = 23, > + .vsync_len = 8, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}, > +#endif > +}; > + > +static int current_panel_idx __initdata = ARRAY_SIZE(panels) - 1; > + > +static int __init panel_setup(char *str) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(panels); i++) { > + int len = strlen(panels[i].mode.name); > + > + if (memcmp(panels[i].mode.name, str, len) == 0) { Should be strcmp. If the length of str is less than panels[i].mode.name then you will buffer overrun. > + current_panel_idx = i; > + break; > + } > + } > + return 0; > +} > + > +early_param("panel", panel_setup); > + > +static inline void preallocate_fb(struct vt8500fb_platform_data *p, > + unsigned long align) { > + p->video_mem_len = (p->xres_virtual * p->yres_virtual * 4) >> > + (p->bpp > 16 ? 0 : (p->bpp > 8 ? 1 : > + (8 / p->bpp) + 1)); > + p->video_mem_phys = (unsigned long)memblock_alloc(p->video_mem_len, > + align); > + p->video_mem_virt = phys_to_virt(p->video_mem_phys); > +} > + > +static struct resource resources_uart0[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; What's happening here? Does something else fill these in? If so, there should be a comment to that effect. > +static struct resource resources_uart1[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static struct resource resources_uart2[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static struct resource resources_uart3[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static struct resource resources_uart4[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +static struct resource resources_uart5[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +struct platform_device vt8500_device_uart0 = { > + .name = "vt8500_serial", > + .id = 0, > + .num_resources = ARRAY_SIZE(resources_uart0), > + .resource = resources_uart0, > +}; > + > +struct platform_device vt8500_device_uart1 = { > + .name = "vt8500_serial", > + .id = 1, > + .num_resources = ARRAY_SIZE(resources_uart1), > + .resource = resources_uart1, > +}; > + > +struct platform_device vt8500_device_uart2 = { > + .name = "vt8500_serial", > + .id = 2, > + .num_resources = ARRAY_SIZE(resources_uart2), > + .resource = resources_uart2, > +}; > + > +struct platform_device vt8500_device_uart3 = { > + .name = "vt8500_serial", > + .id = 3, > + .num_resources = ARRAY_SIZE(resources_uart3), > + .resource = resources_uart3, > +}; > + > +struct platform_device vt8500_device_uart4 = { > + .name = "vt8500_serial", > + .id = 4, > + .num_resources = ARRAY_SIZE(resources_uart4), > + .resource = resources_uart4, > +}; > + > +struct platform_device vt8500_device_uart5 = { > + .name = "vt8500_serial", > + .id = 5, > + .num_resources = ARRAY_SIZE(resources_uart5), > + .resource = resources_uart5, > +}; > + > +static struct resource resources_ehci[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + } > +}; > + > +static u64 ehci_dma_mask = DMA_BIT_MASK(32); > + > +struct platform_device vt8500_device_ehci = { > + .name = "vt8500-ehci", > + .id = 0, > + .dev = { > + .dma_mask = &ehci_dma_mask, > + .coherent_dma_mask = DMA_BIT_MASK(32), > + }, > + .num_resources = ARRAY_SIZE(resources_ehci), > + .resource = resources_ehci, > +}; > + > +static struct resource resources_ge_rops[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + } > +}; > + > +struct platform_device vt8500_device_ge_rops = { > + .name = "wmt_ge_rops", > + .id = 0, > + .num_resources = ARRAY_SIZE(resources_ge_rops), > + .resource = resources_ge_rops, > +}; > + > +static struct resource resources_pwm[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > +}; > + > +struct platform_device vt8500_device_pwm = { > + .name = "vt8500-pwm", > + .id = 0, > + .resource = resources_pwm, > + .num_resources = ARRAY_SIZE(resources_pwm), > +}; > + > +static struct platform_pwm_backlight_data vt8500_pwmbl_data = { > + .pwm_id = 0, > + .max_brightness = 128, > + .dft_brightness = 70, > + .pwm_period_ns = 250000, /* revisit when clocks are implemented */ > +}; > + > +struct platform_device vt8500_device_pwmbl = { > + .name = "pwm-backlight", > + .id = 0, > + .dev = { > + .platform_data = &vt8500_pwmbl_data, > + }, > +}; > + > +static struct resource resources_rtc[] = { > + [0] = { > + .flags = IORESOURCE_MEM, > + }, > + [1] = { > + .flags = IORESOURCE_IRQ, > + }, > + [2] = { > + .flags = IORESOURCE_IRQ, > + }, > +}; > + > +struct platform_device vt8500_device_rtc = { > + .name = "vt8500-rtc", > + .id = 0, > + .resource = resources_rtc, > + .num_resources = ARRAY_SIZE(resources_rtc), > +}; > + > +static struct map_desc vt8500_io_desc[] __initdata = { > + /* SoC MMIO registers, to be filled in later */ > + [0] = { > + .type = MT_DEVICE > + }, > + /* PCI I/O space, numbers tied to those in */ > + [1] = { > + .virtual = 0xf0000000, > + .pfn = __phys_to_pfn(0xc0000000), > + .length = SZ_64K, > + .type = MT_DEVICE > + }, > +}; > + > +void __init wmt_set_resources(void) > +{ > + resources_lcdc[0].start = wmt_current_regs->lcdc; > + resources_lcdc[0].end = wmt_current_regs->lcdc + SZ_1K - 1; > + resources_lcdc[1].start = wmt_current_irqs->lcdc; > + resources_lcdc[1].end = wmt_current_irqs->lcdc; Ah, this makes more sense. But why have all the indirection? The wmt_regmaps table could just be replaced with #defines and then have separate device files for the VT8500 and the WM8505. This would also make clearer which variants have which peripherals. > + resources_wm8505_fb[0].start = wmt_current_regs->govr; > + resources_wm8505_fb[0].end = wmt_current_regs->govr + 512 - 1; > + > + resources_uart0[0].start = wmt_current_regs->uart0; > + resources_uart0[0].end = wmt_current_regs->uart0 + 0x103f; > + resources_uart0[1].start = wmt_current_irqs->uart0; > + resources_uart0[1].end = wmt_current_irqs->uart0; > + resources_uart1[0].start = wmt_current_regs->uart1; > + resources_uart1[0].end = wmt_current_regs->uart1 + 0x103f; > + resources_uart1[1].start = wmt_current_irqs->uart1; > + resources_uart1[1].end = wmt_current_irqs->uart1; > + resources_uart2[0].start = wmt_current_regs->uart2; > + resources_uart2[0].end = wmt_current_regs->uart2 + 0x103f; > + resources_uart2[1].start = wmt_current_irqs->uart2; > + resources_uart2[1].end = wmt_current_irqs->uart2; > + resources_uart3[0].start = wmt_current_regs->uart3; > + resources_uart3[0].end = wmt_current_regs->uart3 + 0x103f; > + resources_uart3[1].start = wmt_current_irqs->uart3; > + resources_uart3[1].end = wmt_current_irqs->uart3; > + resources_uart4[0].start = wmt_current_regs->uart4; > + resources_uart4[0].end = wmt_current_regs->uart4 + 0x103f; > + resources_uart4[1].start = wmt_current_irqs->uart4; > + resources_uart4[1].end = wmt_current_irqs->uart4; > + resources_uart5[0].start = wmt_current_regs->uart5; > + resources_uart5[0].end = wmt_current_regs->uart5 + 0x103f; > + resources_uart5[1].start = wmt_current_irqs->uart5; > + resources_uart5[1].end = wmt_current_irqs->uart5; > + > + resources_ehci[0].start = wmt_current_regs->ehci; > + resources_ehci[0].end = wmt_current_regs->ehci + 512 - 1; > + resources_ehci[1].start = wmt_current_irqs->ehci; > + resources_ehci[1].end = wmt_current_irqs->ehci; There is a mix of hex and decimal constants here and exact sizes and sizes with 1 subtracted. Please be consistent. > + resources_ge_rops[0].start = wmt_current_regs->ge; > + resources_ge_rops[0].end = wmt_current_regs->ge + 0xff; > + > + resources_pwm[0].start = wmt_current_regs->pwm; > + resources_pwm[0].end = wmt_current_regs->pwm + 0x43; > + > + resources_rtc[0].start = wmt_current_regs->rtc; > + resources_rtc[0].end = wmt_current_regs->rtc + 0x2c - 1; > + resources_rtc[1].start = wmt_current_irqs->rtc; > + resources_rtc[1].end = wmt_current_irqs->rtc; > + resources_rtc[2].start = wmt_current_irqs->rtc_hz; > + resources_rtc[2].end = wmt_current_irqs->rtc_hz; > +} > + > +void __init vt8500_map_io(void) > +{ > + wmt_current_regs = &wmt_regmaps[VT8500_INDEX]; > + wmt_current_irqs = &wmt_irqs[VT8500_INDEX]; > + > + vt8500_io_desc[0].virtual = wmt_current_regs->mmio_regs_virt; > + vt8500_io_desc[0].pfn = > + __phys_to_pfn(wmt_current_regs->mmio_regs_start); > + vt8500_io_desc[0].length = wmt_current_regs->mmio_regs_length; > + > + iotable_init(vt8500_io_desc, ARRAY_SIZE(vt8500_io_desc)); > +} > + > +void __init wm8505_map_io(void) > +{ > + wmt_current_regs = &wmt_regmaps[WM8505_INDEX]; > + wmt_current_irqs = &wmt_irqs[WM8505_INDEX]; > + > + vt8500_io_desc[0].virtual = wmt_current_regs->mmio_regs_virt; > + vt8500_io_desc[0].pfn = > + __phys_to_pfn(wmt_current_regs->mmio_regs_start); > + vt8500_io_desc[0].length = wmt_current_regs->mmio_regs_length; > + > + iotable_init(vt8500_io_desc, ARRAY_SIZE(vt8500_io_desc)); > +} Separate files. If more variants get added, this file will become unwieldy very quickly. > + > +void __init vt8500_reserve_mem(void) > +{ > +#ifdef CONFIG_FB_VT8500 > + panels[current_panel_idx].bpp = 16; /* Always use RGB565 */ > + preallocate_fb(&panels[current_panel_idx], SZ_4M); > + vt8500_device_lcdc.dev.platform_data = &panels[current_panel_idx]; > +#endif > +} Not sure if this should exist in the platform code or the framebuffer driver. In the latter case it would automatically be CONFIG_FB_VT8500 and the platform_data can still be set in the platform code. Is there a reason for this not to be in the framebuffer driver? > + > +void __init wm8505_reserve_mem(void) > +{ > +#if defined CONFIG_FB_WM8505 > + panels[current_panel_idx].bpp = 32; /* Always use RGB888 */ > + preallocate_fb(&panels[current_panel_idx], 32); > + vt8500_device_wm8505_fb.dev.platform_data = &panels[current_panel_idx]; > +#endif > +} > diff --git a/arch/arm/mach-vt8500/devices.h b/arch/arm/mach-vt8500/devices.h > new file mode 100644 > index 0000000..428809e > --- /dev/null > +++ b/arch/arm/mach-vt8500/devices.h > @@ -0,0 +1,46 @@ > +/* linux/arch/arm/mach-vt8500/devices.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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. > + * > + */ > + > +#ifndef __ARCH_ARM_MACH_VT8500_DEVICES_H > +#define __ARCH_ARM_MACH_VT8500_DEVICES_H > + > +#include > + > +void __init vt8500_init_irq(void); > +void __init wm8505_init_irq(void); > +void __init vt8500_map_io(void); > +void __init wm8505_map_io(void); > +void __init vt8500_reserve_mem(void); > +void __init wm8505_reserve_mem(void); > +void __init wmt_set_resources(void); > +void __init vt8500_gpio_init(void); > + > +extern struct sys_timer vt8500_timer; > + > +extern struct platform_device vt8500_device_uart0; > +extern struct platform_device vt8500_device_uart1; > +extern struct platform_device vt8500_device_uart2; > +extern struct platform_device vt8500_device_uart3; > +extern struct platform_device vt8500_device_uart4; > +extern struct platform_device vt8500_device_uart5; > + > +extern struct platform_device vt8500_device_lcdc; > +extern struct platform_device vt8500_device_wm8505_fb; > +extern struct platform_device vt8500_device_ehci; > +extern struct platform_device vt8500_device_ge_rops; > +extern struct platform_device vt8500_device_pwm; > +extern struct platform_device vt8500_device_pwmbl; > +extern struct platform_device vt8500_device_rtc; This could all disappear if you had separate files for the vt8500/wm8505 peripherals since the platform_devices could all be static. > +#endif > diff --git a/arch/arm/mach-vt8500/gpio.c b/arch/arm/mach-vt8500/gpio.c > new file mode 100644 > index 0000000..49daee6 > --- /dev/null > +++ b/arch/arm/mach-vt8500/gpio.c > @@ -0,0 +1,230 @@ > +/* linux/arch/arm/mach-vt8500/gpio.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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 > + > +#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip) > + > +static void __iomem *regbase; > + > +struct vt8500_gpio_chip { > + struct gpio_chip chip; > + unsigned int shift; > + unsigned int regoff; > +}; > + > +static int gpio_to_irq_map[8]; > + > +static int vt8500_muxed_gpio_request(struct gpio_chip *chip, > + unsigned offset) > +{ > + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); > + > + writel(readl(regbase + vt8500_chip->regoff) | > + (1 << vt8500_chip->shift << offset), > + regbase + vt8500_chip->regoff); This would be more readable as: unsigned val; val = readl(regbase + vt8500_chop->regoff); val |= 1 << vt8500_chop->shift << offset; writel(val, regbase + vt8500_chip->regoff); It's much clearer what is actually being done. Same goes for other functions in this file. > + > + return 0; > +} > + > +static void vt8500_muxed_gpio_free(struct gpio_chip *chip, > + unsigned offset) > +{ > + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); > + > + writel(readl(regbase + vt8500_chip->regoff) & > + ~(1 << vt8500_chip->shift << offset), > + regbase + vt8500_chip->regoff); > +} > + > +static int vt8500_muxed_gpio_direction_input(struct gpio_chip *chip, > + unsigned offset) > +{ > + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); > + > + writel(readl(regbase + 0x20 + vt8500_chip->regoff) & > + ~(1 << vt8500_chip->shift << offset), > + regbase + 0x20 + vt8500_chip->regoff); > + > + return 0; > +} > + > +static int vt8500_muxed_gpio_direction_output(struct gpio_chip *chip, > + unsigned offset, int value) > +{ > + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); > + > + writel(readl(regbase + 0x20 + vt8500_chip->regoff) | > + (1 << vt8500_chip->shift << offset), > + regbase + 0x20 + vt8500_chip->regoff); > + > + if (value) > + writel(readl(regbase + 0x40 + vt8500_chip->regoff) | > + (1 << vt8500_chip->shift << offset), > + regbase + 0x40 + vt8500_chip->regoff); > + return 0; > +} > + > +static int vt8500_muxed_gpio_get_value(struct gpio_chip *chip, > + unsigned offset) > +{ > + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); > + > + return (readl(regbase + 0x60 + vt8500_chip->regoff) > + >> vt8500_chip->shift >> offset) & 1; > +} > + > +static void vt8500_muxed_gpio_set_value(struct gpio_chip *chip, > + unsigned offset, int value) > +{ > + struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip); > + > + if (value) > + writel(readl(regbase + 0x40 + vt8500_chip->regoff) | > + (1 << vt8500_chip->shift << offset), > + regbase + 0x40 + vt8500_chip->regoff); > + else > + writel(readl(regbase + 0x40 + vt8500_chip->regoff) & > + ~(1 << vt8500_chip->shift << offset), > + regbase + 0x40 + vt8500_chip->regoff); > +} > + > +#define VT8500_GPIO_BANK(__name, __shift, __off, __base, __num) \ > +{ \ > + .chip = { \ > + .label = __name, \ > + .request = vt8500_muxed_gpio_request, \ > + .free = vt8500_muxed_gpio_free, \ > + .direction_input = vt8500_muxed_gpio_direction_input, \ > + .direction_output = vt8500_muxed_gpio_direction_output, \ > + .get = vt8500_muxed_gpio_get_value, \ > + .set = vt8500_muxed_gpio_set_value, \ > + .can_sleep = 0, \ > + .base = __base, \ > + .ngpio = __num, \ > + }, \ > + .shift = __shift, \ > + .regoff = __off, \ > +} > + > +static struct vt8500_gpio_chip vt8500_muxed_gpios[] = { > + VT8500_GPIO_BANK("uart0", 0, 0x0, 8, 4), > + VT8500_GPIO_BANK("uart1", 4, 0x0, 12, 4), > + VT8500_GPIO_BANK("spi0", 8, 0x0, 16, 4), > + VT8500_GPIO_BANK("spi1", 12, 0x0, 20, 4), > + VT8500_GPIO_BANK("spi2", 16, 0x0, 24, 4), > + VT8500_GPIO_BANK("pwmout", 24, 0x0, 28, 2), Nitpick: Line up the columns to make these mpore readable. > + > + VT8500_GPIO_BANK("sdmmc", 0, 0x4, 30, 11), > + VT8500_GPIO_BANK("ms", 16, 0x4, 41, 7), > + VT8500_GPIO_BANK("i2c0", 24, 0x4, 48, 2), > + VT8500_GPIO_BANK("i2c1", 26, 0x4, 50, 2), > + > + VT8500_GPIO_BANK("mii", 0, 0x8, 52, 20), > + VT8500_GPIO_BANK("see", 20, 0x8, 72, 4), > + VT8500_GPIO_BANK("ide", 24, 0x8, 76, 7), > + > + VT8500_GPIO_BANK("ccir", 0, 0xc, 83, 19), > + > + VT8500_GPIO_BANK("ts", 8, 0x10, 102, 11), > + > + VT8500_GPIO_BANK("lcd", 0, 0x14, 113, 23), > +}; > + > +static int vt8500_gpio_direction_input(struct gpio_chip *chip, > + unsigned offset) > +{ > + writel(readl(regbase + 0x3c) & ~(1 << offset), regbase + 0x3c); > + return 0; > +} > + > +static int vt8500_gpio_direction_output(struct gpio_chip *chip, > + unsigned offset, int value) > +{ > + writel(readl(regbase + 0x3c) | (1 << offset), regbase + 0x3c); > + > + if (value) > + writel(readl(regbase + 0x5c) | (1 << offset), > + regbase + 0x5c); > + return 0; > +} > + > +static int vt8500_gpio_get_value(struct gpio_chip *chip, > + unsigned offset) > +{ > + return (readl(regbase + 0x7c) >> offset) & 1; > +} > + > +static void vt8500_gpio_set_value(struct gpio_chip *chip, > + unsigned offset, int value) > +{ > + if (value) > + writel(readl(regbase + 0x5c) | (1 << offset), > + regbase + 0x5c); > + else > + writel(readl(regbase + 0x5c) & ~(1 << offset), > + regbase + 0x5c); > +} > + > +static int vt8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset) > +{ > + if (offset > 7) > + return -EINVAL; > + > + return gpio_to_irq_map[offset]; > +} > + > +static struct gpio_chip vt8500_external_gpios = { > + .label = "extgpio", > + .direction_input = vt8500_gpio_direction_input, > + .direction_output = vt8500_gpio_direction_output, > + .get = vt8500_gpio_get_value, > + .set = vt8500_gpio_set_value, > + .to_irq = vt8500_gpio_to_irq, > + .can_sleep = 0, > + .base = 0, > + .ngpio = 8, > +}; > + > +void __init vt8500_gpio_init(void) > +{ > + int i; > + > + gpio_to_irq_map[0] = wmt_current_irqs->ext0; > + gpio_to_irq_map[1] = wmt_current_irqs->ext1; > + gpio_to_irq_map[2] = wmt_current_irqs->ext2; > + gpio_to_irq_map[3] = wmt_current_irqs->ext3; > + gpio_to_irq_map[4] = wmt_current_irqs->ext4; > + gpio_to_irq_map[5] = wmt_current_irqs->ext5; > + gpio_to_irq_map[6] = wmt_current_irqs->ext6; > + gpio_to_irq_map[7] = wmt_current_irqs->ext7; > + > + regbase = ioremap(wmt_current_regs->gpio, SZ_64K); > + if (!regbase) { > + printk(KERN_ERR "Failed to map MMIO registers for GPIO\n"); > + return; > + } > + > + gpiochip_add(&vt8500_external_gpios); > + > + for (i = 0; i < ARRAY_SIZE(vt8500_muxed_gpios); i++) > + gpiochip_add(&vt8500_muxed_gpios[i].chip); > +} > diff --git a/arch/arm/mach-vt8500/include/mach/debug-macro.S b/arch/arm/mach-vt8500/include/mach/debug-macro.S > new file mode 100644 > index 0000000..f119162 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/debug-macro.S > @@ -0,0 +1,31 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/debug-macro.S > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * Debugging macro include header > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > +*/ > + > + .macro addruart, rp, rv > + mov \rp, #0x00200000 > + orr \rv, \rp, #0xf8000000 > + orr \rp, \rp, #0xd8000000 > + .endm > + > + .macro senduart,rd,rx > + strb \rd, [\rx, #0] > + .endm > + > + .macro busyuart,rd,rx > +1001: ldr \rd, [\rx, #0x1c] > + ands \rd, \rd, #0x2 > + bne 1001b > + .endm > + > + .macro waituart,rd,rx > + .endm > diff --git a/arch/arm/mach-vt8500/include/mach/entry-macro.S b/arch/arm/mach-vt8500/include/mach/entry-macro.S > new file mode 100644 > index 0000000..92684c7 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/entry-macro.S > @@ -0,0 +1,32 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/entry-macro.S > + * > + * Low-level IRQ helper macros for VIA VT8500 > + * > + * 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. > + */ > + > + .macro disable_fiq > + .endm > + > + .macro get_irqnr_preamble, base, tmp > + @ physical 0xd8140000 is virtual 0xf8140000 > + mov \base, #0xf8000000 > + orr \base, \base, #0x00140000 > + .endm > + > + .macro arch_ret_to_user, tmp1, tmp2 > + .endm > + > + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp > + ldr \irqnr, [\base] > + cmp \irqnr, #63 @ may be false positive, check interrupt status > + bne 1001f > + ldr \irqstat, [\base, #0x84] > + ands \irqstat, #0x80000000 > + moveq \irqnr, #0 > +1001: > + .endm > + > diff --git a/arch/arm/mach-vt8500/include/mach/gpio.h b/arch/arm/mach-vt8500/include/mach/gpio.h > new file mode 100644 > index 0000000..94ff276 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/gpio.h > @@ -0,0 +1,6 @@ > +#include > + > +#define gpio_get_value __gpio_get_value > +#define gpio_set_value __gpio_set_value > +#define gpio_cansleep __gpio_cansleep > +#define gpio_to_irq __gpio_to_irq > diff --git a/arch/arm/mach-vt8500/include/mach/hardware.h b/arch/arm/mach-vt8500/include/mach/hardware.h > new file mode 100644 > index 0000000..db4163f > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/hardware.h > @@ -0,0 +1,12 @@ > +/* arch/arm/mach-vt8500/include/mach/hardware.h > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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. > + * > + */ > diff --git a/arch/arm/mach-vt8500/include/mach/io.h b/arch/arm/mach-vt8500/include/mach/io.h > new file mode 100644 > index 0000000..8dd55c8 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/io.h > @@ -0,0 +1,28 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/io.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + */ > +#ifndef __ASM_ARM_ARCH_IO_H > +#define __ASM_ARM_ARCH_IO_H > + > +#define IO_SPACE_LIMIT 0xffff > + > +#define __io(a) ((void __iomem *)((a) + 0xf0000000)) Should use __typesafe_io. > +#define __mem_pci(a) (a) > + > +#endif > diff --git a/arch/arm/mach-vt8500/include/mach/irq_defs.h b/arch/arm/mach-vt8500/include/mach/irq_defs.h > new file mode 100644 > index 0000000..fa8f4b3 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/irq_defs.h > @@ -0,0 +1,124 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/irq_defs.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + */ > +#ifndef VT8500_IRQ_DEFS_H > +#define VT8500_IRQ_DEFS_H > + > +#include > + > +struct wmt_irq_srcs { > + u8 nr_irqs; > + u8 jpegenc; > + u8 jpegdec; > + u8 pata; > + u8 dma; > + u8 ext0; > + u8 ext1; > + u8 ext2; > + u8 ext3; > + u8 ext4; > + u8 ext5; > + u8 ext6; > + u8 ext7; > + u8 ether; > + u8 mpegts; > + u8 ge; > + u8 gov; > + u8 lcdc; > + u8 lcdf; > + u8 vpp; > + u8 vpu; > + u8 vid; > + u8 spu; > + u8 pip; > + u8 dvo; > + u8 govw; > + u8 govrsdscd; > + u8 govrsdmif; > + u8 govrhdscd; > + u8 govrhdmif; > + u8 cipher; > + u8 i2c0; > + u8 i2c1; > + u8 sdmmc; > + u8 sdmmc_dma; > + u8 pmc_wu; > + u8 spi0; > + u8 spi1; > + u8 spi2; > + u8 nand; > + u8 nand_dma; > + u8 nor; > + u8 memstick; > + u8 memstick_dma; > + u8 uart0; > + u8 uart1; > + u8 uart2; > + u8 uart3; > + u8 uart4; > + u8 uart5; > + u8 i2s; > + u8 pcm; > + u8 ac97; > + u8 timer_match0; > + u8 timer_match1; > + u8 timer_match2; > + u8 timer_match3; > + u8 ehci; > + u8 uhci; > + u8 udc; > + u8 udc_dma; > + u8 keypad; > + u8 ps2mouse; > + u8 ps2kbd; > + u8 rtc; > + u8 rtc_hz; > + u8 adc; > + u8 cir; > + u8 dma0; > + u8 dma1; > + u8 dma2; > + u8 dma3; > + u8 dma4; > + u8 dma5; > + u8 dma6; > + u8 dma7; > + u8 dma8; > + u8 dma9; > + u8 dma10; > + u8 dma11; > + u8 dma12; > + u8 dma13; > + u8 dma14; > + u8 dma15; > + u8 irq0; > + u8 irq1; > + u8 irq2; > + u8 irq3; > + u8 irq4; > + u8 irq5; > + u8 irq6; > + u8 irq7; > + u8 sae; > +}; > + > +extern struct wmt_irq_srcs wmt_irqs[] __initdata; > +extern struct wmt_irq_srcs *wmt_current_irqs __initdata; > + > +#endif > diff --git a/arch/arm/mach-vt8500/include/mach/irqs.h b/arch/arm/mach-vt8500/include/mach/irqs.h > new file mode 100644 > index 0000000..a129fd1 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/irqs.h > @@ -0,0 +1,22 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/irqs.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + */ > + > +/* This value is just to make the core happy, never used otherwise */ > +#define NR_IRQS 128 > diff --git a/arch/arm/mach-vt8500/include/mach/memory.h b/arch/arm/mach-vt8500/include/mach/memory.h > new file mode 100644 > index 0000000..175f914 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/memory.h > @@ -0,0 +1,28 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/memory.h > + * > + * Copyright (C) 2003 ARM Limited > + * > + * 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 > + */ > +#ifndef __ASM_ARCH_MEMORY_H > +#define __ASM_ARCH_MEMORY_H > + > +/* > + * Physical DRAM offset. > + */ > +#define PHYS_OFFSET UL(0x00000000) If you renamed this to PHYS_DRAM_OFFSET you wouldn't need the comment :-). > + > +#endif > diff --git a/arch/arm/mach-vt8500/include/mach/mmio_regs.h b/arch/arm/mach-vt8500/include/mach/mmio_regs.h > new file mode 100644 > index 0000000..76439dd > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/mmio_regs.h > @@ -0,0 +1,90 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/mmio_regs.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + */ > +#ifndef __ASM_ARM_ARCH_MMIO_REGS_H > +#define __ASM_ARM_ARCH_MMIO_REGS_H > + > +#include > + > +struct wmt_mmio_regs { > + unsigned long mmio_regs_start; > + unsigned long mmio_regs_length; > + unsigned long mmio_regs_virt; > + unsigned long ddr; > + unsigned long dma; > + unsigned long vdma; > + unsigned long sflash; > + unsigned long ether; > + unsigned long cipher; > + unsigned long ehci; > + unsigned long uhci; > + unsigned long pata; > + unsigned long ps2; > + unsigned long nand; > + unsigned long nor; > + unsigned long sdmmc; > + unsigned long memstick; > + unsigned long lcdc; > + unsigned long vpu; > + unsigned long gov; > + unsigned long ge; > + unsigned long govr; > + unsigned long scl; > + unsigned long lcdf; > + unsigned long vid; > + unsigned long vpp; > + unsigned long tsbk; > + unsigned long jpegdec; > + unsigned long jpegenc; > + unsigned long rtc; > + unsigned long gpio; > + unsigned long scc; > + unsigned long pmc; > + unsigned long ic0; > + unsigned long ic1; > + unsigned long uart0; > + unsigned long uart1; > + unsigned long uart2; > + unsigned long uart3; > + unsigned long uart4; > + unsigned long uart5; > + unsigned long pwm; > + unsigned long spi0; > + unsigned long spi1; > + unsigned long spi2; > + unsigned long cir; > + unsigned long i2c0; > + unsigned long i2c1; > + unsigned long ac97; > + unsigned long pcm; > + unsigned long i2s; > + unsigned long adc; > + unsigned long keypad; > +}; > + > +enum { > + VT8500_INDEX, > + WM8505_INDEX, > +}; > + > +extern struct wmt_mmio_regs wmt_regmaps[] __initdata; > +extern struct wmt_mmio_regs *wmt_current_regs __initdata; > + > +#endif > + > diff --git a/arch/arm/mach-vt8500/include/mach/system.h b/arch/arm/mach-vt8500/include/mach/system.h > new file mode 100644 > index 0000000..d6c757e > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/system.h > @@ -0,0 +1,18 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/system.h > + * > + */ > +#include > + > +/* PM Software Reset request register */ > +#define VT8500_PMSR_VIRT 0xf8130060 > + > +static inline void arch_idle(void) > +{ > + cpu_do_idle(); > +} > + > +static inline void arch_reset(char mode, const char *cmd) > +{ > + writel(1, VT8500_PMSR_VIRT); > +} > diff --git a/arch/arm/mach-vt8500/include/mach/timex.h b/arch/arm/mach-vt8500/include/mach/timex.h > new file mode 100644 > index 0000000..8487e4c > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/timex.h > @@ -0,0 +1,26 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/timex.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + */ > + > +#ifndef MACH_TIMEX_H > +#define MACH_TIMEX_H > + > +#define CLOCK_TICK_RATE (3000000) > + > +#endif /* MACH_TIMEX_H */ > diff --git a/arch/arm/mach-vt8500/include/mach/uncompress.h b/arch/arm/mach-vt8500/include/mach/uncompress.h > new file mode 100644 > index 0000000..bb9e2d2 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/uncompress.h > @@ -0,0 +1,37 @@ > +/* arch/arm/mach-vt8500/include/mach/uncompress.h > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * Based on arch/arm/mach-dove/include/mach/uncompress.h > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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. > + * > + */ > + > +#define UART0_PHYS 0xd8200000 > +#include > + > +static void putc(const char c) > +{ > + while (readb(UART0_PHYS + 0x1c) & 0x2) > + /* Tx busy, wait and poll */; > + > + writeb(c, UART0_PHYS); > +} > + > +static void flush(void) > +{ > +} > + > +/* > + * nothing to do > + */ > +#define arch_decomp_setup() > +#define arch_decomp_wdog() > diff --git a/arch/arm/mach-vt8500/include/mach/vmalloc.h b/arch/arm/mach-vt8500/include/mach/vmalloc.h > new file mode 100644 > index 0000000..4642290 > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/vmalloc.h > @@ -0,0 +1,20 @@ > +/* > + * arch/arm/mach-vt8500/include/mach/vmalloc.h > + * > + * Copyright (C) 2000 Russell King. > + * > + * 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 > + */ > +#define VMALLOC_END 0xd0000000UL > diff --git a/arch/arm/mach-vt8500/include/mach/vt8500fb.h b/arch/arm/mach-vt8500/include/mach/vt8500fb.h > new file mode 100644 > index 0000000..cc7f25e > --- /dev/null > +++ b/arch/arm/mach-vt8500/include/mach/vt8500fb.h > @@ -0,0 +1,31 @@ > +/* > + * VT8500/WM8505 Frame Buffer platform data definitions > + * > + * Copyright (C) 2010 Ed Spiridonov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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. > + */ > + > +#ifndef _VT8500FB_H > +#define _VT8500FB_H > + > +#include > + > +struct vt8500fb_platform_data { > + struct fb_videomode mode; > + __u32 xres_virtual; > + __u32 yres_virtual; > + __u32 bpp; Is this struct exported to user space? If not, use u32 rather than __u32. > + unsigned long video_mem_phys; > + void *video_mem_virt; > + unsigned long video_mem_len; > +}; > + > +#endif /* _VT8500FB_H */ > diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c > new file mode 100644 > index 0000000..c042e85 > --- /dev/null > +++ b/arch/arm/mach-vt8500/irq.c > @@ -0,0 +1,179 @@ > +/* > + * arch/arm/mach-vt8500/irq.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + > +#define VT8500_IC_DCTR 0x40 /* Destination control > + register, 64*u8 */ > +#define VT8500_INT_ENABLE (1 << 3) > +#define VT8500_TRIGGER_HIGH (0 << 4) > +#define VT8500_TRIGGER_RISING (1 << 4) > +#define VT8500_TRIGGER_FALLING (2 << 4) > +#define VT8500_IC_STATUS 0x80 /* Interrupt status, 2*u32 */ > + > +static void __iomem *ic_regbase; > +static void __iomem *sic_regbase; > + > +static void vt8500_irq_mask(unsigned int irq) > +{ > + void __iomem *base = ic_regbase; > + u8 edge; Nitpick: blank line between variable declarations and code. > + if (irq >= 64) { > + base = sic_regbase; > + irq -= 64; > + } > + edge = readb(base + VT8500_IC_DCTR + irq) & (3 << 4); What is (3 << 4)? Replace with a #define. > + if (edge) > + writel(readl(base > + + VT8500_IC_STATUS + (irq < 32 ? 0 : 4)) > + | (1 << (irq & 0x1f)), base > + + VT8500_IC_STATUS + (irq & 0x20 ? 4 : 0)); More unexplained magic numbers. > + else > + writeb(readb(base > + + VT8500_IC_DCTR + irq) & ~VT8500_INT_ENABLE, > + base + VT8500_IC_DCTR + irq); > +} > + > +static void vt8500_irq_unmask(unsigned int irq) > +{ > + void __iomem *base = ic_regbase; > + if (irq >= 64) { > + base = sic_regbase; > + irq -= 64; > + } > + writeb(readb(base > + + VT8500_IC_DCTR + irq) | VT8500_INT_ENABLE, > + base + VT8500_IC_DCTR + irq); > +} > + > +static int vt8500_irq_set_wake(unsigned int irq, unsigned int on) > +{ > + return -EINVAL; > +} You don't have to provide this function. > +static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type) > +{ > + void __iomem *base = ic_regbase; > + unsigned int orig_irq = irq; > + if (irq >= 64) { > + base = sic_regbase; > + irq -= 64; > + } > + switch (flow_type) { > + case IRQF_TRIGGER_LOW: > + return -EINVAL; > + case IRQF_TRIGGER_HIGH: > + writeb((readb(base > + + VT8500_IC_DCTR + irq) & ~(3 << 4)) > + | VT8500_TRIGGER_HIGH, base > + + VT8500_IC_DCTR + irq); > + irq_desc[orig_irq].handle_irq = handle_level_irq; > + break; > + case IRQF_TRIGGER_FALLING: > + writeb((readb(base > + + VT8500_IC_DCTR + irq) & ~(3 << 4)) > + | VT8500_TRIGGER_FALLING, base > + + VT8500_IC_DCTR + irq); > + irq_desc[orig_irq].handle_irq = handle_edge_irq; > + break; > + case IRQF_TRIGGER_RISING: > + writeb((readb(base > + + VT8500_IC_DCTR + irq) & ~(3 << 4)) > + | VT8500_TRIGGER_RISING, base > + + VT8500_IC_DCTR + irq); > + irq_desc[orig_irq].handle_irq = handle_edge_irq; > + break; > + } > + > + return 0; > +} > + > +static struct irq_chip vt8500_irq_chip = { > + .name = "vt8500", > + .ack = vt8500_irq_mask, > + .mask = vt8500_irq_mask, > + .unmask = vt8500_irq_unmask, > + .set_wake = vt8500_irq_set_wake, Remove .set_wake. > + .set_type = vt8500_irq_set_type, > +}; > + > +void __init vt8500_init_irq(void) > +{ > + unsigned int i; > + > + ic_regbase = ioremap(wmt_current_regs->ic0, SZ_64K); > + > + if (ic_regbase) { > + /* Enable rotating priority for IRQ */ > + writel((1 << 6), ic_regbase + 0x20); > + writel(0, ic_regbase + 0x24); > + > + for (i = 0; i < wmt_current_irqs->nr_irqs; i++) { > + /* Disable all interrupts and route them to IRQ */ > + writeb(0x00, ic_regbase + VT8500_IC_DCTR + i); > + > + set_irq_chip(i, &vt8500_irq_chip); > + set_irq_handler(i, handle_level_irq); > + set_irq_flags(i, IRQF_VALID); > + } > + } else { > + printk(KERN_ERR "Unable to remap the Interrupt Controller " > + "registers, not enabling IRQs!\n"); printk strings should be on a single line (can be > 80 columns) to make grepping easier. You could also use the pr_ macros with pr_fmt set. > + } > +} > + > +void __init wm8505_init_irq(void) > +{ > + unsigned int i; > + > + ic_regbase = ioremap(wmt_current_regs->ic0, SZ_64K); > + sic_regbase = ioremap(wmt_current_regs->ic1, SZ_64K); > + > + if (ic_regbase && sic_regbase) { > + /* Enable rotating priority for IRQ */ > + writel((1 << 6), ic_regbase + 0x20); > + writel(0, ic_regbase + 0x24); > + writel((1 << 6), sic_regbase + 0x20); > + writel(0, sic_regbase + 0x24); > + > + for (i = 0; i < wmt_current_irqs->nr_irqs; i++) { > + /* Disable all interrupts and route them to IRQ */ > + if (i < 64) > + writeb(0x00, ic_regbase + VT8500_IC_DCTR + i); > + else > + writeb(0x00, sic_regbase + VT8500_IC_DCTR > + + i - 64); > + > + set_irq_chip(i, &vt8500_irq_chip); > + set_irq_handler(i, handle_level_irq); > + set_irq_flags(i, IRQF_VALID); > + } > + } else { > + printk(KERN_ERR "Unable to remap the Interrupt Controller " > + "registers, not enabling IRQs!\n"); > + } > +} > diff --git a/arch/arm/mach-vt8500/irq_defs.c b/arch/arm/mach-vt8500/irq_defs.c > new file mode 100644 > index 0000000..b338c04 > --- /dev/null > +++ b/arch/arm/mach-vt8500/irq_defs.c > @@ -0,0 +1,173 @@ > +/* linux/arch/arm/mach-vt8500/irq_defs.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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 > + > +struct wmt_irq_srcs *wmt_current_irqs __initdata; > + > +struct wmt_irq_srcs wmt_irqs[] __initdata = { > + [VT8500_INDEX] = { > + .jpegenc = 0, > + .jpegdec = 1, > + .pata = 3, > + .dma = 5, > + .ext0 = 6, > + .ext1 = 7, > + .ge = 8, > + .gov = 9, > + .ether = 10, > + .mpegts = 11, > + .lcdc = 12, > + .ext2 = 13, > + .ext3 = 14, > + .ext4 = 15, > + .cipher = 16, > + .vpp = 17, > + .i2c1 = 18, > + .i2c0 = 19, > + .sdmmc = 20, > + .sdmmc_dma = 21, > + .pmc_wu = 22, > + .spi0 = 24, > + .spi1 = 25, > + .spi2 = 26, > + .lcdf = 27, > + .nand = 28, > + .nand_dma = 29, > + .memstick = 30, > + .memstick_dma = 31, > + .uart0 = 32, > + .uart1 = 33, > + .i2s = 34, > + .pcm = 35, > + .timer_match0 = 36, > + .timer_match1 = 37, > + .timer_match2 = 38, > + .timer_match3 = 39, > + .vpu = 40, > + .vid = 41, > + .ac97 = 42, > + .ehci = 43, > + .nor = 44, > + .ps2mouse = 45, > + .ps2kbd = 46, > + .uart2 = 47, > + .rtc = 48, > + .rtc_hz = 49, > + .uart3 = 50, > + .adc = 51, > + .ext5 = 52, > + .ext6 = 53, > + .ext7 = 54, > + .cir = 55, > + .dma0 = 56, > + .dma1 = 57, > + .dma2 = 58, > + .dma3 = 59, > + .dma4 = 60, > + .dma5 = 61, > + .dma6 = 62, > + .dma7 = 63, > + .nr_irqs = 64, > + }, > + [WM8505_INDEX] = { > + .uhci = 0, > + .ehci = 1, > + .udc_dma = 2, > + .ps2mouse = 4, > + .udc = 5, > + .ext0 = 6, > + .ext1 = 7, > + .keypad = 8, > + .dma = 9, > + .ether = 10, > + .ext2 = 13, > + .ext3 = 14, > + .ext4 = 15, > + .dma0 = 17, > + .i2c1 = 18, > + .i2c0 = 19, > + .sdmmc = 20, > + .sdmmc_dma = 21, > + .pmc_wu = 22, > + .ps2kbd = 23, > + .spi0 = 24, > + .spi1 = 25, > + .spi2 = 26, > + .dma1 = 27, > + .nand = 28, > + .nand_dma = 29, > + .uart5 = 30, > + .uart4 = 31, > + .uart0 = 32, > + .uart1 = 33, > + .dma2 = 34, > + .i2s = 35, > + .timer_match0 = 36, > + .timer_match1 = 37, > + .timer_match2 = 38, > + .timer_match3 = 39, > + .dma3 = 40, > + .dma4 = 41, > + .ac97 = 42, > + .nor = 44, > + .dma5 = 45, > + .dma6 = 46, > + .uart2 = 47, > + .rtc = 48, > + .rtc_hz = 49, > + .uart3 = 50, > + .dma7 = 51, > + .ext5 = 52, > + .ext6 = 53, > + .ext7 = 54, > + .cir = 55, > + .irq0 = 56, > + .irq1 = 57, > + .irq2 = 58, > + .irq3 = 59, > + .irq4 = 60, > + .irq5 = 61, > + .irq6 = 62, > + .irq7 = 63, > + .jpegdec = 65, > + .sae = 66, > + .vpu = 79, > + .vpp = 80, > + .vid = 81, > + .spu = 82, > + .pip = 83, > + .ge = 84, > + .gov = 85, > + .dvo = 86, > + .dma8 = 92, > + .dma9 = 93, > + .dma10 = 94, > + .dma11 = 95, > + .dma12 = 96, > + .dma13 = 97, > + .dma14 = 98, > + .dma15 = 99, > + .govw = 111, > + .govrsdscd = 112, > + .govrsdmif = 113, > + .govrhdscd = 114, > + .govrhdmif = 115, > + .nr_irqs = 116, > + }, > +}; > diff --git a/arch/arm/mach-vt8500/mmio_regs.c b/arch/arm/mach-vt8500/mmio_regs.c > new file mode 100644 > index 0000000..e9b3264 > --- /dev/null > +++ b/arch/arm/mach-vt8500/mmio_regs.c > @@ -0,0 +1,118 @@ > +/* linux/arch/arm/mach-vt8500/mmio_regs.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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 > + > +struct wmt_mmio_regs *wmt_current_regs __initdata; > + > +struct wmt_mmio_regs wmt_regmaps[] __initdata = { > + [VT8500_INDEX] = { > + .mmio_regs_start = 0xd8000000, > + .mmio_regs_length = 0x00350000, > + .mmio_regs_virt = 0xf8000000, > + .ddr = 0xd8000000, > + .dma = 0xd8001000, > + .sflash = 0xd8002000, > + .ether = 0xd8004000, > + .cipher = 0xd8006000, > + .ehci = 0xd8007900, > + .uhci = 0xd8007b01, > + .pata = 0xd8008000, > + .ps2 = 0xd8008800, > + .nand = 0xd8009000, > + .nor = 0xd8009400, > + .sdmmc = 0xd800a000, > + .memstick = 0xd800b400, > + .lcdc = 0xd800e400, > + .vpu = 0xd8050000, > + .gov = 0xd8050300, > + .ge = 0xd8050400, > + .lcdf = 0xd8050900, > + .vid = 0xd8050a00, > + .vpp = 0xd8050b00, > + .tsbk = 0xd80f4000, > + .jpegdec = 0xd80fe000, > + .jpegenc = 0xd80ff000, > + .rtc = 0xd8100000, > + .gpio = 0xd8110000, > + .scc = 0xd8120000, > + .pmc = 0xd8130000, > + .ic0 = 0xd8140000, > + .uart0 = 0xd8200000, > + .uart2 = 0xd8210000, > + .pwm = 0xd8220000, > + .spi0 = 0xd8240000, > + .spi1 = 0xd8250000, > + .cir = 0xd8270000, > + .i2c0 = 0xd8280000, > + .ac97 = 0xd8290000, > + .spi2 = 0xd82a0000, > + .uart1 = 0xd82b0000, > + .uart3 = 0xd82c0000, > + .pcm = 0xd82d0000, > + .i2c1 = 0xd8320000, > + .i2s = 0xd8330000, > + .adc = 0xd8340000, > + }, > + [WM8505_INDEX] = { > + .mmio_regs_start = 0xd8000000, > + .mmio_regs_length = 0x00390000, > + .mmio_regs_virt = 0xf8000000, > + .ddr = 0xd8000400, > + .dma = 0xd8001800, > + .vdma = 0xd8001c00, > + .sflash = 0xd8002000, > + .ether = 0xd8004000, > + .cipher = 0xd8006000, > + .ehci = 0xd8007100, > + .uhci = 0xd8007301, > + .ps2 = 0xd8008800, > + .nand = 0xd8009000, > + .nor = 0xd8009400, > + .sdmmc = 0xd800a000, > + .vpu = 0xd8050000, > + .gov = 0xd8050300, > + .ge = 0xd8050400, > + .govr = 0xd8050800, > + .vid = 0xd8050a00, > + .scl = 0xd8050d00, > + .vpp = 0xd8050f00, > + .jpegdec = 0xd80fe000, > + .rtc = 0xd8100000, > + .gpio = 0xd8110000, > + .scc = 0xd8120000, > + .pmc = 0xd8130000, > + .ic0 = 0xd8140000, > + .ic1 = 0xd8150000, > + .uart0 = 0xd8200000, > + .uart2 = 0xd8210000, > + .pwm = 0xd8220000, > + .spi0 = 0xd8240000, > + .spi1 = 0xd8250000, > + .keypad = 0xd8260000, > + .cir = 0xd8270000, > + .i2c0 = 0xd8280000, > + .ac97 = 0xd8290000, > + .spi2 = 0xd82a0000, > + .uart1 = 0xd82b0000, > + .uart3 = 0xd82c0000, > + .i2c1 = 0xd8320000, > + .i2s = 0xd8330000, > + .uart4 = 0xd8370000, > + .uart5 = 0xd8380000, > + }, > +}; > diff --git a/arch/arm/mach-vt8500/pwm.c b/arch/arm/mach-vt8500/pwm.c > new file mode 100644 > index 0000000..d1356a1 > --- /dev/null > +++ b/arch/arm/mach-vt8500/pwm.c I'm not sure what the state of the various efforts to provide a common pwm framework are, but you may want to check. > @@ -0,0 +1,254 @@ > +/* > + * arch/arm/mach-vt8500/pwm.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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 > + > +#define VT8500_NR_PWMS 4 > + > +struct pwm_device { > + struct list_head node; > + struct platform_device *pdev; > + > + const char *label; > + > + void __iomem *regbase; > + > + unsigned int use_count; > + unsigned int pwm_id; > +}; > + > +static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask) > +{ > + int loops = 1000; > + while ((readb(reg) & bitmask) && --loops) > + cpu_relax(); Ugh. If you are going to busy wait, can't you delay for a known amount of time? Even better, can this be replaced with wait_event or some equivalent? > +} > + > +int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) > +{ > + unsigned long long c; > + unsigned long period_cycles, prescale, pv, dc; > + > + if (pwm == NULL || period_ns == 0 || duty_ns > period_ns) > + return -EINVAL; > + > + c = 25000000/2; /* wild guess --- need to implement clocks */ > + c = c * period_ns; > + do_div(c, 1000000000); > + period_cycles = c; This looks like it could be reworked to remove the do_div call. > + > + if (period_cycles < 1) > + period_cycles = 1; > + prescale = (period_cycles - 1) / 4096; > + pv = period_cycles / (prescale + 1) - 1; > + if (pv > 4095) > + pv = 4095; > + > + if (prescale > 1023) > + return -EINVAL; > + > + dc = pv * duty_ns / period_ns; > + > + pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 1)); > + writel(prescale, pwm->regbase + 0x4 + (pwm->pwm_id << 4)); > + > + pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 2)); > + writel(pv, pwm->regbase + 0x8 + (pwm->pwm_id << 4)); > + > + pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 3)); > + writel(dc, pwm->regbase + 0xc + (pwm->pwm_id << 4)); > + > + return 0; > +} > +EXPORT_SYMBOL(pwm_config); > + > +int pwm_enable(struct pwm_device *pwm) > +{ > + pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); > + writel(5, pwm->regbase + (pwm->pwm_id << 4)); > + return 0; > +} > +EXPORT_SYMBOL(pwm_enable); > + > +void pwm_disable(struct pwm_device *pwm) > +{ > + pwm_busy_wait(pwm->regbase + 0x40 + pwm->pwm_id, (1 << 0)); > + writel(0, pwm->regbase + (pwm->pwm_id << 4)); > +} > +EXPORT_SYMBOL(pwm_disable); > + > +static DEFINE_MUTEX(pwm_lock); > +static LIST_HEAD(pwm_list); These should be at the top of the file. > +struct pwm_device *pwm_request(int pwm_id, const char *label) > +{ > + struct pwm_device *pwm; > + int found = 0; > + > + mutex_lock(&pwm_lock); > + > + list_for_each_entry(pwm, &pwm_list, node) { > + if (pwm->pwm_id == pwm_id) { > + found = 1; > + break; > + } > + } > + > + if (found) { > + if (pwm->use_count == 0) { > + pwm->use_count++; > + pwm->label = label; > + } else > + pwm = ERR_PTR(-EBUSY); > + } else > + pwm = ERR_PTR(-ENOENT); > + > + mutex_unlock(&pwm_lock); > + return pwm; > +} Maybe a bit clearer and more concise like this? Also replaces -ENOENT (No such file or directory) with -ENODEV (No such device): pwm = ERR_PTR(-ENODEV); mutex_lock(&pwm_lock); list_for_each_entry(pwm, &pwm_list, node) { if (pwm->pwm_id == pwm_id) { if (pwm->use_count != 0) { pwm = ERR_PTR(-EBUSY); break; } pwm->use_count++; pwm->label = label; break; } } mutex_unlock(&pwm_lock); return pwm; > +EXPORT_SYMBOL(pwm_request); > + > +void pwm_free(struct pwm_device *pwm) > +{ > + mutex_lock(&pwm_lock); > + > + if (pwm->use_count) { > + pwm->use_count--; > + pwm->label = NULL; > + } else > + pr_warning("PWM device already freed\n"); > + Nitpick: Single line else should have braces if the if has braces > + mutex_unlock(&pwm_lock); > +} > +EXPORT_SYMBOL(pwm_free); > + > +static inline void __add_pwm(struct pwm_device *pwm) > +{ > + mutex_lock(&pwm_lock); > + list_add_tail(&pwm->node, &pwm_list); > + mutex_unlock(&pwm_lock); > +} > + > +static int __devinit pwm_probe(struct platform_device *pdev) > +{ > + struct pwm_device *pwms; > + struct resource *r; > + int ret = 0; > + int i; > + > + pwms = kzalloc(sizeof(struct pwm_device) * VT8500_NR_PWMS, GFP_KERNEL); > + if (pwms == NULL) { > + dev_err(&pdev->dev, "failed to allocate memory\n"); > + return -ENOMEM; > + } Devices should ideally be a single entity, so one platform device per pwm. > + > + for (i = 0; i < VT8500_NR_PWMS; i++) { > + pwms[i].use_count = 0; > + pwms[i].pwm_id = i; > + pwms[i].pdev = pdev; > + } > + > + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (r == NULL) { > + dev_err(&pdev->dev, "no memory resource defined\n"); > + ret = -ENODEV; > + goto err_free; > + } > + > + r = request_mem_region(r->start, resource_size(r), pdev->name); > + if (r == NULL) { > + dev_err(&pdev->dev, "failed to request memory resource\n"); > + ret = -EBUSY; > + goto err_free; > + } > + > + pwms[0].regbase = ioremap(r->start, resource_size(r)); > + if (pwms[0].regbase == NULL) { > + dev_err(&pdev->dev, "failed to ioremap() registers\n"); > + ret = -ENODEV; > + goto err_free_mem; > + } > + > + for (i = 1; i < VT8500_NR_PWMS; i++) > + pwms[i].regbase = pwms[0].regbase; > + > + for (i = 0; i < VT8500_NR_PWMS; i++) > + __add_pwm(&pwms[i]); > + > + platform_set_drvdata(pdev, pwms); > + return 0; > + > +err_free_mem: > + release_mem_region(r->start, resource_size(r)); > +err_free: > + kfree(pwms); > + return ret; > +} > + > +static int __devexit pwm_remove(struct platform_device *pdev) > +{ > + struct pwm_device *pwms; > + struct resource *r; > + int i; > + > + pwms = platform_get_drvdata(pdev); > + if (pwms == NULL) > + return -ENODEV; > + > + mutex_lock(&pwm_lock); > + > + for (i = 0; i < VT8500_NR_PWMS; i++) > + list_del(&pwms[i].node); > + mutex_unlock(&pwm_lock); > + > + iounmap(pwms[0].regbase); > + > + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + release_mem_region(r->start, resource_size(r)); > + > + kfree(pwms); > + return 0; > +} > + > +static struct platform_driver pwm_driver = { > + .driver = { > + .name = "vt8500-pwm", > + .owner = THIS_MODULE, > + }, > + .probe = pwm_probe, > + .remove = __devexit_p(pwm_remove), > +}; > + > +static int __init pwm_init(void) > +{ > + return platform_driver_register(&pwm_driver); > +} > +arch_initcall(pwm_init); > + > +static void __exit pwm_exit(void) > +{ > + platform_driver_unregister(&pwm_driver); > +} > +module_exit(pwm_exit); > + > +MODULE_LICENSE("GPL"); > diff --git a/arch/arm/mach-vt8500/timer.c b/arch/arm/mach-vt8500/timer.c > new file mode 100644 > index 0000000..ab4f7aa > --- /dev/null > +++ b/arch/arm/mach-vt8500/timer.c > @@ -0,0 +1,154 @@ > +/* > + * arch/arm/mach-vt8500/timer.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 > + > +#define VT8500_TIMER_OFFSET 0x0100 > +#define TIMER_MATCH_VAL 0x0000 > +#define TIMER_COUNT_VAL 0x0010 > +#define TIMER_STATUS_VAL 0x0014 > +#define TIMER_IER_VAL 0x001c /* interrupt enable */ > +#define TIMER_CTRL_VAL 0x0020 > +#define TIMER_AS_VAL 0x0024 /* access status */ > +#define TIMER_COUNT_R_ACTIVE (1 << 5) /* not ready for read */ > +#define TIMER_COUNT_W_ACTIVE (1 << 4) /* not ready for write */ > +#define TIMER_MATCH_W_ACTIVE (1 << 0) /* not ready for write */ > +#define VT8500_TIMER_HZ 3000000 > + > +static void __iomem *regbase; > + > +static cycle_t vt8500_timer_read(struct clocksource *cs) > +{ > + int loops = 1000; > + writel(3, regbase + TIMER_CTRL_VAL); > + while ((readl((regbase + TIMER_AS_VAL)) & TIMER_COUNT_R_ACTIVE) > + && --loops) > + cpu_relax(); More loop counting? Surely there is a better solution? > + return readl(regbase + TIMER_COUNT_VAL); > +} > + > +struct clocksource clocksource = { > + .name = "vt8500_timer", > + .rating = 200, > + .read = vt8500_timer_read, > + .mask = CLOCKSOURCE_MASK(32), > + .flags = CLOCK_SOURCE_IS_CONTINUOUS, > +}; > + > +static int vt8500_timer_set_next_event(unsigned long cycles, > + struct clock_event_device *evt) > +{ > + int loops = 1000; > + cycle_t alarm = clocksource.read(&clocksource) + cycles; > + while ((readl(regbase + TIMER_AS_VAL) & TIMER_MATCH_W_ACTIVE) > + && --loops) > + cpu_relax(); > + writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); > + > + if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) > + return -ETIME; > + > + writel(1, regbase + TIMER_IER_VAL); > + > + return 0; > +} > + > +static void vt8500_timer_set_mode(enum clock_event_mode mode, > + struct clock_event_device *evt) > +{ > + switch (mode) { > + case CLOCK_EVT_MODE_RESUME: > + case CLOCK_EVT_MODE_PERIODIC: > + break; > + case CLOCK_EVT_MODE_ONESHOT: > + case CLOCK_EVT_MODE_UNUSED: > + case CLOCK_EVT_MODE_SHUTDOWN: > + writel(readl(regbase + TIMER_CTRL_VAL) | 1, > + regbase + TIMER_CTRL_VAL); > + writel(0, regbase + TIMER_IER_VAL); > + break; > + } > +} > + > +struct clock_event_device clockevent = { > + .name = "vt8500_timer", > + .features = CLOCK_EVT_FEAT_ONESHOT, > + .rating = 200, > + .set_next_event = vt8500_timer_set_next_event, > + .set_mode = vt8500_timer_set_mode, > +}; > + > +static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) > +{ > + struct clock_event_device *evt = dev_id; > + writel(0xf, regbase + TIMER_STATUS_VAL); > + evt->event_handler(evt); > + > + return IRQ_HANDLED; > +} > + > +struct irqaction irq = { > + .name = "vt8500_timer", > + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, > + .handler = vt8500_timer_interrupt, > + .dev_id = &clockevent, > +}; > + > +static void __init vt8500_timer_init(void) > +{ > + regbase = ioremap(wmt_current_regs->pmc + VT8500_TIMER_OFFSET, 0x28); > + if (!regbase) > + printk(KERN_ERR "vt8500_timer_init: failed to map MMIO " > + "registers\n"); > + > + writel(1, regbase + TIMER_CTRL_VAL); > + writel(0xf, regbase + TIMER_STATUS_VAL); > + writel(~0, regbase + TIMER_MATCH_VAL); > + > + if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ)) > + printk(KERN_ERR "vt8500_timer_init: clocksource_register " > + "failed for %s\n", clocksource.name); > + > + clockevents_calc_mult_shift(&clockevent, VT8500_TIMER_HZ, 4); > + > + /* copy-pasted from mach-msm; no idea */ > + clockevent.max_delta_ns = > + clockevent_delta2ns(0xf0000000, &clockevent); > + clockevent.min_delta_ns = clockevent_delta2ns(4, &clockevent); > + clockevent.cpumask = cpumask_of(0); > + > + if (setup_irq(wmt_current_irqs->timer_match0, &irq)) > + printk(KERN_ERR "vt8500_timer_init: setup_irq " > + "failed for %s\n", clockevent.name); > + clockevents_register_device(&clockevent); > +} > + > +struct sys_timer vt8500_timer = { > + .init = vt8500_timer_init > +}; > diff --git a/arch/arm/mach-vt8500/wm8505_7in.c b/arch/arm/mach-vt8500/wm8505_7in.c > new file mode 100644 > index 0000000..181ad6f > --- /dev/null > +++ b/arch/arm/mach-vt8500/wm8505_7in.c > @@ -0,0 +1,81 @@ > +/* > + * arch/arm/mach-vt8500/wm8505_7in.c > + * > + * Copyright (C) 2010 Alexey Charkov > + * > + * 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 "devices.h" > + > +static void __iomem *pmc_hiber; > + > +static struct platform_device *devices[] __initdata = { > + &vt8500_device_uart0, > + &vt8500_device_ehci, > + &vt8500_device_wm8505_fb, > + &vt8500_device_ge_rops, > + &vt8500_device_pwm, > + &vt8500_device_pwmbl, > + &vt8500_device_rtc, > +}; > + > +static void vt8500_power_off(void) > +{ > + local_irq_disable(); Is this necessary? > + writew(5, pmc_hiber); > + asm("mcr%? p15, 0, %0, c7, c0, 4" : : "r" (0)); > +} > + > +void __init wm8505_7in_init(void) > +{ > +#ifdef CONFIG_FB_WM8505 > + void __iomem *gpio_mux_reg = ioremap(wmt_current_regs->gpio > + + 0x200, 4); > + if (gpio_mux_reg) { > + writel(readl(gpio_mux_reg) | 0x80000000, gpio_mux_reg); > + iounmap(gpio_mux_reg); > + } else { > + printk(KERN_ERR "Could not remap the GPIO mux register, " > + "display may not work properly!\n"); > + } > +#endif > + pmc_hiber = ioremap(wmt_current_regs->pmc + 0x12, 2); > + if (pmc_hiber) > + pm_power_off = &vt8500_power_off; > + else > + printk(KERN_ERR "PMC Hibernation register could not be " > + "remapped, not enabling power off!\n"); > + > + wmt_set_resources(); > + platform_add_devices(devices, ARRAY_SIZE(devices)); > + vt8500_gpio_init(); > +} > + > +MACHINE_START(WM8505_7IN_NETBOOK, "WM8505 7-inch generic netbook") > + .boot_params = 0x00000100, > + .reserve = wm8505_reserve_mem, > + .map_io = wm8505_map_io, > + .init_irq = wm8505_init_irq, > + .timer = &vt8500_timer, > + .init_machine = wm8505_7in_init, > +MACHINE_END ~Ryan -- Bluewater Systems Ltd - ARM Technology Solution Centre Ryan Mallon 5 Amuri Park, 404 Barbadoes St ryan@bluewatersys.com PO Box 13 889, Christchurch 8013 http://www.bluewatersys.com New Zealand Phone: +64 3 3779127 Freecall: Australia 1800 148 751 Fax: +64 3 3779135 USA 1800 261 2934