Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Oct 2010 15:32:05 +0000 (08:32 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 25 Oct 2010 15:32:05 +0000 (08:32 -0700)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (365 commits)
  ALSA: hda - Disable sticky PCM stream assignment for AD codecs
  ALSA: usb - Creative USB X-Fi volume knob support
  ALSA: ca0106: Use card specific dac id for mute controls.
  ALSA: ca0106: Allow different sound cards to use different SPI channel mappings.
  ALSA: ca0106: Create a nice spot for mapping channels to dacs.
  ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence.
  ALSA: ca0106: Pull out dac powering routine into separate function.
  ALSA: ca0106 - add Sound Blaster 5.1vx info.
  ASoC: tlv320dac33: Use usleep_range for delays
  ALSA: usb-audio: add Novation Launchpad support
  ALSA: hda - Add workarounds for CT-IBG controllers
  ALSA: hda - Fix wrong TLV mute bit for STAC/IDT codecs
  ASoC: tpa6130a2: Error handling for broken chip
  ASoC: max98088: Staticise m98088_eq_band
  ASoC: soc-core: Fix codec->name memory leak
  ALSA: hda - Apply ideapad quirk to Acer laptops with Cxt5066
  ALSA: hda - Add some workarounds for Creative IBG
  ALSA: hda - Fix wrong SPDIF NID assignment for CA0110
  ALSA: hda - Fix codec rename rules for ALC662-compatible codecs
  ALSA: hda - Add alc_init_jacks() call to other codecs
  ...

19 files changed:
1  2 
arch/arm/mach-ep93xx/simone.c
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/board-zoom-peripherals.c
arch/arm/mach-omap2/board-zoom2.c
arch/arm/mach-omap2/devices.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/devices.h
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/zylonite.c
arch/arm/mach-s3c64xx/mach-smdk6410.c
arch/arm/plat-samsung/include/plat/devs.h
arch/powerpc/platforms/85xx/p1022_ds.c
drivers/video/Kconfig
include/sound/core.h
sound/core/init.c
sound/oss/msnd_pinnacle.c
sound/soc/sh/siu_pcm.c
sound/soc/soc-core.c
sound/soc/soc-dapm.c

index f22ce8db7947b616f7f45cf7fe6cf7eeebec62f2,f5f81f9719bd37d49d8db4b060e0e42407f1e122..d96dc1c5da20a26c0f3b4017d2411d16ceacadd7
@@@ -61,10 -61,13 +61,11 @@@ static void __init simone_init_machine(
        ep93xx_register_fb(&simone_fb_info);
        ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
                            ARRAY_SIZE(simone_i2c_board_info));
+       ep93xx_register_ac97();
  }
  
  MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
  /* Maintainer: Ryan Mallon <ryan@bluewatersys.com> */
 -      .phys_io        = EP93XX_APB_PHYS_BASE,
 -      .io_pg_offst    = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
        .boot_params    = EP93XX_SDCE0_PHYS_BASE + 0x100,
        .map_io         = ep93xx_map_io,
        .init_irq       = ep93xx_init_irq,
index ce28a851dcd3f06f954ccd64a03e72c30e229854,11ce4b24befdc76aa441ede512542cc57e82f589..63d786bccb67f60f9f9366b690de20f928236b59
@@@ -14,7 -14,7 +14,7 @@@
  #include <linux/input.h>
  #include <linux/input/matrix_keypad.h>
  #include <linux/spi/spi.h>
 -#include <linux/spi/wl12xx.h>
 +#include <linux/wl12xx.h>
  #include <linux/i2c.h>
  #include <linux/i2c/twl.h>
  #include <linux/clk.h>
@@@ -23,6 -23,7 +23,7 @@@
  #include <linux/gpio.h>
  #include <linux/gpio_keys.h>
  #include <linux/mmc/host.h>
+ #include <sound/tlv320aic3x.h>
  
  #include <plat/mcspi.h>
  #include <plat/board.h>
@@@ -689,7 -690,6 +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,
@@@ -728,6 -724,17 +724,17 @@@ static struct i2c_board_info __initdat
        },
  };
  
+ /* 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),
index 189a6d1600b208ef448ea210139d2d3faa056e29,3c6530475710a890aaf47a5768d2bfa292030dd1..bc8232845d7ade22e219b4c4ddf01ef08acf24df
@@@ -16,8 -16,6 +16,8 @@@
  #include <linux/gpio.h>
  #include <linux/i2c/twl.h>
  #include <linux/regulator/machine.h>
 +#include <linux/regulator/fixed.h>
 +#include <linux/wl12xx.h>
  
  #include <asm/mach-types.h>
  #include <asm/mach/arch.h>
  #include <plat/common.h>
  #include <plat/usb.h>
  
+ #include <mach/board-zoom.h>
  #include "mux.h"
  #include "hsmmc.h"
  
 +#define OMAP_ZOOM_WLAN_PMENA_GPIO     (101)
 +#define OMAP_ZOOM_WLAN_IRQ_GPIO               (162)
 +
  /* Zoom2 has Qwerty keyboard*/
  static int board_keymap[] = {
        KEY(0, 0, KEY_E),
@@@ -111,11 -108,6 +113,11 @@@ static struct regulator_consumer_suppl
        .supply         = "vmmc",
  };
  
 +static struct regulator_consumer_supply zoom_vmmc3_supply = {
 +      .supply         = "vmmc",
 +      .dev_name       = "mmci-omap-hs.2",
 +};
 +
  /* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
  static struct regulator_init_data zoom_vmmc1 = {
        .constraints = {
@@@ -161,38 -153,6 +163,38 @@@ static struct regulator_init_data zoom_
        .consumer_supplies      = &zoom_vsim_supply,
  };
  
 +static struct regulator_init_data zoom_vmmc3 = {
 +      .constraints = {
 +              .valid_ops_mask = REGULATOR_CHANGE_STATUS,
 +      },
 +      .num_consumer_supplies  = 1,
 +      .consumer_supplies = &zoom_vmmc3_supply,
 +};
 +
 +static struct fixed_voltage_config zoom_vwlan = {
 +      .supply_name            = "vwl1271",
 +      .microvolts             = 1800000, /* 1.8V */
 +      .gpio                   = OMAP_ZOOM_WLAN_PMENA_GPIO,
 +      .startup_delay          = 70000, /* 70msec */
 +      .enable_high            = 1,
 +      .enabled_at_boot        = 0,
 +      .init_data              = &zoom_vmmc3,
 +};
 +
 +static struct platform_device omap_vwlan_device = {
 +      .name           = "reg-fixed-voltage",
 +      .id             = 1,
 +      .dev = {
 +              .platform_data  = &zoom_vwlan,
 +      },
 +};
 +
 +struct wl12xx_platform_data omap_zoom_wlan_data __initdata = {
 +      .irq = OMAP_GPIO_IRQ(OMAP_ZOOM_WLAN_IRQ_GPIO),
 +      /* ZOOM ref clock is 26 MHz */
 +      .board_ref_clock = 1,
 +};
 +
  static struct omap2_hsmmc_info mmc[] __initdata = {
        {
                .name           = "external",
                .nonremovable   = true,
                .power_saving   = true,
        },
 +      {
 +              .name           = "wl1271",
 +              .mmc            = 3,
 +              .caps           = MMC_CAP_4_BIT_DATA,
 +              .gpio_wp        = -EINVAL,
 +              .gpio_cd        = -EINVAL,
 +              .nonremovable   = true,
 +      },
        {}      /* Terminator */
  };
  
@@@ -238,6 -190,11 +240,11 @@@ static int zoom_twl_gpio_setup(struct d
        return 0;
  }
  
