Просмотр исходного кода

Merge branch 'topic/asoc' into for-linus

Conflicts:
	arch/powerpc/platforms/85xx/p1022_ds.c
Takashi Iwai 14 лет назад
Родитель
Сommit
aa5c14d5c0
100 измененных файлов с 3661 добавлено и 2046 удалено
  1. 13 0
      arch/arm/mach-davinci/devices.c
  2. 40 0
      arch/arm/mach-ep93xx/core.c
  3. 1 0
      arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
  4. 1 0
      arch/arm/mach-ep93xx/include/mach/platform.h
  5. 1 0
      arch/arm/mach-ep93xx/simone.c
  6. 6 0
      arch/arm/mach-kirkwood/common.c
  7. 26 0
      arch/arm/mach-omap1/devices.c
  8. 12 5
      arch/arm/mach-omap2/board-rx51-peripherals.c
  9. 12 0
      arch/arm/mach-omap2/board-zoom-peripherals.c
  10. 1 35
      arch/arm/mach-omap2/board-zoom2.c
  11. 39 0
      arch/arm/mach-omap2/devices.c
  12. 2 0
      arch/arm/mach-omap2/include/mach/board-zoom.h
  13. 25 0
      arch/arm/mach-pxa/devices.c
  14. 6 0
      arch/arm/mach-pxa/devices.h
  15. 4 0
      arch/arm/mach-pxa/pxa27x.c
  16. 5 0
      arch/arm/mach-pxa/pxa3xx.c
  17. 11 0
      arch/arm/mach-pxa/zylonite.c
  18. 18 2
      arch/arm/mach-s3c64xx/dev-audio.c
  19. 1 0
      arch/arm/mach-s3c64xx/mach-smdk6410.c
  20. 7 0
      arch/arm/plat-omap/include/plat/mcbsp.h
  21. 30 4
      arch/arm/plat-s3c24xx/devs.c
  22. 2 0
      arch/arm/plat-samsung/include/plat/devs.h
  23. 6 0
      arch/mips/alchemy/devboards/db1200/platform.c
  24. 1 0
      arch/powerpc/boot/dts/mpc8610_hpcd.dts
  25. 3 0
      arch/powerpc/configs/mpc85xx_defconfig
  26. 3 0
      arch/powerpc/configs/mpc85xx_smp_defconfig
  27. 76 35
      arch/powerpc/include/asm/fsl_guts.h
  28. 209 2
      arch/powerpc/platforms/85xx/p1022_ds.c
  29. 1 1
      arch/sh/kernel/cpu/sh4a/setup-sh7722.c
  30. 2 2
      drivers/input/misc/twl4030-vibra.c
  31. 3 3
      drivers/mfd/twl-core.c
  32. 4 4
      drivers/mfd/twl4030-codec.c
  33. 1 1
      drivers/staging/xgifb/TODO
  34. 3 0
      drivers/video/Kconfig
  35. 83 1
      drivers/video/sh_mobile_hdmi.c
  36. 5 1
      include/linux/i2c/twl.h
  37. 50 0
      include/sound/max98088.h
  38. 0 3
      include/sound/sh_fsi.h
  39. 63 35
      include/sound/soc-dai.h
  40. 14 4
      include/sound/soc-dapm.h
  41. 0 25
      include/sound/soc-of-simple.h
  42. 148 97
      include/sound/soc.h
  43. 42 1
      include/sound/tlv320aic3x.h
  44. 32 0
      include/sound/wm8962.h
  45. 16 0
      include/video/sh_mobile_hdmi.h
  46. 36 23
      sound/soc/atmel/atmel-pcm.c
  47. 0 3
      sound/soc/atmel/atmel-pcm.h
  48. 123 25
      sound/soc/atmel/atmel_ssc_dai.c
  49. 2 1
      sound/soc/atmel/atmel_ssc_dai.h
  50. 12 53
      sound/soc/atmel/playpaq_wm8510.c
  51. 17 42
      sound/soc/atmel/sam9g20_wm8731.c
  52. 9 26
      sound/soc/atmel/snd-soc-afeb9260.c
  53. 14 25
      sound/soc/au1x/db1200.c
  54. 29 66
      sound/soc/au1x/dbdma2.c
  55. 37 34
      sound/soc/au1x/psc-ac97.c
  56. 15 38
      sound/soc/au1x/psc-i2s.c
  57. 2 8
      sound/soc/au1x/psc.h
  58. 31 12
      sound/soc/blackfin/bf5xx-ac97-pcm.c
  59. 0 3
      sound/soc/blackfin/bf5xx-ac97-pcm.h
  60. 30 11
      sound/soc/blackfin/bf5xx-ac97.c
  61. 0 2
      sound/soc/blackfin/bf5xx-ac97.h
  62. 9 14
      sound/soc/blackfin/bf5xx-ad1836.c
  63. 9 14
      sound/soc/blackfin/bf5xx-ad193x.c
  64. 7 12
      sound/soc/blackfin/bf5xx-ad1980.c
  65. 8 14
      sound/soc/blackfin/bf5xx-ad73311.c
  66. 31 13
      sound/soc/blackfin/bf5xx-i2s-pcm.c
  67. 0 3
      sound/soc/blackfin/bf5xx-i2s-pcm.h
  68. 31 14
      sound/soc/blackfin/bf5xx-i2s.c
  69. 0 14
      sound/soc/blackfin/bf5xx-i2s.h
  70. 9 29
      sound/soc/blackfin/bf5xx-ssm2602.c
  71. 31 12
      sound/soc/blackfin/bf5xx-tdm-pcm.c
  72. 0 3
      sound/soc/blackfin/bf5xx-tdm-pcm.h
  73. 6 9
      sound/soc/blackfin/bf5xx-tdm.c
  74. 0 2
      sound/soc/blackfin/bf5xx-tdm.h
  75. 1486 0
      sound/soc/codecs/88pm860x-codec.c
  76. 97 0
      sound/soc/codecs/88pm860x-codec.h
  77. 24 0
      sound/soc/codecs/Kconfig
  78. 12 0
      sound/soc/codecs/Makefile
  79. 51 74
      sound/soc/codecs/ac97.c
  80. 0 19
      sound/soc/codecs/ac97.h
  81. 55 136
      sound/soc/codecs/ad1836.c
  82. 0 2
      sound/soc/codecs/ad1836.h
  83. 77 140
      sound/soc/codecs/ad193x.c
  84. 0 3
      sound/soc/codecs/ad193x.h
  85. 47 66
      sound/soc/codecs/ad1980.c
  86. 0 3
      sound/soc/codecs/ad1980.h
  87. 19 47
      sound/soc/codecs/ad73311.c
  88. 0 2
      sound/soc/codecs/ad73311.h
  89. 11 61
      sound/soc/codecs/ads117x.c
  90. 2 2
      sound/soc/codecs/ads117x.h
  91. 53 96
      sound/soc/codecs/ak4104.c
  92. 0 7
      sound/soc/codecs/ak4104.h
  93. 61 175
      sound/soc/codecs/ak4535.c
  94. 0 8
      sound/soc/codecs/ak4535.h
  95. 82 153
      sound/soc/codecs/ak4642.c
  96. 0 20
      sound/soc/codecs/ak4642.h
  97. 29 111
      sound/soc/codecs/ak4671.c
  98. 0 3
      sound/soc/codecs/ak4671.h
  99. 29 103
      sound/soc/codecs/cq93vc.c
  100. 0 29
      sound/soc/codecs/cq93vc.h

+ 13 - 0
arch/arm/mach-davinci/devices.c

@@ -295,6 +295,18 @@ static void davinci_init_wdt(void)
 
 /*-------------------------------------------------------------------------*/
 
+struct platform_device davinci_pcm_device = {
+	.name		= "davinci-pcm-audio",
+	.id		= -1,
+};
+
+static void davinci_init_pcm(void)
+{
+	platform_device_register(&davinci_pcm_device);
+}
+
+/*-------------------------------------------------------------------------*/
+
 struct davinci_timer_instance davinci_timer_instance[2] = {
 	{
 		.base		= DAVINCI_TIMER0_BASE,
@@ -315,6 +327,7 @@ static int __init davinci_init_devices(void)
 	/* please keep these calls, and their implementations above,
 	 * in alphabetical order so they're easier to sort through.
 	 */
+	davinci_init_pcm();
 	davinci_init_wdt();
 
 	return 0;

+ 40 - 0
arch/arm/mach-ep93xx/core.c

@@ -776,9 +776,15 @@ static struct platform_device ep93xx_i2s_device = {
 	.resource	= ep93xx_i2s_resource,
 };
 
+static struct platform_device ep93xx_pcm_device = {
+	.name		= "ep93xx-pcm-audio",
+	.id		= -1,
+};
+
 void __init ep93xx_register_i2s(void)
 {
 	platform_device_register(&ep93xx_i2s_device);
+	platform_device_register(&ep93xx_pcm_device);
 }
 
 #define EP93XX_SYSCON_DEVCFG_I2S_MASK	(EP93XX_SYSCON_DEVCFG_I2SONSSP | \
@@ -826,6 +832,40 @@ void ep93xx_i2s_release(void)
 }
 EXPORT_SYMBOL(ep93xx_i2s_release);
 
+/*************************************************************************
+ * EP93xx AC97 audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_ac97_resources[] = {
+	{
+		.start	= EP93XX_AAC_PHYS_BASE,
+		.end	= EP93XX_AAC_PHYS_BASE + 0xb0 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start	= IRQ_EP93XX_AACINTR,
+		.end	= IRQ_EP93XX_AACINTR,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device ep93xx_ac97_device = {
+	.name		= "ep93xx-ac97",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_ac97_resources),
+	.resource	= ep93xx_ac97_resources,
+};
+
+void __init ep93xx_register_ac97(void)
+{
+	/*
+	 * Make sure that the AC97 pins are not used by I2S.
+	 */
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONAC97);
+
+	platform_device_register(&ep93xx_ac97_device);
+	platform_device_register(&ep93xx_pcm_device);
+}
+
 extern void ep93xx_gpio_init(void);
 
 void __init ep93xx_init_devices(void)

+ 1 - 0
arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h

@@ -105,6 +105,7 @@
 #define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
 #define EP93XX_GPIO_EEDRIVE		EP93XX_GPIO_REG(0xc8)
 
+#define EP93XX_AAC_PHYS_BASE		EP93XX_APB_PHYS(0x00080000)
 #define EP93XX_AAC_BASE			EP93XX_APB_IOMEM(0x00080000)
 
 #define EP93XX_SPI_PHYS_BASE		EP93XX_APB_PHYS(0x000a0000)

+ 1 - 0
arch/arm/mach-ep93xx/include/mach/platform.h

@@ -61,6 +61,7 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev);
 void ep93xx_register_i2s(void);
 int ep93xx_i2s_acquire(unsigned i2s_pins, unsigned i2s_config);
 void ep93xx_i2s_release(void);
+void ep93xx_register_ac97(void);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;

+ 1 - 0
arch/arm/mach-ep93xx/simone.c

@@ -61,6 +61,7 @@ static void __init simone_init_machine(void)
 	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")

+ 6 - 0
arch/arm/mach-kirkwood/common.c

@@ -903,10 +903,16 @@ static struct platform_device kirkwood_i2s_device = {
 	},
 };
 
+static struct platform_device kirkwood_pcm_device = {
+	.name		= "kirkwood-pcm-audio",
+	.id		= -1,
+};
+
 void __init kirkwood_audio_init(void)
 {
 	kirkwood_clk_ctrl |= CGC_AUDIO;
 	platform_device_register(&kirkwood_i2s_device);
+	platform_device_register(&kirkwood_pcm_device);
 }
 
 /*****************************************************************************

+ 26 - 0
arch/arm/mach-omap1/devices.c

@@ -25,6 +25,7 @@
 #include <mach/gpio.h>
 #include <plat/mmc.h>
 #include <plat/omap7xx.h>
+#include <plat/mcbsp.h>
 
 /*-------------------------------------------------------------------------*/
 
@@ -195,6 +196,30 @@ static inline void omap_init_spi100k(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,
+};
+
+OMAP_MCBSP_PLATFORM_DEVICE(1);
+OMAP_MCBSP_PLATFORM_DEVICE(2);
+OMAP_MCBSP_PLATFORM_DEVICE(3);
+
+static void omap_init_audio(void)
+{
+	platform_device_register(&omap_mcbsp1);
+	platform_device_register(&omap_mcbsp2);
+	if (!cpu_is_omap7xx())
+		platform_device_register(&omap_mcbsp3);
+	platform_device_register(&omap_pcm);
+}
+
+#else
+static inline void omap_init_audio(void) {}
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -227,6 +252,7 @@ static int __init omap1_init_devices(void)
 	omap_init_rtc();
 	omap_init_spi100k();
 	omap_init_sti();
+	omap_init_audio();
 
 	return 0;
 }

+ 12 - 5
arch/arm/mach-omap2/board-rx51-peripherals.c

@@ -23,6 +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 @@ static struct twl4030_power_data rx51_t2scripts_data __initdata = {
 };
 
 
-
 static struct twl4030_platform_data rx51_twldata __initdata = {
 	.irq_base		= TWL4030_IRQ_BASE,
 	.irq_end		= TWL4030_IRQ_END,
@@ -710,10 +710,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
 	.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 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_1[] = {
 	},
 };
 
+/* 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),

+ 12 - 0
arch/arm/mach-omap2/board-zoom-peripherals.c

@@ -24,6 +24,8 @@
 #include <plat/common.h>
 #include <plat/usb.h>
 
+#include <mach/board-zoom.h>
+
 #include "mux.h"
 #include "hsmmc.h"
 
@@ -188,6 +190,11 @@ static int zoom_twl_gpio_setup(struct device *dev,
 	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*/
@@ -257,6 +264,11 @@ static struct i2c_board_info __initdata zoom_i2c_boardinfo[] = {
 
 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);

+ 1 - 35
arch/arm/mach-omap2/board-zoom2.c

@@ -14,6 +14,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/gpio.h>
+#include <linux/i2c/twl.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -34,41 +35,6 @@ static void __init omap_zoom2_init_irq(void)
 	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 */

+ 39 - 0
arch/arm/mach-omap2/devices.c

@@ -25,6 +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 @@ 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>
@@ -847,6 +885,7 @@ static int __init omap2_init_devices(void)
 	 * 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();

+ 2 - 0
arch/arm/mach-omap2/include/mach/board-zoom.h

@@ -9,3 +9,5 @@
 extern void __init board_nand_init(struct mtd_partition *, u8 nr_parts, u8 cs);
 extern int __init zoom_debugboard_init(void);
 extern void __init zoom_peripherals_init(void);
+
+#define ZOOM2_HEADSET_EXTMUTE_GPIO	153

+ 25 - 0
arch/arm/mach-pxa/devices.c

@@ -354,6 +354,31 @@ struct platform_device pxa_device_i2s = {
 	.num_resources	= ARRAY_SIZE(pxai2s_resources),
 };
 
+struct platform_device pxa_device_asoc_ssp1 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 0,
+};
+
+struct platform_device pxa_device_asoc_ssp2= {
+	.name		= "pxa-ssp-dai",
+	.id		= 1,
+};
+
+struct platform_device pxa_device_asoc_ssp3 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 2,
+};
+
+struct platform_device pxa_device_asoc_ssp4 = {
+	.name		= "pxa-ssp-dai",
+	.id		= 3,
+};
+
+struct platform_device pxa_device_asoc_platform = {
+	.name		= "pxa-pcm-audio",
+	.id		= -1,
+};
+
 static u64 pxaficp_dmamask = ~(u32)0;
 
 struct platform_device pxa_device_ficp = {

+ 6 - 0
arch/arm/mach-pxa/devices.h

@@ -38,4 +38,10 @@ extern struct platform_device pxa3xx_device_i2c_power;
 
 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);

+ 4 - 0
arch/arm/mach-pxa/pxa27x.c

@@ -385,6 +385,10 @@ static struct platform_device *devices[] __initdata = {
 	&pxa27x_device_udc,
 	&pxa_device_pmu,
 	&pxa_device_i2s,
+	&pxa_device_asoc_ssp1,
+	&pxa_device_asoc_ssp2,
+	&pxa_device_asoc_ssp3,
+	&pxa_device_asoc_platform,
 	&sa1100_device_rtc,
 	&pxa_device_rtc,
 	&pxa27x_device_ssp1,

+ 5 - 0
arch/arm/mach-pxa/pxa3xx.c

@@ -610,6 +610,11 @@ static struct platform_device *devices[] __initdata = {
 	&pxa27x_device_udc,
 	&pxa_device_pmu,
 	&pxa_device_i2s,
+	&pxa_device_asoc_ssp1,
+	&pxa_device_asoc_ssp2,
+	&pxa_device_asoc_ssp3,
+	&pxa_device_asoc_ssp4,
+	&pxa_device_asoc_platform,
 	&sa1100_device_rtc,
 	&pxa_device_rtc,
 	&pxa27x_device_ssp1,

+ 11 - 0
arch/arm/mach-pxa/zylonite.c

@@ -45,6 +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,6 +418,7 @@ 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)")

+ 18 - 2
arch/arm/mach-s3c64xx/dev-audio.c

@@ -43,8 +43,10 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
 		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_I2S1_LRCLK);
 		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_I2S1_DI);
 		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_I2S1_D0);
+		break;
 	default:
-		printk(KERN_DEBUG "Invalid I2S Controller number!");
+		printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
+			pdev->id);
 		return -EINVAL;
 	}
 
@@ -184,7 +186,8 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev)
 		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
 		break;
 	default:
-		printk(KERN_DEBUG "Invalid PCM Controller number!");
+		printk(KERN_DEBUG "Invalid PCM Controller number: %d\n",
+			pdev->id);
 		return -EINVAL;
 	}
 
@@ -333,3 +336,16 @@ void __init s3c64xx_ac97_setup_gpio(int num)
 	else
 		s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
 }
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+	.name		  = "s3c24xx-pcm-audio",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+EXPORT_SYMBOL(s3c_device_pcm);
+

+ 1 - 0
arch/arm/mach-s3c64xx/mach-smdk6410.c

@@ -283,6 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
 	&s3c_device_fb,
 	&s3c_device_ohci,
 	&s3c_device_usb_hsotg,
+	&s3c_device_pcm,
 	&s3c64xx_device_iisv4,
 	&samsung_device_keypad,
 

+ 7 - 0
arch/arm/plat-omap/include/plat/mcbsp.h

@@ -30,6 +30,13 @@
 #include <mach/hardware.h>
 #include <plat/clock.h>
 
+/* macro for building platform_device for McBSP ports */
+#define OMAP_MCBSP_PLATFORM_DEVICE(port_nr)		\
+static struct platform_device omap_mcbsp##port_nr = {	\
+	.name	= "omap-mcbsp-dai",			\
+	.id	= OMAP_MCBSP##port_nr,			\
+}
+
 #define OMAP7XX_MCBSP1_BASE	0xfffb1000
 #define OMAP7XX_MCBSP2_BASE	0xfffb1800
 

+ 30 - 4
arch/arm/plat-s3c24xx/devs.c

