++ struct gpio_item *gpio = dev_id;
++ u32 old_state, new_state;
++
++ old_state = gpio->pin_state;
++ new_state = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
++ gpio->pin_state = new_state;
++
++ if (new_state != old_state) {
++ gpio->changed = 1;
++ wake_up_interruptible(&gpio->change_wq);
++
++ if (gpio->async_queue)
++ kill_fasync(&gpio->async_queue, SIGIO, POLL_IN);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static int gpio_dev_open(struct inode *inode, struct file *file)
++{
++ struct gpio_item *gpio = container_of(inode->i_cdev,
++ struct gpio_item,
++ char_dev);
++ unsigned int irq;
++ unsigned int i;
++ int ret;
++
++ nonseekable_open(inode, file);
++ config_item_get(&gpio->item);
++ file->private_data = gpio;
++
++ gpio->pin_state = at32_gpio_get_value_multiple(gpio->port,
++ gpio->pin_mask);
++ gpio->changed = 1;
++
++ for (i = 0; i < 32; i++) {
++ if (gpio->pin_mask & (1 << i)) {
++ irq = gpio_to_irq(32 * gpio->port + i);
++ ret = request_irq(irq, gpio_dev_interrupt, 0,
++ "gpio-dev", gpio);
++ if (ret)
++ goto err_irq;
++ }
++ }
++
++ return 0;
++
++err_irq:
++ while (i--) {
++ if (gpio->pin_mask & (1 << i)) {
++ irq = gpio_to_irq(32 * gpio->port + i);
++ free_irq(irq, gpio);
++ }
++ }
++
++ config_item_put(&gpio->item);
++
++ return ret;
++}
++
++static int gpio_dev_fasync(int fd, struct file *file, int mode)
++{
++ struct gpio_item *gpio = file->private_data;
++
++ return fasync_helper(fd, file, mode, &gpio->async_queue);
++}
++
++static int gpio_dev_release(struct inode *inode, struct file *file)
++{
++ struct gpio_item *gpio = file->private_data;
++ unsigned int irq;
++ unsigned int i;
++
++ gpio_dev_fasync(-1, file, 0);
++
++ for (i = 0; i < 32; i++) {
++ if (gpio->pin_mask & (1 << i)) {
++ irq = gpio_to_irq(32 * gpio->port + i);
++ free_irq(irq, gpio);
++ }
++ }
++
++ config_item_put(&gpio->item);
++
++ return 0;
++}
++
++static unsigned int gpio_dev_poll(struct file *file, poll_table *wait)
++{
++ struct gpio_item *gpio = file->private_data;
++ unsigned int mask = 0;
++
++ poll_wait(file, &gpio->change_wq, wait);
++ if (gpio->changed)
++ mask |= POLLIN | POLLRDNORM;
++
++ return mask;
++}
++
++static ssize_t gpio_dev_read(struct file *file, char __user *buf,
++ size_t count, loff_t *offset)
++{
++ struct gpio_item *gpio = file->private_data;
++ u32 value;
++
++ spin_lock_irq(&gpio->lock);
++ while (!gpio->changed) {
++ spin_unlock_irq(&gpio->lock);
++
++ if (file->f_flags & O_NONBLOCK)
++ return -EAGAIN;
++
++ if (wait_event_interruptible(gpio->change_wq, gpio->changed))
++ return -ERESTARTSYS;
++
++ spin_lock_irq(&gpio->lock);
++ }
++
++ gpio->changed = 0;
++ value = at32_gpio_get_value_multiple(gpio->port, gpio->pin_mask);
++
++ spin_unlock_irq(&gpio->lock);
++
++ count = min(count, (size_t)4);
++ if (copy_to_user(buf, &value, count))
++ return -EFAULT;
++
++ return count;
++}
++
++static ssize_t gpio_dev_write(struct file *file, const char __user *buf,
++ size_t count, loff_t *offset)
++{
++ struct gpio_item *gpio = file->private_data;
++ u32 value = 0;
++ u32 mask = ~0UL;
++
++ count = min(count, (size_t)4);
++ if (copy_from_user(&value, buf, count))
++ return -EFAULT;
++
++ /* Assuming big endian */
++ mask <<= (4 - count) * 8;
++ mask &= gpio->pin_mask;
++
++ at32_gpio_set_value_multiple(gpio->port, value, mask);
++
++ return count;
++}
++
++static struct file_operations gpio_dev_fops = {
++ .owner = THIS_MODULE,
++ .llseek = no_llseek,
++ .open = gpio_dev_open,
++ .release = gpio_dev_release,
++ .fasync = gpio_dev_fasync,
++ .poll = gpio_dev_poll,
++ .read = gpio_dev_read,
++ .write = gpio_dev_write,
++};
++
++static struct gpio_item *to_gpio_item(struct config_item *item)
++{
++ return item ? container_of(item, struct gpio_item, item) : NULL;
++}
++
++static ssize_t gpio_show_gpio_id(struct gpio_item *gpio, char *page)
++{
++ return sprintf(page, "%d\n", gpio->port);
++}
++
++static ssize_t gpio_store_gpio_id(struct gpio_item *gpio,
++ const char *page, size_t count)
++{
++ unsigned long id;
++ char *p = (char *)page;
++ ssize_t ret = -EINVAL;
++
++ id = simple_strtoul(p, &p, 0);
++ if (!p || (*p && (*p != '\n')))
++ return -EINVAL;
++
++ /* Switching PIO is not allowed when live... */
++ spin_lock(&gpio->lock);
++ if (!gpio->enabled) {
++ ret = -ENXIO;
++ if (at32_gpio_port_is_valid(id)) {
++ gpio->port = id;
++ ret = count;
++ }
++ }
++ spin_unlock(&gpio->lock);
++
++ return ret;
++}
++
++static ssize_t gpio_show_pin_mask(struct gpio_item *gpio, char *page)
++{
++ return sprintf(page, "0x%08x\n", gpio->pin_mask);
++}
++
++static ssize_t gpio_store_pin_mask(struct gpio_item *gpio,
++ const char *page, size_t count)
++{
++ u32 new_mask;
++ char *p = (char *)page;
++ ssize_t ret = -EINVAL;
++
++ new_mask = simple_strtoul(p, &p, 0);
++ if (!p || (*p && (*p != '\n')))
++ return -EINVAL;
++
++ /* Can't update the pin mask while live. */
++ spin_lock(&gpio->lock);
++ if (!gpio->enabled) {
++ gpio->oe_mask &= new_mask;
++ gpio->pin_mask = new_mask;
++ ret = count;
++ }
++ spin_unlock(&gpio->lock);
++
++ return ret;
++}
++
++static ssize_t gpio_show_oe_mask(struct gpio_item *gpio, char *page)
++{
++ return sprintf(page, "0x%08x\n", gpio->oe_mask);
++}
++
++static ssize_t gpio_store_oe_mask(struct gpio_item *gpio,
++ const char *page, size_t count)
++{
++ u32 mask;
++ char *p = (char *)page;
++ ssize_t ret = -EINVAL;
++
++ mask = simple_strtoul(p, &p, 0);
++ if (!p || (*p && (*p != '\n')))
++ return -EINVAL;
++
++ spin_lock(&gpio->lock);
++ if (!gpio->enabled) {
++ gpio->oe_mask = mask & gpio->pin_mask;
++ ret = count;
++ }
++ spin_unlock(&gpio->lock);
++
++ return ret;
++}
++
++static ssize_t gpio_show_enabled(struct gpio_item *gpio, char *page)
++{
++ return sprintf(page, "%d\n", gpio->enabled);
++}
++
++static ssize_t gpio_store_enabled(struct gpio_item *gpio,
++ const char *page, size_t count)
++{
++ char *p = (char *)page;
++ int enabled;
++ int ret;
++
++ enabled = simple_strtoul(p, &p, 0);
++ if (!p || (*p && (*p != '\n')))
++ return -EINVAL;
++
++ /* make it a boolean value */
++ enabled = !!enabled;
++
++ if (gpio->enabled == enabled)
++ /* No change; do nothing. */
++ return count;
++
++ BUG_ON(gpio->id >= GPIO_DEV_MAX);
++
++ if (!enabled) {
++ class_device_unregister(gpio->gpio_dev);
++ cdev_del(&gpio->char_dev);
++ at32_deselect_pins(gpio->port, gpio->pin_mask);
++ gpio->initialized = 0;
++ } else {
++ if (gpio->port < 0 || !gpio->pin_mask)
++ return -ENODEV;
++ }
++
++ /* Disallow any updates to gpio_id or pin_mask */
++ spin_lock(&gpio->lock);
++ gpio->enabled = enabled;
++ spin_unlock(&gpio->lock);
++
++ if (!enabled)
++ return count;
++
++ /* Now, try to allocate the pins */
++ ret = at32_select_gpio_pins(gpio->port, gpio->pin_mask, gpio->oe_mask);
++ if (ret)
++ goto err_alloc_pins;
++
++ gpio->initialized = 1;
++
++ cdev_init(&gpio->char_dev, &gpio_dev_fops);
++ gpio->char_dev.owner = THIS_MODULE;
++ ret = cdev_add(&gpio->char_dev, MKDEV(MAJOR(gpio_devt), gpio->id), 1);
++ if (ret < 0)
++ goto err_cdev_add;
++ gpio->gpio_dev = class_device_create(gpio_dev_class, NULL,
++ MKDEV(MAJOR(gpio_devt), gpio->id),
++ NULL,
++ "gpio%d", gpio->id);
++ if (IS_ERR(gpio->gpio_dev)) {
++ printk(KERN_ERR "failed to create gpio%d\n", gpio->id);
++ ret = PTR_ERR(gpio->gpio_dev);
++ goto err_class_dev;
++ }
++
++ printk(KERN_INFO "created gpio%d (port%d/0x%08x) as (%d:%d)\n",
++ gpio->id, gpio->port, gpio->pin_mask,
++ MAJOR(gpio->gpio_dev->devt), MINOR(gpio->gpio_dev->devt));
++
++ return 0;
++
++err_class_dev:
++ cdev_del(&gpio->char_dev);
++err_cdev_add:
++ at32_deselect_pins(gpio->port, gpio->pin_mask);
++ gpio->initialized = 0;
++err_alloc_pins:
++ spin_lock(&gpio->lock);
++ gpio->enabled = 0;
++ spin_unlock(&gpio->lock);
++
++ return ret;
++}
++
++static struct gpio_attribute gpio_item_attr_gpio_id = {
++ .attr = {
++ .ca_owner = THIS_MODULE,
++ .ca_name = "gpio_id",
++ .ca_mode = S_IRUGO | S_IWUSR,
++ },
++ .show = gpio_show_gpio_id,
++ .store = gpio_store_gpio_id,
++};
++static struct gpio_attribute gpio_item_attr_pin_mask = {
++ .attr = {
++ .ca_owner = THIS_MODULE,
++ .ca_name = "pin_mask",
++ .ca_mode = S_IRUGO | S_IWUSR,
++ },
++ .show = gpio_show_pin_mask,
++ .store = gpio_store_pin_mask,
++};
++static struct gpio_attribute gpio_item_attr_oe_mask = {
++ .attr = {
++ .ca_owner = THIS_MODULE,
++ .ca_name = "oe_mask",
++ .ca_mode = S_IRUGO | S_IWUSR,
++ },
++ .show = gpio_show_oe_mask,
++ .store = gpio_store_oe_mask,
++};
++static struct gpio_attribute gpio_item_attr_enabled = {
++ .attr = {
++ .ca_owner = THIS_MODULE,
++ .ca_name = "enabled",
++ .ca_mode = S_IRUGO | S_IWUSR,
++ },
++ .show = gpio_show_enabled,
++ .store = gpio_store_enabled,
++};
++
++static struct configfs_attribute *gpio_item_attrs[] = {
++ &gpio_item_attr_gpio_id.attr,
++ &gpio_item_attr_pin_mask.attr,
++ &gpio_item_attr_oe_mask.attr,
++ &gpio_item_attr_enabled.attr,
++ NULL,
++};
++
++static ssize_t gpio_show_attr(struct config_item *item,
++ struct configfs_attribute *attr,
++ char *page)
++{
++ struct gpio_item *gpio_item = to_gpio_item(item);
++ struct gpio_attribute *gpio_attr
++ = container_of(attr, struct gpio_attribute, attr);
++ ssize_t ret = 0;
++
++ if (gpio_attr->show)
++ ret = gpio_attr->show(gpio_item, page);
++ return ret;
++}
++
++static ssize_t gpio_store_attr(struct config_item *item,
++ struct configfs_attribute *attr,
++ const char *page, size_t count)
++{
++ struct gpio_item *gpio_item = to_gpio_item(item);
++ struct gpio_attribute *gpio_attr
++ = container_of(attr, struct gpio_attribute, attr);
++ ssize_t ret = -EINVAL;
++
++ if (gpio_attr->store)
++ ret = gpio_attr->store(gpio_item, page, count);
++ return ret;
++}
++
++static void gpio_release(struct config_item *item)
++{
++ kfree(to_gpio_item(item));
++}
++
++static struct configfs_item_operations gpio_item_ops = {
++ .release = gpio_release,
++ .show_attribute = gpio_show_attr,
++ .store_attribute = gpio_store_attr,
++};
++
++static struct config_item_type gpio_item_type = {
++ .ct_item_ops = &gpio_item_ops,
++ .ct_attrs = gpio_item_attrs,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct config_item *gpio_make_item(struct config_group *group,
++ const char *name)
++{
++ static int next_id;
++ struct gpio_item *gpio;
++
++ if (next_id >= GPIO_DEV_MAX)
++ return NULL;
++
++ gpio = kzalloc(sizeof(struct gpio_item), GFP_KERNEL);
++ if (!gpio)
++ return NULL;
++
++ gpio->id = next_id++;
++ config_item_init_type_name(&gpio->item, name, &gpio_item_type);
++ spin_lock_init(&gpio->lock);
++ init_waitqueue_head(&gpio->change_wq);
++
++ return &gpio->item;
++}
++
++static void gpio_drop_item(struct config_group *group,
++ struct config_item *item)
++{
++ struct gpio_item *gpio = to_gpio_item(item);
++
++ spin_lock(&gpio->lock);
++ if (gpio->enabled) {
++ class_device_unregister(gpio->gpio_dev);
++ cdev_del(&gpio->char_dev);
++ }
++
++ if (gpio->initialized) {
++ at32_deselect_pins(gpio->port, gpio->pin_mask);
++ gpio->initialized = 0;
++ gpio->enabled = 0;
++ }
++ spin_unlock(&gpio->lock);
++}
++
++static struct configfs_group_operations gpio_group_ops = {
++ .make_item = gpio_make_item,
++ .drop_item = gpio_drop_item,
++};
++
++static struct config_item_type gpio_group_type = {
++ .ct_group_ops = &gpio_group_ops,
++ .ct_owner = THIS_MODULE,
++};
++
++static struct configfs_subsystem gpio_subsys = {
++ .su_group = {
++ .cg_item = {
++ .ci_namebuf = "gpio",
++ .ci_type = &gpio_group_type,
++ },
++ },
++};
++
++static int __init gpio_dev_init(void)
++{
++ int err;
++
++ gpio_dev_class = class_create(THIS_MODULE, "gpio-dev");
++ if (IS_ERR(gpio_dev_class)) {
++ err = PTR_ERR(gpio_dev_class);
++ goto err_class_create;
++ }
++
++ err = alloc_chrdev_region(&gpio_devt, 0, GPIO_DEV_MAX, "gpio");
++ if (err < 0)
++ goto err_alloc_chrdev;
++
++ /* Configfs initialization */
++ config_group_init(&gpio_subsys.su_group);
++ mutex_init(&gpio_subsys.su_mutex);
++ err = configfs_register_subsystem(&gpio_subsys);
++ if (err)
++ goto err_register_subsys;
++
++ return 0;
++
++err_register_subsys:
++ unregister_chrdev_region(gpio_devt, GPIO_DEV_MAX);
++err_alloc_chrdev:
++ class_destroy(gpio_dev_class);
++err_class_create:
++ printk(KERN_WARNING "Failed to initialize gpio /dev interface\n");
++ return err;
++}
++late_initcall(gpio_dev_init);
+--- a/arch/avr32/mach-at32ap/hsmc.c
++++ b/arch/avr32/mach-at32ap/hsmc.c
+@@ -278,4 +278,4 @@
+ {
+ return platform_driver_register(&hsmc_driver);
+ }
+-arch_initcall(hsmc_init);
++core_initcall(hsmc_init);
+--- a/arch/avr32/mach-at32ap/intc.c
++++ b/arch/avr32/mach-at32ap/intc.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2006 Atmel Corporation
++ * Copyright (C) 2006, 2008 Atmel Corporation
+ *
+ * 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
+@@ -12,15 +12,20 @@
+ #include <linux/interrupt.h>
+ #include <linux/irq.h>
+ #include <linux/platform_device.h>
++#include <linux/sysdev.h>
+
+-#include <asm/intc.h>
+ #include <asm/io.h>
+
+ #include "intc.h"
+
+ struct intc {
+- void __iomem *regs;
+- struct irq_chip chip;
++ void __iomem *regs;
++ struct irq_chip chip;
++ struct sys_device sysdev;
++#ifdef CONFIG_PM
++ unsigned long suspend_ipr;
++ unsigned long saved_ipr[64];
++#endif
+ };
+
+ extern struct platform_device at32_intc0_device;
+@@ -137,6 +142,74 @@
+ panic("Interrupt controller initialization failed!\n");
+ }
+
++#ifdef CONFIG_PM
++void intc_set_suspend_handler(unsigned long offset)
++{
++ intc0.suspend_ipr = offset;
++}
++
++static int intc_suspend(struct sys_device *sdev, pm_message_t state)
++{
++ struct intc *intc = container_of(sdev, struct intc, sysdev);
++ int i;
++
++ if (unlikely(!irqs_disabled())) {
++ pr_err("intc_suspend: called with interrupts enabled\n");
++ return -EINVAL;
++ }
++
++ if (unlikely(!intc->suspend_ipr)) {
++ pr_err("intc_suspend: suspend_ipr not initialized\n");
++ return -EINVAL;
++ }
++
++ for (i = 0; i < 64; i++) {
++ intc->saved_ipr[i] = intc_readl(intc, INTPR0 + 4 * i);
++ intc_writel(intc, INTPR0 + 4 * i, intc->suspend_ipr);
++ }
++
++ return 0;
++}
++
++static int intc_resume(struct sys_device *sdev)
++{
++ struct intc *intc = container_of(sdev, struct intc, sysdev);
++ int i;
++
++ WARN_ON(!irqs_disabled());
++
++ for (i = 0; i < 64; i++)
++ intc_writel(intc, INTPR0 + 4 * i, intc->saved_ipr[i]);
++
++ return 0;
++}
++#else
++#define intc_suspend NULL
++#define intc_resume NULL
++#endif
++
++static struct sysdev_class intc_class = {
++ .name = "intc",
++ .suspend = intc_suspend,
++ .resume = intc_resume,
++};
++
++static int __init intc_init_sysdev(void)
++{
++ int ret;
++
++ ret = sysdev_class_register(&intc_class);
++ if (ret)
++ return ret;
++
++ intc0.sysdev.id = 0;
++ intc0.sysdev.cls = &intc_class;
++ ret = sysdev_register(&intc0.sysdev);
++
++ return ret;
++}
++device_initcall(intc_init_sysdev);
++
+ unsigned long intc_get_pending(unsigned int group)
+ {
+ return intc_readl(&intc0, INTREQ0 + 4 * group);
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/pdc.c
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2006 Atmel Corporation
++ *
++ * 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/clk.h>
++#include <linux/err.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++
++static int __init pdc_probe(struct platform_device *pdev)
++{
++ struct clk *pclk, *hclk;
++
++ pclk = clk_get(&pdev->dev, "pclk");
++ if (IS_ERR(pclk)) {
++ dev_err(&pdev->dev, "no pclk defined\n");
++ return PTR_ERR(pclk);
++ }
++ hclk = clk_get(&pdev->dev, "hclk");
++ if (IS_ERR(hclk)) {
++ dev_err(&pdev->dev, "no hclk defined\n");
++ clk_put(pclk);
++ return PTR_ERR(hclk);
++ }
++
++ clk_enable(pclk);
++ clk_enable(hclk);
++
++ dev_info(&pdev->dev, "Atmel Peripheral DMA Controller enabled\n");
++ return 0;
++}
++
++static struct platform_driver pdc_driver = {
++ .probe = pdc_probe,
++ .driver = {
++ .name = "pdc",
++ },
++};
++
++static int __init pdc_init(void)
++{
++ return platform_driver_register(&pdc_driver);
++}
++arch_initcall(pdc_init);
+--- a/arch/avr32/mach-at32ap/pio.c
++++ b/arch/avr32/mach-at32ap/pio.c
+@@ -157,6 +157,82 @@
+ dump_stack();
+ }
+
++#ifdef CONFIG_GPIO_DEV
++
++/* Gang allocators and accessors; used by the GPIO /dev driver */
++int at32_gpio_port_is_valid(unsigned int port)
++{
++ return port < MAX_NR_PIO_DEVICES && pio_dev[port].regs != NULL;
++}
++
++int at32_select_gpio_pins(unsigned int port, u32 pins, u32 oe_mask)
++{
++ struct pio_device *pio;
++ u32 old, new;
++
++ pio = &pio_dev[port];
++ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs || (oe_mask & ~pins));
++
++ /* Try to allocate the pins */
++ do {
++ old = pio->pinmux_mask;
++ if (old & pins)
++ return -EBUSY;
++
++ new = old | pins;
++ } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
++
++ /* That went well, now configure the port */
++ pio_writel(pio, OER, oe_mask);
++ pio_writel(pio, PER, pins);
++
++ return 0;
++}
++
++void at32_deselect_pins(unsigned int port, u32 pins)
++{
++ struct pio_device *pio;
++ u32 old, new;
++
++ pio = &pio_dev[port];
++ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
++
++ /* Return to a "safe" mux configuration */
++ pio_writel(pio, PUER, pins);
++ pio_writel(pio, ODR, pins);
++
++ /* Deallocate the pins */
++ do {
++ old = pio->pinmux_mask;
++ new = old & ~pins;
++ } while (cmpxchg(&pio->pinmux_mask, old, new) != old);
++}
++
++u32 at32_gpio_get_value_multiple(unsigned int port, u32 pins)
++{
++ struct pio_device *pio;
++
++ pio = &pio_dev[port];
++ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
++
++ return pio_readl(pio, PDSR) & pins;
++}
++
++void at32_gpio_set_value_multiple(unsigned int port, u32 value, u32 mask)
++{
++ struct pio_device *pio;
++
++ pio = &pio_dev[port];
++ BUG_ON(port > ARRAY_SIZE(pio_dev) || !pio->regs);
++
++ /* No atomic updates for now... */
++ pio_writel(pio, CODR, ~value & mask);
++ pio_writel(pio, SODR, value & mask);
++}
++
++#endif /* CONFIG_GPIO_DEV */
++
++
+ /*--------------------------------------------------------------------------*/
+
+ /* GPIO API */
+@@ -318,6 +394,8 @@
+ const char *label;
+
+ label = gpiochip_is_requested(chip, i);
++ if (!label && (imr & mask))
++ label = "[irq]";
+ if (!label)
+ continue;
+
+--- a/arch/avr32/mach-at32ap/pio.h
++++ b/arch/avr32/mach-at32ap/pio.h
+@@ -57,7 +57,7 @@
+
+ /* Bitfields in IFDR */
+
+-/* Bitfields in ISFR */
++/* Bitfields in IFSR */
+
+ /* Bitfields in SODR */
+
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/pm-at32ap700x.S
+@@ -0,0 +1,174 @@
++/*
++ * Low-level Power Management code.
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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 <asm/asm.h>
++#include <asm/asm-offsets.h>
++#include <asm/thread_info.h>
++#include <asm/arch/pm.h>
++
++#include "pm.h"
++#include "sdramc.h"
++
++/* Same as 0xfff00000 but fits in a 21 bit signed immediate */
++#define PM_BASE -0x100000
++
++ .section .bss, "wa", @nobits
++ .global disable_idle_sleep
++ .type disable_idle_sleep, @object
++disable_idle_sleep:
++ .int 4
++ .size disable_idle_sleep, . - disable_idle_sleep
++
++ /* Keep this close to the irq handlers */
++ .section .irq.text, "ax", @progbits
++
++ /*
++ * void cpu_enter_idle(void)
++ *
++ * Put the CPU into "idle" mode, in which it will consume
++ * significantly less power.
++ *
++ * If an interrupt comes along in the window between
++ * unmask_interrupts and the sleep instruction below, the
++ * interrupt code will adjust the return address so that we
++ * never execute the sleep instruction. This is required
++ * because the AP7000 doesn't unmask interrupts when entering
++ * sleep modes; later CPUs may not need this workaround.
++ */
++ .global cpu_enter_idle
++ .type cpu_enter_idle, @function
++cpu_enter_idle:
++ mask_interrupts
++ get_thread_info r8
++ ld.w r9, r8[TI_flags]
++ bld r9, TIF_NEED_RESCHED
++ brcs .Lret_from_sleep
++ sbr r9, TIF_CPU_GOING_TO_SLEEP
++ st.w r8[TI_flags], r9
++ unmask_interrupts
++ sleep CPU_SLEEP_IDLE
++ .size cpu_idle_sleep, . - cpu_idle_sleep
++
++ /*
++ * Common return path for PM functions that don't run from
++ * SRAM.
++ */
++ .global cpu_idle_skip_sleep
++ .type cpu_idle_skip_sleep, @function
++cpu_idle_skip_sleep:
++ mask_interrupts
++ ld.w r9, r8[TI_flags]
++ cbr r9, TIF_CPU_GOING_TO_SLEEP
++ st.w r8[TI_flags], r9
++.Lret_from_sleep:
++ unmask_interrupts
++ retal r12
++ .size cpu_idle_skip_sleep, . - cpu_idle_skip_sleep
++
++#ifdef CONFIG_PM
++ .section .init.text, "ax", @progbits
++
++ .global pm_exception
++ .type pm_exception, @function
++pm_exception:
++ /*
++ * Exceptions are masked when we switch to this handler, so
++ * we'll only get "unrecoverable" exceptions (offset 0.)
++ */
++ sub r12, pc, . - .Lpanic_msg
++ lddpc pc, .Lpanic_addr
++
++ .align 2
++.Lpanic_addr:
++ .long panic
++.Lpanic_msg:
++ .asciz "Unrecoverable exception during suspend\n"
++ .size pm_exception, . - pm_exception
++
++ .global pm_irq0
++ .type pm_irq0, @function
++pm_irq0:
++ /* Disable interrupts and return after the sleep instruction */
++ mfsr r9, SYSREG_RSR_INT0
++ mtsr SYSREG_RAR_INT0, r8
++ sbr r9, SYSREG_GM_OFFSET
++ mtsr SYSREG_RSR_INT0, r9
++ rete
++
++ /*
++ * void cpu_enter_standby(unsigned long sdramc_base)
++ *
++ * Enter PM_SUSPEND_STANDBY mode. At this point, all drivers
++ * are suspended and interrupts are disabled. Interrupts
++ * marked as 'wakeup' event sources may still come along and
++ * get us out of here.
++ *
++ * The SDRAM will be put into self-refresh mode (which does
++ * not require a clock from the CPU), and the CPU will be put
++ * into "frozen" mode (HSB bus stopped). The SDRAM controller
++ * will automatically bring the SDRAM into normal mode on the
++ * first access, and the power manager will automatically
++ * start the HSB and CPU clocks upon a wakeup event.
++ *
++ * This code uses the same "skip sleep" technique as above.
++ * It is very important that we jump directly to
++ * cpu_after_sleep after the sleep instruction since that's
++ * where we'll end up if the interrupt handler decides that we
++ * need to skip the sleep instruction.
++ */
++ .global pm_standby
++ .type pm_standby, @function
++pm_standby:
++ /*
++ * interrupts are already masked at this point, and EVBA
++ * points to pm_exception above.
++ */
++ ld.w r10, r12[SDRAMC_LPR]
++ sub r8, pc, . - 1f /* return address for irq handler */
++ mov r11, SDRAMC_LPR_LPCB_SELF_RFR
++ bfins r10, r11, 0, 2 /* LPCB <- self Refresh */
++ sync 0 /* flush write buffer */
++ st.w r12[SDRAMC_LPR], r11 /* put SDRAM in self-refresh mode */
++ ld.w r11, r12[SDRAMC_LPR]
++ unmask_interrupts
++ sleep CPU_SLEEP_FROZEN
++1: mask_interrupts
++ retal r12
++ .size pm_standby, . - pm_standby
++
++ .global pm_suspend_to_ram
++ .type pm_suspend_to_ram, @function
++pm_suspend_to_ram:
++ /*
++ * interrupts are already masked at this point, and EVBA
++ * points to pm_exception above.
++ */
++ mov r11, 0
++ cache r11[2], 8 /* clean all dcache lines */
++ sync 0 /* flush write buffer */
++ ld.w r10, r12[SDRAMC_LPR]
++ sub r8, pc, . - 1f /* return address for irq handler */
++ mov r11, SDRAMC_LPR_LPCB_SELF_RFR
++ bfins r10, r11, 0, 2 /* LPCB <- self refresh */
++ st.w r12[SDRAMC_LPR], r10 /* put SDRAM in self-refresh mode */
++ ld.w r11, r12[SDRAMC_LPR]
++
++ unmask_interrupts
++ sleep CPU_SLEEP_STOP
++1: mask_interrupts
++
++ retal r12
++ .size pm_suspend_to_ram, . - pm_suspend_to_ram
++
++ .global pm_sram_end
++ .type pm_sram_end, @function
++pm_sram_end:
++ .size pm_sram_end, 0
++
++#endif /* CONFIG_PM */
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/pm.c
+@@ -0,0 +1,245 @@
++/*
++ * AVR32 AP Power Management
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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/io.h>
++#include <linux/suspend.h>
++#include <linux/vmalloc.h>
++
++#include <asm/cacheflush.h>
++#include <asm/sysreg.h>
++
++#include <asm/arch/pm.h>
++#include <asm/arch/sram.h>
++
++/* FIXME: This is only valid for AP7000 */
++#define SDRAMC_BASE 0xfff03800
++
++#include "sdramc.h"
++
++#define SRAM_PAGE_FLAGS (SYSREG_BIT(TLBELO_D) | SYSREG_BF(SZ, 1) \
++ | SYSREG_BF(AP, 3) | SYSREG_BIT(G))
++
++
++static unsigned long pm_sram_start;
++static size_t pm_sram_size;
++static struct vm_struct *pm_sram_area;
++
++static void (*avr32_pm_enter_standby)(unsigned long sdramc_base);
++static void (*avr32_pm_enter_str)(unsigned long sdramc_base);
++
++/*
++ * Must be called with interrupts disabled. Exceptions will be masked
++ * on return (i.e. all exceptions will be "unrecoverable".)
++ */
++static void *avr32_pm_map_sram(void)
++{
++ unsigned long vaddr;
++ unsigned long page_addr;
++ u32 tlbehi;
++ u32 mmucr;
++
++ vaddr = (unsigned long)pm_sram_area->addr;
++ page_addr = pm_sram_start & PAGE_MASK;
++
++ /*
++ * Mask exceptions and grab the first TLB entry. We won't be
++ * needing it while sleeping.
++ */
++ asm volatile("ssrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
++
++ mmucr = sysreg_read(MMUCR);
++ tlbehi = sysreg_read(TLBEHI);
++ sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
++
++ tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
++ tlbehi |= vaddr & PAGE_MASK;
++ tlbehi |= SYSREG_BIT(TLBEHI_V);
++
++ sysreg_write(TLBELO, page_addr | SRAM_PAGE_FLAGS);
++ sysreg_write(TLBEHI, tlbehi);
++ __builtin_tlbw();
++
++ return (void *)(vaddr + pm_sram_start - page_addr);
++}
++
++/*
++ * Must be called with interrupts disabled. Exceptions will be
++ * unmasked on return.
++ */
++static void avr32_pm_unmap_sram(void)
++{
++ u32 mmucr;
++ u32 tlbehi;
++ u32 tlbarlo;
++
++ /* Going to update TLB entry at index 0 */
++ mmucr = sysreg_read(MMUCR);
++ tlbehi = sysreg_read(TLBEHI);
++ sysreg_write(MMUCR, SYSREG_BFINS(DRP, 0, mmucr));
++
++ /* Clear the "valid" bit */
++ tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
++ sysreg_write(TLBEHI, tlbehi);
++
++ /* Mark it as "not accessed" */
++ tlbarlo = sysreg_read(TLBARLO);
++ sysreg_write(TLBARLO, tlbarlo | 0x80000000U);
++
++ /* Update the TLB */
++ __builtin_tlbw();
++
++ /* Unmask exceptions */
++ asm volatile("csrf %0" : : "i"(SYSREG_EM_OFFSET) : "memory");
++}
++
++static int avr32_pm_valid_state(suspend_state_t state)
++{
++ switch (state) {
++ case PM_SUSPEND_ON:
++ case PM_SUSPEND_STANDBY:
++ case PM_SUSPEND_MEM:
++ return 1;
++
++ default:
++ return 0;
++ }
++}
++
++static int avr32_pm_enter(suspend_state_t state)
++{
++ u32 lpr_saved;
++ u32 evba_saved;
++ void *sram;
++
++ switch (state) {
++ case PM_SUSPEND_STANDBY:
++ sram = avr32_pm_map_sram();
++
++ /* Switch to in-sram exception handlers */
++ evba_saved = sysreg_read(EVBA);
++ sysreg_write(EVBA, (unsigned long)sram);
++
++ /*
++ * Save the LPR register so that we can re-enable
++ * SDRAM Low Power mode on resume.
++ */
++ lpr_saved = sdramc_readl(LPR);
++ pr_debug("%s: Entering standby...\n", __func__);
++ avr32_pm_enter_standby(SDRAMC_BASE);
++ sdramc_writel(LPR, lpr_saved);
++
++ /* Switch back to regular exception handlers */
++ sysreg_write(EVBA, evba_saved);
++
++ avr32_pm_unmap_sram();
++ break;
++
++ case PM_SUSPEND_MEM:
++ sram = avr32_pm_map_sram();
++
++ /* Switch to in-sram exception handlers */
++ evba_saved = sysreg_read(EVBA);
++ sysreg_write(EVBA, (unsigned long)sram);
++
++ /*
++ * Save the LPR register so that we can re-enable
++ * SDRAM Low Power mode on resume.
++ */
++ lpr_saved = sdramc_readl(LPR);
++ pr_debug("%s: Entering suspend-to-ram...\n", __func__);
++ avr32_pm_enter_str(SDRAMC_BASE);
++ sdramc_writel(LPR, lpr_saved);
++
++ /* Switch back to regular exception handlers */
++ sysreg_write(EVBA, evba_saved);
++
++ avr32_pm_unmap_sram();
++ break;
++
++ case PM_SUSPEND_ON:
++ pr_debug("%s: Entering idle...\n", __func__);
++ cpu_enter_idle();
++ break;
++
++ default:
++ pr_debug("%s: Invalid suspend state %d\n", __func__, state);
++ goto out;
++ }
++
++ pr_debug("%s: wakeup\n", __func__);
++
++out:
++ return 0;
++}
++
++static struct platform_suspend_ops avr32_pm_ops = {
++ .valid = avr32_pm_valid_state,
++ .enter = avr32_pm_enter,
++};
++
++static unsigned long avr32_pm_offset(void *symbol)
++{
++ extern u8 pm_exception[];
++
++ return (unsigned long)symbol - (unsigned long)pm_exception;
++}
++
++static int __init avr32_pm_init(void)
++{
++ extern u8 pm_exception[];
++ extern u8 pm_irq0[];
++ extern u8 pm_standby[];
++ extern u8 pm_suspend_to_ram[];
++ extern u8 pm_sram_end[];
++ void *dst;
++
++ /*
++ * To keep things simple, we depend on not needing more than a
++ * single page.
++ */
++ pm_sram_size = avr32_pm_offset(pm_sram_end);
++ if (pm_sram_size > PAGE_SIZE)
++ goto err;
++
++ pm_sram_start = sram_alloc(pm_sram_size);
++ if (!pm_sram_start)
++ goto err_alloc_sram;
++
++ /* Grab a virtual area we can use later on. */
++ pm_sram_area = get_vm_area(pm_sram_size, VM_IOREMAP);
++ if (!pm_sram_area)
++ goto err_vm_area;
++ pm_sram_area->phys_addr = pm_sram_start;
++
++ local_irq_disable();
++ dst = avr32_pm_map_sram();
++ memcpy(dst, pm_exception, pm_sram_size);
++ flush_dcache_region(dst, pm_sram_size);
++ invalidate_icache_region(dst, pm_sram_size);
++ avr32_pm_unmap_sram();
++ local_irq_enable();
++
++ avr32_pm_enter_standby = dst + avr32_pm_offset(pm_standby);
++ avr32_pm_enter_str = dst + avr32_pm_offset(pm_suspend_to_ram);
++ intc_set_suspend_handler(avr32_pm_offset(pm_irq0));
++
++ suspend_set_ops(&avr32_pm_ops);
++
++ printk("AVR32 AP Power Management enabled\n");
++
++ return 0;
++
++err_vm_area:
++ sram_free(pm_sram_start, pm_sram_size);
++err_alloc_sram:
++err:
++ pr_err("AVR32 Power Management initialization failed\n");
++ return -ENOMEM;
++}
++arch_initcall(avr32_pm_init);
+--- /dev/null
++++ b/arch/avr32/mach-at32ap/sdramc.h
+@@ -0,0 +1,76 @@
++/*
++ * Register definitions for the AT32AP SDRAM Controller
++ *
++ * Copyright (C) 2008 Atmel Corporation
++ *
++ * 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.
++ */
++
++/* Register offsets */
++#define SDRAMC_MR 0x0000
++#define SDRAMC_TR 0x0004
++#define SDRAMC_CR 0x0008
++#define SDRAMC_HSR 0x000c
++#define SDRAMC_LPR 0x0010
++#define SDRAMC_IER 0x0014
++#define SDRAMC_IDR 0x0018
++#define SDRAMC_IMR 0x001c
++#define SDRAMC_ISR 0x0020
++#define SDRAMC_MDR 0x0024
++
++/* MR - Mode Register */
++#define SDRAMC_MR_MODE_NORMAL ( 0 << 0)
++#define SDRAMC_MR_MODE_NOP ( 1 << 0)
++#define SDRAMC_MR_MODE_BANKS_PRECHARGE ( 2 << 0)
++#define SDRAMC_MR_MODE_LOAD_MODE ( 3 << 0)
++#define SDRAMC_MR_MODE_AUTO_REFRESH ( 4 << 0)
++#define SDRAMC_MR_MODE_EXT_LOAD_MODE ( 5 << 0)
++#define SDRAMC_MR_MODE_POWER_DOWN ( 6 << 0)
++
++/* CR - Configuration Register */
++#define SDRAMC_CR_NC_8_BITS ( 0 << 0)
++#define SDRAMC_CR_NC_9_BITS ( 1 << 0)
++#define SDRAMC_CR_NC_10_BITS ( 2 << 0)
++#define SDRAMC_CR_NC_11_BITS ( 3 << 0)
++#define SDRAMC_CR_NR_11_BITS ( 0 << 2)
++#define SDRAMC_CR_NR_12_BITS ( 1 << 2)
++#define SDRAMC_CR_NR_13_BITS ( 2 << 2)
++#define SDRAMC_CR_NB_2_BANKS ( 0 << 4)
++#define SDRAMC_CR_NB_4_BANKS ( 1 << 4)
++#define SDRAMC_CR_CAS(x) ((x) << 5)
++#define SDRAMC_CR_DBW_32_BITS ( 0 << 7)
++#define SDRAMC_CR_DBW_16_BITS ( 1 << 7)
++#define SDRAMC_CR_TWR(x) ((x) << 8)
++#define SDRAMC_CR_TRC(x) ((x) << 12)
++#define SDRAMC_CR_TRP(x) ((x) << 16)
++#define SDRAMC_CR_TRCD(x) ((x) << 20)
++#define SDRAMC_CR_TRAS(x) ((x) << 24)
++#define SDRAMC_CR_TXSR(x) ((x) << 28)
++
++/* HSR - High Speed Register */
++#define SDRAMC_HSR_DA ( 1 << 0)
++
++/* LPR - Low Power Register */
++#define SDRAMC_LPR_LPCB_INHIBIT ( 0 << 0)
++#define SDRAMC_LPR_LPCB_SELF_RFR ( 1 << 0)
++#define SDRAMC_LPR_LPCB_PDOWN ( 2 << 0)
++#define SDRAMC_LPR_LPCB_DEEP_PDOWN ( 3 << 0)
++#define SDRAMC_LPR_PASR(x) ((x) << 4)
++#define SDRAMC_LPR_TCSR(x) ((x) << 8)
++#define SDRAMC_LPR_DS(x) ((x) << 10)
++#define SDRAMC_LPR_TIMEOUT(x) ((x) << 12)
++
++/* IER/IDR/IMR/ISR - Interrupt Enable/Disable/Mask/Status Register */
++#define SDRAMC_ISR_RES ( 1 << 0)
++
++/* MDR - Memory Device Register */
++#define SDRAMC_MDR_MD_SDRAM ( 0 << 0)
++#define SDRAMC_MDR_MD_LOW_PWR_SDRAM ( 1 << 0)
++
++/* Register access macros */
++#define sdramc_readl(reg) \
++ __raw_readl((void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
++#define sdramc_writel(reg, value) \
++ __raw_writel(value, (void __iomem __force *)SDRAMC_BASE + SDRAMC_##reg)
+--- a/arch/avr32/mach-at32ap/time-tc.c
++++ /dev/null
+@@ -1,218 +0,0 @@
+-/*
+- * Copyright (C) 2004-2007 Atmel Corporation
+- *
+- * Based on MIPS implementation arch/mips/kernel/time.c
+- * Copyright 2001 MontaVista Software Inc.
+- *
+- * 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/clk.h>
+-#include <linux/clocksource.h>
+-#include <linux/time.h>
+-#include <linux/module.h>
+-#include <linux/interrupt.h>
+-#include <linux/irq.h>
+-#include <linux/kernel_stat.h>
+-#include <linux/errno.h>
+-#include <linux/init.h>
+-#include <linux/profile.h>
+-#include <linux/sysdev.h>
+-#include <linux/err.h>
+-
+-#include <asm/div64.h>
+-#include <asm/sysreg.h>
+-#include <asm/io.h>
+-#include <asm/sections.h>
+-
+-#include <asm/arch/time.h>
+-
+-/* how many counter cycles in a jiffy? */
+-static u32 cycles_per_jiffy;
+-
+-/* the count value for the next timer interrupt */
+-static u32 expirelo;
+-
+-/* the I/O registers of the TC module */
+-static void __iomem *ioregs;
+-
+-cycle_t read_cycle_count(void)
+-{
+- return (cycle_t)timer_read(ioregs, 0, CV);
+-}
+-
+-struct clocksource clocksource_avr32 = {
+- .name = "avr32",
+- .rating = 342,
+- .read = read_cycle_count,
+- .mask = CLOCKSOURCE_MASK(16),
+- .shift = 16,
+- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+-};
+-
+-static void avr32_timer_ack(void)
+-{
+- u16 count = expirelo;
+-
+- /* Ack this timer interrupt and set the next one, use a u16
+- * variable so it will wrap around correctly */
+- count += cycles_per_jiffy;
+- expirelo = count;
+- timer_write(ioregs, 0, RC, expirelo);
+-
+- /* Check to see if we have missed any timer interrupts */
+- count = timer_read(ioregs, 0, CV);
+- if ((count - expirelo) < 0x7fff) {
+- expirelo = count + cycles_per_jiffy;
+- timer_write(ioregs, 0, RC, expirelo);
+- }
+-}
+-
+-u32 avr32_hpt_read(void)
+-{
+- return timer_read(ioregs, 0, CV);
+-}
+-
+-static int avr32_timer_calc_div_and_set_jiffies(struct clk *pclk)
+-{
+- unsigned int cycles_max = (clocksource_avr32.mask + 1) / 2;
+- unsigned int divs[] = { 4, 8, 16, 32 };
+- int divs_size = ARRAY_SIZE(divs);
+- int i = 0;
+- unsigned long count_hz;
+- unsigned long shift;
+- unsigned long mult;
+- int clock_div = -1;
+- u64 tmp;
+-
+- shift = clocksource_avr32.shift;
+-
+- do {
+- count_hz = clk_get_rate(pclk) / divs[i];
+- mult = clocksource_hz2mult(count_hz, shift);
+- clocksource_avr32.mult = mult;
+-
+- tmp = TICK_NSEC;
+- tmp <<= shift;
+- tmp += mult / 2;
+- do_div(tmp, mult);
+-
+- cycles_per_jiffy = tmp;
+- } while (cycles_per_jiffy > cycles_max && ++i < divs_size);
+-
+- clock_div = i + 1;
+-
+- if (clock_div > divs_size) {
+- pr_debug("timer: could not calculate clock divider\n");
+- return -EFAULT;
+- }
+-
+- /* Set the clock divider */
+- timer_write(ioregs, 0, CMR, TIMER_BF(CMR_TCCLKS, clock_div));
+-
+- return 0;
+-}
+-
+-int avr32_hpt_init(unsigned int count)
+-{
+- struct resource *regs;
+- struct clk *pclk;
+- int irq = -1;
+- int ret = 0;
+-
+- ret = -ENXIO;
+-
+- irq = platform_get_irq(&at32_systc0_device, 0);
+- if (irq < 0) {
+- pr_debug("timer: could not get irq\n");
+- goto out_error;
+- }
+-
+- pclk = clk_get(&at32_systc0_device.dev, "pclk");
+- if (IS_ERR(pclk)) {
+- pr_debug("timer: could not get clk: %ld\n", PTR_ERR(pclk));
+- goto out_error;
+- }
+- clk_enable(pclk);
+-
+- regs = platform_get_resource(&at32_systc0_device, IORESOURCE_MEM, 0);
+- if (!regs) {
+- pr_debug("timer: could not get resource\n");
+- goto out_error_clk;
+- }
+-
+- ioregs = ioremap(regs->start, regs->end - regs->start + 1);
+- if (!ioregs) {
+- pr_debug("timer: could not get ioregs\n");
+- goto out_error_clk;
+- }
+-
+- ret = avr32_timer_calc_div_and_set_jiffies(pclk);
+- if (ret)
+- goto out_error_io;
+-
+- ret = setup_irq(irq, &timer_irqaction);
+- if (ret) {
+- pr_debug("timer: could not request irq %d: %d\n",
+- irq, ret);
+- goto out_error_io;
+- }
+-
+- expirelo = (timer_read(ioregs, 0, CV) / cycles_per_jiffy + 1)
+- * cycles_per_jiffy;
+-
+- /* Enable clock and interrupts on RC compare */
+- timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_CLKEN));
+- timer_write(ioregs, 0, IER, TIMER_BIT(IER_CPCS));
+- /* Set cycles to first interrupt */
+- timer_write(ioregs, 0, RC, expirelo);
+-
+- printk(KERN_INFO "timer: AT32AP system timer/counter at 0x%p irq %d\n",
+- ioregs, irq);
+-
+- return 0;
+-
+-out_error_io:
+- iounmap(ioregs);
+-out_error_clk:
+- clk_put(pclk);
+-out_error:
+- return ret;
+-}
+-
+-int avr32_hpt_start(void)
+-{
+- timer_write(ioregs, 0, CCR, TIMER_BIT(CCR_SWTRG));
+- return 0;
+-}
+-
+-irqreturn_t timer_interrupt(int irq, void *dev_id)
+-{
+- unsigned int sr = timer_read(ioregs, 0, SR);
+-
+- if (sr & TIMER_BIT(SR_CPCS)) {
+- /* ack timer interrupt and try to set next interrupt */
+- avr32_timer_ack();
+-
+- /*
+- * Call the generic timer interrupt handler
+- */
+- write_seqlock(&xtime_lock);
+- do_timer(1);
+- write_sequnlock(&xtime_lock);
+-
+- /*
+- * In UP mode, we call local_timer_interrupt() to do profiling
+- * and process accounting.
+- *
+- * SMP is not supported yet.
+- */
+- local_timer_interrupt(irq, dev_id);
+-
+- return IRQ_HANDLED;
+- }
+-
+- return IRQ_NONE;
+-}
+--- a/arch/avr32/mm/init.c
++++ b/arch/avr32/mm/init.c
+@@ -11,6 +11,7 @@
+ #include <linux/swap.h>
+ #include <linux/init.h>
+ #include <linux/mmzone.h>
++#include <linux/module.h>
+ #include <linux/bootmem.h>
+ #include <linux/pagemap.h>
+ #include <linux/nodemask.h>
+@@ -23,20 +24,20 @@
+ #include <asm/setup.h>
+ #include <asm/sections.h>
+
++#define __page_aligned __attribute__((section(".data.page_aligned")))
++
+ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+-pgd_t swapper_pg_dir[PTRS_PER_PGD];
++pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned;
+
+ struct page *empty_zero_page;
++EXPORT_SYMBOL(empty_zero_page);
+
+ /*
+ * Cache of MMU context last used.
+ */
+ unsigned long mmu_context_cache = NO_CONTEXT;
+
+-#define START_PFN (NODE_DATA(0)->bdata->node_boot_start >> PAGE_SHIFT)
+-#define MAX_LOW_PFN (NODE_DATA(0)->bdata->node_low_pfn)
+-
+ void show_mem(void)
+ {
+ int total = 0, reserved = 0, cached = 0;
+@@ -109,19 +110,9 @@
+ zero_page = alloc_bootmem_low_pages_node(NODE_DATA(0),
+ PAGE_SIZE);
+
+- {
+- pgd_t *pg_dir;
+- int i;
+-
+- pg_dir = swapper_pg_dir;
+- sysreg_write(PTBR, (unsigned long)pg_dir);
+-
+- for (i = 0; i < PTRS_PER_PGD; i++)
+- pgd_val(pg_dir[i]) = 0;
+-
+- enable_mmu();
+- printk ("CPU: Paging enabled\n");
+- }
++ sysreg_write(PTBR, (unsigned long)swapper_pg_dir);
++ enable_mmu();
++ printk ("CPU: Paging enabled\n");
+
+ for_each_online_node(nid) {
+ pg_data_t *pgdat = NODE_DATA(nid);
+--- a/arch/avr32/mm/tlb.c
++++ b/arch/avr32/mm/tlb.c
+@@ -11,21 +11,21 @@
+
+ #include <asm/mmu_context.h>
+
+-#define _TLBEHI_I 0x100
++/* TODO: Get the correct number from the CONFIG1 system register */
++#define NR_TLB_ENTRIES 32
+
+-void show_dtlb_entry(unsigned int index)
++static void show_dtlb_entry(unsigned int index)
+ {
+- unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
++ u32 tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ mmucr_save = sysreg_read(MMUCR);
+ tlbehi_save = sysreg_read(TLBEHI);
+- mmucr = mmucr_save & 0x13;
+- mmucr |= index << 14;
++ mmucr = SYSREG_BFINS(DRP, index, mmucr_save);
+ sysreg_write(MMUCR, mmucr);
+
+- asm volatile("tlbr" : : : "memory");
++ __builtin_tlbr();
+ cpu_sync_pipeline();
+
+ tlbehi = sysreg_read(TLBEHI);
+@@ -33,15 +33,17 @@
+
+ printk("%2u: %c %c %02x %05x %05x %o %o %c %c %c %c\n",
+ index,
+- (tlbehi & 0x200)?'1':'0',
+- (tlbelo & 0x100)?'1':'0',
+- (tlbehi & 0xff),
+- (tlbehi >> 12), (tlbelo >> 12),
+- (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
+- (tlbelo & 0x200)?'1':'0',
+- (tlbelo & 0x080)?'1':'0',
+- (tlbelo & 0x001)?'1':'0',
+- (tlbelo & 0x002)?'1':'0');
++ SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
++ SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
++ SYSREG_BFEXT(ASID, tlbehi),
++ SYSREG_BFEXT(VPN, tlbehi) >> 2,
++ SYSREG_BFEXT(PFN, tlbelo) >> 2,
++ SYSREG_BFEXT(AP, tlbelo),
++ SYSREG_BFEXT(SZ, tlbelo),
++ SYSREG_BFEXT(TLBELO_C, tlbelo) ? 'C' : ' ',
++ SYSREG_BFEXT(B, tlbelo) ? 'B' : ' ',
++ SYSREG_BFEXT(W, tlbelo) ? 'W' : ' ',
++ SYSREG_BFEXT(TLBELO_D, tlbelo) ? 'D' : ' ');
+
+ sysreg_write(MMUCR, mmucr_save);
+ sysreg_write(TLBEHI, tlbehi_save);
+@@ -54,29 +56,33 @@
+ unsigned int i;
+
+ printk("ID V G ASID VPN PFN AP SZ C B W D\n");
+- for (i = 0; i < 32; i++)
++ for (i = 0; i < NR_TLB_ENTRIES; i++)
+ show_dtlb_entry(i);
+ }
+
+-static unsigned long last_mmucr;
+-
+-static inline void set_replacement_pointer(unsigned shift)
++static void update_dtlb(unsigned long address, pte_t pte)
+ {
+- unsigned long mmucr, mmucr_save;
++ u32 tlbehi;
++ u32 mmucr;
+
+- mmucr = mmucr_save = sysreg_read(MMUCR);
++ /*
++ * We're not changing the ASID here, so no need to flush the
++ * pipeline.
++ */
++ tlbehi = sysreg_read(TLBEHI);
++ tlbehi = SYSREG_BF(ASID, SYSREG_BFEXT(ASID, tlbehi));
++ tlbehi |= address & MMU_VPN_MASK;
++ tlbehi |= SYSREG_BIT(TLBEHI_V);
++ sysreg_write(TLBEHI, tlbehi);
+
+ /* Does this mapping already exist? */
+- __asm__ __volatile__(
+- " tlbs\n"
+- " mfsr %0, %1"
+- : "=r"(mmucr)
+- : "i"(SYSREG_MMUCR));
++ __builtin_tlbs();
++ mmucr = sysreg_read(MMUCR);
+
+ if (mmucr & SYSREG_BIT(MMUCR_N)) {
+ /* Not found -- pick a not-recently-accessed entry */
+- unsigned long rp;
+- unsigned long tlbar = sysreg_read(TLBARLO);
++ unsigned int rp;
++ u32 tlbar = sysreg_read(TLBARLO);
+
+ rp = 32 - fls(tlbar);
+ if (rp == 32) {
+@@ -84,30 +90,14 @@
+ sysreg_write(TLBARLO, -1L);
+ }
+
+- mmucr &= 0x13;
+- mmucr |= (rp << shift);
+-
++ mmucr = SYSREG_BFINS(DRP, rp, mmucr);
+ sysreg_write(MMUCR, mmucr);
+ }
+
+- last_mmucr = mmucr;
+-}
+-
+-static void update_dtlb(unsigned long address, pte_t pte, unsigned long asid)
+-{
+- unsigned long vpn;
+-
+- vpn = (address & MMU_VPN_MASK) | _TLBEHI_VALID | asid;
+- sysreg_write(TLBEHI, vpn);
+- cpu_sync_pipeline();
+-
+- set_replacement_pointer(14);
+-
+ sysreg_write(TLBELO, pte_val(pte) & _PAGE_FLAGS_HARDWARE_MASK);
+
+ /* Let's go */
+- asm volatile("nop\n\ttlbw" : : : "memory");
+- cpu_sync_pipeline();
++ __builtin_tlbw();
+ }
+
+ void update_mmu_cache(struct vm_area_struct *vma,
+@@ -120,39 +110,40 @@
+ return;
+
+ local_irq_save(flags);
+- update_dtlb(address, pte, get_asid());
++ update_dtlb(address, pte);
+ local_irq_restore(flags);
+ }
+
+-void __flush_tlb_page(unsigned long asid, unsigned long page)
++static void __flush_tlb_page(unsigned long asid, unsigned long page)
+ {
+- unsigned long mmucr, tlbehi;
++ u32 mmucr, tlbehi;
+
+- page |= asid;
+- sysreg_write(TLBEHI, page);
+- cpu_sync_pipeline();
+- asm volatile("tlbs");
++ /*
++ * Caller is responsible for masking out non-PFN bits in page
++ * and changing the current ASID if necessary. This means that
++ * we don't need to flush the pipeline after writing TLBEHI.
++ */
++ tlbehi = page | asid;
++ sysreg_write(TLBEHI, tlbehi);
++
++ __builtin_tlbs();
+ mmucr = sysreg_read(MMUCR);
+
+ if (!(mmucr & SYSREG_BIT(MMUCR_N))) {
+- unsigned long tlbarlo;
+- unsigned long entry;
++ unsigned int entry;
++ u32 tlbarlo;
+
+ /* Clear the "valid" bit */
+- tlbehi = sysreg_read(TLBEHI);
+- tlbehi &= ~_TLBEHI_VALID;
+ sysreg_write(TLBEHI, tlbehi);
+- cpu_sync_pipeline();
+
+ /* mark the entry as "not accessed" */
+- entry = (mmucr >> 14) & 0x3f;
++ entry = SYSREG_BFEXT(DRP, mmucr);
+ tlbarlo = sysreg_read(TLBARLO);
+- tlbarlo |= (0x80000000 >> entry);
++ tlbarlo |= (0x80000000UL >> entry);
+ sysreg_write(TLBARLO, tlbarlo);
+
+ /* update the entry with valid bit clear */
+- asm volatile("tlbw");
+- cpu_sync_pipeline();
++ __builtin_tlbw();
+ }
+ }
+
+@@ -190,17 +181,22 @@
+
+ local_irq_save(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
++
+ if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
+ mm->context = NO_CONTEXT;
+ if (mm == current->mm)
+ activate_context(mm);
+ } else {
+- unsigned long asid = mm->context & MMU_CONTEXT_ASID_MASK;
+- unsigned long saved_asid = MMU_NO_ASID;
++ unsigned long asid;
++ unsigned long saved_asid;
++
++ asid = mm->context & MMU_CONTEXT_ASID_MASK;
++ saved_asid = MMU_NO_ASID;
+
+ start &= PAGE_MASK;
+ end += (PAGE_SIZE - 1);
+ end &= PAGE_MASK;
++
+ if (mm != current->mm) {
+ saved_asid = get_asid();
+ set_asid(asid);
+@@ -218,33 +214,34 @@
+ }
+
+ /*
+- * TODO: If this is only called for addresses > TASK_SIZE, we can probably
+- * skip the ASID stuff and just use the Global bit...
++ * This function depends on the pages to be flushed having the G
++ * (global) bit set in their pte. This is true for all
++ * PAGE_KERNEL(_RO) pages.
+ */
+ void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+ {
+ unsigned long flags;
+ int size;
+
+- local_irq_save(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ if (size > (MMU_DTLB_ENTRIES / 4)) { /* Too many entries to flush */
+ flush_tlb_all();
+ } else {
+- unsigned long asid = init_mm.context & MMU_CONTEXT_ASID_MASK;
+- unsigned long saved_asid = get_asid();
++ unsigned long asid;
++
++ local_irq_save(flags);
++ asid = get_asid();
+
+ start &= PAGE_MASK;
+ end += (PAGE_SIZE - 1);
+ end &= PAGE_MASK;
+- set_asid(asid);
++
+ while (start < end) {
+ __flush_tlb_page(asid, start);
+ start += PAGE_SIZE;
+ }
+- set_asid(saved_asid);
++ local_irq_restore(flags);
+ }
+- local_irq_restore(flags);
+ }
+
+ void flush_tlb_mm(struct mm_struct *mm)
+@@ -280,7 +277,7 @@
+ {
+ static unsigned long tlb_index;
+
+- if (*pos >= 32)
++ if (*pos >= NR_TLB_ENTRIES)
+ return NULL;
+
+ tlb_index = 0;
+@@ -291,7 +288,7 @@
+ {
+ unsigned long *index = v;
+
+- if (*index >= 31)
++ if (*index >= NR_TLB_ENTRIES - 1)
+ return NULL;
+
+ ++*pos;
+@@ -313,16 +310,16 @@
+ if (*index == 0)
+ seq_puts(tlb, "ID V G ASID VPN PFN AP SZ C B W D\n");
+
+- BUG_ON(*index >= 32);
++ BUG_ON(*index >= NR_TLB_ENTRIES);
+
+ local_irq_save(flags);
+ mmucr_save = sysreg_read(MMUCR);
+ tlbehi_save = sysreg_read(TLBEHI);
+- mmucr = mmucr_save & 0x13;
+- mmucr |= *index << 14;
++ mmucr = SYSREG_BFINS(DRP, *index, mmucr_save);
+ sysreg_write(MMUCR, mmucr);
+
+- asm volatile("tlbr" : : : "memory");
++ /* TLBR might change the ASID */
++ __builtin_tlbr();
+ cpu_sync_pipeline();
+
+ tlbehi = sysreg_read(TLBEHI);
+@@ -334,16 +331,18 @@
+ local_irq_restore(flags);
+
+ seq_printf(tlb, "%2lu: %c %c %02x %05x %05x %o %o %c %c %c %c\n",
+- *index,
+- (tlbehi & 0x200)?'1':'0',
+- (tlbelo & 0x100)?'1':'0',
+- (tlbehi & 0xff),
+- (tlbehi >> 12), (tlbelo >> 12),
+- (tlbelo >> 4) & 7, (tlbelo >> 2) & 3,
+- (tlbelo & 0x200)?'1':'0',
+- (tlbelo & 0x080)?'1':'0',
+- (tlbelo & 0x001)?'1':'0',
+- (tlbelo & 0x002)?'1':'0');
++ *index,
++ SYSREG_BFEXT(TLBEHI_V, tlbehi) ? '1' : '0',
++ SYSREG_BFEXT(G, tlbelo) ? '1' : '0',
++ SYSREG_BFEXT(ASID, tlbehi),
++ SYSREG_BFEXT(VPN, tlbehi) >> 2,
++ SYSREG_BFEXT(PFN, tlbelo) >> 2,
++ SYSREG_BFEXT(AP, tlbelo),
++ SYSREG_BFEXT(SZ, tlbelo),
++ SYSREG_BFEXT(TLBELO_C, tlbelo) ? '1' : '0',
++ SYSREG_BFEXT(B, tlbelo) ? '1' : '0',
++ SYSREG_BFEXT(W, tlbelo) ? '1' : '0',
++ SYSREG_BFEXT(TLBELO_D, tlbelo) ? '1' : '0');
+
+ return 0;
+ }
+--- a/arch/avr32/oprofile/op_model_avr32.c
++++ b/arch/avr32/oprofile/op_model_avr32.c
+@@ -16,7 +16,6 @@
+ #include <linux/sched.h>
+ #include <linux/types.h>
+
+-#include <asm/intc.h>
+ #include <asm/sysreg.h>
+ #include <asm/system.h>
+
+--- a/drivers/char/Kconfig
++++ b/drivers/char/Kconfig
+@@ -706,7 +706,7 @@
+
+ config RTC
+ tristate "Enhanced Real Time Clock Support"
+- depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390
++ depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV && !ARM && !SUPERH && !S390 && !AVR32
+ ---help---
+ If you say Y here and create a character special file /dev/rtc with
+ major number 10 and minor number 135 using mknod ("man mknod"), you
+@@ -776,7 +776,7 @@
+
+ config GEN_RTC
+ tristate "Generic /dev/rtc emulation"
+- depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH
++ depends on RTC!=y && !IA64 && !ARM && !M32R && !MIPS && !SPARC && !FRV && !S390 && !SUPERH && !AVR32
+ ---help---
+ If you say Y here and create a character special file /dev/rtc with
+ major number 10 and minor number 135 using mknod ("man mknod"), you
+--- a/drivers/char/keyboard.c
++++ b/drivers/char/keyboard.c
+@@ -1033,7 +1033,8 @@
+ #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
+ defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
+ defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
+- (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC))
++ (defined(CONFIG_ARM) && defined(CONFIG_KEYBOARD_ATKBD) && !defined(CONFIG_ARCH_RPC)) ||\
++ defined(CONFIG_AVR32)
+
+ #define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
+ ((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
+--- a/drivers/clocksource/Makefile
++++ b/drivers/clocksource/Makefile
+@@ -1,3 +1,4 @@
++obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o
+ obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
+ obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
+ obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
+--- /dev/null
++++ b/drivers/clocksource/tcb_clksrc.c
+@@ -0,0 +1,302 @@
++#include <linux/init.h>
++#include <linux/clocksource.h>
++#include <linux/clockchips.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++
++#include <linux/clk.h>
++#include <linux/err.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++#include <linux/platform_device.h>
++#include <linux/atmel_tc.h>