Say Y here if you intend to run this kernel on an Atmel
          AT91RM9200-based board.
 
+config ARCH_PNX4008
+       bool "Philips Nexperia PNX4008 Mobile"
+       help
+         This enables support for Philips PNX4008 mobile platform.
+
 endchoice
 
 source "arch/arm/mach-clps711x/Kconfig"
 
  machine-$(CONFIG_ARCH_REALVIEW)   := realview
  machine-$(CONFIG_ARCH_AT91RM9200) := at91rm9200
  machine-$(CONFIG_ARCH_EP93XX)     := ep93xx
+ machine-$(CONFIG_ARCH_PNX4008)    := pnx4008
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
 # This is what happens if you forget the IOCS16 line.
 
--- /dev/null
+#
+# Makefile for the linux kernel.
+#
+
+obj-y                  := core.o irq.o time.o clock.o gpio.o serial.o dma.o
+obj-m                  :=
+obj-n                  :=
+obj-                   :=
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
 
--- /dev/null
+   zreladdr-y          := 0x80008000
+params_phys-y          := 0x80000100
+initrd_phys-y          := 0x80800000
+
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/clock.c
+ *
+ * Clock control driver for PNX4008
+ *
+ * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
+ * Generic clock management functions are partially based on:
+ *  linux/arch/arm/mach-omap/clock.c
+ *
+ * 2005-2006 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+
+#include <asm/semaphore.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/clock.h>
+#include "clock.h"
+
+/*forward declaration*/
+static struct clk per_ck;
+static struct clk hclk_ck;
+static struct clk ck_1MHz;
+static struct clk ck_13MHz;
+static struct clk ck_pll1;
+static int local_set_rate(struct clk *clk, u32 rate);
+
+static inline void clock_lock(void)
+{
+       local_irq_disable();
+}
+
+static inline void clock_unlock(void)
+{
+       local_irq_enable();
+}
+
+static void propagate_rate(struct clk *clk)
+{
+       struct clk *tmp_clk;
+
+       tmp_clk = clk;
+       while (tmp_clk->propagate_next) {
+               tmp_clk = tmp_clk->propagate_next;
+               local_set_rate(tmp_clk, tmp_clk->user_rate);
+       }
+}
+
+static inline void clk_reg_disable(struct clk *clk)
+{
+       if (clk->enable_reg)
+               __raw_writel(__raw_readl(clk->enable_reg) &
+                            ~(1 << clk->enable_shift), clk->enable_reg);
+}
+
+static inline void clk_reg_enable(struct clk *clk)
+{
+       if (clk->enable_reg)
+               __raw_writel(__raw_readl(clk->enable_reg) |
+                            (1 << clk->enable_shift), clk->enable_reg);
+}
+
+static inline void clk_reg_disable1(struct clk *clk)
+{
+       if (clk->enable_reg1)
+               __raw_writel(__raw_readl(clk->enable_reg1) &
+                            ~(1 << clk->enable_shift1), clk->enable_reg1);
+}
+
+static inline void clk_reg_enable1(struct clk *clk)
+{
+       if (clk->enable_reg1)
+               __raw_writel(__raw_readl(clk->enable_reg1) |
+                            (1 << clk->enable_shift1), clk->enable_reg1);
+}
+
+static int clk_wait_for_pll_lock(struct clk *clk)
+{
+       int i;
+       i = 0;
+       while (i++ < 0xFFF && !(__raw_readl(clk->scale_reg) & 1)) ;     /*wait for PLL to lock */
+
+       if (!(__raw_readl(clk->scale_reg) & 1)) {
+               printk(KERN_ERR
+                      "%s ERROR: failed to lock, scale reg data: %x\n",
+                      clk->name, __raw_readl(clk->scale_reg));
+               return -1;
+       }
+       return 0;
+}
+
+static int switch_to_dirty_13mhz(struct clk *clk)
+{
+       int i;
+       int ret;
+       u32 tmp_reg;
+
+       ret = 0;
+
+       if (!clk->rate)
+               clk_reg_enable1(clk);
+
+       tmp_reg = __raw_readl(clk->parent_switch_reg);
+       /*if 13Mhz clock selected, select 13'MHz (dirty) source from OSC */
+       if (!(tmp_reg & 1)) {
+               tmp_reg |= (1 << 1);    /* Trigger switch to 13'MHz (dirty) clock */
+               __raw_writel(tmp_reg, clk->parent_switch_reg);
+               i = 0;
+               while (i++ < 0xFFF && !(__raw_readl(clk->parent_switch_reg) & 1)) ;     /*wait for 13'MHz selection status */
+
+               if (!(__raw_readl(clk->parent_switch_reg) & 1)) {
+                       printk(KERN_ERR
+                              "%s ERROR: failed to select 13'MHz, parent sw reg data: %x\n",
+                              clk->name, __raw_readl(clk->parent_switch_reg));
+                       ret = -1;
+               }
+       }
+
+       if (!clk->rate)
+               clk_reg_disable1(clk);
+
+       return ret;
+}
+
+static int switch_to_clean_13mhz(struct clk *clk)
+{
+       int i;
+       int ret;
+       u32 tmp_reg;
+
+       ret = 0;
+
+       if (!clk->rate)
+               clk_reg_enable1(clk);
+
+       tmp_reg = __raw_readl(clk->parent_switch_reg);
+       /*if 13'Mhz clock selected, select 13MHz (clean) source from OSC */
+       if (tmp_reg & 1) {
+               tmp_reg &= ~(1 << 1);   /* Trigger switch to 13MHz (clean) clock */
+               __raw_writel(tmp_reg, clk->parent_switch_reg);
+               i = 0;
+               while (i++ < 0xFFF && (__raw_readl(clk->parent_switch_reg) & 1)) ;      /*wait for 13MHz selection status */
+
+               if (__raw_readl(clk->parent_switch_reg) & 1) {
+                       printk(KERN_ERR
+                              "%s ERROR: failed to select 13MHz, parent sw reg data: %x\n",
+                              clk->name, __raw_readl(clk->parent_switch_reg));
+                       ret = -1;
+               }
+       }
+
+       if (!clk->rate)
+               clk_reg_disable1(clk);
+
+       return ret;
+}
+
+static int set_13MHz_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = -EINVAL;
+
+       if (parent == &ck_13MHz)
+               ret = switch_to_clean_13mhz(clk);
+       else if (parent == &ck_pll1)
+               ret = switch_to_dirty_13mhz(clk);
+
+       return ret;
+}
+
+#define PLL160_MIN_FCCO 156000
+#define PLL160_MAX_FCCO 320000
+
+/*
+ * Calculate pll160 settings.
+ * Possible input: up to 320MHz with step of clk->parent->rate.
+ * In PNX4008 parent rate for pll160s may be either 1 or 13MHz.
+ * Ignored paths: "feedback" (bit 13 set), "div-by-N".
+ * Setting ARM PLL4 rate to 0 will put CPU into direct run mode.
+ * Setting PLL5 and PLL3 rate to 0 will disable USB and DSP clock input.
+ * Please refer to PNX4008 IC manual for details.
+ */
+
+static int pll160_set_rate(struct clk *clk, u32 rate)
+{
+       u32 tmp_reg, tmp_m, tmp_2p, i;
+       u32 parent_rate;
+       int ret = -EINVAL;
+
+       parent_rate = clk->parent->rate;
+
+       if (!parent_rate)
+               goto out;
+
+       /* set direct run for ARM or disable output for others  */
+       clk_reg_disable(clk);
+
+       /* disable source input as well (ignored for ARM) */
+       clk_reg_disable1(clk);
+
+       tmp_reg = __raw_readl(clk->scale_reg);
+       tmp_reg &= ~0x1ffff;    /*clear all settings, power down */
+       __raw_writel(tmp_reg, clk->scale_reg);
+
+       rate -= rate % parent_rate;     /*round down the input */
+
+       if (rate > PLL160_MAX_FCCO)
+               rate = PLL160_MAX_FCCO;
+
+       if (!rate) {
+               clk->rate = 0;
+               ret = 0;
+               goto out;
+       }
+
+       clk_reg_enable1(clk);
+       tmp_reg = __raw_readl(clk->scale_reg);
+
+       if (rate == parent_rate) {
+               /*enter direct bypass mode */
+               tmp_reg |= ((1 << 14) | (1 << 15));
+               __raw_writel(tmp_reg, clk->scale_reg);
+               clk->rate = parent_rate;
+               clk_reg_enable(clk);
+               ret = 0;
+               goto out;
+       }
+
+       i = 0;
+       for (tmp_2p = 1; tmp_2p < 16; tmp_2p <<= 1) {
+               if (rate * tmp_2p >= PLL160_MIN_FCCO)
+                       break;
+               i++;
+       }
+
+       if (tmp_2p > 1)
+               tmp_reg |= ((i - 1) << 11);
+       else
+               tmp_reg |= (1 << 14);   /*direct mode, no divide */
+
+       tmp_m = rate * tmp_2p;
+       tmp_m /= parent_rate;
+
+       tmp_reg |= (tmp_m - 1) << 1;    /*calculate M */
+       tmp_reg |= (1 << 16);   /*power up PLL */
+       __raw_writel(tmp_reg, clk->scale_reg);
+
+       if (clk_wait_for_pll_lock(clk) < 0) {
+               clk_reg_disable(clk);
+               clk_reg_disable1(clk);
+
+               tmp_reg = __raw_readl(clk->scale_reg);
+               tmp_reg &= ~0x1ffff;    /*clear all settings, power down */
+               __raw_writel(tmp_reg, clk->scale_reg);
+               clk->rate = 0;
+               ret = -EFAULT;
+               goto out;
+       }
+
+       clk->rate = (tmp_m * parent_rate) / tmp_2p;
+
+       if (clk->flags & RATE_PROPAGATES)
+               propagate_rate(clk);
+
+       clk_reg_enable(clk);
+       ret = 0;
+
+out:
+       return ret;
+}
+
+/*configure PER_CLK*/
+static int per_clk_set_rate(struct clk *clk, u32 rate)
+{
+       u32 tmp;
+
+       tmp = __raw_readl(clk->scale_reg);
+       tmp &= ~(0x1f << 2);
+       tmp |= ((clk->parent->rate / clk->rate) - 1) << 2;
+       __raw_writel(tmp, clk->scale_reg);
+       clk->rate = rate;
+       return 0;
+}
+
+/*configure HCLK*/
+static int hclk_set_rate(struct clk *clk, u32 rate)
+{
+       u32 tmp;
+       tmp = __raw_readl(clk->scale_reg);
+       tmp = tmp & ~0x3;
+       switch (rate) {
+       case 1:
+               break;
+       case 2:
+               tmp |= 1;
+               break;
+       case 4:
+               tmp |= 2;
+               break;
+       }
+
+       __raw_writel(tmp, clk->scale_reg);
+       clk->rate = rate;
+       return 0;
+}
+
+static u32 hclk_round_rate(struct clk *clk, u32 rate)
+{
+       switch (rate) {
+       case 1:
+       case 4:
+               return rate;
+       }
+       return 2;
+}
+
+static u32 per_clk_round_rate(struct clk *clk, u32 rate)
+{
+       return CLK_RATE_13MHZ;
+}
+
+static int on_off_set_rate(struct clk *clk, u32 rate)
+{
+       if (rate) {
+               clk_reg_enable(clk);
+               clk->rate = 1;
+       } else {
+               clk_reg_disable(clk);
+               clk->rate = 0;
+       }
+       return 0;
+}
+
+static int on_off_inv_set_rate(struct clk *clk, u32 rate)
+{
+       if (rate) {
+               clk_reg_disable(clk);   /*enable bit is inverted */
+               clk->rate = 1;
+       } else {
+               clk_reg_enable(clk);
+               clk->rate = 0;
+       }
+       return 0;
+}
+
+static u32 on_off_round_rate(struct clk *clk, u32 rate)
+{
+       return (rate ? 1 : 0);
+}
+
+static u32 pll4_round_rate(struct clk *clk, u32 rate)
+{
+       if (rate > CLK_RATE_208MHZ)
+               rate = CLK_RATE_208MHZ;
+       if (rate == CLK_RATE_208MHZ && hclk_ck.user_rate == 1)
+               rate = CLK_RATE_208MHZ - CLK_RATE_13MHZ;
+       return (rate - (rate % (hclk_ck.user_rate * CLK_RATE_13MHZ)));
+}
+
+static u32 pll3_round_rate(struct clk *clk, u32 rate)
+{
+       if (rate > CLK_RATE_208MHZ)
+               rate = CLK_RATE_208MHZ;
+       return (rate - rate % CLK_RATE_13MHZ);
+}
+
+static u32 pll5_round_rate(struct clk *clk, u32 rate)
+{
+       return (rate ? CLK_RATE_48MHZ : 0);
+}
+
+static u32 ck_13MHz_round_rate(struct clk *clk, u32 rate)
+{
+       return (rate ? CLK_RATE_13MHZ : 0);
+}
+
+static int ck_13MHz_set_rate(struct clk *clk, u32 rate)
+{
+       if (rate) {
+               clk_reg_disable(clk);   /*enable bit is inverted */
+               udelay(500);
+               clk->rate = CLK_RATE_13MHZ;
+               ck_1MHz.rate = CLK_RATE_1MHZ;
+       } else {
+               clk_reg_enable(clk);
+               clk->rate = 0;
+               ck_1MHz.rate = 0;
+       }
+       return 0;
+}
+
+static int pll1_set_rate(struct clk *clk, u32 rate)
+{
+#if 0 /* doesn't work on some boards, probably a HW BUG */
+       if (rate) {
+               clk_reg_disable(clk);   /*enable bit is inverted */
+               if (!clk_wait_for_pll_lock(clk)) {
+                       clk->rate = CLK_RATE_13MHZ;
+               } else {
+                       clk_reg_enable(clk);
+                       clk->rate = 0;
+               }
+
+       } else {
+               clk_reg_enable(clk);
+               clk->rate = 0;
+       }
+#endif
+       return 0;
+}
+
+/* Clock sources */
+
+static struct clk osc_13MHz = {
+       .name = "osc_13MHz",
+       .flags = FIXED_RATE,
+       .rate = CLK_RATE_13MHZ,
+};
+
+static struct clk ck_13MHz = {
+       .name = "ck_13MHz",
+       .parent = &osc_13MHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &ck_13MHz_round_rate,
+       .set_rate = &ck_13MHz_set_rate,
+       .enable_reg = OSC13CTRL_REG,
+       .enable_shift = 0,
+       .rate = CLK_RATE_13MHZ,
+};
+
+static struct clk osc_32KHz = {
+       .name = "osc_32KHz",
+       .flags = FIXED_RATE,
+       .rate = CLK_RATE_32KHZ,
+};
+
+/*attached to PLL5*/
+static struct clk ck_1MHz = {
+       .name = "ck_1MHz",
+       .flags = FIXED_RATE | PARENT_SET_RATE,
+       .parent = &ck_13MHz,
+};
+
+/* PLL1 (397) - provides 13' MHz clock */
+static struct clk ck_pll1 = {
+       .name = "ck_pll1",
+       .parent = &osc_32KHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &ck_13MHz_round_rate,
+       .set_rate = &pll1_set_rate,
+       .enable_reg = PLLCTRL_REG,
+       .enable_shift = 1,
+       .scale_reg = PLLCTRL_REG,
+       .rate = CLK_RATE_13MHZ,
+};
+
+/* CPU/Bus PLL */
+static struct clk ck_pll4 = {
+       .name = "ck_pll4",
+       .parent = &ck_pll1,
+       .flags = RATE_PROPAGATES | NEEDS_INITIALIZATION,
+       .propagate_next = &per_ck,
+       .round_rate = &pll4_round_rate,
+       .set_rate = &pll160_set_rate,
+       .rate = CLK_RATE_208MHZ,
+       .scale_reg = HCLKPLLCTRL_REG,
+       .enable_reg = PWRCTRL_REG,
+       .enable_shift = 2,
+       .parent_switch_reg = SYSCLKCTRL_REG,
+       .set_parent = &set_13MHz_parent,
+};
+
+/* USB PLL */
+static struct clk ck_pll5 = {
+       .name = "ck_pll5",
+       .parent = &ck_1MHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &pll5_round_rate,
+       .set_rate = &pll160_set_rate,
+       .scale_reg = USBCTRL_REG,
+       .enable_reg = USBCTRL_REG,
+       .enable_shift = 18,
+       .enable_reg1 = USBCTRL_REG,
+       .enable_shift1 = 17,
+};
+
+/* XPERTTeak DSP PLL */
+static struct clk ck_pll3 = {
+       .name = "ck_pll3",
+       .parent = &ck_pll1,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &pll3_round_rate,
+       .set_rate = &pll160_set_rate,
+       .scale_reg = DSPPLLCTRL_REG,
+       .enable_reg = DSPCLKCTRL_REG,
+       .enable_shift = 3,
+       .enable_reg1 = DSPCLKCTRL_REG,
+       .enable_shift1 = 2,
+       .parent_switch_reg = DSPCLKCTRL_REG,
+       .set_parent = &set_13MHz_parent,
+};
+
+static struct clk hclk_ck = {
+       .name = "hclk_ck",
+       .parent = &ck_pll4,
+       .flags = PARENT_SET_RATE,
+       .set_rate = &hclk_set_rate,
+       .round_rate = &hclk_round_rate,
+       .scale_reg = HCLKDIVCTRL_REG,
+       .rate = 2,
+       .user_rate = 2,
+};
+
+static struct clk per_ck = {
+       .name = "per_ck",
+       .parent = &ck_pll4,
+       .flags = FIXED_RATE,
+       .propagate_next = &hclk_ck,
+       .set_rate = &per_clk_set_rate,
+       .round_rate = &per_clk_round_rate,
+       .scale_reg = HCLKDIVCTRL_REG,
+       .rate = CLK_RATE_13MHZ,
+       .user_rate = CLK_RATE_13MHZ,
+};
+
+static struct clk m2hclk_ck = {
+       .name = "m2hclk_ck",
+       .parent = &hclk_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_inv_set_rate,
+       .rate = 1,
+       .enable_shift = 6,
+       .enable_reg = PWRCTRL_REG,
+};
+
+static struct clk vfp9_ck = {
+       .name = "vfp9_ck",
+       .parent = &ck_pll4,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .rate = 1,
+       .enable_shift = 4,
+       .enable_reg = VFP9CLKCTRL_REG,
+};
+
+static struct clk keyscan_ck = {
+       .name = "keyscan_ck",
+       .parent = &osc_32KHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = KEYCLKCTRL_REG,
+};
+
+static struct clk touch_ck = {
+       .name = "touch_ck",
+       .parent = &osc_32KHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = TSCLKCTRL_REG,
+};
+
+static struct clk pwm1_ck = {
+       .name = "pwm1_ck",
+       .parent = &osc_32KHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = PWMCLKCTRL_REG,
+};
+
+static struct clk pwm2_ck = {
+       .name = "pwm2_ck",
+       .parent = &osc_32KHz,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 2,
+       .enable_reg = PWMCLKCTRL_REG,
+};
+
+static struct clk jpeg_ck = {
+       .name = "jpeg_ck",
+       .parent = &hclk_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = JPEGCLKCTRL_REG,
+};
+
+static struct clk ms_ck = {
+       .name = "ms_ck",
+       .parent = &ck_pll4,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 5,
+       .enable_reg = MSCTRL_REG,
+};
+
+static struct clk dum_ck = {
+       .name = "dum_ck",
+       .parent = &hclk_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = DUMCLKCTRL_REG,
+};
+
+static struct clk flash_ck = {
+       .name = "flash_ck",
+       .parent = &hclk_ck,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 1,      /* Only MLC clock supported */
+       .enable_reg = FLASHCLKCTRL_REG,
+};
+
+static struct clk i2c0_ck = {
+       .name = "i2c0_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = I2CCLKCTRL_REG,
+};
+
+static struct clk i2c1_ck = {
+       .name = "i2c1_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 1,
+       .enable_reg = I2CCLKCTRL_REG,
+};
+
+static struct clk i2c2_ck = {
+       .name = "i2c2_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 2,
+       .enable_reg = USB_OTG_CLKCTRL_REG,
+};
+
+static struct clk spi0_ck = {
+       .name = "spi0_ck",
+       .parent = &hclk_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = SPICTRL_REG,
+};
+
+static struct clk spi1_ck = {
+       .name = "spi1_ck",
+       .parent = &hclk_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 4,
+       .enable_reg = SPICTRL_REG,
+};
+
+static struct clk dma_ck = {
+       .name = "dma_ck",
+       .parent = &hclk_ck,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 0,
+       .enable_reg = DMACLKCTRL_REG,
+};
+
+static struct clk uart3_ck = {
+       .name = "uart3_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .rate = 1,
+       .enable_shift = 0,
+       .enable_reg = UARTCLKCTRL_REG,
+};
+
+static struct clk uart4_ck = {
+       .name = "uart4_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 1,
+       .enable_reg = UARTCLKCTRL_REG,
+};
+
+static struct clk uart5_ck = {
+       .name = "uart5_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .rate = 1,
+       .enable_shift = 2,
+       .enable_reg = UARTCLKCTRL_REG,
+};
+
+static struct clk uart6_ck = {
+       .name = "uart6_ck",
+       .parent = &per_ck,
+       .flags = NEEDS_INITIALIZATION,
+       .round_rate = &on_off_round_rate,
+       .set_rate = &on_off_set_rate,
+       .enable_shift = 3,
+       .enable_reg = UARTCLKCTRL_REG,
+};
+
+/* These clocks are visible outside this module
+ * and can be initialized
+ */
+static struct clk *onchip_clks[] = {
+       &ck_13MHz,
+       &ck_pll1,
+       &ck_pll4,
+       &ck_pll5,
+       &ck_pll3,
+       &vfp9_ck,
+       &m2hclk_ck,
+       &hclk_ck,
+       &dma_ck,
+       &flash_ck,
+       &dum_ck,
+       &keyscan_ck,
+       &pwm1_ck,
+       &pwm2_ck,
+       &jpeg_ck,
+       &ms_ck,
+       &touch_ck,
+       &i2c0_ck,
+       &i2c1_ck,
+       &i2c2_ck,
+       &spi0_ck,
+       &spi1_ck,
+       &uart3_ck,
+       &uart4_ck,
+       &uart5_ck,
+       &uart6_ck,
+};
+
+static int local_set_rate(struct clk *clk, u32 rate)
+{
+       int ret = -EINVAL;
+       if (clk->set_rate) {
+
+               if (clk->user_rate == clk->rate && clk->parent->rate) {
+                       /* if clock enabled or rate not set */
+                       clk->user_rate = clk->round_rate(clk, rate);
+                       ret = clk->set_rate(clk, clk->user_rate);
+               } else
+                       clk->user_rate = clk->round_rate(clk, rate);
+               ret = 0;
+       }
+       return ret;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+
+       if (clk->flags & FIXED_RATE)
+               goto out;
+
+       clock_lock();
+       if ((clk->flags & PARENT_SET_RATE) && clk->parent) {
+
+               clk->user_rate = clk->round_rate(clk, rate);
+               /* parent clock needs to be refreshed
+                  for the setting to take effect */
+       } else {
+               ret = local_set_rate(clk, rate);
+       }
+       ret = 0;
+       clock_unlock();
+
+out:
+       return ret;
+}
+
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+       struct clk *clk = ERR_PTR(-ENOENT);
+       struct clk **clkp;
+
+       clock_lock();
+       for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
+            clkp++) {
+               if (strcmp(id, (*clkp)->name) == 0
+                   && try_module_get((*clkp)->owner)) {
+                       clk = (*clkp);
+                       break;
+               }
+       }
+       clock_unlock();
+
+       return clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+       clock_lock();
+       if (clk && !IS_ERR(clk))
+               module_put(clk->owner);
+       clock_unlock();
+}
+EXPORT_SYMBOL(clk_put);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       unsigned long ret;
+       clock_lock();
+       ret = clk->rate;
+       clock_unlock();
+       return ret;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+static int local_clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (!(clk->flags & FIXED_RATE) && !clk->rate && clk->set_rate
+           && clk->user_rate)
+               ret = clk->set_rate(clk, clk->user_rate);
+       return ret;
+}
+
+static void local_clk_disable(struct clk *clk)
+{
+       if (!(clk->flags & FIXED_RATE) && clk->rate && clk->set_rate)
+               clk->set_rate(clk, 0);
+}
+
+int clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       clock_lock();
+       ret = local_clk_enable(clk);
+       clock_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+       clock_lock();
+       local_clk_disable(clk);
+       clock_unlock();
+}
+
+EXPORT_SYMBOL(clk_disable);
+
+static void local_clk_unuse(struct clk *clk)
+{
+       if (clk->usecount > 0 && !(--clk->usecount)) {
+               local_clk_disable(clk);
+               if (clk->parent)
+                       local_clk_unuse(clk->parent);
+       }
+}
+
+static int local_clk_use(struct clk *clk)
+{
+       int ret = 0;
+       if (clk->usecount++ == 0) {
+               if (clk->parent)
+                       ret = local_clk_use(clk->parent);
+
+               if (ret != 0) {
+                       clk->usecount--;
+                       goto out;
+               }
+
+               ret = local_clk_enable(clk);
+
+               if (ret != 0 && clk->parent) {
+                       local_clk_unuse(clk->parent);
+                       clk->usecount--;
+               }
+       }
+out:
+       return ret;
+}
+
+/* The main purpose of clk_use ans clk_unuse functions
+ * is to control switching 13MHz oscillator and PLL1 (13'MHz),
+ * so that they are disabled whenever none of PLL2-5 is using them.
+ * Although in theory these functions should work with any clock,
+ * please use them only on PLL2 - PLL5 to avoid confusion.
+ */
+int clk_use(struct clk *clk)
+{
+       int ret = 0;
+
+       clock_lock();
+       ret = local_clk_use(clk);
+       clock_unlock();
+       return ret;
+}
+EXPORT_SYMBOL(clk_use);
+
+void clk_unuse(struct clk *clk)
+{
+
+       clock_lock();
+       local_clk_unuse(clk);
+       clock_unlock();
+}
+
+EXPORT_SYMBOL(clk_unuse);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       long ret;
+       clock_lock();
+       if (clk->round_rate)
+               ret = clk->round_rate(clk, rate);
+       else
+               ret = clk->rate;
+       clock_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = -ENODEV;
+       if (!clk->set_parent)
+               goto out;
+
+       clock_lock();
+       ret = clk->set_parent(clk, parent);
+       if (!ret)
+               clk->parent = parent;
+       clock_unlock();
+
+out:
+       return ret;
+}
+
+EXPORT_SYMBOL(clk_set_parent);
+
+static int __init clk_init(void)
+{
+       struct clk **clkp;
+
+       /* Disable autoclocking, as it doesn't seem to work */
+       __raw_writel(0xff, AUTOCLK_CTRL);
+
+       for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
+            clkp++) {
+               if (((*clkp)->flags & NEEDS_INITIALIZATION)
+                   && ((*clkp)->set_rate)) {
+                       (*clkp)->user_rate = (*clkp)->rate;
+                       local_set_rate((*clkp), (*clkp)->user_rate);
+                       if ((*clkp)->set_parent)
+                               (*clkp)->set_parent((*clkp), (*clkp)->parent);
+               }
+               pr_debug("%s: clock %s, rate %ld\n",
+                       __FUNCTION__, (*clkp)->name, (*clkp)->rate);
+       }
+
+       clk_use(&ck_pll4);
+
+       /* if ck_13MHz is not used, disable it. */
+       if (ck_13MHz.usecount == 0)
+               local_clk_disable(&ck_13MHz);
+
+       /* Disable autoclocking */
+       __raw_writeb(0xff, AUTOCLK_CTRL);
+
+       return 0;
+}
+
+arch_initcall(clk_init);
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/clock.h
+ *
+ * Clock control driver for PNX4008 - internal header file
+ *
+ * Author: Vitaly Wool <source@mvista.com>
+ *
+ * 2006 (c) MontaVista Software, Inc. 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.
+ */
+#ifndef __ARCH_ARM_PNX4008_CLOCK_H__
+#define __ARCH_ARM_PNX4008_CLOCK_H__
+
+struct clk {
+       struct list_head node;
+       struct module *owner;
+       const char *name;
+       struct clk *parent;
+       struct clk *propagate_next;
+       u32 rate;
+       u32 user_rate;
+       s8 usecount;
+       u32 flags;
+       u32 scale_reg;
+       u8 enable_shift;
+       u32 enable_reg;
+       u8 enable_shift1;
+       u32 enable_reg1;
+       u32 parent_switch_reg;
+        u32(*round_rate) (struct clk *, u32);
+       int (*set_rate) (struct clk *, u32);
+       int (*set_parent) (struct clk * clk, struct clk * parent);
+};
+
+/* Flags */
+#define RATE_PROPAGATES      (1<<0)
+#define NEEDS_INITIALIZATION (1<<1)
+#define PARENT_SET_RATE      (1<<2)
+#define FIXED_RATE           (1<<3)
+
+#endif
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/core.c
+ *
+ * PNX4008 core startup code
+ *
+ * Authors: Vitaly Wool, Dmitry Chigirev,
+ * Grigory Tolstolytkin, Dmitry Pervushin <source@mvista.com>
+ *
+ * Based on reference code received from Philips:
+ * Copyright (C) 2003 Philips Semiconductors
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/serial_8250.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+#include <asm/arch/irq.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/dma.h>
+
+struct resource spipnx_0_resources[] = {
+       {
+               .start = PNX4008_SPI1_BASE,
+               .end = PNX4008_SPI1_BASE + SZ_4K,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = PER_SPI1_REC_XMIT,
+               .flags = IORESOURCE_DMA,
+       }, {
+               .start = SPI1_INT,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .flags = 0,
+       },
+};
+
+struct resource spipnx_1_resources[] = {
+       {
+               .start = PNX4008_SPI2_BASE,
+               .end = PNX4008_SPI2_BASE + SZ_4K,
+               .flags = IORESOURCE_MEM,
+       }, {
+               .start = PER_SPI2_REC_XMIT,
+               .flags = IORESOURCE_DMA,
+       }, {
+               .start = SPI2_INT,
+               .flags = IORESOURCE_IRQ,
+       }, {
+               .flags = 0,
+       }
+};
+
+static struct spi_board_info spi_board_info[] __initdata = {
+       {
+               .modalias       = "m25p80",
+               .max_speed_hz   = 1000000,
+               .bus_num        = 1,
+               .chip_select    = 0,
+       },
+};
+
+static struct platform_device spipnx_1 = {
+       .name = "spipnx",
+       .id = 1,
+       .num_resources = ARRAY_SIZE(spipnx_0_resources),
+       .resource = spipnx_0_resources,
+       .dev = {
+               .coherent_dma_mask = 0xFFFFFFFF,
+               },
+};
+
+static struct platform_device spipnx_2 = {
+       .name = "spipnx",
+       .id = 2,
+       .num_resources = ARRAY_SIZE(spipnx_1_resources),
+       .resource = spipnx_1_resources,
+       .dev = {
+               .coherent_dma_mask = 0xFFFFFFFF,
+               },
+};
+
+static struct plat_serial8250_port platform_serial_ports[] = {
+       {
+               .membase = (void *)__iomem(IO_ADDRESS(PNX4008_UART5_BASE)),
+               .mapbase = (unsigned long)PNX4008_UART5_BASE,
+               .irq = IIR5_INT,
+               .uartclk = PNX4008_UART_CLK,
+               .regshift = 2,
+               .iotype = UPIO_MEM,
+               .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST,
+       },
+       {
+               .membase = (void *)__iomem(IO_ADDRESS(PNX4008_UART3_BASE)),
+               .mapbase = (unsigned long)PNX4008_UART3_BASE,
+               .irq = IIR3_INT,
+               .uartclk = PNX4008_UART_CLK,
+               .regshift = 2,
+               .iotype = UPIO_MEM,
+               .flags = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART | UPF_SKIP_TEST,
+        },
+       {}
+};
+
+static struct platform_device serial_device = {
+       .name = "serial8250",
+       .id = PLAT8250_DEV_PLATFORM,
+       .dev = {
+               .platform_data = &platform_serial_ports,
+       },
+};
+
+static struct platform_device *devices[] __initdata = {
+       &spipnx_1,
+       &spipnx_2,
+       &serial_device,
+};
+
+
+extern void pnx4008_uart_init(void);
+
+static void __init pnx4008_init(void)
+{
+       /*disable all START interrupt sources,
+          and clear all START interrupt flags */
+       __raw_writel(0, START_INT_ER_REG(SE_PIN_BASE_INT));
+       __raw_writel(0, START_INT_ER_REG(SE_INT_BASE_INT));
+       __raw_writel(0xffffffff, START_INT_RSR_REG(SE_PIN_BASE_INT));
+       __raw_writel(0xffffffff, START_INT_RSR_REG(SE_INT_BASE_INT));
+
+       platform_add_devices(devices, ARRAY_SIZE(devices));
+       spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+       /* Switch on the UART clocks */
+       pnx4008_uart_init();
+}
+
+static struct map_desc pnx4008_io_desc[] __initdata = {
+       {
+               .virtual        = IO_ADDRESS(PNX4008_IRAM_BASE),
+               .pfn            = __phys_to_pfn(PNX4008_IRAM_BASE),
+               .length         = SZ_64K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(PNX4008_NDF_FLASH_BASE),
+               .pfn            = __phys_to_pfn(PNX4008_NDF_FLASH_BASE),
+               .length         = SZ_1M - SZ_128K,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(PNX4008_JPEG_CONFIG_BASE),
+               .pfn            = __phys_to_pfn(PNX4008_JPEG_CONFIG_BASE),
+               .length         = SZ_128K * 3,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(PNX4008_DMA_CONFIG_BASE),
+               .pfn            = __phys_to_pfn(PNX4008_DMA_CONFIG_BASE),
+               .length         = SZ_1M,
+               .type           = MT_DEVICE,
+       }, {
+               .virtual        = IO_ADDRESS(PNX4008_AHB2FAB_BASE),
+               .pfn            = __phys_to_pfn(PNX4008_AHB2FAB_BASE),
+               .length         = SZ_1M,
+               .type           = MT_DEVICE,
+       },
+};
+
+void __init pnx4008_map_io(void)
+{
+       iotable_init(pnx4008_io_desc, ARRAY_SIZE(pnx4008_io_desc));
+}
+
+extern struct sys_timer pnx4008_timer;
+
+MACHINE_START(PNX4008, "Philips PNX4008")
+       /* Maintainer: MontaVista Software Inc. */
+       .phys_io                = 0x40090000,
+       .io_pg_offst            = (0xf4090000 >> 18) & 0xfffc,
+       .boot_params            = 0x80000100,
+       .map_io                 = pnx4008_map_io,
+       .init_irq               = pnx4008_init_irq,
+       .init_machine           = pnx4008_init,
+       .timer                  = &pnx4008_timer,
+MACHINE_END
 