@@ -247,7 +247,7 @@ static struct resource s3c_iis_resource[] = {
 static u64 s3c_device_iis_dmamask = 0xffffffffUL;
 
 struct platform_device s3c_device_iis = {
-	.name		  = "s3c2410-iis",
+	.name		  = "s3c24xx-iis",
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_iis_resource),
 	.resource	  = s3c_iis_resource,
@@ -259,6 +259,21 @@ struct platform_device s3c_device_iis = {
 
 EXPORT_SYMBOL(s3c_device_iis);
 
+/* ASoC PCM DMA */
+
+static u64 s3c_device_audio_dmamask = 0xffffffffUL;
+
+struct platform_device s3c_device_pcm = {
+	.name		  = "s3c24xx-pcm-audio",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c_device_pcm);
+
 /* RTC */
 
 static struct resource s3c_rtc_resource[] = {
@@ -481,19 +496,30 @@ static struct resource s3c_ac97_resource[] = {
 	},
 };
 
-static u64 s3c_device_ac97_dmamask = 0xffffffffUL;
-
 struct platform_device s3c_device_ac97 = {
 	.name		  = "s3c-ac97",
 	.id		  = -1,
 	.num_resources	  = ARRAY_SIZE(s3c_ac97_resource),
 	.resource	  = s3c_ac97_resource,
 	.dev              = {
-		.dma_mask = &s3c_device_ac97_dmamask,
+		.dma_mask = &s3c_device_audio_dmamask,
 		.coherent_dma_mask = 0xffffffffUL
 	}
 };
 
 EXPORT_SYMBOL(s3c_device_ac97);
 
+/* ASoC I2S */
+
+struct platform_device s3c2412_device_iis = {
+	.name		  = "s3c2412-iis",
+	.id		  = -1,
+	.dev              = {
+		.dma_mask = &s3c_device_audio_dmamask,
+		.coherent_dma_mask = 0xffffffffUL
+	}
+};
+
+EXPORT_SYMBOL(s3c2412_device_iis);
+
 #endif // CONFIG_CPU_S32440

+ 2 - 0
arch/arm/plat-samsung/include/plat/devs.h

@@ -32,6 +32,8 @@ extern struct platform_device s3c64xx_device_iisv4;
 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;
 

+ 6 - 0
arch/mips/alchemy/devboards/db1200/platform.c

@@ -429,6 +429,11 @@ static struct platform_device db1200_audio_dev = {
 	.resource	= au1200_psc1_res,
 };
 
+static struct platform_device db1200_stac_dev = {
+	.name		= "ac97-codec",
+	.id		= 1,	/* on PSC1 */
+};
+
 static struct platform_device *db1200_devs[] __initdata = {
 	NULL,		/* PSC0, selected by S6.8 */
 	&db1200_ide_dev,
@@ -436,6 +441,7 @@ static struct platform_device *db1200_devs[] __initdata = {
 	&db1200_rtc_dev,
 	&db1200_nand_dev,
 	&db1200_audio_dev,
+	&db1200_stac_dev,
 };
 
 static int __init db1200_dev_init(void)

+ 1 - 0
arch/powerpc/boot/dts/mpc8610_hpcd.dts

@@ -286,6 +286,7 @@
 
 		ssi@16100 {
 			compatible = "fsl,mpc8610-ssi";
+			status = "disabled";
 			cell-index = <1>;
 			reg = <0x16100 0x100>;
 			interrupt-parent = <&mpic>;

+ 3 - 0
arch/powerpc/configs/mpc85xx_defconfig

@@ -124,6 +124,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set

+ 3 - 0
arch/powerpc/configs/mpc85xx_smp_defconfig

@@ -126,6 +126,9 @@ CONFIG_I2C_CPM=m
 CONFIG_I2C_MPC=y
 # CONFIG_HWMON is not set
 CONFIG_VIDEO_OUTPUT_CONTROL=y
+CONFIG_FB=y
+CONFIG_FB_FSL_DIU=y
+# CONFIG_VGA_CONSOLE is not set
 CONFIG_SOUND=y
 CONFIG_SND=y
 # CONFIG_SND_SUPPORT_OLD_API is not set

+ 76 - 35
arch/powerpc/include/asm/immap_86xx.h → arch/powerpc/include/asm/fsl_guts.h

@@ -1,5 +1,5 @@
 /**
- * MPC86xx Internal Memory Map
+ * Freecale 85xx and 86xx Global Utilties register set
  *
  * Authors: Jeff Brown
  *          Timur Tabi <timur@freescale.com>
@@ -10,73 +10,112 @@
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
- *
- * This header file defines structures for various 86xx SOC devices that are
- * used by multiple source files.
  */
 
-#ifndef __ASM_POWERPC_IMMAP_86XX_H__
-#define __ASM_POWERPC_IMMAP_86XX_H__
+#ifndef __ASM_POWERPC_FSL_GUTS_H__
+#define __ASM_POWERPC_FSL_GUTS_H__
 #ifdef __KERNEL__
 
-/* Global Utility Registers */
-struct ccsr_guts {
+/*
+ * These #ifdefs are safe because it's not possible to build a kernel that
+ * runs on e500 and e600 cores.
+ */
+
+#if !defined(CONFIG_PPC_85xx) && !defined(CONFIG_PPC_86xx)
+#error Only 85xx and 86xx SOCs are supported
+#endif
+
+/**
+ * Global Utility Registers.
+ *
+ * Not all registers defined in this structure are available on all chips, so
+ * you are expected to know whether a given register actually exists on your
+ * chip before you access it.
+ *
+ * Also, some registers are similar on different chips but have slightly
+ * different names.  In these cases, one name is chosen to avoid extraneous
+ * #ifdefs.
+ */
+#ifdef CONFIG_PPC_85xx
+struct ccsr_guts_85xx {
+#else
+struct ccsr_guts_86xx {
+#endif
 	__be32	porpllsr;	/* 0x.0000 - POR PLL Ratio Status Register */
 	__be32	porbmsr;	/* 0x.0004 - POR Boot Mode Status Register */
 	__be32	porimpscr;	/* 0x.0008 - POR I/O Impedance Status and Control Register */
 	__be32	pordevsr;	/* 0x.000c - POR I/O Device Status Register */
 	__be32	pordbgmsr;	/* 0x.0010 - POR Debug Mode Status Register */
-	u8	res1[0x20 - 0x14];
+	__be32	pordevsr2;	/* 0x.0014 - POR device status register 2 */
+	u8	res018[0x20 - 0x18];
 	__be32	porcir;		/* 0x.0020 - POR Configuration Information Register */
-	u8	res2[0x30 - 0x24];
+	u8	res024[0x30 - 0x24];
 	__be32	gpiocr;		/* 0x.0030 - GPIO Control Register */
-	u8	res3[0x40 - 0x34];
+	u8	res034[0x40 - 0x34];
 	__be32	gpoutdr;	/* 0x.0040 - General-Purpose Output Data Register */
-	u8	res4[0x50 - 0x44];
+	u8	res044[0x50 - 0x44];
 	__be32	gpindr;		/* 0x.0050 - General-Purpose Input Data Register */
-	u8	res5[0x60 - 0x54];
+	u8	res054[0x60 - 0x54];
 	__be32	pmuxcr;		/* 0x.0060 - Alternate Function Signal Multiplex Control */
-	u8	res6[0x70 - 0x64];
+        __be32  pmuxcr2;	/* 0x.0064 - Alternate function signal multiplex control 2 */
+        __be32  dmuxcr;		/* 0x.0068 - DMA Mux Control Register */
+        u8	res06c[0x70 - 0x6c];
 	__be32	devdisr;	/* 0x.0070 - Device Disable Control */
 	__be32	devdisr2;	/* 0x.0074 - Device Disable Control 2 */
-	u8	res7[0x80 - 0x78];
+	u8	res078[0x7c - 0x78];
+	__be32  pmjcr;		/* 0x.007c - 4 Power Management Jog Control Register */
 	__be32	powmgtcsr;	/* 0x.0080 - Power Management Status and Control Register */
-	u8	res8[0x90 - 0x84];
+	__be32  pmrccr;		/* 0x.0084 - Power Management Reset Counter Configuration Register */
+	__be32  pmpdccr;	/* 0x.0088 - Power Management Power Down Counter Configuration Register */
+	__be32  pmcdr;		/* 0x.008c - 4Power management clock disable register */
 	__be32	mcpsumr;	/* 0x.0090 - Machine Check Summary Register */
 	__be32	rstrscr;	/* 0x.0094 - Reset Request Status and Control Register */
-	u8	res9[0xA0 - 0x98];
+	__be32  ectrstcr;	/* 0x.0098 - Exception reset control register */
+	__be32  autorstsr;	/* 0x.009c - Automatic reset status register */
 	__be32	pvr;		/* 0x.00a0 - Processor Version Register */
 	__be32	svr;		/* 0x.00a4 - System Version Register */
-	u8	res10[0xB0 - 0xA8];
+	u8	res0a8[0xb0 - 0xa8];
 	__be32	rstcr;		/* 0x.00b0 - Reset Control Register */
-	u8	res11[0xC0 - 0xB4];
+	u8	res0b4[0xc0 - 0xb4];
+#ifdef CONFIG_PPC_85xx
+	__be32  iovselsr;	/* 0x.00c0 - I/O voltage select status register */
+#else
 	__be32	elbcvselcr;	/* 0x.00c0 - eLBC Voltage Select Ctrl Reg */
-	u8	res12[0x800 - 0xC4];
+#endif
+	u8	res0c4[0x224 - 0xc4];
+	__be32  iodelay1;	/* 0x.0224 - IO delay control register 1 */
+	__be32  iodelay2;	/* 0x.0228 - IO delay control register 2 */
+	u8	res22c[0x800 - 0x22c];
 	__be32	clkdvdr;	/* 0x.0800 - Clock Divide Register */
-	u8	res13[0x900 - 0x804];
+	u8	res804[0x900 - 0x804];
 	__be32	ircr;		/* 0x.0900 - Infrared Control Register */
-	u8	res14[0x908 - 0x904];
+	u8	res904[0x908 - 0x904];
 	__be32	dmacr;		/* 0x.0908 - DMA Control Register */
-	u8	res15[0x914 - 0x90C];
+	u8	res90c[0x914 - 0x90c];
 	__be32	elbccr;		/* 0x.0914 - eLBC Control Register */
-	u8	res16[0xB20 - 0x918];
+	u8	res918[0xb20 - 0x918];
 	__be32	ddr1clkdr;	/* 0x.0b20 - DDR1 Clock Disable Register */
 	__be32	ddr2clkdr;	/* 0x.0b24 - DDR2 Clock Disable Register */
 	__be32	ddrclkdr;	/* 0x.0b28 - DDR Clock Disable Register */
-	u8	res17[0xE00 - 0xB2C];
+	u8	resb2c[0xe00 - 0xb2c];
 	__be32	clkocr;		/* 0x.0e00 - Clock Out Select Register */
-	u8	res18[0xE10 - 0xE04];
+	u8	rese04[0xe10 - 0xe04];
 	__be32	ddrdllcr;	/* 0x.0e10 - DDR DLL Control Register */
-	u8	res19[0xE20 - 0xE14];
+	u8	rese14[0xe20 - 0xe14];
 	__be32	lbcdllcr;	/* 0x.0e20 - LBC DLL Control Register */
-	u8	res20[0xF04 - 0xE24];
+	__be32  cpfor;		/* 0x.0e24 - L2 charge pump fuse override register */
+	u8	rese28[0xf04 - 0xe28];
 	__be32	srds1cr0;	/* 0x.0f04 - SerDes1 Control Register 0 */
 	__be32	srds1cr1;	/* 0x.0f08 - SerDes1 Control Register 0 */
-	u8	res21[0xF40 - 0xF0C];
-	__be32	srds2cr0;	/* 0x.0f40 - SerDes1 Control Register 0 */
-	__be32	srds2cr1;	/* 0x.0f44 - SerDes1 Control Register 0 */
+	u8	resf0c[0xf2c - 0xf0c];
+	__be32  itcr;		/* 0x.0f2c - Internal transaction control register */
+	u8	resf30[0xf40 - 0xf30];
+	__be32	srds2cr0;	/* 0x.0f40 - SerDes2 Control Register 0 */
+	__be32	srds2cr1;	/* 0x.0f44 - SerDes2 Control Register 0 */
 } __attribute__ ((packed));
 
+#ifdef CONFIG_PPC_86xx
+
 #define CCSR_GUTS_DMACR_DEV_SSI	0	/* DMA controller/channel set to SSI */
 #define CCSR_GUTS_DMACR_DEV_IR	1	/* DMA controller/channel set to IR */
 
@@ -93,7 +132,7 @@ struct ccsr_guts {
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * device: The device to set as the source (CCSR_GUTS_DMACR_DEV_xx)
  */
-static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
+static inline void guts_set_dmacr(struct ccsr_guts_86xx __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int device)
 {
 	unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
@@ -129,7 +168,7 @@ static inline void guts_set_dmacr(struct ccsr_guts __iomem *guts,
  * ch: The channel on the DMA controller (0, 1, 2, or 3)
  * value: the new value for the bit (0 or 1)
  */
-static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
+static inline void guts_set_pmuxcr_dma(struct ccsr_guts_86xx __iomem *guts,
 	unsigned int co, unsigned int ch, unsigned int value)
 {
 	if ((ch == 0) || (ch == 3)) {
@@ -152,5 +191,7 @@ static inline void guts_set_pmuxcr_dma(struct ccsr_guts __iomem *guts,
 #define CCSR_GUTS_CLKDVDR_SSICLK_MASK	0x000000FF
 #define CCSR_GUTS_CLKDVDR_SSICLK(x) ((x) & CCSR_GUTS_CLKDVDR_SSICLK_MASK)
 
-#endif /* __ASM_POWERPC_IMMAP_86XX_H__ */
-#endif /* __KERNEL__ */
+#endif
+
+#endif
+#endif

+ 209 - 2
arch/powerpc/platforms/85xx/p1022_ds.c

@@ -8,7 +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
  *
@@ -20,12 +19,211 @@
 #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 @@ static void __init p1022_ds_setup_arch(void)
 	}
 #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

+ 1 - 1
arch/sh/kernel/cpu/sh4a/setup-sh7722.c

@@ -551,7 +551,7 @@ static struct resource siu_resources[] = {
 };
 
 static struct platform_device siu_device = {
-	.name		= "sh_siu",
+	.name		= "siu-pcm-audio",
 	.id		= -1,
 	.dev = {
 		.platform_data	= &siu_platform_data,

+ 2 - 2
drivers/input/misc/twl4030-vibra.c

@@ -271,7 +271,7 @@ static struct platform_driver twl4030_vibra_driver = {
 	.probe		= twl4030_vibra_probe,
 	.remove		= __devexit_p(twl4030_vibra_remove),
 	.driver		= {
-		.name	= "twl4030_codec_vibra",
+		.name	= "twl4030-vibra",
 		.owner	= THIS_MODULE,
 #ifdef CONFIG_PM
 		.pm	= &twl4030_vibra_pm_ops,
@@ -291,7 +291,7 @@ static void __exit twl4030_vibra_exit(void)
 }
 module_exit(twl4030_vibra_exit);
 
-MODULE_ALIAS("platform:twl4030_codec_vibra");
+MODULE_ALIAS("platform:twl4030-vibra");
 
 MODULE_DESCRIPTION("TWL4030 Vibra driver");
 MODULE_LICENSE("GPL");

+ 3 - 3
drivers/mfd/twl-core.c

@@ -698,17 +698,17 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
 
 	if (twl_has_codec() && pdata->codec && twl_class_is_4030()) {
 		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-		child = add_child(sub_chip_id, "twl4030_codec",
+		child = add_child(sub_chip_id, "twl4030-audio",
 				pdata->codec, sizeof(*pdata->codec),
 				false, 0, 0);
 		if (IS_ERR(child))
 			return PTR_ERR(child);
 	}
 
-	/* Phoenix*/
+	/* Phoenix codec driver is probed directly atm */
 	if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
 		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
-		child = add_child(sub_chip_id, "twl6040_codec",
+		child = add_child(sub_chip_id, "twl6040-codec",
 				pdata->codec, sizeof(*pdata->codec),
 				false, 0, 0);
 		if (IS_ERR(child))

+ 4 - 4
drivers/mfd/twl4030-codec.c

@@ -207,14 +207,14 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
 
 	if (pdata->audio) {
 		cell = &codec->cells[childs];
-		cell->name = "twl4030_codec_audio";
+		cell->name = "twl4030-codec";
 		cell->platform_data = pdata->audio;
 		cell->data_size = sizeof(*pdata->audio);
 		childs++;
 	}
 	if (pdata->vibra) {
 		cell = &codec->cells[childs];
-		cell->name = "twl4030_codec_vibra";
+		cell->name = "twl4030-vibra";
 		cell->platform_data = pdata->vibra;
 		cell->data_size = sizeof(*pdata->vibra);
 		childs++;
@@ -249,14 +249,14 @@ static int __devexit twl4030_codec_remove(struct platform_device *pdev)
 	return 0;
 }
 
-MODULE_ALIAS("platform:twl4030_codec");
+MODULE_ALIAS("platform:twl4030-audio");
 
 static struct platform_driver twl4030_codec_driver = {
 	.probe		= twl4030_codec_probe,
 	.remove		= __devexit_p(twl4030_codec_remove),
 	.driver		= {
 		.owner	= THIS_MODULE,
-		.name	= "twl4030_codec",
+		.name	= "twl4030-audio",
 	},
 };
 

+ 1 - 1
drivers/staging/xgifb/TODO

@@ -12,4 +12,4 @@ TODO:
 - get rid of non-linux related stuff
 
 Please send patches to:
-Arnaud Patard <apatard@mandriva.com>
+Arnaud Patard <arnaud.patard@rtp-net.org>

+ 3 - 0
drivers/video/Kconfig

@@ -1919,6 +1919,9 @@ config FB_SH_MOBILE_HDMI
 	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.
 

+ 83 - 1
drivers/video/sh_mobile_hdmi.c

@@ -22,6 +22,8 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/workqueue.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
 
 #include <video/sh_mobile_hdmi.h>
 #include <video/sh_mobile_lcdc.h>
@@ -222,6 +224,58 @@ static u8 hdmi_read(struct sh_hdmi *hdmi, u8 reg)
 	return ioread8(hdmi->base + reg);
 }
 
+/*
+ *	HDMI sound
+ */
+static unsigned int sh_hdmi_snd_read(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+	return hdmi_read(hdmi, reg);
+}
+
+static int sh_hdmi_snd_write(struct snd_soc_codec *codec,
+			     unsigned int reg,
+			     unsigned int value)
+{
+	struct sh_hdmi *hdmi = snd_soc_codec_get_drvdata(codec);
+
+	hdmi_write(hdmi, value, reg);
+	return 0;
+}
+
+static struct snd_soc_dai_driver sh_hdmi_dai = {
+	.name = "sh_mobile_hdmi-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100  |
+			 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200  |
+			 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+			 SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+};
+
+static int sh_hdmi_snd_probe(struct snd_soc_codec *codec)
+{
+	dev_info(codec->dev, "SH Mobile HDMI Audio Codec");
+
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = {
+	.probe		= sh_hdmi_snd_probe,
+	.read		= sh_hdmi_snd_read,
+	.write		= sh_hdmi_snd_write,
+};
+
+/*
+ *	HDMI video
+ */
+
 /* External video parameter settings */
 static void hdmi_external_video_param(struct sh_hdmi *hdmi)
 {
@@ -318,6 +372,9 @@ static void sh_hdmi_video_config(struct sh_hdmi *hdmi)
  */
 static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 {
+	u8 data;
+	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
+
 	/*
 	 * [7:4] L/R data swap control
 	 * [3:0] appropriate N[19:16]
@@ -335,7 +392,23 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi)
 	 * [6:5] set required down sampling rate if required
 	 * [4:3] set required audio source
 	 */
-	hdmi_write(hdmi, 0x00, HDMI_AUDIO_SETTING_1);
+	switch (pdata->flags & HDMI_SND_SRC_MASK) {
+	default:
+		/* fall through */
+	case HDMI_SND_SRC_I2S:
+		data = 0x0 << 3;
+		break;
+	case HDMI_SND_SRC_SPDIF:
+		data = 0x1 << 3;
+		break;
+	case HDMI_SND_SRC_DSD:
+		data = 0x2 << 3;
+		break;
+	case HDMI_SND_SRC_HBR:
+		data = 0x3 << 3;
+		break;
+	}
+	hdmi_write(hdmi, data, HDMI_AUDIO_SETTING_1);
 
 	/* [3:0] set sending channel number for channel status */
 	hdmi_write(hdmi, 0x40, HDMI_AUDIO_SETTING_2);
@@ -891,6 +964,11 @@ static int __init sh_hdmi_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	}
 
+	ret =  snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1);
+	if (ret < 0)
+		goto esndreg;
+
 	hdmi->dev = &pdev->dev;
 
 	hdmi->hdmi_clk = clk_get(&pdev->dev, "ick");
@@ -976,6 +1054,8 @@ eclkenable:
 erate:
 	clk_put(hdmi->hdmi_clk);
 egetclk:
+	snd_soc_unregister_codec(&pdev->dev);
+esndreg:
 	kfree(hdmi);
 
 	return ret;
@@ -988,6 +1068,8 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev)
 	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	int irq = platform_get_irq(pdev, 0);
 
+	snd_soc_unregister_codec(&pdev->dev);
+
 	pdata->lcd_chan->board_cfg.display_on = NULL;
 	pdata->lcd_chan->board_cfg.display_off = NULL;
 	pdata->lcd_chan->board_cfg.board_data = NULL;

+ 5 - 1
include/linux/i2c/twl.h

@@ -553,8 +553,12 @@ extern void twl4030_power_init(struct twl4030_power_data *triton2_scripts);
 extern int twl4030_remove_script(u8 flags);
 
 struct twl4030_codec_audio_data {
-	unsigned int	audio_mclk;
+	unsigned int audio_mclk; /* not used, will be removed */
+	unsigned int digimic_delay; /* in ms */
 	unsigned int ramp_delay_value;
+	unsigned int offset_cncl_path;
+	unsigned int check_defaults:1;
+	unsigned int reset_registers:1;
 	unsigned int hs_extmute:1;
 	void (*set_hs_extmute)(int mute);
 };

+ 50 - 0
include/sound/max98088.h

@@ -0,0 +1,50 @@
+/*
+ * Platform data for MAX98088
+ *
+ * Copyright 2010 Maxim Integrated Products
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#ifndef __SOUND_MAX98088_PDATA_H__
+#define __SOUND_MAX98088_PDATA_H__
+
+/* Equalizer filter response configuration */
+struct max98088_eq_cfg {
+       const char *name;
+       unsigned int rate;
+       u16 band1[5];
+       u16 band2[5];
+       u16 band3[5];
+       u16 band4[5];
+       u16 band5[5];
+};
+
+/* codec platform data */
+struct max98088_pdata {
+
+       /* Equalizers for DAI1 and DAI2 */
+       struct max98088_eq_cfg *eq_cfg;
+       unsigned int eq_cfgcnt;
+
+       /* Receiver output can be configured as power amplifier or LINE out */
+       /* Set receiver_mode to:
+        * 0 = amplifier output, or
+        * 1 = LINE level output
+        */
+       unsigned int receiver_mode:1;
+
+       /* Analog/digital microphone configuration:
+        * 0 = analog microphone input (normal setting)
+        * 1 = digital microphone input
+        */
+       unsigned int digmic_left_mode:1;
+       unsigned int digmic_right_mode:1;
+
+};
+
+#endif

+ 0 - 3
include/sound/sh_fsi.h

@@ -114,7 +114,4 @@ struct sh_fsi_platform_info {
 	int (*set_rate)(int is_porta, int rate); /* for master mode */
 };
 
-extern struct snd_soc_dai fsi_soc_dai[2];
-extern struct snd_soc_platform fsi_soc_platform;
-
 #endif /* __SOUND_FSI_H */

+ 63 - 35
include/sound/soc-dai.h

@@ -91,15 +91,17 @@ struct snd_pcm_substream;
                                SNDRV_PCM_FMTBIT_S32_LE |\
                                SNDRV_PCM_FMTBIT_S32_BE)
 
-struct snd_soc_dai_ops;
+struct snd_soc_dai_driver;
 struct snd_soc_dai;
 struct snd_ac97_bus_ops;
 
 /* Digital Audio Interface registration */
-int snd_soc_register_dai(struct snd_soc_dai *dai);
-void snd_soc_unregister_dai(struct snd_soc_dai *dai);
-int snd_soc_register_dais(struct snd_soc_dai *dai, size_t count);
-void snd_soc_unregister_dais(struct snd_soc_dai *dai, size_t count);
+int snd_soc_register_dai(struct device *dev,
+		struct snd_soc_dai_driver *dai_drv);
+void snd_soc_unregister_dai(struct device *dev);
+int snd_soc_register_dais(struct device *dev,
+		struct snd_soc_dai_driver *dai_drv, size_t count);
+void snd_soc_unregister_dais(struct device *dev, size_t count);
 
 /* Digital Audio Interface clocking API.*/
 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -126,16 +128,6 @@ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
 /* Digital Audio Interface mute */
 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute);
 
-/*
- * Digital Audio Interface.
- *
- * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
- * operations and capabilities. Codec and platform drivers will register this
- * structure for every DAI they have.
- *
- * This structure covers the clocking, formating and ALSA operations for each
- * interface.
- */
 struct snd_soc_dai_ops {
 	/*
 	 * DAI clocking configuration, all optional.
@@ -191,24 +183,24 @@ struct snd_soc_dai_ops {
 };
 
 /*
- * Digital Audio Interface runtime data.
+ * Digital Audio Interface Driver.
  *
- * Holds runtime data for a DAI.
+ * Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
+ * operations and capabilities. Codec and platform drivers will register this
+ * structure for every DAI they have.
+ *
+ * This structure covers the clocking, formating and ALSA operations for each
+ * interface.
  */
-struct snd_soc_dai {
+struct snd_soc_dai_driver {
 	/* DAI description */
-	char *name;
+	const char *name;
 	unsigned int id;
 	int ac97_control;
 
-	struct device *dev;
-	void *ac97_pdata;	/* platform_data for the ac97 codec */
-
-	/* DAI callbacks */
-	int (*probe)(struct platform_device *pdev,
-		     struct snd_soc_dai *dai);
-	void (*remove)(struct platform_device *pdev,
-		       struct snd_soc_dai *dai);
+	/* DAI driver callbacks */
+	int (*probe)(struct snd_soc_dai *dai);
+	int (*remove)(struct snd_soc_dai *dai);
 	int (*suspend)(struct snd_soc_dai *dai);
 	int (*resume)(struct snd_soc_dai *dai);
 
@@ -219,26 +211,51 @@ struct snd_soc_dai {
 	struct snd_soc_pcm_stream capture;
 	struct snd_soc_pcm_stream playback;
 	unsigned int symmetric_rates:1;
+};
+
+/*
+ * Digital Audio Interface runtime data.
+ *
+ * Holds runtime data for a DAI.
+ */
+struct snd_soc_dai {
+	const char *name;
+	int id;
+	struct device *dev;
+	void *ac97_pdata;	/* platform_data for the ac97 codec */
+
+	/* driver ops */
+	struct snd_soc_dai_driver *driver;
 
 	/* DAI runtime info */
-	struct snd_soc_codec *codec;
+	unsigned int capture_active:1;		/* stream is in use */
+	unsigned int playback_active:1;		/* stream is in use */
+	unsigned int symmetric_rates:1;
+	struct snd_pcm_runtime *runtime;
 	unsigned int active;
 	unsigned char pop_wait:1;
+	unsigned char probed:1;
 
-	/* DAI private data */
-	void *private_data;
+	/* DAI DMA data */
+	void *playback_dma_data;
+	void *capture_dma_data;
 
-	/* parent platform */
-	struct snd_soc_platform *platform;
+	/* parent platform/codec */
+	union {
+		struct snd_soc_platform *platform;
+		struct snd_soc_codec *codec;
+	};
+	struct snd_soc_card *card;
 
 	struct list_head list;
+	struct list_head card_list;
 };
 
 static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
 					     const struct snd_pcm_substream *ss)
 {
 	return (ss->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-		dai->playback.dma_data : dai->capture.dma_data;
+		dai->playback_dma_data : dai->capture_dma_data;
 }
 
 static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
@@ -246,9 +263,20 @@ static inline void snd_soc_dai_set_dma_data(struct snd_soc_dai *dai,
 					    void *data)
 {
 	if (ss->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		dai->playback.dma_data = data;
+		dai->playback_dma_data = data;
 	else
-		dai->capture.dma_data = data;
+		dai->capture_dma_data = data;
+}
+
+static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
+		void *data)
+{
+	dev_set_drvdata(dai->dev, data);
+}
+
+static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
+{
+	return dev_get_drvdata(dai->dev);
 }
 
 #endif

+ 14 - 4
include/sound/soc-dapm.h

@@ -172,9 +172,19 @@
 #define SND_SOC_DAPM_AIF_IN(wname, stname, wslot, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
 	.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_IN_E(wname, stname, wslot, wreg, wshift, winvert, \
+			      wevent, wflags)				\
+{	.id = snd_soc_dapm_aif_in, .name = wname, .sname = stname, \
+	.reg = wreg, .shift = wshift, .invert = winvert, \
+	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_AIF_OUT(wname, stname, wslot, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
 	.reg = wreg, .shift = wshift, .invert = winvert }
+#define SND_SOC_DAPM_AIF_OUT_E(wname, stname, wslot, wreg, wshift, winvert, \
+			     wevent, wflags)				\
+{	.id = snd_soc_dapm_aif_out, .name = wname, .sname = stname, \
+	.reg = wreg, .shift = wshift, .invert = winvert, \
+	.event = wevent, .event_flags = wflags }
 #define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
 {	.id = snd_soc_dapm_dac, .name = wname, .sname = stname, .reg = wreg, \
 	.shift = wshift, .invert = winvert}
@@ -322,14 +332,14 @@ int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
 
 /* dapm path setup */
 int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
-void snd_soc_dapm_free(struct snd_soc_device *socdev);
+void snd_soc_dapm_free(struct snd_soc_codec *codec);
 int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
 			    const struct snd_soc_dapm_route *route, int num);
 
 /* dapm events */
-int snd_soc_dapm_stream_event(struct snd_soc_codec *codec, char *stream,
-	int event);
-void snd_soc_dapm_shutdown(struct snd_soc_device *socdev);
+int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd,
+	const char *stream, int event);
+void snd_soc_dapm_shutdown(struct snd_soc_card *card);
 
 /* dapm sys fs - used by the core */
 int snd_soc_dapm_sys_add(struct device *dev);

+ 0 - 25
include/sound/soc-of-simple.h

@@ -1,25 +0,0 @@
-/*
- * OF helpers for ALSA SoC
- *
- * Copyright (C) 2008, Secret Lab Technologies Ltd.
- */
-
-#ifndef _INCLUDE_SOC_OF_H_
-#define _INCLUDE_SOC_OF_H_
-
-#if defined(CONFIG_SND_SOC_OF_SIMPLE) || defined(CONFIG_SND_SOC_OF_SIMPLE_MODULE)
-
-#include <linux/of.h>
-#include <sound/soc.h>
-
-int of_snd_soc_register_codec(struct snd_soc_codec_device *codec_dev,
-			      void *codec_data, struct snd_soc_dai *dai,
-			      struct device_node *node);
-
-int of_snd_soc_register_platform(struct snd_soc_platform *platform,
-				 struct device_node *node,
-				 struct snd_soc_dai *cpu_dai);
-
-#endif
-
-#endif /* _INCLUDE_SOC_OF_H_ */

+ 148 - 97
include/sound/soc.h

@@ -214,10 +214,10 @@
  * @OFF:     Power Off. No restrictions on transition times.
  */
 enum snd_soc_bias_level {
-	SND_SOC_BIAS_ON,
-	SND_SOC_BIAS_PREPARE,
-	SND_SOC_BIAS_STANDBY,
 	SND_SOC_BIAS_OFF,
+	SND_SOC_BIAS_STANDBY,
+	SND_SOC_BIAS_PREPARE,
+	SND_SOC_BIAS_ON,
 };
 
 struct snd_jack;
@@ -228,13 +228,17 @@ struct snd_soc_ops;
 struct snd_soc_dai_mode;
 struct snd_soc_pcm_runtime;
 struct snd_soc_dai;
+struct snd_soc_dai_driver;
 struct snd_soc_platform;
 struct snd_soc_dai_link;
+struct snd_soc_platform_driver;
 struct snd_soc_codec;
+struct snd_soc_codec_driver;
 struct soc_enum;
 struct snd_soc_ac97_ops;
 struct snd_soc_jack;
 struct snd_soc_jack_pin;
+
 #ifdef CONFIG_GPIOLIB
 struct snd_soc_jack_gpio;
 #endif
@@ -249,19 +253,18 @@ enum snd_soc_control_type {
 	SND_SOC_SPI,
 };
 
-int snd_soc_register_platform(struct snd_soc_platform *platform);
-void snd_soc_unregister_platform(struct snd_soc_platform *platform);
-int snd_soc_register_codec(struct snd_soc_codec *codec);
-void snd_soc_unregister_codec(struct snd_soc_codec *codec);
+int snd_soc_register_platform(struct device *dev,
+		struct snd_soc_platform_driver *platform_drv);
+void snd_soc_unregister_platform(struct device *dev);
+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);
+void snd_soc_unregister_codec(struct device *dev);
 int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
 int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
 			       int addr_bits, int data_bits,
 			       enum snd_soc_control_type control);
 
-/* pcm <-> DAI connect */
-void snd_soc_free_pcms(struct snd_soc_device *socdev);
-int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid);
-
 /* Utility functions to get clock rates from various things */
 int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
 int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params);
@@ -273,7 +276,7 @@ int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
 	const struct snd_pcm_hardware *hw);
 
 /* Jack reporting */
-int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
+int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type,
 		     struct snd_soc_jack *jack);
 void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
 int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
@@ -382,7 +385,7 @@ struct snd_soc_jack_gpio {
 	int invert;
 	int debounce_time;
 	struct snd_soc_jack *jack;
-	struct work_struct work;
+	struct delayed_work work;
 
 	int (*jack_status_check)(void);
 };
@@ -390,7 +393,7 @@ struct snd_soc_jack_gpio {
 
 struct snd_soc_jack {
 	struct snd_jack *jack;
-	struct snd_soc_card *card;
+	struct snd_soc_codec *codec;
 	struct list_head pins;
 	int status;
 	struct blocking_notifier_head notifier;
@@ -398,15 +401,13 @@ struct snd_soc_jack {
 
 /* SoC PCM stream information */
 struct snd_soc_pcm_stream {
-	char *stream_name;
+	const char *stream_name;
 	u64 formats;			/* SNDRV_PCM_FMTBIT_* */
 	unsigned int rates;		/* SNDRV_PCM_RATE_* */
 	unsigned int rate_min;		/* min rate */
 	unsigned int rate_max;		/* max rate */
 	unsigned int channels_min;	/* min channels */
 	unsigned int channels_max;	/* max channels */
-	unsigned int active;		/* stream is in use */
-	void *dma_data;			/* used by platform code */
 };
 
 /* SoC audio ops */
@@ -419,44 +420,36 @@ struct snd_soc_ops {
 	int (*trigger)(struct snd_pcm_substream *, int);
 };
 
-/* SoC Audio Codec */
+/* SoC Audio Codec device */
 struct snd_soc_codec {
-	char *name;
-	struct module *owner;
-	struct mutex mutex;
+	const char *name;
+	int id;
 	struct device *dev;
-	struct snd_soc_device *socdev;
+	struct snd_soc_codec_driver *driver;
 
+	struct mutex mutex;
+	struct snd_soc_card *card;
 	struct list_head list;
-
-	/* callbacks */
-	int (*set_bias_level)(struct snd_soc_codec *,
-			      enum snd_soc_bias_level level);
+	struct list_head card_list;
+	int num_dai;
 
 	/* runtime */
-	struct snd_card *card;
 	struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
 	unsigned int active;
-	unsigned int pcm_devs;
-	void *drvdata;
+	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
+	unsigned int cache_only:1;  /* Suppress writes to hardware */
+	unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
+	unsigned int suspended:1; /* Codec is in suspend PM state */
+	unsigned int probed:1; /* Codec has been probed */
+	unsigned int ac97_registered:1; /* Codec has been AC97 registered */
+	unsigned int ac97_created:1; /* Codec has been created by SoC */
+	unsigned int sysfs_registered:1; /* codec has been sysfs registered */
 
 	/* codec IO */
 	void *control_data; /* codec control (i2c/3wire) data */
-	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
-	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
-	int (*display_register)(struct snd_soc_codec *, char *,
-				size_t, unsigned int);
-	int (*volatile_register)(unsigned int);
-	int (*readable_register)(unsigned int);
 	hw_write_t hw_write;
 	unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
 	void *reg_cache;
-	short reg_cache_size;
-	short reg_cache_step;
-
-	unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
-	unsigned int cache_only:1;  /* Suppress writes to hardware */
-	unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
 
 	/* dapm */
 	u32 pop_time;
@@ -466,10 +459,6 @@ struct snd_soc_codec {
 	enum snd_soc_bias_level suspend_bias_level;
 	struct delayed_work delayed_work;
 
-	/* codec DAI's */
-	struct snd_soc_dai *dai;
-	unsigned int num_dai;
-
 #ifdef CONFIG_DEBUG_FS
 	struct dentry *debugfs_codec_root;
 	struct dentry *debugfs_reg;
@@ -478,23 +467,40 @@ struct snd_soc_codec {
 #endif
 };
 
-/* codec device */
-struct snd_soc_codec_device {
-	int (*probe)(struct platform_device *pdev);
-	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct platform_device *pdev, pm_message_t state);
-	int (*resume)(struct platform_device *pdev);
+/* codec driver */
+struct snd_soc_codec_driver {
+
+	/* driver ops */
+	int (*probe)(struct snd_soc_codec *);
+	int (*remove)(struct snd_soc_codec *);
+	int (*suspend)(struct snd_soc_codec *,
+			pm_message_t state);
+	int (*resume)(struct snd_soc_codec *);
+
+	/* codec IO */
+	unsigned int (*read)(struct snd_soc_codec *, unsigned int);
+	int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
+	int (*display_register)(struct snd_soc_codec *, char *,
+				size_t, unsigned int);
+	int (*volatile_register)(unsigned int);
+	int (*readable_register)(unsigned int);
+	short reg_cache_size;
+	short reg_cache_step;
+	short reg_word_size;
+	const void *reg_cache_default;
+
+	/* codec bias level */
+	int (*set_bias_level)(struct snd_soc_codec *,
+			      enum snd_soc_bias_level level);
 };
 
 /* SoC platform interface */
-struct snd_soc_platform {
-	char *name;
-	struct list_head list;
+struct snd_soc_platform_driver {
 
-	int (*probe)(struct platform_device *pdev);
-	int (*remove)(struct platform_device *pdev);
-	int (*suspend)(struct snd_soc_dai_link *dai_link);
-	int (*resume)(struct snd_soc_dai_link *dai_link);
+	int (*probe)(struct snd_soc_platform *);
+	int (*remove)(struct snd_soc_platform *);
+	int (*suspend)(struct snd_soc_dai *dai);
+	int (*resume)(struct snd_soc_dai *dai);
 
 	/* pcm creation and destruction */
 	int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
@@ -509,23 +515,31 @@ struct snd_soc_platform {
 		struct snd_soc_dai *);
 
 	/* platform stream ops */
-	struct snd_pcm_ops *pcm_ops;
+	struct snd_pcm_ops *ops;
 };
 
-/* SoC machine DAI configuration, glues a codec and cpu DAI together */
-struct snd_soc_dai_link  {
-	char *name;			/* Codec name */
-	char *stream_name;		/* Stream name */
+struct snd_soc_platform {
+	const char *name;
+	int id;
+	struct device *dev;
+	struct snd_soc_platform_driver *driver;
 
-	/* DAI */
-	struct snd_soc_dai *codec_dai;
-	struct snd_soc_dai *cpu_dai;
+	unsigned int suspended:1; /* platform is suspended */
+	unsigned int probed:1;
 
-	/* machine stream operations */
-	struct snd_soc_ops *ops;
+	struct snd_soc_card *card;
+	struct list_head list;
+	struct list_head card_list;
+};
 
-	/* codec/machine specific init - e.g. add machine controls */
-	int (*init)(struct snd_soc_codec *codec);
+struct snd_soc_dai_link {
+	/* config - must be set by machine driver */
+	const char *name;			/* Codec name */
+	const char *stream_name;		/* Stream name */
+	const char *codec_name;		/* for multi-codec */
+	const char *platform_name;	/* for multi-platform */
+	const char *cpu_dai_name;
+	const char *codec_dai_name;
 
 	/* Keep DAI active over suspend */
 	unsigned int ignore_suspend:1;
@@ -533,21 +547,24 @@ struct snd_soc_dai_link  {
 	/* Symmetry requirements */
 	unsigned int symmetric_rates:1;
 
-	/* Symmetry data - only valid if symmetry is being enforced */
-	unsigned int rate;
+	/* codec/machine specific init - e.g. add machine controls */
+	int (*init)(struct snd_soc_pcm_runtime *rtd);
 
-	/* DAI pcm */
-	struct snd_pcm *pcm;
+	/* machine stream operations */
+	struct snd_soc_ops *ops;
 };
 
 /* SoC card */
 struct snd_soc_card {
-	char *name;
+	const char *name;
 	struct device *dev;
+	struct snd_card *snd_card;
+	struct module *owner;
 
 	struct list_head list;
+	struct mutex mutex;
 
-	int instantiated;
+	bool instantiated;
 
 	int (*probe)(struct platform_device *pdev);
 	int (*remove)(struct platform_device *pdev);
@@ -568,28 +585,38 @@ struct snd_soc_card {
 	/* CPU <--> Codec DAI links  */
 	struct snd_soc_dai_link *dai_link;
 	int num_links;
+	struct snd_soc_pcm_runtime *rtd;
+	int num_rtd;
 
-	struct snd_soc_device *socdev;
-
-	struct snd_soc_codec *codec;
-
-	struct snd_soc_platform *platform;
-	struct delayed_work delayed_work;
 	struct work_struct deferred_resume_work;
+
+	/* lists of probed devices belonging to this card */
+	struct list_head codec_dev_list;
+	struct list_head platform_dev_list;
+	struct list_head dai_dev_list;
 };
 
-/* SoC Device - the audio subsystem */
-struct snd_soc_device {
-	struct device *dev;
+/* SoC machine DAI configuration, glues a codec and cpu DAI together */
+struct snd_soc_pcm_runtime  {
+	struct device dev;
 	struct snd_soc_card *card;
-	struct snd_soc_codec_device *codec_dev;
-	void *codec_data;
-};
+	struct snd_soc_dai_link *dai_link;
+
+	unsigned int complete:1;
+	unsigned int dev_registered:1;
+
+	/* Symmetry data - only valid if symmetry is being enforced */
+	unsigned int rate;
+	long pmdown_time;
 
-/* runtime channel data */
-struct snd_soc_pcm_runtime {
-	struct snd_soc_dai_link *dai;
-	struct snd_soc_device *socdev;
+	/* runtime devices */
+	struct snd_pcm *pcm;
+	struct snd_soc_codec *codec;
+	struct snd_soc_platform *platform;
+	struct snd_soc_dai *codec_dai;
+	struct snd_soc_dai *cpu_dai;
+
+	struct delayed_work delayed_work;
 };
 
 /* mixer control */
@@ -615,24 +642,48 @@ struct soc_enum {
 static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
 					unsigned int reg)
 {
-	return codec->read(codec, reg);
+	return codec->driver->read(codec, reg);
 }
 
 static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
 					 unsigned int reg, unsigned int val)
 {
-	return codec->write(codec, reg, val);
+	return codec->driver->write(codec, reg, val);
 }
 
+/* device driver data */
+
 static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
-					     void *data)
+		void *data)
 {
-	codec->drvdata = data;
+	dev_set_drvdata(codec->dev, data);
 }
 
 static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
 {
-	return codec->drvdata;
+	return dev_get_drvdata(codec->dev);
+}
+
+static inline void snd_soc_platform_set_drvdata(struct snd_soc_platform *platform,
+		void *data)
+{
+	dev_set_drvdata(platform->dev, data);
+}
+
+static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platform)
+{
+	return dev_get_drvdata(platform->dev);
+}
+
+static inline void snd_soc_pcm_set_drvdata(struct snd_soc_pcm_runtime *rtd,
+		void *data)
+{
+	dev_set_drvdata(&rtd->dev, data);
+}
+
+static inline void *snd_soc_pcm_get_drvdata(struct snd_soc_pcm_runtime *rtd)
+{
+	return dev_get_drvdata(&rtd->dev);
 }
 
 #include <sound/soc-dai.h>

+ 42 - 1
include/sound/tlv320aic3x.h

@@ -10,8 +10,49 @@
 #ifndef __TLV320AIC3x_H__
 #define __TLV320AIC3x_H__
 
+/* GPIO API */
+enum {
+	AIC3X_GPIO1_FUNC_DISABLED		= 0,
+	AIC3X_GPIO1_FUNC_AUDIO_WORDCLK_ADC	= 1,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX		= 2,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV2		= 3,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV4		= 4,
+	AIC3X_GPIO1_FUNC_CLOCK_MUX_DIV8		= 5,
+	AIC3X_GPIO1_FUNC_SHORT_CIRCUIT_IRQ	= 6,
+	AIC3X_GPIO1_FUNC_AGC_NOISE_IRQ		= 7,
+	AIC3X_GPIO1_FUNC_INPUT			= 8,
+	AIC3X_GPIO1_FUNC_OUTPUT			= 9,
+	AIC3X_GPIO1_FUNC_DIGITAL_MIC_MODCLK	= 10,
+	AIC3X_GPIO1_FUNC_AUDIO_WORDCLK		= 11,
+	AIC3X_GPIO1_FUNC_BUTTON_IRQ		= 12,
+	AIC3X_GPIO1_FUNC_HEADSET_DETECT_IRQ	= 13,
+	AIC3X_GPIO1_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ	= 14,
+	AIC3X_GPIO1_FUNC_ALL_IRQ		= 16
+};
+
+enum {
+	AIC3X_GPIO2_FUNC_DISABLED		= 0,
+	AIC3X_GPIO2_FUNC_HEADSET_DETECT_IRQ	= 2,
+	AIC3X_GPIO2_FUNC_INPUT			= 3,
+	AIC3X_GPIO2_FUNC_OUTPUT			= 4,
+	AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT	= 5,
+	AIC3X_GPIO2_FUNC_AUDIO_BITCLK		= 8,
+	AIC3X_GPIO2_FUNC_HEADSET_DETECT_OR_BUTTON_IRQ = 9,
+	AIC3X_GPIO2_FUNC_ALL_IRQ		= 10,
+	AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_OR_AGC_IRQ = 11,
+	AIC3X_GPIO2_FUNC_HEADSET_OR_BUTTON_PRESS_OR_SHORT_CIRCUIT_IRQ = 12,
+	AIC3X_GPIO2_FUNC_SHORT_CIRCUIT_IRQ	= 13,
+	AIC3X_GPIO2_FUNC_AGC_NOISE_IRQ		= 14,
+	AIC3X_GPIO2_FUNC_BUTTON_PRESS_IRQ	= 15
+};
+
+struct aic3x_setup_data {
+	unsigned int gpio_func[2];
+};
+
 struct aic3x_pdata {
 	int gpio_reset; /* < 0 if not used */
+	struct aic3x_setup_data *setup;
 };
 
-#endif
+#endif

+ 32 - 0
include/sound/wm8962.h

@@ -0,0 +1,32 @@
+/*
+ * wm8962.h  --  WM8962 Soc Audio driver platform data
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _WM8962_PDATA_H
+#define _WM8962_PDATA_H
+
+#define WM8962_MAX_GPIO 6
+
+/* Use to set GPIO default values to zero */
+#define WM8962_GPIO_SET 0x10000
+
+struct wm8962_pdata {
+	int gpio_base;
+	u32 gpio_init[WM8962_MAX_GPIO];
+
+	/* Setup for microphone detection, raw value to be written to
+	 * R48(0x30) - only microphone related bits will be updated.
+	 * Detection may be enabled here for use with signals brought
+	 * out on the GPIOs. */
+	u32 mic_cfg;
+
+	bool irq_active_low;
+
+	bool spk_mono;   /* Speaker outputs tied together as mono */
+};
+
+#endif

+ 16 - 0
include/video/sh_mobile_hdmi.h

@@ -14,9 +14,25 @@
 struct sh_mobile_lcdc_chan_cfg;
 struct device;
 
+/*
+ * flags format
+ *
+ * 0x0000000A
+ *
+ * A: Audio source select
+ */
+
+/* Audio source select */
+#define HDMI_SND_SRC_MASK	(0xF << 0)
+#define HDMI_SND_SRC_I2S	(0 << 0) /* default */
+#define HDMI_SND_SRC_SPDIF	(1 << 0)
+#define HDMI_SND_SRC_DSD	(2 << 0)
+#define HDMI_SND_SRC_HBR	(3 << 0)
+
 struct sh_mobile_hdmi_info {
 	struct sh_mobile_lcdc_chan_cfg	*lcd_chan;
 	struct device			*lcd_dev;
+	unsigned int			 flags;
 };
 
 #endif

+ 36 - 23
sound/soc/atmel/atmel-pcm.c

@@ -179,7 +179,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 	runtime->dma_bytes = params_buffer_bytes(params);
 
-	prtd->params = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
+	prtd->params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 	prtd->params->dma_intr_handler = atmel_pcm_dma_irq;
 
 	prtd->dma_buffer = runtime->dma_addr;
@@ -374,14 +374,14 @@ static int atmel_pcm_new(struct snd_card *card,
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = 0xffffffff;
 
-	if (dai->playback.channels_min) {
+	if (dai->driver->playback.channels_min) {
 		ret = atmel_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_PLAYBACK);
 		if (ret)
 			goto out;
 	}
 
-	if (dai->capture.channels_min) {
+	if (dai->driver->capture.channels_min) {
 		pr_debug("at32-pcm:"
 				"Allocating PCM capture DMA buffer\n");
 		ret = atmel_pcm_preallocate_dma_buffer(pcm,
@@ -414,12 +414,9 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
 }
 
 #ifdef CONFIG_PM
-static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_suspend(struct snd_soc_dai *dai)
 {
-	struct snd_pcm *pcm = dai_link->pcm;
-	struct snd_pcm_str *stream = &pcm->streams[0];
-	struct snd_pcm_substream *substream = stream->substream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = dai->runtime;
 	struct atmel_runtime_data *prtd;
 	struct atmel_pcm_dma_params *params;
 
@@ -441,12 +438,9 @@ static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
 	return 0;
 }
 
-static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
+static int atmel_pcm_resume(struct snd_soc_dai *dai)
 {
-	struct snd_pcm *pcm = dai_link->pcm;
-	struct snd_pcm_str *stream = &pcm->streams[0];
-	struct snd_pcm_substream *substream = stream->substream;
-	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_pcm_runtime *runtime = dai->runtime;
 	struct atmel_runtime_data *prtd;
 	struct atmel_pcm_dma_params *params;
 
@@ -470,27 +464,46 @@ static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
 #define atmel_pcm_resume	NULL
 #endif
 
-struct snd_soc_platform atmel_soc_platform = {
-	.name		= "atmel-audio",
-	.pcm_ops 	= &atmel_pcm_ops,
+static struct snd_soc_platform_driver atmel_soc_platform = {
+	.ops		= &atmel_pcm_ops,
 	.pcm_new	= atmel_pcm_new,
 	.pcm_free	= atmel_pcm_free_dma_buffers,
 	.suspend	= atmel_pcm_suspend,
 	.resume		= atmel_pcm_resume,
 };
-EXPORT_SYMBOL_GPL(atmel_soc_platform);
 
-static int __init atmel_pcm_modinit(void)
+static int __devinit atmel_soc_platform_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_platform(&pdev->dev, &atmel_soc_platform);
+}
+
+static int __devexit atmel_soc_platform_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver atmel_pcm_driver = {
+	.driver = {
+			.name = "atmel-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = atmel_soc_platform_probe,
+	.remove = __devexit_p(atmel_soc_platform_remove),
+};
+
+static int __init snd_atmel_pcm_init(void)
 {
-	return snd_soc_register_platform(&atmel_soc_platform);
+	return platform_driver_register(&atmel_pcm_driver);
 }
-module_init(atmel_pcm_modinit);
+module_init(snd_atmel_pcm_init);
 
-static void __exit atmel_pcm_modexit(void)
+static void __exit snd_atmel_pcm_exit(void)
 {
-	snd_soc_unregister_platform(&atmel_soc_platform);
+	platform_driver_unregister(&atmel_pcm_driver);
 }
-module_exit(atmel_pcm_modexit);
+module_exit(snd_atmel_pcm_exit);
 
 MODULE_AUTHOR("Sedji Gaouaou <sedji.gaouaou@atmel.com>");
 MODULE_DESCRIPTION("Atmel PCM module");

+ 0 - 3
sound/soc/atmel/atmel-pcm.h

@@ -74,9 +74,6 @@ struct atmel_pcm_dma_params {
 	void (*dma_intr_handler)(u32, struct snd_pcm_substream *);
 };
 
-extern struct snd_soc_platform atmel_soc_platform;
-
-
 /*
  * SSC register access (since ssc_writel() / ssc_readl() require literal name)
  */

+ 123 - 25
sound/soc/atmel/atmel_ssc_dai.c

@@ -205,8 +205,7 @@ static irqreturn_t atmel_ssc_interrupt(int irq, void *dev_id)
 static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-	struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
 	int dir_mask;
 
 	pr_debug("atmel_ssc_startup: SSC_SR=0x%u\n",
@@ -235,8 +234,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream,
 static void atmel_ssc_shutdown(struct snd_pcm_substream *substream,
 			       struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-	struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
 	struct atmel_pcm_dma_params *dma_params;
 	int dir, dir_mask;
 
@@ -338,7 +336,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-	int id = rtd->dai->cpu_dai->id;
+	int id = dai->id;
 	struct atmel_ssc_info *ssc_p = &ssc_info[id];
 	struct atmel_pcm_dma_params *dma_params;
 	int dir, channels, bits;
@@ -368,7 +366,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 	 * function.  It should not be used for other purposes
 	 * as it is common to all substreams.
 	 */
-	snd_soc_dai_set_dma_data(rtd->dai->cpu_dai, substream, dma_params);
+	snd_soc_dai_set_dma_data(rtd->cpu_dai, substream, dma_params);
 
 	channels = params_channels(params);
 
@@ -605,8 +603,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
 static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
 			     struct snd_soc_dai *dai)
 {
-	struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream);
-	struct atmel_ssc_info *ssc_p = &ssc_info[rtd->dai->cpu_dai->id];
+	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
 	struct atmel_pcm_dma_params *dma_params;
 	int dir;
 
@@ -690,6 +687,32 @@ static int atmel_ssc_resume(struct snd_soc_dai *cpu_dai)
 #  define atmel_ssc_resume	NULL
 #endif /* CONFIG_PM */
 
+static int atmel_ssc_probe(struct snd_soc_dai *dai)
+{
+	struct atmel_ssc_info *ssc_p = &ssc_info[dai->id];
+	int ret = 0;
+
+	snd_soc_dai_set_drvdata(dai, ssc_p);
+
+	/*
+	 * Request SSC device
+	 */
+	ssc_p->ssc = ssc_request(dai->id);
+	if (IS_ERR(ssc_p->ssc)) {
+		printk(KERN_ERR "ASoC: Failed to request SSC %d\n", dai->id);
+		ret = PTR_ERR(ssc_p->ssc);
+	}
+
+	return ret;
+}
+
+static int atmel_ssc_remove(struct snd_soc_dai *dai)
+{
+	struct atmel_ssc_info *ssc_p = snd_soc_dai_get_drvdata(dai);
+
+	ssc_free(ssc_p->ssc);
+	return 0;
+}
 
 #define ATMEL_SSC_RATES (SNDRV_PCM_RATE_8000_96000)
 
@@ -705,9 +728,11 @@ static struct snd_soc_dai_ops atmel_ssc_dai_ops = {
 	.set_clkdiv	= atmel_ssc_set_dai_clkdiv,
 };
 
-struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
-	{	.name = "atmel-ssc0",
-		.id = 0,
+static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
+	{
+		.name = "atmel-ssc-dai.0",
+		.probe = atmel_ssc_probe,
+		.remove = atmel_ssc_remove,
 		.suspend = atmel_ssc_suspend,
 		.resume = atmel_ssc_resume,
 		.playback = {
@@ -721,11 +746,12 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
 			.rates = ATMEL_SSC_RATES,
 			.formats = ATMEL_SSC_FORMATS,},
 		.ops = &atmel_ssc_dai_ops,
-		.private_data = &ssc_info[0],
 	},
 #if NUM_SSC_DEVICES == 3
-	{	.name = "atmel-ssc1",
-		.id = 1,
+	{
+		.name = "atmel-ssc-dai.1",
+		.probe = atmel_ssc_probe,
+		.remove = atmel_ssc_remove,
 		.suspend = atmel_ssc_suspend,
 		.resume = atmel_ssc_resume,
 		.playback = {
@@ -739,10 +765,11 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
 			.rates = ATMEL_SSC_RATES,
 			.formats = ATMEL_SSC_FORMATS,},
 		.ops = &atmel_ssc_dai_ops,
-		.private_data = &ssc_info[1],
 	},
-	{	.name = "atmel-ssc2",
-		.id = 2,
+	{
+		.name = "atmel-ssc-dai.2",
+		.probe = atmel_ssc_probe,
+		.remove = atmel_ssc_remove,
 		.suspend = atmel_ssc_suspend,
 		.resume = atmel_ssc_resume,
 		.playback = {
@@ -756,23 +783,94 @@ struct snd_soc_dai atmel_ssc_dai[NUM_SSC_DEVICES] = {
 			.rates = ATMEL_SSC_RATES,
 			.formats = ATMEL_SSC_FORMATS,},
 		.ops = &atmel_ssc_dai_ops,
-		.private_data = &ssc_info[2],
 	},
 #endif
 };
-EXPORT_SYMBOL_GPL(atmel_ssc_dai);
 
-static int __init atmel_ssc_modinit(void)
+static __devinit int asoc_ssc_probe(struct platform_device *pdev)
+{
+	BUG_ON(pdev->id < 0);
+	BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
+	return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
+}
+
+static int __devexit asoc_ssc_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_ssc_driver = {
+	.driver = {
+			.name = "atmel-ssc-dai",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = asoc_ssc_probe,
+	.remove = __devexit_p(asoc_ssc_remove),
+};
+
+/**
+ * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
+ */
+int atmel_ssc_set_audio(int ssc_id)
+{
+	struct ssc_device *ssc;
+	static struct platform_device *dma_pdev;
+	struct platform_device *ssc_pdev;
+	int ret;
+
+	if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
+		return -EINVAL;
+
+	/* Allocate a dummy device for DMA if we don't have one already */
+	if (!dma_pdev) {
+		dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
+		if (!dma_pdev)
+			return -ENOMEM;
+
+		ret = platform_device_add(dma_pdev);
+		if (ret < 0) {
+			platform_device_put(dma_pdev);
+			dma_pdev = NULL;
+			return ret;
+		}
+	}
+
+	ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
+	if (!ssc_pdev) {
+		ssc_free(ssc);
+		return -ENOMEM;
+	}
+
+	/* If we can grab the SSC briefly to parent the DAI device off it */
+	ssc = ssc_request(ssc_id);
+	if (IS_ERR(ssc))
+		pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
+			PTR_ERR(ssc));
+	else
+		ssc_pdev->dev.parent = &(ssc->pdev->dev);
+	ssc_free(ssc);
+
+	ret = platform_device_add(ssc_pdev);
+	if (ret < 0)
+		platform_device_put(ssc_pdev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
+
+static int __init snd_atmel_ssc_init(void)
 {
-	return snd_soc_register_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+	return platform_driver_register(&asoc_ssc_driver);
 }
-module_init(atmel_ssc_modinit);
+module_init(snd_atmel_ssc_init);
 
-static void __exit atmel_ssc_modexit(void)
+static void __exit snd_atmel_ssc_exit(void)
 {
-	snd_soc_unregister_dais(atmel_ssc_dai, ARRAY_SIZE(atmel_ssc_dai));
+	platform_driver_unregister(&asoc_ssc_driver);
 }
-module_exit(atmel_ssc_modexit);
+module_exit(snd_atmel_ssc_exit);
 
 /* Module information */
 MODULE_AUTHOR("Sedji Gaouaou, sedji.gaouaou@atmel.com, www.atmel.com");

+ 2 - 1
sound/soc/atmel/atmel_ssc_dai.h

@@ -116,6 +116,7 @@ struct atmel_ssc_info {
 	struct atmel_pcm_dma_params *dma_params[2];
 	struct atmel_ssc_state ssc_state;
 };
-extern struct snd_soc_dai atmel_ssc_dai[];
+
+int atmel_ssc_set_audio(int ssc);
 
 #endif /* _AT91_SSC_DAI_H */

+ 12 - 53
sound/soc/atmel/playpaq_wm8510.c

@@ -83,7 +83,7 @@ static struct ssc_clock_data playpaq_wm8510_calc_ssc_clock(
 	struct snd_pcm_hw_params *params,
 	struct snd_soc_dai *cpu_dai)
 {
-	struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+	struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
 	struct ssc_device *ssc = ssc_p->ssc;
 	struct ssc_clock_data cd;
 	unsigned int rate, width_bits, channels;
@@ -131,9 +131,9 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream,
 				    struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	struct at32_ssc_info *ssc_p = cpu_dai->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct at32_ssc_info *ssc_p = snd_soc_dai_get_drvdata(cpu_dai);
 	struct ssc_device *ssc = ssc_p->ssc;
 	unsigned int pll_out = 0, bclk = 0, mclk_div = 0;
 	int ret;
@@ -315,8 +315,9 @@ static const struct snd_soc_dapm_route intercon[] = {
 
 
 
-static int playpaq_wm8510_init(struct snd_soc_codec *codec)
+static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_codec *codec = rtd->codec;
 	int i;
 
 	/*
@@ -342,7 +343,7 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
 
 
 	/* Make CSB show PLL rate */
-	snd_soc_dai_set_clkdiv(codec->dai, WM8510_OPCLKDIV,
+	snd_soc_dai_set_clkdiv(rtd->codec_dai, WM8510_OPCLKDIV,
 				       WM8510_OPCLKDIV_1 | 4);
 
 	return 0;
@@ -353,8 +354,10 @@ static int playpaq_wm8510_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link playpaq_wm8510_dai = {
 	.name = "WM8510",
 	.stream_name = "WM8510 PCM",
-	.cpu_dai = &at32_ssc_dai[0],
-	.codec_dai = &wm8510_dai,
+	.cpu_dai_name= "atmel-ssc-dai.0",
+	.platform_name = "atmel-pcm-audio",
+	.codec_name = "wm8510-codec.0-0x1a",
+	.codec_dai_name = "wm8510-hifi",
 	.init = playpaq_wm8510_init,
 	.ops = &playpaq_wm8510_ops,
 };
@@ -363,46 +366,16 @@ static struct snd_soc_dai_link playpaq_wm8510_dai = {
 
 static struct snd_soc_card snd_soc_playpaq = {
 	.name = "LRS_PlayPaq_WM8510",
-	.platform = &at32_soc_platform,
 	.dai_link = &playpaq_wm8510_dai,
 	.num_links = 1,
 };
 
-
-
-static struct wm8510_setup_data playpaq_wm8510_setup = {
-	.i2c_bus = 0,
-	.i2c_address = 0x1a,
-};
-
-
-
-static struct snd_soc_device playpaq_wm8510_snd_devdata = {
-	.card = &snd_soc_playpaq,
-	.codec_dev = &soc_codec_dev_wm8510,
-	.codec_data = &playpaq_wm8510_setup,
-};
-
 static struct platform_device *playpaq_snd_device;
 
 
 static int __init playpaq_asoc_init(void)
 {
 	int ret = 0;
-	struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
-	struct ssc_device *ssc = NULL;
-
-
-	/*
-	 * Request SSC device
-	 */
-	ssc = ssc_request(0);
-	if (IS_ERR(ssc)) {
-		ret = PTR_ERR(ssc);
-		goto err_ssc;
-	}
-	ssc_p->ssc = ssc;
-
 
 	/*
 	 * Configure MCLK for WM8510
@@ -439,8 +412,7 @@ static int __init playpaq_asoc_init(void)
 		goto err_device_alloc;
 	}
 
-	platform_set_drvdata(playpaq_snd_device, &playpaq_wm8510_snd_devdata);
-	playpaq_wm8510_snd_devdata.dev = &playpaq_snd_device->dev;
+	platform_set_drvdata(playpaq_snd_device, &snd_soc_playpaq);
 
 	ret = platform_device_add(playpaq_snd_device);
 	if (ret) {
@@ -468,25 +440,12 @@ err_pll0:
 		clk_put(_gclk0);
 		_gclk0 = NULL;
 	}
-err_gclk0:
-	ssc_free(ssc);
-err_ssc:
 	return ret;
 }
 
 
 static void __exit playpaq_asoc_exit(void)
 {
-	struct at32_ssc_info *ssc_p = playpaq_wm8510_dai.cpu_dai->private_data;
-	struct ssc_device *ssc;
-
-	if (ssc_p != NULL) {
-		ssc = ssc_p->ssc;
-		if (ssc != NULL)
-			ssc_free(ssc);
-		ssc_p->ssc = NULL;
-	}
-
 	if (_gclk0 != NULL) {
 		clk_put(_gclk0);
 		_gclk0 = NULL;

+ 17 - 42
sound/soc/atmel/sam9g20_wm8731.c

@@ -69,8 +69,8 @@ static int at91sam9g20ek_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int ret;
 
 	/* set codec DAI configuration */
@@ -136,16 +136,17 @@ static const struct snd_soc_dapm_route intercon[] = {
 /*
  * Logic for a wm8731 as connected on a at91sam9g20ek board.
  */
-static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
+static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
 {
-	struct snd_soc_dai *codec_dai = &codec->dai[0];
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	int ret;
 
 	printk(KERN_DEBUG
 			"at91sam9g20ek_wm8731 "
 			": at91sam9g20ek_wm8731_init() called\n");
 
-	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
 		MCLK_RATE, SND_SOC_CLOCK_IN);
 	if (ret < 0) {
 		printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
@@ -179,37 +180,37 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link at91sam9g20ek_dai = {
 	.name = "WM8731",
 	.stream_name = "WM8731 PCM",
-	.cpu_dai = &atmel_ssc_dai[0],
-	.codec_dai = &wm8731_dai,
+	.cpu_dai_name = "atmel-ssc-dai.0",
+	.codec_dai_name = "wm8731-hifi",
 	.init = at91sam9g20ek_wm8731_init,
+	.platform_name = "atmel-pcm-audio",
+	.codec_name = "wm8731-codec.0-001b",
 	.ops = &at91sam9g20ek_ops,
 };
 
 static struct snd_soc_card snd_soc_at91sam9g20ek = {
 	.name = "AT91SAMG20-EK",
-	.platform = &atmel_soc_platform,
 	.dai_link = &at91sam9g20ek_dai,
 	.num_links = 1,
 	.set_bias_level = at91sam9g20ek_set_bias_level,
 };
 
-static struct snd_soc_device at91sam9g20ek_snd_devdata = {
-	.card = &snd_soc_at91sam9g20ek,
-	.codec_dev = &soc_codec_dev_wm8731,
-};
-
 static struct platform_device *at91sam9g20ek_snd_device;
 
 static int __init at91sam9g20ek_init(void)
 {
-	struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
-	struct ssc_device *ssc = NULL;
 	struct clk *pllb;
 	int ret;
 
 	if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
 		return -ENODEV;
 
+	ret = atmel_ssc_set_audio(0);
+	if (ret != 0) {
+		pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+		return ret;
+	}
+
 	/*
 	 * Codec MCLK is supplied by PCK0 - set it up.
 	 */
@@ -235,18 +236,6 @@ static int __init at91sam9g20ek_init(void)
 
 	clk_set_rate(mclk, MCLK_RATE);
 
-	/*
-	 * Request SSC device
-	 */
-	ssc = ssc_request(0);
-	if (IS_ERR(ssc)) {
-		printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
-		ret = PTR_ERR(ssc);
-		ssc = NULL;
-		goto err_ssc;
-	}
-	ssc_p->ssc = ssc;
-
 	at91sam9g20ek_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!at91sam9g20ek_snd_device) {
 		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
@@ -254,8 +243,7 @@ static int __init at91sam9g20ek_init(void)
 	}
 
 	platform_set_drvdata(at91sam9g20ek_snd_device,
-			&at91sam9g20ek_snd_devdata);
-	at91sam9g20ek_snd_devdata.dev = &at91sam9g20ek_snd_device->dev;
+			&snd_soc_at91sam9g20ek);
 
 	ret = platform_device_add(at91sam9g20ek_snd_device);
 	if (ret) {
@@ -265,9 +253,6 @@ static int __init at91sam9g20ek_init(void)
 
 	return ret;
 
-err_ssc:
-	ssc_free(ssc);
-	ssc_p->ssc = NULL;
 err_mclk:
 	clk_put(mclk);
 	mclk = NULL;
@@ -277,16 +262,6 @@ err:
 
 static void __exit at91sam9g20ek_exit(void)
 {
-	struct atmel_ssc_info *ssc_p = at91sam9g20ek_dai.cpu_dai->private_data;
-	struct ssc_device *ssc;
-
-	if (ssc_p != NULL) {
-		ssc = ssc_p->ssc;
-		if (ssc != NULL)
-			ssc_free(ssc);
-		ssc_p->ssc = NULL;
-	}
-
 	platform_device_unregister(at91sam9g20ek_snd_device);
 	at91sam9g20ek_snd_device = NULL;
 	clk_put(mclk);

+ 9 - 26
sound/soc/atmel/snd-soc-afeb9260.c

@@ -46,8 +46,8 @@ static int afeb9260_hw_params(struct snd_pcm_substream *substream,
 			 struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int err;
 
 	/* Set codec DAI configuration */
@@ -102,8 +102,9 @@ static const struct snd_soc_dapm_route audio_map[] = {
 	{"MICIN", NULL, "Mic Jack"},
 };
 
-static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
+static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_codec *codec = rtd->codec;
 
 	/* Add afeb9260 specific widgets */
 	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
@@ -125,8 +126,10 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_codec *codec)
 static struct snd_soc_dai_link afeb9260_dai = {
 	.name = "TLV320AIC23",
 	.stream_name = "AIC23",
-	.cpu_dai = &atmel_ssc_dai[0],
-	.codec_dai = &tlv320aic23_dai,
+	.cpu_dai_name = "atmel-ssc-dai.0",
+	.codec_dai_name = "tlv320aic23-hifi",
+	.platform_name = "atmel_pcm-audio",
+	.codec_name = "tlv320aic23-codec.0-0x1a",
 	.init = afeb9260_tlv320aic23_init,
 	.ops = &afeb9260_ops,
 };
@@ -134,37 +137,20 @@ static struct snd_soc_dai_link afeb9260_dai = {
 /* Audio machine driver */
 static struct snd_soc_card snd_soc_machine_afeb9260 = {
 	.name = "AFEB9260",
-	.platform = &atmel_soc_platform,
 	.dai_link = &afeb9260_dai,
 	.num_links = 1,
 };
 
-/* Audio subsystem */
-static struct snd_soc_device afeb9260_snd_devdata = {
-	.card = &snd_soc_machine_afeb9260,
-	.codec_dev = &soc_codec_dev_tlv320aic23,
-};
-
 static struct platform_device *afeb9260_snd_device;
 
 static int __init afeb9260_soc_init(void)
 {
 	int err;
 	struct device *dev;
-	struct atmel_ssc_info *ssc_p = afeb9260_dai.cpu_dai->private_data;
-	struct ssc_device *ssc = NULL;
 
 	if (!(machine_is_afeb9260()))
 		return -ENODEV;
 
-	ssc = ssc_request(0);
-	if (IS_ERR(ssc)) {
-		printk(KERN_ERR "ASoC: Failed to request SSC 0\n");
-		err = PTR_ERR(ssc);
-		ssc = NULL;
-		goto err_ssc;
-	}
-	ssc_p->ssc = ssc;
 
 	afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
 	if (!afeb9260_snd_device) {
@@ -172,8 +158,7 @@ static int __init afeb9260_soc_init(void)
 		return -ENOMEM;
 	}
 
-	platform_set_drvdata(afeb9260_snd_device, &afeb9260_snd_devdata);
-	afeb9260_snd_devdata.dev = &afeb9260_snd_device->dev;
+	platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
 	err = platform_device_add(afeb9260_snd_device);
 	if (err)
 		goto err1;
@@ -184,9 +169,7 @@ static int __init afeb9260_soc_init(void)
 err1:
 	platform_device_del(afeb9260_snd_device);
 	platform_device_put(afeb9260_snd_device);
-err_ssc:
 	return err;
-
 }
 
 static void __exit afeb9260_soc_exit(void)

+ 14 - 25
sound/soc/au1x/db1200.c

@@ -19,7 +19,6 @@
 #include <asm/mach-au1x00/au1xxx_dbdma.h>
 #include <asm/mach-db1x00/bcsr.h>
 
-#include "../codecs/ac97.h"
 #include "../codecs/wm8731.h"
 #include "psc.h"
 
@@ -28,20 +27,16 @@
 static struct snd_soc_dai_link db1200_ac97_dai = {
 	.name		= "AC97",
 	.stream_name	= "AC97 HiFi",
-	.cpu_dai	= &au1xpsc_ac97_dai,
-	.codec_dai	= &ac97_dai,
+	.codec_dai_name	= "ac97-hifi",
+	.cpu_dai_name	= "au1xpsc_ac97.1",
+	.platform_name	= "au1xpsc-pcm.1",
+	.codec_name	= "ac97-codec.1",
 };
 
 static struct snd_soc_card db1200_ac97_machine = {
 	.name		= "DB1200_AC97",
 	.dai_link	= &db1200_ac97_dai,
 	.num_links	= 1,
-	.platform	= &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_ac97_devdata = {
-	.card		= &db1200_ac97_machine,
-	.codec_dev	= &soc_codec_dev_ac97,
 };
 
 /*-------------------------  I2S PART  ---------------------------*/
@@ -49,12 +44,12 @@ static struct snd_soc_device db1200_ac97_devdata = {
 static int db1200_i2s_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int ret;
 
 	/* WM8731 has its own 12MHz crystal */
-	snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK,
+	snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
 				12000000, SND_SOC_CLOCK_IN);
 
 	/* codec is bitclock and lrclk master */
@@ -80,8 +75,10 @@ static struct snd_soc_ops db1200_i2s_wm8731_ops = {
 static struct snd_soc_dai_link db1200_i2s_dai = {
 	.name		= "WM8731",
 	.stream_name	= "WM8731 PCM",
-	.cpu_dai	= &au1xpsc_i2s_dai,
-	.codec_dai	= &wm8731_dai,
+	.codec_dai_name	= "wm8731-hifi",
+	.cpu_dai_name	= "au1xpsc_i2s.1",
+	.platform_name	= "au1xpsc-pcm.1",
+	.codec_name	= "wm8731-codec.0-001b",
 	.ops		= &db1200_i2s_wm8731_ops,
 };
 
@@ -89,12 +86,6 @@ static struct snd_soc_card db1200_i2s_machine = {
 	.name		= "DB1200_I2S",
 	.dai_link	= &db1200_i2s_dai,
 	.num_links	= 1,
-	.platform	= &au1xpsc_soc_platform,
-};
-
-static struct snd_soc_device db1200_i2s_devdata = {
-	.card		= &db1200_i2s_machine,
-	.codec_dev	= &soc_codec_dev_wm8731,
 };
 
 /*-------------------------  COMMON PART  ---------------------------*/
@@ -106,18 +97,16 @@ static int __init db1200_audio_load(void)
 	int ret;
 
 	ret = -ENOMEM;
-	db1200_asoc_dev = platform_device_alloc("soc-audio", -1);
+	db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
 	if (!db1200_asoc_dev)
 		goto out;
 
 	/* DB1200 board setup set PSC1MUX to preferred audio device */
 	if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
-		platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_devdata);
+		platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
 	else
-		platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_devdata);
+		platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
 
-	db1200_ac97_devdata.dev = &db1200_asoc_dev->dev;
-	db1200_i2s_devdata.dev = &db1200_asoc_dev->dev;
 	ret = platform_device_add(db1200_asoc_dev);
 
 	if (ret) {

+ 29 - 66
sound/soc/au1x/dbdma2.c

@@ -10,9 +10,6 @@
  *
  * DMA glue for Au1x-PSC audio.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *	 of a PSC. Multiple independent audio devices are impossible
- *	 with ASoC v1.
  */
 
 
@@ -61,9 +58,6 @@ struct au1xpsc_audio_dmadata {
 	int msbits;
 };
 
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
-
 /*
  * These settings are somewhat okay, at least on my machine audio plays
  * almost skip-free. Especially the 64kB buffer seems to help a LOT.
@@ -199,6 +193,14 @@ out:
 	return 0;
 }
 
+static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream *ss)
+{
+	struct snd_soc_pcm_runtime *rtd = ss->private_data;
+	struct au1xpsc_audio_dmadata *pcd =
+				snd_soc_platform_get_drvdata(rtd->platform);
+	return &pcd[SUBSTREAM_TYPE(ss)];
+}
+
 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params)
 {
@@ -211,7 +213,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
 		goto out;
 
 	stype = SUBSTREAM_TYPE(substream);
-	pcd = au1xpsc_audio_pcmdma[stype];
+	pcd = to_dmadata(substream);
 
 	DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
 	    "runtime->min_align %d\n",
@@ -249,8 +251,7 @@ static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 {
-	struct au1xpsc_audio_dmadata *pcd =
-			au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
+	struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
 
 	au1xxx_dbdma_reset(pcd->ddma_chan);
 
@@ -267,7 +268,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-	u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
+	u32 c = to_dmadata(substream)->ddma_chan;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -287,8 +288,7 @@ static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 static snd_pcm_uframes_t
 au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
 {
-	return bytes_to_frames(substream->runtime,
-		au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
+	return bytes_to_frames(substream->runtime, to_dmadata(substream)->pos);
 }
 
 static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
@@ -299,7 +299,7 @@ static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
 
 static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
 {
-	au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
+	au1x_pcm_dbdma_free(to_dmadata(substream));
 	return 0;
 }
 
@@ -329,42 +329,21 @@ static int au1xpsc_pcm_new(struct snd_card *card,
 	return 0;
 }
 
-static int au1xpsc_pcm_probe(struct platform_device *pdev)
-{
-	if (!au1xpsc_audio_pcmdma[PCM_TX] || !au1xpsc_audio_pcmdma[PCM_RX])
-		return -ENODEV;
-
-	return 0;
-}
-
-static int au1xpsc_pcm_remove(struct platform_device *pdev)
-{
-	return 0;
-}
-
 /* au1xpsc audio platform */
-struct snd_soc_platform au1xpsc_soc_platform = {
-	.name		= "au1xpsc-pcm-dbdma",
-	.probe		= au1xpsc_pcm_probe,
-	.remove		= au1xpsc_pcm_remove,
-	.pcm_ops 	= &au1xpsc_pcm_ops,
+struct snd_soc_platform_driver au1xpsc_soc_platform = {
+	.ops		= &au1xpsc_pcm_ops,
 	.pcm_new	= au1xpsc_pcm_new,
 	.pcm_free	= au1xpsc_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
 
 static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 {
+	struct au1xpsc_audio_dmadata *dmadata;
 	struct resource *r;
 	int ret;
 
-	if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
-		return -EBUSY;
-
-	/* TX DMA */
-	au1xpsc_audio_pcmdma[PCM_TX]
-		= kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
-	if (!au1xpsc_audio_pcmdma[PCM_TX])
+	dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
+	if (!dmadata)
 		return -ENOMEM;
 
 	r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -372,47 +351,33 @@ static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
 		ret = -ENODEV;
 		goto out1;
 	}
-	(au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
+	dmadata[PCM_TX].ddma_id = r->start;
 
 	/* RX DMA */
-	au1xpsc_audio_pcmdma[PCM_RX]
-		= kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
-	if (!au1xpsc_audio_pcmdma[PCM_RX])
-		return -ENOMEM;
-
 	r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
 	if (!r) {
 		ret = -ENODEV;
-		goto out2;
+		goto out1;
 	}
-	(au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
+	dmadata[PCM_RX].ddma_id = r->start;
+
+	platform_set_drvdata(pdev, dmadata);
 
-	ret = snd_soc_register_platform(&au1xpsc_soc_platform);
+	ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
 	if (!ret)
 		return ret;
 
-out2:
-	kfree(au1xpsc_audio_pcmdma[PCM_RX]);
-	au1xpsc_audio_pcmdma[PCM_RX] = NULL;
 out1:
-	kfree(au1xpsc_audio_pcmdma[PCM_TX]);
-	au1xpsc_audio_pcmdma[PCM_TX] = NULL;
+	kfree(dmadata);
 	return ret;
 }
 
 static int __devexit au1xpsc_pcm_drvremove(struct platform_device *pdev)
 {
-	int i;
+	struct au1xpsc_audio_dmadata *dmadata = platform_get_drvdata(pdev);
 
-	snd_soc_unregister_platform(&au1xpsc_soc_platform);
-
-	for (i = 0; i < 2; i++) {
-		if (au1xpsc_audio_pcmdma[i]) {
-			au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
-			kfree(au1xpsc_audio_pcmdma[i]);
-			au1xpsc_audio_pcmdma[i] = NULL;
-		}
-	}
+	snd_soc_unregister_platform(&pdev->dev);
+	kfree(dmadata);
 
 	return 0;
 }
@@ -428,8 +393,6 @@ static struct platform_driver au1xpsc_pcm_driver = {
 
 static int __init au1xpsc_audio_dbdma_load(void)
 {
-	au1xpsc_audio_pcmdma[PCM_TX] = NULL;
-	au1xpsc_audio_pcmdma[PCM_RX] = NULL;
 	return platform_driver_register(&au1xpsc_pcm_driver);
 }
 
@@ -467,7 +430,7 @@ struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
 	res[1].start = res[1].end = id[1];
 	res[0].flags = res[1].flags = IORESOURCE_DMA;
 
-	pd = platform_device_alloc("au1xpsc-pcm", -1);
+	pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
 	if (!pd)
 		goto out;
 

+ 37 - 34
sound/soc/au1x/psc-ac97.c

@@ -10,9 +10,6 @@
  *
  * Au1xxx-PSC AC97 glue.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *	 of a PSC. Multiple independent audio devices are impossible
- *	 with ASoC v1.
  */
 
 #include <linux/init.h>
@@ -56,12 +53,29 @@
 /* instance data. There can be only one, MacLeod!!!! */
 static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
 
+#if 0
+
+/* this could theoretically work, but ac97->bus->card->private_data can be NULL
+ * when snd_ac97_mixer() is called; I don't know if the rest further down the
+ * chain are always valid either.
+ */
+static inline struct au1xpsc_audio_data *ac97_to_pscdata(struct snd_ac97 *x)
+{
+	struct snd_soc_card *c = x->bus->card->private_data;
+	return snd_soc_dai_get_drvdata(c->rtd->cpu_dai);
+}
+
+#else
+
+#define ac97_to_pscdata(x)	au1xpsc_ac97_workdata
+
+#endif
+
 /* AC97 controller reads codec register */
 static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
 					unsigned short reg)
 {
-	/* FIXME */
-	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
 	unsigned short retry, tmo;
 	unsigned long data;
 
@@ -102,8 +116,7 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97,
 static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 				unsigned short val)
 {
-	/* FIXME */
-	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
 	unsigned int tmo, retry;
 
 	au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata));
@@ -134,8 +147,7 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
 /* AC97 controller asserts a warm reset */
 static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
 {
-	/* FIXME */
-	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
 
 	au_writel(PSC_AC97RST_SNC, AC97_RST(pscdata));
 	au_sync();
@@ -146,8 +158,7 @@ static void au1xpsc_ac97_warm_reset(struct snd_ac97 *ac97)
 
 static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97)
 {
-	/* FIXME */
-	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+	struct au1xpsc_audio_data *pscdata = ac97_to_pscdata(ac97);
 	int i;
 
 	/* disable PSC during cold reset */
@@ -202,8 +213,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
 				  struct snd_pcm_hw_params *params,
 				  struct snd_soc_dai *dai)
 {
-	/* FIXME */
-	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
 	unsigned long r, ro, stat;
 	int chans, t, stype = SUBSTREAM_TYPE(substream);
 
@@ -283,8 +293,7 @@ out:
 static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
 				int cmd, struct snd_soc_dai *dai)
 {
-	/* FIXME */
-	struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata;
+	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
 	int ret, stype = SUBSTREAM_TYPE(substream);
 
 	ret = 0;
@@ -315,27 +324,19 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int au1xpsc_ac97_probe(struct platform_device *pdev,
-			      struct snd_soc_dai *dai)
+static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
 {
 	return au1xpsc_ac97_workdata ? 0 : -ENODEV;
 }
 
-static void au1xpsc_ac97_remove(struct platform_device *pdev,
-				struct snd_soc_dai *dai)
-{
-}
-
 static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
 	.trigger	= au1xpsc_ac97_trigger,
 	.hw_params	= au1xpsc_ac97_hw_params,
 };
 
-struct snd_soc_dai au1xpsc_ac97_dai = {
-	.name			= "au1xpsc_ac97",
+static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
 	.ac97_control		= 1,
 	.probe			= au1xpsc_ac97_probe,
-	.remove			= au1xpsc_ac97_remove,
 	.playback = {
 		.rates		= AC97_RATES,
 		.formats	= AC97_FMTS,
@@ -350,7 +351,6 @@ struct snd_soc_dai au1xpsc_ac97_dai = {
 	},
 	.ops = &au1xpsc_ac97_dai_ops,
 };
-EXPORT_SYMBOL_GPL(au1xpsc_ac97_dai);
 
 static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 {
@@ -359,9 +359,6 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 	unsigned long sel;
 	struct au1xpsc_audio_data *wd;
 
-	if (au1xpsc_ac97_workdata)
-		return -EBUSY;
-
 	wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
 	if (!wd)
 		return -ENOMEM;
@@ -395,18 +392,24 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
 	au_writel(PSC_SEL_PS_AC97MODE | sel, PSC_SEL(wd));
 	au_sync();
 
-	ret = snd_soc_register_dai(&au1xpsc_ac97_dai);
+	/* name the DAI like this device instance ("au1xpsc-ac97.PSCINDEX") */
+	memcpy(&wd->dai_drv, &au1xpsc_ac97_dai_template,
+	       sizeof(struct snd_soc_dai_driver));
+	wd->dai_drv.name = dev_name(&pdev->dev);
+
+	platform_set_drvdata(pdev, wd);
+
+	ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
 	if (ret)
 		goto out1;
 
 	wd->dmapd = au1xpsc_pcm_add(pdev);
 	if (wd->dmapd) {
-		platform_set_drvdata(pdev, wd);
-		au1xpsc_ac97_workdata = wd;	/* MDEV */
+		au1xpsc_ac97_workdata = wd;
 		return 0;
 	}
 
-	snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+	snd_soc_unregister_dai(&pdev->dev);
 out1:
 	release_mem_region(r->start, resource_size(r));
 out0:
@@ -422,7 +425,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
 	if (wd->dmapd)
 		au1xpsc_pcm_destroy(wd->dmapd);
 
-	snd_soc_unregister_dai(&au1xpsc_ac97_dai);
+	snd_soc_unregister_dai(&pdev->dev);
 
 	/* disable PSC completely */
 	au_writel(0, AC97_CFG(wd));

+ 15 - 38
sound/soc/au1x/psc-i2s.c

@@ -10,9 +10,6 @@
  *
  * Au1xxx-PSC I2S glue.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *	 of a PSC. Multiple independent audio devices are impossible
- *	 with ASoC v1.
  * NOTE: so far only PSC slave mode (bit- and frameclock) is supported.
  */
 
@@ -54,13 +51,10 @@
 	((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
 
 
-/* instance data. There can be only one, MacLeod!!!! */
-static struct au1xpsc_audio_data *au1xpsc_i2s_workdata;
-
 static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
 			       unsigned int fmt)
 {
-	struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(cpu_dai);
 	unsigned long ct;
 	int ret;
 
@@ -120,7 +114,7 @@ static int au1xpsc_i2s_hw_params(struct snd_pcm_substream *substream,
 				 struct snd_pcm_hw_params *params,
 				 struct snd_soc_dai *dai)
 {
-	struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
 
 	int cfgbits;
 	unsigned long stat;
@@ -245,7 +239,7 @@ static int au1xpsc_i2s_stop(struct au1xpsc_audio_data *pscdata, int stype)
 static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 			       struct snd_soc_dai *dai)
 {
-	struct au1xpsc_audio_data *pscdata = au1xpsc_i2s_workdata;
+	struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
 	int ret, stype = SUBSTREAM_TYPE(substream);
 
 	switch (cmd) {
@@ -263,27 +257,13 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
 	return ret;
 }
 
-static int au1xpsc_i2s_probe(struct platform_device *pdev,
-			     struct snd_soc_dai *dai)
-{
-	return 	au1xpsc_i2s_workdata ? 0 : -ENODEV;
-}
-
-static void au1xpsc_i2s_remove(struct platform_device *pdev,
-			       struct snd_soc_dai *dai)
-{
-}
-
 static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
 	.trigger	= au1xpsc_i2s_trigger,
 	.hw_params	= au1xpsc_i2s_hw_params,
 	.set_fmt	= au1xpsc_i2s_set_fmt,
 };
 
-struct snd_soc_dai au1xpsc_i2s_dai = {
-	.name			= "au1xpsc_i2s",
-	.probe			= au1xpsc_i2s_probe,
-	.remove			= au1xpsc_i2s_remove,
+static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
 	.playback = {
 		.rates		= AU1XPSC_I2S_RATES,
 		.formats	= AU1XPSC_I2S_FMTS,
@@ -298,7 +278,6 @@ struct snd_soc_dai au1xpsc_i2s_dai = {
 	},
 	.ops = &au1xpsc_i2s_dai_ops,
 };
-EXPORT_SYMBOL(au1xpsc_i2s_dai);
 
 static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 {
@@ -307,9 +286,6 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 	int ret;
 	struct au1xpsc_audio_data *wd;
 
-	if (au1xpsc_i2s_workdata)
-		return -EBUSY;
-
 	wd = kzalloc(sizeof(struct au1xpsc_audio_data), GFP_KERNEL);
 	if (!wd)
 		return -ENOMEM;
@@ -346,19 +322,23 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
 	 * time out.
 	 */
 
-	ret = snd_soc_register_dai(&au1xpsc_i2s_dai);
+	/* name the DAI like this device instance ("au1xpsc-i2s.PSCINDEX") */
+	memcpy(&wd->dai_drv, &au1xpsc_i2s_dai_template,
+	       sizeof(struct snd_soc_dai_driver));
+	wd->dai_drv.name = dev_name(&pdev->dev);
+
+	platform_set_drvdata(pdev, wd);
+
+	ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
 	if (ret)
 		goto out1;
 
 	/* finally add the DMA device for this PSC */
 	wd->dmapd = au1xpsc_pcm_add(pdev);
-	if (wd->dmapd) {
-		platform_set_drvdata(pdev, wd);
-		au1xpsc_i2s_workdata = wd;
+	if (wd->dmapd)
 		return 0;
-	}
 
-	snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+	snd_soc_unregister_dai(&pdev->dev);
 out1:
 	release_mem_region(r->start, resource_size(r));
 out0:
@@ -374,7 +354,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 	if (wd->dmapd)
 		au1xpsc_pcm_destroy(wd->dmapd);
 
-	snd_soc_unregister_dai(&au1xpsc_i2s_dai);
+	snd_soc_unregister_dai(&pdev->dev);
 
 	au_writel(0, I2S_CFG(wd));
 	au_sync();
@@ -385,8 +365,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
 	release_mem_region(r->start, resource_size(r));
 	kfree(wd);
 
-	au1xpsc_i2s_workdata = NULL;	/* MDEV */
-
 	return 0;
 }
 
@@ -446,7 +424,6 @@ static struct platform_driver au1xpsc_i2s_driver = {
 
 static int __init au1xpsc_i2s_load(void)
 {
-	au1xpsc_i2s_workdata = NULL;
 	return platform_driver_register(&au1xpsc_i2s_driver);
 }
 

+ 2 - 8
sound/soc/au1x/psc.h

@@ -8,19 +8,11 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  *
- * NOTE: all of these drivers can only work with a SINGLE instance
- *	 of a PSC. Multiple independent audio devices are impossible
- *	 with ASoC v1.
  */
 
 #ifndef _AU1X_PCM_H
 #define _AU1X_PCM_H
 
-extern struct snd_soc_dai au1xpsc_ac97_dai;
-extern struct snd_soc_dai au1xpsc_i2s_dai;
-extern struct snd_soc_platform au1xpsc_soc_platform;
-extern struct snd_ac97_bus_ops soc_ac97_ops;
-
 /* DBDMA helpers */
 extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
 extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
@@ -31,6 +23,8 @@ struct au1xpsc_audio_data {
 	unsigned long cfg;
 	unsigned long rate;
 
+	struct snd_soc_dai_driver dai_drv;
+
 	unsigned long pm[2];
 	struct mutex lock;
 	struct platform_device *dmapd;

+ 31 - 12
sound/soc/blackfin/bf5xx-ac97-pcm.c

@@ -422,14 +422,14 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	if (dai->playback.channels_min) {
+	if (dai->driver->playback.channels_min) {
 		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_PLAYBACK);
 		if (ret)
 			goto out;
 	}
 
-	if (dai->capture.channels_min) {
+	if (dai->driver->capture.channels_min) {
 		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_CAPTURE);
 		if (ret)
@@ -439,25 +439,44 @@ int bf5xx_pcm_ac97_new(struct snd_card *card, struct snd_soc_dai *dai,
 	return ret;
 }
 
-struct snd_soc_platform bf5xx_ac97_soc_platform = {
-	.name		= "bf5xx-audio",
-	.pcm_ops 	= &bf5xx_pcm_ac97_ops,
+static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = {
+	.ops			= &bf5xx_pcm_ac97_ops,
 	.pcm_new	= bf5xx_pcm_ac97_new,
 	.pcm_free	= bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_ac97_soc_platform);
 
-static int __init bfin_ac97_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_platform(&bf5xx_ac97_soc_platform);
+	return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform);
 }
-module_init(bfin_ac97_init);
 
-static void __exit bfin_ac97_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_platform(&bf5xx_ac97_soc_platform);
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver bf5xx_pcm_driver = {
+	.driver = {
+			.name = "bf5xx-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = bf5xx_soc_platform_probe,
+	.remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bf5xx_pcm_init(void)
+{
+	return platform_driver_register(&bf5xx_pcm_driver);
+}
+module_init(snd_bf5xx_pcm_init);
+
+static void __exit snd_bf5xx_pcm_exit(void)
+{
+	platform_driver_unregister(&bf5xx_pcm_driver);
 }
-module_exit(bfin_ac97_exit);
+module_exit(snd_bf5xx_pcm_exit);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin AC97 PCM DMA module");

+ 0 - 3
sound/soc/blackfin/bf5xx-ac97-pcm.h

@@ -23,7 +23,4 @@ struct bf5xx_gpio {
 	u32 frm;
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_ac97_soc_platform;
-
 #endif

+ 30 - 11
sound/soc/blackfin/bf5xx-ac97.c

@@ -255,7 +255,7 @@ EXPORT_SYMBOL_GPL(soc_ac97_ops);
 #ifdef CONFIG_PM
 static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 {
-	struct sport_device *sport = dai->private_data;
+	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	if (!dai->active)
@@ -270,7 +270,7 @@ static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
 static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 {
 	int ret;
-	struct sport_device *sport = dai->private_data;
+	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 	if (!dai->active)
@@ -306,8 +306,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
 #define bf5xx_ac97_resume	NULL
 #endif
 
-static int bf5xx_ac97_probe(struct platform_device *pdev,
-			    struct snd_soc_dai *dai)
+static int bf5xx_ac97_probe(struct snd_soc_dai *dai)
 {
 	int ret = 0;
 	cmd_count = (int *)get_zeroed_page(GFP_KERNEL);
@@ -379,8 +378,7 @@ peripheral_err:
 	return ret;
 }
 
-static void bf5xx_ac97_remove(struct platform_device *pdev,
-			      struct snd_soc_dai *dai)
+static int bf5xx_ac97_remove(struct snd_soc_dai *dai)
 {
 	free_page((unsigned long)cmd_count);
 	cmd_count = NULL;
@@ -388,11 +386,10 @@ static void bf5xx_ac97_remove(struct platform_device *pdev,
 #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
 #endif
+	return 0;
 }
 
-struct snd_soc_dai bfin_ac97_dai = {
-	.name = "bf5xx-ac97",
-	.id = 0,
+struct snd_soc_dai_driver bfin_ac97_dai = {
 	.ac97_control = 1,
 	.probe = bf5xx_ac97_probe,
 	.remove = bf5xx_ac97_remove,
@@ -417,18 +414,40 @@ struct snd_soc_dai bfin_ac97_dai = {
 };
 EXPORT_SYMBOL_GPL(bfin_ac97_dai);
 
+static __devinit int asoc_bfin_ac97_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai);
+}
+
+static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver asoc_bfin_ac97_driver = {
+	.driver = {
+			.name = "bfin-ac97",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = asoc_bfin_ac97_probe,
+	.remove = __devexit_p(asoc_bfin_ac97_remove),
+};
+
 static int __init bfin_ac97_init(void)
 {
-	return snd_soc_register_dai(&bfin_ac97_dai);
+	return platform_driver_register(&asoc_bfin_ac97_driver);
 }
 module_init(bfin_ac97_init);
 
 static void __exit bfin_ac97_exit(void)
 {
-	snd_soc_unregister_dai(&bfin_ac97_dai);
+	platform_driver_unregister(&asoc_bfin_ac97_driver);
 }
 module_exit(bfin_ac97_exit);
 
+
 MODULE_AUTHOR("Roy Huang");
 MODULE_DESCRIPTION("AC97 driver for ADI Blackfin");
 MODULE_LICENSE("GPL");

+ 0 - 2
sound/soc/blackfin/bf5xx-ac97.h

@@ -50,8 +50,6 @@ struct ac97_frame {
 #define TAG_PCM_SR		0x0080
 #define TAG_PCM_LFE		0x0040
 
-extern struct snd_soc_dai bfin_ac97_dai;
-
 void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, \
 		size_t count, unsigned int chan_mask);
 

+ 9 - 14
sound/soc/blackfin/bf5xx-ad1836.c

@@ -40,9 +40,9 @@ static struct snd_soc_card bf5xx_ad1836;
 static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-	cpu_dai->private_data = sport_handle;
+	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
 	return 0;
 }
 
@@ -50,8 +50,8 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
 	int ret = 0;
 	/* set cpu DAI configuration */
@@ -83,23 +83,19 @@ static struct snd_soc_ops bf5xx_ad1836_ops = {
 static struct snd_soc_dai_link bf5xx_ad1836_dai = {
 	.name = "ad1836",
 	.stream_name = "AD1836",
-	.cpu_dai = &bf5xx_tdm_dai,
-	.codec_dai = &ad1836_dai,
+	.cpu_dai_name = "bf5xx-tdm",
+	.codec_dai_name = "ad1836-hifi",
+	.platform_name = "bf5xx-tdm-pcm-audio",
+	.codec_name = "ad1836-codec.0",
 	.ops = &bf5xx_ad1836_ops,
 };
 
 static struct snd_soc_card bf5xx_ad1836 = {
 	.name = "bf5xx_ad1836",
-	.platform = &bf5xx_tdm_soc_platform,
 	.dai_link = &bf5xx_ad1836_dai,
 	.num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad1836_snd_devdata = {
-	.card = &bf5xx_ad1836,
-	.codec_dev = &soc_codec_dev_ad1836,
-};
-
 static struct platform_device *bfxx_ad1836_snd_device;
 
 static int __init bf5xx_ad1836_init(void)
@@ -110,8 +106,7 @@ static int __init bf5xx_ad1836_init(void)
 	if (!bfxx_ad1836_snd_device)
 		return -ENOMEM;
 
-	platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata);
-	bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev;
+	platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836);
 	ret = platform_device_add(bfxx_ad1836_snd_device);
 
 	if (ret)

+ 9 - 14
sound/soc/blackfin/bf5xx-ad193x.c

@@ -49,9 +49,9 @@ static struct snd_soc_card bf5xx_ad193x;
 static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
-	cpu_dai->private_data = sport_handle;
+	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
 	return 0;
 }
 
@@ -59,8 +59,8 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
 	unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
 	int ret = 0;
 	/* set cpu DAI configuration */
@@ -97,23 +97,19 @@ static struct snd_soc_ops bf5xx_ad193x_ops = {
 static struct snd_soc_dai_link bf5xx_ad193x_dai = {
 	.name = "ad193x",
 	.stream_name = "AD193X",
-	.cpu_dai = &bf5xx_tdm_dai,
-	.codec_dai = &ad193x_dai,
+	.cpu_dai_name = "bf5xx-tdm",
+	.codec_dai_name ="ad193x-hifi",
+	.platform_name = "bf5xx-tdm-pcm-audio",
+	.codec_name = "ad193x-codec.5",
 	.ops = &bf5xx_ad193x_ops,
 };
 
 static struct snd_soc_card bf5xx_ad193x = {
 	.name = "bf5xx_ad193x",
-	.platform = &bf5xx_tdm_soc_platform,
 	.dai_link = &bf5xx_ad193x_dai,
 	.num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
-	.card = &bf5xx_ad193x,
-	.codec_dev = &soc_codec_dev_ad193x,
-};
-
 static struct platform_device *bfxx_ad193x_snd_device;
 
 static int __init bf5xx_ad193x_init(void)
@@ -124,8 +120,7 @@ static int __init bf5xx_ad193x_init(void)
 	if (!bfxx_ad193x_snd_device)
 		return -ENOMEM;
 
-	platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
-	bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
+	platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x);
 	ret = platform_device_add(bfxx_ad193x_snd_device);
 
 	if (ret)

+ 7 - 12
sound/soc/blackfin/bf5xx-ad1980.c

@@ -56,10 +56,10 @@ static struct snd_soc_card bf5xx_board;
 static int bf5xx_board_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
 	pr_debug("%s enter\n", __func__);
-	cpu_dai->private_data = sport_handle;
+	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
 	return 0;
 }
 
@@ -70,23 +70,19 @@ static struct snd_soc_ops bf5xx_board_ops = {
 static struct snd_soc_dai_link bf5xx_board_dai = {
 	.name = "AC97",
 	.stream_name = "AC97 HiFi",
-	.cpu_dai = &bfin_ac97_dai,
-	.codec_dai = &ad1980_dai,
+	.cpu_dai_name = "bfin-ac97",
+	.codec_dai_name = "ad1980-hifi",
+	.platform_name = "bfin-pcm-audio",
+	.codec_name = "ad1980-codec",
 	.ops = &bf5xx_board_ops,
 };
 
 static struct snd_soc_card bf5xx_board = {
 	.name = "bf5xx-board",
-	.platform = &bf5xx_ac97_soc_platform,
 	.dai_link = &bf5xx_board_dai,
 	.num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_board_snd_devdata = {
-	.card = &bf5xx_board,
-	.codec_dev = &soc_codec_dev_ad1980,
-};
-
 static struct platform_device *bf5xx_board_snd_device;
 
 static int __init bf5xx_board_init(void)
@@ -97,8 +93,7 @@ static int __init bf5xx_board_init(void)
 	if (!bf5xx_board_snd_device)
 		return -ENOMEM;
 
-	platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board_snd_devdata);
-	bf5xx_board_snd_devdata.dev = &bf5xx_board_snd_device->dev;
+	platform_set_drvdata(bf5xx_board_snd_device, &bf5xx_board);
 	ret = platform_device_add(bf5xx_board_snd_device);
 
 	if (ret)

+ 8 - 14
sound/soc/blackfin/bf5xx-ad73311.c

@@ -47,7 +47,6 @@
 #include "../codecs/ad73311.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 
 #if CONFIG_SND_BF5XX_SPORT_NUM == 0
 #define bfin_write_SPORT_TCR1	bfin_write_SPORT0_TCR1
@@ -150,10 +149,10 @@ static int bf5xx_probe(struct platform_device *pdev)
 static int bf5xx_ad73311_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
 	pr_debug("%s enter\n", __func__);
-	cpu_dai->private_data = sport_handle;
+	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
 	return 0;
 }
 
@@ -161,7 +160,7 @@ static int bf5xx_ad73311_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	int ret = 0;
 
 	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
@@ -185,24 +184,20 @@ static struct snd_soc_ops bf5xx_ad73311_ops = {
 static struct snd_soc_dai_link bf5xx_ad73311_dai = {
 	.name = "ad73311",
 	.stream_name = "AD73311",
-	.cpu_dai = &bf5xx_i2s_dai,
-	.codec_dai = &ad73311_dai,
+	.cpu_dai_name = "bf5xx-i2s",
+	.codec_dai_name = "ad73311-hifi",
+	.platform_name = "bfin-pcm-audio",
+	.codec_name = "ad73311-codec",
 	.ops = &bf5xx_ad73311_ops,
 };
 
 static struct snd_soc_card bf5xx_ad73311 = {
 	.name = "bf5xx_ad73311",
-	.platform = &bf5xx_i2s_soc_platform,
 	.probe = bf5xx_probe,
 	.dai_link = &bf5xx_ad73311_dai,
 	.num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ad73311_snd_devdata = {
-	.card = &bf5xx_ad73311,
-	.codec_dev = &soc_codec_dev_ad73311,
-};
-
 static struct platform_device *bf5xx_ad73311_snd_device;
 
 static int __init bf5xx_ad73311_init(void)
@@ -214,8 +209,7 @@ static int __init bf5xx_ad73311_init(void)
 	if (!bf5xx_ad73311_snd_device)
 		return -ENOMEM;
 
-	platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311_snd_devdata);
-	bf5xx_ad73311_snd_devdata.dev = &bf5xx_ad73311_snd_device->dev;
+	platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311);
 	ret = platform_device_add(bf5xx_ad73311_snd_device);
 
 	if (ret)

+ 31 - 13
sound/soc/blackfin/bf5xx-i2s-pcm.c

@@ -40,7 +40,6 @@
 #include <asm/dma.h>
 
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 #include "bf5xx-sport.h"
 
 static void bf5xx_dma_irq(void *data)
@@ -257,14 +256,14 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	if (dai->playback.channels_min) {
+	if (dai->driver->playback.channels_min) {
 		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_PLAYBACK);
 		if (ret)
 			goto out;
 	}
 
-	if (dai->capture.channels_min) {
+	if (dai->driver->capture.channels_min) {
 		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_CAPTURE);
 		if (ret)
@@ -274,25 +273,44 @@ int bf5xx_pcm_i2s_new(struct snd_card *card, struct snd_soc_dai *dai,
 	return ret;
 }
 
-struct snd_soc_platform bf5xx_i2s_soc_platform = {
-	.name		= "bf5xx-audio",
-	.pcm_ops 	= &bf5xx_pcm_i2s_ops,
+static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
+	.ops		= &bf5xx_pcm_i2s_ops,
 	.pcm_new	= bf5xx_pcm_i2s_new,
 	.pcm_free	= bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_i2s_soc_platform);
 
-static int __init bfin_i2s_init(void)
+static int __devinit bfin_i2s_soc_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_platform(&bf5xx_i2s_soc_platform);
+	return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform);
 }
-module_init(bfin_i2s_init);
 
-static void __exit bfin_i2s_exit(void)
+static int __devexit bfin_i2s_soc_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_platform(&bf5xx_i2s_soc_platform);
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver bfin_i2s_pcm_driver = {
+	.driver = {
+			.name = "bfin-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = bfin_i2s_soc_platform_probe,
+	.remove = __devexit_p(bfin_i2s_soc_platform_remove),
+};
+
+static int __init snd_bfin_i2s_pcm_init(void)
+{
+	return platform_driver_register(&bfin_i2s_pcm_driver);
+}
+module_init(snd_bfin_i2s_pcm_init);
+
+static void __exit snd_bfin_i2s_pcm_exit(void)
+{
+	platform_driver_unregister(&bfin_i2s_pcm_driver);
 }
-module_exit(bfin_i2s_exit);
+module_exit(snd_bfin_i2s_pcm_exit);
 
 MODULE_AUTHOR("Cliff Cai");
 MODULE_DESCRIPTION("ADI Blackfin I2S PCM DMA module");

+ 0 - 3
sound/soc/blackfin/bf5xx-i2s-pcm.h

@@ -23,7 +23,4 @@ struct bf5xx_gpio {
 	u32 frm;
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_i2s_soc_platform;
-
 #endif

+ 31 - 14
sound/soc/blackfin/bf5xx-i2s.c

@@ -42,7 +42,6 @@
 #include <linux/gpio.h>
 
 #include "bf5xx-sport.h"
-#include "bf5xx-i2s.h"
 
 struct bf5xx_i2s_port {
 	u16 tcr1;
@@ -195,8 +194,7 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
 		bf5xx_i2s.configured = 0;
 }
 
-static int bf5xx_i2s_probe(struct platform_device *pdev,
-			   struct snd_soc_dai *dai)
+static int bf5xx_i2s_probe(struct snd_soc_dai *dai)
 {
 	pr_debug("%s enter\n", __func__);
 	if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) {
@@ -215,11 +213,11 @@ static int bf5xx_i2s_probe(struct platform_device *pdev,
 	return 0;
 }
 
-static void bf5xx_i2s_remove(struct platform_device *pdev,
-			struct snd_soc_dai *dai)
+static int bf5xx_i2s_remove(struct snd_soc_dai *dai)
 {
 	pr_debug("%s enter\n", __func__);
 	peripheral_free_list(&sport_req[sport_num][0]);
+	return 0;
 }
 
 #ifdef CONFIG_PM
@@ -228,9 +226,9 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
 
 	pr_debug("%s : sport %d\n", __func__, dai->id);
 
-	if (dai->capture.active)
+	if (dai->capture_active)
 		sport_rx_stop(sport_handle);
-	if (dai->playback.active)
+	if (dai->playback_active)
 		sport_tx_stop(sport_handle);
 	return 0;
 }
@@ -277,9 +275,7 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
 	.set_fmt	= bf5xx_i2s_set_dai_fmt,
 };
 
-struct snd_soc_dai bf5xx_i2s_dai = {
-	.name = "bf5xx-i2s",
-	.id = 0,
+static struct snd_soc_dai_driver bf5xx_i2s_dai = {
 	.probe = bf5xx_i2s_probe,
 	.remove = bf5xx_i2s_remove,
 	.suspend = bf5xx_i2s_suspend,
@@ -296,18 +292,39 @@ struct snd_soc_dai bf5xx_i2s_dai = {
 		.formats = BF5XX_I2S_FORMATS,},
 	.ops = &bf5xx_i2s_dai_ops,
 };
-EXPORT_SYMBOL_GPL(bf5xx_i2s_dai);
+
+static int bfin_i2s_drv_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai);
+}
+
+static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_dai(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver bfin_i2s_driver = {
+	.probe = bfin_i2s_drv_probe,
+	.remove = __devexit_p(bfin_i2s_drv_remove),
+
+	.driver = {
+		.name = "bf5xx-i2s",
+		.owner = THIS_MODULE,
+	},
+};
 
 static int __init bfin_i2s_init(void)
 {
-	return snd_soc_register_dai(&bf5xx_i2s_dai);
+	return platform_driver_register(&bfin_i2s_driver);
 }
-module_init(bfin_i2s_init);
 
 static void __exit bfin_i2s_exit(void)
 {
-	snd_soc_unregister_dai(&bf5xx_i2s_dai);
+	platform_driver_unregister(&bfin_i2s_driver);
 }
+
+module_init(bfin_i2s_init);
 module_exit(bfin_i2s_exit);
 
 /* Module information */

+ 0 - 14
sound/soc/blackfin/bf5xx-i2s.h

@@ -1,14 +0,0 @@
-/*
- * sound/soc/blackfin/bf5xx-i2s.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _BF5XX_I2S_H
-#define _BF5XX_I2S_H
-
-extern struct snd_soc_dai bf5xx_i2s_dai;
-
-#endif

+ 9 - 29
sound/soc/blackfin/bf5xx-ssm2602.c

@@ -42,17 +42,16 @@
 #include "../codecs/ssm2602.h"
 #include "bf5xx-sport.h"
 #include "bf5xx-i2s-pcm.h"
-#include "bf5xx-i2s.h"
 
 static struct snd_soc_card bf5xx_ssm2602;
 
 static int bf5xx_ssm2602_startup(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 
 	pr_debug("%s enter\n", __func__);
-	cpu_dai->private_data = sport_handle;
+	snd_soc_dai_set_drvdata(cpu_dai, sport_handle);
 	return 0;
 }
 
@@ -60,8 +59,8 @@ static int bf5xx_ssm2602_hw_params(struct snd_pcm_substream *substream,
 	struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
-	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 	unsigned int clk = 0;
 	int ret = 0;
 
@@ -118,36 +117,19 @@ static struct snd_soc_ops bf5xx_ssm2602_ops = {
 static struct snd_soc_dai_link bf5xx_ssm2602_dai = {
 	.name = "ssm2602",
 	.stream_name = "SSM2602",
-	.cpu_dai = &bf5xx_i2s_dai,
-	.codec_dai = &ssm2602_dai,
+	.cpu_dai_name = "bf5xx-i2s",
+	.codec_dai_name = "ssm2602-hifi",
+	.platform_name = "bf5xx-pcm-audio",
+	.codec_name = "ssm2602-codec.0-0x1b",
 	.ops = &bf5xx_ssm2602_ops,
 };
 
-/*
- * SSM2602 2 wire address is determined by CSB
- * state during powerup.
- *    low  = 0x1a
- *    high = 0x1b
- */
-
-static struct ssm2602_setup_data bf5xx_ssm2602_setup = {
-	.i2c_bus = 0,
-	.i2c_address = 0x1b,
-};
-
 static struct snd_soc_card bf5xx_ssm2602 = {
 	.name = "bf5xx_ssm2602",
-	.platform = &bf5xx_i2s_soc_platform,
 	.dai_link = &bf5xx_ssm2602_dai,
 	.num_links = 1,
 };
 
-static struct snd_soc_device bf5xx_ssm2602_snd_devdata = {
-	.card = &bf5xx_ssm2602,
-	.codec_dev = &soc_codec_dev_ssm2602,
-	.codec_data = &bf5xx_ssm2602_setup,
-};
-
 static struct platform_device *bf5xx_ssm2602_snd_device;
 
 static int __init bf5xx_ssm2602_init(void)
@@ -159,9 +141,7 @@ static int __init bf5xx_ssm2602_init(void)
 	if (!bf5xx_ssm2602_snd_device)
 		return -ENOMEM;
 
-	platform_set_drvdata(bf5xx_ssm2602_snd_device,
-				&bf5xx_ssm2602_snd_devdata);
-	bf5xx_ssm2602_snd_devdata.dev = &bf5xx_ssm2602_snd_device->dev;
+	platform_set_drvdata(bf5xx_ssm2602_snd_device, &bf5xx_ssm2602);
 	ret = platform_device_add(bf5xx_ssm2602_snd_device);
 
 	if (ret)

+ 31 - 12
sound/soc/blackfin/bf5xx-tdm-pcm.c

@@ -290,14 +290,14 @@ static int bf5xx_pcm_tdm_new(struct snd_card *card, struct snd_soc_dai *dai,
 	if (!card->dev->coherent_dma_mask)
 		card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 
-	if (dai->playback.channels_min) {
+	if (dai->driver->playback.channels_min) {
 		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_PLAYBACK);
 		if (ret)
 			goto out;
 	}
 
-	if (dai->capture.channels_min) {
+	if (dai->driver->capture.channels_min) {
 		ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
 			SNDRV_PCM_STREAM_CAPTURE);
 		if (ret)
@@ -307,25 +307,44 @@ out:
 	return ret;
 }
 
-struct snd_soc_platform bf5xx_tdm_soc_platform = {
-	.name           = "bf5xx-audio",
-	.pcm_ops        = &bf5xx_pcm_tdm_ops,
+static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
+	.ops        = &bf5xx_pcm_tdm_ops,
 	.pcm_new        = bf5xx_pcm_tdm_new,
 	.pcm_free       = bf5xx_pcm_free_dma_buffers,
 };
-EXPORT_SYMBOL_GPL(bf5xx_tdm_soc_platform);
 
-static int __init bfin_pcm_tdm_init(void)
+static int __devinit bf5xx_soc_platform_probe(struct platform_device *pdev)
 {
-	return snd_soc_register_platform(&bf5xx_tdm_soc_platform);
+	return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
 }
-module_init(bfin_pcm_tdm_init);
 
-static void __exit bfin_pcm_tdm_exit(void)
+static int __devexit bf5xx_soc_platform_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_platform(&bf5xx_tdm_soc_platform);
+	snd_soc_unregister_platform(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver bfin_tdm_driver = {
+	.driver = {
+			.name = "bf5xx-tdm-pcm-audio",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = bf5xx_soc_platform_probe,
+	.remove = __devexit_p(bf5xx_soc_platform_remove),
+};
+
+static int __init snd_bfin_tdm_init(void)
+{
+	return platform_driver_register(&bfin_tdm_driver);
+}
+module_init(snd_bfin_tdm_init);
+
+static void __exit snd_bfin_tdm_exit(void)
+{
+	platform_driver_unregister(&bfin_tdm_driver);
 }
-module_exit(bfin_pcm_tdm_exit);
+module_exit(snd_bfin_tdm_exit);
 
 MODULE_AUTHOR("Barry Song");
 MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");

+ 0 - 3
sound/soc/blackfin/bf5xx-tdm-pcm.h

@@ -15,7 +15,4 @@ struct bf5xx_pcm_dma_params {
 	char *name;                     /* stream identifier */
 };
 
-/* platform data */
-extern struct snd_soc_platform bf5xx_tdm_soc_platform;
-
 #endif

+ 6 - 9
sound/soc/blackfin/bf5xx-tdm.c

@@ -214,9 +214,9 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 
 	if (!dai->active)
 		return 0;
-	if (dai->capture.active)
+	if (dai->capture_active)
 		sport_rx_stop(sport);
-	if (dai->playback.active)
+	if (dai->playback_active)
 		sport_tx_stop(sport);
 	return 0;
 }
@@ -224,7 +224,7 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
 static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
 {
 	int ret;
-	struct sport_device *sport = dai->private_data;
+	struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
 
 	if (!dai->active)
 		return 0;
@@ -262,9 +262,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
 	.set_channel_map   = bf5xx_tdm_set_channel_map,
 };
 
-struct snd_soc_dai bf5xx_tdm_dai = {
-	.name = "bf5xx-tdm",
-	.id = 0,
+static struct snd_soc_dai_driver bf5xx_tdm_dai = {
 	.suspend = bf5xx_tdm_suspend,
 	.resume = bf5xx_tdm_resume,
 	.playback = {
@@ -279,7 +277,6 @@ struct snd_soc_dai bf5xx_tdm_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S32_LE,},
 	.ops = &bf5xx_tdm_dai_ops,
 };
-EXPORT_SYMBOL_GPL(bf5xx_tdm_dai);
 
 static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 {
@@ -320,7 +317,7 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev)
 		goto sport_config_err;
 	}
 
-	ret = snd_soc_register_dai(&bf5xx_tdm_dai);
+	ret = snd_soc_register_dai(&pdev->dev, &bf5xx_tdm_dai);
 	if (ret) {
 		pr_err("Failed to register DAI: %d\n", ret);
 		goto sport_config_err;
@@ -337,7 +334,7 @@ sport_config_err:
 static int __devexit bfin_tdm_remove(struct platform_device *pdev)
 {
 	peripheral_free_list(&sport_req[sport_num][0]);
-	snd_soc_unregister_dai(&bf5xx_tdm_dai);
+	snd_soc_unregister_dai(&pdev->dev);
 
 	return 0;
 }

+ 0 - 2
sound/soc/blackfin/bf5xx-tdm.h

@@ -20,6 +20,4 @@ struct bf5xx_tdm_port {
 	int configured;
 };
 
-extern struct snd_soc_dai bf5xx_tdm_dai;
-
 #endif

+ 1486 - 0
sound/soc/codecs/88pm860x-codec.c

@@ -0,0 +1,1486 @@
+/*
+ * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm860x.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+
+#include "88pm860x-codec.h"
+
+#define MAX_NAME_LEN		20
+#define REG_CACHE_SIZE		0x40
+#define REG_CACHE_BASE		0xb0
+
+/* Status Register 1 (0x01) */
+#define REG_STATUS_1		0x01
+#define MIC_STATUS		(1 << 7)
+#define HOOK_STATUS		(1 << 6)
+#define HEADSET_STATUS		(1 << 5)
+
+/* Mic Detection Register (0x37) */
+#define REG_MIC_DET		0x37
+#define CONTINUOUS_POLLING	(3 << 1)
+#define EN_MIC_DET		(1 << 0)
+#define MICDET_MASK		0x07
+
+/* Headset Detection Register (0x38) */
+#define REG_HS_DET		0x38
+#define EN_HS_DET		(1 << 0)
+
+/* Misc2 Register (0x42) */
+#define REG_MISC2		0x42
+#define AUDIO_PLL		(1 << 5)
+#define AUDIO_SECTION_RESET	(1 << 4)
+#define AUDIO_SECTION_ON	(1 << 3)
+
+/* PCM Interface Register 2 (0xb1) */
+#define PCM_INF2_BCLK		(1 << 6)	/* Bit clock polarity */
+#define PCM_INF2_FS		(1 << 5)	/* Frame Sync polarity */
+#define PCM_INF2_MASTER		(1 << 4)	/* Master / Slave */
+#define PCM_INF2_18WL		(1 << 3)	/* 18 / 16 bits */
+#define PCM_GENERAL_I2S		0
+#define PCM_EXACT_I2S		1
+#define PCM_LEFT_I2S		2
+#define PCM_RIGHT_I2S		3
+#define PCM_SHORT_FS		4
+#define PCM_LONG_FS		5
+#define PCM_MODE_MASK		7
+
+/* I2S Interface Register 4 (0xbe) */
+#define I2S_EQU_BYP		(1 << 6)
+
+/* DAC Offset Register (0xcb) */
+#define DAC_MUTE		(1 << 7)
+#define MUTE_LEFT		(1 << 6)
+#define MUTE_RIGHT		(1 << 2)
+
+/* ADC Analog Register 1 (0xd0) */
+#define REG_ADC_ANA_1		0xd0
+#define MIC1BIAS_MASK		0x60
+
+/* Earpiece/Speaker Control Register 2 (0xda) */
+#define REG_EAR2		0xda
+#define RSYNC_CHANGE		(1 << 2)
+
+/* Audio Supplies Register 2 (0xdc) */
+#define REG_SUPPLIES2		0xdc
+#define LDO15_READY		(1 << 4)
+#define LDO15_EN		(1 << 3)
+#define CPUMP_READY		(1 << 2)
+#define CPUMP_EN		(1 << 1)
+#define AUDIO_EN		(1 << 0)
+#define SUPPLY_MASK		(LDO15_EN | CPUMP_EN | AUDIO_EN)
+
+/* Audio Enable Register 1 (0xdd) */
+#define ADC_MOD_RIGHT		(1 << 1)
+#define ADC_MOD_LEFT		(1 << 0)
+
+/* Audio Enable Register 2 (0xde) */
+#define ADC_LEFT		(1 << 5)
+#define ADC_RIGHT		(1 << 4)
+
+/* DAC Enable Register 2 (0xe1) */
+#define DAC_LEFT		(1 << 5)
+#define DAC_RIGHT		(1 << 4)
+#define MODULATOR		(1 << 3)
+
+/* Shorts Register (0xeb) */
+#define REG_SHORTS		0xeb
+#define CLR_SHORT_LO2		(1 << 7)
+#define SHORT_LO2		(1 << 6)
+#define CLR_SHORT_LO1		(1 << 5)
+#define SHORT_LO1		(1 << 4)
+#define CLR_SHORT_HS2		(1 << 3)
+#define SHORT_HS2		(1 << 2)
+#define CLR_SHORT_HS1		(1 << 1)
+#define SHORT_HS1		(1 << 0)
+
+/*
+ * This widget should be just after DAC & PGA in DAPM power-on sequence and
+ * before DAC & PGA in DAPM power-off sequence.
+ */
+#define PM860X_DAPM_OUTPUT(wname, wevent)	\
+{	.id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
+	.shift = 0, .invert = 0, .kcontrols = NULL, \
+	.num_kcontrols = 0, .event = wevent, \
+	.event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
+
+struct pm860x_det {
+	struct snd_soc_jack	*hp_jack;
+	struct snd_soc_jack	*mic_jack;
+	int			hp_det;
+	int			mic_det;
+	int			hook_det;
+	int			hs_shrt;
+	int			lo_shrt;
+};
+
+struct pm860x_priv {
+	unsigned int		sysclk;
+	unsigned int		pcmclk;
+	unsigned int		dir;
+	unsigned int		filter;
+	struct snd_soc_codec	*codec;
+	struct i2c_client	*i2c;
+	struct pm860x_chip	*chip;
+	struct pm860x_det	det;
+
+	int			irq[4];
+	unsigned char		name[4][MAX_NAME_LEN];
+	unsigned char		reg_cache[REG_CACHE_SIZE];
+};
+
+/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
+static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
+
+/* -9dB to 0db in 3dB steps */
+static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
+
+/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
+static const unsigned int mic_tlv[] = {
+	TLV_DB_RANGE_HEAD(5),
+	0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
+	1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
+	2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
+	3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
+	4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
+};
+
+/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
+static const unsigned int aux_tlv[] = {
+	TLV_DB_RANGE_HEAD(2),
+	0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
+	3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
+};
+
+/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
+static const unsigned int out_tlv[] = {
+	TLV_DB_RANGE_HEAD(4),
+	0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
+	4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
+	5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
+};
+
+static const unsigned int st_tlv[] = {
+	TLV_DB_RANGE_HEAD(8),
+	0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
+	2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
+	4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
+	6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
+	8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
+	10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
+	14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
+	18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
+};
+
+/* Sidetone Gain = M * 2^(-5-N) */
+struct st_gain {
+	unsigned int	db;
+	unsigned int	m;
+	unsigned int	n;
+};
+
+static struct st_gain st_table[] = {
+	{-12041,  1, 15}, {-11439,  1, 14}, {-11087,  3, 15}, {-10837,  1, 13},
+	{-10643,  5, 15}, {-10485,  3, 14}, {-10351,  7, 15}, {-10235,  1, 12},
+	{-10133,  9, 15}, {-10041,  5, 14}, { -9958, 11, 15}, { -9883,  3, 13},
+	{ -9813, 13, 15}, { -9749,  7, 14}, { -9689, 15, 15}, { -9633,  1, 11},
+	{ -9580, 17, 15}, { -9531,  9, 14}, { -9484, 19, 15}, { -9439,  5, 13},
+	{ -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281,  3, 12},
+	{ -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147,  7, 13},
+	{ -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031,  1, 10},
+	{ -8978, 17, 14}, { -8929,  9, 13}, { -8882, 19, 14}, { -8837,  5, 12},
+	{ -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679,  3, 11},
+	{ -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545,  7, 12},
+	{ -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429,  1,  9},
+	{ -8376, 17, 13}, { -8327,  9, 12}, { -8280, 19, 13}, { -8235,  5, 11},
+	{ -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077,  3, 10},
+	{ -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943,  7, 11},
+	{ -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827,  1,  8},
+	{ -7774, 17, 12}, { -7724,  9, 11}, { -7678, 19, 12}, { -7633,  5, 10},
+	{ -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475,  3,  9},
+	{ -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341,  7, 10},
+	{ -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225,  1,  7},
+	{ -7172, 17, 11}, { -7122,  9, 10}, { -7075, 19, 11}, { -7031,  5,  9},
+	{ -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873,  3,  8},
+	{ -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739,  7,  9},
+	{ -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623,  1,  6},
+	{ -6570, 17, 10}, { -6520,  9,  9}, { -6473, 19, 10}, { -6429,  5,  8},
+	{ -6386, 21, 10}, { -6346, 11,  9}, { -6307, 23, 10}, { -6270,  3,  7},
+	{ -6235, 25, 10}, { -6201, 13,  9}, { -6168, 27, 10}, { -6137,  7,  8},
+	{ -6106, 29, 10}, { -6077, 15,  9}, { -6048, 31, 10}, { -6021,  1,  5},
+	{ -5968, 17,  9}, { -5918,  9,  8}, { -5871, 19,  9}, { -5827,  5,  7},
+	{ -5784, 21,  9}, { -5744, 11,  8}, { -5705, 23,  9}, { -5668,  3,  6},
+	{ -5633, 25,  9}, { -5599, 13,  8}, { -5566, 27,  9}, { -5535,  7,  7},
+	{ -5504, 29,  9}, { -5475, 15,  8}, { -5446, 31,  9}, { -5419,  1,  4},
+	{ -5366, 17,  8}, { -5316,  9,  7}, { -5269, 19,  8}, { -5225,  5,  6},
+	{ -5182, 21,  8}, { -5142, 11,  7}, { -5103, 23,  8}, { -5066,  3,  5},
+	{ -5031, 25,  8}, { -4997, 13,  7}, { -4964, 27,  8}, { -4932,  7,  6},
+	{ -4902, 29,  8}, { -4873, 15,  7}, { -4844, 31,  8}, { -4816,  1,  3},
+	{ -4764, 17,  7}, { -4714,  9,  6}, { -4667, 19,  7}, { -4623,  5,  5},
+	{ -4580, 21,  7}, { -4540, 11,  6}, { -4501, 23,  7}, { -4464,  3,  4},
+	{ -4429, 25,  7}, { -4395, 13,  6}, { -4362, 27,  7}, { -4330,  7,  5},
+	{ -4300, 29,  7}, { -4270, 15,  6}, { -4242, 31,  7}, { -4214,  1,  2},
+	{ -4162, 17,  6}, { -4112,  9,  5}, { -4065, 19,  6}, { -4021,  5,  4},
+	{ -3978, 21,  6}, { -3938, 11,  5}, { -3899, 23,  6}, { -3862,  3,  3},
+	{ -3827, 25,  6}, { -3793, 13,  5}, { -3760, 27,  6}, { -3728,  7,  4},
+	{ -3698, 29,  6}, { -3668, 15,  5}, { -3640, 31,  6}, { -3612,  1,  1},
+	{ -3560, 17,  5}, { -3510,  9,  4}, { -3463, 19,  5}, { -3419,  5,  3},
+	{ -3376, 21,  5}, { -3336, 11,  4}, { -3297, 23,  5}, { -3260,  3,  2},
+	{ -3225, 25,  5}, { -3191, 13,  4}, { -3158, 27,  5}, { -3126,  7,  3},
+	{ -3096, 29,  5}, { -3066, 15,  4}, { -3038, 31,  5}, { -3010,  1,  0},
+	{ -2958, 17,  4}, { -2908,  9,  3}, { -2861, 19,  4}, { -2816,  5,  2},
+	{ -2774, 21,  4}, { -2734, 11,  3}, { -2695, 23,  4}, { -2658,  3,  1},
+	{ -2623, 25,  4}, { -2589, 13,  3}, { -2556, 27,  4}, { -2524,  7,  2},
+	{ -2494, 29,  4}, { -2464, 15,  3}, { -2436, 31,  4}, { -2408,  2,  0},
+	{ -2356, 17,  3}, { -2306,  9,  2}, { -2259, 19,  3}, { -2214,  5,  1},
+	{ -2172, 21,  3}, { -2132, 11,  2}, { -2093, 23,  3}, { -2056,  3,  0},
+	{ -2021, 25,  3}, { -1987, 13,  2}, { -1954, 27,  3}, { -1922,  7,  1},
+	{ -1892, 29,  3}, { -1862, 15,  2}, { -1834, 31,  3}, { -1806,  4,  0},
+	{ -1754, 17,  2}, { -1704,  9,  1}, { -1657, 19,  2}, { -1612,  5,  0},
+	{ -1570, 21,  2}, { -1530, 11,  1}, { -1491, 23,  2}, { -1454,  6,  0},
+	{ -1419, 25,  2}, { -1384, 13,  1}, { -1352, 27,  2}, { -1320,  7,  0},
+	{ -1290, 29,  2}, { -1260, 15,  1}, { -1232, 31,  2}, { -1204,  8,  0},
+	{ -1151, 17,  1}, { -1102,  9,  0}, { -1055, 19,  1}, { -1010, 10,  0},
+	{  -968, 21,  1}, {  -928, 11,  0}, {  -889, 23,  1}, {  -852, 12,  0},
+	{  -816, 25,  1}, {  -782, 13,  0}, {  -750, 27,  1}, {  -718, 14,  0},
+	{  -688, 29,  1}, {  -658, 15,  0}, {  -630, 31,  1}, {  -602, 16,  0},
+	{  -549, 17,  0}, {  -500, 18,  0}, {  -453, 19,  0}, {  -408, 20,  0},
+	{  -366, 21,  0}, {  -325, 22,  0}, {  -287, 23,  0}, {  -250, 24,  0},
+	{  -214, 25,  0}, {  -180, 26,  0}, {  -148, 27,  0}, {  -116, 28,  0},
+	{   -86, 29,  0}, {   -56, 30,  0}, {   -28, 31,  0}, {     0,  0,  0},
+};
+
+static int pm860x_volatile(unsigned int reg)
+{
+	BUG_ON(reg >= REG_CACHE_SIZE);
+
+	switch (reg) {
+	case PM860X_AUDIO_SUPPLIES_2:
+		return 1;
+	}
+
+	return 0;
+}
+
+static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
+					  unsigned int reg)
+{
+	unsigned char *cache = codec->reg_cache;
+
+	BUG_ON(reg >= REG_CACHE_SIZE);
+
+	if (pm860x_volatile(reg))
+		return cache[reg];
+
+	reg += REG_CACHE_BASE;
+
+	return pm860x_reg_read(codec->control_data, reg);
+}
+
+static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
+				  unsigned int reg, unsigned int value)
+{
+	unsigned char *cache = codec->reg_cache;
+
+	BUG_ON(reg >= REG_CACHE_SIZE);
+
+	if (!pm860x_volatile(reg))
+		cache[reg] = (unsigned char)value;
+
+	reg += REG_CACHE_BASE;
+
+	return pm860x_reg_write(codec->control_data, reg, value);
+}
+
+static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	int val[2], val2[2], i;
+
+	val[0] = snd_soc_read(codec, reg) & 0x3f;
+	val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
+	val2[0] = snd_soc_read(codec, reg2) & 0x3f;
+	val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
+
+	for (i = 0; i < ARRAY_SIZE(st_table); i++) {
+		if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
+			ucontrol->value.integer.value[0] = i;
+		if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
+			ucontrol->value.integer.value[1] = i;
+	}
+	return 0;
+}
+
+static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	int err;
+	unsigned int val, val2;
+
+	val = ucontrol->value.integer.value[0];
+	val2 = ucontrol->value.integer.value[1];
+
+	err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
+	if (err < 0)
+		return err;
+	err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
+				  st_table[val].n << 4);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
+	if (err < 0)
+		return err;
+	err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
+				  st_table[val2].n);
+	return err;
+}
+
+static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max, val, val2;
+	unsigned int mask = (1 << fls(max)) - 1;
+
+	val = snd_soc_read(codec, reg) >> shift;
+	val2 = snd_soc_read(codec, reg2) >> shift;
+	ucontrol->value.integer.value[0] = (max - val) & mask;
+	ucontrol->value.integer.value[1] = (max - val2) & mask;
+
+	return 0;
+}
+
+static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *mc =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+	unsigned int reg = mc->reg;
+	unsigned int reg2 = mc->rreg;
+	unsigned int shift = mc->shift;
+	int max = mc->max;
+	unsigned int mask = (1 << fls(max)) - 1;
+	int err;
+	unsigned int val, val2, val_mask;
+
+	val_mask = mask << shift;
+	val = ((max - ucontrol->value.integer.value[0]) & mask);
+	val2 = ((max - ucontrol->value.integer.value[1]) & mask);
+
+	val = val << shift;
+	val2 = val2 << shift;
+
+	err = snd_soc_update_bits(codec, reg, val_mask, val);
+	if (err < 0)
+		return err;
+
+	err = snd_soc_update_bits(codec, reg2, val_mask, val2);
+	return err;
+}
+
+/* DAPM Widget Events */
+/*
+ * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
+ * after updating these registers. Otherwise, these updated registers won't
+ * be effective.
+ */
+static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
+			      struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+
+	/*
+	 * In order to avoid current on the load, mute power-on and power-off
+	 * should be transients.
+	 * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
+	 * finished.
+	 */
+	snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
+	snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+			    RSYNC_CHANGE, RSYNC_CHANGE);
+	return 0;
+}
+
+static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_codec *codec = w->codec;
+	unsigned int dac = 0;
+	int data;
+
+	if (!strcmp(w->name, "Left DAC"))
+		dac = DAC_LEFT;
+	if (!strcmp(w->name, "Right DAC"))
+		dac = DAC_RIGHT;
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (dac) {
+			/* Auto mute in power-on sequence. */
+			dac |= MODULATOR;
+			snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+					    DAC_MUTE, DAC_MUTE);
+			snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+					    RSYNC_CHANGE, RSYNC_CHANGE);
+			/* update dac */
+			snd_soc_update_bits(codec, PM860X_DAC_EN_2,
+					    dac, dac);
+		}
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		if (dac) {
+			/* Auto mute in power-off sequence. */
+			snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
+					    DAC_MUTE, DAC_MUTE);
+			snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+					    RSYNC_CHANGE, RSYNC_CHANGE);
+			/* update dac */
+			data = snd_soc_read(codec, PM860X_DAC_EN_2);
+			data &= ~dac;
+			if (!(data & (DAC_LEFT | DAC_RIGHT)))
+				data &= ~MODULATOR;
+			snd_soc_write(codec, PM860X_DAC_EN_2, data);
+		}
+		break;
+	}
+	return 0;
+}
+
+static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
+
+static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
+
+static const struct soc_enum pm860x_hs1_opamp_enum =
+	SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs2_opamp_enum =
+	SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_hs1_pa_enum =
+	SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_hs2_pa_enum =
+	SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo1_opamp_enum =
+	SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo2_opamp_enum =
+	SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
+
+static const struct soc_enum pm860x_lo1_pa_enum =
+	SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_lo2_pa_enum =
+	SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_pa_enum =
+	SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_ear_pa_enum =
+	SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
+
+static const struct soc_enum pm860x_spk_ear_opamp_enum =
+	SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
+
+static const struct snd_kcontrol_new pm860x_snd_controls[] = {
+	SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
+			PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
+	SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
+			aux_tlv),
+	SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
+			mic_tlv),
+	SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
+			mic_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
+			     PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
+			     0, snd_soc_get_volsw_2r_st,
+			     snd_soc_put_volsw_2r_st, st_tlv),
+	SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
+			0, 7, 0, out_tlv),
+	SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
+			 PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
+	SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
+			 PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
+			     PM860X_HIFIL_GAIN_LEFT,
+			     PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
+			     snd_soc_get_volsw_2r_out,
+			     snd_soc_put_volsw_2r_out, dpga_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
+			     PM860X_HIFIR_GAIN_LEFT,
+			     PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
+			     snd_soc_get_volsw_2r_out,
+			     snd_soc_put_volsw_2r_out, dpga_tlv),
+	SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
+			     PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
+			     snd_soc_get_volsw_2r_out,
+			     snd_soc_put_volsw_2r_out, dpga_tlv),
+	SOC_ENUM("Headset1 Operational Amplifier Current",
+		 pm860x_hs1_opamp_enum),
+	SOC_ENUM("Headset2 Operational Amplifier Current",
+		 pm860x_hs2_opamp_enum),
+	SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
+	SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
+	SOC_ENUM("Lineout1 Operational Amplifier Current",
+		 pm860x_lo1_opamp_enum),
+	SOC_ENUM("Lineout2 Operational Amplifier Current",
+		 pm860x_lo2_opamp_enum),
+	SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
+	SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
+	SOC_ENUM("Speaker Operational Amplifier Current",
+		 pm860x_spk_ear_opamp_enum),
+	SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
+	SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
+};
+
+/*
+ * DAPM Controls
+ */
+
+/* PCM Switch / PCM Interface */
+static const struct snd_kcontrol_new pcm_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
+
+/* AUX1 Switch */
+static const struct snd_kcontrol_new aux1_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
+
+/* AUX2 Switch */
+static const struct snd_kcontrol_new aux2_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
+
+/* Left Ex. PA Switch */
+static const struct snd_kcontrol_new lepa_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
+
+/* Right Ex. PA Switch */
+static const struct snd_kcontrol_new repa_switch_controls =
+	SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
+
+/* PCM Mux / Mux7 */
+static const char *aif1_text[] = {
+	"PCM L", "PCM R",
+};
+
+static const struct soc_enum aif1_enum =
+	SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
+
+static const struct snd_kcontrol_new aif1_mux =
+	SOC_DAPM_ENUM("PCM Mux", aif1_enum);
+
+/* I2S Mux / Mux9 */
+static const char *i2s_din_text[] = {
+	"DIN", "DIN1",
+};
+
+static const struct soc_enum i2s_din_enum =
+	SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
+
+static const struct snd_kcontrol_new i2s_din_mux =
+	SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
+
+/* I2S Mic Mux / Mux8 */
+static const char *i2s_mic_text[] = {
+	"Ex PA", "ADC",
+};
+
+static const struct soc_enum i2s_mic_enum =
+	SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
+
+static const struct snd_kcontrol_new i2s_mic_mux =
+	SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
+
+/* ADCL Mux / Mux2 */
+static const char *adcl_text[] = {
+	"ADCR", "ADCL",
+};
+
+static const struct soc_enum adcl_enum =
+	SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
+
+static const struct snd_kcontrol_new adcl_mux =
+	SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
+
+/* ADCR Mux / Mux3 */
+static const char *adcr_text[] = {
+	"ADCL", "ADCR",
+};
+
+static const struct soc_enum adcr_enum =
+	SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
+
+static const struct snd_kcontrol_new adcr_mux =
+	SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
+
+/* ADCR EC Mux / Mux6 */
+static const char *adcr_ec_text[] = {
+	"ADCR", "EC",
+};
+
+static const struct soc_enum adcr_ec_enum =
+	SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
+
+static const struct snd_kcontrol_new adcr_ec_mux =
+	SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
+
+/* EC Mux / Mux4 */
+static const char *ec_text[] = {
+	"Left", "Right", "Left + Right",
+};
+
+static const struct soc_enum ec_enum =
+	SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
+
+static const struct snd_kcontrol_new ec_mux =
+	SOC_DAPM_ENUM("EC Mux", ec_enum);
+
+static const char *dac_text[] = {
+	"No input", "Right", "Left", "No input",
+};
+
+/* DAC Headset 1 Mux / Mux10 */
+static const struct soc_enum dac_hs1_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs1_mux =
+	SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
+
+/* DAC Headset 2 Mux / Mux11 */
+static const struct soc_enum dac_hs2_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_hs2_mux =
+	SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
+
+/* DAC Lineout 1 Mux / Mux12 */
+static const struct soc_enum dac_lo1_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo1_mux =
+	SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
+
+/* DAC Lineout 2 Mux / Mux13 */
+static const struct soc_enum dac_lo2_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_lo2_mux =
+	SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
+
+/* DAC Spearker Earphone Mux / Mux14 */
+static const struct soc_enum dac_spk_ear_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
+
+static const struct snd_kcontrol_new dac_spk_ear_mux =
+	SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
+
+/* Headset 1 Mux / Mux15 */
+static const char *in_text[] = {
+	"Digital", "Analog",
+};
+
+static const struct soc_enum hs1_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
+
+static const struct snd_kcontrol_new hs1_mux =
+	SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
+
+/* Headset 2 Mux / Mux16 */
+static const struct soc_enum hs2_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
+
+static const struct snd_kcontrol_new hs2_mux =
+	SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
+
+/* Lineout 1 Mux / Mux17 */
+static const struct soc_enum lo1_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
+
+static const struct snd_kcontrol_new lo1_mux =
+	SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
+
+/* Lineout 2 Mux / Mux18 */
+static const struct soc_enum lo2_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
+
+static const struct snd_kcontrol_new lo2_mux =
+	SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
+
+/* Speaker Earpiece Demux */
+static const char *spk_text[] = {
+	"Earpiece", "Speaker",
+};
+
+static const struct soc_enum spk_enum =
+	SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
+
+static const struct snd_kcontrol_new spk_demux =
+	SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
+
+/* MIC Mux / Mux1 */
+static const char *mic_text[] = {
+	"Mic 1", "Mic 2",
+};
+
+static const struct soc_enum mic_enum =
+	SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
+
+static const struct snd_kcontrol_new mic_mux =
+	SOC_DAPM_ENUM("MIC Mux", mic_enum);
+
+static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
+	SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
+			    PM860X_ADC_EN_2, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
+			     PM860X_PCM_IFACE_3, 1, 1),
+
+
+	SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
+			    PM860X_DAC_EN_2, 0, 0),
+	SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
+			    PM860X_DAC_EN_2, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
+			     PM860X_I2S_IFACE_3, 5, 1),
+	SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
+	SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
+	SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
+	SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
+	SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
+	SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
+			    &lepa_switch_controls),
+	SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
+			    &repa_switch_controls),
+
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
+			 0, 1, 1, 0),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
+			 1, 1, 1, 0),
+	SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
+	SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
+
+	SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
+			    &aux1_switch_controls),
+	SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
+			    &aux2_switch_controls),
+
+	SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
+	SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
+	SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
+	SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
+
+	SND_SOC_DAPM_INPUT("AUX1"),
+	SND_SOC_DAPM_INPUT("AUX2"),
+	SND_SOC_DAPM_INPUT("MIC1P"),
+	SND_SOC_DAPM_INPUT("MIC1N"),
+	SND_SOC_DAPM_INPUT("MIC2P"),
+	SND_SOC_DAPM_INPUT("MIC2N"),
+	SND_SOC_DAPM_INPUT("MIC3P"),
+	SND_SOC_DAPM_INPUT("MIC3N"),
+
+	SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
+			   pm860x_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
+			   pm860x_dac_event,
+			   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
+	SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
+	SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
+	SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
+	SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
+	SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
+	SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
+	SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
+	SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
+	SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
+	SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
+			 &spk_demux),
+
+
+	SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("HS1"),
+	SND_SOC_DAPM_OUTPUT("HS2"),
+	SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
+	SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("LINEOUT1"),
+	SND_SOC_DAPM_OUTPUT("LINEOUT2"),
+	SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("EARP"),
+	SND_SOC_DAPM_OUTPUT("EARN"),
+	SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
+	SND_SOC_DAPM_OUTPUT("LSP"),
+	SND_SOC_DAPM_OUTPUT("LSN"),
+	SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
+			 0, SUPPLY_MASK, SUPPLY_MASK, 0),
+
+	PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* supply */
+	{"Left DAC", NULL, "VCODEC"},
+	{"Right DAC", NULL, "VCODEC"},
+	{"Left ADC", NULL, "VCODEC"},
+	{"Right ADC", NULL, "VCODEC"},
+	{"Left ADC", NULL, "Left ADC MOD"},
+	{"Right ADC", NULL, "Right ADC MOD"},
+
+	/* PCM/AIF1 Inputs */
+	{"PCM SDO", NULL, "ADC Left Mux"},
+	{"PCM SDO", NULL, "ADCR EC Mux"},
+
+	/* PCM/AFI2 Outputs */
+	{"Lofi PGA", NULL, "PCM SDI"},
+	{"Lofi PGA", NULL, "Sidetone PGA"},
+	{"Left DAC", NULL, "Lofi PGA"},
+	{"Right DAC", NULL, "Lofi PGA"},
+
+	/* I2S/AIF2 Inputs */
+	{"MIC Mux", "Mic 1", "MIC1P"},
+	{"MIC Mux", "Mic 1", "MIC1N"},
+	{"MIC Mux", "Mic 2", "MIC2P"},
+	{"MIC Mux", "Mic 2", "MIC2N"},
+	{"MIC1 Volume", NULL, "MIC Mux"},
+	{"MIC3 Volume", NULL, "MIC3P"},
+	{"MIC3 Volume", NULL, "MIC3N"},
+	{"Left ADC", NULL, "MIC1 Volume"},
+	{"Right ADC", NULL, "MIC3 Volume"},
+	{"ADC Left Mux", "ADCR", "Right ADC"},
+	{"ADC Left Mux", "ADCL", "Left ADC"},
+	{"ADC Right Mux", "ADCL", "Left ADC"},
+	{"ADC Right Mux", "ADCR", "Right ADC"},
+	{"Left EPA", "Switch", "Left DAC"},
+	{"Right EPA", "Switch", "Right DAC"},
+	{"EC Mux", "Left", "Left DAC"},
+	{"EC Mux", "Right", "Right DAC"},
+	{"EC Mux", "Left + Right", "Left DAC"},
+	{"EC Mux", "Left + Right", "Right DAC"},
+	{"ADCR EC Mux", "ADCR", "ADC Right Mux"},
+	{"ADCR EC Mux", "EC", "EC Mux"},
+	{"I2S Mic Mux", "Ex PA", "Left EPA"},
+	{"I2S Mic Mux", "Ex PA", "Right EPA"},
+	{"I2S Mic Mux", "ADC", "ADC Left Mux"},
+	{"I2S Mic Mux", "ADC", "ADCR EC Mux"},
+	{"I2S DOUT", NULL, "I2S Mic Mux"},
+
+	/* I2S/AIF2 Outputs */
+	{"I2S DIN Mux", "DIN", "I2S DIN"},
+	{"I2S DIN Mux", "DIN1", "I2S DIN1"},
+	{"Left DAC", NULL, "I2S DIN Mux"},
+	{"Right DAC", NULL, "I2S DIN Mux"},
+	{"DAC HS1 Mux", "Left", "Left DAC"},
+	{"DAC HS1 Mux", "Right", "Right DAC"},
+	{"DAC HS2 Mux", "Left", "Left DAC"},
+	{"DAC HS2 Mux", "Right", "Right DAC"},
+	{"DAC LO1 Mux", "Left", "Left DAC"},
+	{"DAC LO1 Mux", "Right", "Right DAC"},
+	{"DAC LO2 Mux", "Left", "Left DAC"},
+	{"DAC LO2 Mux", "Right", "Right DAC"},
+	{"Headset1 Mux", "Digital", "DAC HS1 Mux"},
+	{"Headset2 Mux", "Digital", "DAC HS2 Mux"},
+	{"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
+	{"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
+	{"Headset1 PGA", NULL, "Headset1 Mux"},
+	{"Headset2 PGA", NULL, "Headset2 Mux"},
+	{"Lineout1 PGA", NULL, "Lineout1 Mux"},
+	{"Lineout2 PGA", NULL, "Lineout2 Mux"},
+	{"DAC SP Mux", "Left", "Left DAC"},
+	{"DAC SP Mux", "Right", "Right DAC"},
+	{"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
+	{"Speaker PGA", NULL, "Speaker Earpiece Demux"},
+	{"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
+
+	{"RSYNC", NULL, "Headset1 PGA"},
+	{"RSYNC", NULL, "Headset2 PGA"},
+	{"RSYNC", NULL, "Lineout1 PGA"},
+	{"RSYNC", NULL, "Lineout2 PGA"},
+	{"RSYNC", NULL, "Speaker PGA"},
+	{"RSYNC", NULL, "Speaker PGA"},
+	{"RSYNC", NULL, "Earpiece PGA"},
+	{"RSYNC", NULL, "Earpiece PGA"},
+
+	{"HS1", NULL, "RSYNC"},
+	{"HS2", NULL, "RSYNC"},
+	{"LINEOUT1", NULL, "RSYNC"},
+	{"LINEOUT2", NULL, "RSYNC"},
+	{"LSP", NULL, "RSYNC"},
+	{"LSN", NULL, "RSYNC"},
+	{"EARP", NULL, "RSYNC"},
+	{"EARN", NULL, "RSYNC"},
+};
+
+/*
+ * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
+ * These bits can also be used to mute.
+ */
+static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
+
+	if (mute)
+		data = mask;
+	snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
+	snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
+			    RSYNC_CHANGE, RSYNC_CHANGE);
+	return 0;
+}
+
+static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned char inf = 0, mask = 0;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		inf &= ~PCM_INF2_18WL;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		inf |= PCM_INF2_18WL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mask |= PCM_INF2_18WL;
+	snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+
+	/* sample rate */
+	switch (params_rate(params)) {
+	case 8000:
+		inf = 0;
+		break;
+	case 16000:
+		inf = 3;
+		break;
+	case 32000:
+		inf = 6;
+		break;
+	case 48000:
+		inf = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
+
+	return 0;
+}
+
+static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	unsigned char inf = 0, mask = 0;
+	int ret = -EINVAL;
+
+	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+		if (pm860x->dir == PM860X_CLK_DIR_OUT) {
+			inf |= PCM_INF2_MASTER;
+			ret = 0;
+		}
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		if (pm860x->dir == PM860X_CLK_DIR_IN) {
+			inf &= ~PCM_INF2_MASTER;
+			ret = 0;
+		}
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		inf |= PCM_EXACT_I2S;
+		ret = 0;
+		break;
+	}
+	mask |= PCM_MODE_MASK;
+	if (ret)
+		return ret;
+	snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
+	return 0;
+}
+
+static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+	if (dir == PM860X_CLK_DIR_OUT)
+		pm860x->dir = PM860X_CLK_DIR_OUT;
+	else {
+		pm860x->dir = PM860X_CLK_DIR_IN;
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	unsigned char inf;
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		inf = 0;
+		break;
+	case SNDRV_PCM_FORMAT_S18_3LE:
+		inf = PCM_INF2_18WL;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
+
+	/* sample rate */
+	switch (params_rate(params)) {
+	case 8000:
+		inf = 0;
+		break;
+	case 11025:
+		inf = 1;
+		break;
+	case 16000:
+		inf = 3;
+		break;
+	case 22050:
+		inf = 4;
+		break;
+	case 32000:
+		inf = 6;
+		break;
+	case 44100:
+		inf = 7;
+		break;
+	case 48000:
+		inf = 8;
+		break;
+	default:
+		return -EINVAL;
+	}
+	snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
+
+	return 0;
+}
+
+static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
+				  unsigned int fmt)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	unsigned char inf = 0, mask = 0;
+
+	mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
+
+	/* set master/slave audio interface */
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		if (pm860x->dir == PM860X_CLK_DIR_OUT)
+			inf |= PCM_INF2_MASTER;
+		else
+			return -EINVAL;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		if (pm860x->dir == PM860X_CLK_DIR_IN)
+			inf &= ~PCM_INF2_MASTER;
+		else
+			return -EINVAL;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		inf |= PCM_EXACT_I2S;
+		break;
+	default:
+		return -EINVAL;
+	}
+	mask |= PCM_MODE_MASK;
+	snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
+	return 0;
+}
+
+static int pm860x_set_bias_level(struct snd_soc_codec *codec,
+				 enum snd_soc_bias_level level)
+{
+	int data;
+
+	switch (level) {
+	case SND_SOC_BIAS_ON:
+		break;
+
+	case SND_SOC_BIAS_PREPARE:
+		break;
+
+	case SND_SOC_BIAS_STANDBY:
+		if (codec->bias_level == SND_SOC_BIAS_OFF) {
+			/* Enable Audio PLL & Audio section */
+			data = AUDIO_PLL | AUDIO_SECTION_RESET
+				| AUDIO_SECTION_ON;
+			pm860x_reg_write(codec->control_data, REG_MISC2, data);
+		}
+		break;
+
+	case SND_SOC_BIAS_OFF:
+		data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
+		pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
+		break;
+	}
+	codec->bias_level = level;
+	return 0;
+}
+
+static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
+	.digital_mute	= pm860x_digital_mute,
+	.hw_params	= pm860x_pcm_hw_params,
+	.set_fmt	= pm860x_pcm_set_dai_fmt,
+	.set_sysclk	= pm860x_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
+	.digital_mute	= pm860x_digital_mute,
+	.hw_params	= pm860x_i2s_hw_params,
+	.set_fmt	= pm860x_i2s_set_dai_fmt,
+	.set_sysclk	= pm860x_set_dai_sysclk,
+};
+
+#define PM860X_RATES	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |	\
+			 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
+
+static struct snd_soc_dai_driver pm860x_dai[] = {
+	{
+		/* DAI PCM */
+		.name	= "88pm860x-pcm",
+		.id	= 1,
+		.playback = {
+			.stream_name	= "PCM Playback",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= PM860X_RATES,
+			.formats	= SNDRV_PCM_FORMAT_S16_LE | \
+					  SNDRV_PCM_FORMAT_S18_3LE,
+		},
+		.capture = {
+			.stream_name	= "PCM Capture",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= PM860X_RATES,
+			.formats	= SNDRV_PCM_FORMAT_S16_LE | \
+					  SNDRV_PCM_FORMAT_S18_3LE,
+		},
+		.ops	= &pm860x_pcm_dai_ops,
+	}, {
+		/* DAI I2S */
+		.name	= "88pm860x-i2s",
+		.id	= 2,
+		.playback = {
+			.stream_name	= "I2S Playback",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_48000,
+			.formats	= SNDRV_PCM_FORMAT_S16_LE | \
+					  SNDRV_PCM_FORMAT_S18_3LE,
+		},
+		.capture = {
+			.stream_name	= "I2S Capture",
+			.channels_min	= 2,
+			.channels_max	= 2,
+			.rates		= SNDRV_PCM_RATE_8000_48000,
+			.formats	= SNDRV_PCM_FORMAT_S16_LE | \
+					  SNDRV_PCM_FORMAT_S18_3LE,
+		},
+		.ops	= &pm860x_i2s_dai_ops,
+	},
+};
+
+static irqreturn_t pm860x_codec_handler(int irq, void *data)
+{
+	struct pm860x_priv *pm860x = data;
+	int status, shrt, report = 0, mic_report = 0;
+	int mask;
+
+	status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
+	shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
+	mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
+		| pm860x->det.hp_det;
+
+	if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
+		&& (status & HEADSET_STATUS))
+		report |= SND_JACK_HEADPHONE;
+
+	if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
+		&& (status & MIC_STATUS))
+		mic_report |= SND_JACK_MICROPHONE;
+
+	if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
+		report |= pm860x->det.hs_shrt;
+
+	if (pm860x->det.hook_det && (status & HOOK_STATUS))
+		report |= pm860x->det.hook_det;
+
+	if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
+		report |= pm860x->det.lo_shrt;
+
+	if (report)
+		snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
+	if (mic_report)
+		snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
+				    SND_JACK_MICROPHONE);
+
+	dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
+		report, mask);
+	dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
+	return IRQ_HANDLED;
+}
+
+int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
+			  struct snd_soc_jack *jack,
+			  int det, int hook, int hs_shrt, int lo_shrt)
+{
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	int data;
+
+	pm860x->det.hp_jack = jack;
+	pm860x->det.hp_det = det;
+	pm860x->det.hook_det = hook;
+	pm860x->det.hs_shrt = hs_shrt;
+	pm860x->det.lo_shrt = lo_shrt;
+
+	if (det & SND_JACK_HEADPHONE)
+		pm860x_set_bits(codec->control_data, REG_HS_DET,
+				EN_HS_DET, EN_HS_DET);
+	/* headset short detect */
+	if (hs_shrt) {
+		data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
+		pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+	}
+	/* Lineout short detect */
+	if (lo_shrt) {
+		data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
+		pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
+	}
+
+	/* sync status */
+	pm860x_codec_handler(0, pm860x);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
+
+int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
+			   struct snd_soc_jack *jack, int det)
+{
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+
+	pm860x->det.mic_jack = jack;
+	pm860x->det.mic_det = det;
+
+	if (det & SND_JACK_MICROPHONE)
+		pm860x_set_bits(codec->control_data, REG_MIC_DET,
+				MICDET_MASK, MICDET_MASK);
+
+	/* sync status */
+	pm860x_codec_handler(0, pm860x);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
+
+static int pm860x_probe(struct snd_soc_codec *codec)
+{
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	int i, ret;
+
+	pm860x->codec = codec;
+
+	codec->control_data = pm860x->i2c;
+
+	for (i = 0; i < 4; i++) {
+		ret = request_threaded_irq(pm860x->irq[i], NULL,
+					   pm860x_codec_handler, IRQF_ONESHOT,
+					   pm860x->name[i], pm860x);
+		if (ret < 0) {
+			dev_err(codec->dev, "Failed to request IRQ!\n");
+			goto out_irq;
+		}
+	}
+
+	pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
+			       REG_CACHE_SIZE, codec->reg_cache);
+	if (ret < 0) {
+		dev_err(codec->dev, "Failed to fill register cache: %d\n",
+			ret);
+		goto out_codec;
+	}
+
+	snd_soc_add_controls(codec, pm860x_snd_controls,
+			     ARRAY_SIZE(pm860x_snd_controls));
+	snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
+				  ARRAY_SIZE(pm860x_dapm_widgets));
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+	return 0;
+
+out_codec:
+	i = 3;
+out_irq:
+	for (; i >= 0; i--)
+		free_irq(pm860x->irq[i], pm860x);
+	return -EINVAL;
+}
+
+static int pm860x_remove(struct snd_soc_codec *codec)
+{
+	struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
+	int i;
+
+	for (i = 3; i >= 0; i--)
+		free_irq(pm860x->irq[i], pm860x);
+	pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
+}
+
+static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
+	.probe		= pm860x_probe,
+	.remove		= pm860x_remove,
+	.read		= pm860x_read_reg_cache,
+	.write		= pm860x_write_reg_cache,
+	.reg_cache_size	= REG_CACHE_SIZE,
+	.reg_word_size	= sizeof(u8),
+	.set_bias_level	= pm860x_set_bias_level,
+};
+
+static int __devinit pm860x_codec_probe(struct platform_device *pdev)
+{
+	struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+	struct pm860x_priv *pm860x;
+	struct resource *res;
+	int i, ret;
+
+	pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
+	if (pm860x == NULL)
+		return -ENOMEM;
+
+	pm860x->chip = chip;
+	pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
+			: chip->companion;
+	platform_set_drvdata(pdev, pm860x);
+
+	for (i = 0; i < 4; i++) {
+		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+		if (!res) {
+			dev_err(&pdev->dev, "Failed to get IRQ resources\n");
+			goto out;
+		}
+		pm860x->irq[i] = res->start + chip->irq_base;
+		strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
+	}
+
+	ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
+				     pm860x_dai, ARRAY_SIZE(pm860x_dai));
+	if (ret) {
+		dev_err(&pdev->dev, "Failed to register codec\n");
+		goto out;
+	}
+	return ret;
+
+out:
+	platform_set_drvdata(pdev, NULL);
+	kfree(pm860x);
+	return -EINVAL;
+}
+
+static int __devexit pm860x_codec_remove(struct platform_device *pdev)
+{
+	struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_codec(&pdev->dev);
+	platform_set_drvdata(pdev, NULL);
+	kfree(pm860x);
+	return 0;
+}
+
+static struct platform_driver pm860x_codec_driver = {
+	.driver	= {
+		.name	= "88pm860x-codec",
+		.owner	= THIS_MODULE,
+	},
+	.probe	= pm860x_codec_probe,
+	.remove	= __devexit_p(pm860x_codec_remove),
+};
+
+static __init int pm860x_init(void)
+{
+	return platform_driver_register(&pm860x_codec_driver);
+}
+module_init(pm860x_init);
+
+static __exit void pm860x_exit(void)
+{
+	platform_driver_unregister(&pm860x_codec_driver);
+}
+module_exit(pm860x_exit);
+
+MODULE_DESCRIPTION("ASoC 88PM860x driver");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:88pm860x-codec");
+

+ 97 - 0
sound/soc/codecs/88pm860x-codec.h

@@ -0,0 +1,97 @@
+/*
+ * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
+ *
+ * Copyright 2010 Marvell International Ltd.
+ *	Haojian Zhuang <haojian.zhuang@marvell.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __88PM860X_H
+#define __88PM860X_H
+
+/* The offset of these registers are 0xb0 */
+#define PM860X_PCM_IFACE_1		0x00
+#define PM860X_PCM_IFACE_2		0x01
+#define PM860X_PCM_IFACE_3		0x02
+#define PM860X_PCM_RATE			0x03
+#define PM860X_EC_PATH			0x04
+#define PM860X_SIDETONE_L_GAIN		0x05
+#define PM860X_SIDETONE_R_GAIN		0x06
+#define PM860X_SIDETONE_SHIFT		0x07
+#define PM860X_ADC_OFFSET_1		0x08
+#define PM860X_ADC_OFFSET_2		0x09
+#define PM860X_DMIC_DELAY		0x0a
+
+#define PM860X_I2S_IFACE_1		0x0b
+#define PM860X_I2S_IFACE_2		0x0c
+#define PM860X_I2S_IFACE_3		0x0d
+#define PM860X_I2S_IFACE_4		0x0e
+#define PM860X_EQUALIZER_N0_1		0x0f
+#define PM860X_EQUALIZER_N0_2		0x10
+#define PM860X_EQUALIZER_N1_1		0x11
+#define PM860X_EQUALIZER_N1_2		0x12
+#define PM860X_EQUALIZER_D1_1		0x13
+#define PM860X_EQUALIZER_D1_2		0x14
+#define PM860X_LOFI_GAIN_LEFT		0x15
+#define PM860X_LOFI_GAIN_RIGHT		0x16
+#define PM860X_HIFIL_GAIN_LEFT		0x17
+#define PM860X_HIFIL_GAIN_RIGHT		0x18
+#define PM860X_HIFIR_GAIN_LEFT		0x19
+#define PM860X_HIFIR_GAIN_RIGHT		0x1a
+#define PM860X_DAC_OFFSET		0x1b
+#define PM860X_OFFSET_LEFT_1		0x1c
+#define PM860X_OFFSET_LEFT_2		0x1d
+#define PM860X_OFFSET_RIGHT_1		0x1e
+#define PM860X_OFFSET_RIGHT_2		0x1f
+#define PM860X_ADC_ANA_1		0x20
+#define PM860X_ADC_ANA_2		0x21
+#define PM860X_ADC_ANA_3		0x22
+#define PM860X_ADC_ANA_4		0x23
+#define PM860X_ANA_TO_ANA		0x24
+#define PM860X_HS1_CTRL			0x25
+#define PM860X_HS2_CTRL			0x26
+#define PM860X_LO1_CTRL			0x27
+#define PM860X_LO2_CTRL			0x28
+#define PM860X_EAR_CTRL_1		0x29
+#define PM860X_EAR_CTRL_2		0x2a
+#define PM860X_AUDIO_SUPPLIES_1		0x2b
+#define PM860X_AUDIO_SUPPLIES_2		0x2c
+#define PM860X_ADC_EN_1			0x2d
+#define PM860X_ADC_EN_2			0x2e
+#define PM860X_DAC_EN_1			0x2f
+#define PM860X_DAC_EN_2			0x31
+#define PM860X_AUDIO_CAL_1		0x32
+#define PM860X_AUDIO_CAL_2		0x33
+#define PM860X_AUDIO_CAL_3		0x34
+#define PM860X_AUDIO_CAL_4		0x35
+#define PM860X_AUDIO_CAL_5		0x36
+#define PM860X_ANA_INPUT_SEL_1		0x37
+#define PM860X_ANA_INPUT_SEL_2		0x38
+
+#define PM860X_PCM_IFACE_4		0x39
+#define PM860X_I2S_IFACE_5		0x3a
+
+#define PM860X_SHORTS			0x3b
+#define PM860X_PLL_ADJ_1		0x3c
+#define PM860X_PLL_ADJ_2		0x3d
+
+/* bits definition */
+#define PM860X_CLK_DIR_IN		0
+#define PM860X_CLK_DIR_OUT		1
+
+#define PM860X_DET_HEADSET		(1 << 0)
+#define PM860X_DET_MIC			(1 << 1)
+#define PM860X_DET_HOOK			(1 << 2)
+#define PM860X_SHORT_HEADSET		(1 << 3)
+#define PM860X_SHORT_LINEOUT		(1 << 4)
+#define PM860X_DET_MASK			0x1F
+
+extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+				 int, int, int, int);
+extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
+				  int);
+
+#endif	/* __88PM860X_H */

+ 24 - 0
sound/soc/codecs/Kconfig

@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
 
 config SND_SOC_ALL_CODECS
 	tristate "Build all ASoC CODEC drivers"
+	select SND_SOC_88PM860X if MFD_88PM860X
 	select SND_SOC_L3
 	select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
 	select SND_SOC_AD1836 if SPI_MASTER
@@ -26,6 +27,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_CS4270 if I2C
 	select SND_SOC_DA7210 if I2C
 	select SND_SOC_JZ4740 if SOC_JZ4740
+	select SND_SOC_MAX98088 if I2C
 	select SND_SOC_MAX9877 if I2C
 	select SND_SOC_PCM3008
 	select SND_SOC_SPDIF
@@ -40,6 +42,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_TWL6040 if TWL4030_CORE
 	select SND_SOC_UDA134X
 	select SND_SOC_UDA1380 if I2C
+	select SND_SOC_WL1273 if WL1273_CORE
 	select SND_SOC_WM2000 if I2C
 	select SND_SOC_WM8350 if MFD_WM8350
 	select SND_SOC_WM8400 if MFD_WM8400
@@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
+	select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8900 if I2C
 	select SND_SOC_WM8903 if I2C
 	select SND_SOC_WM8904 if I2C
@@ -61,9 +65,11 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_WM8955 if I2C
 	select SND_SOC_WM8960 if I2C
 	select SND_SOC_WM8961 if I2C
+	select SND_SOC_WM8962 if I2C
 	select SND_SOC_WM8971 if I2C
 	select SND_SOC_WM8974 if I2C
 	select SND_SOC_WM8978 if I2C
+	select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI
 	select SND_SOC_WM8990 if I2C
 	select SND_SOC_WM8993 if I2C
@@ -84,6 +90,9 @@ config SND_SOC_ALL_CODECS
 
           If unsure select "N".
 
+config SND_SOC_88PM860X
+	tristate
+
 config SND_SOC_WM_HUBS
 	tristate
 	default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
@@ -150,6 +159,9 @@ config SND_SOC_L3
 config SND_SOC_DA7210
         tristate
 
+config SND_SOC_MAX98088
+       tristate
+
 config SND_SOC_PCM3008
        tristate
 
@@ -188,6 +200,9 @@ config SND_SOC_UDA134X
 config SND_SOC_UDA1380
         tristate
 
+config SND_SOC_WL1273
+	tristate
+
 config SND_SOC_WM8350
 	tristate
 
@@ -227,6 +242,9 @@ config SND_SOC_WM8753
 config SND_SOC_WM8776
 	tristate
 
+config SND_SOC_WM8804
+	tristate
+
 config SND_SOC_WM8900
 	tristate
 
@@ -248,6 +266,9 @@ config SND_SOC_WM8960
 config SND_SOC_WM8961
 	tristate
 
+config SND_SOC_WM8962
+	tristate
+
 config SND_SOC_WM8971
 	tristate
 
@@ -257,6 +278,9 @@ config SND_SOC_WM8974
 config SND_SOC_WM8978
 	tristate
 
+config SND_SOC_WM8985
+	tristate
+
 config SND_SOC_WM8988
 	tristate
 

+ 12 - 0
sound/soc/codecs/Makefile

@@ -1,3 +1,4 @@
+snd-soc-88pm860x-objs := 88pm860x-codec.o
 snd-soc-ac97-objs := ac97.o
 snd-soc-ad1836-objs := ad1836.o
 snd-soc-ad193x-objs := ad193x.o
@@ -14,6 +15,7 @@ snd-soc-cs4270-objs := cs4270.o
 snd-soc-cx20442-objs := cx20442.o
 snd-soc-da7210-objs := da7210.o
 snd-soc-l3-objs := l3.o
+snd-soc-max98088-objs := max98088.o
 snd-soc-pcm3008-objs := pcm3008.o
 snd-soc-spdif-objs := spdif_transciever.o
 snd-soc-ssm2602-objs := ssm2602.o
@@ -26,6 +28,7 @@ snd-soc-twl4030-objs := twl4030.o
 snd-soc-twl6040-objs := twl6040.o
 snd-soc-uda134x-objs := uda134x.o
 snd-soc-uda1380-objs := uda1380.o
+snd-soc-wl1273-objs := wl1273.o
 snd-soc-wm8350-objs := wm8350.o
 snd-soc-wm8400-objs := wm8400.o
 snd-soc-wm8510-objs := wm8510.o
@@ -39,6 +42,7 @@ snd-soc-wm8741-objs := wm8741.o
 snd-soc-wm8750-objs := wm8750.o
 snd-soc-wm8753-objs := wm8753.o
 snd-soc-wm8776-objs := wm8776.o
+snd-soc-wm8804-objs := wm8804.o
 snd-soc-wm8900-objs := wm8900.o
 snd-soc-wm8903-objs := wm8903.o
 snd-soc-wm8904-objs := wm8904.o
@@ -46,9 +50,11 @@ snd-soc-wm8940-objs := wm8940.o
 snd-soc-wm8955-objs := wm8955.o
 snd-soc-wm8960-objs := wm8960.o
 snd-soc-wm8961-objs := wm8961.o
+snd-soc-wm8962-objs := wm8962.o
 snd-soc-wm8971-objs := wm8971.o
 snd-soc-wm8974-objs := wm8974.o
 snd-soc-wm8978-objs := wm8978.o
+snd-soc-wm8985-objs := wm8985.o
 snd-soc-wm8988-objs := wm8988.o
 snd-soc-wm8990-objs := wm8990.o
 snd-soc-wm8993-objs := wm8993.o
@@ -66,6 +72,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
 snd-soc-wm2000-objs := wm2000.o
 snd-soc-wm9090-objs := wm9090.o
 
+obj-$(CONFIG_SND_SOC_88PM860X)	+= snd-soc-88pm860x.o
 obj-$(CONFIG_SND_SOC_AC97_CODEC)	+= snd-soc-ac97.o
 obj-$(CONFIG_SND_SOC_AD1836)	+= snd-soc-ad1836.o
 obj-$(CONFIG_SND_SOC_AD193X)	+= snd-soc-ad193x.o
@@ -83,6 +90,7 @@ obj-$(CONFIG_SND_SOC_CX20442)	+= snd-soc-cx20442.o
 obj-$(CONFIG_SND_SOC_DA7210)	+= snd-soc-da7210.o
 obj-$(CONFIG_SND_SOC_L3)	+= snd-soc-l3.o
 obj-$(CONFIG_SND_SOC_JZ4740_CODEC)	+= snd-soc-jz4740-codec.o
+obj-$(CONFIG_SND_SOC_MAX98088)	+= snd-soc-max98088.o
 obj-$(CONFIG_SND_SOC_PCM3008)	+= snd-soc-pcm3008.o
 obj-$(CONFIG_SND_SOC_SPDIF)	+= snd-soc-spdif.o
 obj-$(CONFIG_SND_SOC_SSM2602)	+= snd-soc-ssm2602.o
@@ -95,6 +103,7 @@ obj-$(CONFIG_SND_SOC_TWL4030)	+= snd-soc-twl4030.o
 obj-$(CONFIG_SND_SOC_TWL6040)	+= snd-soc-twl6040.o
 obj-$(CONFIG_SND_SOC_UDA134X)	+= snd-soc-uda134x.o
 obj-$(CONFIG_SND_SOC_UDA1380)	+= snd-soc-uda1380.o
+obj-$(CONFIG_SND_SOC_WL1273)	+= snd-soc-wl1273.o
 obj-$(CONFIG_SND_SOC_WM8350)	+= snd-soc-wm8350.o
 obj-$(CONFIG_SND_SOC_WM8400)	+= snd-soc-wm8400.o
 obj-$(CONFIG_SND_SOC_WM8510)	+= snd-soc-wm8510.o
@@ -108,6 +117,7 @@ obj-$(CONFIG_SND_SOC_WM8741)	+= snd-soc-wm8741.o
 obj-$(CONFIG_SND_SOC_WM8750)	+= snd-soc-wm8750.o
 obj-$(CONFIG_SND_SOC_WM8753)	+= snd-soc-wm8753.o
 obj-$(CONFIG_SND_SOC_WM8776)	+= snd-soc-wm8776.o
+obj-$(CONFIG_SND_SOC_WM8804)	+= snd-soc-wm8804.o
 obj-$(CONFIG_SND_SOC_WM8900)	+= snd-soc-wm8900.o
 obj-$(CONFIG_SND_SOC_WM8903)	+= snd-soc-wm8903.o
 obj-$(CONFIG_SND_SOC_WM8904)	+= snd-soc-wm8904.o
@@ -115,9 +125,11 @@ obj-$(CONFIG_SND_SOC_WM8940)	+= snd-soc-wm8940.o
 obj-$(CONFIG_SND_SOC_WM8955)	+= snd-soc-wm8955.o
 obj-$(CONFIG_SND_SOC_WM8960)	+= snd-soc-wm8960.o
 obj-$(CONFIG_SND_SOC_WM8961)	+= snd-soc-wm8961.o
+obj-$(CONFIG_SND_SOC_WM8962)	+= snd-soc-wm8962.o
 obj-$(CONFIG_SND_SOC_WM8971)	+= snd-soc-wm8971.o
 obj-$(CONFIG_SND_SOC_WM8974)	+= snd-soc-wm8974.o
 obj-$(CONFIG_SND_SOC_WM8978)	+= snd-soc-wm8978.o
+obj-$(CONFIG_SND_SOC_WM8985)	+= snd-soc-wm8985.o
 obj-$(CONFIG_SND_SOC_WM8988)	+= snd-soc-wm8988.o
 obj-$(CONFIG_SND_SOC_WM8990)	+= snd-soc-wm8990.o
 obj-$(CONFIG_SND_SOC_WM8993)	+= snd-soc-wm8993.o

+ 51 - 74
sound/soc/codecs/ac97.c

@@ -21,17 +21,13 @@
 #include <sound/ac97_codec.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
-#include "ac97.h"
-
-#define AC97_VERSION "0.6"
 
 static int ac97_prepare(struct snd_pcm_substream *substream,
 			struct snd_soc_dai *dai)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_codec *codec = rtd->codec;
 
 	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
 		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
@@ -46,8 +42,8 @@ static struct snd_soc_dai_ops ac97_dai_ops = {
 	.prepare	= ac97_prepare,
 };
 
-struct snd_soc_dai ac97_dai = {
-	.name = "AC97 HiFi",
+static struct snd_soc_dai_driver ac97_dai = {
+	.name = "ac97-hifi",
 	.ac97_control = 1,
 	.playback = {
 		.stream_name = "AC97 Playback",
@@ -63,7 +59,6 @@ struct snd_soc_dai ac97_dai = {
 		.formats = SND_SOC_STD_AC97_FMTS,},
 	.ops = &ac97_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ac97_dai);
 
 static unsigned int ac97_read(struct snd_soc_codec *codec,
 	unsigned int reg)
@@ -78,95 +73,41 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 	return 0;
 }
 
-static int ac97_soc_probe(struct platform_device *pdev)
+static int ac97_soc_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_card *card = socdev->card;
-	struct snd_soc_codec *codec;
 	struct snd_ac97_bus *ac97_bus;
 	struct snd_ac97_template ac97_template;
-	int i;
-	int ret = 0;
-
-	printk(KERN_INFO "AC97 SoC Audio Codec %s\n", AC97_VERSION);
-
-	socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (!socdev->card->codec)
-		return -ENOMEM;
-	codec = socdev->card->codec;
-	mutex_init(&codec->mutex);
-
-	codec->name = "AC97";
-	codec->owner = THIS_MODULE;
-	codec->dai = &ac97_dai;
-	codec->num_dai = 1;
-	codec->write = ac97_write;
-	codec->read = ac97_read;
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0)
-		goto err;
+	int ret;
 
 	/* add codec as bus device for standard ac97 */
-	ret = snd_ac97_bus(codec->card, 0, &soc_ac97_ops, NULL, &ac97_bus);
+	ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus);
 	if (ret < 0)
-		goto bus_err;
+		return ret;
 
 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
 	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
 	if (ret < 0)
-		goto bus_err;
-
-	for (i = 0; i < card->num_links; i++) {
-		if (card->dai_link[i].codec_dai->ac97_control) {
-			snd_ac97_dev_add_pdata(codec->ac97,
-				card->dai_link[i].cpu_dai->ac97_pdata);
-		}
-	}
+		return ret;
 
 	return 0;
-
-bus_err:
-	snd_soc_free_pcms(socdev);
-
-err:
-	kfree(socdev->card->codec);
-	socdev->card->codec = NULL;
-	return ret;
 }
 
-static int ac97_soc_remove(struct platform_device *pdev)
+static int ac97_soc_remove(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	if (!codec)
-		return 0;
-
-	snd_soc_free_pcms(socdev);
-	kfree(socdev->card->codec);
-
 	return 0;
 }
 
 #ifdef CONFIG_PM
-static int ac97_soc_suspend(struct platform_device *pdev, pm_message_t msg)
+static int ac97_soc_suspend(struct snd_soc_codec *codec, pm_message_t msg)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_ac97_suspend(socdev->card->codec->ac97);
+	snd_ac97_suspend(codec->ac97);
 
 	return 0;
 }
 
-static int ac97_soc_resume(struct platform_device *pdev)
+static int ac97_soc_resume(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_ac97_resume(socdev->card->codec->ac97);
+	snd_ac97_resume(codec->ac97);
 
 	return 0;
 }
@@ -175,14 +116,50 @@ static int ac97_soc_resume(struct platform_device *pdev)
 #define ac97_soc_resume NULL
 #endif
 
-struct snd_soc_codec_device soc_codec_dev_ac97 = {
+static struct snd_soc_codec_driver soc_codec_dev_ac97 = {
+	.write =	ac97_write,
+	.read =		ac97_read,
 	.probe = 	ac97_soc_probe,
 	.remove = 	ac97_soc_remove,
 	.suspend =	ac97_soc_suspend,
 	.resume =	ac97_soc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ac97);
+
+static __devinit int ac97_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_ac97, &ac97_dai, 1);
+}
+
+static int __devexit ac97_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver ac97_codec_driver = {
+	.driver = {
+		.name = "ac97-codec",
+		.owner = THIS_MODULE,
+	},
+
+	.probe = ac97_probe,
+	.remove = __devexit_p(ac97_remove),
+};
+
+static int __init ac97_init(void)
+{
+	return platform_driver_register(&ac97_codec_driver);
+}
+module_init(ac97_init);
+
+static void __exit ac97_exit(void)
+{
+	platform_driver_unregister(&ac97_codec_driver);
+}
+module_exit(ac97_exit);
 
 MODULE_DESCRIPTION("Soc Generic AC97 driver");
 MODULE_AUTHOR("Liam Girdwood");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ac97-codec");