+ /* EXTMUTE callback function */
+ void zoom2_set_hs_extmute(int mute)
+ {
+       gpio_set_value(ZOOM2_HEADSET_EXTMUTE_GPIO, mute);
+ }
  
  static int zoom_batt_table[] = {
  /* 0 C*/
@@@ -307,6 -264,11 +314,11 @@@ static struct i2c_board_info __initdat
  
  static int __init omap_i2c_init(void)
  {
+       if (machine_is_omap_zoom2()) {
+               zoom_audio_data.ramp_delay_value = 3;   /* 161 ms */
+               zoom_audio_data.hs_extmute = 1;
+               zoom_audio_data.set_hs_extmute = zoom2_set_hs_extmute;
+       }
        omap_register_i2c_bus(1, 2400, zoom_i2c_boardinfo,
                        ARRAY_SIZE(zoom_i2c_boardinfo));
        omap_register_i2c_bus(2, 400, NULL, 0);
@@@ -329,11 -291,7 +341,11 @@@ static void enable_board_wakeup_source(
  
  void __init zoom_peripherals_init(void)
  {
 +      if (wl12xx_set_platform_data(&omap_zoom_wlan_data))
 +              pr_err("error setting wl12xx data\n");
 +
        omap_i2c_init();
 +      platform_device_register(&omap_vwlan_device);
        usb_musb_init(&musb_board_data);
        enable_board_wakeup_source();
  }
index 24bbd0def64ff4b3e6617dc01910c491a7b557c8,00c8f835649faee64e9f8e70bc8fe7e88d67fd6a..4ccbc32386a079acf5202ee75a98c078f010702c
@@@ -14,6 -14,7 +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>
@@@ -34,41 -35,6 +35,6 @@@ static void __init omap_zoom2_init_irq(
        omap_gpio_init();
  }
  
- /* REVISIT: These audio entries can be removed once MFD code is merged */
- #if 0
- static struct twl4030_madc_platform_data zoom2_madc_data = {
-       .irq_line       = 1,
- };
- static struct twl4030_codec_audio_data zoom2_audio_data = {
-       .audio_mclk = 26000000,
- };
- static struct twl4030_codec_data zoom2_codec_data = {
-       .audio_mclk = 26000000,
-       .audio = &zoom2_audio_data,
- };
- static struct twl4030_platform_data zoom2_twldata = {
-       .irq_base       = TWL4030_IRQ_BASE,
-       .irq_end        = TWL4030_IRQ_END,
-       /* platform_data for children goes here */
-       .bci            = &zoom2_bci_data,
-       .madc           = &zoom2_madc_data,
-       .usb            = &zoom2_usb_data,
-       .gpio           = &zoom2_gpio_data,
-       .keypad         = &zoom2_kp_twl4030_data,
-       .codec          = &zoom2_codec_data,
-       .vmmc1          = &zoom2_vmmc1,
-       .vmmc2          = &zoom2_vmmc2,
-       .vsim           = &zoom2_vsim,
- };
- #endif
  #ifdef CONFIG_OMAP_MUX
  static struct omap_board_mux board_mux[] __initdata = {
        /* WLAN IRQ - GPIO 162 */
@@@ -141,6 -107,8 +107,6 @@@ static void __init omap_zoom2_init(void
  }
  
  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         = omap3_map_io,
        .reserve        = omap_reserve,
index b27e7cbb3f2936187692b0dcc8066477afd68ba5,512ae4696a6c319b3875c4ae4286387210a5d352..c5cf1ba08a6f525732c9e76b4e5b109a1b495aca
@@@ -25,6 -25,7 +25,7 @@@
  #include <plat/control.h>
  #include <plat/tc.h>
  #include <plat/board.h>
+ #include <plat/mcbsp.h>
  #include <mach/gpio.h>
  #include <plat/mmc.h>
  #include <plat/dma.h>
@@@ -235,6 -236,43 +236,43 @@@ static inline void omap_init_mbox(void
  
  static inline void omap_init_sti(void) {}
  
+ #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>
@@@ -498,76 -536,6 +536,76 @@@ static void omap_init_sham(void
  static inline void omap_init_sham(void) { }
  #endif
  
 +#if defined(CONFIG_CRYPTO_DEV_OMAP_AES) || defined(CONFIG_CRYPTO_DEV_OMAP_AES_MODULE)
 +
 +#ifdef CONFIG_ARCH_OMAP24XX
 +static struct resource omap2_aes_resources[] = {
 +      {
 +              .start  = OMAP24XX_SEC_AES_BASE,
 +              .end    = OMAP24XX_SEC_AES_BASE + 0x4C,
 +              .flags  = IORESOURCE_MEM,
 +      },
 +      {
 +              .start  = OMAP24XX_DMA_AES_TX,
 +              .flags  = IORESOURCE_DMA,
 +      },
 +      {
 +              .start  = OMAP24XX_DMA_AES_RX,
 +              .flags  = IORESOURCE_DMA,
 +      }
 +};
 +static int omap2_aes_resources_sz = ARRAY_SIZE(omap2_aes_resources);
 +#else
 +#define omap2_aes_resources           NULL
 +#define omap2_aes_resources_sz                0
 +#endif
 +
 +#ifdef CONFIG_ARCH_OMAP34XX
 +static struct resource omap3_aes_resources[] = {
 +      {
 +              .start  = OMAP34XX_SEC_AES_BASE,
 +              .end    = OMAP34XX_SEC_AES_BASE + 0x4C,
 +              .flags  = IORESOURCE_MEM,
 +      },
 +      {
 +              .start  = OMAP34XX_DMA_AES2_TX,
 +              .flags  = IORESOURCE_DMA,
 +      },
 +      {
 +              .start  = OMAP34XX_DMA_AES2_RX,
 +              .flags  = IORESOURCE_DMA,
 +      }
 +};
 +static int omap3_aes_resources_sz = ARRAY_SIZE(omap3_aes_resources);
 +#else
 +#define omap3_aes_resources           NULL
 +#define omap3_aes_resources_sz                0
 +#endif
 +
 +static struct platform_device aes_device = {
 +      .name           = "omap-aes",
 +      .id             = -1,
 +};
 +
 +static void omap_init_aes(void)
 +{
 +      if (cpu_is_omap24xx()) {
 +              aes_device.resource = omap2_aes_resources;
 +              aes_device.num_resources = omap2_aes_resources_sz;
 +      } else if (cpu_is_omap34xx()) {
 +              aes_device.resource = omap3_aes_resources;
 +              aes_device.num_resources = omap3_aes_resources_sz;
 +      } else {
 +              pr_err("%s: platform not supported\n", __func__);
 +              return;
 +      }
 +      platform_device_register(&aes_device);
 +}
 +
 +#else
 +static inline void omap_init_aes(void) { }
 +#endif
 +
  /*-------------------------------------------------------------------------*/
  
  #if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
@@@ -917,6 -885,7 +955,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();
        omap_hdq_init();
        omap_init_sti();
        omap_init_sham();
 +      omap_init_aes();
        omap_init_vout();
  
        return 0;
index 08b410343870ae2518afb4303110d5807dfc12d1,6d845446ce26927b3ac5ecc5ae0665d15d5e2f2e..aaa1166df9640a925e50c822cd3ddd777080b4d6
@@@ -6,12 -6,11 +6,12 @@@
  
  #include <asm/pmu.h>
  #include <mach/udc.h>
 +#include <mach/pxa3xx-u2d.h>
  #include <mach/pxafb.h>
  #include <mach/mmc.h>
  #include <mach/irda.h>
  #include <mach/ohci.h>
 -#include <mach/pxa27x_keypad.h>
 +#include <plat/pxa27x_keypad.h>
  #include <mach/pxa2xx_spi.h>
  #include <mach/camera.h>
  #include <mach/audio.h>
@@@ -135,33 -134,6 +135,33 @@@ struct platform_device pxa27x_device_ud
        }
  };
  
 +#ifdef CONFIG_PXA3xx
 +static struct resource pxa3xx_u2d_resources[] = {
 +      [0] = {
 +              .start  = 0x54100000,
 +              .end    = 0x54100fff,
 +              .flags  = IORESOURCE_MEM,
 +      },
 +      [1] = {
 +              .start  = IRQ_USB2,
 +              .end    = IRQ_USB2,
 +              .flags  = IORESOURCE_IRQ,
 +      },
 +};
 +
 +struct platform_device pxa3xx_device_u2d = {
 +      .name           = "pxa3xx-u2d",
 +      .id             = -1,
 +      .resource       = pxa3xx_u2d_resources,
 +      .num_resources  = ARRAY_SIZE(pxa3xx_u2d_resources),
 +};
 +
 +void __init pxa3xx_set_u2d_info(struct pxa3xx_u2d_platform_data *info)
 +{
 +      pxa_register_device(&pxa3xx_device_u2d, info);
 +}
 +#endif /* CONFIG_PXA3xx */
 +
  static struct resource pxafb_resources[] = {
        [0] = {
                .start  = 0x44000000,
@@@ -382,6 -354,31 +382,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 = {
index 715e8bd02e248930e449c4e6c2c169054c837c6e,491a27a92735471716f91b57f6d98b9c7d4745dc..2fd5a8b35757ac5463303b278d3970d7d4df9d02
@@@ -4,7 -4,6 +4,7 @@@ extern struct platform_device pxa3xx_de
  extern struct platform_device pxa3xx_device_mci3;
  extern struct platform_device pxa25x_device_udc;
  extern struct platform_device pxa27x_device_udc;
 +extern struct platform_device pxa3xx_device_u2d;
  extern struct platform_device pxa_device_fb;
  extern struct platform_device pxa_device_ffuart;
  extern struct platform_device pxa_device_btuart;
@@@ -39,4 -38,10 +39,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);
index c85c3a7abd314f84cce570a79d4f38ecce21ecce,90974e6fae6a69458a91b4bc82f281baa5f3b003..d1c747cdacf879f32f947c54795e86ba06435efc
@@@ -98,6 -98,23 +98,6 @@@ unsigned int pxa3xx_get_clk_frequency_k
        return CLK / 1000;
  }
  
 -/*
 - * Return the current static memory controller clock frequency
 - * in units of 10kHz
 - */
 -unsigned int pxa3xx_get_memclk_frequency_10khz(void)
 -{
 -      unsigned long acsr;
 -      unsigned int smcfs, clk = 0;
 -
 -      acsr = ACSR;
 -
 -      smcfs = (acsr >> 23) & 0x7;
 -      clk = (acsr & ACCR_D0CS) ? RO_CLK : smcfs_mult[smcfs] * BASE_CLK;
 -
 -      return (clk / 10000);
 -}
 -
  void pxa3xx_clear_reset_status(unsigned int mask)
  {
        /* RESET_STATUS_* has a 1:1 mapping with ARSR */
@@@ -248,7 -265,7 +248,7 @@@ static struct clk_lookup pxa3xx_clkregs
        INIT_CLKREG(&clk_pxa3xx_i2c, "pxa2xx-i2c.0", NULL),
        INIT_CLKREG(&clk_pxa3xx_udc, "pxa27x-udc", NULL),
        INIT_CLKREG(&clk_pxa3xx_usbh, "pxa27x-ohci", NULL),
 -      INIT_CLKREG(&clk_pxa3xx_u2d, NULL, "U2DCLK"),
 +      INIT_CLKREG(&clk_pxa3xx_u2d, "pxa3xx-u2d", NULL),
        INIT_CLKREG(&clk_pxa3xx_keypad, "pxa27x-keypad", NULL),
        INIT_CLKREG(&clk_pxa3xx_ssp1, "pxa27x-ssp.0", NULL),
        INIT_CLKREG(&clk_pxa3xx_ssp2, "pxa27x-ssp.1", NULL),
@@@ -593,6 -610,11 +593,11 @@@ static struct platform_device *devices[
        &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,
index f25fb6245bd787bc93636163b241f8fefe9f0210,5ba9d99a1bf6c5c33032686f9d64c05777e27d29..702f7a68e87d593f18bb60ef54091cec561726c1
@@@ -30,7 -30,7 +30,7 @@@
  #include <mach/zylonite.h>
  #include <mach/mmc.h>
  #include <mach/ohci.h>
 -#include <mach/pxa27x_keypad.h>
 +#include <plat/pxa27x_keypad.h>
  #include <plat/pxa3xx_nand.h>
  
  #include "devices.h"
@@@ -45,6 -45,16 +45,16 @@@ int wm9713_irq
  int lcd_id;
  int lcd_orientation;
  
+ struct platform_device pxa_device_wm9713_audio = {
+       .name           = "wm9713-codec",
+       .id             = -1,
+ };
+ static void __init zylonite_init_wm9713_audio(void)
+ {
+       platform_device_register(&pxa_device_wm9713_audio);
+ }
  static struct resource smc91x_resources[] = {
        [0] = {
                .start  = ZYLONITE_ETH_PHYS + 0x300,
@@@ -408,12 -418,14 +418,13 @@@ static void __init zylonite_init(void
        zylonite_init_nand();
        zylonite_init_leds();
        zylonite_init_ohci();
+       zylonite_init_wm9713_audio();
  }
  
  MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
 -      .phys_io        = 0x40000000,
        .boot_params    = 0xa0000100,
 -      .io_pg_offst    = (io_p2v(0x40000000) >> 18) & 0xfffc,
        .map_io         = pxa_map_io,
 +      .nr_irqs        = ZYLONITE_NR_IRQS,
        .init_irq       = pxa3xx_init_irq,
        .timer          = &pxa_timer,
        .init_machine   = zylonite_init,
index ec8865c03a1965d0ae51c7f64251fd8e0a08beae,ecbddd377cb88b583b483efeb7b97830d5fd2f1d..77488facfe4cab45ad9c8c9ea996e06138ec0074
@@@ -283,6 -283,7 +283,7 @@@ static struct platform_device *smdk6410
        &s3c_device_fb,
        &s3c_device_ohci,
        &s3c_device_usb_hsotg,
+       &s3c_device_pcm,
        &s3c64xx_device_iisv4,
        &samsung_device_keypad,
  
@@@ -704,6 -705,8 +705,6 @@@ static void __init smdk6410_machine_ini
  
  MACHINE_START(SMDK6410, "SMDK6410")
        /* Maintainer: Ben Dooks <ben-linux@fluff.org> */
 -      .phys_io        = S3C_PA_UART & 0xfff00000,
 -      .io_pg_offst    = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
        .boot_params    = S3C64XX_PA_SDRAM + 0x100,
  
        .init_irq       = s3c6410_init_irq,
index 7d448e13879241c8a62da6f26604ea00ecc1a3d1,a9fecd615de4235f434c758f8de0e526d042d264..c8b94279bad101037553659e73a4886aa44148bb
@@@ -32,6 -32,8 +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;
  
@@@ -67,15 -69,13 +69,15 @@@ extern struct platform_device s5pv210_d
  extern struct platform_device s5pv210_device_spi1;
  extern struct platform_device s5p6440_device_spi0;
  extern struct platform_device s5p6440_device_spi1;
 +extern struct platform_device s5p6450_device_spi0;
 +extern struct platform_device s5p6450_device_spi1;
  
  extern struct platform_device s3c_device_hwmon;
  
  extern struct platform_device s3c_device_nand;
  extern struct platform_device s3c_device_onenand;
  extern struct platform_device s3c64xx_device_onenand1;
 -extern struct platform_device s5pc110_device_onenand;
 +extern struct platform_device s5p_device_onenand;
  
  extern struct platform_device s3c_device_usbgadget;
  extern struct platform_device s3c_device_usb_hsotg;
@@@ -97,9 -97,6 +99,9 @@@ extern struct platform_device s5p6442_d
  extern struct platform_device s5p6440_device_pcm;
  extern struct platform_device s5p6440_device_iis;
  
 +extern struct platform_device s5p6450_device_iis0;
 +extern struct platform_device s5p6450_device_pcm0;
 +
  extern struct platform_device s5pc100_device_ac97;
  extern struct platform_device s5pc100_device_pcm0;
  extern struct platform_device s5pc100_device_pcm1;
index 2b390d19a1d179bfd1d1c0d58498f693ed1f4c27,e15afdf123432b01bd2d51abc8a857cc26c2d7f5..7eb5c40c069fafb296b436c99241b721be33895f
@@@ -8,7 -8,6 +8,6 @@@
   * Copyright 2010 Freescale Semiconductor, Inc.
   *
   * This file is taken from the Freescale P1022DS BSP, with modifications:
-  * 1) No DIU support (pending rewrite of DIU code)
   * 2) No AMP support
   * 3) No PCI endpoint support
   *
  #include <linux/pci.h>
  #include <linux/of_platform.h>
  #include <linux/memblock.h>
+ #include <asm/div64.h>
  #include <asm/mpic.h>
  #include <asm/swiotlb.h>
  
  #include <sysdev/fsl_soc.h>
  #include <sysdev/fsl_pci.h>
+ #include <asm/fsl_guts.h>
+ #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+ /*
+  * Board-specific initialization of the DIU.  This code should probably be
+  * executed when the DIU is opened, rather than in arch code, but the DIU
+  * driver does not have a mechanism for this (yet).
+  *
+  * This is especially problematic on the P1022DS because the local bus (eLBC)
+  * and the DIU video signals share the same pins, which means that enabling the
+  * DIU will disable access to NOR flash.
+  */
+ /* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+ #define CLKDVDR_PXCKEN                0x80000000
+ #define CLKDVDR_PXCKINV               0x10000000
+ #define CLKDVDR_PXCKDLY               0x06000000
+ #define CLKDVDR_PXCLK_MASK    0x00FF0000
+ /* Some ngPIXIS register definitions */
+ #define PX_BRDCFG1_DVIEN      0x80
+ #define PX_BRDCFG1_DFPEN      0x40
+ #define PX_BRDCFG1_BACKLIGHT  0x20
+ #define PX_BRDCFG1_DDCEN      0x10
+ /*
+  * DIU Area Descriptor
+  *
+  * Note that we need to byte-swap the value before it's written to the AD
+  * register.  So even though the registers don't look like they're in the same
+  * bit positions as they are on the MPC8610, the same value is written to the
+  * AD register on the MPC8610 and on the P1022.
+  */
+ #define AD_BYTE_F             0x10000000
+ #define AD_ALPHA_C_MASK               0x0E000000
+ #define AD_ALPHA_C_SHIFT      25
+ #define AD_BLUE_C_MASK                0x01800000
+ #define AD_BLUE_C_SHIFT               23
+ #define AD_GREEN_C_MASK               0x00600000
+ #define AD_GREEN_C_SHIFT      21
+ #define AD_RED_C_MASK         0x00180000
+ #define AD_RED_C_SHIFT                19
+ #define AD_PALETTE            0x00040000
+ #define AD_PIXEL_S_MASK               0x00030000
+ #define AD_PIXEL_S_SHIFT      16
+ #define AD_COMP_3_MASK                0x0000F000
+ #define AD_COMP_3_SHIFT               12
+ #define AD_COMP_2_MASK                0x00000F00
+ #define AD_COMP_2_SHIFT               8
+ #define AD_COMP_1_MASK                0x000000F0
+ #define AD_COMP_1_SHIFT               4
+ #define AD_COMP_0_MASK                0x0000000F
+ #define AD_COMP_0_SHIFT               0
+ #define MAKE_AD(alpha, red, blue, green, size, c0, c1, c2, c3) \
+       cpu_to_le32(AD_BYTE_F | (alpha << AD_ALPHA_C_SHIFT) | \
+       (blue << AD_BLUE_C_SHIFT) | (green << AD_GREEN_C_SHIFT) | \
+       (red << AD_RED_C_SHIFT) | (c3 << AD_COMP_3_SHIFT) | \
+       (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
+       (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
+ /**
+  * p1022ds_get_pixel_format: return the Area Descriptor for a given pixel depth
+  *
+  * The Area Descriptor is a 32-bit value that determine which bits in each
+  * pixel are to be used for each color.
+  */
+ static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
+       int monitor_port)
+ {
+       switch (bits_per_pixel) {
+       case 32:
+               /* 0x88883316 */
+               return MAKE_AD(3, 2, 0, 1, 3, 8, 8, 8, 8);
+       case 24:
+               /* 0x88082219 */
+               return MAKE_AD(4, 0, 1, 2, 2, 0, 8, 8, 8);
+       case 16:
+               /* 0x65053118 */
+               return MAKE_AD(4, 2, 1, 0, 1, 5, 6, 5, 0);
+       default:
+               pr_err("fsl-diu: unsupported pixel depth %u\n", bits_per_pixel);
+               return 0;
+       }
+ }
+ /**
+  * p1022ds_set_gamma_table: update the gamma table, if necessary
+  *
+  * On some boards, the gamma table for some ports may need to be modified.
+  * This is not the case on the P1022DS, so we do nothing.
+ */
+ static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
+ {
+ }
+ /**
+  * p1022ds_set_monitor_port: switch the output to a different monitor port
+  *
+  */
+ static void p1022ds_set_monitor_port(int monitor_port)
+ {
+       struct device_node *pixis_node;
+       u8 __iomem *brdcfg1;
+       pixis_node = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis");
+       if (!pixis_node) {
+               pr_err("p1022ds: missing ngPIXIS node\n");
+               return;
+       }
+       brdcfg1 = of_iomap(pixis_node, 0);
+       if (!brdcfg1) {
+               pr_err("p1022ds: could not map ngPIXIS registers\n");
+               return;
+       }
+       brdcfg1 += 9;   /* BRDCFG1 is at offset 9 in the ngPIXIS */
+       switch (monitor_port) {
+       case 0: /* DVI */
+               /* Enable the DVI port, disable the DFP and the backlight */
+               clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
+                            PX_BRDCFG1_DVIEN);
+               break;
+       case 1: /* Single link LVDS */
+               /* Enable the DFP port, disable the DVI and the backlight */
+               clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
+                            PX_BRDCFG1_DFPEN);
+               break;
+       default:
+               pr_err("p1022ds: unsupported monitor port %i\n", monitor_port);
+       }
+ }
+ /**
+  * p1022ds_set_pixel_clock: program the DIU's clock
+  *
+  * @pixclock: the wavelength, in picoseconds, of the clock
+  */
+ void p1022ds_set_pixel_clock(unsigned int pixclock)
+ {
+       struct device_node *guts_np = NULL;
+       struct ccsr_guts_85xx __iomem *guts;
+       unsigned long freq;
+       u64 temp;
+       u32 pxclk;
+       /* Map the global utilities registers. */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (!guts_np) {
+               pr_err("p1022ds: missing global utilties device node\n");
+               return;
+       }
+       guts = of_iomap(guts_np, 0);
+       of_node_put(guts_np);
+       if (!guts) {
+               pr_err("p1022ds: could not map global utilties device\n");
+               return;
+       }
+       /* Convert pixclock from a wavelength to a frequency */
+       temp = 1000000000000ULL;
+       do_div(temp, pixclock);
+       freq = temp;
+       /* pixclk is the ratio of the platform clock to the pixel clock */
+       pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+       /* Disable the pixel clock, and set it to non-inverted and no delay */
+       clrbits32(&guts->clkdvdr,
+                 CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+       /* Enable the clock and set the pxclk */
+       setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+ }
+ /**
+  * p1022ds_show_monitor_port: show the current monitor
+  *
+  * This function returns a string indicating whether the current monitor is
+  * set to DVI or LVDS.
+  */
+ ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf)
+ {
+       return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n",
+               monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' ');
+ }
+ /**
+  * p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs
+  */
+ int p1022ds_set_sysfs_monitor_port(int val)
+ {
+       return val < 2 ? val : 0;
+ }
+ #endif
  
  void __init p1022_ds_pic_init(void)
  {
@@@ -92,6 -290,15 +290,15 @@@ static void __init p1022_ds_setup_arch(
        }
  #endif
  
+ #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+       diu_ops.get_pixel_format        = p1022ds_get_pixel_format;
+       diu_ops.set_gamma_table         = p1022ds_set_gamma_table;
+       diu_ops.set_monitor_port        = p1022ds_set_monitor_port;
+       diu_ops.set_pixel_clock         = p1022ds_set_pixel_clock;
+       diu_ops.show_monitor_port       = p1022ds_show_monitor_port;
+       diu_ops.set_sysfs_monitor_port  = p1022ds_set_sysfs_monitor_port;
+ #endif
  #ifdef CONFIG_SMP
        mpc85xx_smp_init();
  #endif
@@@ -112,8 -319,6 +319,8 @@@ static struct of_device_id __initdata p
        { .compatible = "soc", },
        { .compatible = "simple-bus", },
        { .compatible = "gianfar", },
 +      /* So that the DMA channel nodes can be probed individually: */
 +      { .compatible = "fsl,eloplus-dma", },
        {},
  };
  
diff --combined drivers/video/Kconfig
index dc06ff13455921f2d23748be845d6b51e3a92309,935cdc204f9390f04b34871bf69c391df3542a97..596ef6b922bfa4965682179b29fce8c0cd3bfca1
@@@ -49,7 -49,7 +49,7 @@@ menuconfig F
          You need an utility program called fbset to make full use of frame
          buffer devices. Please read <file:Documentation/fb/framebuffer.txt>
          and the Framebuffer-HOWTO at
 -        <http://www.munted.org.uk/programming/Framebuffer-HOWTO-1.2.html> for more
 +        <http://www.munted.org.uk/programming/Framebuffer-HOWTO-1.3.html> for more
          information.
  
          Say Y here and to the driver for your graphics board below if you
@@@ -955,7 -955,7 +955,7 @@@ config FB_EPSON135
          Build in support for the SED1355 Epson Research Embedded RAMDAC
          LCD/CRT Controller (since redesignated as the S1D13505) as a
          framebuffer.  Product specs at
 -        <http://www.erd.epson.com/vdc/html/products.htm>.
 +        <http://vdc.epson.com/>.
  
  config FB_S1D13XXX
        tristate "Epson S1D13XXX framebuffer support"
        help
          Support for S1D13XXX framebuffer device family (currently only
          working with S1D13806). Product specs at
 -        <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 +        <http://vdc.epson.com/>
  
  config FB_ATMEL
        tristate "AT91/AT32 LCD Controller support"
@@@ -1323,7 -1323,7 +1323,7 @@@ config FB_RADEO
          don't need to choose this to run the Radeon in plain VGA mode.
  
          There is a product page at
 -        http://apps.ati.com/ATIcompare/
 +        http://products.amd.com/en-us/GraphicCardResult.aspx
  
  config FB_RADEON_I2C
        bool "DDC/I2C for ATI Radeon support"
@@@ -1395,7 -1395,7 +1395,7 @@@ config FB_ATY_C
          Say Y here to support use of ATI's 64-bit Rage boards (or other
          boards based on the Mach64 CT, VT, GT, and LT chipsets) as a
          framebuffer device.  The ATI product support page for these boards
 -        is at <http://support.ati.com/products/pc/mach64/>.
 +        is at <http://support.ati.com/products/pc/mach64/mach64.html>.
  
  config FB_ATY_GENERIC_LCD
        bool "Mach64 generic LCD support (EXPERIMENTAL)"
@@@ -1919,6 -1919,9 +1919,9 @@@ config FB_SH_MOBILE_HDM
        tristate "SuperH Mobile HDMI controller support"
        depends on FB_SH_MOBILE_LCDC
        select FB_MODE_HELPERS
+       select SOUND
+       select SND
+       select SND_SOC
        ---help---
          Driver for the on-chip SH-Mobile HDMI controller.
  
diff --combined include/sound/core.h
index df26ebbfa9c697584ec95b429300a5b0d407ccb0,c129f0813baeb49a07830fb9ccc4c89a130277f9..1fa2407c966fdc5240d9853395fd22af6f435724
@@@ -133,7 -133,9 +133,7 @@@ struct snd_card 
        int free_on_last_close;         /* free in context of file_release */
        wait_queue_head_t shutdown_sleep;
        struct device *dev;             /* device assigned to this card */
 -#ifndef CONFIG_SYSFS_DEPRECATED
        struct device *card_dev;        /* cardX object for sysfs */
 -#endif
  
  #ifdef CONFIG_PM
        unsigned int power_state;       /* power state */
@@@ -177,7 -179,7 +177,7 @@@ int snd_power_wait(struct snd_card *car
  #define snd_power_lock(card)          do { (void)(card); } while (0)
  #define snd_power_unlock(card)                do { (void)(card); } while (0)
  static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
- #define snd_power_get_state(card)     SNDRV_CTL_POWER_D0
+ #define snd_power_get_state(card)     ({ (void)(card); SNDRV_CTL_POWER_D0; })
  #define snd_power_change_state(card, state)   do { (void)(card); } while (0)
  
  #endif /* CONFIG_PM */
@@@ -194,7 -196,11 +194,7 @@@ struct snd_minor 
  /* return a device pointer linked to each sound device as a parent */
  static inline struct device *snd_card_get_device_link(struct snd_card *card)
  {
 -#ifdef CONFIG_SYSFS_DEPRECATED
 -      return card ? card->dev : NULL;
 -#else
        return card ? card->card_dev : NULL;
 -#endif
  }
  
  /* sound.c */
diff --combined sound/core/init.c
index f7c3df8b521b2c85db5771a68acf27f981084aae,2de45fbd70fb10532f91334916ea68bd0acc90bf..57b792e2439a0f9b939c5789d7c23678ff8377bc
@@@ -395,10 -395,12 +395,10 @@@ int snd_card_disconnect(struct snd_car
                snd_printk(KERN_ERR "not all devices for card %i can be disconnected\n", card->number);
  
        snd_info_card_disconnect(card);
 -#ifndef CONFIG_SYSFS_DEPRECATED
        if (card->card_dev) {
                device_unregister(card->card_dev);
                card->card_dev = NULL;
        }
 -#endif
  #ifdef CONFIG_PM
        wake_up(&card->power_sleep);
  #endif
@@@ -571,6 -573,7 +571,6 @@@ void snd_card_set_id(struct snd_card *c
  }
  EXPORT_SYMBOL(snd_card_set_id);
  
 -#ifndef CONFIG_SYSFS_DEPRECATED
  static ssize_t
  card_id_show_attr(struct device *dev,
                  struct device_attribute *attr, char *buf)
@@@ -604,11 -607,16 +604,16 @@@ card_id_store_attr(struct device *dev, 
                return -EEXIST;
        }
        for (idx = 0; idx < snd_ecards_limit; idx++) {
-               if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1))
-                       goto __exist;
+               if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
+                       if (card == snd_cards[idx])
+                               goto __ok;
+                       else
+                               goto __exist;
+               }
        }
        strcpy(card->id, buf1);
        snd_info_card_id_change(card);
+ __ok:
        mutex_unlock(&snd_card_mutex);
  
        return count;
@@@ -627,6 -635,7 +632,6 @@@ card_number_show_attr(struct device *de
  
  static struct device_attribute card_number_attrs =
        __ATTR(number, S_IRUGO, card_number_show_attr, NULL);
 -#endif /* CONFIG_SYSFS_DEPRECATED */
  
  /**
   *  snd_card_register - register the soundcard
@@@ -645,7 -654,7 +650,7 @@@ int snd_card_register(struct snd_card *
  
        if (snd_BUG_ON(!card))
                return -EINVAL;
 -#ifndef CONFIG_SYSFS_DEPRECATED
 +
        if (!card->card_dev) {
                card->card_dev = device_create(sound_class, card->dev,
                                               MKDEV(0, 0), card,
                if (IS_ERR(card->card_dev))
                        card->card_dev = NULL;
        }
 -#endif
 +
        if ((err = snd_device_register_all(card)) < 0)
                return err;
        mutex_lock(&snd_card_mutex);
        if (snd_mixer_oss_notify_callback)
                snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER);
  #endif
 -#ifndef CONFIG_SYSFS_DEPRECATED
        if (card->card_dev) {
                err = device_create_file(card->card_dev, &card_id_attrs);
                if (err < 0)
                if (err < 0)
                        return err;
        }
 -#endif
 +
        return 0;
  }
  
index ca942f7cd2313c38c95d091f20c78658b36b36b7,b4c1eb504c22b1d2f4dc31a64d6f2696c598622b..7b5c77b32a90b9a5d4c967dcb58f2cb8e335fd24
@@@ -39,7 -39,7 +39,7 @@@
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
- #include <linux/smp_lock.h>
+ #include <linux/mutex.h>
  #include <linux/gfp.h>
  #include <asm/irq.h>
  #include <asm/io.h>
@@@ -79,6 -79,7 +79,7 @@@
                                         dev.rec_sample_rate /          \
                                         dev.rec_channels)
  
+ static DEFINE_MUTEX(msnd_pinnacle_mutex);
  static multisound_dev_t                       dev;
  
  #ifndef HAVE_DSPCODEH
@@@ -651,12 -652,12 +652,12 @@@ static long dev_ioctl(struct file *file
  
        ret = -EINVAL;
  
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor)
                ret = dsp_ioctl(file, cmd, arg);
        else if (minor == dev.mixer_minor)
                ret = mixer_ioctl(cmd, arg);
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
  
        return ret;
  }
@@@ -761,7 -762,7 +762,7 @@@ static int dev_open(struct inode *inode
        int minor = iminor(inode);
        int err = 0;
  
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor) {
                if ((file->f_mode & FMODE_WRITE &&
                     test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
        } else
                err = -EINVAL;
  out:
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
        return err;
  }
  
@@@ -800,14 -801,14 +801,14 @@@ static int dev_release(struct inode *in
        int minor = iminor(inode);
        int err = 0;
  
-       lock_kernel();
+       mutex_lock(&msnd_pinnacle_mutex);
        if (minor == dev.dsp_minor)
                err = dsp_release(file);
        else if (minor == dev.mixer_minor) {
                /* nothing */
        } else
                err = -EINVAL;
-       unlock_kernel();
+       mutex_unlock(&msnd_pinnacle_mutex);
        return err;
  }
  
@@@ -1117,7 -1118,6 +1118,7 @@@ static const struct file_operations dev
        .unlocked_ioctl = dev_ioctl,
        .open           = dev_open,
        .release        = dev_release,
 +      .llseek         = noop_llseek,
  };
  
  static int reset_dsp(void)
diff --combined sound/soc/sh/siu_pcm.c
index b0ccd0b862fc3722512a9d559f107d1a655e67de,d6c79fa56d12fe3016504b987efc91abca5584ad..ed29c9e1ed4efe764ad7a06d448e58386201efcb
@@@ -48,7 -48,7 +48,7 @@@ struct siu_port *siu_ports[SIU_PORT_NUM
  /* transfersize is number of u32 dma transfers per period */
  static int siu_pcm_stmwrite_stop(struct siu_port *port_info)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->playback;
        u32 stfifo;
@@@ -114,7 -114,7 +114,7 @@@ static void siu_dma_tx_complete(void *a
  static int siu_pcm_wr_set(struct siu_port *port_info,
                          dma_addr_t buff, u32 size)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->playback;
        struct snd_pcm_substream *substream = siu_stream->substream;
        sg_init_table(&sg, 1);
        sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
                    size, offset_in_page(buff));
 +      sg_dma_len(&sg) = size;
        sg_dma_address(&sg) = buff;
  
        desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
  static int siu_pcm_rd_set(struct siu_port *port_info,
                          dma_addr_t buff, size_t size)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->capture;
        struct snd_pcm_substream *substream = siu_stream->substream;
        sg_init_table(&sg, 1);
        sg_set_page(&sg, pfn_to_page(PFN_DOWN(buff)),
                    size, offset_in_page(buff));
 +      sg_dma_len(&sg) = size;
        sg_dma_address(&sg) = buff;
  
        desc = siu_stream->chan->device->device_prep_slave_sg(siu_stream->chan,
@@@ -272,7 -270,7 +272,7 @@@ static int siu_pcm_stmread_start(struc
  
  static int siu_pcm_stmread_stop(struct siu_port *port_info)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_stream *siu_stream = &port_info->capture;
        struct device *dev = siu_stream->substream->pcm->card->dev;
  static int siu_pcm_hw_params(struct snd_pcm_substream *ss,
                             struct snd_pcm_hw_params *hw_params)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        int ret;
  
  
  static int siu_pcm_hw_free(struct snd_pcm_substream *ss)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct device *dev = ss->pcm->card->dev;
        struct siu_stream *siu_stream;
@@@ -342,11 -340,12 +342,12 @@@ static bool filter(struct dma_chan *cha
  static int siu_pcm_open(struct snd_pcm_substream *ss)
  {
        /* Playback / Capture */
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct snd_soc_pcm_runtime *rtd = ss->private_data;
+       struct siu_platform *pdata = rtd->platform->dev->platform_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct siu_stream *siu_stream;
        u32 port = info->port_id;
-       struct siu_platform *pdata = siu_i2s_dai.dev->platform_data;
        struct device *dev = ss->pcm->card->dev;
        dma_cap_mask_t mask;
        struct sh_dmae_slave *param;
  
  static int siu_pcm_close(struct snd_pcm_substream *ss)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        struct siu_port *port_info = siu_port_info(ss);
        struct siu_stream *siu_stream;
  
  static int siu_pcm_prepare(struct snd_pcm_substream *ss)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct siu_port *port_info = siu_port_info(ss);
        struct device *dev = ss->pcm->card->dev;
        struct snd_pcm_runtime  *rt = ss->runtime;
  
  static int siu_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
  {
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct device *dev = ss->pcm->card->dev;
        struct siu_port *port_info = siu_port_info(ss);
        int ret;
  static snd_pcm_uframes_t siu_pcm_pointer_dma(struct snd_pcm_substream *ss)
  {
        struct device *dev = ss->pcm->card->dev;
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        u32 __iomem *base = info->reg;
        struct siu_port *port_info = siu_port_info(ss);
        struct snd_pcm_runtime *rt = ss->runtime;
@@@ -530,7 -529,7 +531,7 @@@ static int siu_pcm_new(struct snd_card 
                       struct snd_pcm *pcm)
  {
        /* card->dev == socdev->dev, see snd_soc_new_pcms() */
-       struct siu_info *info = siu_i2s_dai.private_data;
+       struct siu_info *info = siu_i2s_data;
        struct platform_device *pdev = to_platform_device(card->dev);
        int ret;
        int i;
@@@ -607,9 -606,8 +608,8 @@@ static struct snd_pcm_ops siu_pcm_ops 
        .pointer        = siu_pcm_pointer_dma,
  };
  
- struct snd_soc_platform siu_platform = {
-       .name           = "siu-audio",
-       .pcm_ops        = &siu_pcm_ops,
+ struct snd_soc_platform_driver siu_platform = {
+       .ops                    = &siu_pcm_ops,
        .pcm_new        = siu_pcm_new,
        .pcm_free       = siu_pcm_free,
  };
diff --combined sound/soc/soc-core.c
index 4057d35343bbbbd434e6a2f99bf0398aeac2a75e,70d9a7394b2b35fde32e812108dadf86031a95c0..1c8f3f507f54e7d1fc469ff03a2fdbf787640e3a
@@@ -3,6 -3,8 +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 :-
@@@ -37,6 -39,8 +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);
  
@@@ -52,6 -56,7 +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().
@@@ -86,30 -91,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;
  }
@@@ -203,19 -210,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;
  }
  
@@@ -223,21 -230,11 +230,12 @@@ static const struct file_operations cod
        .open = codec_reg_open_file,
        .read = codec_reg_read_file,
        .write = codec_reg_write_file,
 +      .llseek = default_llseek,
  };
  
  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
@@@ -273,6 -270,106 +271,106 @@@ static void soc_cleanup_codec_debugfs(s
        debugfs_remove_recursive(codec->debugfs_codec_root);
  }
  
+ static ssize_t codec_list_read_file(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+ {
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_codec *codec;
+       if (!buf)
+               return -ENOMEM;
+       list_for_each_entry(codec, &codec_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                              codec->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+       if (ret >= 0)
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+       kfree(buf);
+       return ret;
+ }
+ static const struct file_operations codec_list_fops = {
+       .read = codec_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+ };
+ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf,
+                                 size_t count, loff_t *ppos)
+ {
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_dai *dai;
+       if (!buf)
+               return -ENOMEM;
+       list_for_each_entry(dai, &dai_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+       kfree(buf);
+       return ret;
+ }
+ static const struct file_operations dai_list_fops = {
+       .read = dai_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+ };
+ static ssize_t platform_list_read_file(struct file *file,
+                                      char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+ {
+       char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       ssize_t len, ret = 0;
+       struct snd_soc_platform *platform;
+       if (!buf)
+               return -ENOMEM;
+       list_for_each_entry(platform, &platform_list, list) {
+               len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n",
+                              platform->name);
+               if (len >= 0)
+                       ret += len;
+               if (ret > PAGE_SIZE) {
+                       ret = PAGE_SIZE;
+                       break;
+               }
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
+       kfree(buf);
+       return ret;
+ }
+ static const struct file_operations platform_list_fops = {
+       .read = platform_list_read_file,
+       .llseek = default_llseek,/* read accesses f_pos */
+ };
  #else
  
  static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec)
@@@ -306,7 -403,7 +404,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);
@@@ -693,26 -777,23 +778,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;
  
@@@ -881,104 -953,111 +954,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.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) {
+               /*
+                * It is possible that the AC97 device is already registered to
+                * the device subsystem. This happens when the device is created
+                * via snd_ac97_mixer(). Currently only SoC codec that does so
+                * is the generic AC97 glue but others migh emerge.
+                *
+                * In those cases we don't try to register the device again.
+                */
+               if (!rtd->codec->ac97_created)
+                       return 0;
+               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;
  
- card_err:
-       if (platform->remove)
-               platform->remove(pdev);
+ #ifdef CONFIG_PM
+       /* deferred resume work */
+       INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
+ #endif
  
- platform_err:
-       if (codec_dev->remove)
-               codec_dev->remove(pdev);
+       /* initialise the sound card only once */
+       if (card->probe) {
+               ret = card->probe(pdev);
+               if (ret < 0)
+                       goto card_probe_error;
+       }
  
- 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);
+       for (i = 0; i < card->num_links; i++) {
+               ret = soc_probe_dai_link(card, i);
+               if (ret < 0) {
+                       pr_err("asoc: failed to instantiate card %s: %d\n",
+                              card->name, ret);
+                       goto probe_dai_err;
+               }
        }
  
+       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);
  }
  
  /*
@@@ -1333,15 -1654,15 +1655,15 @@@ static void snd_soc_instantiate_cards(v
  /* 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 (card->instantiated) {
  
-               if (codec_dev->remove)
-                       codec_dev->remove(pdev);
-               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;
  }
@@@ -1420,53 -1740,42 +1741,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;
  }
@@@ -1533,7 -1841,13 +1842,13 @@@ int snd_soc_new_ac97_codec(struct snd_s
  
        codec->ac97->bus->ops = ops;
        codec->ac97->num = num;
-       codec->dev = &codec->ac97->dev;
+       /*
+        * Mark the AC97 device to be created by us. This way we ensure that the
+        * device will be registered with the device subsystem later on.
+        */
+       codec->ac97_created = 1;
        mutex_unlock(&codec->mutex);
        return 0;
  }
@@@ -1548,9 -1862,13 +1863,13 @@@ 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;
+       codec->ac97_created = 0;
        mutex_unlock(&codec->mutex);
  }
  EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
@@@ -1633,95 -1951,6 +1952,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
@@@ -1783,15 -2012,15 +2013,15 @@@ 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++) {
                const struct snd_kcontrol_new *control = &controls[i];
                err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL));
                if (err < 0) {
-                       dev_err(codec->dev, "%s: Failed to add %s\n",
-                               codec->name, control->name);
+                       dev_err(codec->dev, "%s: Failed to add %s: %d\n",
+                               codec->name, control->name, err);
                        return err;
                }
        }
