Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[sfrench/cifs-2.6.git] / arch / mips / alchemy / common / dbdma.c
index 99ae84ce5af3dc528e6ccdcebe833c2ef633ac1e..ca0506a8585a192834fc72f50fd5fceb3af6c1e6 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/sysdev.h>
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 
@@ -174,10 +175,6 @@ static dbdev_tab_t dbdev_tab[] = {
 
 #define DBDEV_TAB_SIZE ARRAY_SIZE(dbdev_tab)
 
-#ifdef CONFIG_PM
-static u32 au1xxx_dbdma_pm_regs[NUM_DBDMA_CHANS + 1][6];
-#endif
-
 
 static chan_tab_t *chan_tab_ptr[NUM_DBDMA_CHANS];
 
@@ -960,29 +957,37 @@ u32 au1xxx_dbdma_put_dscr(u32 chanid, au1x_ddma_desc_t *dscr)
        return nbytes;
 }
 
-#ifdef CONFIG_PM
-void au1xxx_dbdma_suspend(void)
+
+struct alchemy_dbdma_sysdev {
+       struct sys_device sysdev;
+       u32 pm_regs[NUM_DBDMA_CHANS + 1][6];
+};
+
+static int alchemy_dbdma_suspend(struct sys_device *dev,
+                                pm_message_t state)
 {
+       struct alchemy_dbdma_sysdev *sdev =
+               container_of(dev, struct alchemy_dbdma_sysdev, sysdev);
        int i;
        u32 addr;
 
        addr = DDMA_GLOBAL_BASE;
-       au1xxx_dbdma_pm_regs[0][0] = au_readl(addr + 0x00);
-       au1xxx_dbdma_pm_regs[0][1] = au_readl(addr + 0x04);
-       au1xxx_dbdma_pm_regs[0][2] = au_readl(addr + 0x08);
-       au1xxx_dbdma_pm_regs[0][3] = au_readl(addr + 0x0c);
+       sdev->pm_regs[0][0] = au_readl(addr + 0x00);
+       sdev->pm_regs[0][1] = au_readl(addr + 0x04);
+       sdev->pm_regs[0][2] = au_readl(addr + 0x08);
+       sdev->pm_regs[0][3] = au_readl(addr + 0x0c);
 
        /* save channel configurations */
        for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
-               au1xxx_dbdma_pm_regs[i][0] = au_readl(addr + 0x00);
-               au1xxx_dbdma_pm_regs[i][1] = au_readl(addr + 0x04);
-               au1xxx_dbdma_pm_regs[i][2] = au_readl(addr + 0x08);
-               au1xxx_dbdma_pm_regs[i][3] = au_readl(addr + 0x0c);
-               au1xxx_dbdma_pm_regs[i][4] = au_readl(addr + 0x10);
-               au1xxx_dbdma_pm_regs[i][5] = au_readl(addr + 0x14);
+               sdev->pm_regs[i][0] = au_readl(addr + 0x00);
+               sdev->pm_regs[i][1] = au_readl(addr + 0x04);
+               sdev->pm_regs[i][2] = au_readl(addr + 0x08);
+               sdev->pm_regs[i][3] = au_readl(addr + 0x0c);
+               sdev->pm_regs[i][4] = au_readl(addr + 0x10);
+               sdev->pm_regs[i][5] = au_readl(addr + 0x14);
 
                /* halt channel */
-               au_writel(au1xxx_dbdma_pm_regs[i][0] & ~1, addr + 0x00);
+               au_writel(sdev->pm_regs[i][0] & ~1, addr + 0x00);
                au_sync();
                while (!(au_readl(addr + 0x14) & 1))
                        au_sync();
@@ -992,32 +997,65 @@ void au1xxx_dbdma_suspend(void)
        /* disable channel interrupts */
        au_writel(0, DDMA_GLOBAL_BASE + 0x0c);
        au_sync();
+
+       return 0;
 }
 
-void au1xxx_dbdma_resume(void)
+static int alchemy_dbdma_resume(struct sys_device *dev)
 {
+       struct alchemy_dbdma_sysdev *sdev =
+               container_of(dev, struct alchemy_dbdma_sysdev, sysdev);
        int i;
        u32 addr;
 
        addr = DDMA_GLOBAL_BASE;
-       au_writel(au1xxx_dbdma_pm_regs[0][0], addr + 0x00);
-       au_writel(au1xxx_dbdma_pm_regs[0][1], addr + 0x04);
-       au_writel(au1xxx_dbdma_pm_regs[0][2], addr + 0x08);
-       au_writel(au1xxx_dbdma_pm_regs[0][3], addr + 0x0c);
+       au_writel(sdev->pm_regs[0][0], addr + 0x00);
+       au_writel(sdev->pm_regs[0][1], addr + 0x04);
+       au_writel(sdev->pm_regs[0][2], addr + 0x08);
+       au_writel(sdev->pm_regs[0][3], addr + 0x0c);
 
        /* restore channel configurations */
        for (i = 1, addr = DDMA_CHANNEL_BASE; i <= NUM_DBDMA_CHANS; i++) {
-               au_writel(au1xxx_dbdma_pm_regs[i][0], addr + 0x00);
-               au_writel(au1xxx_dbdma_pm_regs[i][1], addr + 0x04);
-               au_writel(au1xxx_dbdma_pm_regs[i][2], addr + 0x08);
-               au_writel(au1xxx_dbdma_pm_regs[i][3], addr + 0x0c);
-               au_writel(au1xxx_dbdma_pm_regs[i][4], addr + 0x10);
-               au_writel(au1xxx_dbdma_pm_regs[i][5], addr + 0x14);
+               au_writel(sdev->pm_regs[i][0], addr + 0x00);
+               au_writel(sdev->pm_regs[i][1], addr + 0x04);
+               au_writel(sdev->pm_regs[i][2], addr + 0x08);
+               au_writel(sdev->pm_regs[i][3], addr + 0x0c);
+               au_writel(sdev->pm_regs[i][4], addr + 0x10);
+               au_writel(sdev->pm_regs[i][5], addr + 0x14);
                au_sync();
                addr += 0x100;  /* next channel base */
        }
+
+       return 0;
+}
+
+static struct sysdev_class alchemy_dbdma_sysdev_class = {
+       .name           = "dbdma",
+       .suspend        = alchemy_dbdma_suspend,
+       .resume         = alchemy_dbdma_resume,
+};
+
+static int __init alchemy_dbdma_sysdev_init(void)
+{
+       struct alchemy_dbdma_sysdev *sdev;
+       int ret;
+
+       ret = sysdev_class_register(&alchemy_dbdma_sysdev_class);
+       if (ret)
+               return ret;
+
+       sdev = kzalloc(sizeof(struct alchemy_dbdma_sysdev), GFP_KERNEL);
+       if (!sdev)
+               return -ENOMEM;
+
+       sdev->sysdev.id = -1;
+       sdev->sysdev.cls = &alchemy_dbdma_sysdev_class;
+       ret = sysdev_register(&sdev->sysdev);
+       if (ret)
+               kfree(sdev);
+
+       return ret;
 }
-#endif /* CONFIG_PM */
 
 static int __init au1xxx_dbdma_init(void)
 {
@@ -1046,6 +1084,11 @@ static int __init au1xxx_dbdma_init(void)
        else {
                dbdma_initialized = 1;
                printk(KERN_INFO "Alchemy DBDMA initialized\n");
+               ret = alchemy_dbdma_sysdev_init();
+               if (ret) {
+                       printk(KERN_ERR "DBDMA PM init failed\n");
+                       ret = 0;
+               }
        }
 
        return ret;