+ 0 - 19
sound/soc/codecs/ac97.h

@@ -1,19 +0,0 @@
-/*
- * linux/sound/codecs/ac97.h -- ALSA SoC Layer
- *
- * Author:		Liam Girdwood
- * Created:		Dec 1st 2005
- * Copyright:	Wolfson Microelectronics. PLC.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __LINUX_SND_SOC_AC97_H
-#define __LINUX_SND_SOC_AC97_H
-
-extern struct snd_soc_codec_device soc_codec_dev_ac97;
-extern struct snd_soc_dai ac97_dai;
-
-#endif

+ 55 - 136
sound/soc/codecs/ad1836.c

@@ -33,15 +33,10 @@
 
 /* codec private data */
 struct ad1836_priv {
-	struct snd_soc_codec codec;
-	u16 reg_cache[AD1836_NUM_REGS];
+	enum snd_soc_control_type control_type;
+	void *control_data;
 };
 
-static struct snd_soc_codec *ad1836_codec;
-struct snd_soc_codec_device soc_codec_dev_ad1836;
-static int ad1836_register(struct ad1836_priv *ad1836);
-static void ad1836_unregister(struct ad1836_priv *ad1836);
-
 /*
  * AD1836 volume/mute/de-emphasis etc. controls
  */
@@ -146,8 +141,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
 	int word_len = 0;
 
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_codec *codec = rtd->codec;
 
 	/* bit size */
 	switch (params_format(params)) {
@@ -173,12 +167,9 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream,
 }
 
 #ifdef CONFIG_PM