@@@ -2338,7 -2567,7 +2568,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;
@@@ -2470,8 -2699,8 +2700,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;
  }
@@@ -2490,8 -2719,8 +2720,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;
  }
@@@ -2510,8 -2739,8 +2740,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;
@@@ -2527,8 -2756,8 +2757,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;
  }
@@@ -2548,8 -2777,8 +2778,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;
@@@ -2572,8 -2801,8 +2802,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;
@@@ -2589,8 -2818,8 +2819,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;
  }
@@@ -2605,8 -2834,8 +2835,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;
  }
@@@ -2623,11 -2852,22 +2853,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);
@@@ -2653,30 -2893,97 +2894,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);
@@@ -2694,13 -3001,24 +3002,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 #%Zu\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->driver = &dai_drv[i];
+               if (dai->driver->id)
+                       dai->id = dai->driver->id;
+               else
+                       dai->id = 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;
  }
@@@ -2736,12 -3083,12 +3084,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));
  
-       INIT_LIST_HEAD(&platform->list);
+       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;
+       }
+       platform->dev = dev;
+       platform->driver = platform_drv;
  
        mutex_lock(&client_mutex);
        list_add(&platform->list, &platform_list);
@@@ -2773,13 -3134,24 +3135,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);
  
@@@ -2821,22 -3193,61 +3194,61 @@@ 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;
+       /* create CODEC component name */
+       codec->name = fmt_single_name(dev, &codec->id);
+       if (codec->name == NULL) {
+               kfree(codec);
+               return -ENOMEM;
+       }
  
