[PATCH 1/6 v9] ARM: Add basic architecture support for VIA/WonderMedia 85xx SoC's
Ryan Mallon
ryan at bluewatersys.com
Mon Dec 20 15:50:54 EST 2010
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 <alchark at gmail.com>
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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <edo.rus at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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 <alchark at gmail.com>
> + *
> + * 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
More information about the linux-arm-kernel
mailing list