-static int ad1836_soc_suspend(struct platform_device *pdev,
+static int ad1836_soc_suspend(struct snd_soc_codec *codec,
 		pm_message_t state)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
 	/* reset clock control mode */
 	u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
 	adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
@@ -186,11 +177,8 @@ static int ad1836_soc_suspend(struct platform_device *pdev,
 	return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-static int ad1836_soc_resume(struct platform_device *pdev)
+static int ad1836_soc_resume(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
 	/* restore clock control mode */
 	u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
 	adc_ctrl2 |= AD1836_ADC_AUX;
@@ -202,49 +190,14 @@ static int ad1836_soc_resume(struct platform_device *pdev)
 #define ad1836_soc_resume  NULL
 #endif
 
-static int __devinit ad1836_spi_probe(struct spi_device *spi)
-{
-	struct snd_soc_codec *codec;
-	struct ad1836_priv *ad1836;
-
-	ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
-	if (ad1836 == NULL)
-		return -ENOMEM;
-
-	codec = &ad1836->codec;
-	codec->control_data = spi;
-	codec->dev = &spi->dev;
-
-	dev_set_drvdata(&spi->dev, ad1836);
-
-	return ad1836_register(ad1836);
-}
-
-static int __devexit ad1836_spi_remove(struct spi_device *spi)
-{
-	struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev);
-
-	ad1836_unregister(ad1836);
-	return 0;
-}
-
-static struct spi_driver ad1836_spi_driver = {
-	.driver = {
-		.name	= "ad1836",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= ad1836_spi_probe,
-	.remove		= __devexit_p(ad1836_spi_remove),
-};
-
 static struct snd_soc_dai_ops ad1836_dai_ops = {
 	.hw_params = ad1836_hw_params,
 	.set_fmt = ad1836_set_dai_fmt,
 };
 
 /* codec DAI instance */
-struct snd_soc_dai ad1836_dai = {
-	.name = "AD1836",
+static struct snd_soc_dai_driver ad1836_dai = {
+	.name = "ad1836-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
@@ -263,35 +216,13 @@ struct snd_soc_dai ad1836_dai = {
 	},
 	.ops = &ad1836_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ad1836_dai);
 
-static int ad1836_register(struct ad1836_priv *ad1836)
+static int ad1836_probe(struct snd_soc_codec *codec)
 {
-	int ret;
-	struct snd_soc_codec *codec = &ad1836->codec;
-
-	if (ad1836_codec) {
-		dev_err(codec->dev, "Another ad1836 is registered\n");
-		kfree(ad1836);
-		return -EINVAL;
-	}
-
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-	snd_soc_codec_set_drvdata(codec, ad1836);
-	codec->reg_cache = ad1836->reg_cache;
-	codec->reg_cache_size = AD1836_NUM_REGS;
-	codec->name = "AD1836";
-	codec->owner = THIS_MODULE;
-	codec->dai = &ad1836_dai;
-	codec->num_dai = 1;
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	ad1836_dai.dev = codec->dev;
-	ad1836_codec = codec;
+	struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
+	int ret = 0;
 
+	codec->control_data = ad1836->control_data;
 	ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI);
 	if (ret < 0) {
 		dev_err(codec->dev, "failed to set cache I/O: %d\n",
@@ -319,81 +250,69 @@ static int ad1836_register(struct ad1836_priv *ad1836)
 	snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF);
 	snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF);
 
-	ret = snd_soc_register_codec(codec);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-		kfree(ad1836);
-		return ret;
-	}
-
-	ret = snd_soc_register_dai(&ad1836_dai);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-		snd_soc_unregister_codec(codec);
-		kfree(ad1836);
-		return ret;
-	}
-
-	return 0;
-}
-
-static void ad1836_unregister(struct ad1836_priv *ad1836)
-{
-	snd_soc_unregister_dai(&ad1836_dai);
-	snd_soc_unregister_codec(&ad1836->codec);
-	kfree(ad1836);
-	ad1836_codec = NULL;
-}
-
-static int ad1836_probe(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret = 0;
-
-	if (ad1836_codec == NULL) {
-		dev_err(&pdev->dev, "Codec device not registered\n");
-		return -ENODEV;
-	}
-
-	socdev->card->codec = ad1836_codec;
-	codec = ad1836_codec;
-
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-		goto pcm_err;
-	}
-
 	snd_soc_add_controls(codec, ad1836_snd_controls,
 			     ARRAY_SIZE(ad1836_snd_controls));
 	snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
 				  ARRAY_SIZE(ad1836_dapm_widgets));
 	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-pcm_err:
 	return ret;
 }
 
 /* power down chip */