-       /* The device should become mandatory over time */
-       if (!codec->dev)
-               printk(KERN_WARNING "No device for codec %s\n", codec->name);
+       /* 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 any DAIs */
+       if (num_dai) {
+               ret = snd_soc_register_dais(dev, dai_drv, num_dai);
+               if (ret < 0)
+                       goto error;
        }
  
        mutex_lock(&client_mutex);
        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:
+       if (codec->num_dai)
+               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->name);
+       kfree(codec);
  }
  EXPORT_SYMBOL_GPL(snd_soc_unregister_codec);
  
@@@ -2874,10 -3313,23 +3314,23 @@@ static int __init snd_soc_init(void
                       "ASoC: Failed to create debugfs directory\n");
                debugfs_root = NULL;
        }
+       if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL,
+                                &codec_list_fops))
+               pr_warn("ASoC: Failed to create CODEC list debugfs file\n");
+       if (!debugfs_create_file("dais", 0444, debugfs_root, NULL,
+                                &dai_list_fops))
+               pr_warn("ASoC: Failed to create DAI list debugfs file\n");
+       if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL,
+                                &platform_list_fops))
+               pr_warn("ASoC: Failed to create platform list debugfs file\n");
  #endif
  
        return platform_driver_register(&soc_driver);
  }
+ module_init(snd_soc_init);
  
  static void __exit snd_soc_exit(void)
  {
  #endif
        platform_driver_unregister(&soc_driver);
  }
