Merge branch 'for-2.6.36' into for-2.6.37
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 16 Aug 2010 17:42:58 +0000 (18:42 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Mon, 16 Aug 2010 17:42:58 +0000 (18:42 +0100)
Fairly simple conflicts, the most serious ones are the i.MX ones which I
suspect now need another rename.

Conflicts:
arch/arm/mach-mx2/clock_imx27.c
arch/arm/mach-mx2/devices.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom2.c
sound/soc/fsl/mpc5200_dma.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc8610_hpcd.c
sound/soc/pxa/spitz.c

24 files changed:
1  2 
arch/arm/mach-ep93xx/core.c
arch/arm/mach-kirkwood/common.c
arch/arm/mach-mx3/clock-imx35.c
arch/arm/mach-mx3/devices.c
arch/arm/mach-omap1/devices.c
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/include/mach/board-zoom.h
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/pxa27x.c
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-s3c64xx/dev-audio.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/plat-mxc/audmux-v2.c
arch/arm/plat-samsung/include/plat/devs.h
sound/soc/codecs/wm8776.c
sound/soc/fsl/mpc5200_dma.h
sound/soc/fsl/mpc5200_psc_ac97.c
sound/soc/fsl/mpc5200_psc_i2s.c
sound/soc/imx/imx-ssi.c
sound/soc/soc-core.c

@@@ -29,6 -29,7 +29,7 @@@
  #include <linux/termios.h>
  #include <linux/amba/bus.h>
  #include <linux/amba/serial.h>
+ #include <linux/mtd/physmap.h>
  #include <linux/i2c.h>
  #include <linux/i2c-gpio.h>
  #include <linux/spi/spi.h>
@@@ -215,8 -216,8 +216,8 @@@ void ep93xx_devcfg_set_clear(unsigned i
        spin_lock_irqsave(&syscon_swlock, flags);
  
        val = __raw_readl(EP93XX_SYSCON_DEVCFG);
-       val |= set_bits;
        val &= ~clear_bits;
+       val |= set_bits;
        __raw_writel(0xaa, EP93XX_SYSCON_SWLOCK);
        __raw_writel(val, EP93XX_SYSCON_DEVCFG);
  
@@@ -347,6 -348,43 +348,43 @@@ static struct platform_device ep93xx_oh
  };
  
  
+ /*************************************************************************
+  * EP93xx physmap'ed flash
+  *************************************************************************/
+ static struct physmap_flash_data ep93xx_flash_data;
+ static struct resource ep93xx_flash_resource = {
+       .flags          = IORESOURCE_MEM,
+ };
+ static struct platform_device ep93xx_flash = {
+       .name           = "physmap-flash",
+       .id             = 0,
+       .dev            = {
+               .platform_data  = &ep93xx_flash_data,
+       },
+       .num_resources  = 1,
+       .resource       = &ep93xx_flash_resource,
+ };
+ /**
+  * ep93xx_register_flash() - Register the external flash device.
+  * @width:    bank width in octets
+  * @start:    resource start address
+  * @size:     resource size
+  */
+ void __init ep93xx_register_flash(unsigned int width,
+                                 resource_size_t start, resource_size_t size)
+ {
+       ep93xx_flash_data.width         = width;
+       ep93xx_flash_resource.start     = start;
+       ep93xx_flash_resource.end       = start + size - 1;
+       platform_device_register(&ep93xx_flash);
+ }
  /*************************************************************************
   * EP93xx ethernet peripheral handling
   *************************************************************************/
@@@ -620,6 -658,11 +658,11 @@@ static struct platform_device ep93xx_fb
        .resource               = ep93xx_fb_resource,
  };
  
+ static struct platform_device ep93xx_bl_device = {
+       .name           = "ep93xx-bl",
+       .id             = -1,
+ };
  /**
   * ep93xx_register_fb - Register the framebuffer platform device.
   * @data:     platform specific framebuffer configuration (__initdata)
@@@ -628,6 -671,7 +671,7 @@@ void __init ep93xx_register_fb(struct e
  {
        ep93xxfb_data = *data;
        platform_device_register(&ep93xx_fb_device);
+       platform_device_register(&ep93xx_bl_device);
  }
  
  
@@@ -732,15 -776,9 +776,15 @@@ static struct platform_device ep93xx_i2
        .resource       = ep93xx_i2s_resource,
  };
  
 +static struct platform_device ep93xx_pcm_device = {
 +      .name           = "ep93xx-pcm-audio",
 +      .id             = -1,
 +};
 +
  void __init ep93xx_register_i2s(void)
  {
        platform_device_register(&ep93xx_i2s_device);
 +      platform_device_register(&ep93xx_pcm_device);
  }
  
  #define EP93XX_SYSCON_DEVCFG_I2S_MASK (EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@@ -44,6 -44,11 +44,11 @@@ static struct map_desc kirkwood_io_desc
                .pfn            = __phys_to_pfn(KIRKWOOD_PCIE_IO_PHYS_BASE),
                .length         = KIRKWOOD_PCIE_IO_SIZE,
                .type           = MT_DEVICE,
+       }, {
+               .virtual        = KIRKWOOD_PCIE1_IO_VIRT_BASE,
+               .pfn            = __phys_to_pfn(KIRKWOOD_PCIE1_IO_PHYS_BASE),
+               .length         = KIRKWOOD_PCIE1_IO_SIZE,
+               .type           = MT_DEVICE,
        }, {
                .virtual        = KIRKWOOD_REGS_VIRT_BASE,
                .pfn            = __phys_to_pfn(KIRKWOOD_REGS_PHYS_BASE),
@@@ -403,7 -408,7 +408,7 @@@ void __init kirkwood_sdio_init(struct m
        u32 dev, rev;
  
        kirkwood_pcie_id(&dev, &rev);
-       if (rev == 0 /* catch all Kirkwood Z0's */
+       if (rev == 0 && dev != MV88F6282_DEV_ID) /* catch all Kirkwood Z0's */
                mvsdio_data->clock = 100000000;
        else
                mvsdio_data->clock = 200000000;
@@@ -848,8 -853,10 +853,10 @@@ int __init kirkwood_find_tclk(void
        u32 dev, rev;
  
        kirkwood_pcie_id(&dev, &rev);
-       if (dev == MV88F6281_DEV_ID && (rev == MV88F6281_REV_A0 ||
-                                       rev == MV88F6281_REV_A1))
+       if ((dev == MV88F6281_DEV_ID && (rev == MV88F6281_REV_A0 ||
+                                       rev == MV88F6281_REV_A1)) ||
+           (dev == MV88F6282_DEV_ID))
                return 200000000;
  
        return 166666667;
@@@ -896,16 -903,10 +903,16 @@@ static struct platform_device kirkwood_
        },
  };
  
 +static struct platform_device kirkwood_pcm_device = {
 +      .name           = "kirkwood-pcm",
 +      .id             = -1,
 +};
 +
  void __init kirkwood_audio_init(void)
  {
        kirkwood_clk_ctrl |= CGC_AUDIO;
        platform_device_register(&kirkwood_i2s_device);
 +      platform_device_register(&kirkwood_pcm_device);
  }
  
  /*****************************************************************************
@@@ -934,13 -935,22 +941,22 @@@ static char * __init kirkwood_id(void
                        return "MV88F6192-Z0";
                else if (rev == MV88F6192_REV_A0)
                        return "MV88F6192-A0";
+               else if (rev == MV88F6192_REV_A1)
+                       return "MV88F6192-A1";
                else
                        return "MV88F6192-Rev-Unsupported";
        } else if (dev == MV88F6180_DEV_ID) {
                if (rev == MV88F6180_REV_A0)
                        return "MV88F6180-Rev-A0";
+               else if (rev == MV88F6180_REV_A1)
+                       return "MV88F6180-Rev-A1";
                else
                        return "MV88F6180-Rev-Unsupported";
+       } else if (dev == MV88F6282_DEV_ID) {
+               if (rev == MV88F6282_REV_A0)
+                       return "MV88F6282-Rev-A0";
+               else
+                       return "MV88F6282-Rev-Unsupported";
        } else {
                return "Device-Unknown";
        }
@@@ -993,12 -1003,14 +1009,14 @@@ void __init kirkwood_init(void
  static int __init kirkwood_clock_gate(void)
  {
        unsigned int curr = readl(CLOCK_GATING_CTRL);
+       u32 dev, rev;
  
+       kirkwood_pcie_id(&dev, &rev);
        printk(KERN_DEBUG "Gating clock of unused units\n");
        printk(KERN_DEBUG "before: 0x%08x\n", curr);
  
        /* Make sure those units are accessible */
-       writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL);
+       writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0 | CGC_PEX1, CLOCK_GATING_CTRL);
  
        /* For SATA: first shutdown the phy */
        if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
                writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL);
        }
  
+       /* For PCIe 1: first shutdown the phy */
+       if (dev == MV88F6282_DEV_ID) {
+               if (!(kirkwood_clk_ctrl & CGC_PEX1)) {
+                       writel(readl(PCIE1_LINK_CTRL) | 0x10, PCIE1_LINK_CTRL);
+                       while (1)
+                               if (readl(PCIE1_STATUS) & 0x1)
+                                       break;
+                       writel(readl(PCIE1_LINK_CTRL) & ~0x10, PCIE1_LINK_CTRL);
+               }
+       } else  /* keep this bit set for devices that don't have PCIe1 */
+               kirkwood_clk_ctrl |= CGC_PEX1;
        /* Now gate clock the required units */
        writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL);
        printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL));