-static int ad1836_remove(struct platform_device *pdev)
+static int ad1836_remove(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
+	/* reset clock control mode */
+	u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2);
+	adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK;
 
-	return 0;
+	return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2);
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad1836 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1836 = {
 	.probe = 	ad1836_probe,
 	.remove = 	ad1836_remove,
 	.suspend =      ad1836_soc_suspend,
 	.resume =       ad1836_soc_resume,
+	.reg_cache_size = AD1836_NUM_REGS,
+	.reg_word_size = sizeof(u16),
+};
+
+static int __devinit ad1836_spi_probe(struct spi_device *spi)
+{
+	struct ad1836_priv *ad1836;
+	int ret;
+
+	ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL);
+	if (ad1836 == NULL)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, ad1836);
+	ad1836->control_data = spi;
+	ad1836->control_type = SND_SOC_SPI;
+
+	ret = snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_ad1836, &ad1836_dai, 1);
+	if (ret < 0)
+		kfree(ad1836);
+	return ret;
+}
+
+static int __devexit ad1836_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver ad1836_spi_driver = {
+	.driver = {
+		.name	= "ad1836-codec",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ad1836_spi_probe,
+	.remove		= __devexit_p(ad1836_spi_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836);
 
 static int __init ad1836_init(void)
 {

+ 0 - 2
sound/soc/codecs/ad1836.h

@@ -60,6 +60,4 @@
 
 #define AD1836_NUM_REGS                16
 
-extern struct snd_soc_dai ad1836_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1836;
 #endif

+ 77 - 140
sound/soc/codecs/ad193x.c

@@ -24,9 +24,10 @@
 
 /* codec private data */
 struct ad193x_priv {
-	unsigned int sysclk;
-	struct snd_soc_codec codec;
 	u8 reg_cache[AD193X_NUM_REGS];
+	enum snd_soc_control_type bus_type;
+	void *control_data;
+	int sysclk;
 };
 
 /* ad193x register cache & default register settings */
@@ -34,9 +35,6 @@ static const u8 ad193x_reg[AD193X_NUM_REGS] = {
 	0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
 };
 
-static struct snd_soc_codec *ad193x_codec;
-struct snd_soc_codec_device soc_codec_dev_ad193x;
-
 /*
  * AD193X volume/mute/de-emphasis etc. controls
  */
@@ -275,8 +273,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
 	int word_len = 0, reg = 0, master_rate = 0;
 
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_codec *codec = rtd->codec;
 	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
 
 	/* bit size */
@@ -323,100 +320,6 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
-{
-	struct snd_soc_codec *codec;
-	struct ad193x_priv *ad193x;
-	int ret;
-
-	if (ad193x_codec) {
-		dev_err(dev, "Another ad193x is registered\n");
-		return -EINVAL;
-	}
-
-	ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
-	if (ad193x == NULL)
-		return -ENOMEM;
-
-	dev_set_drvdata(dev, ad193x);
-
-	codec = &ad193x->codec;
-	mutex_init(&codec->mutex);
-	codec->control_data = ctrl_data;
-	codec->dev = dev;
-	snd_soc_codec_set_drvdata(codec, ad193x);
-	codec->reg_cache = ad193x->reg_cache;
-	codec->reg_cache_size = AD193X_NUM_REGS;
-	codec->name = "AD193X";
-	codec->owner = THIS_MODULE;
-	codec->dai = &ad193x_dai;
-	codec->num_dai = 1;
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	ad193x_dai.dev = codec->dev;
-	ad193x_codec = codec;
-
-	memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
-
-	if (bus_type == SND_SOC_I2C)
-		ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
-	else
-		ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
-	if (ret < 0) {
-		dev_err(codec->dev, "failed to set cache I/O: %d\n",
-				ret);
-		kfree(ad193x);
-		return ret;
-	}
-
-	/* default setting for ad193x */
-
-	/* unmute dac channels */
-	snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
-	/* de-emphasis: 48kHz, powedown dac */
-	snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
-	/* powerdown dac, dac in tdm mode */
-	snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
-	/* high-pass filter enable */
-	snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
-	/* sata delay=1, adc aux mode */
-	snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
-	/* pll input: mclki/xi */
-	snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
-	snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
-	ad193x->sysclk = 12288000;
-
-	ret = snd_soc_register_codec(codec);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-		kfree(ad193x);
-		return ret;
-	}
-
-	ret = snd_soc_register_dai(&ad193x_dai);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-		snd_soc_unregister_codec(codec);
-		kfree(ad193x);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int ad193x_bus_remove(struct device *dev)
-{
-	struct ad193x_priv *ad193x = dev_get_drvdata(dev);
-
-	snd_soc_unregister_dai(&ad193x_dai);
-	snd_soc_unregister_codec(&ad193x->codec);
-	kfree(ad193x);
-	ad193x_codec = NULL;
-
-	return 0;
-}
-
 static struct snd_soc_dai_ops ad193x_dai_ops = {
 	.hw_params = ad193x_hw_params,
 	.digital_mute = ad193x_mute,
@@ -426,8 +329,8 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
 };
 
 /* codec DAI instance */
-struct snd_soc_dai ad193x_dai = {
-	.name = "AD193X",
+static struct snd_soc_dai_driver ad193x_dai = {
+	.name = "ad193x-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
@@ -446,28 +349,39 @@ struct snd_soc_dai ad193x_dai = {
 	},
 	.ops = &ad193x_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ad193x_dai);
 
-static int ad193x_probe(struct platform_device *pdev)
+static int ad193x_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret = 0;
+	struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+	int ret;
 
-	if (ad193x_codec == NULL) {
-		dev_err(&pdev->dev, "Codec device not registered\n");
-		return -ENODEV;
+	codec->control_data = ad193x->control_data;
+	if (ad193x->bus_type == SND_SOC_I2C)
+		ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->bus_type);
+	else
+		ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->bus_type);
+	if (ret < 0) {
+		dev_err(codec->dev, "failed to set cache I/O: %d\n",
+				ret);
+		kfree(ad193x);
+		return ret;
 	}
 
-	socdev->card->codec = ad193x_codec;
-	codec = ad193x_codec;
+	/* default setting for ad193x */
 
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-		goto pcm_err;
-	}
+	/* unmute dac channels */
+	snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
+	/* de-emphasis: 48kHz, powedown dac */
+	snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
+	/* powerdown dac, dac in tdm mode */
+	snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
+	/* high-pass filter enable */
+	snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
+	/* sata delay=1, adc aux mode */
+	snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
+	/* pll input: mclki/xi */
+	snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
+	snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
 
 	snd_soc_add_controls(codec, ad193x_snd_controls,
 			     ARRAY_SIZE(ad193x_snd_controls));
@@ -475,41 +389,47 @@ static int ad193x_probe(struct platform_device *pdev)
 				  ARRAY_SIZE(ad193x_dapm_widgets));
 	snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
 
-pcm_err:
 	return ret;
 }
 