- module_init(snd_soc_init);
  module_exit(snd_soc_exit);
  
  /* Module information */
diff --combined sound/soc/soc-dapm.c
index 72a53d0a41e934972120efe156902d4d42290533,035cab85cb66af64c38ae89103fe8cc240cc9d7a..7d85c6496afa432cbd9791be5f1a9510e7cb78c7
@@@ -112,43 -112,41 +112,41 @@@ static inline struct snd_soc_dapm_widge
  
  /**
   * snd_soc_dapm_set_bias_level - set the bias level for the system
-  * @socdev: audio device
+  * @card: audio device
   * @level: level to configure
   *
   * Configure the bias (power) levels for the SoC audio device.
   *
   * Returns 0 for success else error.
   */
- static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev,
-                                      enum snd_soc_bias_level level)
+ static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card,
+               struct snd_soc_codec *codec, enum snd_soc_bias_level level)
  {
-       struct snd_soc_card *card = socdev->card;
-       struct snd_soc_codec *codec = socdev->card->codec;
        int ret = 0;
  
        switch (level) {
        case SND_SOC_BIAS_ON:
-               dev_dbg(socdev->dev, "Setting full bias\n");
+               dev_dbg(codec->dev, "Setting full bias\n");
                break;
        case SND_SOC_BIAS_PREPARE:
-               dev_dbg(socdev->dev, "Setting bias prepare\n");
+               dev_dbg(codec->dev, "Setting bias prepare\n");
                break;
        case SND_SOC_BIAS_STANDBY:
-               dev_dbg(socdev->dev, "Setting standby bias\n");
+               dev_dbg(codec->dev, "Setting standby bias\n");
                break;
        case SND_SOC_BIAS_OFF:
-               dev_dbg(socdev->dev, "Setting bias off\n");
+               dev_dbg(codec->dev, "Setting bias off\n");
                break;
        default:
-               dev_err(socdev->dev, "Setting invalid bias %d\n", level);
+               dev_err(codec->dev, "Setting invalid bias %d\n", level);
                return -EINVAL;
        }
  
-       if (card->set_bias_level)
+       if (card && card->set_bias_level)
                ret = card->set_bias_level(card, level);
        if (ret == 0) {
-               if (codec->set_bias_level)
-                       ret = codec->set_bias_level(codec, level);
+               if (codec->driver->set_bias_level)
+                       ret = codec->driver->set_bias_level(codec, level);
                else
                        codec->bias_level = level;
        }
@@@ -370,7 -368,7 +368,7 @@@ static int dapm_new_mixer(struct snd_so
  
                        path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w,
                                path->long_name);
-                       ret = snd_ctl_add(codec->card, path->kcontrol);
+                       ret = snd_ctl_add(codec->card->snd_card, path->kcontrol);
                        if (ret < 0) {
                                printk(KERN_ERR "asoc: failed to add dapm kcontrol %s: %d\n",
                                       path->long_name,
@@@ -398,7 -396,7 +396,7 @@@ static int dapm_new_mux(struct snd_soc_
        }
  
        kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name);
-       ret = snd_ctl_add(codec->card, kcontrol);
+       ret = snd_ctl_add(codec->card->snd_card, kcontrol);
        if (ret < 0)
                goto err;
  
@@@ -437,9 -435,9 +435,9 @@@ static inline void dapm_clear_walk(stru
   */
  static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget)
  {
-       struct snd_soc_codec *codec = widget->codec;
+       int level = snd_power_get_state(widget->codec->card->snd_card);
  
-       switch (snd_power_get_state(codec->card)) {
+       switch (level) {
        case SNDRV_CTL_POWER_D3hot:
        case SNDRV_CTL_POWER_D3cold:
                if (widget->ignore_suspend)
@@@ -893,7 -891,7 +891,7 @@@ static void dapm_seq_run(struct snd_soc
   */
  static int dapm_power_widgets(struct snd_soc_codec *codec, int event)
  {
-       struct snd_soc_device *socdev = codec->socdev;
+       struct snd_soc_card *card = codec->card;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(up_list);
        LIST_HEAD(down_list);
        }
  
        if (sys_power && codec->bias_level == SND_SOC_BIAS_OFF) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
+               ret = snd_soc_dapm_set_bias_level(card, codec,
                                                  SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        pr_err("Failed to turn on bias: %d\n", ret);
        /* If we're changing to all on or all off then prepare */
        if ((sys_power && codec->bias_level == SND_SOC_BIAS_STANDBY) ||
            (!sys_power && codec->bias_level == SND_SOC_BIAS_ON)) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_PREPARE);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_PREPARE);
                if (ret != 0)
                        pr_err("Failed to prepare bias: %d\n", ret);
        }
  
        /* If we just powered the last thing off drop to standby bias */
        if (codec->bias_level == SND_SOC_BIAS_PREPARE && !sys_power) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_STANDBY);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_STANDBY);
                if (ret != 0)
                        pr_err("Failed to apply standby bias: %d\n", ret);
        }
        /* If we're in standby and can support bias off then do that */
        if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
            codec->idle_bias_off) {
-               ret = snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
                if (ret != 0)
                        pr_err("Failed to turn off bias: %d\n", ret);
        }
  
        /* If we just powered up then move to active bias */
        if (codec->bias_level == SND_SOC_BIAS_PREPARE && sys_power) {
-               ret = snd_soc_dapm_set_bias_level(socdev,
-                                                 SND_SOC_BIAS_ON);
+               ret = snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_ON);
                if (ret != 0)
                        pr_err("Failed to apply active bias: %d\n", ret);
        }