--- /dev/null
+/*
+ *  linux/arch/arm/mach-pnx4008/dma.c
+ *
+ *  PNX4008 DMA registration and IRQ dispatching
+ *
+ *  Author:    Vitaly Wool
+ *  Copyright: MontaVista Software Inc. (c) 2005
+ *
+ *  Based on the code from Nicolas Pitre
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/dma.h>
+#include <asm/dma-mapping.h>
+#include <asm/io.h>
+#include <asm/mach/dma.h>
+#include <asm/arch/clock.h>
+
+static struct dma_channel {
+       char *name;
+       void (*irq_handler) (int, int, void *, struct pt_regs *);
+       void *data;
+       struct pnx4008_dma_ll *ll;
+       u32 ll_dma;
+       void *target_addr;
+       int target_id;
+} dma_channels[MAX_DMA_CHANNELS];
+
+static struct ll_pool {
+       void *vaddr;
+       void *cur;
+       dma_addr_t dma_addr;
+       int count;
+} ll_pool;
+
+static spinlock_t ll_lock = SPIN_LOCK_UNLOCKED;
+
+struct pnx4008_dma_ll *pnx4008_alloc_ll_entry(dma_addr_t * ll_dma)
+{
+       struct pnx4008_dma_ll *ll = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ll_lock, flags);
+       if (ll_pool.count > 4) { /* can give one more */
+               ll = *(struct pnx4008_dma_ll **) ll_pool.cur;
+               *ll_dma = ll_pool.dma_addr + ((void *)ll - ll_pool.vaddr);
+               *(void **)ll_pool.cur = **(void ***)ll_pool.cur;
+               memset(ll, 0, sizeof(*ll));
+               ll_pool.count--;
+       }
+       spin_unlock_irqrestore(&ll_lock, flags);
+
+       return ll;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_alloc_ll_entry);
+
+void pnx4008_free_ll_entry(struct pnx4008_dma_ll * ll, dma_addr_t ll_dma)
+{
+       unsigned long flags;
+
+       if (ll) {
+               if ((unsigned long)((long)ll - (long)ll_pool.vaddr) > 0x4000) {
+                       printk(KERN_ERR "Trying to free entry not allocated by DMA\n");
+                       BUG();
+               }
+
+               if (ll->flags & DMA_BUFFER_ALLOCATED)
+                       ll->free(ll->alloc_data);
+
+               spin_lock_irqsave(&ll_lock, flags);
+               *(long *)ll = *(long *)ll_pool.cur;
+               *(long *)ll_pool.cur = (long)ll;
+               ll_pool.count++;
+               spin_unlock_irqrestore(&ll_lock, flags);
+       }
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_free_ll_entry);
+
+void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll * ll)
+{
+       struct pnx4008_dma_ll *ptr;
+       u32 dma;
+
+       while (ll) {
+               dma = ll->next_dma;
+               ptr = ll->next;
+               pnx4008_free_ll_entry(ll, ll_dma);
+
+               ll_dma = dma;
+               ll = ptr;
+       }
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_free_ll);
+
+static int dma_channels_requested = 0;
+
+static inline void dma_increment_usage(void)
+{
+       if (!dma_channels_requested++) {
+               struct clk *clk = clk_get(0, "dma_ck");
+               if (!IS_ERR(clk)) {
+                       clk_set_rate(clk, 1);
+                       clk_put(clk);
+               }
+               pnx4008_config_dma(-1, -1, 1);
+       }
+}
+static inline void dma_decrement_usage(void)
+{
+       if (!--dma_channels_requested) {
+               struct clk *clk = clk_get(0, "dma_ck");
+               if (!IS_ERR(clk)) {
+                       clk_set_rate(clk, 0);
+                       clk_put(clk);
+               }
+               pnx4008_config_dma(-1, -1, 0);
+
+       }
+}
+
+static spinlock_t dma_lock = SPIN_LOCK_UNLOCKED;
+
+static inline void pnx4008_dma_lock(void)
+{
+       spin_lock_irq(&dma_lock);
+}
+
+static inline void pnx4008_dma_unlock(void)
+{
+       spin_unlock_irq(&dma_lock);
+}
+
+#define VALID_CHANNEL(c)       (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
+
+int pnx4008_request_channel(char *name, int ch,
+                           void (*irq_handler) (int, int, void *,
+                                                struct pt_regs *), void *data)
+{
+       int i, found = 0;
+
+       /* basic sanity checks */
+       if (!name || (ch != -1 && !VALID_CHANNEL(ch)))
+               return -EINVAL;
+
+       pnx4008_dma_lock();
+
+       /* try grabbing a DMA channel with the requested priority */
+       for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
+               if (!dma_channels[i].name && (ch == -1 || ch == i)) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found) {
+               dma_increment_usage();
+               dma_channels[i].name = name;
+               dma_channels[i].irq_handler = irq_handler;
+               dma_channels[i].data = data;
+               dma_channels[i].ll = NULL;
+               dma_channels[i].ll_dma = 0;
+       } else {
+               printk(KERN_WARNING "No more available DMA channels for %s\n",
+                      name);
+               i = -ENODEV;
+       }
+
+       pnx4008_dma_unlock();
+       return i;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_request_channel);
+
+void pnx4008_free_channel(int ch)
+{
+       if (!dma_channels[ch].name) {
+               printk(KERN_CRIT
+                      "%s: trying to free channel %d which is already freed\n",
+                      __FUNCTION__, ch);
+               return;
+       }
+
+       pnx4008_dma_lock();
+       pnx4008_free_ll(dma_channels[ch].ll_dma, dma_channels[ch].ll);
+       dma_channels[ch].ll = NULL;
+       dma_decrement_usage();
+
+       dma_channels[ch].name = NULL;
+       pnx4008_dma_unlock();
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_free_channel);
+
+int pnx4008_config_dma(int ahb_m1_be, int ahb_m2_be, int enable)
+{
+       unsigned long dma_cfg = __raw_readl(DMAC_CONFIG);
+
+       switch (ahb_m1_be) {
+       case 0:
+               dma_cfg &= ~(1 << 1);
+               break;
+       case 1:
+               dma_cfg |= (1 << 1);
+               break;
+       default:
+               break;
+       }
+
+       switch (ahb_m2_be) {
+       case 0:
+               dma_cfg &= ~(1 << 2);
+               break;
+       case 1:
+               dma_cfg |= (1 << 2);
+               break;
+       default:
+               break;
+       }
+
+       switch (enable) {
+       case 0:
+               dma_cfg &= ~(1 << 0);
+               break;
+       case 1:
+               dma_cfg |= (1 << 0);
+               break;
+       default:
+               break;
+       }
+
+       pnx4008_dma_lock();
+       __raw_writel(dma_cfg, DMAC_CONFIG);
+       pnx4008_dma_unlock();
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_config_dma);
+
+int pnx4008_dma_pack_control(const struct pnx4008_dma_ch_ctrl * ch_ctrl,
+                            unsigned long *ctrl)
+{
+       int i = 0, dbsize, sbsize, err = 0;
+
+       if (!ctrl || !ch_ctrl) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       *ctrl = 0;
+
+       switch (ch_ctrl->tc_mask) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 31);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+
+       switch (ch_ctrl->cacheable) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 30);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->bufferable) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 29);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->priv_mode) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 28);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->di) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 27);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->si) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 26);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->dest_ahb1) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 25);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->src_ahb1) {
+       case 0:
+               break;
+       case 1:
+               *ctrl |= (1 << 24);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->dwidth) {
+       case WIDTH_BYTE:
+               *ctrl &= ~(7 << 21);
+               break;
+       case WIDTH_HWORD:
+               *ctrl &= ~(7 << 21);
+               *ctrl |= (1 << 21);
+               break;
+       case WIDTH_WORD:
+               *ctrl &= ~(7 << 21);
+               *ctrl |= (2 << 21);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_ctrl->swidth) {
+       case WIDTH_BYTE:
+               *ctrl &= ~(7 << 18);
+               break;
+       case WIDTH_HWORD:
+               *ctrl &= ~(7 << 18);
+               *ctrl |= (1 << 18);
+               break;
+       case WIDTH_WORD:
+               *ctrl &= ~(7 << 18);
+               *ctrl |= (2 << 18);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       dbsize = ch_ctrl->dbsize;
+       while (!(dbsize & 1)) {
+               i++;
+               dbsize >>= 1;
+       }
+       if (ch_ctrl->dbsize != 1 || i > 8 || i == 1) {
+               err = -EINVAL;
+               goto out;
+       } else if (i > 1)
+               i--;
+       *ctrl &= ~(7 << 15);
+       *ctrl |= (i << 15);
+
+       sbsize = ch_ctrl->sbsize;
+       while (!(sbsize & 1)) {
+               i++;
+               sbsize >>= 1;
+       }
+       if (ch_ctrl->sbsize != 1 || i > 8 || i == 1) {
+               err = -EINVAL;
+               goto out;
+       } else if (i > 1)
+               i--;
+       *ctrl &= ~(7 << 12);
+       *ctrl |= (i << 12);
+
+       if (ch_ctrl->tr_size > 0x7ff) {
+               err = -E2BIG;
+               goto out;
+       }
+       *ctrl &= ~0x7ff;
+       *ctrl |= ch_ctrl->tr_size & 0x7ff;
+
+out:
+       return err;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_pack_control);
+
+int pnx4008_dma_parse_control(unsigned long ctrl,
+                             struct pnx4008_dma_ch_ctrl * ch_ctrl)
+{
+       int err = 0;
+
+       if (!ch_ctrl) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       ch_ctrl->tr_size = ctrl & 0x7ff;
+       ctrl >>= 12;
+
+       ch_ctrl->sbsize = 1 << (ctrl & 7);
+       if (ch_ctrl->sbsize > 1)
+               ch_ctrl->sbsize <<= 1;
+       ctrl >>= 3;
+
+       ch_ctrl->dbsize = 1 << (ctrl & 7);
+       if (ch_ctrl->dbsize > 1)
+               ch_ctrl->dbsize <<= 1;
+       ctrl >>= 3;
+
+       switch (ctrl & 7) {
+       case 0:
+               ch_ctrl->swidth = WIDTH_BYTE;
+               break;
+       case 1:
+               ch_ctrl->swidth = WIDTH_HWORD;
+               break;
+       case 2:
+               ch_ctrl->swidth = WIDTH_WORD;
+               break;
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       ctrl >>= 3;
+
+       switch (ctrl & 7) {
+       case 0:
+               ch_ctrl->dwidth = WIDTH_BYTE;
+               break;
+       case 1:
+               ch_ctrl->dwidth = WIDTH_HWORD;
+               break;
+       case 2:
+               ch_ctrl->dwidth = WIDTH_WORD;
+               break;
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       ctrl >>= 3;
+
+       ch_ctrl->src_ahb1 = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->dest_ahb1 = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->si = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->di = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->priv_mode = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->bufferable = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->cacheable = ctrl & 1;
+       ctrl >>= 1;
+
+       ch_ctrl->tc_mask = ctrl & 1;
+
+out:
+       return err;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_parse_control);
+
+int pnx4008_dma_pack_config(const struct pnx4008_dma_ch_config * ch_cfg,
+                           unsigned long *cfg)
+{
+       int err = 0;
+
+       if (!cfg || !ch_cfg) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       *cfg = 0;
+
+       switch (ch_cfg->halt) {
+       case 0:
+               break;
+       case 1:
+               *cfg |= (1 << 18);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_cfg->active) {
+       case 0:
+               break;
+       case 1:
+               *cfg |= (1 << 17);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_cfg->lock) {
+       case 0:
+               break;
+       case 1:
+               *cfg |= (1 << 16);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_cfg->itc) {
+       case 0:
+               break;
+       case 1:
+               *cfg |= (1 << 15);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_cfg->ie) {
+       case 0:
+               break;
+       case 1:
+               *cfg |= (1 << 14);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       switch (ch_cfg->flow_cntrl) {
+       case FC_MEM2MEM_DMA:
+               *cfg &= ~(7 << 11);
+               break;
+       case FC_MEM2PER_DMA:
+               *cfg &= ~(7 << 11);
+               *cfg |= (1 << 11);
+               break;
+       case FC_PER2MEM_DMA:
+               *cfg &= ~(7 << 11);
+               *cfg |= (2 << 11);
+               break;
+       case FC_PER2PER_DMA:
+               *cfg &= ~(7 << 11);
+               *cfg |= (3 << 11);
+               break;
+       case FC_PER2PER_DPER:
+               *cfg &= ~(7 << 11);
+               *cfg |= (4 << 11);
+               break;
+       case FC_MEM2PER_PER:
+               *cfg &= ~(7 << 11);
+               *cfg |= (5 << 11);
+               break;
+       case FC_PER2MEM_PER:
+               *cfg &= ~(7 << 11);
+               *cfg |= (6 << 11);
+               break;
+       case FC_PER2PER_SPER:
+               *cfg |= (7 << 11);
+               break;
+
+       default:
+               err = -EINVAL;
+               goto out;
+       }
+       *cfg &= ~(0x1f << 6);
+       *cfg |= ((ch_cfg->dest_per & 0x1f) << 6);
+
+       *cfg &= ~(0x1f << 1);
+       *cfg |= ((ch_cfg->src_per & 0x1f) << 1);
+
+out:
+       return err;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_pack_config);
+
+int pnx4008_dma_parse_config(unsigned long cfg,
+                            struct pnx4008_dma_ch_config * ch_cfg)
+{
+       int err = 0;
+
+       if (!ch_cfg) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       cfg >>= 1;
+
+       ch_cfg->src_per = cfg & 0x1f;
+       cfg >>= 5;
+
+       ch_cfg->dest_per = cfg & 0x1f;
+       cfg >>= 5;
+
+       switch (cfg & 7) {
+       case 0:
+               ch_cfg->flow_cntrl = FC_MEM2MEM_DMA;
+               break;
+       case 1:
+               ch_cfg->flow_cntrl = FC_MEM2PER_DMA;
+               break;
+       case 2:
+               ch_cfg->flow_cntrl = FC_PER2MEM_DMA;
+               break;
+       case 3:
+               ch_cfg->flow_cntrl = FC_PER2PER_DMA;
+               break;
+       case 4:
+               ch_cfg->flow_cntrl = FC_PER2PER_DPER;
+               break;
+       case 5:
+               ch_cfg->flow_cntrl = FC_MEM2PER_PER;
+               break;
+       case 6:
+               ch_cfg->flow_cntrl = FC_PER2MEM_PER;
+               break;
+       case 7:
+               ch_cfg->flow_cntrl = FC_PER2PER_SPER;
+       }
+       cfg >>= 3;
+
+       ch_cfg->ie = cfg & 1;
+       cfg >>= 1;
+
+       ch_cfg->itc = cfg & 1;
+       cfg >>= 1;
+
+       ch_cfg->lock = cfg & 1;
+       cfg >>= 1;
+
+       ch_cfg->active = cfg & 1;
+       cfg >>= 1;
+
+       ch_cfg->halt = cfg & 1;
+
+out:
+       return err;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_parse_config);
+
+void pnx4008_dma_split_head_entry(struct pnx4008_dma_config * config,
+                                 struct pnx4008_dma_ch_ctrl * ctrl)
+{
+       int new_len = ctrl->tr_size, num_entries = 0;
+       int old_len = new_len;
+       int src_width, dest_width, count = 1;
+
+       switch (ctrl->swidth) {
+       case WIDTH_BYTE:
+               src_width = 1;
+               break;
+       case WIDTH_HWORD:
+               src_width = 2;
+               break;
+       case WIDTH_WORD:
+               src_width = 4;
+               break;
+       default:
+               return;
+       }
+
+       switch (ctrl->dwidth) {
+       case WIDTH_BYTE:
+               dest_width = 1;
+               break;
+       case WIDTH_HWORD:
+               dest_width = 2;
+               break;
+       case WIDTH_WORD:
+               dest_width = 4;
+               break;
+       default:
+               return;
+       }
+
+       while (new_len > 0x7FF) {
+               num_entries++;
+               new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
+       }
+       if (num_entries != 0) {
+               struct pnx4008_dma_ll *ll = NULL;
+               config->ch_ctrl &= ~0x7ff;
+               config->ch_ctrl |= new_len;
+               if (!config->is_ll) {
+                       config->is_ll = 1;
+                       while (num_entries) {
+                               if (!ll) {
+                                       config->ll =
+                                           pnx4008_alloc_ll_entry(&config->
+                                                                  ll_dma);
+                                       ll = config->ll;
+                               } else {
+                                       ll->next =
+                                           pnx4008_alloc_ll_entry(&ll->
+                                                                  next_dma);
+                                       ll = ll->next;
+                               }
+
+                               if (ctrl->si)
+                                       ll->src_addr =
+                                           config->src_addr +
+                                           src_width * new_len * count;
+                               else
+                                       ll->src_addr = config->src_addr;
+                               if (ctrl->di)
+                                       ll->dest_addr =
+                                           config->dest_addr +
+                                           dest_width * new_len * count;
+                               else
+                                       ll->dest_addr = config->dest_addr;
+                               ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
+                               ll->next_dma = 0;
+                               ll->next = NULL;
+                               num_entries--;
+                               count++;
+                       }
+               } else {
+                       struct pnx4008_dma_ll *ll_old = config->ll;
+                       unsigned long ll_dma_old = config->ll_dma;
+                       while (num_entries) {
+                               if (!ll) {
+                                       config->ll =
+                                           pnx4008_alloc_ll_entry(&config->
+                                                                  ll_dma);
+                                       ll = config->ll;
+                               } else {
+                                       ll->next =
+                                           pnx4008_alloc_ll_entry(&ll->
+                                                                  next_dma);
+                                       ll = ll->next;
+                               }
+
+                               if (ctrl->si)
+                                       ll->src_addr =
+                                           config->src_addr +
+                                           src_width * new_len * count;
+                               else
+                                       ll->src_addr = config->src_addr;
+                               if (ctrl->di)
+                                       ll->dest_addr =
+                                           config->dest_addr +
+                                           dest_width * new_len * count;
+                               else
+                                       ll->dest_addr = config->dest_addr;
+                               ll->ch_ctrl = config->ch_ctrl & 0x7fffffff;
+                               ll->next_dma = 0;
+                               ll->next = NULL;
+                               num_entries--;
+                               count++;
+                       }
+                       ll->next_dma = ll_dma_old;
+                       ll->next = ll_old;
+               }
+               /* adjust last length/tc */
+               ll->ch_ctrl = config->ch_ctrl & (~0x7ff);
+               ll->ch_ctrl |= old_len - new_len * (count - 1);
+               config->ch_ctrl &= 0x7fffffff;
+       }
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_split_head_entry);
+
+void pnx4008_dma_split_ll_entry(struct pnx4008_dma_ll * cur_ll,
+                               struct pnx4008_dma_ch_ctrl * ctrl)
+{
+       int new_len = ctrl->tr_size, num_entries = 0;
+       int old_len = new_len;
+       int src_width, dest_width, count = 1;
+
+       switch (ctrl->swidth) {
+       case WIDTH_BYTE:
+               src_width = 1;
+               break;
+       case WIDTH_HWORD:
+               src_width = 2;
+               break;
+       case WIDTH_WORD:
+               src_width = 4;
+               break;
+       default:
+               return;
+       }
+
+       switch (ctrl->dwidth) {
+       case WIDTH_BYTE:
+               dest_width = 1;
+               break;
+       case WIDTH_HWORD:
+               dest_width = 2;
+               break;
+       case WIDTH_WORD:
+               dest_width = 4;
+               break;
+       default:
+               return;
+       }
+
+       while (new_len > 0x7FF) {
+               num_entries++;
+               new_len = (ctrl->tr_size + num_entries) / (num_entries + 1);
+       }
+       if (num_entries != 0) {
+               struct pnx4008_dma_ll *ll = NULL;
+               cur_ll->ch_ctrl &= ~0x7ff;
+               cur_ll->ch_ctrl |= new_len;
+               if (!cur_ll->next) {
+                       while (num_entries) {
+                               if (!ll) {
+                                       cur_ll->next =
+                                           pnx4008_alloc_ll_entry(&cur_ll->
+                                                                  next_dma);
+                                       ll = cur_ll->next;
+                               } else {
+                                       ll->next =
+                                           pnx4008_alloc_ll_entry(&ll->
+                                                                  next_dma);
+                                       ll = ll->next;
+                               }
+
+                               if (ctrl->si)
+                                       ll->src_addr =
+                                           cur_ll->src_addr +
+                                           src_width * new_len * count;
+                               else
+                                       ll->src_addr = cur_ll->src_addr;
+                               if (ctrl->di)
+                                       ll->dest_addr =
+                                           cur_ll->dest_addr +
+                                           dest_width * new_len * count;
+                               else
+                                       ll->dest_addr = cur_ll->dest_addr;
+                               ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
+                               ll->next_dma = 0;
+                               ll->next = NULL;
+                               num_entries--;
+                               count++;
+                       }
+               } else {
+                       struct pnx4008_dma_ll *ll_old = cur_ll->next;
+                       unsigned long ll_dma_old = cur_ll->next_dma;
+                       while (num_entries) {
+                               if (!ll) {
+                                       cur_ll->next =
+                                           pnx4008_alloc_ll_entry(&cur_ll->
+                                                                  next_dma);
+                                       ll = cur_ll->next;
+                               } else {
+                                       ll->next =
+                                           pnx4008_alloc_ll_entry(&ll->
+                                                                  next_dma);
+                                       ll = ll->next;
+                               }
+
+                               if (ctrl->si)
+                                       ll->src_addr =
+                                           cur_ll->src_addr +
+                                           src_width * new_len * count;
+                               else
+                                       ll->src_addr = cur_ll->src_addr;
+                               if (ctrl->di)
+                                       ll->dest_addr =
+                                           cur_ll->dest_addr +
+                                           dest_width * new_len * count;
+                               else
+                                       ll->dest_addr = cur_ll->dest_addr;
+                               ll->ch_ctrl = cur_ll->ch_ctrl & 0x7fffffff;
+                               ll->next_dma = 0;
+                               ll->next = NULL;
+                               num_entries--;
+                               count++;
+                       }
+
+                       ll->next_dma = ll_dma_old;
+                       ll->next = ll_old;
+               }
+               /* adjust last length/tc */
+               ll->ch_ctrl = cur_ll->ch_ctrl & (~0x7ff);
+               ll->ch_ctrl |= old_len - new_len * (count - 1);
+               cur_ll->ch_ctrl &= 0x7fffffff;
+       }
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_split_ll_entry);
+
+int pnx4008_config_channel(int ch, struct pnx4008_dma_config * config)
+{
+       if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
+               return -EINVAL;
+
+       pnx4008_dma_lock();
+       __raw_writel(config->src_addr, DMAC_Cx_SRC_ADDR(ch));
+       __raw_writel(config->dest_addr, DMAC_Cx_DEST_ADDR(ch));
+
+       if (config->is_ll)
+               __raw_writel(config->ll_dma, DMAC_Cx_LLI(ch));
+       else
+               __raw_writel(0, DMAC_Cx_LLI(ch));
+
+       __raw_writel(config->ch_ctrl, DMAC_Cx_CONTROL(ch));
+       __raw_writel(config->ch_cfg, DMAC_Cx_CONFIG(ch));
+       pnx4008_dma_unlock();
+
+       return 0;
+
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_config_channel);
+
+int pnx4008_channel_get_config(int ch, struct pnx4008_dma_config * config)
+{
+       if (!VALID_CHANNEL(ch) || !dma_channels[ch].name || !config)
+               return -EINVAL;
+
+       pnx4008_dma_lock();
+       config->ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
+       config->ch_ctrl = __raw_readl(DMAC_Cx_CONTROL(ch));
+
+       config->ll_dma = __raw_readl(DMAC_Cx_LLI(ch));
+       config->is_ll = config->ll_dma ? 1 : 0;
+
+       config->src_addr = __raw_readl(DMAC_Cx_SRC_ADDR(ch));
+       config->dest_addr = __raw_readl(DMAC_Cx_DEST_ADDR(ch));
+       pnx4008_dma_unlock();
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_channel_get_config);
+
+int pnx4008_dma_ch_enable(int ch)
+{
+       unsigned long ch_cfg;
+
+       if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
+               return -EINVAL;
+
+       pnx4008_dma_lock();
+       ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
+       ch_cfg |= 1;
+       __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
+       pnx4008_dma_unlock();
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enable);
+
+int pnx4008_dma_ch_disable(int ch)
+{
+       unsigned long ch_cfg;
+
+       if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
+               return -EINVAL;
+
+       pnx4008_dma_lock();
+       ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
+       ch_cfg &= ~1;
+       __raw_writel(ch_cfg, DMAC_Cx_CONFIG(ch));
+       pnx4008_dma_unlock();
+
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_ch_disable);
+
+int pnx4008_dma_ch_enabled(int ch)
+{
+       unsigned long ch_cfg;
+
+       if (!VALID_CHANNEL(ch) || !dma_channels[ch].name)
+               return -EINVAL;
+
+       pnx4008_dma_lock();
+       ch_cfg = __raw_readl(DMAC_Cx_CONFIG(ch));
+       pnx4008_dma_unlock();
+
+       return ch_cfg & 1;
+}
+
+EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
+
+static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+       int i;
+       unsigned long dint = __raw_readl(DMAC_INT_STAT);
+       unsigned long tcint = __raw_readl(DMAC_INT_TC_STAT);
+       unsigned long eint = __raw_readl(DMAC_INT_ERR_STAT);
+       unsigned long i_bit;
+
+       for (i = MAX_DMA_CHANNELS - 1; i >= 0; i--) {
+               i_bit = 1 << i;
+               if (dint & i_bit) {
+                       struct dma_channel *channel = &dma_channels[i];
+
+                       if (channel->name && channel->irq_handler) {
+                               int cause = 0;
+
+                               if (eint & i_bit)
+                                       cause |= DMA_ERR_INT;
+                               if (tcint & i_bit)
+                                       cause |= DMA_TC_INT;
+                               channel->irq_handler(i, cause, channel->data,
+                                                    regs);
+                       } else {
+                               /*
+                                * IRQ for an unregistered DMA channel
+                                */
+                               printk(KERN_WARNING
+                                      "spurious IRQ for DMA channel %d\n", i);
+                       }
+                       if (tcint & i_bit)
+                               __raw_writel(i_bit, DMAC_INT_TC_CLEAR);
+                       if (eint & i_bit)
+                               __raw_writel(i_bit, DMAC_INT_ERR_CLEAR);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static int __init pnx4008_dma_init(void)
+{
+       int ret, i;
+
+       ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
+       if (ret) {
+               printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
+               goto out;
+       }
+
+       ll_pool.count = 0x4000 / sizeof(struct pnx4008_dma_ll);
+       ll_pool.cur = ll_pool.vaddr =
+           dma_alloc_coherent(NULL, ll_pool.count * sizeof(struct pnx4008_dma_ll),
+                              &ll_pool.dma_addr, GFP_KERNEL);
+
+       if (!ll_pool.vaddr) {
+               ret = -ENOMEM;
+               free_irq(DMA_INT, NULL);
+               goto out;
+       }
+
+       for (i = 0; i < ll_pool.count - 1; i++) {
+               void **addr = ll_pool.vaddr + i * sizeof(struct pnx4008_dma_ll);
+               *addr = (void *)addr + sizeof(struct pnx4008_dma_ll);
+       }
+       *(long *)(ll_pool.vaddr +
+                 (ll_pool.count - 1) * sizeof(struct pnx4008_dma_ll)) =
+           (long)ll_pool.vaddr;
+
+       __raw_writel(1, DMAC_CONFIG);
+
+out:
+       return ret;
+}
+arch_initcall(pnx4008_dma_init);
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/gpio.c
+ *
+ * PNX4008 GPIO driver
+ *
+ * Author: Dmitry Chigirev <source@mvista.com>
+ *
+ * Based on reference code by Iwo Mergler and Z.Tabaaloute from Philips:
+ * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <asm/arch/platform.h>
+#include <asm/arch/gpio.h>
+
+/* register definitions */
+#define PIO_VA_BASE    IO_ADDRESS(PNX4008_PIO_BASE)
+
+#define PIO_INP_STATE  (0x00U)
+#define PIO_OUTP_SET   (0x04U)
+#define PIO_OUTP_CLR   (0x08U)
+#define PIO_OUTP_STATE (0x0CU)
+#define PIO_DRV_SET    (0x10U)
+#define PIO_DRV_CLR    (0x14U)
+#define PIO_DRV_STATE  (0x18U)
+#define PIO_SDINP_STATE        (0x1CU)
+#define PIO_SDOUTP_SET (0x20U)
+#define PIO_SDOUTP_CLR (0x24U)
+#define PIO_MUX_SET    (0x28U)
+#define PIO_MUX_CLR    (0x2CU)
+#define PIO_MUX_STATE  (0x30U)
+
+static inline void gpio_lock(void)
+{
+       local_irq_disable();
+}
+
+static inline void gpio_unlock(void)
+{
+       local_irq_enable();
+}
+
+/* Inline functions */
+static inline int gpio_read_bit(u32 reg, int gpio)
+{
+       u32 bit, val;
+       int ret = -EFAULT;
+
+       if (gpio < 0)
+               goto out;
+
+       bit = GPIO_BIT(gpio);
+       if (bit) {
+               val = __raw_readl(PIO_VA_BASE + reg);
+               ret = (val & bit) ? 1 : 0;
+       }
+out:
+       return ret;
+}
+
+static inline int gpio_set_bit(u32 reg, int gpio)
+{
+       u32 bit, val;
+       int ret = -EFAULT;
+
+       if (gpio < 0)
+               goto out;
+
+       bit = GPIO_BIT(gpio);
+       if (bit) {
+               val = __raw_readl(PIO_VA_BASE + reg);
+               val |= bit;
+               __raw_writel(val, PIO_VA_BASE + reg);
+               ret = 0;
+       }
+out:
+       return ret;
+}
+
+/* Very simple access control, bitmap for allocated/free */
+static unsigned long access_map[4];
+#define INP_INDEX      0
+#define OUTP_INDEX     1
+#define GPIO_INDEX     2
+#define MUX_INDEX      3
+
+/*GPIO to Input Mapping */
+static short gpio_to_inp_map[32] = {
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, 10, 11, 12, 13, 14, 24, -1
+};
+
+/*GPIO to Mux Mapping */
+static short gpio_to_mux_map[32] = {
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, 0, 1, 4, 5, -1
+};
+
+/*Output to Mux Mapping */
+static short outp_to_mux_map[32] = {
+       -1, -1, -1, 6, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1,
+       -1, -1, -1, -1, -1, 2, -1, -1,
+       -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+int pnx4008_gpio_register_pin(unsigned short pin)
+{
+       unsigned long bit = GPIO_BIT(pin);
+       int ret = -EBUSY;       /* Already in use */
+
+       gpio_lock();
+
+       if (GPIO_ISBID(pin)) {
+               if (access_map[GPIO_INDEX] & bit)
+                       goto out;
+               access_map[GPIO_INDEX] |= bit;
+
+       } else if (GPIO_ISRAM(pin)) {
+               if (access_map[GPIO_INDEX] & bit)
+                       goto out;
+               access_map[GPIO_INDEX] |= bit;
+
+       } else if (GPIO_ISMUX(pin)) {
+               if (access_map[MUX_INDEX] & bit)
+                       goto out;
+               access_map[MUX_INDEX] |= bit;
+
+       } else if (GPIO_ISOUT(pin)) {
+               if (access_map[OUTP_INDEX] & bit)
+                       goto out;
+               access_map[OUTP_INDEX] |= bit;
+
+       } else if (GPIO_ISIN(pin)) {
+               if (access_map[INP_INDEX] & bit)
+                       goto out;
+               access_map[INP_INDEX] |= bit;
+       } else
+               goto out;
+       ret = 0;
+
+out:
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_register_pin);
+
+int pnx4008_gpio_unregister_pin(unsigned short pin)
+{
+       unsigned long bit = GPIO_BIT(pin);
+       int ret = -EFAULT;      /* Not registered */
+
+       gpio_lock();
+
+       if (GPIO_ISBID(pin)) {
+               if (~access_map[GPIO_INDEX] & bit)
+                       goto out;
+               access_map[GPIO_INDEX] &= ~bit;
+       } else if (GPIO_ISRAM(pin)) {
+               if (~access_map[GPIO_INDEX] & bit)
+                       goto out;
+               access_map[GPIO_INDEX] &= ~bit;
+       } else if (GPIO_ISMUX(pin)) {
+               if (~access_map[MUX_INDEX] & bit)
+                       goto out;
+               access_map[MUX_INDEX] &= ~bit;
+       } else if (GPIO_ISOUT(pin)) {
+               if (~access_map[OUTP_INDEX] & bit)
+                       goto out;
+               access_map[OUTP_INDEX] &= ~bit;
+       } else if (GPIO_ISIN(pin)) {
+               if (~access_map[INP_INDEX] & bit)
+                       goto out;
+               access_map[INP_INDEX] &= ~bit;
+       } else
+               goto out;
+       ret = 0;
+
+out:
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_unregister_pin);
+
+unsigned long pnx4008_gpio_read_pin(unsigned short pin)
+{
+       unsigned long ret = -EFAULT;
+       int gpio = GPIO_BIT_MASK(pin);
+       gpio_lock();
+       if (GPIO_ISOUT(pin)) {
+               ret = gpio_read_bit(PIO_OUTP_STATE, gpio);
+       } else if (GPIO_ISRAM(pin)) {
+               if (gpio_read_bit(PIO_DRV_STATE, gpio) == 0) {
+                       ret = gpio_read_bit(PIO_SDINP_STATE, gpio);
+               }
+       } else if (GPIO_ISBID(pin)) {
+               ret = gpio_read_bit(PIO_DRV_STATE, gpio);
+               if (ret > 0)
+                       ret = gpio_read_bit(PIO_OUTP_STATE, gpio);
+               else if (ret == 0)
+                       ret =
+                           gpio_read_bit(PIO_INP_STATE, gpio_to_inp_map[gpio]);
+       } else if (GPIO_ISIN(pin)) {
+               ret = gpio_read_bit(PIO_INP_STATE, gpio);
+       }
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_read_pin);
+
+/* Write Value to output */
+int pnx4008_gpio_write_pin(unsigned short pin, int output)
+{
+       int gpio = GPIO_BIT_MASK(pin);
+       int ret = -EFAULT;
+
+       gpio_lock();
+       if (GPIO_ISOUT(pin)) {
+               printk( "writing '%x' to '%x'\n",
+                               gpio, output ? PIO_OUTP_SET : PIO_OUTP_CLR );
+               ret = gpio_set_bit(output ? PIO_OUTP_SET : PIO_OUTP_CLR, gpio);
+       } else if (GPIO_ISRAM(pin)) {
+               if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0)
+                       ret = gpio_set_bit(output ? PIO_SDOUTP_SET :
+                                          PIO_SDOUTP_CLR, gpio);
+       } else if (GPIO_ISBID(pin)) {
+               if (gpio_read_bit(PIO_DRV_STATE, gpio) > 0)
+                       ret = gpio_set_bit(output ? PIO_OUTP_SET :
+                                          PIO_OUTP_CLR, gpio);
+       }
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_write_pin);
+
+/* Value = 1 : Set GPIO pin as output */
+/* Value = 0 : Set GPIO pin as input */
+int pnx4008_gpio_set_pin_direction(unsigned short pin, int output)
+{
+       int gpio = GPIO_BIT_MASK(pin);
+       int ret = -EFAULT;
+
+       gpio_lock();
+       if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) {
+               ret = gpio_set_bit(output ? PIO_DRV_SET : PIO_DRV_CLR, gpio);
+       }
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_set_pin_direction);
+
+/* Read GPIO pin direction: 0= pin used as input, 1= pin used as output*/
+int pnx4008_gpio_read_pin_direction(unsigned short pin)
+{
+       int gpio = GPIO_BIT_MASK(pin);
+       int ret = -EFAULT;
+
+       gpio_lock();
+       if (GPIO_ISBID(pin) || GPIO_ISRAM(pin)) {
+               ret = gpio_read_bit(PIO_DRV_STATE, gpio);
+       }
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_read_pin_direction);
+
+/* Value = 1 : Set pin to muxed function  */
+/* Value = 0 : Set pin as GPIO */
+int pnx4008_gpio_set_pin_mux(unsigned short pin, int output)
+{
+       int gpio = GPIO_BIT_MASK(pin);
+       int ret = -EFAULT;
+
+       gpio_lock();
+       if (GPIO_ISBID(pin)) {
+               ret =
+                   gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR,
+                                gpio_to_mux_map[gpio]);
+       } else if (GPIO_ISOUT(pin)) {
+               ret =
+                   gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR,
+                                outp_to_mux_map[gpio]);
+       } else if (GPIO_ISMUX(pin)) {
+               ret = gpio_set_bit(output ? PIO_MUX_SET : PIO_MUX_CLR, gpio);
+       }
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_set_pin_mux);
+
+/* Read pin mux function: 0= pin used as GPIO, 1= pin used for muxed function*/
+int pnx4008_gpio_read_pin_mux(unsigned short pin)
+{
+       int gpio = GPIO_BIT_MASK(pin);
+       int ret = -EFAULT;
+
+       gpio_lock();
+       if (GPIO_ISBID(pin)) {
+               ret = gpio_read_bit(PIO_MUX_STATE, gpio_to_mux_map[gpio]);
+       } else if (GPIO_ISOUT(pin)) {
+               ret = gpio_read_bit(PIO_MUX_STATE, outp_to_mux_map[gpio]);
+       } else if (GPIO_ISMUX(pin)) {
+               ret = gpio_read_bit(PIO_MUX_STATE, gpio);
+       }
+       gpio_unlock();
+       return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_gpio_read_pin_mux);
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/irq.c
+ *
+ * PNX4008 IRQ controller driver
+ *
+ * Author: Dmitry Chigirev <source@mvista.com>
+ *
+ * Based on reference code received from Philips:
+ * Copyright (C) 2003 Philips Semiconductors
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/map.h>
+#include <asm/arch/irq.h>
+
+static u8 pnx4008_irq_type[NR_IRQS] = PNX4008_IRQ_TYPES;
+
+static void pnx4008_mask_irq(unsigned int irq)
+{
+       __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */
+}
+
+static void pnx4008_unmask_irq(unsigned int irq)
+{
+       __raw_writel(__raw_readl(INTC_ER(irq)) | INTC_BIT(irq), INTC_ER(irq));  /* unmask interrupt */
+}
+
+static void pnx4008_mask_ack_irq(unsigned int irq)
+{
+       __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */
+       __raw_writel(INTC_BIT(irq), INTC_SR(irq));      /* clear interrupt status */
+}
+
+static int pnx4008_set_irq_type(unsigned int irq, unsigned int type)
+{
+       switch (type) {
+       case IRQT_RISING:
+               __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq));        /*edge sensitive */
+               __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq));        /*rising edge */
+               set_irq_handler(irq, do_edge_IRQ);
+               break;
+       case IRQT_FALLING:
+               __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq));        /*edge sensitive */
+               __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq));       /*falling edge */
+               set_irq_handler(irq, do_edge_IRQ);
+               break;
+       case IRQT_LOW:
+               __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq));       /*level sensitive */
+               __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq));       /*low level */
+               set_irq_handler(irq, do_level_IRQ);
+               break;
+       case IRQT_HIGH:
+               __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq));       /*level sensitive */
+               __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq));        /* high level */
+               set_irq_handler(irq, do_level_IRQ);
+               break;
+
+       /* IRQT_BOTHEDGE is not supported */
+       default:
+               printk(KERN_ERR "PNX4008 IRQ: Unsupported irq type %d\n", type);
+               return -1;
+       }
+       return 0;
+}
+
+static struct irqchip pnx4008_irq_chip = {
+       .ack = pnx4008_mask_ack_irq,
+       .mask = pnx4008_mask_irq,
+       .unmask = pnx4008_unmask_irq,
+       .set_type = pnx4008_set_irq_type,
+};
+
+void __init pnx4008_init_irq(void)
+{
+       unsigned int i;
+
+       /* configure and enable IRQ 0,1,30,31 (cascade interrupts) mask all others */
+       pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]);
+       pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]);
+       pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]);
+       pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]);
+
+       __raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) |
+                       (1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N),
+               INTC_ER(MAIN_BASE_INT));
+       __raw_writel(0, INTC_ER(SIC1_BASE_INT));
+       __raw_writel(0, INTC_ER(SIC2_BASE_INT));
+
+       /* configure all other IRQ's */
+       for (i = 0; i < NR_IRQS; i++) {
+               if (i == SUB2_FIQ_N || i == SUB1_FIQ_N ||
+                       i == SUB2_IRQ_N || i == SUB1_IRQ_N)
+                       continue;
+               set_irq_flags(i, IRQF_VALID);
+               set_irq_chip(i, &pnx4008_irq_chip);
+               pnx4008_set_irq_type(i, pnx4008_irq_type[i]);
+       }
+}
+
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/pm.c
+ *
+ * Power Management driver for PNX4008
+ *
+ * Authors: Vitaly Wool, Dmitry Chigirev <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/pm.h>
+#include <linux/rtc.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/pm.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/cacheflush.h>
+#include <asm/arch/pm.h>
+#include <asm/arch/clock.h>
+
+#define SRAM_VA IO_ADDRESS(PNX4008_IRAM_BASE)
+
+static void *saved_sram;
+
+static struct clk *pll4_clk;
+
+static inline void pnx4008_standby(void)
+{
+       void (*pnx4008_cpu_standby_ptr) (void);
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       clk_disable(pll4_clk);
+
+       /*saving portion of SRAM to be used by suspend function. */
+       memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_standby_sz);
+
+       /*make sure SRAM copy gets physically written into SDRAM.
+          SDRAM will be placed into self-refresh during power down */
+       flush_cache_all();
+
+       /*copy suspend function into SRAM */
+       memcpy((void *)SRAM_VA, pnx4008_cpu_standby, pnx4008_cpu_standby_sz);
+
+       /*do suspend */
+       pnx4008_cpu_standby_ptr = (void *)SRAM_VA;
+       pnx4008_cpu_standby_ptr();
+
+       /*restoring portion of SRAM that was used by suspend function */
+       memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_standby_sz);
+
+       clk_enable(pll4_clk);
+
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static inline void pnx4008_suspend(void)
+{
+       void (*pnx4008_cpu_suspend_ptr) (void);
+
+       local_irq_disable();
+       local_fiq_disable();
+
+       clk_disable(pll4_clk);
+
+       __raw_writel(0xffffffff, START_INT_RSR_REG(SE_PIN_BASE_INT));
+       __raw_writel(0xffffffff, START_INT_RSR_REG(SE_INT_BASE_INT));
+
+       /*saving portion of SRAM to be used by suspend function. */
+       memcpy(saved_sram, (void *)SRAM_VA, pnx4008_cpu_suspend_sz);
+
+       /*make sure SRAM copy gets physically written into SDRAM.
+          SDRAM will be placed into self-refresh during power down */
+       flush_cache_all();
+
+       /*copy suspend function into SRAM */
+       memcpy((void *)SRAM_VA, pnx4008_cpu_suspend, pnx4008_cpu_suspend_sz);
+
+       /*do suspend */
+       pnx4008_cpu_suspend_ptr = (void *)SRAM_VA;
+       pnx4008_cpu_suspend_ptr();
+
+       /*restoring portion of SRAM that was used by suspend function */
+       memcpy((void *)SRAM_VA, saved_sram, pnx4008_cpu_suspend_sz);
+
+       clk_enable(pll4_clk);
+
+       local_fiq_enable();
+       local_irq_enable();
+}
+
+static int pnx4008_pm_enter(suspend_state_t state)
+{
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+               pnx4008_standby();
+               break;
+       case PM_SUSPEND_MEM:
+               pnx4008_suspend();
+               break;
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/*
+ * Called after processes are frozen, but before we shut down devices.
+ */
+static int pnx4008_pm_prepare(suspend_state_t state)
+{
+       switch (state) {
+       case PM_SUSPEND_STANDBY:
+       case PM_SUSPEND_MEM:
+               break;
+
+       case PM_SUSPEND_DISK:
+               return -ENOTSUPP;
+               break;
+
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
+/*
+ * Called after devices are re-setup, but before processes are thawed.
+ */
+static int pnx4008_pm_finish(suspend_state_t state)
+{
+       return 0;
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static struct pm_ops pnx4008_pm_ops = {
+       .prepare = pnx4008_pm_prepare,
+       .enter = pnx4008_pm_enter,
+       .finish = pnx4008_pm_finish,
+};
+
+static int __init pnx4008_pm_init(void)
+{
+       u32 sram_size_to_allocate;
+
+       pll4_clk = clk_get(0, "ck_pll4");
+       if (IS_ERR(pll4_clk)) {
+               printk(KERN_ERR
+                      "PM Suspend cannot acquire ARM(PLL4) clock control\n");
+               return PTR_ERR(pll4_clk);
+       }
+
+       if (pnx4008_cpu_standby_sz > pnx4008_cpu_suspend_sz)
+               sram_size_to_allocate = pnx4008_cpu_standby_sz;
+       else
+               sram_size_to_allocate = pnx4008_cpu_suspend_sz;
+
+       saved_sram = kmalloc(sram_size_to_allocate, GFP_ATOMIC);
+       if (!saved_sram) {
+               printk(KERN_ERR
+                      "PM Suspend: cannot allocate memory to save portion of SRAM\n");
+               clk_put(pll4_clk);
+               return -ENOMEM;
+       }
+
+       pm_set_ops(&pnx4008_pm_ops);
+       return 0;
+}
+
+late_initcall(pnx4008_pm_init);
 
--- /dev/null
+/*
+ *  linux/arch/arm/mach-pnx4008/serial.c
+ *
+ *  PNX4008 UART initialization
+ *
+ *  Copyright: MontaVista Software Inc. (c) 2005
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/platform.h>
+#include <asm/arch/hardware.h>
+
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <asm/arch/pm.h>
+
+#include <asm/arch/clock.h>
+
+#define UART_3         0
+#define UART_4         1
+#define UART_5         2
+#define UART_6         3
+#define UART_UNKNOWN   (-1)
+
+#define UART3_BASE_VA  IO_ADDRESS(PNX4008_UART3_BASE)
+#define UART4_BASE_VA  IO_ADDRESS(PNX4008_UART4_BASE)
+#define UART5_BASE_VA  IO_ADDRESS(PNX4008_UART5_BASE)
+#define UART6_BASE_VA  IO_ADDRESS(PNX4008_UART6_BASE)
+
+#define UART_FCR_OFFSET                8
+#define UART_FIFO_SIZE         64
+
+void pnx4008_uart_init(void)
+{
+       u32 tmp;
+       int i = UART_FIFO_SIZE;
+
+       __raw_writel(0xC1, UART5_BASE_VA + UART_FCR_OFFSET);
+       __raw_writel(0xC1, UART3_BASE_VA + UART_FCR_OFFSET);
+
+       /* Send a NULL to fix the UART HW bug */
+       __raw_writel(0x00, UART5_BASE_VA);
+       __raw_writel(0x00, UART3_BASE_VA);
+
+       while (i--) {
+               tmp = __raw_readl(UART5_BASE_VA);
+               tmp = __raw_readl(UART3_BASE_VA);
+       }
+       __raw_writel(0, UART5_BASE_VA + UART_FCR_OFFSET);
+       __raw_writel(0, UART3_BASE_VA + UART_FCR_OFFSET);
+
+       /* setup wakeup interrupt */
+       start_int_set_rising_edge(SE_U3_RX_INT);
+       start_int_ack(SE_U3_RX_INT);
+       start_int_umask(SE_U3_RX_INT);
+
+       start_int_set_rising_edge(SE_U5_RX_INT);
+       start_int_ack(SE_U5_RX_INT);
+       start_int_umask(SE_U5_RX_INT);
+}
+
 
--- /dev/null
+/*
+ * linux/arch/arm/mach-pnx4008/sleep.S
+ *
+ * PNX4008 support for STOP mode and SDRAM self-refresh
+ *
+ * Authors: Dmitry Chigirev, Vitaly Wool <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+#define PWRMAN_VA_BASE IO_ADDRESS(PNX4008_PWRMAN_BASE)
+#define PWR_CTRL_REG_OFFS 0x44
+
+#define SDRAM_CFG_VA_BASE IO_ADDRESS(PNX4008_SDRAM_CFG_BASE)
+#define MPMC_STATUS_REG_OFFS 0x4
+
+               .text
+
+ENTRY(pnx4008_cpu_suspend)
+       @this function should be entered in Direct run mode.
+
+       @ save registers on stack
+       stmfd   sp!, {r0 - r6, lr}
+
+       @ setup Power Manager base address in r4
+       @ and put it's value in r5
+       mov     r4, #(PWRMAN_VA_BASE & 0xff000000)
+       orr     r4, r4, #(PWRMAN_VA_BASE & 0x00ff0000)
+       orr     r4, r4, #(PWRMAN_VA_BASE & 0x0000ff00)
+       orr     r4, r4, #(PWRMAN_VA_BASE & 0x000000ff)
+       ldr     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ setup SDRAM controller base address in r2
+       @ and put it's value in r3
+       mov     r2, #(SDRAM_CFG_VA_BASE & 0xff000000)
+       orr     r2, r2, #(SDRAM_CFG_VA_BASE & 0x00ff0000)
+       orr     r2, r2, #(SDRAM_CFG_VA_BASE & 0x0000ff00)
+       orr     r2, r2, #(SDRAM_CFG_VA_BASE & 0x000000ff)
+       ldr     r3, [r2, #MPMC_STATUS_REG_OFFS] @extra read - HW bug workaround
+
+       @ clear SDRAM self-refresh bit latch
+       and     r5, r5, #(~(1 << 8))
+       @ clear SDRAM self-refresh bit
+       and     r5, r5, #(~(1 << 9))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ do save current bit settings in r1
+       mov     r1, r5
+
+       @ set SDRAM self-refresh bit
+       orr     r5, r5, #(1 << 9)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ set SDRAM self-refresh bit latch
+       orr     r5, r5, #(1 << 8)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ clear SDRAM self-refresh bit latch
+       and     r5, r5, #(~(1 << 8))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ clear SDRAM self-refresh bit
+       and     r5, r5, #(~(1 << 9))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ wait for SDRAM to get into self-refresh mode
+2:     ldr     r3, [r2, #MPMC_STATUS_REG_OFFS]
+       tst     r3, #(1 << 2)
+       beq     2b
+
+       @ to prepare SDRAM to get out of self-refresh mode after wakeup
+       orr     r5, r5, #(1 << 7)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ do enter stop mode
+       orr     r5, r5, #(1 << 0)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+       nop
+
+       @ sleeping now...
+
+       @ coming out of STOP mode into Direct Run mode
+       @ clear STOP mode and SDRAM self-refresh bits
+       str     r1, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ wait for SDRAM to get out self-refresh mode
+3:     ldr     r3, [r2, #MPMC_STATUS_REG_OFFS]
+       tst     r3, #5
+       bne     3b
+
+       @ restore regs and return
+       ldmfd   sp!, {r0 - r6, pc}
+
+ENTRY(pnx4008_cpu_suspend_sz)
+       .word   . - pnx4008_cpu_suspend
+
+ENTRY(pnx4008_cpu_standby)
+       @ save registers on stack
+       stmfd   sp!, {r0 - r6, lr}
+
+       @ setup Power Manager base address in r4
+       @ and put it's value in r5
+       mov     r4, #(PWRMAN_VA_BASE & 0xff000000)
+       orr     r4, r4, #(PWRMAN_VA_BASE & 0x00ff0000)
+       orr     r4, r4, #(PWRMAN_VA_BASE & 0x0000ff00)
+       orr     r4, r4, #(PWRMAN_VA_BASE & 0x000000ff)
+       ldr     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ setup SDRAM controller base address in r2
+       @ and put it's value in r3
+       mov     r2, #(SDRAM_CFG_VA_BASE & 0xff000000)
+       orr     r2, r2, #(SDRAM_CFG_VA_BASE & 0x00ff0000)
+       orr     r2, r2, #(SDRAM_CFG_VA_BASE & 0x0000ff00)
+       orr     r2, r2, #(SDRAM_CFG_VA_BASE & 0x000000ff)
+       ldr     r3, [r2, #MPMC_STATUS_REG_OFFS] @extra read - HW bug workaround
+
+       @ clear SDRAM self-refresh bit latch
+       and     r5, r5, #(~(1 << 8))
+       @ clear SDRAM self-refresh bit
+       and     r5, r5, #(~(1 << 9))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ do save current bit settings in r1
+       mov     r1, r5
+
+       @ set SDRAM self-refresh bit
+       orr     r5, r5, #(1 << 9)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ set SDRAM self-refresh bit latch
+       orr     r5, r5, #(1 << 8)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ clear SDRAM self-refresh bit latch
+       and     r5, r5, #(~(1 << 8))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ clear SDRAM self-refresh bit
+       and     r5, r5, #(~(1 << 9))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ wait for SDRAM to get into self-refresh mode
+2:     ldr     r3, [r2, #MPMC_STATUS_REG_OFFS]
+       tst     r3, #(1 << 2)
+       beq     2b
+
+       @ set 'get out of self-refresh mode after wakeup' bit
+       orr     r5, r5, #(1 << 7)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       mcr     p15, 0, r0, c7, c0, 4   @ kinda sleeping now...
+
+       @ set SDRAM self-refresh bit latch
+       orr     r5, r5, #(1 << 8)
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ clear SDRAM self-refresh bit latch
+       and     r5, r5, #(~(1 << 8))
+       str     r5, [r4, #PWR_CTRL_REG_OFFS]
+
+       @ wait for SDRAM to get out self-refresh mode
+3:     ldr     r3, [r2, #MPMC_STATUS_REG_OFFS]
+       tst     r3, #5
+       bne     3b
+
+       @ restore regs and return
+       ldmfd   sp!, {r0 - r6, pc}
+
+ENTRY(pnx4008_cpu_standby_sz)
+       .word   . - pnx4008_cpu_standby
+
+ENTRY(pnx4008_cache_clean_invalidate)
+       stmfd   sp!, {r0 - r6, lr}
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+       mcr     p15, 0, ip, c7, c6, 0           @ invalidate D cache
+#else
+1:     mrc     p15, 0, r15, c7, c14, 3         @ test,clean,invalidate
+       bne     1b
+#endif
+       ldmfd   sp!, {r0 - r6, pc}
 
--- /dev/null
+/*
+ * arch/arm/mach-pnx4008/time.c
+ *
+ * PNX4008 Timers
+ *
+ * Authors: Vitaly Wool, Dmitry Chigirev, Grigory Tolstolytkin <source@mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/leds.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <asm/errno.h>
+
+/*! Note: all timers are UPCOUNTING */
+
+/*!
+ * Returns number of us since last clock interrupt.  Note that interrupts
+ * will have been disabled by do_gettimeoffset()
+ */
+static unsigned long pnx4008_gettimeoffset(void)
+{
+       u32 ticks_to_match =
+           __raw_readl(HSTIM_MATCH0) - __raw_readl(HSTIM_COUNTER);
+       u32 elapsed = LATCH - ticks_to_match;
+       return (elapsed * (tick_nsec / 1000)) / LATCH;
+}
+
+/*!
+ * IRQ handler for the timer
+ */
+static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id,
+                                          struct pt_regs *regs)
+{
+       if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
+
+               write_seqlock(&xtime_lock);
+
+               do {
+                       timer_tick(regs);
+
+                       /*
+                        * this algorithm takes care of possible delay
+                        * for this interrupt handling longer than a normal
+                        * timer period
+                        */
+                       __raw_writel(__raw_readl(HSTIM_MATCH0) + LATCH,
+                                    HSTIM_MATCH0);
+                       __raw_writel(MATCH0_INT, HSTIM_INT);    /* clear interrupt */
+
+                       /*
+                        * The goal is to keep incrementing HSTIM_MATCH0
+                        * register until HSTIM_MATCH0 indicates time after
+                        * what HSTIM_COUNTER indicates.
+                        */
+               } while ((signed)
+                        (__raw_readl(HSTIM_MATCH0) -
+                         __raw_readl(HSTIM_COUNTER)) < 0);
+
+               write_sequnlock(&xtime_lock);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction pnx4008_timer_irq = {
+       .name = "PNX4008 Tick Timer",
+       .flags = SA_INTERRUPT | SA_TIMER,
+       .handler = pnx4008_timer_interrupt
+};
+
+/*!
+ * Set up timer and timer interrupt.
+ */
+static __init void pnx4008_setup_timer(void)
+{
+       __raw_writel(RESET_COUNT, MSTIM_CTRL);
+       while (__raw_readl(MSTIM_COUNTER)) ;    /* wait for reset to complete. 100% guarantee event */
+       __raw_writel(0, MSTIM_CTRL);    /* stop the timer */
+       __raw_writel(0, MSTIM_MCTRL);
+
+       __raw_writel(RESET_COUNT, HSTIM_CTRL);
+       while (__raw_readl(HSTIM_COUNTER)) ;    /* wait for reset to complete. 100% guarantee event */
+       __raw_writel(0, HSTIM_CTRL);
+       __raw_writel(0, HSTIM_MCTRL);
+       __raw_writel(0, HSTIM_CCR);
+       __raw_writel(12, HSTIM_PMATCH); /* scale down to 1 MHZ */
+       __raw_writel(LATCH, HSTIM_MATCH0);
+       __raw_writel(MR0_INT, HSTIM_MCTRL);
+
+       setup_irq(HSTIMER_INT, &pnx4008_timer_irq);
+
+       __raw_writel(COUNT_ENAB | DEBUG_EN, HSTIM_CTRL);        /*start timer, stop when JTAG active */
+}
+
+/* Timer Clock Control in PM register */
+#define TIMCLK_CTRL_REG  IO_ADDRESS((PNX4008_PWRMAN_BASE + 0xBC))
+#define WATCHDOG_CLK_EN                   1
+#define TIMER_CLK_EN                      2    /* HS and MS timers? */
+
+static u32 timclk_ctrl_reg_save;
+
+void pnx4008_timer_suspend(void)
+{
+       timclk_ctrl_reg_save = __raw_readl(TIMCLK_CTRL_REG);
+       __raw_writel(0, TIMCLK_CTRL_REG);       /* disable timers */
+}
+
+void pnx4008_timer_resume(void)
+{
+       __raw_writel(timclk_ctrl_reg_save, TIMCLK_CTRL_REG);    /* enable timers */
+}
+
+struct sys_timer pnx4008_timer = {
+       .init = pnx4008_setup_timer,
+       .offset = pnx4008_gettimeoffset,
+       .suspend = pnx4008_timer_suspend,
+       .resume = pnx4008_timer_resume,
+};
+
 
 # ARM926T
 config CPU_ARM926T
        bool "Support ARM926T processor"
-       depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB
-       default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX
+       depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008
+       default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008
        select CPU_32v5
        select CPU_ABRT_EV5TJ
        select CPU_CACHE_VIVT