-/* power down chip */
-static int ad193x_remove(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
-
-	return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ad193x = {
+static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
 	.probe = 	ad193x_probe,
-	.remove = 	ad193x_remove,
+	.reg_cache_default = ad193x_reg,
+	.reg_cache_size = AD193X_NUM_REGS,
+	.reg_word_size = sizeof(u16),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
 
 #if defined(CONFIG_SPI_MASTER)
 static int __devinit ad193x_spi_probe(struct spi_device *spi)
 {
-	return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
+	struct ad193x_priv *ad193x;
+	int ret;
+
+	ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+	if (ad193x == NULL)
+		return -ENOMEM;
+
+	spi_set_drvdata(spi, ad193x);
+	ad193x->control_data = spi;
+	ad193x->bus_type = SND_SOC_SPI;
+
+	ret = snd_soc_register_codec(&spi->dev,
+			&soc_codec_dev_ad193x, &ad193x_dai, 1);
+	if (ret < 0)
+		kfree(ad193x);
+	return ret;
 }
 
 static int __devexit ad193x_spi_remove(struct spi_device *spi)
 {
-	return ad193x_bus_remove(&spi->dev);
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
 }
 
 static struct spi_driver ad193x_spi_driver = {
 	.driver = {
-		.name	= "ad193x",
+		.name	= "ad193x-codec",
 		.owner	= THIS_MODULE,
 	},
 	.probe		= ad193x_spi_probe,
@@ -528,17 +448,34 @@ MODULE_DEVICE_TABLE(i2c, ad193x_id);
 static int __devinit ad193x_i2c_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
-	return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
+	struct ad193x_priv *ad193x;
+	int ret;
+
+	ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
+	if (ad193x == NULL)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, ad193x);
+	ad193x->control_data = client;
+	ad193x->bus_type = SND_SOC_I2C;
+
+	ret =  snd_soc_register_codec(&client->dev,
+			&soc_codec_dev_ad193x, &ad193x_dai, 1);
+	if (ret < 0)
+		kfree(ad193x);
+	return ret;
 }
 
 static int __devexit ad193x_i2c_remove(struct i2c_client *client)
 {
-	return ad193x_bus_remove(&client->dev);
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
+	return 0;
 }
 
 static struct i2c_driver ad193x_i2c_driver = {
 	.driver = {
-		.name = "ad193x",
+		.name = "ad193x-codec",
 	},
 	.probe    = ad193x_i2c_probe,
 	.remove   = __devexit_p(ad193x_i2c_remove),

+ 0 - 3
sound/soc/codecs/ad193x.h

@@ -80,7 +80,4 @@
 
 #define AD193X_NUM_REGS          17
 
-extern struct snd_soc_dai ad193x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad193x;
-
 #endif

+ 47 - 66
sound/soc/codecs/ad1980.c

@@ -33,11 +33,6 @@
 
 #include "ad1980.h"
 
-static unsigned int ac97_read(struct snd_soc_codec *codec,
-	unsigned int reg);
-static int ac97_write(struct snd_soc_codec *codec,
-	unsigned int reg, unsigned int val);
-
 /*
  * AD1980 register cache
  */
@@ -138,8 +133,8 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
 	return 0;
 }
 
-struct snd_soc_dai ad1980_dai = {
-	.name = "AC97",
+static struct snd_soc_dai_driver ad1980_dai = {
+	.name = "ad1980-hifi",
 	.ac97_control = 1,
 	.playback = {
 		.stream_name = "Playback",
@@ -185,53 +180,20 @@ err:
 	return -EIO;
 }
 
-static int ad1980_soc_probe(struct platform_device *pdev)
+static int ad1980_soc_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret = 0;
+	int ret;
 	u16 vendor_id2;
 	u16 ext_status;
 
 	printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
-	socdev->card->codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (socdev->card->codec == NULL)
-		return -ENOMEM;
-	codec = socdev->card->codec;
-	mutex_init(&codec->mutex);
-
-	codec->reg_cache =
-		kzalloc(sizeof(u16) * ARRAY_SIZE(ad1980_reg), GFP_KERNEL);
-	if (codec->reg_cache == NULL) {
-		ret = -ENOMEM;
-		goto cache_err;
-	}
-	memcpy(codec->reg_cache, ad1980_reg, sizeof(u16) * \
-			ARRAY_SIZE(ad1980_reg));
-	codec->reg_cache_size = sizeof(u16) * ARRAY_SIZE(ad1980_reg);
-	codec->reg_cache_step = 2;
-	codec->name = "AD1980";
-	codec->owner = THIS_MODULE;
-	codec->dai = &ad1980_dai;
-	codec->num_dai = 1;
-	codec->write = ac97_write;
-	codec->read = ac97_read;
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
 	ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
 	if (ret < 0) {
 		printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
-		goto codec_err;
+		return ret;
 	}
 
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0)
-		goto pcm_err;
-
-
 	ret = ad1980_reset(codec, 0);
 	if (ret < 0) {
 		printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
@@ -270,41 +232,60 @@ static int ad1980_soc_probe(struct platform_device *pdev)
 	return 0;
 
 reset_err:
-	snd_soc_free_pcms(socdev);
-
-pcm_err:
 	snd_soc_free_ac97_codec(codec);
-
-codec_err:
-	kfree(codec->reg_cache);
-
-cache_err:
-	kfree(socdev->card->codec);
-	socdev->card->codec = NULL;
 	return ret;
 }
 
-static int ad1980_soc_remove(struct platform_device *pdev)
+static int ad1980_soc_remove(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	if (codec == NULL)
-		return 0;
-
-	snd_soc_dapm_free(socdev);
-	snd_soc_free_pcms(socdev);
 	snd_soc_free_ac97_codec(codec);
-	kfree(codec->reg_cache);
-	kfree(codec);
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad1980 = {
+static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
 	.probe = 	ad1980_soc_probe,
 	.remove = 	ad1980_soc_remove,
+	.reg_cache_size = ARRAY_SIZE(ad1980_reg),
+	.reg_word_size = sizeof(u16),
+	.reg_cache_default = ad1980_reg,
+	.reg_cache_step = 2,
+	.write = ac97_write,
+	.read = ac97_read,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980);
+
+static __devinit int ad1980_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_ad1980, &ad1980_dai, 1);
+}
+
+static int __devexit ad1980_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+	return 0;
+}
+
+static struct platform_driver ad1980_codec_driver = {
+	.driver = {
+			.name = "ad1980-codec",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = ad1980_probe,
+	.remove = __devexit_p(ad1980_remove),
+};
+
+static int __init ad1980_init(void)
+{
+	return platform_driver_register(&ad1980_codec_driver);
+}
+module_init(ad1980_init);
+
+static void __exit ad1980_exit(void)
+{
+	platform_driver_unregister(&ad1980_codec_driver);
+}
+module_exit(ad1980_exit);
 
 MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)");
 MODULE_AUTHOR("Roy Huang, Cliff Cai");