@@@ -1089,7 -1084,6 +1084,7 @@@ static ssize_t dapm_widget_power_read_f
  static const struct file_operations dapm_widget_power_fops = {
        .open = dapm_widget_power_open_file,
        .read = dapm_widget_power_read_file,
 +      .llseek = default_llseek,
  };
  
  void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec)
@@@ -1189,8 -1183,9 +1184,9 @@@ static int dapm_mixer_update_power(stru
  static ssize_t dapm_widget_show(struct device *dev,
        struct device_attribute *attr, char *buf)
  {
-       struct snd_soc_device *devdata = dev_get_drvdata(dev);
-       struct snd_soc_codec *codec = devdata->card->codec;
+       struct snd_soc_pcm_runtime *rtd =
+                       container_of(dev, struct snd_soc_pcm_runtime, dev);
+       struct snd_soc_codec *codec =rtd->codec;
        struct snd_soc_dapm_widget *w;
        int count = 0;
        char *state = "not set";
@@@ -1999,9 -1994,10 +1995,10 @@@ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_cont
   *
   * Returns 0 for success else error.
   */
- int snd_soc_dapm_stream_event(struct snd_soc_codec *codec,
-       char *stream, int event)
+ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+       const char *stream, int event)
  {
+       struct snd_soc_codec *codec = rtd->codec;
        struct snd_soc_dapm_widget *w;
  
        if (stream == NULL)
@@@ -2169,25 -2165,19 +2166,19 @@@ EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_s
  
  /**
   * snd_soc_dapm_free - free dapm resources
-  * @socdev: SoC device
+  * @card: SoC device
   *
   * Free all dapm widgets and resources.
   */
- void snd_soc_dapm_free(struct snd_soc_device *socdev)
+ void snd_soc_dapm_free(struct snd_soc_codec *codec)
  {
-       struct snd_soc_codec *codec = socdev->card->codec;
-       snd_soc_dapm_sys_remove(socdev->dev);
+       snd_soc_dapm_sys_remove(codec->dev);
        dapm_free_widgets(codec);
  }
  EXPORT_SYMBOL_GPL(snd_soc_dapm_free);
  
- /*
-  * snd_soc_dapm_shutdown - callback for system shutdown
-  */
- void snd_soc_dapm_shutdown(struct snd_soc_device *socdev)
+ static void soc_dapm_shutdown_codec(struct snd_soc_codec *codec)
  {
-       struct snd_soc_codec *codec = socdev->card->codec;
        struct snd_soc_dapm_widget *w;
        LIST_HEAD(down_list);
        int powerdown = 0;
         * standby.
         */
        if (powerdown) {
-               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_PREPARE);
+               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_PREPARE);
                dapm_seq_run(codec, &down_list, 0, dapm_down_seq);
-               snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_STANDBY);
+               snd_soc_dapm_set_bias_level(NULL, codec, SND_SOC_BIAS_STANDBY);
        }
+ }
+ /*
+  * snd_soc_dapm_shutdown - callback for system shutdown
+  */
+ void snd_soc_dapm_shutdown(struct snd_soc_card *card)
+ {
+       struct snd_soc_codec *codec;
+       list_for_each_entry(codec, &card->codec_dev_list, list)
+               soc_dapm_shutdown_codec(codec);
  
-       snd_soc_dapm_set_bias_level(socdev, SND_SOC_BIAS_OFF);
+       snd_soc_dapm_set_bias_level(card, codec, SND_SOC_BIAS_OFF);
  }
  
  /* Module information */