Subject: [PATCH 1/6 v9] ARM: Add basic architecture support for VIA/WonderMedia 85xx SoC's

From: [email-masked] (Ryan Mallon)
Date: Tue, 21 Dec 2010 09:50:54 +1300

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 <[email-masked]>

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 <[email-masked]>
> + *
> + * VIA VT8500 specific tweaks. This is merged into head.S by the linker.
> + *
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/mach-types.h>
> +
> +		.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 <[email-masked]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/io.h>
> +#include <linux/pm.h>
> +
> +#include <asm/mach-types.h>
> +#include <asm/mach/arch.h>
> +
> +#include <mach/mmio_regs.h>
> +#include <mach/irq_defs.h>
> +#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 <[email-masked]>
> + *
> + * 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 <linux/kernel.h>
> +#include <linux/io.h>
> +#include <linux/device.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm_backlight.h>
> +#include <linux/memblock.h>
> +
> +#include <asm/mach/arch.h>
> +#include <asm/mach/map.h>
> +
> +#include <mach/mmio_regs.h>
> +#include <mach/irq_defs.h>
> +#include <mach/vt8500fb.h>
> +#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 <mach/io.h> */
> +	[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 <[email-masked]>
> + *
> + * 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 <linux/platform_device.h>
> +
> +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 <[email-masked]>
> + *
> + * 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 <linux/gpio.h>
> +#include <linux/init.h>
> +#include <linux/irq.h>
> +#include <linux/io.h>
> +
> +#include <mach/mmio_regs.h>
> +#include <mach/irq_defs.h>
> +
> +#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 <[email-masked]>
> + *
> + * 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 <asm-generic/gpio.h>
> +
> +#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 <[email-masked]>
> + *
> + * 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 <linux/types.h>
> +
> +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 <[email-masked]>
> + *
> + * 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 <[email-masked]>
> + *
> + * 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 <linux/init.h>
> +
> +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 <asm/io.h>
> +
> +/* 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 <[email-masked]>
> + *
> + * 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 <[email-masked]>
> + *
> + * 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 <asm/io.h>
> +
> +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 <[email-masked]>
> + *
> + * 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 <linux/fb.h>
> +
> +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 <[email-masked]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +
> +#include <asm/irq.h>
> +
> +#include <mach/mmio_regs.h>
> +#include <mach/irq_defs.h>
> +
> +#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 <[email-masked]>
> + *
> + * 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 <linux/init.h>
> +
> +#include <mach/irq_defs.h>
> +#include <mach/mmio_regs.h>
> +
> +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 <[email-masked]>
> + *
> + * 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 <linux/init.h>
> +
> +#include <mach/mmio_regs.h>
> +
> +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 <[email-masked]>
> + *
> + * 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 <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/pwm.h>
> +
> +#include <asm/div64.h>
> +
> +#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 <[email-masked]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/io.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/clocksource.h>
> +#include <linux/clockchips.h>
> +
> +#include <asm/mach/time.h>
> +
> +#include <mach/mmio_regs.h>
> +#include <mach/irq_defs.h>
> +
> +#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 <[email-masked]>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/io.h>
> +#include <linux/pm.h>
> +
> +#include <asm/mach-types.h>
> +#include <asm/mach/arch.h>
> +
> +#include <mach/mmio_regs.h>
> +#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 at 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