+ 0 - 3
sound/soc/codecs/ad1980.h

@@ -23,7 +23,4 @@
 #define PR5		0x2000
 #define PR6		0x4000
 
-extern struct snd_soc_dai ad1980_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad1980;
-
 #endif

+ 19 - 47
sound/soc/codecs/ad73311.c

@@ -23,8 +23,8 @@
 
 #include "ad73311.h"
 
-struct snd_soc_dai ad73311_dai = {
-	.name = "AD73311",
+static struct snd_soc_dai_driver ad73311_dai = {
+	.name = "ad73311-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -38,68 +38,40 @@ struct snd_soc_dai ad73311_dai = {
 		.rates = SNDRV_PCM_RATE_8000,
 		.formats = SNDRV_PCM_FMTBIT_S16_LE, },
 };
-EXPORT_SYMBOL_GPL(ad73311_dai);
 
-static int ad73311_soc_probe(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret = 0;
-
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
-		return -ENOMEM;
-	mutex_init(&codec->mutex);
-	codec->name = "AD73311";
-	codec->owner = THIS_MODULE;
-	codec->dai = &ad73311_dai;
-	codec->num_dai = 1;
-	socdev->card->codec = codec;
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		printk(KERN_ERR "ad73311: failed to create pcms\n");
-		goto pcm_err;
-	}
-
-	return ret;
+static struct snd_soc_codec_driver soc_codec_dev_ad73311;
 
-pcm_err:
-	kfree(socdev->card->codec);
-	socdev->card->codec = NULL;
-	return ret;
+static int ad73311_probe(struct platform_device *pdev)
+{
+	return snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_ad73311, &ad73311_dai, 1);
 }
 
-static int ad73311_soc_remove(struct platform_device *pdev)
+static int ad73311_remove(struct platform_device *pdev)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	if (codec == NULL)
-		return 0;
-	snd_soc_free_pcms(socdev);
-	kfree(codec);
+	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ad73311 = {
-	.probe = 	ad73311_soc_probe,
-	.remove = 	ad73311_soc_remove,
+static struct platform_driver ad73311_codec_driver = {
+	.driver = {
+			.name = "ad73311-codec",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = ad73311_probe,
+	.remove = __devexit_p(ad73311_remove),
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ad73311);
 
 static int __init ad73311_init(void)
 {
-	return snd_soc_register_dai(&ad73311_dai);
+	return platform_driver_register(&ad73311_codec_driver);
 }
 module_init(ad73311_init);
 
 static void __exit ad73311_exit(void)
 {
-	snd_soc_unregister_dai(&ad73311_dai);
+	platform_driver_unregister(&ad73311_codec_driver);
 }
 module_exit(ad73311_exit);
 

+ 0 - 2
sound/soc/codecs/ad73311.h

@@ -85,6 +85,4 @@
 #define REGF_INV		(1 << 6)
 #define REGF_ALB		(1 << 7)
 
-extern struct snd_soc_dai ad73311_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ad73311;
 #endif

+ 11 - 61
sound/soc/codecs/ads117x.c

@@ -19,16 +19,12 @@
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include "ads117x.h"
-
 #define ADS117X_RATES (SNDRV_PCM_RATE_8000_48000)
-
 #define ADS117X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
 
-struct snd_soc_dai ads117x_dai = {
+static struct snd_soc_dai_driver ads117x_dai = {
 /* ADC */
-	.name = "ADS117X ADC",
-	.id = 1,
+	.name = "ads117x-hifi",
 	.capture = {
 		.stream_name = "Capture",
 		.channels_min = 1,
@@ -36,75 +32,29 @@ struct snd_soc_dai ads117x_dai = {
 		.rates = ADS117X_RATES,
 		.formats = ADS117X_FORMATS,},
 };
-EXPORT_SYMBOL_GPL(ads117x_dai);
-
-static int ads117x_probe(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret;
-
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
-		return -ENOMEM;
 
-	socdev->card->codec = codec;
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-	codec->name = "ADS117X";
-	codec->owner = THIS_MODULE;
-	codec->dai = &ads117x_dai;
-	codec->num_dai = 1;
-
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		printk(KERN_ERR "ads117x: failed to create pcms\n");
-		kfree(codec);
-		return ret;
-	}
-
-	return 0;
-}
-
-static int ads117x_remove(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	snd_soc_free_pcms(socdev);
-	kfree(codec);
-
-	return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ads117x = {
-	.probe =	ads117x_probe,
-	.remove =	ads117x_remove,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ads117x);
+static struct snd_soc_codec_driver soc_codec_dev_ads117x;
 
-static __devinit int ads117x_platform_probe(struct platform_device *pdev)
+static __devinit int ads117x_probe(struct platform_device *pdev)
 {
-	ads117x_dai.dev = &pdev->dev;
-	return snd_soc_register_dai(&ads117x_dai);
+	return snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_ads117x, &ads117x_dai, 1);
 }
 
-static int __devexit ads117x_platform_remove(struct platform_device *pdev)
+static int __devexit ads117x_remove(struct platform_device *pdev)
 {
-	snd_soc_unregister_dai(&ads117x_dai);
+	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
 static struct platform_driver ads117x_codec_driver = {
 	.driver = {
-			.name = "ads117x",
+			.name = "ads117x-codec",
 			.owner = THIS_MODULE,
 	},
 
-	.probe = ads117x_platform_probe,
-	.remove = __devexit_p(ads117x_platform_remove),
+	.probe = ads117x_probe,
+	.remove = __devexit_p(ads117x_remove),
 };
 
 static int __init ads117x_init(void)

+ 2 - 2
sound/soc/codecs/ads117x.h

@@ -9,5 +9,5 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  */
-extern struct snd_soc_dai ads117x_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ads117x;
+extern struct snd_soc_dai_driver ads117x_dai;
+extern struct snd_soc_codec_driver soc_codec_dev_ads117x;

+ 53 - 96
sound/soc/codecs/ak4104.c

@@ -17,8 +17,6 @@
 #include <linux/spi/spi.h>
 #include <sound/asoundef.h>
 
-#include "ak4104.h"
-
 /* AK4104 registers addresses */
 #define AK4104_REG_CONTROL1		0x00
 #define AK4104_REG_RESERVED		0x01
@@ -45,11 +43,11 @@
 #define AK4104_TX_TXE			(1 << 0)
 #define AK4104_TX_V			(1 << 1)
 
-#define DRV_NAME "ak4104"
+#define DRV_NAME "ak4104-codec"
 
 struct ak4104_private {
-	struct snd_soc_codec codec;
-	u8 reg_cache[AK4104_NUM_REGS];
+	enum snd_soc_control_type control_type;
+	void *control_data;
 };
 
 static int ak4104_fill_cache(struct snd_soc_codec *codec)
@@ -58,7 +56,7 @@ static int ak4104_fill_cache(struct snd_soc_codec *codec)
 	u8 *reg_cache = codec->reg_cache;
 	struct spi_device *spi = codec->control_data;
 
-	for (i = 0; i < codec->reg_cache_size; i++) {
+	for (i = 0; i < codec->driver->reg_cache_size; i++) {
 		int ret = spi_w8r8(spi, i | AK4104_READ);
 		if (ret < 0) {
 			dev_err(&spi->dev, "SPI write failure\n");
@@ -76,7 +74,7 @@ static unsigned int ak4104_read_reg_cache(struct snd_soc_codec *codec,
 {
 	u8 *reg_cache = codec->reg_cache;
 
-	if (reg >= codec->reg_cache_size)
+	if (reg >= codec->driver->reg_cache_size)
 		return -EINVAL;
 
 	return reg_cache[reg];
@@ -88,7 +86,7 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg,
 	u8 *cache = codec->reg_cache;
 	struct spi_device *spi = codec->control_data;
 
-	if (reg >= codec->reg_cache_size)
+	if (reg >= codec->driver->reg_cache_size)
 		return -EINVAL;
 
 	/* only write to the hardware if value has changed */
@@ -145,8 +143,7 @@ static int ak4104_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_codec *codec = rtd->codec;
 	int val = 0;
 
 	/* set the IEC958 bits: consumer mode, no copyright bit */
@@ -178,8 +175,8 @@ static struct snd_soc_dai_ops ak4101_dai_ops = {
 	.set_fmt = ak4104_set_dai_fmt,
 };
 
-struct snd_soc_dai ak4104_dai = {
-	.name = DRV_NAME,
+static struct snd_soc_dai_driver ak4104_dai = {
+	.name = "ak4104-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 2,
@@ -192,45 +189,17 @@ struct snd_soc_dai ak4104_dai = {
 	.ops = &ak4101_dai_ops,
 };
 
-static struct snd_soc_codec *ak4104_codec;
-
-static int ak4104_spi_probe(struct spi_device *spi)
+static int ak4104_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_codec *codec;
-	struct ak4104_private *ak4104;
+	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);
 	int ret, val;
 
-	spi->bits_per_word = 8;
-	spi->mode = SPI_MODE_0;
-	ret = spi_setup(spi);
-	if (ret < 0)
-		return ret;
-
-	ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
-	if (!ak4104) {
-		dev_err(&spi->dev, "could not allocate codec\n");
-		return -ENOMEM;
-	}
-
-	codec = &ak4104->codec;
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	codec->dev = &spi->dev;
-	codec->name = DRV_NAME;
-	codec->owner = THIS_MODULE;
-	codec->dai = &ak4104_dai;
-	codec->num_dai = 1;
-	snd_soc_codec_set_drvdata(codec, ak4104);
-	codec->control_data = spi;
-	codec->reg_cache = ak4104->reg_cache;
-	codec->reg_cache_size = AK4104_NUM_REGS;
+	codec->control_data = ak4104->control_data;
 
 	/* read all regs and fill the cache */
 	ret = ak4104_fill_cache(codec);
 	if (ret < 0) {
-		dev_err(&spi->dev, "failed to fill register cache\n");
+		dev_err(codec->dev, "failed to fill register cache\n");
 		return ret;
 	}
 
@@ -238,93 +207,81 @@ static int ak4104_spi_probe(struct spi_device *spi)
 	 * should contain 0x5b. Not a good way to verify the presence of
 	 * the device, but there is no hardware ID register. */
 	if (ak4104_read_reg_cache(codec, AK4104_REG_RESERVED) !=
-					 AK4104_RESERVED_VAL) {
-		ret = -ENODEV;
-		goto error_free_codec;
-	}
+					 AK4104_RESERVED_VAL)
+		return -ENODEV;
 
 	/* set power-up and non-reset bits */
 	val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
 	val |= AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN;
 	ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
 	if (ret < 0)
-		goto error_free_codec;
+		return ret;
 
 	/* enable transmitter */
 	val = ak4104_read_reg_cache(codec, AK4104_REG_TX);
 	val |= AK4104_TX_TXE;
 	ret = ak4104_spi_write(codec, AK4104_REG_TX, val);
 	if (ret < 0)
-		goto error_free_codec;
-
-	ak4104_codec = codec;
-	ret = snd_soc_register_dai(&ak4104_dai);
-	if (ret < 0) {
-		dev_err(&spi->dev, "failed to register DAI\n");
-		goto error_free_codec;
-	}
+		return ret;
 
-	spi_set_drvdata(spi, ak4104);
-	dev_info(&spi->dev, "SPI device initialized\n");
+	dev_info(codec->dev, "SPI device initialized\n");
 	return 0;
-
-error_free_codec:
-	kfree(ak4104);
-	ak4104_dai.dev = NULL;
-	return ret;
 }
 
-static int __devexit ak4104_spi_remove(struct spi_device *spi)
+static int ak4104_remove(struct snd_soc_codec *codec)
 {
-	int ret, val;
-	struct ak4104_private *ak4104 = spi_get_drvdata(spi);
+	int val, ret;
 
-	val = ak4104_read_reg_cache(&ak4104->codec, AK4104_REG_CONTROL1);
+	val = ak4104_read_reg_cache(codec, AK4104_REG_CONTROL1);
 	if (val < 0)
 		return val;
 
 	/* clear power-up and non-reset bits */
 	val &= ~(AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);
-	ret = ak4104_spi_write(&ak4104->codec, AK4104_REG_CONTROL1, val);
-	if (ret < 0)
-		return ret;
+	ret = ak4104_spi_write(codec, AK4104_REG_CONTROL1, val);
 
-	ak4104_codec = NULL;
-	kfree(ak4104);
-	return 0;
+	return ret;
 }
 
-static int ak4104_probe(struct platform_device *pdev)
+static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
+	.probe =	ak4104_probe,
+	.remove =	ak4104_remove,
+	.reg_cache_size = AK4104_NUM_REGS,
+	.reg_word_size = sizeof(u16),
+};
+
+static int ak4104_spi_probe(struct spi_device *spi)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = ak4104_codec;
+	struct ak4104_private *ak4104;
 	int ret;
 
-	/* Connect the codec to the socdev.  snd_soc_new_pcms() needs this. */
-	socdev->card->codec = codec;
-
-	/* Register PCMs */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		dev_err(codec->dev, "failed to create pcms\n");
+	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_0;
+	ret = spi_setup(spi);
+	if (ret < 0)
 		return ret;
-	}
 
-	return 0;
+	ak4104 = kzalloc(sizeof(struct ak4104_private), GFP_KERNEL);
+	if (ak4104 == NULL)
+		return -ENOMEM;
+
+	ak4104->control_data = spi;
+	ak4104->control_type = SND_SOC_SPI;
+	spi_set_drvdata(spi, ak4104);
+
+	ret = snd_soc_register_codec(&spi->dev,
+			&soc_codec_device_ak4104, &ak4104_dai, 1);
+	if (ret < 0)
+		kfree(ak4104);
+	return ret;
 }
 
-static int ak4104_remove(struct platform_device *pdev)
+static int __devexit ak4104_spi_remove(struct spi_device *spi)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	snd_soc_free_pcms(socdev);
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
 	return 0;
-};
-
-struct snd_soc_codec_device soc_codec_device_ak4104 = {
-	.probe = 	ak4104_probe,
-	.remove = 	ak4104_remove
-};
-EXPORT_SYMBOL_GPL(soc_codec_device_ak4104);
+}
 
 static struct spi_driver ak4104_spi_driver = {
 	.driver  = {

+ 0 - 7
sound/soc/codecs/ak4104.h

@@ -1,7 +0,0 @@
-#ifndef _AK4104_H
-#define _AK4104_H
-
-extern struct snd_soc_dai ak4104_dai;
-extern struct snd_soc_codec_device soc_codec_device_ak4104;
-
-#endif

+ 61 - 175
sound/soc/codecs/ak4535.c

@@ -31,11 +31,11 @@
 
 #define AK4535_VERSION "0.3"
 
-struct snd_soc_codec_device soc_codec_dev_ak4535;
-
 /* codec private data */
 struct ak4535_priv {
 	unsigned int sysclk;
+	enum snd_soc_control_type control_type;
+	void *control_data;
 };
 
 /*
@@ -313,8 +313,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
 			    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_soc_device *socdev = rtd->socdev;
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct snd_soc_codec *codec = rtd->codec;
 	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 	u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
 	int rate = params_rate(params), fs = 256;
@@ -378,14 +377,16 @@ static int ak4535_mute(struct snd_soc_dai *dai, int mute)
 static int ak4535_set_bias_level(struct snd_soc_codec *codec,
 	enum snd_soc_bias_level level)
 {
-	u16 i;
+	u16 i, mute_reg;
 
 	switch (level) {
 	case SND_SOC_BIAS_ON:
-		ak4535_mute(codec->dai, 0);
+		mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+		ak4535_write(codec, AK4535_DAC, mute_reg);
 		break;
 	case SND_SOC_BIAS_PREPARE:
-		ak4535_mute(codec->dai, 1);
+		mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
+		ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
 		break;
 	case SND_SOC_BIAS_STANDBY:
 		i = ak4535_read_reg_cache(codec, AK4535_PM1);
@@ -413,8 +414,8 @@ static struct snd_soc_dai_ops ak4535_dai_ops = {
 	.set_sysclk	= ak4535_set_dai_sysclk,
 };
 
-struct snd_soc_dai ak4535_dai = {
-	.name = "AK4535",
+static struct snd_soc_dai_driver ak4535_dai = {
+	.name = "ak4535-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -429,54 +430,27 @@ struct snd_soc_dai ak4535_dai = {
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
 	.ops = &ak4535_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ak4535_dai);
 
-static int ak4535_suspend(struct platform_device *pdev, pm_message_t state)
+static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
 	ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	return 0;
 }
 
-static int ak4535_resume(struct platform_device *pdev)
+static int ak4535_resume(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
 	ak4535_sync(codec);
 	ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 	return 0;
 }
 
-/*
- * initialise the AK4535 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4535_init(struct snd_soc_device *socdev)
+static int ak4535_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_codec *codec = socdev->card->codec;
-	int ret = 0;
+	struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
 
-	codec->name = "AK4535";
-	codec->owner = THIS_MODULE;
-	codec->read = ak4535_read_reg_cache;
-	codec->write = ak4535_write;
-	codec->set_bias_level = ak4535_set_bias_level;
-	codec->dai = &ak4535_dai;
-	codec->num_dai = 1;
-	codec->reg_cache_size = ARRAY_SIZE(ak4535_reg);
-	codec->reg_cache = kmemdup(ak4535_reg, sizeof(ak4535_reg), GFP_KERNEL);
-
-	if (codec->reg_cache == NULL)
-		return -ENOMEM;
+	printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
 
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		printk(KERN_ERR "ak4535: failed to create pcms\n");
-		goto pcm_err;
-	}
+	codec->control_data = ak4535->control_data;
 
 	/* power on device */
 	ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -485,39 +459,55 @@ static int ak4535_init(struct snd_soc_device *socdev)
 				ARRAY_SIZE(ak4535_snd_controls));
 	ak4535_add_widgets(codec);
 
-	return ret;
-
-pcm_err:
-	kfree(codec->reg_cache);
+	return 0;
+}
 
-	return ret;
+/* power down chip */
+static int ak4535_remove(struct snd_soc_codec *codec)
+{
+	ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
+	return 0;
 }
 
-static struct snd_soc_device *ak4535_socdev;
+static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
+	.probe =	ak4535_probe,
+	.remove =	ak4535_remove,
+	.suspend =	ak4535_suspend,
+	.resume =	ak4535_resume,
+	.read = ak4535_read_reg_cache,
+	.write = ak4535_write,
+	.set_bias_level = ak4535_set_bias_level,
+	.reg_cache_size = ARRAY_SIZE(ak4535_reg),
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = ak4535_reg,
+};
 
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-
-static int ak4535_i2c_probe(struct i2c_client *i2c,
-			    const struct i2c_device_id *id)
+static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
 {
-	struct snd_soc_device *socdev = ak4535_socdev;
-	struct snd_soc_codec *codec = socdev->card->codec;
+	struct ak4535_priv *ak4535;
 	int ret;
 
-	i2c_set_clientdata(i2c, codec);
-	codec->control_data = i2c;
+	ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
+	if (ak4535 == NULL)
+		return -ENOMEM;
 
-	ret = ak4535_init(socdev);
-	if (ret < 0)
-		printk(KERN_ERR "failed to initialise AK4535\n");
+	i2c_set_clientdata(i2c, ak4535);
+	ak4535->control_data = i2c;
+	ak4535->control_type = SND_SOC_I2C;
 
+	ret = snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_ak4535, &ak4535_dai, 1);
+	if (ret < 0)
+		kfree(ak4535);
 	return ret;
 }
 
-static int ak4535_i2c_remove(struct i2c_client *client)
+static __devexit int ak4535_i2c_remove(struct i2c_client *client)
 {
-	struct snd_soc_codec *codec = i2c_get_clientdata(client);
-	kfree(codec->reg_cache);
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -529,138 +519,34 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id);
 
 static struct i2c_driver ak4535_i2c_driver = {
 	.driver = {
-		.name = "AK4535 I2C Codec",
+		.name = "ak4535-codec",
 		.owner = THIS_MODULE,
 	},
 	.probe =    ak4535_i2c_probe,
-	.remove =   ak4535_i2c_remove,
+	.remove =   __devexit_p(ak4535_i2c_remove),
 	.id_table = ak4535_i2c_id,
 };
-
-static int ak4535_add_i2c_device(struct platform_device *pdev,
-				 const struct ak4535_setup_data *setup)
-{
-	struct i2c_board_info info;
-	struct i2c_adapter *adapter;
-	struct i2c_client *client;
-	int ret;
-
-	ret = i2c_add_driver(&ak4535_i2c_driver);
-	if (ret != 0) {
-		dev_err(&pdev->dev, "can't add i2c driver\n");
-		return ret;
-	}
-
-	memset(&info, 0, sizeof(struct i2c_board_info));
-	info.addr = setup->i2c_address;
-	strlcpy(info.type, "ak4535", I2C_NAME_SIZE);
-
-	adapter = i2c_get_adapter(setup->i2c_bus);
-	if (!adapter) {
-		dev_err(&pdev->dev, "can't get i2c adapter %d\n",
-			setup->i2c_bus);
-		goto err_driver;
-	}
-
-	client = i2c_new_device(adapter, &info);
-	i2c_put_adapter(adapter);
-	if (!client) {
-		dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
-			(unsigned int)info.addr);
-		goto err_driver;
-	}
-
-	return 0;
-
-err_driver:
-	i2c_del_driver(&ak4535_i2c_driver);
-	return -ENODEV;
-}
 #endif
 