@@@ -359,7 -359,7 +359,7 @@@ DEFINE_CLOCK(i2c1_clk,   0, CCM_CGR1, 1
  DEFINE_CLOCK(i2c2_clk,   1, CCM_CGR1, 12, get_rate_ipg_per, NULL);
  DEFINE_CLOCK(i2c3_clk,   2, CCM_CGR1, 14, get_rate_ipg_per, NULL);
  DEFINE_CLOCK(iomuxc_clk, 0, CCM_CGR1, 16, NULL, NULL);
- DEFINE_CLOCK(ipu_clk,    0, CCM_CGR1, 18, NULL, NULL);
+ DEFINE_CLOCK(ipu_clk,    0, CCM_CGR1, 18, get_rate_ahb, NULL);
  DEFINE_CLOCK(kpp_clk,    0, CCM_CGR1, 20, get_rate_ipg, NULL);
  DEFINE_CLOCK(mlb_clk,    0, CCM_CGR1, 22, get_rate_ahb, NULL);
  DEFINE_CLOCK(mshc_clk,   0, CCM_CGR1, 24, get_rate_mshc, NULL);
@@@ -428,8 -428,8 +428,8 @@@ static struct clk nfc_clk = 
  static struct clk_lookup lookups[] = {
        _REGISTER_CLOCK(NULL, "asrc", asrc_clk)
        _REGISTER_CLOCK(NULL, "ata", ata_clk)
-       _REGISTER_CLOCK(NULL, "can", can1_clk)
-       _REGISTER_CLOCK(NULL, "can", can2_clk)
+       _REGISTER_CLOCK("flexcan.0", NULL, can1_clk)
+       _REGISTER_CLOCK("flexcan.1", NULL, can2_clk)
        _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
        _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
        _REGISTER_CLOCK(NULL, "ect", ect_clk)
        _REGISTER_CLOCK(NULL, "sdma", sdma_clk)
        _REGISTER_CLOCK(NULL, "spba", spba_clk)
        _REGISTER_CLOCK(NULL, "spdif", spdif_clk)
 -      _REGISTER_CLOCK("imx-ssi.0", NULL, ssi1_clk)
 -      _REGISTER_CLOCK("imx-ssi.1", NULL, ssi2_clk)
 +      _REGISTER_CLOCK("imx-ssi-dai.0", NULL, ssi1_clk)
 +      _REGISTER_CLOCK("imx-ssi-dai.1", NULL, ssi2_clk)
        _REGISTER_CLOCK("imx-uart.0", NULL, uart1_clk)
        _REGISTER_CLOCK("imx-uart.1", NULL, uart2_clk)
        _REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
  #include <mach/hardware.h>
  #include <mach/irqs.h>
  #include <mach/common.h>
- #include <mach/imx-uart.h>
  #include <mach/mx3_camera.h>
  
  #include "devices.h"
  
- static struct resource uart0[] = {
-       {
-               .start = UART1_BASE_ADDR,
-               .end = UART1_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART1,
-               .end = MXC_INT_UART1,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_uart_device0 = {
-       .name = "imx-uart",
-       .id = 0,
-       .resource = uart0,
-       .num_resources = ARRAY_SIZE(uart0),
- };
- static struct resource uart1[] = {
-       {
-               .start = UART2_BASE_ADDR,
-               .end = UART2_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART2,
-               .end = MXC_INT_UART2,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_uart_device1 = {
-       .name = "imx-uart",
-       .id = 1,
-       .resource = uart1,
-       .num_resources = ARRAY_SIZE(uart1),
- };
- static struct resource uart2[] = {
-       {
-               .start = UART3_BASE_ADDR,
-               .end = UART3_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART3,
-               .end = MXC_INT_UART3,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_uart_device2 = {
-       .name = "imx-uart",
-       .id = 2,
-       .resource = uart2,
-       .num_resources = ARRAY_SIZE(uart2),
- };
- #ifdef CONFIG_ARCH_MX31
- static struct resource uart3[] = {
-       {
-               .start = UART4_BASE_ADDR,
-               .end = UART4_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART4,
-               .end = MXC_INT_UART4,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_uart_device3 = {
-       .name = "imx-uart",
-       .id = 3,
-       .resource = uart3,
-       .num_resources = ARRAY_SIZE(uart3),
- };
- static struct resource uart4[] = {
-       {
-               .start = UART5_BASE_ADDR,
-               .end = UART5_BASE_ADDR + 0x0B5,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_UART5,
-               .end = MXC_INT_UART5,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_uart_device4 = {
-       .name = "imx-uart",
-       .id = 4,
-       .resource = uart4,
-       .num_resources = ARRAY_SIZE(uart4),
- };
- #endif /* CONFIG_ARCH_MX31 */
  /* GPIO port description */
  static struct mxc_gpio_port imx_gpio_ports[] = {
        {
        }
  };
  
- int __init mxc_register_gpios(void)
+ int __init imx3x_register_gpios(void)
  {
        return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
  }
@@@ -167,82 -69,6 +69,6 @@@ struct platform_device mxc_w1_master_de
        .resource = mxc_w1_master_resources,
  };
  
- static struct resource mxc_nand_resources[] = {
-       {
-               .start  = 0, /* runtime dependent */
-               .end    = 0,
-               .flags  = IORESOURCE_MEM,
-       }, {
-               .start  = MXC_INT_NANDFC,
-               .end    = MXC_INT_NANDFC,
-               .flags  = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_nand_device = {
-       .name = "mxc_nand",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_nand_resources),
-       .resource = mxc_nand_resources,
- };
- static struct resource mxc_i2c0_resources[] = {
-       {
-               .start = I2C_BASE_ADDR,
-               .end = I2C_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_I2C,
-               .end = MXC_INT_I2C,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_i2c_device0 = {
-       .name = "imx-i2c",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_i2c0_resources),
-       .resource = mxc_i2c0_resources,
- };
- static struct resource mxc_i2c1_resources[] = {
-       {
-               .start = I2C2_BASE_ADDR,
-               .end = I2C2_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_I2C2,
-               .end = MXC_INT_I2C2,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_i2c_device1 = {
-       .name = "imx-i2c",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_i2c1_resources),
-       .resource = mxc_i2c1_resources,
- };
- static struct resource mxc_i2c2_resources[] = {
-       {
-               .start = I2C3_BASE_ADDR,
-               .end = I2C3_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_I2C3,
-               .end = MXC_INT_I2C3,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_i2c_device2 = {
-       .name = "imx-i2c",
-       .id = 2,
-       .num_resources = ARRAY_SIZE(mxc_i2c2_resources),
-       .resource = mxc_i2c2_resources,
- };
  #ifdef CONFIG_ARCH_MX31
  static struct resource mxcsdhc0_resources[] = {
        {
@@@ -455,68 -281,7 +281,7 @@@ struct platform_device mxc_usbh2 = 
        .num_resources = ARRAY_SIZE(mxc_usbh2_resources),
  };
  
- /*
-  * SPI master controller
-  * 3 channels
-  */
- static struct resource mxc_spi_0_resources[] = {
-       {
-              .start = CSPI1_BASE_ADDR,
-              .end = CSPI1_BASE_ADDR + SZ_4K - 1,
-              .flags = IORESOURCE_MEM,
-       }, {
-              .start = MXC_INT_CSPI1,
-              .end = MXC_INT_CSPI1,
-              .flags = IORESOURCE_IRQ,
-       },
- };
- static struct resource mxc_spi_1_resources[] = {
-       {
-               .start = CSPI2_BASE_ADDR,
-               .end = CSPI2_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_CSPI2,
-               .end = MXC_INT_CSPI2,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- static struct resource mxc_spi_2_resources[] = {
-       {
-               .start = CSPI3_BASE_ADDR,
-               .end = CSPI3_BASE_ADDR + SZ_4K - 1,
-               .flags = IORESOURCE_MEM,
-       }, {
-               .start = MXC_INT_CSPI3,
-               .end = MXC_INT_CSPI3,
-               .flags = IORESOURCE_IRQ,
-       },
- };
- struct platform_device mxc_spi_device0 = {
-       .name = "spi_imx",
-       .id = 0,
-       .num_resources = ARRAY_SIZE(mxc_spi_0_resources),
-       .resource = mxc_spi_0_resources,
- };
- struct platform_device mxc_spi_device1 = {
-       .name = "spi_imx",
-       .id = 1,
-       .num_resources = ARRAY_SIZE(mxc_spi_1_resources),
-       .resource = mxc_spi_1_resources,
- };
- struct platform_device mxc_spi_device2 = {
-       .name = "spi_imx",
-       .id = 2,
-       .num_resources = ARRAY_SIZE(mxc_spi_2_resources),
-       .resource = mxc_spi_2_resources,
- };
- #ifdef CONFIG_ARCH_MX35
+ #if defined(CONFIG_ARCH_MX35)
  static struct resource mxc_fec_resources[] = {
        {
                .start  = MXC_FEC_BASE_ADDR,
@@@ -562,14 -327,14 +327,14 @@@ static struct resource imx_ssi_resource
  };
  
  struct platform_device imx_ssi_device0 = {
 -      .name = "imx-ssi",
 +      .name = "imx-ssi-dai",
        .id = 0,
        .num_resources = ARRAY_SIZE(imx_ssi_resources0),
        .resource = imx_ssi_resources0,
  };
  
  struct platform_device imx_ssi_device1 = {
 -      .name = "imx-ssi",
 +      .name = "imx-ssi-dai",
        .id = 1,
        .num_resources = ARRAY_SIZE(imx_ssi_resources1),
        .resource = imx_ssi_resources1,
@@@ -628,16 -393,15 +393,15 @@@ struct platform_device imx_kpp_device 
  
  static int __init mx3_devices_init(void)
  {
+ #if defined(CONFIG_ARCH_MX31)
        if (cpu_is_mx31()) {
-               mxc_nand_resources[0].start = MX31_NFC_BASE_ADDR;
-               mxc_nand_resources[0].end = MX31_NFC_BASE_ADDR + 0xfff;
                imx_wdt_resources[0].start = MX31_WDOG_BASE_ADDR;
                imx_wdt_resources[0].end = MX31_WDOG_BASE_ADDR + 0x3fff;
                mxc_register_device(&mxc_rnga_device, NULL);
        }
+ #endif
+ #if defined(CONFIG_ARCH_MX35)
        if (cpu_is_mx35()) {
-               mxc_nand_resources[0].start = MX35_NFC_BASE_ADDR;
-               mxc_nand_resources[0].end = MX35_NFC_BASE_ADDR + 0x1fff;
                otg_resources[0].start = MX35_OTG_BASE_ADDR;
                otg_resources[0].end = MX35_OTG_BASE_ADDR + 0x1ff;
                otg_resources[1].start = MXC_INT_USBOTG;
                imx_wdt_resources[0].start = MX35_WDOG_BASE_ADDR;
                imx_wdt_resources[0].end = MX35_WDOG_BASE_ADDR + 0x3fff;
        }
+ #endif
  
        return 0;
  }
@@@ -25,7 -25,6 +25,7 @@@
  #include <mach/gpio.h>
  #include <plat/mmc.h>
  #include <plat/omap7xx.h>
 +#include <plat/mcbsp.h>
  
  /*-------------------------------------------------------------------------*/
  
@@@ -64,44 -63,7 +64,7 @@@ static void omap_init_rtc(void
  static inline void omap_init_rtc(void) {}
  #endif
  
- #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE)
- #if defined(CONFIG_ARCH_OMAP15XX)
- #  define OMAP1_MBOX_SIZE     0x23
- #  define INT_DSP_MAILBOX1    INT_1510_DSP_MAILBOX1
- #elif defined(CONFIG_ARCH_OMAP16XX)
- #  define OMAP1_MBOX_SIZE     0x2f
- #  define INT_DSP_MAILBOX1    INT_1610_DSP_MAILBOX1
- #endif
- #define OMAP1_MBOX_BASE               OMAP16XX_MAILBOX_BASE
- static struct resource mbox_resources[] = {
-       {
-               .start          = OMAP1_MBOX_BASE,
-               .end            = OMAP1_MBOX_BASE + OMAP1_MBOX_SIZE,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = INT_DSP_MAILBOX1,
-               .flags          = IORESOURCE_IRQ,
-       },
- };
- static struct platform_device mbox_device = {
-       .name           = "omap1-mailbox",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(mbox_resources),
-       .resource       = mbox_resources,
- };
- static inline void omap_init_mbox(void)
- {
-       platform_device_register(&mbox_device);
- }
- #else
  static inline void omap_init_mbox(void) { }
- #endif
  
  /*-------------------------------------------------------------------------*/
  
@@@ -231,67 -193,8 +194,32 @@@ static inline void omap_init_spi100k(vo
  
  /*-------------------------------------------------------------------------*/
  
- #if defined(CONFIG_OMAP_STI)
- #define OMAP1_STI_BASE                0xfffea000
- #define OMAP1_STI_CHANNEL_BASE        (OMAP1_STI_BASE + 0x400)
- static struct resource sti_resources[] = {
-       {
-               .start          = OMAP1_STI_BASE,
-               .end            = OMAP1_STI_BASE + SZ_1K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP1_STI_CHANNEL_BASE,
-               .end            = OMAP1_STI_CHANNEL_BASE + SZ_1K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = INT_1610_STI,
-               .flags          = IORESOURCE_IRQ,
-       }
- };
- static struct platform_device sti_device = {
-       .name           = "sti",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(sti_resources),
-       .resource       = sti_resources,
- };
- static inline void omap_init_sti(void)
- {
-       platform_device_register(&sti_device);
- }
- #else
  static inline void omap_init_sti(void) {}
- #endif
  
 +#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
 +
 +static struct platform_device omap_pcm = {
 +      .name   = "omap-pcm-audio",
 +      .id     = -1,
 +};
 +
 +OMAP_MCBSP_PLATFORM_DEVICE(1);
 +OMAP_MCBSP_PLATFORM_DEVICE(2);
 +OMAP_MCBSP_PLATFORM_DEVICE(3);
 +
 +static void omap_init_audio(void)
 +{
 +      platform_device_register(&omap_mcbsp1);
 +      platform_device_register(&omap_mcbsp2);
 +      if (!cpu_is_omap7xx())
 +              platform_device_register(&omap_mcbsp3);
 +      platform_device_register(&omap_pcm);
 +}
 +
 +#else
 +static inline void omap_init_audio(void) {}
 +#endif
 +
  /*-------------------------------------------------------------------------*/
  
  /*
@@@ -324,7 -227,6 +252,7 @@@ static int __init omap1_init_devices(vo
        omap_init_rtc();
        omap_init_spi100k();
        omap_init_sti();
 +      omap_init_audio();
  
        return 0;
  }
@@@ -20,7 -20,6 +20,7 @@@
  #include <linux/i2c.h>
  #include <linux/spi/spi.h>
  #include <linux/usb/musb.h>
 +#include <sound/tlv320aic3x.h>
  
  #include <asm/mach/arch.h>
  #include <asm/mach-types.h>
@@@ -34,6 -33,8 +34,8 @@@
  #include <plat/mmc.h>
  #include <plat/serial.h>
  
+ #include "mux.h"
  static int slot1_cover_open;
  static int slot2_cover_open;
  static struct device *mmc_device;
@@@ -613,25 -614,11 +615,25 @@@ static int n8x0_menelaus_late_init(stru
        return 0;
  }
  
 +static struct aic3x_setup_data n810_aic33_setup = {
 +      .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
 +      .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
 +};
 +
 +static struct aic3x_pdata n810_aic33_data = {
 +      .setup = &n810_aic33_setup,
 +      .gpio_reset = -1,
 +};
 +
  static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] = {
        {
                I2C_BOARD_INFO("menelaus", 0x72),
                .irq = INT_24XX_SYS_NIRQ,
        },
 +      {
 +              I2C_BOARD_INFO("tlv320aic3x", 0x1b),
 +              .platform_data = &n810_aic33_data,
 +      },
  };
  
  static struct menelaus_platform_data n8x0_menelaus_platform_data = {
@@@ -664,8 -651,17 +666,17 @@@ static void __init n8x0_init_irq(void
        omap_gpio_init();
  }
  
+ #ifdef CONFIG_OMAP_MUX
+ static struct omap_board_mux board_mux[] __initdata = {
+       { .reg_offset = OMAP_MUX_TERMINATOR },
+ };
+ #else
+ #define board_mux     NULL
+ #endif
  static void __init n8x0_init_machine(void)
  {
+       omap2420_mux_init(board_mux, OMAP_PACKAGE_ZAC);
        /* FIXME: add n810 spi devices */
        spi_register_board_info(n800_spi_board_info,
                                ARRAY_SIZE(n800_spi_board_info));
@@@ -682,6 -678,7 +693,7 @@@ MACHINE_START(NOKIA_N800, "Nokia N800"
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = n8x0_init_irq,
        .init_machine   = n8x0_init_machine,
        .timer          = &omap_timer,
@@@ -692,6 -689,7 +704,7 @@@ MACHINE_START(NOKIA_N810, "Nokia N810"
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = n8x0_init_irq,
        .init_machine   = n8x0_init_machine,
        .timer          = &omap_timer,
@@@ -702,6 -700,7 +715,7 @@@ MACHINE_START(NOKIA_N810_WIMAX, "Nokia 
        .io_pg_offst    = ((0xfa000000) >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
        .map_io         = n8x0_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = n8x0_init_irq,
        .init_machine   = n8x0_init_machine,
        .timer          = &omap_timer,
  #include <linux/gpio.h>
  #include <linux/gpio_keys.h>
  #include <linux/mmc/host.h>
 +#include <sound/tlv320aic3x.h>
  
  #include <plat/mcspi.h>
- #include <plat/mux.h>
  #include <plat/board.h>
  #include <plat/common.h>
  #include <plat/dma.h>
  #include <plat/onenand.h>
  #include <plat/gpmc-smc91x.h>
  
+ #include <sound/tlv320aic3x.h>
+ #include <sound/tpa6130a2-plat.h>
+ #include <../drivers/staging/iio/light/tsl2563.h>
  #include "mux.h"
  #include "hsmmc.h"
  
@@@ -52,6 -55,12 +56,12 @@@ enum 
  
  static struct wl12xx_platform_data wl1251_pdata;
  
+ #if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE)
+ static struct tsl2563_platform_data rx51_tsl2563_platform_data = {
+       .cover_comp_gain = 16,
+ };
+ #endif
  static struct omap2_mcspi_device_config wl1251_mcspi_config = {
        .turbo_mode     = 0,
        .single_channel = 1,
@@@ -176,6 -185,10 +186,10 @@@ static void __init rx51_add_gpio_keys(v
  #endif /* CONFIG_KEYBOARD_GPIO || CONFIG_KEYBOARD_GPIO_MODULE */
  
  static int board_keymap[] = {
+       /*
+        * Note that KEY(x, 8, KEY_XXX) entries represent "entrire row
+        * connected to the ground" matrix state.
+        */
        KEY(0, 0, KEY_Q),
        KEY(0, 1, KEY_O),
        KEY(0, 2, KEY_P),
        KEY(0, 4, KEY_BACKSPACE),
        KEY(0, 6, KEY_A),
        KEY(0, 7, KEY_S),
        KEY(1, 0, KEY_W),
        KEY(1, 1, KEY_D),
        KEY(1, 2, KEY_F),
        KEY(1, 5, KEY_J),
        KEY(1, 6, KEY_K),
        KEY(1, 7, KEY_L),
        KEY(2, 0, KEY_E),
        KEY(2, 1, KEY_DOT),
        KEY(2, 2, KEY_UP),
        KEY(2, 5, KEY_Z),
        KEY(2, 6, KEY_X),
        KEY(2, 7, KEY_C),
+       KEY(2, 8, KEY_F9),
        KEY(3, 0, KEY_R),
        KEY(3, 1, KEY_V),
        KEY(3, 2, KEY_B),
        KEY(3, 5, KEY_SPACE),
        KEY(3, 6, KEY_SPACE),
        KEY(3, 7, KEY_LEFT),
        KEY(4, 0, KEY_T),
        KEY(4, 1, KEY_DOWN),
        KEY(4, 2, KEY_RIGHT),
        KEY(4, 4, KEY_LEFTCTRL),
        KEY(4, 5, KEY_RIGHTALT),
        KEY(4, 6, KEY_LEFTSHIFT),
+       KEY(4, 8, KEY_F10),
        KEY(5, 0, KEY_Y),
+       KEY(5, 8, KEY_F11),
        KEY(6, 0, KEY_U),
        KEY(7, 0, KEY_I),
        KEY(7, 1, KEY_F7),
        KEY(7, 2, KEY_F8),
-       KEY(0xff, 2, KEY_F9),
-       KEY(0xff, 4, KEY_F10),
-       KEY(0xff, 5, KEY_F11),
  };
  
  static struct matrix_keymap_data board_map_data = {
@@@ -301,48 -321,29 +322,29 @@@ static struct omap2_hsmmc_info mmc[] __
        {}      /* Terminator */
  };
  
- static struct regulator_consumer_supply rx51_vmmc1_supply = {
-       .supply   = "vmmc",
-       .dev_name = "mmci-omap-hs.0",
- };
+ static struct regulator_consumer_supply rx51_vmmc1_supply =
+       REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.0");
  
- static struct regulator_consumer_supply rx51_vaux3_supply = {
-       .supply   = "vmmc",
-       .dev_name = "mmci-omap-hs.1",
- };
+ static struct regulator_consumer_supply rx51_vaux3_supply =
+       REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1");
  
- static struct regulator_consumer_supply rx51_vsim_supply = {
-       .supply   = "vmmc_aux",
-       .dev_name = "mmci-omap-hs.1",
- };
+ static struct regulator_consumer_supply rx51_vsim_supply =
+       REGULATOR_SUPPLY("vmmc_aux", "mmci-omap-hs.1");
  
  static struct regulator_consumer_supply rx51_vmmc2_supplies[] = {
        /* tlv320aic3x analog supplies */
-       {
-               .supply         = "AVDD",
-               .dev_name       = "2-0018",
-       },
-       {
-               .supply         = "DRVDD",
-               .dev_name       = "2-0018",
-       },
+       REGULATOR_SUPPLY("AVDD", "2-0018"),
+       REGULATOR_SUPPLY("DRVDD", "2-0018"),
+       /* tpa6130a2 */
+       REGULATOR_SUPPLY("Vdd", "2-0060"),
        /* Keep vmmc as last item. It is not iterated for newer boards */
-       {
-               .supply         = "vmmc",
-               .dev_name       = "mmci-omap-hs.1",
-       },
+       REGULATOR_SUPPLY("vmmc", "mmci-omap-hs.1"),
  };
  
  static struct regulator_consumer_supply rx51_vio_supplies[] = {
        /* tlv320aic3x digital supplies */
-       {
-               .supply         = "IOVDD",
-               .dev_name       = "2-0018"
-       },
-       {
-               .supply         = "DVDD",
-               .dev_name       = "2-0018"
-       },
+       REGULATOR_SUPPLY("IOVDD", "2-0018"),
+       REGULATOR_SUPPLY("DVDD", "2-0018"),
  };
  
  #if defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)
@@@ -363,6 -364,7 +365,7 @@@ static struct regulator_init_data rx51_
                .name                   = "V28",
                .min_uV                 = 2800000,
                .max_uV                 = 2800000,
+               .always_on              = true, /* due battery cover sensor */
                .valid_modes_mask       = REGULATOR_MODE_NORMAL
                                        | REGULATOR_MODE_STANDBY,
                .valid_ops_mask         = REGULATOR_CHANGE_MODE
@@@ -687,6 -689,7 +690,6 @@@ static struct twl4030_power_data rx51_t
  };
  
  
 -
  static struct twl4030_platform_data rx51_twldata __initdata = {
        .irq_base               = TWL4030_IRQ_BASE,
        .irq_end                = TWL4030_IRQ_END,
        .vio                    = &rx51_vio,
  };
  
+ static struct aic3x_pdata rx51_aic3x_data __initdata = {
+       .gpio_reset             = 60,
+ };
+ static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata = {
+       .id                     = TPA6130A2,
+       .power_gpio             = 98,
+ };
  static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
        {
                I2C_BOARD_INFO("twl5030", 0x48),
        },
  };
  
- static struct aic3x_pdata rx51_aic34_data = {
 +/* Audio setup data */
 +static struct aic3x_setup_data rx51_aic34_setup = {
 +      .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED,
 +      .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT,
 +};
 +
++static struct aic3x_pdata rx51_aic3x_data = {
 +      .setup = &rx51_aic34_setup,
 +      .gpio_reset = 60,
 +};
 +
  static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
        {
                I2C_BOARD_INFO("tlv320aic3x", 0x18),
-               .platform_data = &rx51_aic34_data,
+               .platform_data = &rx51_aic3x_data,
+       },
+ #if defined(CONFIG_SENSORS_TSL2563) || defined(CONFIG_SENSORS_TSL2563_MODULE)
+       {
+               I2C_BOARD_INFO("tsl2563", 0x29),
+               .platform_data = &rx51_tsl2563_platform_data,
        },
+ #endif
+       {
+               I2C_BOARD_INFO("tpa6130a2", 0x60),
+               .platform_data = &rx51_tpa6130a2_data,
+       }
  };
  
  static int __init rx51_i2c_init(void)
@@@ -14,7 -14,6 +14,7 @@@
  #include <linux/platform_device.h>
  #include <linux/input.h>
  #include <linux/gpio.h>
 +#include <linux/i2c/twl.h>
  
  #include <asm/mach-types.h>
  #include <asm/mach/arch.h>
@@@ -35,11 -34,8 +35,11 @@@ static void __init omap_zoom2_init_irq(
        omap_gpio_init();
  }
  
 -/* REVISIT: These audio entries can be removed once MFD code is merged */
 -#if 0
 +/* EXTMUTE callback function */
 +void zoom2_set_hs_extmute(int mute)
 +{
 +      gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
 +}
  
  static struct twl4030_madc_platform_data zoom2_madc_data = {
        .irq_line       = 1,
@@@ -47,9 -43,6 +47,9 @@@
  
  static struct twl4030_codec_audio_data zoom2_audio_data = {
        .audio_mclk = 26000000,
 +      .ramp_delay_value = 3,  /* 161 ms */
 +      .hs_extmute = 1,
 +      .set_hs_extmute = zoom2_set_hs_extmute,
  };
  
  static struct twl4030_codec_data zoom2_codec_data = {
@@@ -71,52 -64,88 +71,103 @@@ static struct twl4030_platform_data zoo
        .vmmc1          = &zoom2_vmmc1,
        .vmmc2          = &zoom2_vmmc2,
        .vsim           = &zoom2_vsim,
 +};
  
 +static struct i2c_board_info __initdata zoom2_i2c_boardinfo[] = {
 +      {
 +              I2C_BOARD_INFO("twl4030", 0x48),
 +              .flags = I2C_CLIENT_WAKE,
 +              .irq = INT_34XX_SYS_NIRQ,
 +              .platform_data = &zoom2_twldata,
 +      },
  };
  
 -#endif
 +static int __init omap3_zoom2_i2c_init(void)
 +{
 +      omap_register_i2c_bus(1, 2600, zoom2_i2c_boardinfo,
 +                      ARRAY_SIZE(zoom2_i2c_boardinfo));
 +      return 0;
 +}
 +
  
  #ifdef CONFIG_OMAP_MUX
  static struct omap_board_mux board_mux[] __initdata = {
+       /* WLAN IRQ - GPIO 162 */
+       OMAP3_MUX(MCBSP1_CLKX, OMAP_MUX_MODE4 | OMAP_PIN_INPUT_PULLUP),
+       /* WLAN POWER ENABLE - GPIO 101 */
+       OMAP3_MUX(CAM_D2, OMAP_MUX_MODE4 | OMAP_PIN_OUTPUT),
+       /* WLAN SDIO: MMC3 CMD */
+       OMAP3_MUX(MCSPI1_CS1, OMAP_MUX_MODE3 | OMAP_PIN_INPUT_PULLUP),
+       /* WLAN SDIO: MMC3 CLK */
+       OMAP3_MUX(ETK_CLK, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP),
+       /* WLAN SDIO: MMC3 DAT[0-3] */
+       OMAP3_MUX(ETK_D3, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP),
+       OMAP3_MUX(ETK_D4, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP),
+       OMAP3_MUX(ETK_D5, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP),
+       OMAP3_MUX(ETK_D6, OMAP_MUX_MODE2 | OMAP_PIN_INPUT_PULLUP),
        { .reg_offset = OMAP_MUX_TERMINATOR },
  };
  #else
  #define board_mux     NULL
  #endif
  
+ static struct mtd_partition zoom_nand_partitions[] = {
+       /* All the partition sizes are listed in terms of NAND block size */
+       {
+               .name           = "X-Loader-NAND",
+               .offset         = 0,
+               .size           = 4 * (64 * 2048),      /* 512KB, 0x80000 */
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "U-Boot-NAND",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x80000 */
+               .size           = 10 * (64 * 2048),     /* 1.25MB, 0x140000 */
+               .mask_flags     = MTD_WRITEABLE,        /* force read-only */
+       },
+       {
+               .name           = "Boot Env-NAND",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x1c0000 */
+               .size           = 2 * (64 * 2048),      /* 256KB, 0x40000 */
+       },
+       {
+               .name           = "Kernel-NAND",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x0200000*/
+               .size           = 240 * (64 * 2048),    /* 30M, 0x1E00000 */
+       },
+       {
+               .name           = "system",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x2000000 */
+               .size           = 3328 * (64 * 2048),   /* 416M, 0x1A000000 */
+       },
+       {
+               .name           = "userdata",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x1C000000*/
+               .size           = 256 * (64 * 2048),    /* 32M, 0x2000000 */
+       },
+       {
+               .name           = "cache",
+               .offset         = MTDPART_OFS_APPEND,   /* Offset = 0x1E000000*/
+               .size           = 256 * (64 * 2048),    /* 32M, 0x2000000 */
+       },
+ };
  static void __init omap_zoom2_init(void)
  {
        omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
        zoom_peripherals_init();
 +      omap3_zoom2_i2c_init();
+       board_nand_init(zoom_nand_partitions,
+                       ARRAY_SIZE(zoom_nand_partitions), ZOOM_NAND_CS);
        zoom_debugboard_init();
  }
  
- static void __init omap_zoom2_map_io(void)
- {
-       omap2_set_globals_343x();
-       omap34xx_map_common_io();
- }
  MACHINE_START(OMAP_ZOOM2, "OMAP Zoom2 board")
        .phys_io        = ZOOM_UART_BASE,
        .io_pg_offst    = (ZOOM_UART_VIRT >> 18) & 0xfffc,
        .boot_params    = 0x80000100,
-       .map_io         = omap_zoom2_map_io,
+       .map_io         = omap3_map_io,
+       .reserve        = omap_reserve,
        .init_irq       = omap_zoom2_init_irq,
        .init_machine   = omap_zoom2_init,
        .timer          = &omap_timer,
  #include <plat/control.h>
  #include <plat/tc.h>
  #include <plat/board.h>
- #include <plat/mux.h>
  #include <mach/gpio.h>
  #include <plat/mmc.h>
  #include <plat/dma.h>
 +#include <plat/mcbsp.h>
  
  #include "mux.h"
  
@@@ -154,10 -152,12 +153,12 @@@ static struct resource omap2_mbox_resou
        {
                .start          = INT_24XX_MAIL_U0_MPU,
                .flags          = IORESOURCE_IRQ,
+               .name           = "dsp",
        },
        {
                .start          = INT_24XX_MAIL_U3_MPU,
                .flags          = IORESOURCE_IRQ,
+               .name           = "iva",
        },
  };
  static int omap2_mbox_resources_sz = ARRAY_SIZE(omap2_mbox_resources);
@@@ -176,6 -176,7 +177,7 @@@ static struct resource omap3_mbox_resou
        {
                .start          = INT_24XX_MAIL_U0_MPU,
                .flags          = IORESOURCE_IRQ,
+               .name           = "dsp",
        },
  };
  static int omap3_mbox_resources_sz = ARRAY_SIZE(omap3_mbox_resources);
@@@ -197,6 -198,7 +199,7 @@@ static struct resource omap4_mbox_resou
        {
                .start          = OMAP44XX_IRQ_MAIL_U0,
                .flags          = IORESOURCE_IRQ,
+               .name           = "mbox",
        },
  };
  static int omap4_mbox_resources_sz = ARRAY_SIZE(omap4_mbox_resources);
  #endif
  
  static struct platform_device mbox_device = {
-       .name           = "omap2-mailbox",
+       .name           = "omap-mailbox",
        .id             = -1,
  };
  
@@@ -231,102 -233,8 +234,45 @@@ static inline void omap_init_mbox(void
  static inline void omap_init_mbox(void) { }
  #endif /* CONFIG_OMAP_MBOX_FWK */
  
- #if defined(CONFIG_OMAP_STI)
- #if defined(CONFIG_ARCH_OMAP2)
- #define OMAP2_STI_BASE                0x48068000
- #define OMAP2_STI_CHANNEL_BASE        0x54000000
- #define OMAP2_STI_IRQ         4
- static struct resource sti_resources[] = {
-       {
-               .start          = OMAP2_STI_BASE,
-               .end            = OMAP2_STI_BASE + 0x7ff,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP2_STI_CHANNEL_BASE,
-               .end            = OMAP2_STI_CHANNEL_BASE + SZ_64K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP2_STI_IRQ,
-               .flags          = IORESOURCE_IRQ,
-       }
- };
- #elif defined(CONFIG_ARCH_OMAP3)
- #define OMAP3_SDTI_BASE               0x54500000
- #define OMAP3_SDTI_CHANNEL_BASE       0x54600000
- static struct resource sti_resources[] = {
-       {
-               .start          = OMAP3_SDTI_BASE,
-               .end            = OMAP3_SDTI_BASE + 0xFFF,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = OMAP3_SDTI_CHANNEL_BASE,
-               .end            = OMAP3_SDTI_CHANNEL_BASE + SZ_1M - 1,
-               .flags          = IORESOURCE_MEM,
-       }
- };
- #endif
- static struct platform_device sti_device = {
-       .name           = "sti",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(sti_resources),
-       .resource       = sti_resources,
- };
- static inline void omap_init_sti(void)
- {
-       platform_device_register(&sti_device);
- }
- #else
  static inline void omap_init_sti(void) {}
- #endif
  
 +#if defined(CONFIG_SND_SOC) || defined(CONFIG_SND_SOC_MODULE)
 +
 +static struct platform_device omap_pcm = {
 +      .name   = "omap-pcm-audio",
 +      .id     = -1,
 +};
 +
 +/*
 + * OMAP2420 has 2 McBSP ports
 + * OMAP2430 has 5 McBSP ports
 + * OMAP3 has 5 McBSP ports
 + * OMAP4 has 4 McBSP ports
 + */
 +OMAP_MCBSP_PLATFORM_DEVICE(1);
 +OMAP_MCBSP_PLATFORM_DEVICE(2);
 +OMAP_MCBSP_PLATFORM_DEVICE(3);
 +OMAP_MCBSP_PLATFORM_DEVICE(4);
 +OMAP_MCBSP_PLATFORM_DEVICE(5);
 +
 +static void omap_init_audio(void)
 +{
 +      platform_device_register(&omap_mcbsp1);
 +      platform_device_register(&omap_mcbsp2);
 +      if (cpu_is_omap243x() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
 +              platform_device_register(&omap_mcbsp3);
 +              platform_device_register(&omap_mcbsp4);
 +      }
 +      if (cpu_is_omap243x() || cpu_is_omap34xx())
 +              platform_device_register(&omap_mcbsp5);
 +
 +      platform_device_register(&omap_pcm);
 +}
 +
 +#else
 +static inline void omap_init_audio(void) {}
 +#endif
 +
  #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
  
  #include <plat/mcspi.h>
@@@ -710,19 -618,19 +656,19 @@@ static inline void omap2_mmc_mux(struc
                                        OMAP_PIN_INPUT_PULLUP);
  
        if (cpu_is_omap2420() && controller_nr == 0) {
-               omap_cfg_reg(H18_24XX_MMC_CMD);
-               omap_cfg_reg(H15_24XX_MMC_CLKI);
-               omap_cfg_reg(G19_24XX_MMC_CLKO);
-               omap_cfg_reg(F20_24XX_MMC_DAT0);
-               omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
-               omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
+               omap_mux_init_signal("sdmmc_cmd", 0);
+               omap_mux_init_signal("sdmmc_clki", 0);
+               omap_mux_init_signal("sdmmc_clko", 0);
+               omap_mux_init_signal("sdmmc_dat0", 0);
+               omap_mux_init_signal("sdmmc_dat_dir0", 0);
+               omap_mux_init_signal("sdmmc_cmd_dir", 0);
                if (mmc_controller->slots[0].wires == 4) {
-                       omap_cfg_reg(H14_24XX_MMC_DAT1);
-                       omap_cfg_reg(E19_24XX_MMC_DAT2);
-                       omap_cfg_reg(D19_24XX_MMC_DAT3);
-                       omap_cfg_reg(E20_24XX_MMC_DAT_DIR1);
-                       omap_cfg_reg(F18_24XX_MMC_DAT_DIR2);
-                       omap_cfg_reg(E18_24XX_MMC_DAT_DIR3);
+                       omap_mux_init_signal("sdmmc_dat1", 0);
+                       omap_mux_init_signal("sdmmc_dat2", 0);
+                       omap_mux_init_signal("sdmmc_dat3", 0);
+                       omap_mux_init_signal("sdmmc_dat_dir1", 0);
+                       omap_mux_init_signal("sdmmc_dat_dir2", 0);
+                       omap_mux_init_signal("sdmmc_dat_dir3", 0);
                }
  
                /*
@@@ -939,7 -847,6 +885,7 @@@ static int __init omap2_init_devices(vo
         * in alphabetical order so they're easier to sort through.
         */
        omap_hsmmc_reset();
 +      omap_init_audio();
        omap_init_camera();
        omap_init_mbox();
        omap_init_mcspi();
@@@ -1,7 -1,11 +1,13 @@@
  /*
   * Defines for zoom boards
   */
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #define ZOOM_NAND_CS    0
+ extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
  extern int __init zoom_debugboard_init(void);
  extern void __init zoom_peripherals_init(void);
 +
 +#define ZOOM2_HEADSET_EXTMUTE_GPIO    153
@@@ -4,6 -4,7 +4,7 @@@
  #include <linux/platform_device.h>
  #include <linux/dma-mapping.h>
  
+ #include <asm/pmu.h>
  #include <mach/udc.h>
  #include <mach/pxafb.h>
  #include <mach/mmc.h>
@@@ -31,6 -32,19 +32,19 @@@ void __init pxa_register_device(struct 
                dev_err(&dev->dev, "unable to register device: %d\n", ret);
  }
  
+ static struct resource pxa_resource_pmu = {
+       .start  = IRQ_PMU,
+       .end    = IRQ_PMU,
+       .flags  = IORESOURCE_IRQ,
+ };
+ struct platform_device pxa_device_pmu = {
+       .name           = "arm-pmu",
+       .id             = ARM_PMU_DEVICE_CPU,
+       .resource       = &pxa_resource_pmu,
+       .num_resources  = 1,
+ };
  static struct resource pxamci_resources[] = {
        [0] = {
                .start  = 0x41100000,
@@@ -340,31 -354,6 +354,31 @@@ struct platform_device pxa_device_i2s 
        .num_resources  = ARRAY_SIZE(pxai2s_resources),
  };
  
 +struct platform_device pxa_device_asoc_ssp1 = {
 +      .name           = "pxa-ssp-dai",
 +      .id             = 0,
 +};
 +
 +struct platform_device pxa_device_asoc_ssp2= {
 +      .name           = "pxa-ssp-dai",
 +      .id             = 1,
 +};
 +
 +struct platform_device pxa_device_asoc_ssp3 = {
 +      .name           = "pxa-ssp-dai",
 +      .id             = 2,
 +};
 +
 +struct platform_device pxa_device_asoc_ssp4 = {
 +      .name           = "pxa-ssp-dai",
 +      .id             = 3,
 +};
 +
 +struct platform_device pxa_device_asoc_platform = {
 +      .name           = "pxa-pcm-audio",
 +      .id             = -1,
 +};
 +
  static u64 pxaficp_dmamask = ~(u32)0;
  
  struct platform_device pxa_device_ficp = {
@@@ -1,3 -1,4 +1,4 @@@
+ extern struct platform_device pxa_device_pmu;
  extern struct platform_device pxa_device_mci;
  extern struct platform_device pxa3xx_device_mci2;
  extern struct platform_device pxa3xx_device_mci3;
@@@ -37,10 -38,4 +38,10 @@@ extern struct platform_device pxa3xx_de
  
  extern struct platform_device pxa3xx_device_gcu;
  
 +extern struct platform_device pxa_device_asoc_platform;
 +extern struct platform_device pxa_device_asoc_ssp1;
 +extern struct platform_device pxa_device_asoc_ssp2;
 +extern struct platform_device pxa_device_asoc_ssp3;
 +extern struct platform_device pxa_device_asoc_ssp4;
 +
  void __init pxa_register_device(struct platform_device *dev, void *data);
@@@ -41,10 -41,10 +41,10 @@@ void pxa27x_clear_otgph(void
  EXPORT_SYMBOL(pxa27x_clear_otgph);
  
  static unsigned long ac97_reset_config[] = {
-       GPIO95_AC97_nRESET,
-       GPIO95_GPIO,
-       GPIO113_AC97_nRESET,
        GPIO113_GPIO,
+       GPIO113_AC97_nRESET,
+       GPIO95_GPIO,
+       GPIO95_AC97_nRESET,
  };
  
  void pxa27x_assert_ac97reset(int reset_gpio, int on)
@@@ -383,11 -383,8 +383,12 @@@ void __init pxa27x_set_i2c_power_info(s
  
  static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
+       &pxa_device_pmu,
        &pxa_device_i2s,
 +      &pxa_device_asoc_ssp1,
 +      &pxa_device_asoc_ssp2,
 +      &pxa_device_asoc_ssp3,
 +      &pxa_device_asoc_platform,
        &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
@@@ -52,7 -52,7 +52,7 @@@
  static unsigned char smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
  
  /* crystal frequency to HSIO bus frequency multiplier (HSS) */
- static unsigned char hss_mult[4] = { 8, 12, 16, 0 };
+ static unsigned char hss_mult[4] = { 8, 12, 16, 24 };
  
  /*
   * Get the clock frequency as reflected by CCSR and the turbo flag.
@@@ -552,11 -552,23 +552,23 @@@ static void pxa_unmask_ext_wakeup(unsig
        PECR |= PECR_IE(irq - IRQ_WAKEUP0);
  }
  
+ static int pxa_set_ext_wakeup_type(unsigned int irq, unsigned int flow_type)
+ {
+       if (flow_type & IRQ_TYPE_EDGE_RISING)
+               PWER |= 1 << (irq - IRQ_WAKEUP0);
+       if (flow_type & IRQ_TYPE_EDGE_FALLING)
+               PWER |= 1 << (irq - IRQ_WAKEUP0 + 2);
+       return 0;
+ }
  static struct irq_chip pxa_ext_wakeup_chip = {
        .name           = "WAKEUP",
        .ack            = pxa_ack_ext_wakeup,
        .mask           = pxa_mask_ext_wakeup,
        .unmask         = pxa_unmask_ext_wakeup,
+       .set_type       = pxa_set_ext_wakeup_type,
  };
  
  static void __init pxa_init_ext_wakeup_irq(set_wake_t fn)
@@@ -596,12 -608,8 +608,13 @@@ void __init pxa3xx_set_i2c_power_info(s
  
  static struct platform_device *devices[] __initdata = {
        &pxa27x_device_udc,
+       &pxa_device_pmu,
        &pxa_device_i2s,
 +      &pxa_device_asoc_ssp1,
 +      &pxa_device_asoc_ssp2,
 +      &pxa_device_asoc_ssp3,
 +      &pxa_device_asoc_ssp4,
 +      &pxa_device_asoc_platform,
        &sa1100_device_rtc,
        &pxa_device_rtc,
        &pxa27x_device_ssp1,
  #include <linux/string.h>
  #include <linux/platform_device.h>
  #include <linux/dma-mapping.h>
+ #include <linux/gpio.h>
  
  #include <mach/irqs.h>
  #include <mach/map.h>
  #include <mach/dma.h>
- #include <mach/gpio.h>
  
  #include <plat/devs.h>
  #include <plat/audio.h>
@@@ -333,16 -333,3 +333,16 @@@ void __init s3c64xx_ac97_setup_gpio(in
        else
                s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
  }
 +
 +static u64 s3c_device_audio_dmamask = 0xffffffffUL;
 +
 +struct platform_device s3c_device_pcm = {
 +      .name             = "s3c24xx-pcm-audio",
 +      .id               = -1,
 +      .dev              = {
 +              .dma_mask = &s3c_device_audio_dmamask,
 +              .coherent_dma_mask = 0xffffffffUL
 +      }
 +};
 +EXPORT_SYMBOL(s3c_device_pcm);
 +
@@@ -17,6 -17,7 +17,7 @@@
  #include <linux/list.h>
  #include <linux/timer.h>
  #include <linux/init.h>
+ #include <linux/input.h>
  #include <linux/serial_core.h>
  #include <linux/platform_device.h>
  #include <linux/io.h>
@@@ -56,6 -57,7 +57,7 @@@
  #include <mach/regs-gpio.h>
  #include <mach/regs-sys.h>
  #include <mach/regs-srom.h>
+ #include <plat/ata.h>
  #include <plat/iic.h>
  #include <plat/fb.h>
  #include <plat/gpio-cfg.h>
@@@ -66,6 -68,7 +68,7 @@@
  #include <plat/cpu.h>
  #include <plat/adc.h>
  #include <plat/ts.h>
+ #include <plat/keypad.h>
  
  #define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
  #define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
@@@ -141,7 -144,6 +144,6 @@@ static struct platform_device smdk6410_
  static struct s3c_fb_pd_win smdk6410_fb_win0 = {
        /* this is to ensure we use win0 */
        .win_mode       = {
-               .pixclock       = 41094,
                .left_margin    = 8,
                .right_margin   = 13,
                .upper_margin   = 7,
        },
        .max_bpp        = 32,
        .default_bpp    = 16,
+       .virtual_y      = 480 * 2,
+       .virtual_x      = 800,
  };
  
  /* 405566 clocks per frame => 60Hz refresh requires 24333960Hz clock */
@@@ -242,6 -246,29 +246,29 @@@ static struct platform_device smdk6410_
  };
  #endif
  
+ static struct s3c_ide_platdata smdk6410_ide_pdata __initdata = {
+       .setup_gpio     = s3c64xx_ide_setup_gpio,
+ };
+ static uint32_t smdk6410_keymap[] __initdata = {
+       /* KEY(row, col, keycode) */
+       KEY(0, 3, KEY_1), KEY(0, 4, KEY_2), KEY(0, 5, KEY_3),
+       KEY(0, 6, KEY_4), KEY(0, 7, KEY_5),
+       KEY(1, 3, KEY_A), KEY(1, 4, KEY_B), KEY(1, 5, KEY_C),
+       KEY(1, 6, KEY_D), KEY(1, 7, KEY_E)
+ };
+ static struct matrix_keymap_data smdk6410_keymap_data __initdata = {
+       .keymap         = smdk6410_keymap,
+       .keymap_size    = ARRAY_SIZE(smdk6410_keymap),
+ };
+ static struct samsung_keypad_platdata smdk6410_keypad_data __initdata = {
+       .keymap_data    = &smdk6410_keymap_data,
+       .rows           = 2,
+       .cols           = 8,
+ };
  static struct map_desc smdk6410_iodesc[] = {};
  
  static struct platform_device *smdk6410_devices[] __initdata = {
        &s3c_device_fb,
        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
 +      &s3c_device_pcm,
        &s3c64xx_device_iisv4,
+       &samsung_device_keypad,
  
  #ifdef CONFIG_REGULATOR
        &smdk6410_b_pwr_5v,
  
        &smdk6410_smsc911x,
        &s3c_device_adc,
+       &s3c_device_cfcon,
+       &s3c_device_rtc,
        &s3c_device_ts,
        &s3c_device_wdt,
  };
@@@ -637,6 -666,8 +667,8 @@@ static void __init smdk6410_machine_ini
        s3c_i2c1_set_platdata(NULL);
        s3c_fb_set_platdata(&smdk6410_lcd_pdata);
  
+       samsung_keypad_set_platdata(&smdk6410_keypad_data);
        s3c24xx_ts_set_platdata(&s3c_ts_platform);
  
        /* configure nCS1 width to 16 bits */
        i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
        i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
  
+       s3c_ide_set_platdata(&smdk6410_ide_pdata);
        platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
  }
  
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
-  *
-  * You should have received a copy of the GNU General Public License
-  * along with this program; if not, write to the Free Software
-  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  #include <linux/module.h>
@@@ -49,9 -45,9 +45,9 @@@ static const char *audmux_port_string(i
  {
        switch (port) {
        case MX31_AUDMUX_PORT1_SSI0:
 -              return "imx-ssi.0";
 +              return "imx-ssi-dai.0";
        case MX31_AUDMUX_PORT2_SSI1:
 -              return "imx-ssi.1";
 +              return "imx-ssi-dai.1";
        case MX31_AUDMUX_PORT3_SSI_PINS_3:
                return "SSI3";
        case MX31_AUDMUX_PORT4_SSI_PINS_4:
@@@ -191,6 -187,7 +187,7 @@@ static int mxc_audmux_v2_init(void
  {
        int ret;
  
+ #if defined(CONFIG_ARCH_MX3)
        if (cpu_is_mx31())
                audmux_base = MX31_IO_ADDRESS(MX31_AUDMUX_BASE_ADDR);
  
                }
                audmux_base = MX35_IO_ADDRESS(MX35_AUDMUX_BASE_ADDR);
        }
+ #endif
+ #if defined(CONFIG_ARCH_MX25)
+       if (cpu_is_mx25()) {
+               audmux_clk = clk_get(NULL, "audmux");
+               if (IS_ERR(audmux_clk)) {
+                       ret = PTR_ERR(audmux_clk);
+                       printk(KERN_ERR "%s: cannot get clock: %d\n", __func__,
+                                       ret);
+                       return ret;
+               }
+               audmux_base = MX25_IO_ADDRESS(MX25_AUDMUX_BASE_ADDR);
+       }
+ #endif
        audmux_debugfs_init();
  
        return 0;
@@@ -32,8 -32,6 +32,8 @@@ extern struct platform_device s3c64xx_d
  extern struct platform_device s3c64xx_device_spi0;
  extern struct platform_device s3c64xx_device_spi1;
  
 +extern struct platform_device s3c_device_pcm;
 +
  extern struct platform_device s3c64xx_device_pcm0;
  extern struct platform_device s3c64xx_device_pcm1;
  
@@@ -56,6 -54,8 +56,8 @@@ extern struct platform_device s3c_devic
  extern struct platform_device s3c_device_hsmmc0;
  extern struct platform_device s3c_device_hsmmc1;
  extern struct platform_device s3c_device_hsmmc2;
+ extern struct platform_device s3c_device_hsmmc3;
+ extern struct platform_device s3c_device_cfcon;
  
  extern struct platform_device s3c_device_spi0;
  extern struct platform_device s3c_device_spi1;
@@@ -102,6 -102,12 +104,12 @@@ extern struct platform_device s5pc100_d
  extern struct platform_device s5pc100_device_iis1;
  extern struct platform_device s5pc100_device_iis2;
  
+ extern struct platform_device samsung_device_keypad;
+ extern struct platform_device s5p_device_fimc0;
+ extern struct platform_device s5p_device_fimc1;
+ extern struct platform_device s5p_device_fimc2;
  /* s3c2440 specific devices */
  
  #ifdef CONFIG_CPU_S3C2440
@@@ -110,3 -116,15 +118,15 @@@ extern struct platform_device s3c_devic
  extern struct platform_device s3c_device_ac97;
  
  #endif
+ /**
+  * s3c_set_platdata() - helper for setting platform data
+  * @pd: The default platform data for this device.
+  * @pdsize: The size of the platform data.
+  * @pdev: Pointer to the device to fill in.
+  *
+  * This helper replaces a number of calls that copy and then set the
+  * platform data of the device.
+  */
+ extern void *s3c_set_platdata(void *pd, size_t pdsize,
+                             struct platform_device *pdev);
  
  #include "wm8776.h"
  
 -static struct snd_soc_codec *wm8776_codec;
 -struct snd_soc_codec_device soc_codec_dev_wm8776;
 -
  /* codec private data */
  struct wm8776_priv {
 -      struct snd_soc_codec codec;
 +      enum snd_soc_control_type control_type;
        u16 reg_cache[WM8776_CACHEREGNUM];
        int sysclk[2];
  };
  
 -#ifdef CONFIG_SPI_MASTER
 -static int wm8776_spi_write(struct spi_device *spi, const char *data, int len);
 -#endif
 -
  static const u16 wm8776_reg[WM8776_CACHEREGNUM] = {
        0x79, 0x79, 0x79, 0xff, 0xff,  /* 4 */
        0xff, 0x00, 0x90, 0x00, 0x00,  /* 9 */
@@@ -137,7 -144,7 +137,7 @@@ static int wm8776_set_fmt(struct snd_so
        struct snd_soc_codec *codec = dai->codec;
        int reg, iface, master;
  
 -      switch (dai->id) {
 +      switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                reg = WM8776_DACIFCTRL;
                master = 0x80;
        case SND_SOC_DAIFMT_LEFT_J:
                iface |= 0x0001;
                break;
-               /* FIXME: CHECK A/B */
-       case SND_SOC_DAIFMT_DSP_A:
-               iface |= 0x0003;
-               break;
-       case SND_SOC_DAIFMT_DSP_B:
-               iface |= 0x0007;
-               break;
        default:
                return -EINVAL;
        }
@@@ -226,7 -226,7 +219,7 @@@ static int wm8776_hw_params(struct snd_
  
        iface = 0;
  
 -      switch (dai->id) {
 +      switch (dai->driver->id) {
        case WM8776_DAI_DAC:
                iface_reg = WM8776_DACIFCTRL;
                master = 0x80;
        /* Only need to set MCLK/LRCLK ratio if we're master */
        if (snd_soc_read(codec, WM8776_MSTRCTRL) & master) {
                for (i = 0; i < ARRAY_SIZE(mclk_ratios); i++) {
 -                      if (wm8776->sysclk[dai->id] / params_rate(params)
 +                      if (wm8776->sysclk[dai->driver->id] / params_rate(params)
                            == mclk_ratios[i])
                                break;
                }
                if (i == ARRAY_SIZE(mclk_ratios)) {
                        dev_err(codec->dev,
                                "Unable to configure MCLK ratio %d/%d\n",
 -                              wm8776->sysclk[dai->id], params_rate(params));
 +                              wm8776->sysclk[dai->driver->id], params_rate(params));
                        return -EINVAL;
                }
  
@@@ -298,9 -298,9 +291,9 @@@ static int wm8776_set_sysclk(struct snd
        struct snd_soc_codec *codec = dai->codec;
        struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
  
 -      BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
 +      BUG_ON(dai->driver->id >= ARRAY_SIZE(wm8776->sysclk));
  
 -      wm8776->sysclk[dai->id] = freq;
 +      wm8776->sysclk[dai->driver->id] = freq;
  
        return 0;
  }
@@@ -350,10 -350,10 +343,10 @@@ static struct snd_soc_dai_ops wm8776_ad
        .set_sysclk     = wm8776_set_sysclk,
  };
  
 -struct snd_soc_dai wm8776_dai[] = {
 +static struct snd_soc_dai_driver wm8776_dai[] = {
        {
 -              .name = "WM8776 Playback",
 -              .id = WM8776_DAI_DAC,
 +              .name = "wm8776-hifi-playback",
 +              .id     = WM8776_DAI_DAC,
                .playback = {
                        .stream_name = "Playback",
                        .channels_min = 2,
                .ops = &wm8776_dac_ops,
        },
        {
 -              .name = "WM8776 Capture",
 -              .id = WM8776_DAI_ADC,
 +              .name = "wm8776-hifi-capture",
 +              .id     = WM8776_DAI_ADC,
                .capture = {
                        .stream_name = "Capture",
                        .channels_min = 2,
                .ops = &wm8776_adc_ops,
        },
  };
 -EXPORT_SYMBOL_GPL(wm8776_dai);
  
  #ifdef CONFIG_PM
 -static int wm8776_suspend(struct platform_device *pdev, pm_message_t state)
 +static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
  {
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_codec *codec = socdev->card->codec;
 -
        wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
  
        return 0;
  }
  
 -static int wm8776_resume(struct platform_device *pdev)
 +static int wm8776_resume(struct snd_soc_codec *codec)
  {
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_codec *codec = socdev->card->codec;
        int i;
        u8 data[2];
        u16 *cache = codec->reg_cache;
  #define wm8776_resume NULL
  #endif
  
 -static int wm8776_probe(struct platform_device *pdev)
 +static int wm8776_probe(struct snd_soc_codec *codec)
  {
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_codec *codec;
 +      struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
        int ret = 0;
  
 -      if (wm8776_codec == NULL) {
 -              dev_err(&pdev->dev, "Codec device not registered\n");
 -              return -ENODEV;
 +      ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8776->control_type);
 +      if (ret < 0) {
 +              dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 +              return ret;
        }
  
 -      socdev->card->codec = wm8776_codec;
 -      codec = wm8776_codec;
 -
 -      /* register pcms */
 -      ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
 +      ret = wm8776_reset(codec);
        if (ret < 0) {
 -              dev_err(codec->dev, "failed to create pcms: %d\n", ret);
 -              goto pcm_err;
 +              dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
 +              return ret;
        }
  
 +      wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 +
 +      /* Latch the update bits; right channel only since we always
 +       * update both. */
 +      snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
 +      snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
 +
        snd_soc_add_controls(codec, wm8776_snd_controls,
                             ARRAY_SIZE(wm8776_snd_controls));
        snd_soc_dapm_new_controls(codec, wm8776_dapm_widgets,
        snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes));
  
        return ret;
 -
 -pcm_err:
 -      return ret;
  }
  
  /* power down chip */
 -static int wm8776_remove(struct platform_device *pdev)
 +static int wm8776_remove(struct snd_soc_codec *codec)
  {
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -
 -      snd_soc_free_pcms(socdev);
 -      snd_soc_dapm_free(socdev);
 -
 +      wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
        return 0;
  }
  
 -struct snd_soc_codec_device soc_codec_dev_wm8776 = {
 +static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
        .probe =        wm8776_probe,
        .remove =       wm8776_remove,
        .suspend =      wm8776_suspend,
        .resume =       wm8776_resume,
 +      .set_bias_level = wm8776_set_bias_level,
 +      .reg_cache_size = sizeof(wm8776_reg),
 +      .reg_word_size = sizeof(u16),
 +      .reg_cache_default = wm8776_reg,
  };
 -EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776);
 -
 -static int wm8776_register(struct wm8776_priv *wm8776,
 -                         enum snd_soc_control_type control)
 -{
 -      int ret, i;
 -      struct snd_soc_codec *codec = &wm8776->codec;
 -
 -      if (wm8776_codec) {
 -              dev_err(codec->dev, "Another WM8776 is registered\n");
 -              ret = -EINVAL;
 -              goto err;
 -      }
 -
 -      mutex_init(&codec->mutex);
 -      INIT_LIST_HEAD(&codec->dapm_widgets);
 -      INIT_LIST_HEAD(&codec->dapm_paths);
 -
 -      snd_soc_codec_set_drvdata(codec, wm8776);
 -      codec->name = "WM8776";
 -      codec->owner = THIS_MODULE;
 -      codec->bias_level = SND_SOC_BIAS_OFF;
 -      codec->set_bias_level = wm8776_set_bias_level;
 -      codec->dai = wm8776_dai;
 -      codec->num_dai = ARRAY_SIZE(wm8776_dai);
 -      codec->reg_cache_size = WM8776_CACHEREGNUM;
 -      codec->reg_cache = &wm8776->reg_cache;
 -
 -      memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg));
 -
 -      ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
 -      if (ret < 0) {
 -              dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 -              goto err;
 -      }
 -
 -      for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++)
 -              wm8776_dai[i].dev = codec->dev;
 -
 -      ret = wm8776_reset(codec);
 -      if (ret < 0) {
 -              dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
 -              goto err;
 -      }
 -
 -      wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 -
 -      /* Latch the update bits; right channel only since we always
 -       * update both. */
 -      snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
 -      snd_soc_update_bits(codec, WM8776_DACRVOL, 0x100, 0x100);
 -
 -      wm8776_codec = codec;
 -
 -      ret = snd_soc_register_codec(codec);
 -      if (ret != 0) {
 -              dev_err(codec->dev, "Failed to register codec: %d\n", ret);
 -              goto err;
 -      }
 -
 -      ret = snd_soc_register_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
 -      if (ret != 0) {
 -              dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
 -              goto err_codec;
 -      }
 -
 -      return 0;
 -
 -err_codec:
 -      snd_soc_unregister_codec(codec);
 -err:
 -      kfree(wm8776);
 -      return ret;
 -}
 -
 -static void wm8776_unregister(struct wm8776_priv *wm8776)
 -{
 -      wm8776_set_bias_level(&wm8776->codec, SND_SOC_BIAS_OFF);
 -      snd_soc_unregister_dais(wm8776_dai, ARRAY_SIZE(wm8776_dai));
 -      snd_soc_unregister_codec(&wm8776->codec);
 -      kfree(wm8776);
 -      wm8776_codec = NULL;
 -}
  
  #if defined(CONFIG_SPI_MASTER)
 -static int wm8776_spi_write(struct spi_device *spi, const char *data, int len)
 -{
 -      struct spi_transfer t;
 -      struct spi_message m;
 -      u8 msg[2];
 -
 -      if (len <= 0)
 -              return 0;
 -
 -      msg[0] = data[0];
 -      msg[1] = data[1];
 -
 -      spi_message_init(&m);
 -      memset(&t, 0, (sizeof t));
 -
 -      t.tx_buf = &msg[0];
 -      t.len = len;
 -
 -      spi_message_add_tail(&t, &m);
 -      spi_sync(spi, &m);
 -
 -      return len;
 -}
 -
  static int __devinit wm8776_spi_probe(struct spi_device *spi)
  {
 -      struct snd_soc_codec *codec;
        struct wm8776_priv *wm8776;
 +      int ret;
  
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
  
 -      codec = &wm8776->codec;
 -      codec->control_data = spi;
 -      codec->hw_write = (hw_write_t)wm8776_spi_write;
 -      codec->dev = &spi->dev;
 +      wm8776->control_type = SND_SOC_SPI;
 +      spi_set_drvdata(spi, wm8776);
  
 -      dev_set_drvdata(&spi->dev, wm8776);
 -
 -      return wm8776_register(wm8776, SND_SOC_SPI);
 +      ret = snd_soc_register_codec(&spi->dev,
 +                      &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
 +      if (ret < 0)
 +              kfree(wm8776);
 +      return ret;
  }
  
  static int __devexit wm8776_spi_remove(struct spi_device *spi)
  {
 -      struct wm8776_priv *wm8776 = dev_get_drvdata(&spi->dev);
 -
 -      wm8776_unregister(wm8776);
 -
 +      snd_soc_unregister_codec(&spi->dev);
 +      kfree(spi_get_drvdata(spi));
        return 0;
  }
  
  static struct spi_driver wm8776_spi_driver = {
        .driver = {
 -              .name   = "wm8776",
 +              .name   = "wm8776-codec",
                .bus    = &spi_bus_type,
                .owner  = THIS_MODULE,
        },
@@@ -503,26 -618,27 +496,26 @@@ static __devinit int wm8776_i2c_probe(s
                                      const struct i2c_device_id *id)
  {
        struct wm8776_priv *wm8776;
 -      struct snd_soc_codec *codec;
 +      int ret;
  
        wm8776 = kzalloc(sizeof(struct wm8776_priv), GFP_KERNEL);
        if (wm8776 == NULL)
                return -ENOMEM;
  
 -      codec = &wm8776->codec;
 -      codec->hw_write = (hw_write_t)i2c_master_send;
 -
        i2c_set_clientdata(i2c, wm8776);
 -      codec->control_data = i2c;
 -
 -      codec->dev = &i2c->dev;
 +      wm8776->control_type = SND_SOC_I2C;
  
 -      return wm8776_register(wm8776, SND_SOC_I2C);
 +      ret =  snd_soc_register_codec(&i2c->dev,
 +                      &soc_codec_dev_wm8776, wm8776_dai, ARRAY_SIZE(wm8776_dai));
 +      if (ret < 0)
 +              kfree(wm8776);
 +      return ret;
  }
  
  static __devexit int wm8776_i2c_remove(struct i2c_client *client)
  {
 -      struct wm8776_priv *wm8776 = i2c_get_clientdata(client);
 -      wm8776_unregister(wm8776);
 +      snd_soc_unregister_codec(&client->dev);
 +      kfree(i2c_get_clientdata(client));
        return 0;
  }
  
@@@ -534,7 -650,7 +527,7 @@@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id)
  
  static struct i2c_driver wm8776_i2c_driver = {
        .driver = {
 -              .name = "wm8776",
 +              .name = "wm8776-codec",
                .owner = THIS_MODULE,
        },
        .probe =    wm8776_i2c_probe,
  
  static int __init wm8776_modinit(void)
  {
 -      int ret;
 +      int ret = 0;
  #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
        ret = i2c_add_driver(&wm8776_i2c_driver);
        if (ret != 0) {
 -              printk(KERN_ERR "Failed to register WM8776 I2C driver: %d\n",
 +              printk(KERN_ERR "Failed to register wm8776 I2C driver: %d\n",
                       ret);
        }
  #endif
  #if defined(CONFIG_SPI_MASTER)
        ret = spi_register_driver(&wm8776_spi_driver);
        if (ret != 0) {
 -              printk(KERN_ERR "Failed to register WM8776 SPI driver: %d\n",
 +              printk(KERN_ERR "Failed to register wm8776 SPI driver: %d\n",
                       ret);
        }
  #endif
 -      return 0;
 +      return ret;
  }
  module_init(wm8776_modinit);
  
@@@ -73,7 -73,7 +73,7 @@@ struct psc_dma 
  };
  
  /* Utility for retrieving psc_dma_stream structure from a substream */
- inline struct psc_dma_stream *
static inline struct psc_dma_stream *
  to_psc_dma_stream(struct snd_pcm_substream *substream, struct psc_dma *psc_dma)
  {
        if (substream->pstr->stream == SNDRV_PCM_STREAM_CAPTURE)
@@@ -81,4 -81,9 +81,4 @@@
        return &psc_dma->playback;
  }
  
 -int mpc5200_audio_dma_create(struct platform_device *op);
 -int mpc5200_audio_dma_destroy(struct platform_device *op);
 -
 -extern struct snd_soc_platform mpc5200_audio_dma_platform;
 -
  #endif /* __SOUND_SOC_FSL_MPC5200_DMA_H__ */
@@@ -20,6 -20,7 +20,7 @@@
  
  #include <asm/time.h>
  #include <asm/delay.h>
+ #include <asm/mpc52xx.h>
  #include <asm/mpc52xx_psc.h>
  
  #include "mpc5200_dma.h"
@@@ -100,19 -101,32 +101,32 @@@ static void psc_ac97_warm_reset(struct 
  {
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
  
+       mutex_lock(&psc_dma->mutex);
        out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_AWR);
        udelay(3);
        out_be32(&regs->sicr, psc_dma->sicr);
+       mutex_unlock(&psc_dma->mutex);
  }
  
  static void psc_ac97_cold_reset(struct snd_ac97 *ac97)
  {
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
  
-       /* Do a cold reset */
-       out_8(&regs->op1, MPC52xx_PSC_OP_RES);
-       udelay(10);
-       out_8(&regs->op0, MPC52xx_PSC_OP_RES);
+       mutex_lock(&psc_dma->mutex);
+       dev_dbg(psc_dma->dev, "cold reset\n");
+       mpc5200_psc_ac97_gpio_reset(psc_dma->id);
+       /* Notify the PSC that a reset has occurred */
+       out_be32(&regs->sicr, psc_dma->sicr | MPC52xx_PSC_SICR_ACRB);
+       /* Re-enable RX and TX */
+       out_8(&regs->command, MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
+       mutex_unlock(&psc_dma->mutex);
        msleep(1);
        psc_ac97_warm_reset(ac97);
  }
@@@ -129,7 -143,7 +143,7 @@@ static int psc_ac97_hw_analog_params(st
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
  {
 -      struct psc_dma *psc_dma = cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
  
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@@ -152,7 -166,7 +166,7 @@@ static int psc_ac97_hw_digital_params(s
                                 struct snd_pcm_hw_params *params,
                                 struct snd_soc_dai *cpu_dai)
  {
 -      struct psc_dma *psc_dma = cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
  
        dev_dbg(psc_dma->dev, "%s(substream=%p)\n", __func__, substream);
  
  static int psc_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
                                                        struct snd_soc_dai *dai)
  {
 -      struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(dai);
        struct psc_dma_stream *s = to_psc_dma_stream(substream, psc_dma);
  
        switch (cmd) {
        return 0;
  }
  
 -static int psc_ac97_probe(struct platform_device *pdev,
 -                                      struct snd_soc_dai *cpu_dai)
 +static int psc_ac97_probe(struct snd_soc_dai *cpu_dai)
  {
 -      struct psc_dma *psc_dma = cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        struct mpc52xx_psc __iomem *regs = psc_dma->psc_regs;
  
        /* Go */
@@@ -221,8 -237,9 +235,8 @@@ static struct snd_soc_dai_ops psc_ac97_
        .hw_params      = psc_ac97_hw_digital_params,
  };
  
 -struct snd_soc_dai psc_ac97_dai[] = {
 +static struct snd_soc_dai_driver psc_ac97_dai[] = {
  {
 -      .name   = "AC97",
        .ac97_control = 1,
        .probe  = psc_ac97_probe,
        .playback = {
        .ops = &psc_ac97_analog_ops,
  },
  {
 -      .name   = "SPDIF",
        .ac97_control = 1,
        .playback = {
                .channels_min   = 1,
        },
        .ops = &psc_ac97_digital_ops,
  } };
 -EXPORT_SYMBOL_GPL(psc_ac97_dai);
  
  
  
   * - Probe/remove operations
   * - OF device match table
   */
- static int __devinit psc_ac97_of_probe(struct of_device *op,
+ static int __devinit psc_ac97_of_probe(struct platform_device *op,
                                      const struct of_device_id *match)
  {
 -      int rc, i;
 +      int rc;
        struct snd_ac97 ac97;
        struct mpc52xx_psc __iomem *regs;
  
 -      rc = mpc5200_audio_dma_create(op);
 -      if (rc != 0)
 -              return rc;
 -
 -      for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
 -              psc_ac97_dai[i].dev = &op->dev;
 -
 -      rc = snd_soc_register_dais(psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
 +      rc = snd_soc_register_dais(&op->dev, psc_ac97_dai, ARRAY_SIZE(psc_ac97_dai));
        if (rc != 0) {
                dev_err(&op->dev, "Failed to register DAI\n");
                return rc;
        regs = psc_dma->psc_regs;
        ac97.private_data = psc_dma;
  
 -      for (i = 0; i < ARRAY_SIZE(psc_ac97_dai); i++)
 -              psc_ac97_dai[i].private_data = psc_dma;
 -
        psc_dma->imr = 0;
        out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
  
        return 0;
  }
  
- static int __devexit psc_ac97_of_remove(struct of_device *op)
+ static int __devexit psc_ac97_of_remove(struct platform_device *op)
  {
 -      return mpc5200_audio_dma_destroy(op);
 +      snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_ac97_dai));
 +      return 0;
  }
  
  /* Match table for of_platform binding */
@@@ -40,7 -40,7 +40,7 @@@ static int psc_i2s_hw_params(struct snd
                                 struct snd_soc_dai *dai)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct psc_dma *psc_dma = rtd->dai->cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(rtd->cpu_dai);
        u32 mode;
  
        dev_dbg(psc_dma->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
@@@ -88,7 -88,7 +88,7 @@@
  static int psc_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
                              int clk_id, unsigned int freq, int dir)
  {
 -      struct psc_dma *psc_dma = cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        dev_dbg(psc_dma->dev, "psc_i2s_set_sysclk(cpu_dai=%p, dir=%i)\n",
                                cpu_dai, dir);
        return (dir == SND_SOC_CLOCK_IN) ? 0 : -EINVAL;
   */
  static int psc_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int format)
  {
 -      struct psc_dma *psc_dma = cpu_dai->private_data;
 +      struct psc_dma *psc_dma = snd_soc_dai_get_drvdata(cpu_dai);
        dev_dbg(psc_dma->dev, "psc_i2s_set_fmt(cpu_dai=%p, format=%i)\n",
                                cpu_dai, format);
        return (format == SND_SOC_DAIFMT_I2S) ? 0 : -EINVAL;
@@@ -129,7 -129,8 +129,7 @@@ static struct snd_soc_dai_ops psc_i2s_d
        .set_fmt        = psc_i2s_set_fmt,
  };
  
 -struct snd_soc_dai psc_i2s_dai[] = {{
 -      .name   = "I2S",
 +static struct snd_soc_dai_driver psc_i2s_dai[] = {{
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
        },
        .ops = &psc_i2s_dai_ops,
  } };
 -EXPORT_SYMBOL_GPL(psc_i2s_dai);
  
  /* ---------------------------------------------------------------------
   * OF platform bus binding code:
   * - Probe/remove operations
   * - OF device match table
   */
- static int __devinit psc_i2s_of_probe(struct of_device *op,
+ static int __devinit psc_i2s_of_probe(struct platform_device *op,
                                      const struct of_device_id *match)
  {
        int rc;
        struct psc_dma *psc_dma;
        struct mpc52xx_psc __iomem *regs;
  
 -      rc = mpc5200_audio_dma_create(op);
 -      if (rc != 0)
 -              return rc;
 -
 -      rc = snd_soc_register_dais(psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
 +      rc = snd_soc_register_dais(&op->dev, psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));
        if (rc != 0) {
                pr_err("Failed to register DAI\n");
                return 0;
  
  }
  
- static int __devexit psc_i2s_of_remove(struct of_device *op)
+ static int __devexit psc_i2s_of_remove(struct platform_device *op)
  {
 -      return mpc5200_audio_dma_destroy(op);
 +      snd_soc_unregister_dais(&op->dev, ARRAY_SIZE(psc_i2s_dai));
 +      return 0;
  }
  
  /* Match table for of_platform binding */
diff --combined sound/soc/imx/imx-ssi.c
@@@ -23,7 -23,7 +23,7 @@@
   * between pcm data and GPIO status data changes. Our FIQ handler is not
   * able to handle this, hence this driver only works with 48000Hz sampling
   * rate.
-  * Reading and writing AC97 registers is another challange. The core
+  * Reading and writing AC97 registers is another challenge. The core
   * provides us status bits when the read register is updated with *another*
   * value. When we read the same register two times (and the register still
   * contains the same value) these status bits are not set. We work
@@@ -61,7 -61,7 +61,7 @@@
  static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
  {
 -      struct imx_ssi *ssi = cpu_dai->private_data;
 +      struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 sccr;
  
        sccr = readl(ssi->base + SSI_STCCR);
@@@ -86,7 -86,7 +86,7 @@@
   */
  static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
  {
 -      struct imx_ssi *ssi = cpu_dai->private_data;
 +      struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 strcr = 0, scr;
  
        scr = readl(ssi->base + SSI_SCR) & ~(SSI_SCR_SYN | SSI_SCR_NET);
  static int imx_ssi_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
                                  int clk_id, unsigned int freq, int dir)
  {
 -      struct imx_ssi *ssi = cpu_dai->private_data;
 +      struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 scr;
  
        scr = readl(ssi->base + SSI_SCR);
  static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
                                  int div_id, int div)
  {
 -      struct imx_ssi *ssi = cpu_dai->private_data;
 +      struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        u32 stccr, srccr;
  
        stccr = readl(ssi->base + SSI_STCCR);
@@@ -241,7 -241,7 +241,7 @@@ static int imx_ssi_hw_params(struct snd
                             struct snd_pcm_hw_params *params,
                             struct snd_soc_dai *cpu_dai)
  {
 -      struct imx_ssi *ssi = cpu_dai->private_data;
 +      struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
        struct imx_pcm_dma_params *dma_data;
        u32 reg, sccr;
  
  static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
                struct snd_soc_dai *dai)
  {
 -      struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 -      struct imx_ssi *ssi = cpu_dai->private_data;
 +      struct imx_ssi *ssi = snd_soc_dai_get_drvdata(dai);
        unsigned int sier_bits, sier;
        unsigned int scr;
  
@@@ -348,6 -350,22 +348,6 @@@ static struct snd_soc_dai_ops imx_ssi_p
        .trigger        = imx_ssi_trigger,
  };
  
 -static struct snd_soc_dai imx_ssi_dai = {
 -      .playback = {
 -              .channels_min = 2,
 -              .channels_max = 2,
 -              .rates = SNDRV_PCM_RATE_8000_96000,
 -              .formats = SNDRV_PCM_FMTBIT_S16_LE,
 -      },
 -      .capture = {
 -              .channels_min = 2,
 -              .channels_max = 2,
 -              .rates = SNDRV_PCM_RATE_8000_96000,
 -              .formats = SNDRV_PCM_FMTBIT_S16_LE,
 -      },
 -      .ops = &imx_ssi_pcm_dai_ops,
 -};
 -
  int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
                struct vm_area_struct *vma)
  {
                        runtime->dma_bytes);
        return ret;
  }
 +EXPORT_SYMBOL_GPL(snd_imx_pcm_mmap);
  
  static int imx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
  {
@@@ -395,14 -412,14 +395,14 @@@ int imx_pcm_new(struct snd_card *card, 
                card->dev->dma_mask = &imx_pcm_dmamask;
        if (!card->dev->coherent_dma_mask)
                card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 -      if (dai->playback.channels_min) {
 +      if (dai->driver->playback.channels_min) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_PLAYBACK);
                if (ret)
                        goto out;
        }
  
 -      if (dai->capture.channels_min) {
 +      if (dai->driver->capture.channels_min) {
                ret = imx_pcm_preallocate_dma_buffer(pcm,
                        SNDRV_PCM_STREAM_CAPTURE);
                if (ret)
  out:
        return ret;
  }
 +EXPORT_SYMBOL_GPL(imx_pcm_new);
  
  void imx_pcm_free(struct snd_pcm *pcm)
  {
                buf->area = NULL;
        }
  }
 +EXPORT_SYMBOL_GPL(imx_pcm_free);
  
 -struct snd_soc_platform imx_soc_platform = {
 -      .name           = "imx-audio",
 +static struct snd_soc_dai_driver imx_ssi_dai = {
 +      .playback = {
 +              .channels_min = 2,
 +              .channels_max = 2,
 +              .rates = SNDRV_PCM_RATE_8000_96000,
 +              .formats = SNDRV_PCM_FMTBIT_S16_LE,
 +      },
 +      .capture = {
 +              .channels_min = 2,
 +              .channels_max = 2,
 +              .rates = SNDRV_PCM_RATE_8000_96000,
 +              .formats = SNDRV_PCM_FMTBIT_S16_LE,
 +      },
 +      .ops = &imx_ssi_pcm_dai_ops,
  };
 -EXPORT_SYMBOL_GPL(imx_soc_platform);
  
 -static struct snd_soc_dai imx_ac97_dai = {
 -      .name = "AC97",
 +static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 +{
 +      struct imx_ssi *ssi = dev_get_drvdata(dai->dev);
 +      uint32_t val;
 +
 +      snd_soc_dai_set_drvdata(dai, ssi);
 +
 +      val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
 +              SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
 +      writel(val, ssi->base + SSI_SFCSR);
 +
 +      return 0;
 +}
 +
 +static struct snd_soc_dai_driver imx_ac97_dai = {
 +      .probe = imx_ssi_dai_probe,
        .ac97_control = 1,
        .playback = {
                .stream_name = "AC97 Playback",
@@@ -587,18 -577,25 +587,18 @@@ struct snd_ac97_bus_ops soc_ac97_ops = 
  };
  EXPORT_SYMBOL_GPL(soc_ac97_ops);
  
 -struct snd_soc_dai imx_ssi_pcm_dai[2];
 -EXPORT_SYMBOL_GPL(imx_ssi_pcm_dai);
 -
  static int imx_ssi_probe(struct platform_device *pdev)
  {
        struct resource *res;
        struct imx_ssi *ssi;
        struct imx_ssi_platform_data *pdata = pdev->dev.platform_data;
 -      struct snd_soc_platform *platform;
        int ret = 0;
 -      unsigned int val;
 -      struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
 -
 -      if (dai->id >= ARRAY_SIZE(imx_ssi_pcm_dai))
 -              return -EINVAL;
 +      struct snd_soc_dai_driver *dai;
  
        ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
        if (!ssi)
                return -ENOMEM;
 +      dev_set_drvdata(&pdev->dev, ssi);
  
        if (pdata) {
                ssi->ac97_reset = pdata->ac97_reset;
                }
                ac97_ssi = ssi;
                setup_channel_to_ac97(ssi);
 -              memcpy(dai, &imx_ac97_dai, sizeof(imx_ac97_dai));
 +              dai = &imx_ac97_dai;
        } else
 -              memcpy(dai, &imx_ssi_dai, sizeof(imx_ssi_dai));
 +              dai = &imx_ssi_dai;
  
        writel(0x0, ssi->base + SSI_SIER);
  
        if (res)
                ssi->dma_params_rx.dma = res->start;
  
 -      dai->id = pdev->id;
 -      dai->dev = &pdev->dev;
 -      dai->name = kasprintf(GFP_KERNEL, "imx-ssi.%d", pdev->id);
 -      dai->private_data = ssi;
 -
        if ((cpu_is_mx27() || cpu_is_mx21()) &&
                        !(ssi->flags & IMX_SSI_USE_AC97) &&
                        (ssi->flags & IMX_SSI_DMA)) {
                ssi->flags |= IMX_SSI_DMA;
 -              platform = imx_ssi_dma_mx2_init(pdev, ssi);
 -      } else
 -              platform = imx_ssi_fiq_init(pdev, ssi);
 -
 -      imx_soc_platform.pcm_ops = platform->pcm_ops;
 -      imx_soc_platform.pcm_new = platform->pcm_new;
 -      imx_soc_platform.pcm_free = platform->pcm_free;
 +      }
  
 -      val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) |
 -              SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize);
 -      writel(val, ssi->base + SSI_SFCSR);
 +      platform_set_drvdata(pdev, ssi);
  
 -      ret = snd_soc_register_dai(dai);
 +      ret = snd_soc_register_dai(&pdev->dev, dai);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
                goto failed_register;
        }
  
 -      platform_set_drvdata(pdev, ssi);
 +      ssi->soc_platform_pdev = platform_device_alloc("imx-fiq-pcm-audio", pdev->id);
 +      if (!ssi->soc_platform_pdev)
 +              goto failed_pdev_alloc;
 +      platform_set_drvdata(ssi->soc_platform_pdev, ssi);
 +      ret = platform_device_add(ssi->soc_platform_pdev);
 +      if (ret) {
 +              dev_err(&pdev->dev, "failed to add platform device\n");
 +              goto failed_pdev_add;
 +      }
  
        return 0;
  
 +failed_pdev_add:
 +      platform_device_put(ssi->soc_platform_pdev);
 +failed_pdev_alloc:
 +      snd_soc_unregister_dai(&pdev->dev);
  failed_register:
  failed_ac97:
        iounmap(ssi->base);
@@@ -708,15 -706,16 +708,15 @@@ static int __devexit imx_ssi_remove(str
  {
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct imx_ssi *ssi = platform_get_drvdata(pdev);
 -      struct snd_soc_dai *dai = &imx_ssi_pcm_dai[pdev->id];
  
 -      snd_soc_unregister_dai(dai);
 +      platform_device_del(ssi->soc_platform_pdev);
 +      platform_device_put(ssi->soc_platform_pdev);
 +
 +      snd_soc_unregister_dai(&pdev->dev);
  
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
  
 -      if (!(ssi->flags & IMX_SSI_DMA))
 -              imx_ssi_fiq_exit(pdev, ssi);
 -
        iounmap(ssi->base);
        release_mem_region(res->start, resource_size(res));
        clk_disable(ssi->clk);
@@@ -731,19 -730,34 +731,19 @@@ static struct platform_driver imx_ssi_d
        .remove = __devexit_p(imx_ssi_remove),
  
        .driver = {
 -              .name = DRV_NAME,
 +              .name = "imx-ssi-dai",
                .owner = THIS_MODULE,
        },
  };
  
  static int __init imx_ssi_init(void)
  {
 -      int ret;
 -
 -      ret = snd_soc_register_platform(&imx_soc_platform);
 -      if (ret) {
 -              pr_err("failed to register soc platform: %d\n", ret);
 -              return ret;
 -      }
 -
 -      ret = platform_driver_register(&imx_ssi_driver);
 -      if (ret) {
 -              snd_soc_unregister_platform(&imx_soc_platform);
 -              return ret;
 -      }
 -
 -      return 0;
 +      return platform_driver_register(&imx_ssi_driver);
  }
  
  static void __exit imx_ssi_exit(void)
  {
        platform_driver_unregister(&imx_ssi_driver);
 -      snd_soc_unregister_platform(&imx_soc_platform);
  }
  
  module_init(imx_ssi_init);
diff --combined sound/soc/soc-core.c
@@@ -3,8 -3,6 +3,8 @@@
   *
   * Copyright 2005 Wolfson Microelectronics PLC.
   * Copyright 2005 Openedhand Ltd.
 + * Copyright (C) 2010 Slimlogic Ltd.
 + * Copyright (C) 2010 Texas Instruments Inc.
   *
   * Author: Liam Girdwood <lrg@slimlogic.co.uk>
   *         with code, comments and ideas from :-
@@@ -39,8 -37,6 +39,8 @@@
  #include <sound/soc-dapm.h>
  #include <sound/initval.h>
  
 +#define NAME_SIZE     32
 +
  static DEFINE_MUTEX(pcm_mutex);
  static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq);
  
@@@ -56,7 -52,6 +56,7 @@@ static LIST_HEAD(codec_list)
  
  static int snd_soc_register_card(struct snd_soc_card *card);
  static int snd_soc_unregister_card(struct snd_soc_card *card);
 +static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
  
  /*
   * This is a timeout to do a DAPM powerdown after a stream is closed().
@@@ -91,30 -86,30 +91,30 @@@ static ssize_t soc_codec_reg_show(struc
  {
        int ret, i, step = 1, count = 0;
  
 -      if (!codec->reg_cache_size)
 +      if (!codec->driver->reg_cache_size)
                return 0;
  
 -      if (codec->reg_cache_step)
 -              step = codec->reg_cache_step;
 +      if (codec->driver->reg_cache_step)
 +              step = codec->driver->reg_cache_step;
  
        count += sprintf(buf, "%s registers\n", codec->name);
 -      for (i = 0; i < codec->reg_cache_size; i += step) {
 -              if (codec->readable_register && !codec->readable_register(i))
 +      for (i = 0; i < codec->driver->reg_cache_size; i += step) {
 +              if (codec->driver->readable_register && !codec->driver->readable_register(i))
                        continue;
  
                count += sprintf(buf + count, "%2x: ", i);
                if (count >= PAGE_SIZE - 1)
                        break;
  
 -              if (codec->display_register) {
 -                      count += codec->display_register(codec, buf + count,
 +              if (codec->driver->display_register) {
 +                      count += codec->driver->display_register(codec, buf + count,
                                                         PAGE_SIZE - count, i);
                } else {
                        /* If the read fails it's almost certainly due to
                         * the register being volatile and the device being
                         * powered off.
                         */
 -                      ret = codec->read(codec, i);
 +                      ret = codec->driver->read(codec, i);
                        if (ret >= 0)
                                count += snprintf(buf + count,
                                                  PAGE_SIZE - count,
  static ssize_t codec_reg_show(struct device *dev,
        struct device_attribute *attr, char *buf)
  {
 -      struct snd_soc_device *devdata = dev_get_drvdata(dev);
 -      return soc_codec_reg_show(devdata->card->codec, buf);
 +      struct snd_soc_pcm_runtime *rtd =
 +                      container_of(dev, struct snd_soc_pcm_runtime, dev);
 +
 +      return soc_codec_reg_show(rtd->codec, buf);
  }
  
  static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL);
  static ssize_t pmdown_time_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
  {
 -      struct snd_soc_device *socdev = dev_get_drvdata(dev);
 -      struct snd_soc_card *card = socdev->card;
 +      struct snd_soc_pcm_runtime *rtd =
 +                      container_of(dev, struct snd_soc_pcm_runtime, dev);
  
 -      return sprintf(buf, "%ld\n", card->pmdown_time);
 +      return sprintf(buf, "%ld\n", rtd->pmdown_time);
  }
  
  static ssize_t pmdown_time_set(struct device *dev,
                               struct device_attribute *attr,
                               const char *buf, size_t count)
  {
 -      struct snd_soc_device *socdev = dev_get_drvdata(dev);
 -      struct snd_soc_card *card = socdev->card;
 +      struct snd_soc_pcm_runtime *rtd =
 +                      container_of(dev, struct snd_soc_pcm_runtime, dev);
  
 -      strict_strtol(buf, 10, &card->pmdown_time);
 +      strict_strtol(buf, 10, &rtd->pmdown_time);
  
        return count;
  }
@@@ -210,19 -203,19 +210,19 @@@ static ssize_t codec_reg_write_file(str
                return -EFAULT;
        buf[buf_size] = 0;
  
 -      if (codec->reg_cache_step)
 -              step = codec->reg_cache_step;
 +      if (codec->driver->reg_cache_step)
 +              step = codec->driver->reg_cache_step;
  
        while (*start == ' ')
                start++;
        reg = simple_strtoul(start, &start, 16);
 -      if ((reg >= codec->reg_cache_size) || (reg % step))
 +      if ((reg >= codec->driver->reg_cache_size) || (reg % step))
                return -EINVAL;
        while (*start == ' ')
                start++;
        if (strict_strtoul(start, 16, &value))
                return -EINVAL;
 -      codec->write(codec, reg, value);
 +      codec->driver->write(codec, reg, value);
        return buf_size;
  }
  
@@@ -234,7 -227,16 +234,7 @@@ static const struct file_operations cod
  
  static void soc_init_codec_debugfs(struct snd_soc_codec *codec)
  {
 -      char codec_root[128];
 -
 -      if (codec->dev)
 -              snprintf(codec_root, sizeof(codec_root),
 -                      "%s.%s", codec->name, dev_name(codec->dev));
 -      else
 -              snprintf(codec_root, sizeof(codec_root),
 -                      "%s", codec->name);
 -
 -      codec->debugfs_codec_root = debugfs_create_dir(codec_root,
 +      codec->debugfs_codec_root = debugfs_create_dir(codec->name ,
                                                       debugfs_root);
        if (!codec->debugfs_codec_root) {
                printk(KERN_WARNING
@@@ -303,7 -305,7 +303,7 @@@ static int soc_ac97_dev_register(struc
        codec->ac97->dev.release = soc_ac97_device_release;
  
        dev_set_name(&codec->ac97->dev, "%d-%d:%s",
 -                   codec->card->number, 0, codec->name);
 +                   codec->card->snd_card->number, 0, codec->name);
        err = device_register(&codec->ac97->dev);
        if (err < 0) {
                snd_printk(KERN_ERR "Can't register ac97 bus\n");
  static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
  
 -      if (codec_dai->symmetric_rates || cpu_dai->symmetric_rates ||
 -          machine->symmetric_rates) {
 -              dev_dbg(card->dev, "Symmetry forces %dHz rate\n",
 -                      machine->rate);
 +      if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates ||
 +                      rtd->dai_link->symmetric_rates) {
 +              dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n",
 +                              rtd->rate);
  
                ret = snd_pcm_hw_constraint_minmax(substream->runtime,
                                                   SNDRV_PCM_HW_PARAM_RATE,
 -                                                 machine->rate,
 -                                                 machine->rate);
 +                                                 rtd->rate,
 +                                                 rtd->rate);
                if (ret < 0) {
 -                      dev_err(card->dev,
 +                      dev_err(&rtd->dev,
                                "Unable to apply rate symmetry constraint: %d\n", ret);
                        return ret;
                }
  static int soc_pcm_open(struct snd_pcm_substream *substream)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_card *card = socdev->card;
        struct snd_pcm_runtime *runtime = substream->runtime;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
 +      struct snd_soc_dai_driver *cpu_dai_drv = cpu_dai->driver;
 +      struct snd_soc_dai_driver *codec_dai_drv = codec_dai->driver;
        int ret = 0;
  
        mutex_lock(&pcm_mutex);
  
        /* startup the audio subsystem */
 -      if (cpu_dai->ops->startup) {
 -              ret = cpu_dai->ops->startup(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->startup) {
 +              ret = cpu_dai->driver->ops->startup(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open interface %s\n",
                                cpu_dai->name);
                }
        }
  
 -      if (platform->pcm_ops->open) {
 -              ret = platform->pcm_ops->open(substream);
 +      if (platform->driver->ops->open) {
 +              ret = platform->driver->ops->open(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open platform %s\n", platform->name);
                        goto platform_err;
                }
        }
  
 -      if (codec_dai->ops->startup) {
 -              ret = codec_dai->ops->startup(substream, codec_dai);
 +      if (codec_dai->driver->ops->startup) {
 +              ret = codec_dai->driver->ops->startup(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't open codec %s\n",
                                codec_dai->name);
                }
        }
  
 -      if (machine->ops && machine->ops->startup) {
 -              ret = machine->ops->startup(substream);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->startup) {
 +              ret = rtd->dai_link->ops->startup(substream);
                if (ret < 0) {
 -                      printk(KERN_ERR "asoc: %s startup failed\n", machine->name);
 +                      printk(KERN_ERR "asoc: %s startup failed\n", rtd->dai_link->name);
                        goto machine_err;
                }
        }
        /* Check that the codec and cpu DAI's are compatible */
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                runtime->hw.rate_min =
 -                      max(codec_dai->playback.rate_min,
 -                          cpu_dai->playback.rate_min);
 +                      max(codec_dai_drv->playback.rate_min,
 +                          cpu_dai_drv->playback.rate_min);
                runtime->hw.rate_max =
 -                      min(codec_dai->playback.rate_max,
 -                          cpu_dai->playback.rate_max);
 +                      min(codec_dai_drv->playback.rate_max,
 +                          cpu_dai_drv->playback.rate_max);
                runtime->hw.channels_min =
 -                      max(codec_dai->playback.channels_min,
 -                              cpu_dai->playback.channels_min);
 +                      max(codec_dai_drv->playback.channels_min,
 +                              cpu_dai_drv->playback.channels_min);
                runtime->hw.channels_max =
 -                      min(codec_dai->playback.channels_max,
 -                              cpu_dai->playback.channels_max);
 +                      min(codec_dai_drv->playback.channels_max,
 +                              cpu_dai_drv->playback.channels_max);
                runtime->hw.formats =
 -                      codec_dai->playback.formats & cpu_dai->playback.formats;
 +                      codec_dai_drv->playback.formats & cpu_dai_drv->playback.formats;
                runtime->hw.rates =
 -                      codec_dai->playback.rates & cpu_dai->playback.rates;
 -              if (codec_dai->playback.rates
 +                      codec_dai_drv->playback.rates & cpu_dai_drv->playback.rates;
 +              if (codec_dai_drv->playback.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 -                      runtime->hw.rates |= cpu_dai->playback.rates;
 -              if (cpu_dai->playback.rates
 +                      runtime->hw.rates |= cpu_dai_drv->playback.rates;
 +              if (cpu_dai_drv->playback.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 -                      runtime->hw.rates |= codec_dai->playback.rates;
 +                      runtime->hw.rates |= codec_dai_drv->playback.rates;
        } else {
                runtime->hw.rate_min =
 -                      max(codec_dai->capture.rate_min,
 -                          cpu_dai->capture.rate_min);
 +                      max(codec_dai_drv->capture.rate_min,
 +                          cpu_dai_drv->capture.rate_min);
                runtime->hw.rate_max =
 -                      min(codec_dai->capture.rate_max,
 -                          cpu_dai->capture.rate_max);
 +                      min(codec_dai_drv->capture.rate_max,
 +                          cpu_dai_drv->capture.rate_max);
                runtime->hw.channels_min =
 -                      max(codec_dai->capture.channels_min,
 -                              cpu_dai->capture.channels_min);
 +                      max(codec_dai_drv->capture.channels_min,
 +                              cpu_dai_drv->capture.channels_min);
                runtime->hw.channels_max =
 -                      min(codec_dai->capture.channels_max,
 -                              cpu_dai->capture.channels_max);
 +                      min(codec_dai_drv->capture.channels_max,
 +                              cpu_dai_drv->capture.channels_max);
                runtime->hw.formats =
 -                      codec_dai->capture.formats & cpu_dai->capture.formats;
 +                      codec_dai_drv->capture.formats & cpu_dai_drv->capture.formats;
                runtime->hw.rates =
 -                      codec_dai->capture.rates & cpu_dai->capture.rates;
 -              if (codec_dai->capture.rates
 +                      codec_dai_drv->capture.rates & cpu_dai_drv->capture.rates;
 +              if (codec_dai_drv->capture.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 -                      runtime->hw.rates |= cpu_dai->capture.rates;
 -              if (cpu_dai->capture.rates
 +                      runtime->hw.rates |= cpu_dai_drv->capture.rates;
 +              if (cpu_dai_drv->capture.rates
                           & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))
 -                      runtime->hw.rates |= codec_dai->capture.rates;
 +                      runtime->hw.rates |= codec_dai_drv->capture.rates;
        }
  
        snd_pcm_limit_hw_rates(runtime);
        }
        if (!runtime->hw.channels_min || !runtime->hw.channels_max) {
                printk(KERN_ERR "asoc: %s <-> %s No matching channels\n",
 -                      codec_dai->name, cpu_dai->name);
 +                              codec_dai->name, cpu_dai->name);
                goto config_err;
        }
  
                        goto config_err;
        }
  
 -      pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name);
 +      pr_debug("asoc: %s <-> %s info:\n",
 +                      codec_dai->name, cpu_dai->name);
        pr_debug("asoc: rate mask 0x%x\n", runtime->hw.rates);
        pr_debug("asoc: min ch %d max ch %d\n", runtime->hw.channels_min,
                 runtime->hw.channels_max);
                 runtime->hw.rate_max);
  
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 -              cpu_dai->playback.active++;
 -              codec_dai->playback.active++;
 +              cpu_dai->playback_active++;
 +              codec_dai->playback_active++;
        } else {
 -              cpu_dai->capture.active++;
 -              codec_dai->capture.active++;
 +              cpu_dai->capture_active++;
 +              codec_dai->capture_active++;
        }
        cpu_dai->active++;
        codec_dai->active++;
 -      card->codec->active++;
 +      rtd->codec->active++;
        mutex_unlock(&pcm_mutex);
        return 0;
  
  config_err:
 -      if (machine->ops && machine->ops->shutdown)
 -              machine->ops->shutdown(substream);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
 +              rtd->dai_link->ops->shutdown(substream);
  
  machine_err:
 -      if (codec_dai->ops->shutdown)
 -              codec_dai->ops->shutdown(substream, codec_dai);
 +      if (codec_dai->driver->ops->shutdown)
 +              codec_dai->driver->ops->shutdown(substream, codec_dai);
  
  codec_dai_err:
 -      if (platform->pcm_ops->close)
 -              platform->pcm_ops->close(substream);
 +      if (platform->driver->ops->close)
 +              platform->driver->ops->close(substream);
  
  platform_err:
 -      if (cpu_dai->ops->shutdown)
 -              cpu_dai->ops->shutdown(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->shutdown)
 +              cpu_dai->driver->ops->shutdown(substream, cpu_dai);
  out:
        mutex_unlock(&pcm_mutex);
        return ret;
   */
  static void close_delayed_work(struct work_struct *work)
  {
 -      struct snd_soc_card *card = container_of(work, struct snd_soc_card,
 -                                               delayed_work.work);
 -      struct snd_soc_codec *codec = card->codec;
 -      struct snd_soc_dai *codec_dai;
 -      int i;
 +      struct snd_soc_pcm_runtime *rtd =
 +                      container_of(work, struct snd_soc_pcm_runtime, delayed_work.work);
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
  
        mutex_lock(&pcm_mutex);
 -      for (i = 0; i < codec->num_dai; i++) {
 -              codec_dai = &codec->dai[i];
 -
 -              pr_debug("pop wq checking: %s status: %s waiting: %s\n",
 -                       codec_dai->playback.stream_name,
 -                       codec_dai->playback.active ? "active" : "inactive",
 -                       codec_dai->pop_wait ? "yes" : "no");
 -
 -              /* are we waiting on this codec DAI stream */
 -              if (codec_dai->pop_wait == 1) {
 -                      codec_dai->pop_wait = 0;
 -                      snd_soc_dapm_stream_event(codec,
 -                              codec_dai->playback.stream_name,
 -                              SND_SOC_DAPM_STREAM_STOP);
 -              }
 +
 +      pr_debug("pop wq checking: %s status: %s waiting: %s\n",
 +               codec_dai->driver->playback.stream_name,
 +               codec_dai->playback_active ? "active" : "inactive",
 +               codec_dai->pop_wait ? "yes" : "no");
 +
 +      /* are we waiting on this codec DAI stream */
 +      if (codec_dai->pop_wait == 1) {
 +              codec_dai->pop_wait = 0;
 +              snd_soc_dapm_stream_event(rtd,
 +                      codec_dai->driver->playback.stream_name,
 +                      SND_SOC_DAPM_STREAM_STOP);
        }
 +
        mutex_unlock(&pcm_mutex);
  }
  
  static int soc_codec_close(struct snd_pcm_substream *substream)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 -      struct snd_soc_codec *codec = card->codec;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
 +      struct snd_soc_codec *codec = rtd->codec;
  
        mutex_lock(&pcm_mutex);
  
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 -              cpu_dai->playback.active--;
 -              codec_dai->playback.active--;
 +              cpu_dai->playback_active--;
 +              codec_dai->playback_active--;
        } else {
 -              cpu_dai->capture.active--;
 -              codec_dai->capture.active--;
 +              cpu_dai->capture_active--;
 +              codec_dai->capture_active--;
        }
  
        cpu_dai->active--;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                snd_soc_dai_digital_mute(codec_dai, 1);
  
 -      if (cpu_dai->ops->shutdown)
 -              cpu_dai->ops->shutdown(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->shutdown)
 +              cpu_dai->driver->ops->shutdown(substream, cpu_dai);
  
 -      if (codec_dai->ops->shutdown)
 -              codec_dai->ops->shutdown(substream, codec_dai);
 +      if (codec_dai->driver->ops->shutdown)
 +              codec_dai->driver->ops->shutdown(substream, codec_dai);
  
 -      if (machine->ops && machine->ops->shutdown)
 -              machine->ops->shutdown(substream);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->shutdown)
 +              rtd->dai_link->ops->shutdown(substream);
  
 -      if (platform->pcm_ops->close)
 -              platform->pcm_ops->close(substream);
 +      if (platform->driver->ops->close)
 +              platform->driver->ops->close(substream);
 +      cpu_dai->runtime = NULL;
  
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
                /* start delayed pop wq here for playback streams */
                codec_dai->pop_wait = 1;
 -              schedule_delayed_work(&card->delayed_work,
 -                      msecs_to_jiffies(card->pmdown_time));
 +              schedule_delayed_work(&rtd->delayed_work,
 +                      msecs_to_jiffies(rtd->pmdown_time));
        } else {
                /* capture streams can be powered down now */
 -              snd_soc_dapm_stream_event(codec,
 -                      codec_dai->capture.stream_name,
 +              snd_soc_dapm_stream_event(rtd,
 +                      codec_dai->driver->capture.stream_name,
                        SND_SOC_DAPM_STREAM_STOP);
        }
  
  static int soc_pcm_prepare(struct snd_pcm_substream *substream)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 -      struct snd_soc_codec *codec = card->codec;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
  
        mutex_lock(&pcm_mutex);
  
 -      if (machine->ops && machine->ops->prepare) {
 -              ret = machine->ops->prepare(substream);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->prepare) {
 +              ret = rtd->dai_link->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: machine prepare error\n");
                        goto out;
                }
        }
  
 -      if (platform->pcm_ops->prepare) {
 -              ret = platform->pcm_ops->prepare(substream);
 +      if (platform->driver->ops->prepare) {
 +              ret = platform->driver->ops->prepare(substream);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform prepare error\n");
                        goto out;
                }
        }
  
 -      if (codec_dai->ops->prepare) {
 -              ret = codec_dai->ops->prepare(substream, codec_dai);
 +      if (codec_dai->driver->ops->prepare) {
 +              ret = codec_dai->driver->ops->prepare(substream, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: codec DAI prepare error\n");
                        goto out;
                }
        }
  
 -      if (cpu_dai->ops->prepare) {
 -              ret = cpu_dai->ops->prepare(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->prepare) {
 +              ret = cpu_dai->driver->ops->prepare(substream, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: cpu DAI prepare error\n");
                        goto out;
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
            codec_dai->pop_wait) {
                codec_dai->pop_wait = 0;
 -              cancel_delayed_work(&card->delayed_work);
 +              cancel_delayed_work(&rtd->delayed_work);
        }
  
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 -              snd_soc_dapm_stream_event(codec,
 -                                        codec_dai->playback.stream_name,
 +              snd_soc_dapm_stream_event(rtd,
 +                                        codec_dai->driver->playback.stream_name,
                                          SND_SOC_DAPM_STREAM_START);
        else
 -              snd_soc_dapm_stream_event(codec,
 -                                        codec_dai->capture.stream_name,
 +              snd_soc_dapm_stream_event(rtd,
 +                                        codec_dai->driver->capture.stream_name,
                                          SND_SOC_DAPM_STREAM_START);
  
        snd_soc_dai_digital_mute(codec_dai, 0);
@@@ -677,23 -692,26 +677,23 @@@ static int soc_pcm_hw_params(struct snd
                                struct snd_pcm_hw_params *params)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret = 0;
  
        mutex_lock(&pcm_mutex);
  
 -      if (machine->ops && machine->ops->hw_params) {
 -              ret = machine->ops->hw_params(substream, params);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->hw_params) {
 +              ret = rtd->dai_link->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: machine hw_params failed\n");
                        goto out;
                }
        }
  
 -      if (codec_dai->ops->hw_params) {
 -              ret = codec_dai->ops->hw_params(substream, params, codec_dai);
 +      if (codec_dai->driver->ops->hw_params) {
 +              ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: can't set codec %s hw params\n",
                                codec_dai->name);
                }
        }
  
 -      if (cpu_dai->ops->hw_params) {
 -              ret = cpu_dai->ops->hw_params(substream, params, cpu_dai);
 +      if (cpu_dai->driver->ops->hw_params) {
 +              ret = cpu_dai->driver->ops->hw_params(substream, params, cpu_dai);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: interface %s hw params failed\n",
                                cpu_dai->name);
                }
        }
  
 -      if (platform->pcm_ops->hw_params) {
 -              ret = platform->pcm_ops->hw_params(substream, params);
 +      if (platform->driver->ops->hw_params) {
 +              ret = platform->driver->ops->hw_params(substream, params);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: platform %s hw params failed\n",
                                platform->name);
                }
        }
  
 -      machine->rate = params_rate(params);
 +      rtd->rate = params_rate(params);
  
  out:
        mutex_unlock(&pcm_mutex);
        return ret;
  
  platform_err:
 -      if (cpu_dai->ops->hw_free)
 -              cpu_dai->ops->hw_free(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->hw_free)
 +              cpu_dai->driver->ops->hw_free(substream, cpu_dai);
  
  interface_err:
 -      if (codec_dai->ops->hw_free)
 -              codec_dai->ops->hw_free(substream, codec_dai);
 +      if (codec_dai->driver->ops->hw_free)
 +              codec_dai->driver->ops->hw_free(substream, codec_dai);
  
  codec_err:
 -      if (machine->ops && machine->ops->hw_free)
 -              machine->ops->hw_free(substream);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
 +              rtd->dai_link->ops->hw_free(substream);
  
        mutex_unlock(&pcm_mutex);
        return ret;
  static int soc_pcm_hw_free(struct snd_pcm_substream *substream)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 -      struct snd_soc_codec *codec = card->codec;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
 +      struct snd_soc_codec *codec = rtd->codec;
  
        mutex_lock(&pcm_mutex);
  
                snd_soc_dai_digital_mute(codec_dai, 1);
  
        /* free any machine hw params */
 -      if (machine->ops && machine->ops->hw_free)
 -              machine->ops->hw_free(substream);
 +      if (rtd->dai_link->ops && rtd->dai_link->ops->hw_free)
 +              rtd->dai_link->ops->hw_free(substream);
  
        /* free any DMA resources */
 -      if (platform->pcm_ops->hw_free)
 -              platform->pcm_ops->hw_free(substream);
 +      if (platform->driver->ops->hw_free)
 +              platform->driver->ops->hw_free(substream);
  
        /* now free hw params for the DAI's  */
 -      if (codec_dai->ops->hw_free)
 -              codec_dai->ops->hw_free(substream, codec_dai);
 +      if (codec_dai->driver->ops->hw_free)
 +              codec_dai->driver->ops->hw_free(substream, codec_dai);
  
 -      if (cpu_dai->ops->hw_free)
 -              cpu_dai->ops->hw_free(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->hw_free)
 +              cpu_dai->driver->ops->hw_free(substream, cpu_dai);
  
        mutex_unlock(&pcm_mutex);
        return 0;
  static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_card *card= socdev->card;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
        int ret;
  
 -      if (codec_dai->ops->trigger) {
 -              ret = codec_dai->ops->trigger(substream, cmd, codec_dai);
 +      if (codec_dai->driver->ops->trigger) {
 +              ret = codec_dai->driver->ops->trigger(substream, cmd, codec_dai);
                if (ret < 0)
                        return ret;
        }
  
 -      if (platform->pcm_ops->trigger) {
 -              ret = platform->pcm_ops->trigger(substream, cmd);
 +      if (platform->driver->ops->trigger) {
 +              ret = platform->driver->ops->trigger(substream, cmd);
                if (ret < 0)
                        return ret;
        }
  
 -      if (cpu_dai->ops->trigger) {
 -              ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai);
 +      if (cpu_dai->driver->ops->trigger) {
 +              ret = cpu_dai->driver->ops->trigger(substream, cmd, cpu_dai);
                if (ret < 0)
                        return ret;
        }
  static snd_pcm_uframes_t soc_pcm_pointer(struct snd_pcm_substream *substream)
  {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 -      struct snd_soc_device *socdev = rtd->socdev;
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai_link *machine = rtd->dai;
 -      struct snd_soc_dai *cpu_dai = machine->cpu_dai;
 -      struct snd_soc_dai *codec_dai = machine->codec_dai;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
        struct snd_pcm_runtime *runtime = substream->runtime;
        snd_pcm_uframes_t offset = 0;
        snd_pcm_sframes_t delay = 0;
  
 -      if (platform->pcm_ops->pointer)
 -              offset = platform->pcm_ops->pointer(substream);
 +      if (platform->driver->ops->pointer)
 +              offset = platform->driver->ops->pointer(substream);
  
 -      if (cpu_dai->ops->delay)
 -              delay += cpu_dai->ops->delay(substream, cpu_dai);
 +      if (cpu_dai->driver->ops->delay)
 +              delay += cpu_dai->driver->ops->delay(substream, cpu_dai);
  
 -      if (codec_dai->ops->delay)
 -              delay += codec_dai->ops->delay(substream, codec_dai);
 +      if (codec_dai->driver->ops->delay)
 +              delay += codec_dai->driver->ops->delay(substream, codec_dai);
  
 -      if (platform->delay)
 -              delay += platform->delay(substream, codec_dai);
 +      if (platform->driver->delay)
 +              delay += platform->driver->delay(substream, codec_dai);
  
        runtime->delay = delay;
  
@@@ -853,111 -880,104 +853,111 @@@ static struct snd_pcm_ops soc_pcm_ops 
  static int soc_suspend(struct device *dev)
  {
        struct platform_device *pdev = to_platform_device(dev);
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 -      struct snd_soc_codec *codec = card->codec;
 +      struct snd_soc_card *card = platform_get_drvdata(pdev);
        int i;
  
        /* If the initialization of this soc device failed, there is no codec
         * associated with it. Just bail out in this case.
         */
 -      if (!codec)
 +      if (list_empty(&card->codec_dev_list))
                return 0;
  
        /* Due to the resume being scheduled into a workqueue we could
        * suspend before that's finished - wait for it to complete.
         */
 -      snd_power_lock(codec->card);
 -      snd_power_wait(codec->card, SNDRV_CTL_POWER_D0);
 -      snd_power_unlock(codec->card);
 +      snd_power_lock(card->snd_card);
 +      snd_power_wait(card->snd_card, SNDRV_CTL_POWER_D0);
 +      snd_power_unlock(card->snd_card);
  
        /* we're going to block userspace touching us until resume completes */
 -      snd_power_change_state(codec->card, SNDRV_CTL_POWER_D3hot);
 +      snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot);
  
        /* mute any active DAC's */
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *dai = card->rtd[i].codec_dai;
 +              struct snd_soc_dai_driver *drv = dai->driver;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (dai->ops->digital_mute && dai->playback.active)
 -                      dai->ops->digital_mute(dai, 1);
 +              if (drv->ops->digital_mute && dai->playback_active)
 +                      drv->ops->digital_mute(dai, 1);
        }
  
        /* suspend all pcms */
 -      for (i = 0; i < card->num_links; i++) {
 -              if (card->dai_link[i].ignore_suspend)
 +      for (i = 0; i < card->num_rtd; i++) {
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              snd_pcm_suspend_all(card->dai_link[i].pcm);
 +              snd_pcm_suspend_all(card->rtd[i].pcm);
        }
  
        if (card->suspend_pre)
                card->suspend_pre(pdev, PMSG_SUSPEND);
  
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai  *cpu_dai = card->dai_link[i].cpu_dai;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 +              struct snd_soc_platform *platform = card->rtd[i].platform;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (cpu_dai->suspend && !cpu_dai->ac97_control)
 -                      cpu_dai->suspend(cpu_dai);
 -              if (platform->suspend)
 -                      platform->suspend(&card->dai_link[i]);
 +              if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
 +                      cpu_dai->driver->suspend(cpu_dai);
 +              if (platform->driver->suspend && !platform->suspended) {
 +                      platform->driver->suspend(cpu_dai);
 +                      platform->suspended = 1;
 +              }
        }
  
        /* close any waiting streams and save state */
 -      run_delayed_work(&card->delayed_work);
 -      codec->suspend_bias_level = codec->bias_level;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              run_delayed_work(&card->rtd[i].delayed_work);
 +              card->rtd[i].codec->suspend_bias_level = card->rtd[i].codec->bias_level;
 +      }
  
 -      for (i = 0; i < codec->num_dai; i++) {
 -              char *stream = codec->dai[i].playback.stream_name;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (stream != NULL)
 -                      snd_soc_dapm_stream_event(codec, stream,
 +              if (driver->playback.stream_name != NULL)
 +                      snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
                                SND_SOC_DAPM_STREAM_SUSPEND);
 -              stream = codec->dai[i].capture.stream_name;
 -              if (stream != NULL)
 -                      snd_soc_dapm_stream_event(codec, stream,
 +
 +              if (driver->capture.stream_name != NULL)
 +                      snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
                                SND_SOC_DAPM_STREAM_SUSPEND);
        }
  
 -      /* If there are paths active then the CODEC will be held with
 -       * bias _ON and should not be suspended. */
 -      if (codec_dev->suspend) {
 -              switch (codec->bias_level) {
 -              case SND_SOC_BIAS_STANDBY:
 -              case SND_SOC_BIAS_OFF:
 -                      codec_dev->suspend(pdev, PMSG_SUSPEND);
 -                      break;
 -              default:
 -                      dev_dbg(socdev->dev, "CODEC is on over suspend\n");
 -                      break;
 +      /* suspend all CODECs */
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_codec *codec = card->rtd[i].codec;
 +              /* If there are paths active then the CODEC will be held with
 +               * bias _ON and should not be suspended. */
 +              if (!codec->suspended && codec->driver->suspend) {
 +                      switch (codec->bias_level) {
 +                      case SND_SOC_BIAS_STANDBY:
 +                      case SND_SOC_BIAS_OFF:
 +                              codec->driver->suspend(codec, PMSG_SUSPEND);
 +                              codec->suspended = 1;
 +                              break;
 +                      default:
 +                              dev_dbg(codec->dev, "CODEC is on over suspend\n");
 +                              break;
 +                      }
                }
        }
  
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (cpu_dai->suspend && cpu_dai->ac97_control)
 -                      cpu_dai->suspend(cpu_dai);
 +              if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
 +                      cpu_dai->driver->suspend(cpu_dai);
        }
  
        if (card->suspend_post)
   */
  static void soc_resume_deferred(struct work_struct *work)
  {
 -      struct snd_soc_card *card = container_of(work,
 -                                               struct snd_soc_card,
 -                                               deferred_resume_work);
 -      struct snd_soc_device *socdev = card->socdev;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
 -      struct snd_soc_codec *codec = card->codec;
 -      struct platform_device *pdev = to_platform_device(socdev->dev);
 +      struct snd_soc_card *card =
 +                      container_of(work, struct snd_soc_card, deferred_resume_work);
 +      struct platform_device *pdev = to_platform_device(card->dev);
        int i;
  
        /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time,
         * so userspace apps are blocked from touching us
         */
  
 -      dev_dbg(socdev->dev, "starting resume work\n");
 +      dev_dbg(card->dev, "starting resume work\n");
  
        /* Bring us up into D2 so that DAPM starts enabling things */
 -      snd_power_change_state(codec->card, SNDRV_CTL_POWER_D2);
 +      snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2);
  
        if (card->resume_pre)
                card->resume_pre(pdev);
  
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 +      /* resume AC97 DAIs */
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (cpu_dai->resume && cpu_dai->ac97_control)
 -                      cpu_dai->resume(cpu_dai);
 -      }
 -
 -      /* If the CODEC was idle over suspend then it will have been
 -       * left with bias OFF or STANDBY and suspended so we must now
 -       * resume.  Otherwise the suspend was suppressed.
 -       */
 -      if (codec_dev->resume) {
 -              switch (codec->bias_level) {
 -              case SND_SOC_BIAS_STANDBY:
 -              case SND_SOC_BIAS_OFF:
 -                      codec_dev->resume(pdev);
 -                      break;
 -              default:
 -                      dev_dbg(socdev->dev, "CODEC was on over suspend\n");
 -                      break;
 +              if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
 +                      cpu_dai->driver->resume(cpu_dai);
 +      }
 +
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_codec *codec = card->rtd[i].codec;
 +              /* If the CODEC was idle over suspend then it will have been
 +               * left with bias OFF or STANDBY and suspended so we must now
 +               * resume.  Otherwise the suspend was suppressed.
 +               */
 +              if (codec->driver->resume && codec->suspended) {
 +                      switch (codec->bias_level) {
 +                      case SND_SOC_BIAS_STANDBY:
 +                      case SND_SOC_BIAS_OFF:
 +                              codec->driver->resume(codec);
 +                              codec->suspended = 0;
 +                              break;
 +                      default:
 +                              dev_dbg(codec->dev, "CODEC was on over suspend\n");
 +                              break;
 +                      }
                }
        }
  
 -      for (i = 0; i < codec->num_dai; i++) {
 -              char *stream = codec->dai[i].playback.stream_name;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai_driver *driver = card->rtd[i].codec_dai->driver;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (stream != NULL)
 -                      snd_soc_dapm_stream_event(codec, stream,
 +              if (driver->playback.stream_name != NULL)
 +                      snd_soc_dapm_stream_event(&card->rtd[i], driver->playback.stream_name,
                                SND_SOC_DAPM_STREAM_RESUME);
 -              stream = codec->dai[i].capture.stream_name;
 -              if (stream != NULL)
 -                      snd_soc_dapm_stream_event(codec, stream,
 +
 +              if (driver->capture.stream_name != NULL)
 +                      snd_soc_dapm_stream_event(&card->rtd[i], driver->capture.stream_name,
                                SND_SOC_DAPM_STREAM_RESUME);
        }
  
        /* unmute any active DACs */
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai *dai = card->dai_link[i].codec_dai;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *dai = card->rtd[i].codec_dai;
 +              struct snd_soc_dai_driver *drv = dai->driver;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (dai->ops->digital_mute && dai->playback.active)
 -                      dai->ops->digital_mute(dai, 0);
 +              if (drv->ops->digital_mute && dai->playback_active)
 +                      drv->ops->digital_mute(dai, 0);
        }
  
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 +              struct snd_soc_platform *platform = card->rtd[i].platform;
  
 -              if (card->dai_link[i].ignore_suspend)
 +              if (card->rtd[i].dai_link->ignore_suspend)
                        continue;
  
 -              if (cpu_dai->resume && !cpu_dai->ac97_control)
 -                      cpu_dai->resume(cpu_dai);
 -              if (platform->resume)
 -                      platform->resume(&card->dai_link[i]);
 +              if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
 +                      cpu_dai->driver->resume(cpu_dai);
 +              if (platform->driver->resume && platform->suspended) {
 +                      platform->driver->resume(cpu_dai);
 +                      platform->suspended = 0;
 +              }
        }
  
        if (card->resume_post)
                card->resume_post(pdev);
  
 -      dev_dbg(socdev->dev, "resume work completed\n");
 +      dev_dbg(card->dev, "resume work completed\n");
  
        /* userspace can access us now we are back as we were before */
 -      snd_power_change_state(codec->card, SNDRV_CTL_POWER_D0);
 +      snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
  }
  
  /* powers up audio subsystem after a suspend */
  static int soc_resume(struct device *dev)
  {
        struct platform_device *pdev = to_platform_device(dev);
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai;
 -
 -      /* If the initialization of this soc device failed, there is no codec
 -       * associated with it. Just bail out in this case.
 -       */
 -      if (!card->codec)
 -              return 0;
 +      struct snd_soc_card *card = platform_get_drvdata(pdev);
 +      int i;
  
        /* AC97 devices might have other drivers hanging off them so
         * need to resume immediately.  Other drivers don't have that
         * problem and may take a substantial amount of time to resume
         * due to I/O costs and anti-pop so handle them out of line.
         */
 -      if (cpu_dai->ac97_control) {
 -              dev_dbg(socdev->dev, "Resuming AC97 immediately\n");
 -              soc_resume_deferred(&card->deferred_resume_work);
 -      } else {
 -              dev_dbg(socdev->dev, "Scheduling resume work\n");
 -              if (!schedule_work(&card->deferred_resume_work))
 -                      dev_err(socdev->dev, "resume work item may be lost\n");
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
 +              if (cpu_dai->driver->ac97_control) {
 +                      dev_dbg(dev, "Resuming AC97 immediately\n");
 +                      soc_resume_deferred(&card->deferred_resume_work);
 +              } else {
 +                      dev_dbg(dev, "Scheduling resume work\n");
 +                      if (!schedule_work(&card->deferred_resume_work))
 +                              dev_err(dev, "resume work item may be lost\n");
 +              }
        }
  
        return 0;
  static struct snd_soc_dai_ops null_dai_ops = {
  };
  
 -static void snd_soc_instantiate_card(struct snd_soc_card *card)
 +static int soc_bind_dai_link(struct snd_soc_card *card, int num)
  {
 -      struct platform_device *pdev = container_of(card->dev,
 -                                                  struct platform_device,
 -                                                  dev);
 -      struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
 +      struct snd_soc_dai_link *dai_link = &card->dai_link[num];
 +      struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
        struct snd_soc_codec *codec;
        struct snd_soc_platform *platform;
 -      struct snd_soc_dai *dai;
 -      int i, found, ret, ac97;
 +      struct snd_soc_dai *codec_dai, *cpu_dai;
  
 -      if (card->instantiated)
 -              return;
 +      if (rtd->complete)
 +              return 1;
 +      dev_dbg(card->dev, "binding %s at idx %d\n", dai_link->name, num);
  
 -      found = 0;
 -      list_for_each_entry(platform, &platform_list, list)
 -              if (card->platform == platform) {
 -                      found = 1;
 -                      break;
 +      /* do we already have the CPU DAI for this link ? */
 +      if (rtd->cpu_dai) {
 +              goto find_codec;
 +      }
 +      /* no, then find CPU DAI from registered DAIs*/
 +      list_for_each_entry(cpu_dai, &dai_list, list) {
 +              if (!strcmp(cpu_dai->name, dai_link->cpu_dai_name)) {
 +
 +                      if (!try_module_get(cpu_dai->dev->driver->owner))
 +                              return -ENODEV;
 +
 +                      rtd->cpu_dai = cpu_dai;
 +                      goto find_codec;
                }
 -      if (!found) {
 -              dev_dbg(card->dev, "Platform %s not registered\n",
 -                      card->platform->name);
 -              return;
        }
 +      dev_dbg(card->dev, "CPU DAI %s not registered\n",
 +                      dai_link->cpu_dai_name);
  
 -      ac97 = 0;
 -      for (i = 0; i < card->num_links; i++) {
 -              found = 0;
 -              list_for_each_entry(dai, &dai_list, list)
 -                      if (card->dai_link[i].cpu_dai == dai) {
 -                              found = 1;
 -                              break;
 +find_codec:
 +      /* do we already have the CODEC for this link ? */
 +      if (rtd->codec) {
 +              goto find_platform;
 +      }
 +
 +      /* no, then find CODEC from registered CODECs*/
 +      list_for_each_entry(codec, &codec_list, list) {
 +              if (!strcmp(codec->name, dai_link->codec_name)) {
 +                      rtd->codec = codec;
 +
 +                      if (!try_module_get(codec->dev->driver->owner))
 +                              return -ENODEV;
 +
 +                      /* CODEC found, so find CODEC DAI from registered DAIs from this CODEC*/
 +                      list_for_each_entry(codec_dai, &dai_list, list) {
 +                              if (codec->dev == codec_dai->dev &&
 +                                              !strcmp(codec_dai->name, dai_link->codec_dai_name)) {
 +                                      rtd->codec_dai = codec_dai;
 +                                      goto find_platform;
 +                              }
                        }
 -              if (!found) {
 -                      dev_dbg(card->dev, "DAI %s not registered\n",
 -                              card->dai_link[i].cpu_dai->name);
 -                      return;
 +                      dev_dbg(card->dev, "CODEC DAI %s not registered\n",
 +                                      dai_link->codec_dai_name);
 +
 +                      goto find_platform;
                }
 +      }
 +      dev_dbg(card->dev, "CODEC %s not registered\n",
 +                      dai_link->codec_name);
  
 -              if (card->dai_link[i].cpu_dai->ac97_control)
 -                      ac97 = 1;
 +find_platform:
 +      /* do we already have the CODEC DAI for this link ? */
 +      if (rtd->platform) {
 +              goto out;
        }
 +      /* no, then find CPU DAI from registered DAIs*/
 +      list_for_each_entry(platform, &platform_list, list) {
 +              if (!strcmp(platform->name, dai_link->platform_name)) {
  
 -      for (i = 0; i < card->num_links; i++) {
 -              if (!card->dai_link[i].codec_dai->ops)
 -                      card->dai_link[i].codec_dai->ops = &null_dai_ops;
 +                      if (!try_module_get(platform->dev->driver->owner))
 +                              return -ENODEV;
 +
 +                      rtd->platform = platform;
 +                      goto out;
 +              }
        }
  
 -      /* If we have AC97 in the system then don't wait for the
 -       * codec.  This will need revisiting if we have to handle
 -       * systems with mixed AC97 and non-AC97 parts.  Only check for
 -       * DAIs currently; we can't do this per link since some AC97
 -       * codecs have non-AC97 DAIs.
 -       */
 -      if (!ac97)
 -              for (i = 0; i < card->num_links; i++) {
 -                      found = 0;
 -                      list_for_each_entry(dai, &dai_list, list)
 -                              if (card->dai_link[i].codec_dai == dai) {
 -                                      found = 1;
 -                                      break;
 -                              }
 -                      if (!found) {
 -                              dev_dbg(card->dev, "DAI %s not registered\n",
 -                                      card->dai_link[i].codec_dai->name);
 -                              return;
 -                      }
 +      dev_dbg(card->dev, "platform %s not registered\n",
 +                      dai_link->platform_name);
 +      return 0;
 +
 +out:
 +      /* mark rtd as complete if we found all 4 of our client devices */
 +      if (rtd->codec && rtd->codec_dai && rtd->platform && rtd->cpu_dai) {
 +              rtd->complete = 1;
 +              card->num_rtd++;
 +      }
 +      return 1;
 +}
 +
 +static void soc_remove_dai_link(struct snd_soc_card *card, int num)
 +{
 +      struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 +      struct snd_soc_codec *codec = rtd->codec;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
 +      int err;
 +
 +      /* unregister the rtd device */
 +      if (rtd->dev_registered) {
 +              device_remove_file(&rtd->dev, &dev_attr_pmdown_time);
 +              device_unregister(&rtd->dev);
 +              rtd->dev_registered = 0;
 +      }
 +
 +      /* remove the CODEC DAI */
 +      if (codec_dai && codec_dai->probed) {
 +              if (codec_dai->driver->remove) {
 +                      err = codec_dai->driver->remove(codec_dai);
 +                      if (err < 0)
 +                              printk(KERN_ERR "asoc: failed to remove %s\n", codec_dai->name);
                }
 +              codec_dai->probed = 0;
 +              list_del(&codec_dai->card_list);
 +      }
  
 -      /* Note that we do not current check for codec components */
 +      /* remove the platform */
 +      if (platform && platform->probed) {
 +              if (platform->driver->remove) {
 +                      err = platform->driver->remove(platform);
 +                      if (err < 0)
 +                              printk(KERN_ERR "asoc: failed to remove %s\n", platform->name);
 +              }
 +              platform->probed = 0;
 +              list_del(&platform->card_list);
 +              module_put(platform->dev->driver->owner);
 +      }
  
 -      dev_dbg(card->dev, "All components present, instantiating\n");
 +      /* remove the CODEC */
 +      if (codec && codec->probed) {
 +              if (codec->driver->remove) {
 +                      err = codec->driver->remove(codec);
 +                      if (err < 0)
 +                              printk(KERN_ERR "asoc: failed to remove %s\n", codec->name);
 +              }
  
 -      /* Found everything, bring it up */
 -      card->pmdown_time = pmdown_time;
 +              /* Make sure all DAPM widgets are freed */
 +              snd_soc_dapm_free(codec);
  
 -      if (card->probe) {
 -              ret = card->probe(pdev);
 -              if (ret < 0)
 -                      return;
 +              soc_cleanup_codec_debugfs(codec);
 +              device_remove_file(&rtd->dev, &dev_attr_codec_reg);
 +              codec->probed = 0;
 +              list_del(&codec->card_list);
 +              module_put(codec->dev->driver->owner);
        }
  
 -      for (i = 0; i < card->num_links; i++) {
 -              struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 -              if (cpu_dai->probe) {
 -                      ret = cpu_dai->probe(pdev, cpu_dai);
 -                      if (ret < 0)
 -                              goto cpu_dai_err;
 +      /* remove the cpu_dai */
 +      if (cpu_dai && cpu_dai->probed) {
 +              if (cpu_dai->driver->remove) {
 +                      err = cpu_dai->driver->remove(cpu_dai);
 +                      if (err < 0)
 +                              printk(KERN_ERR "asoc: failed to remove %s\n", cpu_dai->name);
                }
 +              cpu_dai->probed = 0;
 +              list_del(&cpu_dai->card_list);
 +              module_put(cpu_dai->dev->driver->owner);
        }
 +}
  
 -      if (codec_dev->probe) {
 -              ret = codec_dev->probe(pdev);
 -              if (ret < 0)
 -                      goto cpu_dai_err;
 +static void rtd_release(struct device *dev) {}
 +
 +static int soc_probe_dai_link(struct snd_soc_card *card, int num)
 +{
 +      struct snd_soc_dai_link *dai_link = &card->dai_link[num];
 +      struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
 +      struct snd_soc_codec *codec = rtd->codec;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai;
 +      int ret;
 +
 +      dev_dbg(card->dev, "probe %s dai link %d\n", card->name, num);
 +
 +      /* config components */
 +      codec_dai->codec = codec;
 +      codec->card = card;
 +      cpu_dai->platform = platform;
 +      rtd->card = card;
 +      rtd->dev.parent = card->dev;
 +      codec_dai->card = card;
 +      cpu_dai->card = card;
 +
 +      /* set default power off timeout */
 +      rtd->pmdown_time = pmdown_time;
 +
 +      /* probe the cpu_dai */
 +      if (!cpu_dai->probed) {
 +              if (cpu_dai->driver->probe) {
 +                      ret = cpu_dai->driver->probe(cpu_dai);
 +                      if (ret < 0) {
 +                              printk(KERN_ERR "asoc: failed to probe CPU DAI %s\n",
 +                                              cpu_dai->name);
 +                              return ret;
 +                      }
 +              }
 +              cpu_dai->probed = 1;
 +              /* mark cpu_dai as probed and add to card cpu_dai list */
 +              list_add(&cpu_dai->card_list, &card->dai_dev_list);
        }
 -      codec = card->codec;
  
 -      if (platform->probe) {
 -              ret = platform->probe(pdev);
 -              if (ret < 0)
 -                      goto platform_err;
 +      /* probe the CODEC */
 +      if (!codec->probed) {
 +              if (codec->driver->probe) {
 +                      ret = codec->driver->probe(codec);
 +                      if (ret < 0) {
 +                              printk(KERN_ERR "asoc: failed to probe CODEC %s\n",
 +                                              codec->name);
 +                              return ret;
 +                      }
 +              }
 +
 +              soc_init_codec_debugfs(codec);
 +
 +              /* mark codec as probed and add to card codec list */
 +              codec->probed = 1;
 +              list_add(&codec->card_list, &card->codec_dev_list);
        }
  
 -      /* DAPM stream work */
 -      INIT_DELAYED_WORK(&card->delayed_work, close_delayed_work);
 -#ifdef CONFIG_PM
 -      /* deferred resume work */
 -      INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 -#endif
 +      /* probe the platform */
 +      if (!platform->probed) {
 +              if (platform->driver->probe) {
 +                      ret = platform->driver->probe(platform);
 +                      if (ret < 0) {
 +                              printk(KERN_ERR "asoc: failed to probe platform %s\n",
 +                                              platform->name);
 +                              return ret;
 +                      }
 +              }
 +              /* mark platform as probed and add to card platform list */
 +              platform->probed = 1;
 +              list_add(&platform->card_list, &card->platform_dev_list);
 +      }
  
 -      for (i = 0; i < card->num_links; i++) {
 -              if (card->dai_link[i].init) {
 -                      ret = card->dai_link[i].init(codec);
 +      /* probe the CODEC DAI */
 +      if (!codec_dai->probed) {
 +              if (codec_dai->driver->probe) {
 +                      ret = codec_dai->driver->probe(codec_dai);
                        if (ret < 0) {
 -                              printk(KERN_ERR "asoc: failed to init %s\n",
 -                                      card->dai_link[i].stream_name);
 -                              continue;
 +                              printk(KERN_ERR "asoc: failed to probe CODEC DAI %s\n",
 +                                              codec_dai->name);
 +                              return ret;
                        }
                }
 -              if (card->dai_link[i].codec_dai->ac97_control)
 -                      ac97 = 1;
 +
 +              /* mark cpu_dai as probed and add to card cpu_dai list */
 +              codec_dai->probed = 1;
 +              list_add(&codec_dai->card_list, &card->dai_dev_list);
        }
  
 -      snprintf(codec->card->shortname, sizeof(codec->card->shortname),
 -               "%s",  card->name);
 -      snprintf(codec->card->longname, sizeof(codec->card->longname),
 -               "%s (%s)", card->name, codec->name);
 +      /* DAPM dai link stream work */
 +      INIT_DELAYED_WORK(&rtd->delayed_work, close_delayed_work);
 +
 +      /* now that all clients have probed, initialise the DAI link */
 +      if (dai_link->init) {
 +              ret = dai_link->init(rtd);
 +              if (ret < 0) {
 +                      printk(KERN_ERR "asoc: failed to init %s\n", dai_link->stream_name);
 +                      return ret;
 +              }
 +      }
  
        /* Make sure all DAPM widgets are instantiated */
        snd_soc_dapm_new_widgets(codec);
 +      snd_soc_dapm_sync(codec);
  
 -      ret = snd_card_register(codec->card);
 +      /* register the rtd device */
 +      rtd->dev.init_name = rtd->dai_link->stream_name;
 +      rtd->dev.release = rtd_release;
 +      rtd->dev.init_name = dai_link->name;
 +      ret = device_register(&rtd->dev);
        if (ret < 0) {
 -              printk(KERN_ERR "asoc: failed to register soundcard for %s\n",
 -                              codec->name);
 -              goto card_err;
 +              printk(KERN_ERR "asoc: failed to register DAI runtime device %d\n", ret);
 +              return ret;
        }
  
 -      mutex_lock(&codec->mutex);
 +      rtd->dev_registered = 1;
 +      ret = device_create_file(&rtd->dev, &dev_attr_pmdown_time);
 +      if (ret < 0)
 +              printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
 +
 +      /* add DAPM sysfs entries for this codec */
 +      ret = snd_soc_dapm_sys_add(&rtd->dev);
 +      if (ret < 0)
 +              printk(KERN_WARNING "asoc: failed to add codec dapm sysfs entries\n");
 +
 +      /* add codec sysfs entries */
 +      ret = device_create_file(&rtd->dev, &dev_attr_codec_reg);
 +      if (ret < 0)
 +              printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 +
 +      /* create the pcm */
 +      ret = soc_new_pcm(rtd, num);
 +      if (ret < 0) {
 +              printk(KERN_ERR "asoc: can't create pcm %s\n", dai_link->stream_name);
 +              return ret;
 +      }
 +
 +      /* add platform data for AC97 devices */
 +      if (rtd->codec_dai->driver->ac97_control)
 +              snd_ac97_dev_add_pdata(codec->ac97, rtd->cpu_dai->ac97_pdata);
 +
 +      return 0;
 +}
 +
  #ifdef CONFIG_SND_SOC_AC97_BUS
 +static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
 +{
 +      int ret;
 +
        /* Only instantiate AC97 if not already done by the adaptor
         * for the generic AC97 subsystem.
         */
 -      if (ac97 && strcmp(codec->name, "AC97") != 0) {
 -              ret = soc_ac97_dev_register(codec);
 +      if (rtd->codec_dai->driver->ac97_control && !rtd->codec->ac97_registered) {
 +
 +              ret = soc_ac97_dev_register(rtd->codec);
                if (ret < 0) {
                        printk(KERN_ERR "asoc: AC97 device register failed\n");
 -                      snd_card_free(codec->card);
 -                      mutex_unlock(&codec->mutex);
 -                      goto card_err;
 +                      return ret;
                }
 +
 +              rtd->codec->ac97_registered = 1;
 +      }
 +      return 0;
 +}
 +
 +static void soc_unregister_ac97_dai_link(struct snd_soc_codec *codec)
 +{
 +      if (codec->ac97_registered) {
 +              soc_ac97_dev_unregister(codec);
 +              codec->ac97_registered = 0;
        }
 +}
  #endif
  
 -      ret = snd_soc_dapm_sys_add(card->socdev->dev);
 -      if (ret < 0)
 -              printk(KERN_WARNING "asoc: failed to add dapm sysfs entries\n");
 +static void snd_soc_instantiate_card(struct snd_soc_card *card)
 +{
 +      struct platform_device *pdev = to_platform_device(card->dev);
 +      int ret, i;
  
 -      ret = device_create_file(card->socdev->dev, &dev_attr_pmdown_time);
 -      if (ret < 0)
 -              printk(KERN_WARNING "asoc: failed to add pmdown_time sysfs\n");
 +      mutex_lock(&card->mutex);
  
 -      ret = device_create_file(card->socdev->dev, &dev_attr_codec_reg);
 -      if (ret < 0)
 -              printk(KERN_WARNING "asoc: failed to add codec sysfs files\n");
 +      if (card->instantiated) {
 +              mutex_unlock(&card->mutex);
 +              return;
 +      }
  
 -      soc_init_codec_debugfs(codec);
 -      mutex_unlock(&codec->mutex);
 +      /* bind DAIs */
 +      for (i = 0; i < card->num_links; i++)
 +              soc_bind_dai_link(card, i);
  
 -      card->instantiated = 1;
 +      /* bind completed ? */
 +      if (card->num_rtd != card->num_links) {
 +              mutex_unlock(&card->mutex);
 +              return;
 +      }
  
 -      return;
 +      /* card bind complete so register a sound card */
 +      ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
 +                      card->owner, 0, &card->snd_card);
 +      if (ret < 0) {
 +              printk(KERN_ERR "asoc: can't create sound card for card %s\n",
 +                      card->name);
 +              mutex_unlock(&card->mutex);
 +              return;
 +      }
 +      card->snd_card->dev = card->dev;
 +
 +#ifdef CONFIG_PM
 +      /* deferred resume work */
 +      INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
 +#endif
  
 -card_err:
 -      if (platform->remove)
 -              platform->remove(pdev);
 +      /* initialise the sound card only once */
 +      if (card->probe) {
 +              ret = card->probe(pdev);
 +              if (ret < 0)
 +                      goto card_probe_error;
 +      }
  
 -platform_err:
 -      if (codec_dev->remove)
 -              codec_dev->remove(pdev);
 +      for (i = 0; i < card->num_links; i++) {
 +              ret = soc_probe_dai_link(card, i);
 +              if (ret < 0) {
 +                      printk(KERN_ERR "asoc: failed to instanciate card %s\n", card->name);
 +                      goto probe_dai_err;
 +              }
 +      }
  
 -cpu_dai_err:
 -      for (i--; i >= 0; i--) {
 -              struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 -              if (cpu_dai->remove)
 -                      cpu_dai->remove(pdev, cpu_dai);
 +      snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
 +               "%s",  card->name);
 +      snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
 +               "%s", card->name);
 +
 +      ret = snd_card_register(card->snd_card);
 +      if (ret < 0) {
 +              printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
 +              goto probe_dai_err;
        }
  
 +#ifdef CONFIG_SND_SOC_AC97_BUS
 +      /* register any AC97 codecs */
 +      for (i = 0; i < card->num_rtd; i++) {
 +                      ret = soc_register_ac97_dai_link(&card->rtd[i]);
 +                      if (ret < 0) {
 +                              printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
 +                              goto probe_dai_err;
 +                      }
 +              }
 +#endif
 +
 +      card->instantiated = 1;
 +      mutex_unlock(&card->mutex);
 +      return;
 +
 +probe_dai_err:
 +      for (i = 0; i < card->num_links; i++)
 +              soc_remove_dai_link(card, i);
 +
 +card_probe_error:
        if (card->remove)
                card->remove(pdev);
 +
 +      snd_card_free(card->snd_card);
 +
 +      mutex_unlock(&card->mutex);
  }
  
  /*
-  * Attempt to initialise any uninitalised cards.  Must be called with
+  * Attempt to initialise any uninitialised cards.  Must be called with
   * client_mutex.
   */
  static void snd_soc_instantiate_cards(void)
  /* probes a new socdev */
  static int soc_probe(struct platform_device *pdev)
  {
 +      struct snd_soc_card *card = platform_get_drvdata(pdev);
        int ret = 0;
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_card *card = socdev->card;
 -
 -      /* Bodge while we push things out of socdev */
 -      card->socdev = socdev;
  
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
 +      INIT_LIST_HEAD(&card->dai_dev_list);
 +      INIT_LIST_HEAD(&card->codec_dev_list);
 +      INIT_LIST_HEAD(&card->platform_dev_list);
 +
        ret = snd_soc_register_card(card);
        if (ret != 0) {
                dev_err(&pdev->dev, "Failed to register card\n");
  /* removes a socdev */
  static int soc_remove(struct platform_device *pdev)
  {
 +      struct snd_soc_card *card = platform_get_drvdata(pdev);
        int i;
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_codec_device *codec_dev = socdev->codec_dev;
  
 -      if (card->instantiated) {
 -              run_delayed_work(&card->delayed_work);
 -
 -              if (platform->remove)
 -                      platform->remove(pdev);
 -
 -              if (codec_dev->remove)
 -                      codec_dev->remove(pdev);
 +              if (card->instantiated) {
  
 -              for (i = 0; i < card->num_links; i++) {
 -                      struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
 -                      if (cpu_dai->remove)
 -                              cpu_dai->remove(pdev, cpu_dai);
 +              /* make sure any delayed work runs */
 +              for (i = 0; i < card->num_rtd; i++) {
 +                      struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
 +                      run_delayed_work(&rtd->delayed_work);
                }
  
 +              /* remove and free each DAI */
 +              for (i = 0; i < card->num_rtd; i++)
 +                      soc_remove_dai_link(card, i);
 +
 +              /* remove the card */
                if (card->remove)
                        card->remove(pdev);
 -      }
  
 +              kfree(card->rtd);
 +              snd_card_free(card->snd_card);
 +      }
        snd_soc_unregister_card(card);
 -
        return 0;
  }
  
  static int soc_poweroff(struct device *dev)
  {
        struct platform_device *pdev = to_platform_device(dev);
 -      struct snd_soc_device *socdev = platform_get_drvdata(pdev);
 -      struct snd_soc_card *card = socdev->card;
 +      struct snd_soc_card *card = platform_get_drvdata(pdev);
 +      int i;
  
        if (!card->instantiated)
                return 0;
  
        /* Flush out pmdown_time work - we actually do want to run it
         * now, we're shutting down so no imminent restart. */
 -      run_delayed_work(&card->delayed_work);
 +      for (i = 0; i < card->num_rtd; i++) {
 +              struct snd_soc_pcm_runtime *rtd = &card->rtd[i];
 +              run_delayed_work(&rtd->delayed_work);
 +      }
  
 -      snd_soc_dapm_shutdown(socdev);
 +      snd_soc_dapm_shutdown(card);
  
        return 0;
  }
@@@ -1630,42 -1419,53 +1630,42 @@@ static struct platform_driver soc_drive
  };
  
  /* create a new pcm */
 -static int soc_new_pcm(struct snd_soc_device *socdev,
 -      struct snd_soc_dai_link *dai_link, int num)
 -{
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_codec *codec = card->codec;
 -      struct snd_soc_platform *platform = card->platform;
 -      struct snd_soc_dai *codec_dai = dai_link->codec_dai;
 -      struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
 -      struct snd_soc_pcm_runtime *rtd;
 +static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num)
 +{
 +      struct snd_soc_codec *codec = rtd->codec;
 +      struct snd_soc_platform *platform = rtd->platform;
 +      struct snd_soc_dai *codec_dai = rtd->codec_dai;
 +      struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
        struct snd_pcm *pcm;
        char new_name[64];
        int ret = 0, playback = 0, capture = 0;
  
 -      rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL);
 -      if (rtd == NULL)
 -              return -ENOMEM;
 -
 -      rtd->dai = dai_link;
 -      rtd->socdev = socdev;
 -      codec_dai->codec = card->codec;
 -
        /* check client and interface hw capabilities */
        snprintf(new_name, sizeof(new_name), "%s %s-%d",
 -               dai_link->stream_name, codec_dai->name, num);
 +                      rtd->dai_link->stream_name, codec_dai->name, num);
  
 -      if (codec_dai->playback.channels_min)
 +      if (codec_dai->driver->playback.channels_min)
                playback = 1;
 -      if (codec_dai->capture.channels_min)
 +      if (codec_dai->driver->capture.channels_min)
                capture = 1;
  
 -      ret = snd_pcm_new(codec->card, new_name, codec->pcm_devs++, playback,
 -              capture, &pcm);
 +      dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num,new_name);
 +      ret = snd_pcm_new(rtd->card->snd_card, new_name,
 +                      num, playback, capture, &pcm);
        if (ret < 0) {
 -              printk(KERN_ERR "asoc: can't create pcm for codec %s\n",
 -                      codec->name);
 -              kfree(rtd);
 +              printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name);
                return ret;
        }
  
 -      dai_link->pcm = pcm;
 +      rtd->pcm = pcm;
        pcm->private_data = rtd;
 -      soc_pcm_ops.mmap = platform->pcm_ops->mmap;
 -      soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
 -      soc_pcm_ops.copy = platform->pcm_ops->copy;
 -      soc_pcm_ops.silence = platform->pcm_ops->silence;
 -      soc_pcm_ops.ack = platform->pcm_ops->ack;
 -      soc_pcm_ops.page = platform->pcm_ops->page;
 +      soc_pcm_ops.mmap = platform->driver->ops->mmap;
 +      soc_pcm_ops.pointer = platform->driver->ops->pointer;
 +      soc_pcm_ops.ioctl = platform->driver->ops->ioctl;
 +      soc_pcm_ops.copy = platform->driver->ops->copy;
 +      soc_pcm_ops.silence = platform->driver->ops->silence;
 +      soc_pcm_ops.ack = platform->driver->ops->ack;
 +      soc_pcm_ops.page = platform->driver->ops->page;
  
        if (playback)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
        if (capture)
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
  
 -      ret = platform->pcm_new(codec->card, codec_dai, pcm);
 +      ret = platform->driver->pcm_new(rtd->card->snd_card, codec_dai, pcm);
        if (ret < 0) {
                printk(KERN_ERR "asoc: platform pcm constructor failed\n");
 -              kfree(rtd);
                return ret;
        }
  
 -      pcm->private_free = platform->pcm_free;
 +      pcm->private_free = platform->driver->pcm_free;
        printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name,
                cpu_dai->name);
        return ret;
   */
  int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg)
  {
 -      if (codec->volatile_register)
 -              return codec->volatile_register(reg);
 +      if (codec->driver->volatile_register)
 +              return codec->driver->volatile_register(reg);
        else
                return 0;
  }
@@@ -1731,6 -1532,7 +1731,6 @@@ int snd_soc_new_ac97_codec(struct snd_s
  
        codec->ac97->bus->ops = ops;
        codec->ac97->num = num;
 -      codec->dev = &codec->ac97->dev;
        mutex_unlock(&codec->mutex);
        return 0;
  }
@@@ -1745,9 -1547,6 +1745,9 @@@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_code
  void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
  {
        mutex_lock(&codec->mutex);
 +#ifdef CONFIG_SND_SOC_AC97_BUS
 +      soc_unregister_ac97_dai_link(codec);
 +#endif
        kfree(codec->ac97->bus);
        kfree(codec->ac97);
        codec->ac97 = NULL;
@@@ -1833,6 -1632,95 +1833,6 @@@ int snd_soc_test_bits(struct snd_soc_co
  }
  EXPORT_SYMBOL_GPL(snd_soc_test_bits);
  
 -/**
 - * snd_soc_new_pcms - create new sound card and pcms
 - * @socdev: the SoC audio device
 - * @idx: ALSA card index
 - * @xid: card identification
 - *
 - * Create a new sound card based upon the codec and interface pcms.
 - *
 - * Returns 0 for success, else error.
 - */
 -int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid)
 -{
 -      struct snd_soc_card *card = socdev->card;
 -      struct snd_soc_codec *codec = card->codec;
 -      int ret, i;
 -
 -      mutex_lock(&codec->mutex);
 -
 -      /* register a sound card */
 -      ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card);
 -      if (ret < 0) {
 -              printk(KERN_ERR "asoc: can't create sound card for codec %s\n",
 -                      codec->name);
 -              mutex_unlock(&codec->mutex);
 -              return ret;
 -      }
 -
 -      codec->socdev = socdev;
 -      codec->card->dev = socdev->dev;
 -      codec->card->private_data = codec;
 -      strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
 -
 -      /* create the pcms */
 -      for (i = 0; i < card->num_links; i++) {
 -              ret = soc_new_pcm(socdev, &card->dai_link[i], i);
 -              if (ret < 0) {
 -                      printk(KERN_ERR "asoc: can't create pcm %s\n",
 -                              card->dai_link[i].stream_name);
 -                      mutex_unlock(&codec->mutex);
 -                      return ret;
 -              }
 -              /* Check for codec->ac97 to handle the ac97.c fun */
 -              if (card->dai_link[i].codec_dai->ac97_control && codec->ac97) {
 -                      snd_ac97_dev_add_pdata(codec->ac97,
 -                              card->dai_link[i].cpu_dai->ac97_pdata);
 -              }
 -      }
 -
 -      mutex_unlock(&codec->mutex);
 -      return ret;
 -}
 -EXPORT_SYMBOL_GPL(snd_soc_new_pcms);
 -
 -/**
 - * snd_soc_free_pcms - free sound card and pcms
 - * @socdev: the SoC audio device
 - *
 - * Frees sound card and pcms associated with the socdev.
 - * Also unregister the codec if it is an AC97 device.
 - */
 -void snd_soc_free_pcms(struct snd_soc_device *socdev)
 -{
 -      struct snd_soc_codec *codec = socdev->card->codec;
 -#ifdef CONFIG_SND_SOC_AC97_BUS
 -      struct snd_soc_dai *codec_dai;
 -      int i;
 -#endif
 -
 -      mutex_lock(&codec->mutex);
 -      soc_cleanup_codec_debugfs(codec);
 -#ifdef CONFIG_SND_SOC_AC97_BUS
 -      for (i = 0; i < codec->num_dai; i++) {
 -              codec_dai = &codec->dai[i];
 -              if (codec_dai->ac97_control && codec->ac97 &&
 -                  strcmp(codec->name, "AC97") != 0) {
 -                      soc_ac97_dev_unregister(codec);
 -                      goto free_card;
 -              }
 -      }
 -free_card:
 -#endif
 -
 -      if (codec->card)
 -              snd_card_free(codec->card);
 -      device_remove_file(socdev->dev, &dev_attr_codec_reg);
 -      mutex_unlock(&codec->mutex);
 -}
 -EXPORT_SYMBOL_GPL(snd_soc_free_pcms);
 -
  /**
   * snd_soc_set_runtime_hwparams - set the runtime hardware parameters
   * @substream: the pcm substream
@@@ -1894,7 -1782,7 +1894,7 @@@ EXPORT_SYMBOL_GPL(snd_soc_cnew)
  int snd_soc_add_controls(struct snd_soc_codec *codec,
        const struct snd_kcontrol_new *controls, int num_controls)
  {
 -      struct snd_card *card = codec->card;
 +      struct snd_card *card = codec->card->snd_card;
        int err, i;
  
        for (i = 0; i < num_controls; i++) {
@@@ -2449,7 -2337,7 +2449,7 @@@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8)
  int snd_soc_limit_volume(struct snd_soc_codec *codec,
        const char *name, int max)
  {
 -      struct snd_card *card = codec->card;
 +      struct snd_card *card = codec->card->snd_card;
        struct snd_kcontrol *kctl;
        struct soc_mixer_control *mc;
        int found = 0;
@@@ -2581,8 -2469,8 +2581,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_
  int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
        unsigned int freq, int dir)
  {
 -      if (dai->ops && dai->ops->set_sysclk)
 -              return dai->ops->set_sysclk(dai, clk_id, freq, dir);
 +      if (dai->driver && dai->driver->ops->set_sysclk)
 +              return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
        else
                return -EINVAL;
  }
@@@ -2601,8 -2489,8 +2601,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_syscl
  int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
        int div_id, int div)
  {
 -      if (dai->ops && dai->ops->set_clkdiv)
 -              return dai->ops->set_clkdiv(dai, div_id, div);
 +      if (dai->driver && dai->driver->ops->set_clkdiv)
 +              return dai->driver->ops->set_clkdiv(dai, div_id, div);
        else
                return -EINVAL;
  }
@@@ -2621,8 -2509,8 +2621,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdi
  int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
        unsigned int freq_in, unsigned int freq_out)
  {
 -      if (dai->ops && dai->ops->set_pll)
 -              return dai->ops->set_pll(dai, pll_id, source,
 +      if (dai->driver && dai->driver->ops->set_pll)
 +              return dai->driver->ops->set_pll(dai, pll_id, source,
                                         freq_in, freq_out);
        else
                return -EINVAL;
@@@ -2638,8 -2526,8 +2638,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll)
   */
  int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  {
 -      if (dai->ops && dai->ops->set_fmt)
 -              return dai->ops->set_fmt(dai, fmt);
 +      if (dai->driver && dai->driver->ops->set_fmt)
 +              return dai->driver->ops->set_fmt(dai, fmt);
        else
                return -EINVAL;
  }
@@@ -2659,8 -2547,8 +2659,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt)
  int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
  {
 -      if (dai->ops && dai->ops->set_tdm_slot)
 -              return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask,
 +      if (dai->driver && dai->driver->ops->set_tdm_slot)
 +              return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
                                slots, slot_width);
        else
                return -EINVAL;
@@@ -2683,8 -2571,8 +2683,8 @@@ int snd_soc_dai_set_channel_map(struct 
        unsigned int tx_num, unsigned int *tx_slot,
        unsigned int rx_num, unsigned int *rx_slot)
  {
 -      if (dai->ops && dai->ops->set_channel_map)
 -              return dai->ops->set_channel_map(dai, tx_num, tx_slot,
 +      if (dai->driver && dai->driver->ops->set_channel_map)
 +              return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
                        rx_num, rx_slot);
        else
                return -EINVAL;
@@@ -2700,8 -2588,8 +2700,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_chann
   */
  int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
  {
 -      if (dai->ops && dai->ops->set_tristate)
 -              return dai->ops->set_tristate(dai, tristate);
 +      if (dai->driver && dai->driver->ops->set_tristate)
 +              return dai->driver->ops->set_tristate(dai, tristate);
        else
                return -EINVAL;
  }
@@@ -2716,8 -2604,8 +2716,8 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_trist
   */
  int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute)
  {
 -      if (dai->ops && dai->ops->digital_mute)
 -              return dai->ops->digital_mute(dai, mute);
 +      if (dai->driver && dai->driver->ops->digital_mute)
 +              return dai->driver->ops->digital_mute(dai, mute);
        else
                return -EINVAL;
  }
@@@ -2734,22 -2622,11 +2734,22 @@@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_m
   */
  static int snd_soc_register_card(struct snd_soc_card *card)
  {
 +      int i;
 +
        if (!card->name || !card->dev)
                return -EINVAL;
  
 +      card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * card->num_links,
 +                      GFP_KERNEL);
 +      if (card->rtd == NULL)
 +              return -ENOMEM;
 +
 +      for (i = 0; i < card->num_links; i++)
 +              card->rtd[i].dai_link = &card->dai_link[i];
 +
        INIT_LIST_HEAD(&card->list);
        card->instantiated = 0;
 +      mutex_init(&card->mutex);
  
        mutex_lock(&client_mutex);
        list_add(&card->list, &card_list);
@@@ -2775,97 -2652,30 +2775,97 @@@ static int snd_soc_unregister_card(stru
        mutex_lock(&client_mutex);
        list_del(&card->list);
        mutex_unlock(&client_mutex);
 -
        dev_dbg(card->dev, "Unregistered card '%s'\n", card->name);
  
        return 0;
  }
  
 +/*
 + * Simplify DAI link configuration by removing ".-1" from device names
 + * and sanitizing names.
 + */
 +static inline char *fmt_single_name(struct device *dev, int *id)
 +{
 +      char *found, name[NAME_SIZE];
 +      int id1, id2;
 +
 +      if (dev_name(dev) == NULL)
 +              return NULL;
 +
 +      strncpy(name, dev_name(dev), NAME_SIZE);
 +
 +      /* are we a "%s.%d" name (platform and SPI components) */
 +      found = strstr(name, dev->driver->name);
 +      if (found) {
 +              /* get ID */
 +              if (sscanf(&found[strlen(dev->driver->name)], ".%d", id) == 1) {
 +
 +                      /* discard ID from name if ID == -1 */
 +                      if (*id == -1)
 +                              found[strlen(dev->driver->name)] = '\0';
 +              }
 +
 +      } else {
 +              /* I2C component devices are named "bus-addr"  */
 +              if (sscanf(name, "%x-%x", &id1, &id2) == 2) {
 +                      char tmp[NAME_SIZE];
 +
 +                      /* create unique ID number from I2C addr and bus */
 +                      *id = ((id1 && 0xffff) << 16) + id2;
 +
 +                      /* sanitize component name for DAI link creation */
 +                      snprintf(tmp, NAME_SIZE, "%s.%s", dev->driver->name, name);
 +                      strncpy(name, tmp, NAME_SIZE);
 +              } else
 +                      *id = 0;
 +      }
 +
 +      return kstrdup(name, GFP_KERNEL);
 +}
 +
 +/*
 + * Simplify DAI link naming for single devices with multiple DAIs by removing
 + * any ".-1" and using the DAI name (instead of device name).
 + */
 +static inline char *fmt_multiple_name(struct device *dev,
 +              struct snd_soc_dai_driver *dai_drv)
 +{
 +      if (dai_drv->name == NULL) {
 +              printk(KERN_ERR "asoc: error - multiple DAI %s registered with no name\n",
 +                              dev_name(dev));
 +              return NULL;
 +      }
 +
 +      return kstrdup(dai_drv->name, GFP_KERNEL);
 +}
 +
  /**
   * snd_soc_register_dai - Register a DAI with the ASoC core
   *
   * @dai: DAI to register
   */
 -int snd_soc_register_dai(struct snd_soc_dai *dai)
 +int snd_soc_register_dai(struct device *dev,
 +              struct snd_soc_dai_driver *dai_drv)
  {
 -      if (!dai->name)
 -              return -EINVAL;
 +      struct snd_soc_dai *dai;
 +
 +      dev_dbg(dev, "dai register %s\n", dev_name(dev));
  
 -      /* The device should become mandatory over time */
 -      if (!dai->dev)
 -              printk(KERN_WARNING "No device for DAI %s\n", dai->name);
 +      dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
 +      if (dai == NULL)
 +                      return -ENOMEM;
  
 -      if (!dai->ops)
 -              dai->ops = &null_dai_ops;
 +      /* create DAI component name */
 +      dai->name = fmt_single_name(dev, &dai->id);
 +      if (dai->name == NULL) {
 +              kfree(dai);
 +              return -ENOMEM;
 +      }
  
 -      INIT_LIST_HEAD(&dai->list);
 +      dai->dev = dev;
 +      dai->driver = dai_drv;
 +      if (!dai->driver->ops)
 +              dai->driver->ops = &null_dai_ops;
  
        mutex_lock(&client_mutex);
        list_add(&dai->list, &dai_list);
@@@ -2883,24 -2693,13 +2883,24 @@@ EXPORT_SYMBOL_GPL(snd_soc_register_dai)
   *
   * @dai: DAI to unregister
   */
 -void snd_soc_unregister_dai(struct snd_soc_dai *dai)
 +void snd_soc_unregister_dai(struct device *dev)
  {
 +      struct snd_soc_dai *dai;
 +
 +      list_for_each_entry(dai, &dai_list, list) {
 +              if (dev == dai->dev)
 +                      goto found;
 +      }
 +      return;
 +
 +found:
        mutex_lock(&client_mutex);
        list_del(&dai->list);
        mutex_unlock(&client_mutex);
  
        pr_debug("Unregistered DAI '%s'\n", dai->name);
 +      kfree(dai->name);
 +      kfree(dai);
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_dai);
  
   * @dai: Array of DAIs to register
   * @count: Number of DAIs
   */
 -int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count)
 +int snd_soc_register_dais(struct device *dev,
 +              struct snd_soc_dai_driver *dai_drv, size_t count)
  {
 -      int i, ret;
 +      struct snd_soc_dai *dai;
 +      int i, ret = 0;
 +
 +      dev_dbg(dev, "dai register %s #%d\n", dev_name(dev), count);
  
        for (i = 0; i < count; i++) {
 -              ret = snd_soc_register_dai(&dai[i]);
 -              if (ret != 0)
 +
 +              dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);
 +              if (dai == NULL)
 +                      return -ENOMEM;
 +
 +              /* create DAI component name */
 +              dai->name = fmt_multiple_name(dev, &dai_drv[i]);
 +              if (dai->name == NULL) {
 +                      kfree(dai);
 +                      ret = -EINVAL;
                        goto err;
 +              }
 +
 +              dai->dev = dev;
 +              dai->id = i;
 +              dai->driver = &dai_drv[i];
 +              if (!dai->driver->ops)
 +                      dai->driver->ops = &null_dai_ops;
 +
 +              mutex_lock(&client_mutex);
 +              list_add(&dai->list, &dai_list);
 +              mutex_unlock(&client_mutex);
 +
 +              pr_debug("Registered DAI '%s'\n", dai->name);
        }
  
 +      snd_soc_instantiate_cards();
        return 0;
  
  err:
        for (i--; i >= 0; i--)
 -              snd_soc_unregister_dai(&dai[i]);
 +              snd_soc_unregister_dai(dev);
  
        return ret;
  }
@@@ -2962,12 -2735,12 +2962,12 @@@ EXPORT_SYMBOL_GPL(snd_soc_register_dais
   * @dai: Array of DAIs to unregister
   * @count: Number of DAIs
   */
 -void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count)
 +void snd_soc_unregister_dais(struct device *dev, size_t count)
  {
        int i;
  
        for (i = 0; i < count; i++)
 -              snd_soc_unregister_dai(&dai[i]);
 +              snd_soc_unregister_dai(dev);
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
  
   *
   * @platform: platform to register
   */
 -int snd_soc_register_platform(struct snd_soc_platform *platform)
 +int snd_soc_register_platform(struct device *dev,
 +              struct snd_soc_platform_driver *platform_drv)
  {
 -      if (!platform->name)
 -              return -EINVAL;
 +      struct snd_soc_platform *platform;
 +
 +      dev_dbg(dev, "platform register %s\n", dev_name(dev));
 +
 +      platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
 +      if (platform == NULL)
 +                      return -ENOMEM;
 +
 +      /* create platform component name */
 +      platform->name = fmt_single_name(dev, &platform->id);
 +      if (platform->name == NULL) {
 +              kfree(platform);
 +              return -ENOMEM;
 +      }
  
 -      INIT_LIST_HEAD(&platform->list);
 +      platform->dev = dev;
 +      platform->driver = platform_drv;
  
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
@@@ -3013,24 -2772,13 +3013,24 @@@ EXPORT_SYMBOL_GPL(snd_soc_register_plat
   *
   * @platform: platform to unregister
   */
 -void snd_soc_unregister_platform(struct snd_soc_platform *platform)
 +void snd_soc_unregister_platform(struct device *dev)
  {
 +      struct snd_soc_platform *platform;
 +
 +      list_for_each_entry(platform, &platform_list, list) {
 +              if (dev == platform->dev)
 +                      goto found;
 +      }
 +      return;
 +
 +found:
        mutex_lock(&client_mutex);
        list_del(&platform->list);
        mutex_unlock(&client_mutex);
  
        pr_debug("Unregistered platform '%s'\n", platform->name);
 +      kfree(platform->name);
 +      kfree(platform);
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
  
@@@ -3072,78 -2820,32 +3072,78 @@@ static void fixup_codec_formats(struct 
   *
   * @codec: codec to register
   */
 -int snd_soc_register_codec(struct snd_soc_codec *codec)
 +int snd_soc_register_codec(struct device *dev,
 +              struct snd_soc_codec_driver *codec_drv,
 +              struct snd_soc_dai_driver *dai_drv, int num_dai)
  {
 -      int i;
 +      struct snd_soc_codec *codec;
 +      int ret, i;
  
 -      if (!codec->name)
 -              return -EINVAL;
 +      dev_dbg(dev, "codec register %s\n", dev_name(dev));
 +
 +      codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
 +      if (codec == NULL)
 +              return -ENOMEM;
  
 -      /* The device should become mandatory over time */
 -      if (!codec->dev)
 -              printk(KERN_WARNING "No device for codec %s\n", codec->name);
 +      /* create CODEC component name */
 +      codec->name = fmt_single_name(dev, &codec->id);
 +      if (codec->name == NULL) {
 +              kfree(codec);
 +              return -ENOMEM;
 +      }
 +
 +      /* allocate CODEC register cache */
 +      if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
  
 -      INIT_LIST_HEAD(&codec->list);
 +              if (codec_drv->reg_cache_default)
 +                      codec->reg_cache = kmemdup(codec_drv->reg_cache_default,
 +                              codec_drv->reg_cache_size * codec_drv->reg_word_size, GFP_KERNEL);
 +              else
 +                      codec->reg_cache = kzalloc(codec_drv->reg_cache_size *
 +                              codec_drv->reg_word_size, GFP_KERNEL);
  
 -      for (i = 0; i < codec->num_dai; i++) {
 -              fixup_codec_formats(&codec->dai[i].playback);
 -              fixup_codec_formats(&codec->dai[i].capture);
 +              if (codec->reg_cache == NULL) {
 +                      kfree(codec->name);
 +                      kfree(codec);
 +                      return -ENOMEM;
 +              }
        }
  
 +      codec->dev = dev;
 +      codec->driver = codec_drv;
 +      codec->bias_level = SND_SOC_BIAS_OFF;
 +      codec->num_dai = num_dai;
 +      mutex_init(&codec->mutex);
 +      INIT_LIST_HEAD(&codec->dapm_widgets);
 +      INIT_LIST_HEAD(&codec->dapm_paths);
 +
 +      for (i = 0; i < num_dai; i++) {
 +              fixup_codec_formats(&dai_drv[i].playback);
 +              fixup_codec_formats(&dai_drv[i].capture);
 +      }
 +
 +      /* register DAIs */
 +      ret = snd_soc_register_dais(dev, dai_drv, num_dai);
 +      if (ret < 0)
 +                      goto error;
 +
        mutex_lock(&client_mutex);
        list_add(&codec->list, &codec_list);
        snd_soc_instantiate_cards();
        mutex_unlock(&client_mutex);
  
        pr_debug("Registered codec '%s'\n", codec->name);
 -
        return 0;
 +
 +error:
 +      for (i--; i >= 0; i--)
 +              snd_soc_unregister_dai(dev);
 +
 +      if (codec->reg_cache)
 +              kfree(codec->reg_cache);
 +      kfree(codec->name);
 +      kfree(codec);
 +      return ret;
  }
  EXPORT_SYMBOL_GPL(snd_soc_register_codec);
  
   *
   * @codec: codec to unregister
   */
 -void snd_soc_unregister_codec(struct snd_soc_codec *codec)
 +void snd_soc_unregister_codec(struct device *dev)
  {
 +      struct snd_soc_codec *codec;
 +      int i;
 +
 +      list_for_each_entry(codec, &codec_list, list) {
 +              if (dev == codec->dev)
 +                      goto found;
 +      }
 +      return;
 +
 +found:
 +      for (i = 0; i < codec->num_dai; i++)
 +              snd_soc_unregister_dai(dev);
 +
        mutex_lock(&client_mutex);
        list_del(&codec->list);
        mutex_unlock(&client_mutex);
  
        pr_debug("Unregistered codec '%s'\n", codec->name);
 +
 +      if (codec->reg_cache)
 +              kfree(codec->reg_cache);
 +      kfree(codec);
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);