-static int ak4535_probe(struct platform_device *pdev)
+static int __init ak4535_modinit(void)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct ak4535_setup_data *setup;
-	struct snd_soc_codec *codec;
-	struct ak4535_priv *ak4535;
-	int ret;
-
-	printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
-
-	setup = socdev->codec_data;
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL)
-		return -ENOMEM;
-
-	ak4535 = kzalloc(sizeof(struct ak4535_priv), GFP_KERNEL);
-	if (ak4535 == NULL) {
-		kfree(codec);
-		return -ENOMEM;
-	}
-
-	snd_soc_codec_set_drvdata(codec, ak4535);
-	socdev->card->codec = codec;
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	ak4535_socdev = socdev;
-	ret = -ENODEV;
-
+	int ret = 0;
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	if (setup->i2c_address) {
-		codec->hw_write = (hw_write_t)i2c_master_send;
-		ret = ak4535_add_i2c_device(pdev, setup);
-	}
-#endif
-
+	ret = i2c_add_driver(&ak4535_i2c_driver);
 	if (ret != 0) {
-		kfree(snd_soc_codec_get_drvdata(codec));
-		kfree(codec);
+		printk(KERN_ERR "Failed to register AK4535 I2C driver: %d\n",
+		       ret);
 	}
+#endif
 	return ret;
 }
+module_init(ak4535_modinit);
 
-/* power down chip */
-static int ak4535_remove(struct platform_device *pdev)
+static void __exit ak4535_exit(void)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	if (codec->control_data)
-		ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-	if (codec->control_data)
-		i2c_unregister_device(codec->control_data);
 	i2c_del_driver(&ak4535_i2c_driver);
 #endif
-	kfree(snd_soc_codec_get_drvdata(codec));
-	kfree(codec);
-
-	return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4535 = {
-	.probe = 	ak4535_probe,
-	.remove = 	ak4535_remove,
-	.suspend = 	ak4535_suspend,
-	.resume =	ak4535_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4535);
-
-static int __init ak4535_modinit(void)
-{
-	return snd_soc_register_dai(&ak4535_dai);
-}
-module_init(ak4535_modinit);
-
-static void __exit ak4535_exit(void)
-{
-	snd_soc_unregister_dai(&ak4535_dai);
 }
 module_exit(ak4535_exit);
 

+ 0 - 8
sound/soc/codecs/ak4535.h

@@ -36,12 +36,4 @@
 
 #define AK4535_CACHEREGNUM 	0x10
 
-struct ak4535_setup_data {
-	int            i2c_bus;
-	unsigned short i2c_address;
-};
-
-extern struct snd_soc_dai ak4535_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4535;
-
 #endif

+ 82 - 153
sound/soc/codecs/ak4642.c

@@ -30,8 +30,6 @@
 #include <sound/initval.h>
 #include <sound/tlv.h>
 
-#include "ak4642.h"
-
 #define AK4642_VERSION "0.0.1"
 
 #define PW_MGMT1	0x00
@@ -74,6 +72,12 @@
 
 #define AK4642_CACHEREGNUM 	0x25
 
+/* PW_MGMT1*/
+#define PMVCM		(1 << 6) /* VCOM Power Management */
+#define PMMIN		(1 << 5) /* MIN Input Power Management */
+#define PMDAC		(1 << 2) /* DAC Power Management */
+#define PMADL		(1 << 0) /* MIC Amp Lch and ADC Lch Power Management */
+
 /* PW_MGMT2 */
 #define HPMTN		(1 << 6)
 #define PMHPL		(1 << 5)
@@ -85,6 +89,23 @@
 #define PMHP_MASK	(PMHPL | PMHPR)
 #define PMHP		PMHP_MASK
 
+/* PW_MGMT3 */
+#define PMADR		(1 << 0) /* MIC L / ADC R Power Management */
+
+/* SG_SL1 */
+#define MINS		(1 << 6) /* Switch from MIN to Speaker */
+#define DACL		(1 << 4) /* Switch from DAC to Stereo or Receiver */
+#define PMMP		(1 << 2) /* MPWR pin Power Management */
+#define MGAIN0		(1 << 0) /* MIC amp gain*/
+
+/* TIMER */
+#define ZTM(param)	((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */
+#define WTM(param)	(((param & 0x4) << 4) | ((param & 0x3) << 2))
+
+/* ALC_CTL1 */
+#define ALC		(1 << 5) /* ALC Enable */
+#define LMTH0		(1 << 0) /* ALC Limiter / Recovery Level */
+
 /* MD_CTL1 */
 #define PLL3		(1 << 7)
 #define PLL2		(1 << 6)
@@ -102,7 +123,11 @@
 #define FS3		(1 << 5)
 #define FS_MASK		(FS0 | FS1 | FS2 | FS3)
 
-struct snd_soc_codec_device soc_codec_dev_ak4642;
+/* MD_CTL3 */
+#define BST1		(1 << 3)
+
+/* MD_CTL4 */
+#define DACH		(1 << 0)
 
 /*
  * Playback Volume (table 39)
@@ -123,11 +148,11 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
 
 /* codec private data */
 struct ak4642_priv {
-	struct snd_soc_codec codec;
+	unsigned int sysclk;
+	enum snd_soc_control_type control_type;
+	void *control_data;
 };
 
-static struct snd_soc_codec *ak4642_codec;
-
 /*
  * ak4642 register cache
  */
@@ -219,11 +244,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 		 * This operation came from example code of
 		 * "ASAHI KASEI AK4642" (japanese) manual p97.
 		 */
-		ak4642_write(codec, 0x0f, 0x09);
-		ak4642_write(codec, 0x0e, 0x19);
-		ak4642_write(codec, 0x09, 0x91);
-		ak4642_write(codec, 0x0c, 0x91);
-		ak4642_write(codec, 0x00, 0x64);
+		snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
+		snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
+		ak4642_write(codec, L_IVC, 0x91); /* volume */
+		ak4642_write(codec, R_IVC, 0x91); /* volume */
+		snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
+						     PMVCM | PMMIN | PMDAC);
 		snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK,	PMHP);
 		snd_soc_update_bits(codec, PW_MGMT2, HPMTN,	HPMTN);
 	} else {
@@ -240,13 +266,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
 		 * This operation came from example code of
 		 * "ASAHI KASEI AK4642" (japanese) manual p94.
 		 */
-		ak4642_write(codec, 0x02, 0x05);
-		ak4642_write(codec, 0x06, 0x3c);
-		ak4642_write(codec, 0x08, 0xe1);
-		ak4642_write(codec, 0x0b, 0x00);
-		ak4642_write(codec, 0x07, 0x21);
-		ak4642_write(codec, 0x00, 0x41);
-		ak4642_write(codec, 0x10, 0x01);
+		ak4642_write(codec, SG_SL1, PMMP | MGAIN0);
+		ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
+		ak4642_write(codec, ALC_CTL1, ALC | LMTH0);
+		snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
+						     PMVCM | PMADL);
+		snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
 	}
 
 	return 0;
@@ -262,14 +287,14 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
 		/* stop headphone output */
 		snd_soc_update_bits(codec, PW_MGMT2, HPMTN,	0);
 		snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK,	0);
-		ak4642_write(codec, 0x00, 0x40);
-		ak4642_write(codec, 0x0e, 0x11);
-		ak4642_write(codec, 0x0f, 0x08);
+		snd_soc_update_bits(codec, PW_MGMT1, PMMIN | PMDAC, 0);
+		snd_soc_update_bits(codec, MD_CTL3, BST1, 0);
+		snd_soc_update_bits(codec, MD_CTL4, DACH, 0);
 	} else {
 		/* stop stereo input */
-		ak4642_write(codec, 0x00, 0x40);
-		ak4642_write(codec, 0x10, 0x00);
-		ak4642_write(codec, 0x07, 0x01);
+		snd_soc_update_bits(codec, PW_MGMT1, PMADL, 0);
+		snd_soc_update_bits(codec, PW_MGMT3, PMADR, 0);
+		snd_soc_update_bits(codec, ALC_CTL1, ALC, 0);
 	}
 }
 
@@ -393,8 +418,8 @@ static struct snd_soc_dai_ops ak4642_dai_ops = {
 	.hw_params	= ak4642_dai_hw_params,
 };
 
-struct snd_soc_dai ak4642_dai = {
-	.name = "AK4642",
+static struct snd_soc_dai_driver ak4642_dai = {
+	.name = "ak4642-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -410,112 +435,65 @@ struct snd_soc_dai ak4642_dai = {
 	.ops = &ak4642_dai_ops,
 	.symmetric_rates = 1,
 };
-EXPORT_SYMBOL_GPL(ak4642_dai);
 
-static int ak4642_resume(struct platform_device *pdev)
+static int ak4642_resume(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
 	ak4642_sync(codec);
 	return 0;
 }
 
-/*
- * initialise the AK4642 driver
- * register the mixer and dsp interfaces with the kernel
- */
-static int ak4642_init(struct ak4642_priv *ak4642)
+
+static int ak4642_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_codec *codec = &ak4642->codec;
-	int ret = 0;
+	struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
 
-	if (ak4642_codec) {
-		dev_err(codec->dev, "Another ak4642 is registered\n");
-		return -EINVAL;
-	}
+	dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
 
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	snd_soc_codec_set_drvdata(codec, ak4642);
-	codec->name		= "AK4642";
-	codec->owner		= THIS_MODULE;
-	codec->read		= ak4642_read_reg_cache;
-	codec->write		= ak4642_write;
-	codec->dai		= &ak4642_dai;
-	codec->num_dai		= 1;
 	codec->hw_write		= (hw_write_t)i2c_master_send;
-	codec->reg_cache_size	= ARRAY_SIZE(ak4642_reg);
-	codec->reg_cache	= kmemdup(ak4642_reg,
-					  sizeof(ak4642_reg), GFP_KERNEL);
+	codec->control_data	= ak4642->control_data;
 
-	if (!codec->reg_cache)
-		return -ENOMEM;
-
-	ak4642_dai.dev = codec->dev;
-	ak4642_codec = codec;
-
-	ret = snd_soc_register_codec(codec);
-	if (ret) {
-		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-		goto reg_cache_err;
-	}
-
-	ret = snd_soc_register_dai(&ak4642_dai);
-	if (ret) {
-		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-		snd_soc_unregister_codec(codec);
-		goto reg_cache_err;
-	}
-
-	return ret;
-
-reg_cache_err:
-	kfree(codec->reg_cache);
-	codec->reg_cache = NULL;
+	snd_soc_add_controls(codec, ak4642_snd_controls,
+			     ARRAY_SIZE(ak4642_snd_controls));
 
-	return ret;
+	return 0;
 }
 
+static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
+	.probe			= ak4642_probe,
+	.resume			= ak4642_resume,
+	.read			= ak4642_read_reg_cache,
+	.write			= ak4642_write,
+	.reg_cache_size		= ARRAY_SIZE(ak4642_reg),
+	.reg_word_size		= sizeof(u8),
+	.reg_cache_default	= ak4642_reg,
+};
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
-static int ak4642_i2c_probe(struct i2c_client *i2c,
-			    const struct i2c_device_id *id)
+static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
+				      const struct i2c_device_id *id)
 {
 	struct ak4642_priv *ak4642;
-	struct snd_soc_codec *codec;
 	int ret;
 
 	ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL);
 	if (!ak4642)
 		return -ENOMEM;
 
-	codec = &ak4642->codec;
-	codec->dev = &i2c->dev;
-
 	i2c_set_clientdata(i2c, ak4642);
-	codec->control_data = i2c;
+	ak4642->control_data = i2c;
+	ak4642->control_type = SND_SOC_I2C;
 
-	ret = ak4642_init(ak4642);
-	if (ret < 0) {
-		printk(KERN_ERR "failed to initialise AK4642\n");
+	ret =  snd_soc_register_codec(&i2c->dev,
+			&soc_codec_dev_ak4642, &ak4642_dai, 1);
+	if (ret < 0)
 		kfree(ak4642);
-	}
-
 	return ret;
 }
 
-static int ak4642_i2c_remove(struct i2c_client *client)
+static __devexit int ak4642_i2c_remove(struct i2c_client *client)
 {
-	struct ak4642_priv *ak4642 = i2c_get_clientdata(client);
-
-	snd_soc_unregister_dai(&ak4642_dai);
-	snd_soc_unregister_codec(&ak4642->codec);
-	kfree(ak4642->codec.reg_cache);
-	kfree(ak4642);
-	ak4642_codec = NULL;
-
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -528,64 +506,15 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
 
 static struct i2c_driver ak4642_i2c_driver = {
 	.driver = {
-		.name = "AK4642 I2C Codec",
+		.name = "ak4642-codec",
 		.owner = THIS_MODULE,
 	},
 	.probe		= ak4642_i2c_probe,
-	.remove		= ak4642_i2c_remove,
+	.remove		= __devexit_p(ak4642_i2c_remove),
 	.id_table	= ak4642_i2c_id,
 };
-
 #endif
 
-static int ak4642_probe(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	int ret;
-
-	if (!ak4642_codec) {
-		dev_err(&pdev->dev, "Codec device not registered\n");
-		return -ENODEV;
-	}
-
-	socdev->card->codec = ak4642_codec;
-
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		printk(KERN_ERR "ak4642: failed to create pcms\n");
-		goto pcm_err;
-	}
-
-	snd_soc_add_controls(ak4642_codec, ak4642_snd_controls,
-			     ARRAY_SIZE(ak4642_snd_controls));
-
-	dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
-	return ret;
-
-pcm_err:
-	return ret;
-
-}
-
-/* power down chip */
-static int ak4642_remove(struct platform_device *pdev)
-{
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
-
-	return 0;
-}
-
-struct snd_soc_codec_device soc_codec_dev_ak4642 = {
-	.probe =	ak4642_probe,
-	.remove =	ak4642_remove,
-	.resume =	ak4642_resume,
-};
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642);
-
 static int __init ak4642_modinit(void)
 {
 	int ret = 0;

+ 0 - 20
sound/soc/codecs/ak4642.h

@@ -1,20 +0,0 @@
-/*
- * ak4642.h  --  AK4642 Soc Audio driver
- *
- * Copyright (C) 2009 Renesas Solutions Corp.
- * Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on ak4535.c
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _AK4642_H
-#define _AK4642_H
-
-extern struct snd_soc_dai ak4642_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4642;
-
-#endif

+ 29 - 111
sound/soc/codecs/ak4671.c

@@ -23,11 +23,11 @@
 
 #include "ak4671.h"
 
-static struct snd_soc_codec *ak4671_codec;
 
 /* codec private data */
 struct ak4671_priv {
-	struct snd_soc_codec codec;
+	enum snd_soc_control_type control_type;
+	void *control_data;
 	u8 reg_cache[AK4671_CACHEREGNUM];
 };
 
@@ -619,8 +619,8 @@ static struct snd_soc_dai_ops ak4671_dai_ops = {
 	.set_fmt	= ak4671_set_dai_fmt,
 };
 
-struct snd_soc_dai ak4671_dai = {
-	.name = "AK4671",
+static struct snd_soc_dai_driver ak4671_dai = {
+	.name = "ak4671-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -635,27 +635,18 @@ struct snd_soc_dai ak4671_dai = {
 		.formats = AK4671_FORMATS,},
 	.ops = &ak4671_dai_ops,
 };
-EXPORT_SYMBOL_GPL(ak4671_dai);
 
-static int ak4671_probe(struct platform_device *pdev)
+static int ak4671_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret = 0;
-
-	if (ak4671_codec == NULL) {
-		dev_err(&pdev->dev, "Codec device not registered\n");
-		return -ENODEV;
-	}
+	struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
+	int ret;
 
-	socdev->card->codec = ak4671_codec;
-	codec = ak4671_codec;
+	codec->hw_write = (hw_write_t)i2c_master_send;
 
-	/* register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+	ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
 	if (ret < 0) {
-		dev_err(codec->dev, "failed to create pcms: %d\n", ret);
-		goto pcm_err;
+		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+		return ret;
 	}
 
 	snd_soc_add_controls(codec, ak4671_snd_controls,
@@ -665,121 +656,48 @@ static int ak4671_probe(struct platform_device *pdev)
 	ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return ret;
-
-pcm_err:
-	return ret;
 }
 
-static int ak4671_remove(struct platform_device *pdev)
+static int ak4671_remove(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
-
+	ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_ak4671 = {
+static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
 	.probe = ak4671_probe,
 	.remove = ak4671_remove,
+	.set_bias_level = ak4671_set_bias_level,
+	.reg_cache_size = AK4671_CACHEREGNUM,
+	.reg_word_size = sizeof(u8),
+	.reg_cache_default = ak4671_reg,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671);
-
-static int ak4671_register(struct ak4671_priv *ak4671,
-		enum snd_soc_control_type control)
-{
-	int ret;
-	struct snd_soc_codec *codec = &ak4671->codec;
-
-	if (ak4671_codec) {
-		dev_err(codec->dev, "Another AK4671 is registered\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-
-	snd_soc_codec_set_drvdata(codec,  ak4671);
-	codec->name = "AK4671";
-	codec->owner = THIS_MODULE;
-	codec->bias_level = SND_SOC_BIAS_OFF;
-	codec->set_bias_level = ak4671_set_bias_level;
-	codec->dai = &ak4671_dai;
-	codec->num_dai = 1;
-	codec->reg_cache_size = AK4671_CACHEREGNUM;
-	codec->reg_cache = &ak4671->reg_cache;
-
-	memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg));
-
-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, control);
-	if (ret < 0) {
-		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
-		goto err;
-	}
-
-	ak4671_dai.dev = codec->dev;
-	ak4671_codec = codec;
-
-	ret = snd_soc_register_codec(codec);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to register codec: %d\n", ret);
-		goto err;
-	}
-
-	ret = snd_soc_register_dai(&ak4671_dai);
-	if (ret != 0) {
-		dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
-		goto err_codec;
-	}
-
-	return 0;
-
-err_codec:
-	snd_soc_unregister_codec(codec);
-err:
-	kfree(ak4671);
-	return ret;
-}
-
-static void ak4671_unregister(struct ak4671_priv *ak4671)
-{
-	ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF);
-	snd_soc_unregister_dai(&ak4671_dai);
-	snd_soc_unregister_codec(&ak4671->codec);
-	kfree(ak4671);
-	ak4671_codec = NULL;
-}
 
 static int __devinit ak4671_i2c_probe(struct i2c_client *client,
 		const struct i2c_device_id *id)
 {
 	struct ak4671_priv *ak4671;
-	struct snd_soc_codec *codec;
+	int ret;
 
 	ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL);
 	if (ak4671 == NULL)
 		return -ENOMEM;
 
-	codec = &ak4671->codec;
-	codec->hw_write = (hw_write_t)i2c_master_send;
-
 	i2c_set_clientdata(client, ak4671);
-	codec->control_data = client;
-
-	codec->dev = &client->dev;
+	ak4671->control_data = client;
+	ak4671->control_type = SND_SOC_I2C;
 
-	return ak4671_register(ak4671, SND_SOC_I2C);
+	ret = snd_soc_register_codec(&client->dev,
+			&soc_codec_dev_ak4671, &ak4671_dai, 1);
+	if (ret < 0)
+		kfree(ak4671);
+	return ret;
 }
 
 static __devexit int ak4671_i2c_remove(struct i2c_client *client)
 {
-	struct ak4671_priv *ak4671 = i2c_get_clientdata(client);
-
-	ak4671_unregister(ak4671);
-
+	snd_soc_unregister_codec(&client->dev);
+	kfree(i2c_get_clientdata(client));
 	return 0;
 }
 
@@ -791,7 +709,7 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id);
 
 static struct i2c_driver ak4671_i2c_driver = {
 	.driver = {
-		.name = "ak4671",
+		.name = "ak4671-codec",
 		.owner = THIS_MODULE,
 	},
 	.probe = ak4671_i2c_probe,

+ 0 - 3
sound/soc/codecs/ak4671.h

@@ -150,7 +150,4 @@
 /* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */
 #define AK4671_MUTEN				0x04
 
-extern struct snd_soc_dai ak4671_dai;
-extern struct snd_soc_codec_device soc_codec_dev_ak4671;
-
 #endif

+ 29 - 103
sound/soc/codecs/cq93vc.c

@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/clk.h>
 #include <linux/mfd/davinci_voicecodec.h>
+#include <linux/spi/spi.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -41,8 +42,6 @@
 
 #include <mach/dm365.h>
 
-#include "cq93vc.h"
-
 static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
 						unsigned int reg)
 {
@@ -130,8 +129,8 @@ static struct snd_soc_dai_ops cq93vc_dai_ops = {
 	.set_sysclk	= cq93vc_set_dai_sysclk,
 };
 
-struct snd_soc_dai cq93vc_dai = {
-	.name = "CQ93VC",
+static struct snd_soc_dai_driver cq93vc_dai = {
+	.name = "cq93vc-hifi",
 	.playback = {
 		.stream_name = "Playback",
 		.channels_min = 1,
@@ -146,36 +145,20 @@ struct snd_soc_dai cq93vc_dai = {
 		.formats = CQ93VC_FORMATS,},
 	.ops = &cq93vc_dai_ops,
 };
-EXPORT_SYMBOL_GPL(cq93vc_dai);
 
-static int cq93vc_resume(struct platform_device *pdev)
+static int cq93vc_resume(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
 	cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
 	return 0;
 }
 
-static struct snd_soc_codec *cq93vc_codec;
-
-static int cq93vc_probe(struct platform_device *pdev)
+static int cq93vc_probe(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct device *dev = &pdev->dev;
-	struct snd_soc_codec *codec;
-	int ret;
-
-	socdev->card->codec = cq93vc_codec;
-	codec = socdev->card->codec;
-
-	/* Register pcms */
-	ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
-	if (ret < 0) {
-		dev_err(dev, "%s: failed to create pcms\n", pdev->name);
-		return ret;
-	}
+	struct davinci_vc *davinci_vc = codec->dev->platform_data;
+
+	davinci_vc->cq93vc.codec = codec;
+	codec->control_data = davinci_vc;
 
 	/* Set controls */
 	snd_soc_add_controls(codec, cq93vc_snd_controls,
@@ -187,108 +170,51 @@ static int cq93vc_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static int cq93vc_remove(struct platform_device *pdev)
+static int cq93vc_remove(struct snd_soc_codec *codec)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-
-	snd_soc_free_pcms(socdev);
-	snd_soc_dapm_free(socdev);
+	cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
 
 	return 0;
 }
 
-struct snd_soc_codec_device soc_codec_dev_cq93vc = {
+static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
+	.read = cq93vc_read,
+	.write = cq93vc_write,
+	.set_bias_level = cq93vc_set_bias_level,
 	.probe = cq93vc_probe,
 	.remove = cq93vc_remove,
 	.resume = cq93vc_resume,
 };
-EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
 
-static __init int cq93vc_codec_probe(struct platform_device *pdev)
+static int cq93vc_platform_probe(struct platform_device *pdev)
 {
-	struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec;
-	int ret;
-
-	codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
-	if (codec == NULL) {
-		dev_dbg(davinci_vc->dev,
-			"could not allocate memory for codec data\n");
-		return -ENOMEM;
-	}
-
-	davinci_vc->cq93vc.codec = codec;
-
-	cq93vc_dai.dev = &pdev->dev;
-
-	mutex_init(&codec->mutex);
-	INIT_LIST_HEAD(&codec->dapm_widgets);
-	INIT_LIST_HEAD(&codec->dapm_paths);
-	codec->dev = &pdev->dev;
-	codec->name = "CQ93VC";
-	codec->owner = THIS_MODULE;
-	codec->read = cq93vc_read;
-	codec->write = cq93vc_write;
-	codec->set_bias_level = cq93vc_set_bias_level;
-	codec->dai = &cq93vc_dai;
-	codec->num_dai = 1;
-	codec->control_data = davinci_vc;
-
-	cq93vc_codec = codec;
-
-	ret = snd_soc_register_codec(codec);
-	if (ret) {
-		dev_err(davinci_vc->dev, "failed to register codec\n");
-		goto fail1;
-	}
-
-	ret = snd_soc_register_dai(&cq93vc_dai);
-	if (ret) {
-		dev_err(davinci_vc->dev, "could register dai\n");
-		goto fail2;
-	}
-	return 0;
-
-fail2:
-	snd_soc_unregister_codec(codec);
-
-fail1:
-	kfree(codec);
-	cq93vc_codec = NULL;
-
-	return ret;
+	return snd_soc_register_codec(&pdev->dev,
+			&soc_codec_dev_cq93vc, &cq93vc_dai, 1);
 }
 
-static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
+static int cq93vc_platform_remove(struct platform_device *pdev)
 {
-	struct snd_soc_device *socdev = platform_get_drvdata(pdev);
-	struct snd_soc_codec *codec = socdev->card->codec;
-
-	snd_soc_unregister_dai(&cq93vc_dai);
-	snd_soc_unregister_codec(&codec);
-
-	kfree(codec);
-	cq93vc_codec = NULL;
-
+	snd_soc_unregister_codec(&pdev->dev);
 	return 0;
 }
 
 static struct platform_driver cq93vc_codec_driver = {
 	.driver = {
-		   .name = "cq93vc",
-		   .owner = THIS_MODULE,
-		   },
-	.probe = cq93vc_codec_probe,
-	.remove = __devexit_p(cq93vc_codec_remove),
+			.name = "cq93vc-codec",
+			.owner = THIS_MODULE,
+	},
+
+	.probe = cq93vc_platform_probe,
+	.remove = __devexit_p(cq93vc_platform_remove),
 };
 
-static __init int cq93vc_init(void)
+static int __init cq93vc_init(void)
 {
-	return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
+	return platform_driver_register(&cq93vc_codec_driver);
 }
 module_init(cq93vc_init);
 
-static __exit void cq93vc_exit(void)
+static void __exit cq93vc_exit(void)
 {
 	platform_driver_unregister(&cq93vc_codec_driver);
 }

+ 0 - 29
sound/soc/codecs/cq93vc.h

@@ -1,29 +0,0 @@
-/*
- * ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
- *
- * Copyright (C) 2010 Texas Instruments, Inc
- *
- * Author: Miguel Aguilar <miguel.aguilar@ridgerun.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _CQ93VC_H
-#define _CQ93VC_H
-
-extern struct snd_soc_dai cq93vc_dai;
-extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
-
-#endif

Некоторые файлы не были показаны из-за большого количества измененных файлов