aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-08-23 07:58:01 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-23 07:58:01 -0400
commit97e15b1fcf79a60cb146d4123e7c72ac2736e258 (patch)
tree5923cd4d4f2e1945b66a7aab27acf684f8590c47 /sound
parenta8165e0e6f0511d14132423b4bce2d285e890fc8 (diff)
parent38fec7272bc033b75a0eb8976c56c2024d371b7d (diff)
Merge remote branch 'broonie-asoc/for-2.6.37' into for-2.6.37
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c57
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.h2
-rw-r--r--sound/soc/atmel/sam9g20_wm8731.c12
-rw-r--r--sound/soc/au1x/db1200.c2
-rw-r--r--sound/soc/codecs/88pm860x-codec.c1486
-rw-r--r--sound/soc/codecs/88pm860x-codec.h97
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/cx20442.c2
-rw-r--r--sound/soc/codecs/tlv320aic3x.c80
-rw-r--r--sound/soc/codecs/tlv320aic3x.h2
-rw-r--r--sound/soc/codecs/wm8731.c31
-rw-r--r--sound/soc/codecs/wm8731.h4
-rw-r--r--sound/soc/fsl/Kconfig24
-rw-r--r--sound/soc/fsl/Makefile8
-rw-r--r--sound/soc/fsl/fsl_dma.c57
-rw-r--r--sound/soc/fsl/fsl_ssi.c42
-rw-r--r--sound/soc/fsl/mpc8610_hpcd.c10
-rw-r--r--sound/soc/fsl/p1022_ds.c590
-rw-r--r--sound/soc/omap/ams-delta.c2
-rw-r--r--sound/soc/pxa/Kconfig18
-rw-r--r--sound/soc/pxa/Makefile4
-rw-r--r--sound/soc/pxa/corgi.c2
-rw-r--r--sound/soc/pxa/e740_wm9705.c3
-rw-r--r--sound/soc/pxa/poodle.c2
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c1
-rw-r--r--sound/soc/pxa/saarb.c200
-rw-r--r--sound/soc/pxa/tavorevb3.c200
-rw-r--r--sound/soc/soc-core.c13
29 files changed, 2870 insertions, 87 deletions
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index eabf66af12cd..5d230cee3fa7 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -789,13 +789,14 @@ static struct snd_soc_dai_driver atmel_ssc_dai[NUM_SSC_DEVICES] = {
789 789
790static __devinit int asoc_ssc_probe(struct platform_device *pdev) 790static __devinit int asoc_ssc_probe(struct platform_device *pdev)
791{ 791{
792 return snd_soc_register_dais(&pdev->dev, atmel_ssc_dai, 792 BUG_ON(pdev->id < 0);
793 ARRAY_SIZE(atmel_ssc_dai)); 793 BUG_ON(pdev->id >= ARRAY_SIZE(atmel_ssc_dai));
794 return snd_soc_register_dai(&pdev->dev, &atmel_ssc_dai[pdev->id]);
794} 795}
795 796
796static int __devexit asoc_ssc_remove(struct platform_device *pdev) 797static int __devexit asoc_ssc_remove(struct platform_device *pdev)
797{ 798{
798 snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(atmel_ssc_dai)); 799 snd_soc_unregister_dai(&pdev->dev);
799 return 0; 800 return 0;
800} 801}
801 802
@@ -809,6 +810,56 @@ static struct platform_driver asoc_ssc_driver = {
809 .remove = __devexit_p(asoc_ssc_remove), 810 .remove = __devexit_p(asoc_ssc_remove),
810}; 811};
811 812
813/**
814 * atmel_ssc_set_audio - Allocate the specified SSC for audio use.
815 */
816int atmel_ssc_set_audio(int ssc_id)
817{
818 struct ssc_device *ssc;
819 static struct platform_device *dma_pdev;
820 struct platform_device *ssc_pdev;
821 int ret;
822
823 if (ssc_id < 0 || ssc_id >= ARRAY_SIZE(atmel_ssc_dai))
824 return -EINVAL;
825
826 /* Allocate a dummy device for DMA if we don't have one already */
827 if (!dma_pdev) {
828 dma_pdev = platform_device_alloc("atmel-pcm-audio", -1);
829 if (!dma_pdev)
830 return -ENOMEM;
831
832 ret = platform_device_add(dma_pdev);
833 if (ret < 0) {
834 platform_device_put(dma_pdev);
835 dma_pdev = NULL;
836 return ret;
837 }
838 }
839
840 ssc_pdev = platform_device_alloc("atmel-ssc-dai", ssc_id);
841 if (!ssc_pdev) {
842 ssc_free(ssc);
843 return -ENOMEM;
844 }
845
846 /* If we can grab the SSC briefly to parent the DAI device off it */
847 ssc = ssc_request(ssc_id);
848 if (IS_ERR(ssc))
849 pr_warn("Unable to parent ASoC SSC DAI on SSC: %ld\n",
850 PTR_ERR(ssc));
851 else
852 ssc_pdev->dev.parent = &(ssc->pdev->dev);
853 ssc_free(ssc);
854
855 ret = platform_device_add(ssc_pdev);
856 if (ret < 0)
857 platform_device_put(ssc_pdev);
858
859 return ret;
860}
861EXPORT_SYMBOL_GPL(atmel_ssc_set_audio);
862
812static int __init snd_atmel_ssc_init(void) 863static int __init snd_atmel_ssc_init(void)
813{ 864{
814 return platform_driver_register(&asoc_ssc_driver); 865 return platform_driver_register(&asoc_ssc_driver);
diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h
index 392a46953112..5d4f0f9b4d9a 100644
--- a/sound/soc/atmel/atmel_ssc_dai.h
+++ b/sound/soc/atmel/atmel_ssc_dai.h
@@ -117,4 +117,6 @@ struct atmel_ssc_info {
117 struct atmel_ssc_state ssc_state; 117 struct atmel_ssc_state ssc_state;
118}; 118};
119 119
120int atmel_ssc_set_audio(int ssc);
121
120#endif /* _AT91_SSC_DAI_H */ 122#endif /* _AT91_SSC_DAI_H */
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c
index 66a6f1879689..293569dfd0ed 100644
--- a/sound/soc/atmel/sam9g20_wm8731.c
+++ b/sound/soc/atmel/sam9g20_wm8731.c
@@ -146,7 +146,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
146 "at91sam9g20ek_wm8731 " 146 "at91sam9g20ek_wm8731 "
147 ": at91sam9g20ek_wm8731_init() called\n"); 147 ": at91sam9g20ek_wm8731_init() called\n");
148 148
149 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, 149 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
150 MCLK_RATE, SND_SOC_CLOCK_IN); 150 MCLK_RATE, SND_SOC_CLOCK_IN);
151 if (ret < 0) { 151 if (ret < 0) {
152 printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret); 152 printk(KERN_ERR "Failed to set WM8731 SYSCLK: %d\n", ret);
@@ -183,8 +183,8 @@ static struct snd_soc_dai_link at91sam9g20ek_dai = {
183 .cpu_dai_name = "atmel-ssc-dai.0", 183 .cpu_dai_name = "atmel-ssc-dai.0",
184 .codec_dai_name = "wm8731-hifi", 184 .codec_dai_name = "wm8731-hifi",
185 .init = at91sam9g20ek_wm8731_init, 185 .init = at91sam9g20ek_wm8731_init,
186 .platform_name = "atmel_pcm-audio", 186 .platform_name = "atmel-pcm-audio",
187 .codec_name = "wm8731-codec.0-001a", 187 .codec_name = "wm8731-codec.0-001b",
188 .ops = &at91sam9g20ek_ops, 188 .ops = &at91sam9g20ek_ops,
189}; 189};
190 190
@@ -205,6 +205,12 @@ static int __init at91sam9g20ek_init(void)
205 if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc())) 205 if (!(machine_is_at91sam9g20ek() || machine_is_at91sam9g20ek_2mmc()))
206 return -ENODEV; 206 return -ENODEV;
207 207
208 ret = atmel_ssc_set_audio(0);
209 if (ret != 0) {
210 pr_err("Failed to set SSC 0 for audio: %d\n", ret);
211 return ret;
212 }
213
208 /* 214 /*
209 * Codec MCLK is supplied by PCK0 - set it up. 215 * Codec MCLK is supplied by PCK0 - set it up.
210 */ 216 */
diff --git a/sound/soc/au1x/db1200.c b/sound/soc/au1x/db1200.c
index 8780c90107fc..d8dc8225576a 100644
--- a/sound/soc/au1x/db1200.c
+++ b/sound/soc/au1x/db1200.c
@@ -49,7 +49,7 @@ static int db1200_i2s_startup(struct snd_pcm_substream *substream)
49 int ret; 49 int ret;
50 50
51 /* WM8731 has its own 12MHz crystal */ 51 /* WM8731 has its own 12MHz crystal */
52 snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, 52 snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL,
53 12000000, SND_SOC_CLOCK_IN); 53 12000000, SND_SOC_CLOCK_IN);
54 54
55 /* codec is bitclock and lrclk master */ 55 /* codec is bitclock and lrclk master */
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c
new file mode 100644
index 000000000000..01d19e9f53f9
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.c
@@ -0,0 +1,1486 @@
1/*
2 * 88pm860x-codec.c -- 88PM860x ALSA SoC Audio Driver
3 *
4 * Copyright 2010 Marvell International Ltd.
5 * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/i2c.h>
15#include <linux/platform_device.h>
16#include <linux/mfd/88pm860x.h>
17#include <linux/slab.h>
18#include <sound/core.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
23#include <sound/tlv.h>
24#include <sound/initval.h>
25#include <sound/jack.h>
26
27#include "88pm860x-codec.h"
28
29#define MAX_NAME_LEN 20
30#define REG_CACHE_SIZE 0x40
31#define REG_CACHE_BASE 0xb0
32
33/* Status Register 1 (0x01) */
34#define REG_STATUS_1 0x01
35#define MIC_STATUS (1 << 7)
36#define HOOK_STATUS (1 << 6)
37#define HEADSET_STATUS (1 << 5)
38
39/* Mic Detection Register (0x37) */
40#define REG_MIC_DET 0x37
41#define CONTINUOUS_POLLING (3 << 1)
42#define EN_MIC_DET (1 << 0)
43#define MICDET_MASK 0x07
44
45/* Headset Detection Register (0x38) */
46#define REG_HS_DET 0x38
47#define EN_HS_DET (1 << 0)
48
49/* Misc2 Register (0x42) */
50#define REG_MISC2 0x42
51#define AUDIO_PLL (1 << 5)
52#define AUDIO_SECTION_RESET (1 << 4)
53#define AUDIO_SECTION_ON (1 << 3)
54
55/* PCM Interface Register 2 (0xb1) */
56#define PCM_INF2_BCLK (1 << 6) /* Bit clock polarity */
57#define PCM_INF2_FS (1 << 5) /* Frame Sync polarity */
58#define PCM_INF2_MASTER (1 << 4) /* Master / Slave */
59#define PCM_INF2_18WL (1 << 3) /* 18 / 16 bits */
60#define PCM_GENERAL_I2S 0
61#define PCM_EXACT_I2S 1
62#define PCM_LEFT_I2S 2
63#define PCM_RIGHT_I2S 3
64#define PCM_SHORT_FS 4
65#define PCM_LONG_FS 5
66#define PCM_MODE_MASK 7
67
68/* I2S Interface Register 4 (0xbe) */
69#define I2S_EQU_BYP (1 << 6)
70
71/* DAC Offset Register (0xcb) */
72#define DAC_MUTE (1 << 7)
73#define MUTE_LEFT (1 << 6)
74#define MUTE_RIGHT (1 << 2)
75
76/* ADC Analog Register 1 (0xd0) */
77#define REG_ADC_ANA_1 0xd0
78#define MIC1BIAS_MASK 0x60
79
80/* Earpiece/Speaker Control Register 2 (0xda) */
81#define REG_EAR2 0xda
82#define RSYNC_CHANGE (1 << 2)
83
84/* Audio Supplies Register 2 (0xdc) */
85#define REG_SUPPLIES2 0xdc
86#define LDO15_READY (1 << 4)
87#define LDO15_EN (1 << 3)
88#define CPUMP_READY (1 << 2)
89#define CPUMP_EN (1 << 1)
90#define AUDIO_EN (1 << 0)
91#define SUPPLY_MASK (LDO15_EN | CPUMP_EN | AUDIO_EN)
92
93/* Audio Enable Register 1 (0xdd) */
94#define ADC_MOD_RIGHT (1 << 1)
95#define ADC_MOD_LEFT (1 << 0)
96
97/* Audio Enable Register 2 (0xde) */
98#define ADC_LEFT (1 << 5)
99#define ADC_RIGHT (1 << 4)
100
101/* DAC Enable Register 2 (0xe1) */
102#define DAC_LEFT (1 << 5)
103#define DAC_RIGHT (1 << 4)
104#define MODULATOR (1 << 3)
105
106/* Shorts Register (0xeb) */
107#define REG_SHORTS 0xeb
108#define CLR_SHORT_LO2 (1 << 7)
109#define SHORT_LO2 (1 << 6)
110#define CLR_SHORT_LO1 (1 << 5)
111#define SHORT_LO1 (1 << 4)
112#define CLR_SHORT_HS2 (1 << 3)
113#define SHORT_HS2 (1 << 2)
114#define CLR_SHORT_HS1 (1 << 1)
115#define SHORT_HS1 (1 << 0)
116
117/*
118 * This widget should be just after DAC & PGA in DAPM power-on sequence and
119 * before DAC & PGA in DAPM power-off sequence.
120 */
121#define PM860X_DAPM_OUTPUT(wname, wevent) \
122{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \
123 .shift = 0, .invert = 0, .kcontrols = NULL, \
124 .num_kcontrols = 0, .event = wevent, \
125 .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, }
126
127struct pm860x_det {
128 struct snd_soc_jack *hp_jack;
129 struct snd_soc_jack *mic_jack;
130 int hp_det;
131 int mic_det;
132 int hook_det;
133 int hs_shrt;
134 int lo_shrt;
135};
136
137struct pm860x_priv {
138 unsigned int sysclk;
139 unsigned int pcmclk;
140 unsigned int dir;
141 unsigned int filter;
142 struct snd_soc_codec *codec;
143 struct i2c_client *i2c;
144 struct pm860x_chip *chip;
145 struct pm860x_det det;
146
147 int irq[4];
148 unsigned char name[4][MAX_NAME_LEN];
149 unsigned char reg_cache[REG_CACHE_SIZE];
150};
151
152/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
153static const DECLARE_TLV_DB_SCALE(dpga_tlv, -9450, 150, 1);
154
155/* -9dB to 0db in 3dB steps */
156static const DECLARE_TLV_DB_SCALE(adc_tlv, -900, 300, 0);
157
158/* {-23, -17, -13.5, -11, -9, -6, -3, 0}dB */
159static const unsigned int mic_tlv[] = {
160 TLV_DB_RANGE_HEAD(5),
161 0, 0, TLV_DB_SCALE_ITEM(-2300, 0, 0),
162 1, 1, TLV_DB_SCALE_ITEM(-1700, 0, 0),
163 2, 2, TLV_DB_SCALE_ITEM(-1350, 0, 0),
164 3, 3, TLV_DB_SCALE_ITEM(-1100, 0, 0),
165 4, 7, TLV_DB_SCALE_ITEM(-900, 300, 0),
166};
167
168/* {0, 0, 0, -6, 0, 6, 12, 18}dB */
169static const unsigned int aux_tlv[] = {
170 TLV_DB_RANGE_HEAD(2),
171 0, 2, TLV_DB_SCALE_ITEM(0, 0, 0),
172 3, 7, TLV_DB_SCALE_ITEM(-600, 600, 0),
173};
174
175/* {-16, -13, -10, -7, -5.2, -3,3, -2.2, 0}dB, mute instead of -16dB */
176static const unsigned int out_tlv[] = {
177 TLV_DB_RANGE_HEAD(4),
178 0, 3, TLV_DB_SCALE_ITEM(-1600, 300, 1),
179 4, 4, TLV_DB_SCALE_ITEM(-520, 0, 0),
180 5, 5, TLV_DB_SCALE_ITEM(-330, 0, 0),
181 6, 7, TLV_DB_SCALE_ITEM(-220, 220, 0),
182};
183
184static const unsigned int st_tlv[] = {
185 TLV_DB_RANGE_HEAD(8),
186 0, 1, TLV_DB_SCALE_ITEM(-12041, 602, 0),
187 2, 3, TLV_DB_SCALE_ITEM(-11087, 250, 0),
188 4, 5, TLV_DB_SCALE_ITEM(-10643, 158, 0),
189 6, 7, TLV_DB_SCALE_ITEM(-10351, 116, 0),
190 8, 9, TLV_DB_SCALE_ITEM(-10133, 92, 0),
191 10, 13, TLV_DB_SCALE_ITEM(-9958, 70, 0),
192 14, 17, TLV_DB_SCALE_ITEM(-9689, 53, 0),
193 18, 271, TLV_DB_SCALE_ITEM(-9484, 37, 0),
194};
195
196/* Sidetone Gain = M * 2^(-5-N) */
197struct st_gain {
198 unsigned int db;
199 unsigned int m;
200 unsigned int n;
201};
202
203static struct st_gain st_table[] = {
204 {-12041, 1, 15}, {-11439, 1, 14}, {-11087, 3, 15}, {-10837, 1, 13},
205 {-10643, 5, 15}, {-10485, 3, 14}, {-10351, 7, 15}, {-10235, 1, 12},
206 {-10133, 9, 15}, {-10041, 5, 14}, { -9958, 11, 15}, { -9883, 3, 13},
207 { -9813, 13, 15}, { -9749, 7, 14}, { -9689, 15, 15}, { -9633, 1, 11},
208 { -9580, 17, 15}, { -9531, 9, 14}, { -9484, 19, 15}, { -9439, 5, 13},
209 { -9397, 21, 15}, { -9356, 11, 14}, { -9318, 23, 15}, { -9281, 3, 12},
210 { -9245, 25, 15}, { -9211, 13, 14}, { -9178, 27, 15}, { -9147, 7, 13},
211 { -9116, 29, 15}, { -9087, 15, 14}, { -9058, 31, 15}, { -9031, 1, 10},
212 { -8978, 17, 14}, { -8929, 9, 13}, { -8882, 19, 14}, { -8837, 5, 12},
213 { -8795, 21, 14}, { -8754, 11, 13}, { -8716, 23, 14}, { -8679, 3, 11},
214 { -8643, 25, 14}, { -8609, 13, 13}, { -8576, 27, 14}, { -8545, 7, 12},
215 { -8514, 29, 14}, { -8485, 15, 13}, { -8456, 31, 14}, { -8429, 1, 9},
216 { -8376, 17, 13}, { -8327, 9, 12}, { -8280, 19, 13}, { -8235, 5, 11},
217 { -8193, 21, 13}, { -8152, 11, 12}, { -8114, 23, 13}, { -8077, 3, 10},
218 { -8041, 25, 13}, { -8007, 13, 12}, { -7974, 27, 13}, { -7943, 7, 11},
219 { -7912, 29, 13}, { -7883, 15, 12}, { -7854, 31, 13}, { -7827, 1, 8},
220 { -7774, 17, 12}, { -7724, 9, 11}, { -7678, 19, 12}, { -7633, 5, 10},
221 { -7591, 21, 12}, { -7550, 11, 11}, { -7512, 23, 12}, { -7475, 3, 9},
222 { -7439, 25, 12}, { -7405, 13, 11}, { -7372, 27, 12}, { -7341, 7, 10},
223 { -7310, 29, 12}, { -7281, 15, 11}, { -7252, 31, 12}, { -7225, 1, 7},
224 { -7172, 17, 11}, { -7122, 9, 10}, { -7075, 19, 11}, { -7031, 5, 9},
225 { -6989, 21, 11}, { -6948, 11, 10}, { -6910, 23, 11}, { -6873, 3, 8},
226 { -6837, 25, 11}, { -6803, 13, 10}, { -6770, 27, 11}, { -6739, 7, 9},
227 { -6708, 29, 11}, { -6679, 15, 10}, { -6650, 31, 11}, { -6623, 1, 6},
228 { -6570, 17, 10}, { -6520, 9, 9}, { -6473, 19, 10}, { -6429, 5, 8},
229 { -6386, 21, 10}, { -6346, 11, 9}, { -6307, 23, 10}, { -6270, 3, 7},
230 { -6235, 25, 10}, { -6201, 13, 9}, { -6168, 27, 10}, { -6137, 7, 8},
231 { -6106, 29, 10}, { -6077, 15, 9}, { -6048, 31, 10}, { -6021, 1, 5},
232 { -5968, 17, 9}, { -5918, 9, 8}, { -5871, 19, 9}, { -5827, 5, 7},
233 { -5784, 21, 9}, { -5744, 11, 8}, { -5705, 23, 9}, { -5668, 3, 6},
234 { -5633, 25, 9}, { -5599, 13, 8}, { -5566, 27, 9}, { -5535, 7, 7},
235 { -5504, 29, 9}, { -5475, 15, 8}, { -5446, 31, 9}, { -5419, 1, 4},
236 { -5366, 17, 8}, { -5316, 9, 7}, { -5269, 19, 8}, { -5225, 5, 6},
237 { -5182, 21, 8}, { -5142, 11, 7}, { -5103, 23, 8}, { -5066, 3, 5},
238 { -5031, 25, 8}, { -4997, 13, 7}, { -4964, 27, 8}, { -4932, 7, 6},
239 { -4902, 29, 8}, { -4873, 15, 7}, { -4844, 31, 8}, { -4816, 1, 3},
240 { -4764, 17, 7}, { -4714, 9, 6}, { -4667, 19, 7}, { -4623, 5, 5},
241 { -4580, 21, 7}, { -4540, 11, 6}, { -4501, 23, 7}, { -4464, 3, 4},
242 { -4429, 25, 7}, { -4395, 13, 6}, { -4362, 27, 7}, { -4330, 7, 5},
243 { -4300, 29, 7}, { -4270, 15, 6}, { -4242, 31, 7}, { -4214, 1, 2},
244 { -4162, 17, 6}, { -4112, 9, 5}, { -4065, 19, 6}, { -4021, 5, 4},
245 { -3978, 21, 6}, { -3938, 11, 5}, { -3899, 23, 6}, { -3862, 3, 3},
246 { -3827, 25, 6}, { -3793, 13, 5}, { -3760, 27, 6}, { -3728, 7, 4},
247 { -3698, 29, 6}, { -3668, 15, 5}, { -3640, 31, 6}, { -3612, 1, 1},
248 { -3560, 17, 5}, { -3510, 9, 4}, { -3463, 19, 5}, { -3419, 5, 3},
249 { -3376, 21, 5}, { -3336, 11, 4}, { -3297, 23, 5}, { -3260, 3, 2},
250 { -3225, 25, 5}, { -3191, 13, 4}, { -3158, 27, 5}, { -3126, 7, 3},
251 { -3096, 29, 5}, { -3066, 15, 4}, { -3038, 31, 5}, { -3010, 1, 0},
252 { -2958, 17, 4}, { -2908, 9, 3}, { -2861, 19, 4}, { -2816, 5, 2},
253 { -2774, 21, 4}, { -2734, 11, 3}, { -2695, 23, 4}, { -2658, 3, 1},
254 { -2623, 25, 4}, { -2589, 13, 3}, { -2556, 27, 4}, { -2524, 7, 2},
255 { -2494, 29, 4}, { -2464, 15, 3}, { -2436, 31, 4}, { -2408, 2, 0},
256 { -2356, 17, 3}, { -2306, 9, 2}, { -2259, 19, 3}, { -2214, 5, 1},
257 { -2172, 21, 3}, { -2132, 11, 2}, { -2093, 23, 3}, { -2056, 3, 0},
258 { -2021, 25, 3}, { -1987, 13, 2}, { -1954, 27, 3}, { -1922, 7, 1},
259 { -1892, 29, 3}, { -1862, 15, 2}, { -1834, 31, 3}, { -1806, 4, 0},
260 { -1754, 17, 2}, { -1704, 9, 1}, { -1657, 19, 2}, { -1612, 5, 0},
261 { -1570, 21, 2}, { -1530, 11, 1}, { -1491, 23, 2}, { -1454, 6, 0},
262 { -1419, 25, 2}, { -1384, 13, 1}, { -1352, 27, 2}, { -1320, 7, 0},
263 { -1290, 29, 2}, { -1260, 15, 1}, { -1232, 31, 2}, { -1204, 8, 0},
264 { -1151, 17, 1}, { -1102, 9, 0}, { -1055, 19, 1}, { -1010, 10, 0},
265 { -968, 21, 1}, { -928, 11, 0}, { -889, 23, 1}, { -852, 12, 0},
266 { -816, 25, 1}, { -782, 13, 0}, { -750, 27, 1}, { -718, 14, 0},
267 { -688, 29, 1}, { -658, 15, 0}, { -630, 31, 1}, { -602, 16, 0},
268 { -549, 17, 0}, { -500, 18, 0}, { -453, 19, 0}, { -408, 20, 0},
269 { -366, 21, 0}, { -325, 22, 0}, { -287, 23, 0}, { -250, 24, 0},
270 { -214, 25, 0}, { -180, 26, 0}, { -148, 27, 0}, { -116, 28, 0},
271 { -86, 29, 0}, { -56, 30, 0}, { -28, 31, 0}, { 0, 0, 0},
272};
273
274static int pm860x_volatile(unsigned int reg)
275{
276 BUG_ON(reg >= REG_CACHE_SIZE);
277
278 switch (reg) {
279 case PM860X_AUDIO_SUPPLIES_2:
280 return 1;
281 }
282
283 return 0;
284}
285
286static unsigned int pm860x_read_reg_cache(struct snd_soc_codec *codec,
287 unsigned int reg)
288{
289 unsigned char *cache = codec->reg_cache;
290
291 BUG_ON(reg >= REG_CACHE_SIZE);
292
293 if (pm860x_volatile(reg))
294 return cache[reg];
295
296 reg += REG_CACHE_BASE;
297
298 return pm860x_reg_read(codec->control_data, reg);
299}
300
301static int pm860x_write_reg_cache(struct snd_soc_codec *codec,
302 unsigned int reg, unsigned int value)
303{
304 unsigned char *cache = codec->reg_cache;
305
306 BUG_ON(reg >= REG_CACHE_SIZE);
307
308 if (!pm860x_volatile(reg))
309 cache[reg] = (unsigned char)value;
310
311 reg += REG_CACHE_BASE;
312
313 return pm860x_reg_write(codec->control_data, reg, value);
314}
315
316static int snd_soc_get_volsw_2r_st(struct snd_kcontrol *kcontrol,
317 struct snd_ctl_elem_value *ucontrol)
318{
319 struct soc_mixer_control *mc =
320 (struct soc_mixer_control *)kcontrol->private_value;
321 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
322 unsigned int reg = mc->reg;
323 unsigned int reg2 = mc->rreg;
324 int val[2], val2[2], i;
325
326 val[0] = snd_soc_read(codec, reg) & 0x3f;
327 val[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT) >> 4) & 0xf;
328 val2[0] = snd_soc_read(codec, reg2) & 0x3f;
329 val2[1] = (snd_soc_read(codec, PM860X_SIDETONE_SHIFT)) & 0xf;
330
331 for (i = 0; i < ARRAY_SIZE(st_table); i++) {
332 if ((st_table[i].m == val[0]) && (st_table[i].n == val[1]))
333 ucontrol->value.integer.value[0] = i;
334 if ((st_table[i].m == val2[0]) && (st_table[i].n == val2[1]))
335 ucontrol->value.integer.value[1] = i;
336 }
337 return 0;
338}
339
340static int snd_soc_put_volsw_2r_st(struct snd_kcontrol *kcontrol,
341 struct snd_ctl_elem_value *ucontrol)
342{
343 struct soc_mixer_control *mc =
344 (struct soc_mixer_control *)kcontrol->private_value;
345 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
346 unsigned int reg = mc->reg;
347 unsigned int reg2 = mc->rreg;
348 int err;
349 unsigned int val, val2;
350
351 val = ucontrol->value.integer.value[0];
352 val2 = ucontrol->value.integer.value[1];
353
354 err = snd_soc_update_bits(codec, reg, 0x3f, st_table[val].m);
355 if (err < 0)
356 return err;
357 err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0xf0,
358 st_table[val].n << 4);
359 if (err < 0)
360 return err;
361
362 err = snd_soc_update_bits(codec, reg2, 0x3f, st_table[val2].m);
363 if (err < 0)
364 return err;
365 err = snd_soc_update_bits(codec, PM860X_SIDETONE_SHIFT, 0x0f,
366 st_table[val2].n);
367 return err;
368}
369
370static int snd_soc_get_volsw_2r_out(struct snd_kcontrol *kcontrol,
371 struct snd_ctl_elem_value *ucontrol)
372{
373 struct soc_mixer_control *mc =
374 (struct soc_mixer_control *)kcontrol->private_value;
375 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
376 unsigned int reg = mc->reg;
377 unsigned int reg2 = mc->rreg;
378 unsigned int shift = mc->shift;
379 int max = mc->max, val, val2;
380 unsigned int mask = (1 << fls(max)) - 1;
381
382 val = snd_soc_read(codec, reg) >> shift;
383 val2 = snd_soc_read(codec, reg2) >> shift;
384 ucontrol->value.integer.value[0] = (max - val) & mask;
385 ucontrol->value.integer.value[1] = (max - val2) & mask;
386
387 return 0;
388}
389
390static int snd_soc_put_volsw_2r_out(struct snd_kcontrol *kcontrol,
391 struct snd_ctl_elem_value *ucontrol)
392{
393 struct soc_mixer_control *mc =
394 (struct soc_mixer_control *)kcontrol->private_value;
395 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
396 unsigned int reg = mc->reg;
397 unsigned int reg2 = mc->rreg;
398 unsigned int shift = mc->shift;
399 int max = mc->max;
400 unsigned int mask = (1 << fls(max)) - 1;
401 int err;
402 unsigned int val, val2, val_mask;
403
404 val_mask = mask << shift;
405 val = ((max - ucontrol->value.integer.value[0]) & mask);
406 val2 = ((max - ucontrol->value.integer.value[1]) & mask);
407
408 val = val << shift;
409 val2 = val2 << shift;
410
411 err = snd_soc_update_bits(codec, reg, val_mask, val);
412 if (err < 0)
413 return err;
414
415 err = snd_soc_update_bits(codec, reg2, val_mask, val2);
416 return err;
417}
418
419/* DAPM Widget Events */
420/*
421 * A lot registers are belong to RSYNC domain. It requires enabling RSYNC bit
422 * after updating these registers. Otherwise, these updated registers won't
423 * be effective.
424 */
425static int pm860x_rsync_event(struct snd_soc_dapm_widget *w,
426 struct snd_kcontrol *kcontrol, int event)
427{
428 struct snd_soc_codec *codec = w->codec;
429
430 /*
431 * In order to avoid current on the load, mute power-on and power-off
432 * should be transients.
433 * Unmute by DAC_MUTE. It should be unmuted when DAPM sequence is
434 * finished.
435 */
436 snd_soc_update_bits(codec, PM860X_DAC_OFFSET, DAC_MUTE, 0);
437 snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
438 RSYNC_CHANGE, RSYNC_CHANGE);
439 return 0;
440}
441
442static int pm860x_dac_event(struct snd_soc_dapm_widget *w,
443 struct snd_kcontrol *kcontrol, int event)
444{
445 struct snd_soc_codec *codec = w->codec;
446 unsigned int dac = 0;
447 int data;
448
449 if (!strcmp(w->name, "Left DAC"))
450 dac = DAC_LEFT;
451 if (!strcmp(w->name, "Right DAC"))
452 dac = DAC_RIGHT;
453 switch (event) {
454 case SND_SOC_DAPM_PRE_PMU:
455 if (dac) {
456 /* Auto mute in power-on sequence. */
457 dac |= MODULATOR;
458 snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
459 DAC_MUTE, DAC_MUTE);
460 snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
461 RSYNC_CHANGE, RSYNC_CHANGE);
462 /* update dac */
463 snd_soc_update_bits(codec, PM860X_DAC_EN_2,
464 dac, dac);
465 }
466 break;
467 case SND_SOC_DAPM_PRE_PMD:
468 if (dac) {
469 /* Auto mute in power-off sequence. */
470 snd_soc_update_bits(codec, PM860X_DAC_OFFSET,
471 DAC_MUTE, DAC_MUTE);
472 snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
473 RSYNC_CHANGE, RSYNC_CHANGE);
474 /* update dac */
475 data = snd_soc_read(codec, PM860X_DAC_EN_2);
476 data &= ~dac;
477 if (!(data & (DAC_LEFT | DAC_RIGHT)))
478 data &= ~MODULATOR;
479 snd_soc_write(codec, PM860X_DAC_EN_2, data);
480 }
481 break;
482 }
483 return 0;
484}
485
486static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"};
487
488static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"};
489
490static const struct soc_enum pm860x_hs1_opamp_enum =
491 SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts);
492
493static const struct soc_enum pm860x_hs2_opamp_enum =
494 SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts);
495
496static const struct soc_enum pm860x_hs1_pa_enum =
497 SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts);
498
499static const struct soc_enum pm860x_hs2_pa_enum =
500 SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts);
501
502static const struct soc_enum pm860x_lo1_opamp_enum =
503 SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts);
504
505static const struct soc_enum pm860x_lo2_opamp_enum =
506 SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts);
507
508static const struct soc_enum pm860x_lo1_pa_enum =
509 SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts);
510
511static const struct soc_enum pm860x_lo2_pa_enum =
512 SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts);
513
514static const struct soc_enum pm860x_spk_pa_enum =
515 SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts);
516
517static const struct soc_enum pm860x_ear_pa_enum =
518 SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts);
519
520static const struct soc_enum pm860x_spk_ear_opamp_enum =
521 SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts);
522
523static const struct snd_kcontrol_new pm860x_snd_controls[] = {
524 SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2,
525 PM860X_ADC_ANA_3, 6, 3, 0, adc_tlv),
526 SOC_DOUBLE_TLV("AUX Capture Volume", PM860X_ADC_ANA_3, 0, 3, 7, 0,
527 aux_tlv),
528 SOC_SINGLE_TLV("MIC1 Capture Volume", PM860X_ADC_ANA_2, 0, 7, 0,
529 mic_tlv),
530 SOC_SINGLE_TLV("MIC3 Capture Volume", PM860X_ADC_ANA_2, 3, 7, 0,
531 mic_tlv),
532 SOC_DOUBLE_R_EXT_TLV("Sidetone Volume", PM860X_SIDETONE_L_GAIN,
533 PM860X_SIDETONE_R_GAIN, 0, ARRAY_SIZE(st_table)-1,
534 0, snd_soc_get_volsw_2r_st,
535 snd_soc_put_volsw_2r_st, st_tlv),
536 SOC_SINGLE_TLV("Speaker Playback Volume", PM860X_EAR_CTRL_1,
537 0, 7, 0, out_tlv),
538 SOC_DOUBLE_R_TLV("Line Playback Volume", PM860X_LO1_CTRL,
539 PM860X_LO2_CTRL, 0, 7, 0, out_tlv),
540 SOC_DOUBLE_R_TLV("Headset Playback Volume", PM860X_HS1_CTRL,
541 PM860X_HS2_CTRL, 0, 7, 0, out_tlv),
542 SOC_DOUBLE_R_EXT_TLV("Hifi Left Playback Volume",
543 PM860X_HIFIL_GAIN_LEFT,
544 PM860X_HIFIL_GAIN_RIGHT, 0, 63, 0,
545 snd_soc_get_volsw_2r_out,
546 snd_soc_put_volsw_2r_out, dpga_tlv),
547 SOC_DOUBLE_R_EXT_TLV("Hifi Right Playback Volume",
548 PM860X_HIFIR_GAIN_LEFT,
549 PM860X_HIFIR_GAIN_RIGHT, 0, 63, 0,
550 snd_soc_get_volsw_2r_out,
551 snd_soc_put_volsw_2r_out, dpga_tlv),
552 SOC_DOUBLE_R_EXT_TLV("Lofi Playback Volume", PM860X_LOFI_GAIN_LEFT,
553 PM860X_LOFI_GAIN_RIGHT, 0, 63, 0,
554 snd_soc_get_volsw_2r_out,
555 snd_soc_put_volsw_2r_out, dpga_tlv),
556 SOC_ENUM("Headset1 Operational Amplifier Current",
557 pm860x_hs1_opamp_enum),
558 SOC_ENUM("Headset2 Operational Amplifier Current",
559 pm860x_hs2_opamp_enum),
560 SOC_ENUM("Headset1 Amplifier Current", pm860x_hs1_pa_enum),
561 SOC_ENUM("Headset2 Amplifier Current", pm860x_hs2_pa_enum),
562 SOC_ENUM("Lineout1 Operational Amplifier Current",
563 pm860x_lo1_opamp_enum),
564 SOC_ENUM("Lineout2 Operational Amplifier Current",
565 pm860x_lo2_opamp_enum),
566 SOC_ENUM("Lineout1 Amplifier Current", pm860x_lo1_pa_enum),
567 SOC_ENUM("Lineout2 Amplifier Current", pm860x_lo2_pa_enum),
568 SOC_ENUM("Speaker Operational Amplifier Current",
569 pm860x_spk_ear_opamp_enum),
570 SOC_ENUM("Speaker Amplifier Current", pm860x_spk_pa_enum),
571 SOC_ENUM("Earpiece Amplifier Current", pm860x_ear_pa_enum),
572};
573
574/*
575 * DAPM Controls
576 */
577
578/* PCM Switch / PCM Interface */
579static const struct snd_kcontrol_new pcm_switch_controls =
580 SOC_DAPM_SINGLE("Switch", PM860X_ADC_EN_2, 0, 1, 0);
581
582/* AUX1 Switch */
583static const struct snd_kcontrol_new aux1_switch_controls =
584 SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 4, 1, 0);
585
586/* AUX2 Switch */
587static const struct snd_kcontrol_new aux2_switch_controls =
588 SOC_DAPM_SINGLE("Switch", PM860X_ANA_TO_ANA, 5, 1, 0);
589
590/* Left Ex. PA Switch */
591static const struct snd_kcontrol_new lepa_switch_controls =
592 SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 2, 1, 0);
593
594/* Right Ex. PA Switch */
595static const struct snd_kcontrol_new repa_switch_controls =
596 SOC_DAPM_SINGLE("Switch", PM860X_DAC_EN_2, 1, 1, 0);
597
598/* PCM Mux / Mux7 */
599static const char *aif1_text[] = {
600 "PCM L", "PCM R",
601};
602
603static const struct soc_enum aif1_enum =
604 SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text);
605
606static const struct snd_kcontrol_new aif1_mux =
607 SOC_DAPM_ENUM("PCM Mux", aif1_enum);
608
609/* I2S Mux / Mux9 */
610static const char *i2s_din_text[] = {
611 "DIN", "DIN1",
612};
613
614static const struct soc_enum i2s_din_enum =
615 SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text);
616
617static const struct snd_kcontrol_new i2s_din_mux =
618 SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum);
619
620/* I2S Mic Mux / Mux8 */
621static const char *i2s_mic_text[] = {
622 "Ex PA", "ADC",
623};
624
625static const struct soc_enum i2s_mic_enum =
626 SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text);
627
628static const struct snd_kcontrol_new i2s_mic_mux =
629 SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum);
630
631/* ADCL Mux / Mux2 */
632static const char *adcl_text[] = {
633 "ADCR", "ADCL",
634};
635
636static const struct soc_enum adcl_enum =
637 SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text);
638
639static const struct snd_kcontrol_new adcl_mux =
640 SOC_DAPM_ENUM("ADC Left Mux", adcl_enum);
641
642/* ADCR Mux / Mux3 */
643static const char *adcr_text[] = {
644 "ADCL", "ADCR",
645};
646
647static const struct soc_enum adcr_enum =
648 SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text);
649
650static const struct snd_kcontrol_new adcr_mux =
651 SOC_DAPM_ENUM("ADC Right Mux", adcr_enum);
652
653/* ADCR EC Mux / Mux6 */
654static const char *adcr_ec_text[] = {
655 "ADCR", "EC",
656};
657
658static const struct soc_enum adcr_ec_enum =
659 SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text);
660
661static const struct snd_kcontrol_new adcr_ec_mux =
662 SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum);
663
664/* EC Mux / Mux4 */
665static const char *ec_text[] = {
666 "Left", "Right", "Left + Right",
667};
668
669static const struct soc_enum ec_enum =
670 SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text);
671
672static const struct snd_kcontrol_new ec_mux =
673 SOC_DAPM_ENUM("EC Mux", ec_enum);
674
675static const char *dac_text[] = {
676 "No input", "Right", "Left", "No input",
677};
678
679/* DAC Headset 1 Mux / Mux10 */
680static const struct soc_enum dac_hs1_enum =
681 SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text);
682
683static const struct snd_kcontrol_new dac_hs1_mux =
684 SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum);
685
686/* DAC Headset 2 Mux / Mux11 */
687static const struct soc_enum dac_hs2_enum =
688 SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text);
689
690static const struct snd_kcontrol_new dac_hs2_mux =
691 SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum);
692
693/* DAC Lineout 1 Mux / Mux12 */
694static const struct soc_enum dac_lo1_enum =
695 SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text);
696
697static const struct snd_kcontrol_new dac_lo1_mux =
698 SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum);
699
700/* DAC Lineout 2 Mux / Mux13 */
701static const struct soc_enum dac_lo2_enum =
702 SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text);
703
704static const struct snd_kcontrol_new dac_lo2_mux =
705 SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum);
706
707/* DAC Spearker Earphone Mux / Mux14 */
708static const struct soc_enum dac_spk_ear_enum =
709 SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text);
710
711static const struct snd_kcontrol_new dac_spk_ear_mux =
712 SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum);
713
714/* Headset 1 Mux / Mux15 */
715static const char *in_text[] = {
716 "Digital", "Analog",
717};
718
719static const struct soc_enum hs1_enum =
720 SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text);
721
722static const struct snd_kcontrol_new hs1_mux =
723 SOC_DAPM_ENUM("Headset1 Mux", hs1_enum);
724
725/* Headset 2 Mux / Mux16 */
726static const struct soc_enum hs2_enum =
727 SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text);
728
729static const struct snd_kcontrol_new hs2_mux =
730 SOC_DAPM_ENUM("Headset2 Mux", hs2_enum);
731
732/* Lineout 1 Mux / Mux17 */
733static const struct soc_enum lo1_enum =
734 SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text);
735
736static const struct snd_kcontrol_new lo1_mux =
737 SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum);
738
739/* Lineout 2 Mux / Mux18 */
740static const struct soc_enum lo2_enum =
741 SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text);
742
743static const struct snd_kcontrol_new lo2_mux =
744 SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum);
745
746/* Speaker Earpiece Demux */
747static const char *spk_text[] = {
748 "Earpiece", "Speaker",
749};
750
751static const struct soc_enum spk_enum =
752 SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text);
753
754static const struct snd_kcontrol_new spk_demux =
755 SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum);
756
757/* MIC Mux / Mux1 */
758static const char *mic_text[] = {
759 "Mic 1", "Mic 2",
760};
761
762static const struct soc_enum mic_enum =
763 SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text);
764
765static const struct snd_kcontrol_new mic_mux =
766 SOC_DAPM_ENUM("MIC Mux", mic_enum);
767
768static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
769 SND_SOC_DAPM_AIF_IN("PCM SDI", "PCM Playback", 0,
770 PM860X_ADC_EN_2, 0, 0),
771 SND_SOC_DAPM_AIF_OUT("PCM SDO", "PCM Capture", 0,
772 PM860X_PCM_IFACE_3, 1, 1),
773
774
775 SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
776 PM860X_DAC_EN_2, 0, 0),
777 SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
778 PM860X_DAC_EN_2, 0, 0),
779 SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
780 PM860X_I2S_IFACE_3, 5, 1),
781 SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
782 SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
783 SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
784 SND_SOC_DAPM_MUX("EC Mux", SND_SOC_NOPM, 0, 0, &ec_mux),
785 SND_SOC_DAPM_MUX("ADCR EC Mux", SND_SOC_NOPM, 0, 0, &adcr_ec_mux),
786 SND_SOC_DAPM_SWITCH("Left EPA", SND_SOC_NOPM, 0, 0,
787 &lepa_switch_controls),
788 SND_SOC_DAPM_SWITCH("Right EPA", SND_SOC_NOPM, 0, 0,
789 &repa_switch_controls),
790
791 SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Left ADC MOD", PM860X_ADC_EN_1,
792 0, 1, 1, 0),
793 SND_SOC_DAPM_REG(snd_soc_dapm_supply, "Right ADC MOD", PM860X_ADC_EN_1,
794 1, 1, 1, 0),
795 SND_SOC_DAPM_ADC("Left ADC", NULL, PM860X_ADC_EN_2, 5, 0),
796 SND_SOC_DAPM_ADC("Right ADC", NULL, PM860X_ADC_EN_2, 4, 0),
797
798 SND_SOC_DAPM_SWITCH("AUX1 Switch", SND_SOC_NOPM, 0, 0,
799 &aux1_switch_controls),
800 SND_SOC_DAPM_SWITCH("AUX2 Switch", SND_SOC_NOPM, 0, 0,
801 &aux2_switch_controls),
802
803 SND_SOC_DAPM_MUX("MIC Mux", SND_SOC_NOPM, 0, 0, &mic_mux),
804 SND_SOC_DAPM_MICBIAS("Mic1 Bias", PM860X_ADC_ANA_1, 2, 0),
805 SND_SOC_DAPM_MICBIAS("Mic3 Bias", PM860X_ADC_ANA_1, 7, 0),
806 SND_SOC_DAPM_PGA("MIC1 Volume", PM860X_ADC_EN_1, 2, 0, NULL, 0),
807 SND_SOC_DAPM_PGA("MIC3 Volume", PM860X_ADC_EN_1, 3, 0, NULL, 0),
808 SND_SOC_DAPM_PGA("AUX1 Volume", PM860X_ADC_EN_1, 4, 0, NULL, 0),
809 SND_SOC_DAPM_PGA("AUX2 Volume", PM860X_ADC_EN_1, 5, 0, NULL, 0),
810 SND_SOC_DAPM_PGA("Sidetone PGA", PM860X_ADC_EN_2, 1, 0, NULL, 0),
811 SND_SOC_DAPM_PGA("Lofi PGA", PM860X_ADC_EN_2, 2, 0, NULL, 0),
812
813 SND_SOC_DAPM_INPUT("AUX1"),
814 SND_SOC_DAPM_INPUT("AUX2"),
815 SND_SOC_DAPM_INPUT("MIC1P"),
816 SND_SOC_DAPM_INPUT("MIC1N"),
817 SND_SOC_DAPM_INPUT("MIC2P"),
818 SND_SOC_DAPM_INPUT("MIC2N"),
819 SND_SOC_DAPM_INPUT("MIC3P"),
820 SND_SOC_DAPM_INPUT("MIC3N"),
821
822 SND_SOC_DAPM_DAC_E("Left DAC", NULL, SND_SOC_NOPM, 0, 0,
823 pm860x_dac_event,
824 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
825 SND_SOC_DAPM_DAC_E("Right DAC", NULL, SND_SOC_NOPM, 0, 0,
826 pm860x_dac_event,
827 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD),
828
829 SND_SOC_DAPM_MUX("I2S DIN Mux", SND_SOC_NOPM, 0, 0, &i2s_din_mux),
830 SND_SOC_DAPM_MUX("DAC HS1 Mux", SND_SOC_NOPM, 0, 0, &dac_hs1_mux),
831 SND_SOC_DAPM_MUX("DAC HS2 Mux", SND_SOC_NOPM, 0, 0, &dac_hs2_mux),
832 SND_SOC_DAPM_MUX("DAC LO1 Mux", SND_SOC_NOPM, 0, 0, &dac_lo1_mux),
833 SND_SOC_DAPM_MUX("DAC LO2 Mux", SND_SOC_NOPM, 0, 0, &dac_lo2_mux),
834 SND_SOC_DAPM_MUX("DAC SP Mux", SND_SOC_NOPM, 0, 0, &dac_spk_ear_mux),
835 SND_SOC_DAPM_MUX("Headset1 Mux", SND_SOC_NOPM, 0, 0, &hs1_mux),
836 SND_SOC_DAPM_MUX("Headset2 Mux", SND_SOC_NOPM, 0, 0, &hs2_mux),
837 SND_SOC_DAPM_MUX("Lineout1 Mux", SND_SOC_NOPM, 0, 0, &lo1_mux),
838 SND_SOC_DAPM_MUX("Lineout2 Mux", SND_SOC_NOPM, 0, 0, &lo2_mux),
839 SND_SOC_DAPM_MUX("Speaker Earpiece Demux", SND_SOC_NOPM, 0, 0,
840 &spk_demux),
841
842
843 SND_SOC_DAPM_PGA("Headset1 PGA", PM860X_DAC_EN_1, 0, 0, NULL, 0),
844 SND_SOC_DAPM_PGA("Headset2 PGA", PM860X_DAC_EN_1, 1, 0, NULL, 0),
845 SND_SOC_DAPM_OUTPUT("HS1"),
846 SND_SOC_DAPM_OUTPUT("HS2"),
847 SND_SOC_DAPM_PGA("Lineout1 PGA", PM860X_DAC_EN_1, 2, 0, NULL, 0),
848 SND_SOC_DAPM_PGA("Lineout2 PGA", PM860X_DAC_EN_1, 3, 0, NULL, 0),
849 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
850 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
851 SND_SOC_DAPM_PGA("Earpiece PGA", PM860X_DAC_EN_1, 4, 0, NULL, 0),
852 SND_SOC_DAPM_OUTPUT("EARP"),
853 SND_SOC_DAPM_OUTPUT("EARN"),
854 SND_SOC_DAPM_PGA("Speaker PGA", PM860X_DAC_EN_1, 5, 0, NULL, 0),
855 SND_SOC_DAPM_OUTPUT("LSP"),
856 SND_SOC_DAPM_OUTPUT("LSN"),
857 SND_SOC_DAPM_REG(snd_soc_dapm_supply, "VCODEC", PM860X_AUDIO_SUPPLIES_2,
858 0, SUPPLY_MASK, SUPPLY_MASK, 0),
859
860 PM860X_DAPM_OUTPUT("RSYNC", pm860x_rsync_event),
861};
862
863static const struct snd_soc_dapm_route audio_map[] = {
864 /* supply */
865 {"Left DAC", NULL, "VCODEC"},
866 {"Right DAC", NULL, "VCODEC"},
867 {"Left ADC", NULL, "VCODEC"},
868 {"Right ADC", NULL, "VCODEC"},
869 {"Left ADC", NULL, "Left ADC MOD"},
870 {"Right ADC", NULL, "Right ADC MOD"},
871
872 /* PCM/AIF1 Inputs */
873 {"PCM SDO", NULL, "ADC Left Mux"},
874 {"PCM SDO", NULL, "ADCR EC Mux"},
875
876 /* PCM/AFI2 Outputs */
877 {"Lofi PGA", NULL, "PCM SDI"},
878 {"Lofi PGA", NULL, "Sidetone PGA"},
879 {"Left DAC", NULL, "Lofi PGA"},
880 {"Right DAC", NULL, "Lofi PGA"},
881
882 /* I2S/AIF2 Inputs */
883 {"MIC Mux", "Mic 1", "MIC1P"},
884 {"MIC Mux", "Mic 1", "MIC1N"},
885 {"MIC Mux", "Mic 2", "MIC2P"},
886 {"MIC Mux", "Mic 2", "MIC2N"},
887 {"MIC1 Volume", NULL, "MIC Mux"},
888 {"MIC3 Volume", NULL, "MIC3P"},
889 {"MIC3 Volume", NULL, "MIC3N"},
890 {"Left ADC", NULL, "MIC1 Volume"},
891 {"Right ADC", NULL, "MIC3 Volume"},
892 {"ADC Left Mux", "ADCR", "Right ADC"},
893 {"ADC Left Mux", "ADCL", "Left ADC"},
894 {"ADC Right Mux", "ADCL", "Left ADC"},
895 {"ADC Right Mux", "ADCR", "Right ADC"},
896 {"Left EPA", "Switch", "Left DAC"},
897 {"Right EPA", "Switch", "Right DAC"},
898 {"EC Mux", "Left", "Left DAC"},
899 {"EC Mux", "Right", "Right DAC"},
900 {"EC Mux", "Left + Right", "Left DAC"},
901 {"EC Mux", "Left + Right", "Right DAC"},
902 {"ADCR EC Mux", "ADCR", "ADC Right Mux"},
903 {"ADCR EC Mux", "EC", "EC Mux"},
904 {"I2S Mic Mux", "Ex PA", "Left EPA"},
905 {"I2S Mic Mux", "Ex PA", "Right EPA"},
906 {"I2S Mic Mux", "ADC", "ADC Left Mux"},
907 {"I2S Mic Mux", "ADC", "ADCR EC Mux"},
908 {"I2S DOUT", NULL, "I2S Mic Mux"},
909
910 /* I2S/AIF2 Outputs */
911 {"I2S DIN Mux", "DIN", "I2S DIN"},
912 {"I2S DIN Mux", "DIN1", "I2S DIN1"},
913 {"Left DAC", NULL, "I2S DIN Mux"},
914 {"Right DAC", NULL, "I2S DIN Mux"},
915 {"DAC HS1 Mux", "Left", "Left DAC"},
916 {"DAC HS1 Mux", "Right", "Right DAC"},
917 {"DAC HS2 Mux", "Left", "Left DAC"},
918 {"DAC HS2 Mux", "Right", "Right DAC"},
919 {"DAC LO1 Mux", "Left", "Left DAC"},
920 {"DAC LO1 Mux", "Right", "Right DAC"},
921 {"DAC LO2 Mux", "Left", "Left DAC"},
922 {"DAC LO2 Mux", "Right", "Right DAC"},
923 {"Headset1 Mux", "Digital", "DAC HS1 Mux"},
924 {"Headset2 Mux", "Digital", "DAC HS2 Mux"},
925 {"Lineout1 Mux", "Digital", "DAC LO1 Mux"},
926 {"Lineout2 Mux", "Digital", "DAC LO2 Mux"},
927 {"Headset1 PGA", NULL, "Headset1 Mux"},
928 {"Headset2 PGA", NULL, "Headset2 Mux"},
929 {"Lineout1 PGA", NULL, "Lineout1 Mux"},
930 {"Lineout2 PGA", NULL, "Lineout2 Mux"},
931 {"DAC SP Mux", "Left", "Left DAC"},
932 {"DAC SP Mux", "Right", "Right DAC"},
933 {"Speaker Earpiece Demux", "Speaker", "DAC SP Mux"},
934 {"Speaker PGA", NULL, "Speaker Earpiece Demux"},
935 {"Earpiece PGA", NULL, "Speaker Earpiece Demux"},
936
937 {"RSYNC", NULL, "Headset1 PGA"},
938 {"RSYNC", NULL, "Headset2 PGA"},
939 {"RSYNC", NULL, "Lineout1 PGA"},
940 {"RSYNC", NULL, "Lineout2 PGA"},
941 {"RSYNC", NULL, "Speaker PGA"},
942 {"RSYNC", NULL, "Speaker PGA"},
943 {"RSYNC", NULL, "Earpiece PGA"},
944 {"RSYNC", NULL, "Earpiece PGA"},
945
946 {"HS1", NULL, "RSYNC"},
947 {"HS2", NULL, "RSYNC"},
948 {"LINEOUT1", NULL, "RSYNC"},
949 {"LINEOUT2", NULL, "RSYNC"},
950 {"LSP", NULL, "RSYNC"},
951 {"LSN", NULL, "RSYNC"},
952 {"EARP", NULL, "RSYNC"},
953 {"EARN", NULL, "RSYNC"},
954};
955
956/*
957 * Use MUTE_LEFT & MUTE_RIGHT to implement digital mute.
958 * These bits can also be used to mute.
959 */
960static int pm860x_digital_mute(struct snd_soc_dai *codec_dai, int mute)
961{
962 struct snd_soc_codec *codec = codec_dai->codec;
963 int data = 0, mask = MUTE_LEFT | MUTE_RIGHT;
964
965 if (mute)
966 data = mask;
967 snd_soc_update_bits(codec, PM860X_DAC_OFFSET, mask, data);
968 snd_soc_update_bits(codec, PM860X_EAR_CTRL_2,
969 RSYNC_CHANGE, RSYNC_CHANGE);
970 return 0;
971}
972
973static int pm860x_pcm_hw_params(struct snd_pcm_substream *substream,
974 struct snd_pcm_hw_params *params,
975 struct snd_soc_dai *dai)
976{
977 struct snd_soc_codec *codec = dai->codec;
978 unsigned char inf = 0, mask = 0;
979
980 /* bit size */
981 switch (params_format(params)) {
982 case SNDRV_PCM_FORMAT_S16_LE:
983 inf &= ~PCM_INF2_18WL;
984 break;
985 case SNDRV_PCM_FORMAT_S18_3LE:
986 inf |= PCM_INF2_18WL;
987 break;
988 default:
989 return -EINVAL;
990 }
991 mask |= PCM_INF2_18WL;
992 snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
993
994 /* sample rate */
995 switch (params_rate(params)) {
996 case 8000:
997 inf = 0;
998 break;
999 case 16000:
1000 inf = 3;
1001 break;
1002 case 32000:
1003 inf = 6;
1004 break;
1005 case 48000:
1006 inf = 8;
1007 break;
1008 default:
1009 return -EINVAL;
1010 }
1011 snd_soc_update_bits(codec, PM860X_PCM_RATE, 0x0f, inf);
1012
1013 return 0;
1014}
1015
1016static int pm860x_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai,
1017 unsigned int fmt)
1018{
1019 struct snd_soc_codec *codec = codec_dai->codec;
1020 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1021 unsigned char inf = 0, mask = 0;
1022 int ret = -EINVAL;
1023
1024 mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
1025
1026 /* set master/slave audio interface */
1027 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1028 case SND_SOC_DAIFMT_CBM_CFM:
1029 case SND_SOC_DAIFMT_CBM_CFS:
1030 if (pm860x->dir == PM860X_CLK_DIR_OUT) {
1031 inf |= PCM_INF2_MASTER;
1032 ret = 0;
1033 }
1034 break;
1035 case SND_SOC_DAIFMT_CBS_CFS:
1036 if (pm860x->dir == PM860X_CLK_DIR_IN) {
1037 inf &= ~PCM_INF2_MASTER;
1038 ret = 0;
1039 }
1040 break;
1041 }
1042
1043 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1044 case SND_SOC_DAIFMT_I2S:
1045 inf |= PCM_EXACT_I2S;
1046 ret = 0;
1047 break;
1048 }
1049 mask |= PCM_MODE_MASK;
1050 if (ret)
1051 return ret;
1052 snd_soc_update_bits(codec, PM860X_PCM_IFACE_2, mask, inf);
1053 return 0;
1054}
1055
1056static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
1057 int clk_id, unsigned int freq, int dir)
1058{
1059 struct snd_soc_codec *codec = codec_dai->codec;
1060 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1061
1062 if (dir == PM860X_CLK_DIR_OUT)
1063 pm860x->dir = PM860X_CLK_DIR_OUT;
1064 else {
1065 pm860x->dir = PM860X_CLK_DIR_IN;
1066 return -EINVAL;
1067 }
1068
1069 return 0;
1070}
1071
1072static int pm860x_i2s_hw_params(struct snd_pcm_substream *substream,
1073 struct snd_pcm_hw_params *params,
1074 struct snd_soc_dai *dai)
1075{
1076 struct snd_soc_codec *codec = dai->codec;
1077 unsigned char inf;
1078
1079 /* bit size */
1080 switch (params_format(params)) {
1081 case SNDRV_PCM_FORMAT_S16_LE:
1082 inf = 0;
1083 break;
1084 case SNDRV_PCM_FORMAT_S18_3LE:
1085 inf = PCM_INF2_18WL;
1086 break;
1087 default:
1088 return -EINVAL;
1089 }
1090 snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, PCM_INF2_18WL, inf);
1091
1092 /* sample rate */
1093 switch (params_rate(params)) {
1094 case 8000:
1095 inf = 0;
1096 break;
1097 case 11025:
1098 inf = 1;
1099 break;
1100 case 16000:
1101 inf = 3;
1102 break;
1103 case 22050:
1104 inf = 4;
1105 break;
1106 case 32000:
1107 inf = 6;
1108 break;
1109 case 44100:
1110 inf = 7;
1111 break;
1112 case 48000:
1113 inf = 8;
1114 break;
1115 default:
1116 return -EINVAL;
1117 }
1118 snd_soc_update_bits(codec, PM860X_I2S_IFACE_4, 0xf, inf);
1119
1120 return 0;
1121}
1122
1123static int pm860x_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
1124 unsigned int fmt)
1125{
1126 struct snd_soc_codec *codec = codec_dai->codec;
1127 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1128 unsigned char inf = 0, mask = 0;
1129
1130 mask |= PCM_INF2_BCLK | PCM_INF2_FS | PCM_INF2_MASTER;
1131
1132 /* set master/slave audio interface */
1133 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
1134 case SND_SOC_DAIFMT_CBM_CFM:
1135 if (pm860x->dir == PM860X_CLK_DIR_OUT)
1136 inf |= PCM_INF2_MASTER;
1137 else
1138 return -EINVAL;
1139 break;
1140 case SND_SOC_DAIFMT_CBS_CFS:
1141 if (pm860x->dir == PM860X_CLK_DIR_IN)
1142 inf &= ~PCM_INF2_MASTER;
1143 else
1144 return -EINVAL;
1145 break;
1146 default:
1147 return -EINVAL;
1148 }
1149
1150 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
1151 case SND_SOC_DAIFMT_I2S:
1152 inf |= PCM_EXACT_I2S;
1153 break;
1154 default:
1155 return -EINVAL;
1156 }
1157 mask |= PCM_MODE_MASK;
1158 snd_soc_update_bits(codec, PM860X_I2S_IFACE_2, mask, inf);
1159 return 0;
1160}
1161
1162static int pm860x_set_bias_level(struct snd_soc_codec *codec,
1163 enum snd_soc_bias_level level)
1164{
1165 int data;
1166
1167 switch (level) {
1168 case SND_SOC_BIAS_ON:
1169 break;
1170
1171 case SND_SOC_BIAS_PREPARE:
1172 break;
1173
1174 case SND_SOC_BIAS_STANDBY:
1175 if (codec->bias_level == SND_SOC_BIAS_OFF) {
1176 /* Enable Audio PLL & Audio section */
1177 data = AUDIO_PLL | AUDIO_SECTION_RESET
1178 | AUDIO_SECTION_ON;
1179 pm860x_reg_write(codec->control_data, REG_MISC2, data);
1180 }
1181 break;
1182
1183 case SND_SOC_BIAS_OFF:
1184 data = AUDIO_PLL | AUDIO_SECTION_RESET | AUDIO_SECTION_ON;
1185 pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
1186 break;
1187 }
1188 codec->bias_level = level;
1189 return 0;
1190}
1191
1192static struct snd_soc_dai_ops pm860x_pcm_dai_ops = {
1193 .digital_mute = pm860x_digital_mute,
1194 .hw_params = pm860x_pcm_hw_params,
1195 .set_fmt = pm860x_pcm_set_dai_fmt,
1196 .set_sysclk = pm860x_set_dai_sysclk,
1197};
1198
1199static struct snd_soc_dai_ops pm860x_i2s_dai_ops = {
1200 .digital_mute = pm860x_digital_mute,
1201 .hw_params = pm860x_i2s_hw_params,
1202 .set_fmt = pm860x_i2s_set_dai_fmt,
1203 .set_sysclk = pm860x_set_dai_sysclk,
1204};
1205
1206#define PM860X_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \
1207 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
1208
1209static struct snd_soc_dai_driver pm860x_dai[] = {
1210 {
1211 /* DAI PCM */
1212 .name = "88pm860x-pcm",
1213 .id = 1,
1214 .playback = {
1215 .stream_name = "PCM Playback",
1216 .channels_min = 2,
1217 .channels_max = 2,
1218 .rates = PM860X_RATES,
1219 .formats = SNDRV_PCM_FORMAT_S16_LE | \
1220 SNDRV_PCM_FORMAT_S18_3LE,
1221 },
1222 .capture = {
1223 .stream_name = "PCM Capture",
1224 .channels_min = 2,
1225 .channels_max = 2,
1226 .rates = PM860X_RATES,
1227 .formats = SNDRV_PCM_FORMAT_S16_LE | \
1228 SNDRV_PCM_FORMAT_S18_3LE,
1229 },
1230 .ops = &pm860x_pcm_dai_ops,
1231 }, {
1232 /* DAI I2S */
1233 .name = "88pm860x-i2s",
1234 .id = 2,
1235 .playback = {
1236 .stream_name = "I2S Playback",
1237 .channels_min = 2,
1238 .channels_max = 2,
1239 .rates = SNDRV_PCM_RATE_8000_48000,
1240 .formats = SNDRV_PCM_FORMAT_S16_LE | \
1241 SNDRV_PCM_FORMAT_S18_3LE,
1242 },
1243 .capture = {
1244 .stream_name = "I2S Capture",
1245 .channels_min = 2,
1246 .channels_max = 2,
1247 .rates = SNDRV_PCM_RATE_8000_48000,
1248 .formats = SNDRV_PCM_FORMAT_S16_LE | \
1249 SNDRV_PCM_FORMAT_S18_3LE,
1250 },
1251 .ops = &pm860x_i2s_dai_ops,
1252 },
1253};
1254
1255static irqreturn_t pm860x_codec_handler(int irq, void *data)
1256{
1257 struct pm860x_priv *pm860x = data;
1258 int status, shrt, report = 0, mic_report = 0;
1259 int mask;
1260
1261 status = pm860x_reg_read(pm860x->i2c, REG_STATUS_1);
1262 shrt = pm860x_reg_read(pm860x->i2c, REG_SHORTS);
1263 mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
1264 | pm860x->det.hp_det;
1265
1266 if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
1267 && (status & HEADSET_STATUS))
1268 report |= SND_JACK_HEADPHONE;
1269
1270 if ((pm860x->det.mic_det & SND_JACK_MICROPHONE)
1271 && (status & MIC_STATUS))
1272 mic_report |= SND_JACK_MICROPHONE;
1273
1274 if (pm860x->det.hs_shrt && (shrt & (SHORT_HS1 | SHORT_HS2)))
1275 report |= pm860x->det.hs_shrt;
1276
1277 if (pm860x->det.hook_det && (status & HOOK_STATUS))
1278 report |= pm860x->det.hook_det;
1279
1280 if (pm860x->det.lo_shrt && (shrt & (SHORT_LO1 | SHORT_LO2)))
1281 report |= pm860x->det.lo_shrt;
1282
1283 if (report)
1284 snd_soc_jack_report(pm860x->det.hp_jack, report, mask);
1285 if (mic_report)
1286 snd_soc_jack_report(pm860x->det.mic_jack, SND_JACK_MICROPHONE,
1287 SND_JACK_MICROPHONE);
1288
1289 dev_dbg(pm860x->codec->dev, "headphone report:0x%x, mask:%x\n",
1290 report, mask);
1291 dev_dbg(pm860x->codec->dev, "microphone report:0x%x\n", mic_report);
1292 return IRQ_HANDLED;
1293}
1294
1295int pm860x_hs_jack_detect(struct snd_soc_codec *codec,
1296 struct snd_soc_jack *jack,
1297 int det, int hook, int hs_shrt, int lo_shrt)
1298{
1299 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1300 int data;
1301
1302 pm860x->det.hp_jack = jack;
1303 pm860x->det.hp_det = det;
1304 pm860x->det.hook_det = hook;
1305 pm860x->det.hs_shrt = hs_shrt;
1306 pm860x->det.lo_shrt = lo_shrt;
1307
1308 if (det & SND_JACK_HEADPHONE)
1309 pm860x_set_bits(codec->control_data, REG_HS_DET,
1310 EN_HS_DET, EN_HS_DET);
1311 /* headset short detect */
1312 if (hs_shrt) {
1313 data = CLR_SHORT_HS2 | CLR_SHORT_HS1;
1314 pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
1315 }
1316 /* Lineout short detect */
1317 if (lo_shrt) {
1318 data = CLR_SHORT_LO2 | CLR_SHORT_LO1;
1319 pm860x_set_bits(codec->control_data, REG_SHORTS, data, data);
1320 }
1321
1322 /* sync status */
1323 pm860x_codec_handler(0, pm860x);
1324 return 0;
1325}
1326EXPORT_SYMBOL_GPL(pm860x_hs_jack_detect);
1327
1328int pm860x_mic_jack_detect(struct snd_soc_codec *codec,
1329 struct snd_soc_jack *jack, int det)
1330{
1331 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1332
1333 pm860x->det.mic_jack = jack;
1334 pm860x->det.mic_det = det;
1335
1336 if (det & SND_JACK_MICROPHONE)
1337 pm860x_set_bits(codec->control_data, REG_MIC_DET,
1338 MICDET_MASK, MICDET_MASK);
1339
1340 /* sync status */
1341 pm860x_codec_handler(0, pm860x);
1342 return 0;
1343}
1344EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
1345
1346static int pm860x_probe(struct snd_soc_codec *codec)
1347{
1348 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1349 int i, ret;
1350
1351 pm860x->codec = codec;
1352
1353 codec->control_data = pm860x->i2c;
1354
1355 for (i = 0; i < 4; i++) {
1356 ret = request_threaded_irq(pm860x->irq[i], NULL,
1357 pm860x_codec_handler, IRQF_ONESHOT,
1358 pm860x->name[i], pm860x);
1359 if (ret < 0) {
1360 dev_err(codec->dev, "Failed to request IRQ!\n");
1361 goto out_irq;
1362 }
1363 }
1364
1365 pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1366
1367 ret = pm860x_bulk_read(codec->control_data, REG_CACHE_BASE,
1368 REG_CACHE_SIZE, codec->reg_cache);
1369 if (ret < 0) {
1370 dev_err(codec->dev, "Failed to fill register cache: %d\n",
1371 ret);
1372 goto out_codec;
1373 }
1374
1375 snd_soc_add_controls(codec, pm860x_snd_controls,
1376 ARRAY_SIZE(pm860x_snd_controls));
1377 snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
1378 ARRAY_SIZE(pm860x_dapm_widgets));
1379 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
1380 return 0;
1381
1382out_codec:
1383 i = 3;
1384out_irq:
1385 for (; i >= 0; i--)
1386 free_irq(pm860x->irq[i], pm860x);
1387 return -EINVAL;
1388}
1389
1390static int pm860x_remove(struct snd_soc_codec *codec)
1391{
1392 struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
1393 int i;
1394
1395 for (i = 3; i >= 0; i--)
1396 free_irq(pm860x->irq[i], pm860x);
1397 pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF);
1398 return 0;
1399}
1400
1401static struct snd_soc_codec_driver soc_codec_dev_pm860x = {
1402 .probe = pm860x_probe,
1403 .remove = pm860x_remove,
1404 .read = pm860x_read_reg_cache,
1405 .write = pm860x_write_reg_cache,
1406 .reg_cache_size = REG_CACHE_SIZE,
1407 .reg_word_size = sizeof(u8),
1408 .set_bias_level = pm860x_set_bias_level,
1409};
1410
1411static int __devinit pm860x_codec_probe(struct platform_device *pdev)
1412{
1413 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
1414 struct pm860x_priv *pm860x;
1415 struct resource *res;
1416 int i, ret;
1417
1418 pm860x = kzalloc(sizeof(struct pm860x_priv), GFP_KERNEL);
1419 if (pm860x == NULL)
1420 return -ENOMEM;
1421
1422 pm860x->chip = chip;
1423 pm860x->i2c = (chip->id == CHIP_PM8607) ? chip->client
1424 : chip->companion;
1425 platform_set_drvdata(pdev, pm860x);
1426
1427 for (i = 0; i < 4; i++) {
1428 res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
1429 if (!res) {
1430 dev_err(&pdev->dev, "Failed to get IRQ resources\n");
1431 goto out;
1432 }
1433 pm860x->irq[i] = res->start + chip->irq_base;
1434 strncpy(pm860x->name[i], res->name, MAX_NAME_LEN);
1435 }
1436
1437 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_pm860x,
1438 pm860x_dai, ARRAY_SIZE(pm860x_dai));
1439 if (ret) {
1440 dev_err(&pdev->dev, "Failed to register codec\n");
1441 goto out;
1442 }
1443 return ret;
1444
1445out:
1446 platform_set_drvdata(pdev, NULL);
1447 kfree(pm860x);
1448 return -EINVAL;
1449}
1450
1451static int __devexit pm860x_codec_remove(struct platform_device *pdev)
1452{
1453 struct pm860x_priv *pm860x = platform_get_drvdata(pdev);
1454
1455 snd_soc_unregister_codec(&pdev->dev);
1456 platform_set_drvdata(pdev, NULL);
1457 kfree(pm860x);
1458 return 0;
1459}
1460
1461static struct platform_driver pm860x_codec_driver = {
1462 .driver = {
1463 .name = "88pm860x-codec",
1464 .owner = THIS_MODULE,
1465 },
1466 .probe = pm860x_codec_probe,
1467 .remove = __devexit_p(pm860x_codec_remove),
1468};
1469
1470static __init int pm860x_init(void)
1471{
1472 return platform_driver_register(&pm860x_codec_driver);
1473}
1474module_init(pm860x_init);
1475
1476static __exit void pm860x_exit(void)
1477{
1478 platform_driver_unregister(&pm860x_codec_driver);
1479}
1480module_exit(pm860x_exit);
1481
1482MODULE_DESCRIPTION("ASoC 88PM860x driver");
1483MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
1484MODULE_LICENSE("GPL");
1485MODULE_ALIAS("platform:88pm860x-codec");
1486
diff --git a/sound/soc/codecs/88pm860x-codec.h b/sound/soc/codecs/88pm860x-codec.h
new file mode 100644
index 000000000000..3364ba4a3607
--- /dev/null
+++ b/sound/soc/codecs/88pm860x-codec.h
@@ -0,0 +1,97 @@
1/*
2 * 88pm860x-codec.h -- 88PM860x ALSA SoC Audio Driver
3 *
4 * Copyright 2010 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef __88PM860X_H
13#define __88PM860X_H
14
15/* The offset of these registers are 0xb0 */
16#define PM860X_PCM_IFACE_1 0x00
17#define PM860X_PCM_IFACE_2 0x01
18#define PM860X_PCM_IFACE_3 0x02
19#define PM860X_PCM_RATE 0x03
20#define PM860X_EC_PATH 0x04
21#define PM860X_SIDETONE_L_GAIN 0x05
22#define PM860X_SIDETONE_R_GAIN 0x06
23#define PM860X_SIDETONE_SHIFT 0x07
24#define PM860X_ADC_OFFSET_1 0x08
25#define PM860X_ADC_OFFSET_2 0x09
26#define PM860X_DMIC_DELAY 0x0a
27
28#define PM860X_I2S_IFACE_1 0x0b
29#define PM860X_I2S_IFACE_2 0x0c
30#define PM860X_I2S_IFACE_3 0x0d
31#define PM860X_I2S_IFACE_4 0x0e
32#define PM860X_EQUALIZER_N0_1 0x0f
33#define PM860X_EQUALIZER_N0_2 0x10
34#define PM860X_EQUALIZER_N1_1 0x11
35#define PM860X_EQUALIZER_N1_2 0x12
36#define PM860X_EQUALIZER_D1_1 0x13
37#define PM860X_EQUALIZER_D1_2 0x14
38#define PM860X_LOFI_GAIN_LEFT 0x15
39#define PM860X_LOFI_GAIN_RIGHT 0x16
40#define PM860X_HIFIL_GAIN_LEFT 0x17
41#define PM860X_HIFIL_GAIN_RIGHT 0x18
42#define PM860X_HIFIR_GAIN_LEFT 0x19
43#define PM860X_HIFIR_GAIN_RIGHT 0x1a
44#define PM860X_DAC_OFFSET 0x1b
45#define PM860X_OFFSET_LEFT_1 0x1c
46#define PM860X_OFFSET_LEFT_2 0x1d
47#define PM860X_OFFSET_RIGHT_1 0x1e
48#define PM860X_OFFSET_RIGHT_2 0x1f
49#define PM860X_ADC_ANA_1 0x20
50#define PM860X_ADC_ANA_2 0x21
51#define PM860X_ADC_ANA_3 0x22
52#define PM860X_ADC_ANA_4 0x23
53#define PM860X_ANA_TO_ANA 0x24
54#define PM860X_HS1_CTRL 0x25
55#define PM860X_HS2_CTRL 0x26
56#define PM860X_LO1_CTRL 0x27
57#define PM860X_LO2_CTRL 0x28
58#define PM860X_EAR_CTRL_1 0x29
59#define PM860X_EAR_CTRL_2 0x2a
60#define PM860X_AUDIO_SUPPLIES_1 0x2b
61#define PM860X_AUDIO_SUPPLIES_2 0x2c
62#define PM860X_ADC_EN_1 0x2d
63#define PM860X_ADC_EN_2 0x2e
64#define PM860X_DAC_EN_1 0x2f
65#define PM860X_DAC_EN_2 0x31
66#define PM860X_AUDIO_CAL_1 0x32
67#define PM860X_AUDIO_CAL_2 0x33
68#define PM860X_AUDIO_CAL_3 0x34
69#define PM860X_AUDIO_CAL_4 0x35
70#define PM860X_AUDIO_CAL_5 0x36
71#define PM860X_ANA_INPUT_SEL_1 0x37
72#define PM860X_ANA_INPUT_SEL_2 0x38
73
74#define PM860X_PCM_IFACE_4 0x39
75#define PM860X_I2S_IFACE_5 0x3a
76
77#define PM860X_SHORTS 0x3b
78#define PM860X_PLL_ADJ_1 0x3c
79#define PM860X_PLL_ADJ_2 0x3d
80
81/* bits definition */
82#define PM860X_CLK_DIR_IN 0
83#define PM860X_CLK_DIR_OUT 1
84
85#define PM860X_DET_HEADSET (1 << 0)
86#define PM860X_DET_MIC (1 << 1)
87#define PM860X_DET_HOOK (1 << 2)
88#define PM860X_SHORT_HEADSET (1 << 3)
89#define PM860X_SHORT_LINEOUT (1 << 4)
90#define PM860X_DET_MASK 0x1F
91
92extern int pm860x_hs_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
93 int, int, int, int);
94extern int pm860x_mic_jack_detect(struct snd_soc_codec *, struct snd_soc_jack *,
95 int);
96
97#endif /* __88PM860X_H */
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index bfdd92b78fb6..a3cfc184ee50 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -10,6 +10,7 @@ config SND_SOC_I2C_AND_SPI
10 10
11config SND_SOC_ALL_CODECS 11config SND_SOC_ALL_CODECS
12 tristate "Build all ASoC CODEC drivers" 12 tristate "Build all ASoC CODEC drivers"
13 select SND_SOC_88PM860X if MFD_88PM860X
13 select SND_SOC_L3 14 select SND_SOC_L3
14 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS 15 select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
15 select SND_SOC_AD1836 if SPI_MASTER 16 select SND_SOC_AD1836 if SPI_MASTER
@@ -85,6 +86,9 @@ config SND_SOC_ALL_CODECS
85 86
86 If unsure select "N". 87 If unsure select "N".
87 88
89config SND_SOC_88PM860X
90 tristate
91
88config SND_SOC_WM_HUBS 92config SND_SOC_WM_HUBS
89 tristate 93 tristate
90 default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y 94 default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 9c3c39fd99ad..b9c43582c5bd 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -1,3 +1,4 @@
1snd-soc-88pm860x-objs := 88pm860x-codec.o
1snd-soc-ac97-objs := ac97.o 2snd-soc-ac97-objs := ac97.o
2snd-soc-ad1836-objs := ad1836.o 3snd-soc-ad1836-objs := ad1836.o
3snd-soc-ad193x-objs := ad193x.o 4snd-soc-ad193x-objs := ad193x.o
@@ -67,6 +68,7 @@ snd-soc-tpa6130a2-objs := tpa6130a2.o
67snd-soc-wm2000-objs := wm2000.o 68snd-soc-wm2000-objs := wm2000.o
68snd-soc-wm9090-objs := wm9090.o 69snd-soc-wm9090-objs := wm9090.o
69 70
71obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o
70obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o 72obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
71obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o 73obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
72obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o 74obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
diff --git a/sound/soc/codecs/cx20442.c b/sound/soc/codecs/cx20442.c
index cf4323dbf9c4..e8d27c8f9ba3 100644
--- a/sound/soc/codecs/cx20442.c
+++ b/sound/soc/codecs/cx20442.c
@@ -318,7 +318,7 @@ EXPORT_SYMBOL_GPL(v253_ops);
318 */ 318 */
319 319
320static struct snd_soc_dai_driver cx20442_dai = { 320static struct snd_soc_dai_driver cx20442_dai = {
321 .name = "cx20442-hifi", 321 .name = "cx20442-voice",
322 .playback = { 322 .playback = {
323 .stream_name = "Playback", 323 .stream_name = "Playback",
324 .channels_min = 1, 324 .channels_min = 1,
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index 0b80e242a66d..efae8b53fd64 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -12,11 +12,11 @@
12 * 12 *
13 * Notes: 13 * Notes:
14 * The AIC3X is a driver for a low power stereo audio 14 * The AIC3X is a driver for a low power stereo audio
15 * codecs aic31, aic32, aic33. 15 * codecs aic31, aic32, aic33, aic3007.
16 * 16 *
17 * It supports full aic33 codec functionality. 17 * It supports full aic33 codec functionality.
18 * The compatibility with aic32, aic31 is as follows: 18 * The compatibility with aic32, aic31 and aic3007 is as follows:
19 * aic32 | aic31 19 * aic32/aic3007 | aic31
20 * --------------------------------------- 20 * ---------------------------------------
21 * MONO_LOUT -> N/A | MONO_LOUT -> N/A 21 * MONO_LOUT -> N/A | MONO_LOUT -> N/A
22 * | IN1L -> LINE1L 22 * | IN1L -> LINE1L
@@ -70,6 +70,10 @@ struct aic3x_priv {
70 unsigned int sysclk; 70 unsigned int sysclk;
71 int master; 71 int master;
72 int gpio_reset; 72 int gpio_reset;
73#define AIC3X_MODEL_3X 0
74#define AIC3X_MODEL_33 1
75#define AIC3X_MODEL_3007 2
76 u16 model;
73}; 77};
74 78
75/* 79/*
@@ -361,6 +365,14 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
361 SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), 365 SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
362}; 366};
363 367
368/*
369 * Class-D amplifier gain. From 0 to 18 dB in 6 dB steps
370 */
371static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0);
372
373static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
374 SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv);
375
364/* Left DAC Mux */ 376/* Left DAC Mux */
365static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = 377static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
366SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); 378SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
@@ -589,6 +601,15 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
589 SND_SOC_DAPM_INPUT("LINE2R"), 601 SND_SOC_DAPM_INPUT("LINE2R"),
590}; 602};
591 603
604static const struct snd_soc_dapm_widget aic3007_dapm_widgets[] = {
605 /* Class-D outputs */
606 SND_SOC_DAPM_PGA("Left Class-D Out", CLASSD_CTRL, 3, 0, NULL, 0),
607 SND_SOC_DAPM_PGA("Right Class-D Out", CLASSD_CTRL, 2, 0, NULL, 0),
608
609 SND_SOC_DAPM_OUTPUT("SPOP"),
610 SND_SOC_DAPM_OUTPUT("SPOM"),
611};
612
592static const struct snd_soc_dapm_route intercon[] = { 613static const struct snd_soc_dapm_route intercon[] = {
593 /* Left Output */ 614 /* Left Output */
594 {"Left DAC Mux", "DAC_L1", "Left DAC"}, 615 {"Left DAC Mux", "DAC_L1", "Left DAC"},
@@ -759,14 +780,30 @@ static const struct snd_soc_dapm_route intercon[] = {
759 {"GPIO1 dmic modclk", NULL, "DMic Rate 32"}, 780 {"GPIO1 dmic modclk", NULL, "DMic Rate 32"},
760}; 781};
761 782
783static const struct snd_soc_dapm_route intercon_3007[] = {
784 /* Class-D outputs */
785 {"Left Class-D Out", NULL, "Left Line Out"},
786 {"Right Class-D Out", NULL, "Left Line Out"},
787 {"SPOP", NULL, "Left Class-D Out"},
788 {"SPOM", NULL, "Right Class-D Out"},
789};
790
762static int aic3x_add_widgets(struct snd_soc_codec *codec) 791static int aic3x_add_widgets(struct snd_soc_codec *codec)
763{ 792{
793 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
794
764 snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets, 795 snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
765 ARRAY_SIZE(aic3x_dapm_widgets)); 796 ARRAY_SIZE(aic3x_dapm_widgets));
766 797
767 /* set up audio path interconnects */ 798 /* set up audio path interconnects */
768 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); 799 snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
769 800
801 if (aic3x->model == AIC3X_MODEL_3007) {
802 snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
803 ARRAY_SIZE(aic3007_dapm_widgets));
804 snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
805 }
806
770 return 0; 807 return 0;
771} 808}
772 809
@@ -1117,6 +1154,7 @@ static struct snd_soc_dai_driver aic3x_dai = {
1117 .rates = AIC3X_RATES, 1154 .rates = AIC3X_RATES,
1118 .formats = AIC3X_FORMATS,}, 1155 .formats = AIC3X_FORMATS,},
1119 .ops = &aic3x_dai_ops, 1156 .ops = &aic3x_dai_ops,
1157 .symmetric_rates = 1,
1120}; 1158};
1121 1159
1122static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state) 1160static int aic3x_suspend(struct snd_soc_codec *codec, pm_message_t state)
@@ -1150,6 +1188,7 @@ static int aic3x_resume(struct snd_soc_codec *codec)
1150 */ 1188 */
1151static int aic3x_init(struct snd_soc_codec *codec) 1189static int aic3x_init(struct snd_soc_codec *codec)
1152{ 1190{
1191 struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
1153 int reg; 1192 int reg;
1154 1193
1155 aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); 1194 aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT);
@@ -1218,6 +1257,17 @@ static int aic3x_init(struct snd_soc_codec *codec)
1218 aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL); 1257 aic3x_write(codec, LINE2L_2_MONOLOPM_VOL, DEFAULT_VOL);
1219 aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL); 1258 aic3x_write(codec, LINE2R_2_MONOLOPM_VOL, DEFAULT_VOL);
1220 1259
1260 if (aic3x->model == AIC3X_MODEL_3007) {
1261 /* Class-D speaker driver init; datasheet p. 46 */
1262 aic3x_write(codec, AIC3X_PAGE_SELECT, 0x0D);
1263 aic3x_write(codec, 0xD, 0x0D);
1264 aic3x_write(codec, 0x8, 0x5C);
1265 aic3x_write(codec, 0x8, 0x5D);
1266 aic3x_write(codec, 0x8, 0x5C);
1267 aic3x_write(codec, AIC3X_PAGE_SELECT, 0x00);
1268 aic3x_write(codec, CLASSD_CTRL, 0);
1269 }
1270
1221 /* off, with power on */ 1271 /* off, with power on */
1222 aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); 1272 aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1223 1273
@@ -1243,6 +1293,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
1243 1293
1244 snd_soc_add_controls(codec, aic3x_snd_controls, 1294 snd_soc_add_controls(codec, aic3x_snd_controls,
1245 ARRAY_SIZE(aic3x_snd_controls)); 1295 ARRAY_SIZE(aic3x_snd_controls));
1296 if (aic3x->model == AIC3X_MODEL_3007)
1297 snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
1246 1298
1247 aic3x_add_widgets(codec); 1299 aic3x_add_widgets(codec);
1248 1300
@@ -1274,6 +1326,14 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
1274 * 0x18, 0x19, 0x1A, 0x1B 1326 * 0x18, 0x19, 0x1A, 0x1B
1275 */ 1327 */
1276 1328
1329static const struct i2c_device_id aic3x_i2c_id[] = {
1330 [AIC3X_MODEL_3X] = { "tlv320aic3x", 0 },
1331 [AIC3X_MODEL_33] = { "tlv320aic33", 0 },
1332 [AIC3X_MODEL_3007] = { "tlv320aic3007", 0 },
1333 { }
1334};
1335MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
1336
1277/* 1337/*
1278 * If the i2c layer weren't so broken, we could pass this kind of data 1338 * If the i2c layer weren't so broken, we could pass this kind of data
1279 * around 1339 * around
@@ -1285,6 +1345,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1285 struct aic3x_setup_data *setup = pdata->setup; 1345 struct aic3x_setup_data *setup = pdata->setup;
1286 struct aic3x_priv *aic3x; 1346 struct aic3x_priv *aic3x;
1287 int ret, i; 1347 int ret, i;
1348 const struct i2c_device_id *tbl;
1288 1349
1289 aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); 1350 aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
1290 if (aic3x == NULL) { 1351 if (aic3x == NULL) {
@@ -1305,6 +1366,12 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
1305 gpio_direction_output(aic3x->gpio_reset, 0); 1366 gpio_direction_output(aic3x->gpio_reset, 0);
1306 } 1367 }
1307 1368
1369 for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) {
1370 if (!strcmp(tbl->name, id->name))
1371 break;
1372 }
1373 aic3x->model = tbl - aic3x_i2c_id;
1374
1308 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) 1375 for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
1309 aic3x->supplies[i].supply = aic3x_supply_names[i]; 1376 aic3x->supplies[i].supply = aic3x_supply_names[i];
1310 1377
@@ -1359,13 +1426,6 @@ static int aic3x_i2c_remove(struct i2c_client *client)
1359 return 0; 1426 return 0;
1360} 1427}
1361 1428
1362static const struct i2c_device_id aic3x_i2c_id[] = {
1363 { "tlv320aic3x", 0 },
1364 { "tlv320aic33", 0 },
1365 { }
1366};
1367MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
1368
1369/* machine i2c codec control layer */ 1429/* machine i2c codec control layer */
1370static struct i2c_driver aic3x_i2c_driver = { 1430static struct i2c_driver aic3x_i2c_driver = {
1371 .driver = { 1431 .driver = {
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index f6e3d9b42daf..98e44395b662 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -111,6 +111,8 @@
111#define DACL1_2_MONOLOPM_VOL 75 111#define DACL1_2_MONOLOPM_VOL 75
112#define DACR1_2_MONOLOPM_VOL 78 112#define DACR1_2_MONOLOPM_VOL 78
113#define MONOLOPM_CTRL 79 113#define MONOLOPM_CTRL 79
114/* Class-D speaker driver on tlv320aic3007 */
115#define CLASSD_CTRL 73
114/* Line Output Plus/Minus control registers */ 116/* Line Output Plus/Minus control registers */
115#define LINE2L_2_LLOPM_VOL 80 117#define LINE2L_2_LLOPM_VOL 80
116#define LINE2L_2_RLOPM_VOL 87 118#define LINE2L_2_RLOPM_VOL 87
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index 19844fc8cb1d..56f540838745 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -46,6 +46,7 @@ struct wm8731_priv {
46 struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES]; 46 struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
47 u16 reg_cache[WM8731_CACHEREGNUM]; 47 u16 reg_cache[WM8731_CACHEREGNUM];
48 unsigned int sysclk; 48 unsigned int sysclk;
49 int sysclk_type;
49}; 50};
50 51
51 52
@@ -110,6 +111,7 @@ static const struct snd_kcontrol_new wm8731_input_mux_controls =
110SOC_DAPM_ENUM("Input Select", wm8731_enum[0]); 111SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
111 112
112static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = { 113static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
114SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
113SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, 115SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1,
114 &wm8731_output_mixer_controls[0], 116 &wm8731_output_mixer_controls[0],
115 ARRAY_SIZE(wm8731_output_mixer_controls)), 117 ARRAY_SIZE(wm8731_output_mixer_controls)),
@@ -127,7 +129,18 @@ SND_SOC_DAPM_INPUT("RLINEIN"),
127SND_SOC_DAPM_INPUT("LLINEIN"), 129SND_SOC_DAPM_INPUT("LLINEIN"),
128}; 130};
129 131
132static int wm8731_check_osc(struct snd_soc_dapm_widget *source,
133 struct snd_soc_dapm_widget *sink)
134{
135 struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(source->codec);
136
137 return wm8731->sysclk_type == WM8731_SYSCLK_MCLK;
138}
139
130static const struct snd_soc_dapm_route intercon[] = { 140static const struct snd_soc_dapm_route intercon[] = {
141 {"DAC", NULL, "OSC", wm8731_check_osc},
142 {"ADC", NULL, "OSC", wm8731_check_osc},
143
131 /* output mixer */ 144 /* output mixer */
132 {"Output Mixer", "Line Bypass Switch", "Line Input"}, 145 {"Output Mixer", "Line Bypass Switch", "Line Input"},
133 {"Output Mixer", "HiFi Playback Switch", "DAC"}, 146 {"Output Mixer", "HiFi Playback Switch", "DAC"},
@@ -285,6 +298,15 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
285 struct snd_soc_codec *codec = codec_dai->codec; 298 struct snd_soc_codec *codec = codec_dai->codec;
286 struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); 299 struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
287 300
301 switch (clk_id) {
302 case WM8731_SYSCLK_XTAL:
303 case WM8731_SYSCLK_MCLK:
304 wm8731->sysclk_type = clk_id;
305 break;
306 default:
307 return -EINVAL;
308 }
309
288 switch (freq) { 310 switch (freq) {
289 case 11289600: 311 case 11289600:
290 case 12000000: 312 case 12000000:
@@ -292,9 +314,14 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
292 case 16934400: 314 case 16934400:
293 case 18432000: 315 case 18432000:
294 wm8731->sysclk = freq; 316 wm8731->sysclk = freq;
295 return 0; 317 break;
318 default:
319 return -EINVAL;
296 } 320 }
297 return -EINVAL; 321
322 snd_soc_dapm_sync(codec);
323
324 return 0;
298} 325}
299 326
300 327
diff --git a/sound/soc/codecs/wm8731.h b/sound/soc/codecs/wm8731.h
index 73a70e206ba9..e9c0c76ab73b 100644
--- a/sound/soc/codecs/wm8731.h
+++ b/sound/soc/codecs/wm8731.h
@@ -31,7 +31,9 @@
31 31
32#define WM8731_CACHEREGNUM 10 32#define WM8731_CACHEREGNUM 10
33 33
34#define WM8731_SYSCLK 0 34#define WM8731_SYSCLK_XTAL 1
35#define WM8731_SYSCLK_MCLK 2
36
35#define WM8731_DAI 0 37#define WM8731_DAI 0
36 38
37#endif 39#endif
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 981868700388..d754d34d68a6 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -1,24 +1,36 @@
1config SND_MPC52xx_DMA 1config SND_MPC52xx_DMA
2 tristate 2 tristate
3 3
4# ASoC platform support for the Freescale MPC8610 SOC. This compiles drivers 4# ASoC platform support for the Freescale PowerPC SOCs that have an SSI and
5# for the SSI and the Elo DMA controller. You will still need to select 5# an Elo DMA controller, such as the MPC8610 and P1022. You will still need to
6# a platform driver and a codec driver. 6# select a platform driver and a codec driver.
7config SND_SOC_MPC8610 7config SND_SOC_POWERPC_SSI
8 tristate 8 tristate
9 depends on MPC8610 9 depends on FSL_SOC
10 10
11config SND_SOC_MPC8610_HPCD 11config SND_SOC_MPC8610_HPCD
12 tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" 12 tristate "ALSA SoC support for the Freescale MPC8610 HPCD board"
13 # I2C is necessary for the CS4270 driver 13 # I2C is necessary for the CS4270 driver
14 depends on MPC8610_HPCD && I2C 14 depends on MPC8610_HPCD && I2C
15 select SND_SOC_MPC8610 15 select SND_SOC_POWERPC_SSI
16 select SND_SOC_CS4270 16 select SND_SOC_CS4270
17 select SND_SOC_CS4270_VD33_ERRATA 17 select SND_SOC_CS4270_VD33_ERRATA
18 default y if MPC8610_HPCD 18 default y if MPC8610_HPCD
19 help 19 help
20 Say Y if you want to enable audio on the Freescale MPC8610 HPCD. 20 Say Y if you want to enable audio on the Freescale MPC8610 HPCD.
21 21
22config SND_SOC_P1022_DS
23 tristate "ALSA SoC support for the Freescale P1022 DS board"
24 # I2C is necessary for the WM8776 driver
25 depends on P1022_DS && I2C
26 select SND_SOC_POWERPC_SSI
27 select SND_SOC_WM8776
28 default y if P1022_DS
29 help
30 Say Y if you want to enable audio on the Freescale P1022 DS board.
31 This will also include the Wolfson Microelectronics WM8776 codec
32 driver.
33
22config SND_SOC_MPC5200_I2S 34config SND_SOC_MPC5200_I2S
23 tristate "Freescale MPC5200 PSC in I2S mode driver" 35 tristate "Freescale MPC5200 PSC in I2S mode driver"
24 depends on PPC_MPC52xx && PPC_BESTCOMM 36 depends on PPC_MPC52xx && PPC_BESTCOMM
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 7e472a53fcd3..b4a38c0ac58c 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -2,10 +2,14 @@
2snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o 2snd-soc-mpc8610-hpcd-objs := mpc8610_hpcd.o
3obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o 3obj-$(CONFIG_SND_SOC_MPC8610_HPCD) += snd-soc-mpc8610-hpcd.o
4 4
5# MPC8610 Platform Support 5# P1022 DS Machine Support
6snd-soc-p1022-ds-objs := p1022_ds.o
7obj-$(CONFIG_SND_SOC_P1022_DS) += snd-soc-p1022-ds.o
8
9# Freescale PowerPC SSI/DMA Platform Support
6snd-soc-fsl-ssi-objs := fsl_ssi.o 10snd-soc-fsl-ssi-objs := fsl_ssi.o
7snd-soc-fsl-dma-objs := fsl_dma.o 11snd-soc-fsl-dma-objs := fsl_dma.o
8obj-$(CONFIG_SND_SOC_MPC8610) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o 12obj-$(CONFIG_SND_SOC_POWERPC_SSI) += snd-soc-fsl-ssi.o snd-soc-fsl-dma.o
9 13
10# MPC5200 Platform Support 14# MPC5200 Platform Support
11obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o 15obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index dfe1cb94a70f..4cf98c03af22 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -23,6 +23,7 @@
23#include <linux/gfp.h> 23#include <linux/gfp.h>
24#include <linux/of_platform.h> 24#include <linux/of_platform.h>
25#include <linux/list.h> 25#include <linux/list.h>
26#include <linux/slab.h>
26 27
27#include <sound/core.h> 28#include <sound/core.h>
28#include <sound/pcm.h> 29#include <sound/pcm.h>
@@ -305,21 +306,29 @@ static int fsl_dma_new(struct snd_card *card, struct snd_soc_dai *dai,
305 if (!card->dev->coherent_dma_mask) 306 if (!card->dev->coherent_dma_mask)
306 card->dev->coherent_dma_mask = fsl_dma_dmamask; 307 card->dev->coherent_dma_mask = fsl_dma_dmamask;
307 308
308 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, 309 /* Some codecs have separate DAIs for playback and capture, so we
309 fsl_dma_hardware.buffer_bytes_max, 310 * should allocate a DMA buffer only for the streams that are valid.
310 &pcm->streams[0].substream->dma_buffer); 311 */
311 if (ret) { 312
312 dev_err(card->dev, "can't allocate playback dma buffer\n"); 313 if (dai->driver->playback.channels_min) {
313 return ret; 314 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
315 fsl_dma_hardware.buffer_bytes_max,
316 &pcm->streams[0].substream->dma_buffer);
317 if (ret) {
318 dev_err(card->dev, "can't alloc playback dma buffer\n");
319 return ret;
320 }
314 } 321 }
315 322
316 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev, 323 if (dai->driver->capture.channels_min) {
317 fsl_dma_hardware.buffer_bytes_max, 324 ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, card->dev,
318 &pcm->streams[1].substream->dma_buffer); 325 fsl_dma_hardware.buffer_bytes_max,
319 if (ret) { 326 &pcm->streams[1].substream->dma_buffer);
320 snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer); 327 if (ret) {
321 dev_err(card->dev, "can't allocate capture dma buffer\n"); 328 snd_dma_free_pages(&pcm->streams[0].substream->dma_buffer);
322 return ret; 329 dev_err(card->dev, "can't alloc capture dma buffer\n");
330 return ret;
331 }
323 } 332 }
324 333
325 return 0; 334 return 0;
@@ -887,11 +896,11 @@ static struct snd_pcm_ops fsl_dma_ops = {
887 .pointer = fsl_dma_pointer, 896 .pointer = fsl_dma_pointer,
888}; 897};
889 898
890static int __devinit fsl_soc_dma_probe(struct of_device *of_dev, 899static int __devinit fsl_soc_dma_probe(struct platform_device *pdev,
891 const struct of_device_id *match) 900 const struct of_device_id *match)
892 { 901 {
893 struct dma_object *dma; 902 struct dma_object *dma;
894 struct device_node *np = of_dev->dev.of_node; 903 struct device_node *np = pdev->dev.of_node;
895 struct device_node *ssi_np; 904 struct device_node *ssi_np;
896 struct resource res; 905 struct resource res;
897 const uint32_t *iprop; 906 const uint32_t *iprop;
@@ -900,13 +909,13 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
900 /* Find the SSI node that points to us. */ 909 /* Find the SSI node that points to us. */
901 ssi_np = find_ssi_node(np); 910 ssi_np = find_ssi_node(np);
902 if (!ssi_np) { 911 if (!ssi_np) {
903 dev_err(&of_dev->dev, "cannot find parent SSI node\n"); 912 dev_err(&pdev->dev, "cannot find parent SSI node\n");
904 return -ENODEV; 913 return -ENODEV;
905 } 914 }
906 915
907 ret = of_address_to_resource(ssi_np, 0, &res); 916 ret = of_address_to_resource(ssi_np, 0, &res);
908 if (ret) { 917 if (ret) {
909 dev_err(&of_dev->dev, "could not determine resources for %s\n", 918 dev_err(&pdev->dev, "could not determine resources for %s\n",
910 ssi_np->full_name); 919 ssi_np->full_name);
911 of_node_put(ssi_np); 920 of_node_put(ssi_np);
912 return ret; 921 return ret;
@@ -914,7 +923,7 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
914 923
915 dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL); 924 dma = kzalloc(sizeof(*dma) + strlen(np->full_name), GFP_KERNEL);
916 if (!dma) { 925 if (!dma) {
917 dev_err(&of_dev->dev, "could not allocate dma object\n"); 926 dev_err(&pdev->dev, "could not allocate dma object\n");
918 of_node_put(ssi_np); 927 of_node_put(ssi_np);
919 return -ENOMEM; 928 return -ENOMEM;
920 } 929 }
@@ -937,9 +946,9 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
937 946
938 of_node_put(ssi_np); 947 of_node_put(ssi_np);
939 948
940 ret = snd_soc_register_platform(&of_dev->dev, &dma->dai); 949 ret = snd_soc_register_platform(&pdev->dev, &dma->dai);
941 if (ret) { 950 if (ret) {
942 dev_err(&of_dev->dev, "could not register platform\n"); 951 dev_err(&pdev->dev, "could not register platform\n");
943 kfree(dma); 952 kfree(dma);
944 return ret; 953 return ret;
945 } 954 }
@@ -947,16 +956,16 @@ static int __devinit fsl_soc_dma_probe(struct of_device *of_dev,
947 dma->channel = of_iomap(np, 0); 956 dma->channel = of_iomap(np, 0);
948 dma->irq = irq_of_parse_and_map(np, 0); 957 dma->irq = irq_of_parse_and_map(np, 0);
949 958
950 dev_set_drvdata(&of_dev->dev, dma); 959 dev_set_drvdata(&pdev->dev, dma);
951 960
952 return 0; 961 return 0;
953} 962}
954 963
955static int __devexit fsl_soc_dma_remove(struct of_device *of_dev) 964static int __devexit fsl_soc_dma_remove(struct platform_device *pdev)
956{ 965{
957 struct dma_object *dma = dev_get_drvdata(&of_dev->dev); 966 struct dma_object *dma = dev_get_drvdata(&pdev->dev);
958 967
959 snd_soc_unregister_platform(&of_dev->dev); 968 snd_soc_unregister_platform(&pdev->dev);
960 iounmap(dma->channel); 969 iounmap(dma->channel);
961 irq_dispose_mapping(dma->irq); 970 irq_dispose_mapping(dma->irq);
962 kfree(dma); 971 kfree(dma);
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index d1c855ade8fb..4cc167a7aeb8 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -624,13 +624,13 @@ static void make_lowercase(char *s)
624 } 624 }
625} 625}
626 626
627static int __devinit fsl_ssi_probe(struct of_device *of_dev, 627static int __devinit fsl_ssi_probe(struct platform_device *pdev,
628 const struct of_device_id *match) 628 const struct of_device_id *match)
629{ 629{
630 struct fsl_ssi_private *ssi_private; 630 struct fsl_ssi_private *ssi_private;
631 int ret = 0; 631 int ret = 0;
632 struct device_attribute *dev_attr = NULL; 632 struct device_attribute *dev_attr = NULL;
633 struct device_node *np = of_dev->dev.of_node; 633 struct device_node *np = pdev->dev.of_node;
634 const char *p, *sprop; 634 const char *p, *sprop;
635 const uint32_t *iprop; 635 const uint32_t *iprop;
636 struct resource res; 636 struct resource res;
@@ -645,14 +645,14 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
645 645
646 /* Check for a codec-handle property. */ 646 /* Check for a codec-handle property. */
647 if (!of_get_property(np, "codec-handle", NULL)) { 647 if (!of_get_property(np, "codec-handle", NULL)) {
648 dev_err(&of_dev->dev, "missing codec-handle property\n"); 648 dev_err(&pdev->dev, "missing codec-handle property\n");
649 return -ENODEV; 649 return -ENODEV;
650 } 650 }
651 651
652 /* We only support the SSI in "I2S Slave" mode */ 652 /* We only support the SSI in "I2S Slave" mode */
653 sprop = of_get_property(np, "fsl,mode", NULL); 653 sprop = of_get_property(np, "fsl,mode", NULL);
654 if (!sprop || strcmp(sprop, "i2s-slave")) { 654 if (!sprop || strcmp(sprop, "i2s-slave")) {
655 dev_notice(&of_dev->dev, "mode %s is unsupported\n", sprop); 655 dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
656 return -ENODEV; 656 return -ENODEV;
657 } 657 }
658 658
@@ -661,7 +661,7 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
661 ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p), 661 ssi_private = kzalloc(sizeof(struct fsl_ssi_private) + strlen(p),
662 GFP_KERNEL); 662 GFP_KERNEL);
663 if (!ssi_private) { 663 if (!ssi_private) {
664 dev_err(&of_dev->dev, "could not allocate DAI object\n"); 664 dev_err(&pdev->dev, "could not allocate DAI object\n");
665 return -ENOMEM; 665 return -ENOMEM;
666 } 666 }
667 667
@@ -675,7 +675,7 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
675 /* Get the addresses and IRQ */ 675 /* Get the addresses and IRQ */
676 ret = of_address_to_resource(np, 0, &res); 676 ret = of_address_to_resource(np, 0, &res);
677 if (ret) { 677 if (ret) {
678 dev_err(&of_dev->dev, "could not determine device resources\n"); 678 dev_err(&pdev->dev, "could not determine device resources\n");
679 kfree(ssi_private); 679 kfree(ssi_private);
680 return ret; 680 return ret;
681 } 681 }
@@ -703,19 +703,19 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
703 dev_attr->attr.mode = S_IRUGO; 703 dev_attr->attr.mode = S_IRUGO;
704 dev_attr->show = fsl_sysfs_ssi_show; 704 dev_attr->show = fsl_sysfs_ssi_show;
705 705
706 ret = device_create_file(&of_dev->dev, dev_attr); 706 ret = device_create_file(&pdev->dev, dev_attr);
707 if (ret) { 707 if (ret) {
708 dev_err(&of_dev->dev, "could not create sysfs %s file\n", 708 dev_err(&pdev->dev, "could not create sysfs %s file\n",
709 ssi_private->dev_attr.attr.name); 709 ssi_private->dev_attr.attr.name);
710 goto error; 710 goto error;
711 } 711 }
712 712
713 /* Register with ASoC */ 713 /* Register with ASoC */
714 dev_set_drvdata(&of_dev->dev, ssi_private); 714 dev_set_drvdata(&pdev->dev, ssi_private);
715 715
716 ret = snd_soc_register_dai(&of_dev->dev, &ssi_private->cpu_dai_drv); 716 ret = snd_soc_register_dai(&pdev->dev, &ssi_private->cpu_dai_drv);
717 if (ret) { 717 if (ret) {
718 dev_err(&of_dev->dev, "failed to register DAI: %d\n", ret); 718 dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
719 goto error; 719 goto error;
720 } 720 }
721 721
@@ -733,20 +733,20 @@ static int __devinit fsl_ssi_probe(struct of_device *of_dev,
733 make_lowercase(name); 733 make_lowercase(name);
734 734
735 ssi_private->pdev = 735 ssi_private->pdev =
736 platform_device_register_data(&of_dev->dev, name, 0, NULL, 0); 736 platform_device_register_data(&pdev->dev, name, 0, NULL, 0);
737 if (IS_ERR(ssi_private->pdev)) { 737 if (IS_ERR(ssi_private->pdev)) {
738 ret = PTR_ERR(ssi_private->pdev); 738 ret = PTR_ERR(ssi_private->pdev);
739 dev_err(&of_dev->dev, "failed to register platform: %d\n", ret); 739 dev_err(&pdev->dev, "failed to register platform: %d\n", ret);
740 goto error; 740 goto error;
741 } 741 }
742 742
743 return 0; 743 return 0;
744 744
745error: 745error:
746 snd_soc_unregister_dai(&of_dev->dev); 746 snd_soc_unregister_dai(&pdev->dev);
747 dev_set_drvdata(&of_dev->dev, NULL); 747 dev_set_drvdata(&pdev->dev, NULL);
748 if (dev_attr) 748 if (dev_attr)
749 device_remove_file(&of_dev->dev, dev_attr); 749 device_remove_file(&pdev->dev, dev_attr);
750 irq_dispose_mapping(ssi_private->irq); 750 irq_dispose_mapping(ssi_private->irq);
751 iounmap(ssi_private->ssi); 751 iounmap(ssi_private->ssi);
752 kfree(ssi_private); 752 kfree(ssi_private);
@@ -754,16 +754,16 @@ error:
754 return ret; 754 return ret;
755} 755}
756 756
757static int fsl_ssi_remove(struct of_device *of_dev) 757static int fsl_ssi_remove(struct platform_device *pdev)
758{ 758{
759 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&of_dev->dev); 759 struct fsl_ssi_private *ssi_private = dev_get_drvdata(&pdev->dev);
760 760
761 platform_device_unregister(ssi_private->pdev); 761 platform_device_unregister(ssi_private->pdev);
762 snd_soc_unregister_dai(&of_dev->dev); 762 snd_soc_unregister_dai(&pdev->dev);
763 device_remove_file(&of_dev->dev, &ssi_private->dev_attr); 763 device_remove_file(&pdev->dev, &ssi_private->dev_attr);
764 764
765 kfree(ssi_private); 765 kfree(ssi_private);
766 dev_set_drvdata(&of_dev->dev, NULL); 766 dev_set_drvdata(&pdev->dev, NULL);
767 767
768 return 0; 768 return 0;
769} 769}
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index 38339c158ed9..0d7dcf1e4863 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -13,6 +13,7 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/interrupt.h> 14#include <linux/interrupt.h>
15#include <linux/of_device.h> 15#include <linux/of_device.h>
16#include <linux/slab.h>
16#include <sound/soc.h> 17#include <sound/soc.h>
17#include <asm/fsl_guts.h> 18#include <asm/fsl_guts.h>
18 19
@@ -323,9 +324,10 @@ static int get_dma_channel(struct device_node *ssi_np,
323static int mpc8610_hpcd_probe(struct platform_device *pdev) 324static int mpc8610_hpcd_probe(struct platform_device *pdev)
324{ 325{
325 struct device *dev = pdev->dev.parent; 326 struct device *dev = pdev->dev.parent;
326 /* of_dev is the OF device for the SSI node that probed us */ 327 /* ssi_pdev is the platform device for the SSI node that probed us */
327 struct of_device *of_dev = container_of(dev, struct of_device, dev); 328 struct platform_device *ssi_pdev =
328 struct device_node *np = of_dev->dev.of_node; 329 container_of(dev, struct platform_device, dev);
330 struct device_node *np = ssi_pdev->dev.of_node;
329 struct device_node *codec_np = NULL; 331 struct device_node *codec_np = NULL;
330 struct platform_device *sound_device = NULL; 332 struct platform_device *sound_device = NULL;
331 struct mpc8610_hpcd_data *machine_data; 333 struct mpc8610_hpcd_data *machine_data;
@@ -348,7 +350,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev)
348 if (!machine_data) 350 if (!machine_data)
349 return -ENOMEM; 351 return -ENOMEM;
350 352
351 machine_data->dai[0].cpu_dai_name = dev_name(&of_dev->dev); 353 machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
352 machine_data->dai[0].ops = &mpc8610_hpcd_ops; 354 machine_data->dai[0].ops = &mpc8610_hpcd_ops;
353 355
354 /* Determine the codec name, it will be used as the codec DAI name */ 356 /* Determine the codec name, it will be used as the codec DAI name */
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
new file mode 100644
index 000000000000..f8176e8e1adf
--- /dev/null
+++ b/sound/soc/fsl/p1022_ds.c
@@ -0,0 +1,590 @@
1/**
2 * Freescale P1022DS ALSA SoC Machine driver
3 *
4 * Author: Timur Tabi <timur@freescale.com>
5 *
6 * Copyright 2010 Freescale Semiconductor, Inc.
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/of_device.h>
16#include <linux/slab.h>
17#include <sound/soc.h>
18#include <asm/fsl_guts.h>
19
20#include "fsl_dma.h"
21#include "fsl_ssi.h"
22
23/* P1022-specific PMUXCR and DMUXCR bit definitions */
24
25#define CCSR_GUTS_PMUXCR_UART0_I2C1_MASK 0x0001c000
26#define CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI 0x00010000
27#define CCSR_GUTS_PMUXCR_UART0_I2C1_SSI 0x00018000
28
29#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK 0x00000c00
30#define CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI 0x00000000
31
32#define CCSR_GUTS_DMUXCR_PAD 1 /* DMA controller/channel set to pad */
33#define CCSR_GUTS_DMUXCR_SSI 2 /* DMA controller/channel set to SSI */
34
35/*
36 * Set the DMACR register in the GUTS
37 *
38 * The DMACR register determines the source of initiated transfers for each
39 * channel on each DMA controller. Rather than have a bunch of repetitive
40 * macros for the bit patterns, we just have a function that calculates
41 * them.
42 *
43 * guts: Pointer to GUTS structure
44 * co: The DMA controller (0 or 1)
45 * ch: The channel on the DMA controller (0, 1, 2, or 3)
46 * device: The device to set as the target (CCSR_GUTS_DMUXCR_xxx)
47 */
48static inline void guts_set_dmuxcr(struct ccsr_guts_85xx __iomem *guts,
49 unsigned int co, unsigned int ch, unsigned int device)
50{
51 unsigned int shift = 16 + (8 * (1 - co) + 2 * (3 - ch));
52
53 clrsetbits_be32(&guts->dmuxcr, 3 << shift, device << shift);
54}
55
56/* There's only one global utilities register */
57static phys_addr_t guts_phys;
58
59#define DAI_NAME_SIZE 32
60
61/**
62 * machine_data: machine-specific ASoC device data
63 *
64 * This structure contains data for a single sound platform device on an
65 * P1022 DS. Some of the data is taken from the device tree.
66 */
67struct machine_data {
68 struct snd_soc_dai_link dai[2];
69 struct snd_soc_card card;
70 unsigned int dai_format;
71 unsigned int codec_clk_direction;
72 unsigned int cpu_clk_direction;
73 unsigned int clk_frequency;
74 unsigned int ssi_id; /* 0 = SSI1, 1 = SSI2, etc */
75 unsigned int dma_id[2]; /* 0 = DMA1, 1 = DMA2, etc */
76 unsigned int dma_channel_id[2]; /* 0 = ch 0, 1 = ch 1, etc*/
77 char codec_name[DAI_NAME_SIZE];
78 char platform_name[2][DAI_NAME_SIZE]; /* One for each DMA channel */
79};
80
81/**
82 * p1022_ds_machine_probe: initialize the board
83 *
84 * This function is used to initialize the board-specific hardware.
85 *
86 * Here we program the DMACR and PMUXCR registers.
87 */
88static int p1022_ds_machine_probe(struct platform_device *sound_device)
89{
90 struct snd_soc_card *card = platform_get_drvdata(sound_device);
91 struct machine_data *mdata =
92 container_of(card, struct machine_data, card);
93 struct ccsr_guts_85xx __iomem *guts;
94
95 guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
96 if (!guts) {
97 dev_err(card->dev, "could not map global utilities\n");
98 return -ENOMEM;
99 }
100
101 /* Enable SSI Tx signal */
102 clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK,
103 CCSR_GUTS_PMUXCR_UART0_I2C1_UART0_SSI);
104
105 /* Enable SSI Rx signal */
106 clrsetbits_be32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK,
107 CCSR_GUTS_PMUXCR_SSI_DMA_TDM_SSI);
108
109 /* Enable DMA Channel for SSI */
110 guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0],
111 CCSR_GUTS_DMUXCR_SSI);
112
113 guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1],
114 CCSR_GUTS_DMUXCR_SSI);
115
116 iounmap(guts);
117
118 return 0;
119}
120
121/**
122 * p1022_ds_startup: program the board with various hardware parameters
123 *
124 * This function takes board-specific information, like clock frequencies
125 * and serial data formats, and passes that information to the codec and
126 * transport drivers.
127 */
128static int p1022_ds_startup(struct snd_pcm_substream *substream)
129{
130 struct snd_soc_pcm_runtime *rtd = substream->private_data;
131 struct machine_data *mdata =
132 container_of(rtd->card, struct machine_data, card);
133 struct device *dev = rtd->card->dev;
134 int ret = 0;
135
136 /* Tell the codec driver what the serial protocol is. */
137 ret = snd_soc_dai_set_fmt(rtd->codec_dai, mdata->dai_format);
138 if (ret < 0) {
139 dev_err(dev, "could not set codec driver audio format\n");
140 return ret;
141 }
142
143 /*
144 * Tell the codec driver what the MCLK frequency is, and whether it's
145 * a slave or master.
146 */
147 ret = snd_soc_dai_set_sysclk(rtd->codec_dai, 0, mdata->clk_frequency,
148 mdata->codec_clk_direction);
149 if (ret < 0) {
150 dev_err(dev, "could not set codec driver clock params\n");
151 return ret;
152 }
153
154 return 0;
155}
156
157/**
158 * p1022_ds_machine_remove: Remove the sound device
159 *
160 * This function is called to remove the sound device for one SSI. We
161 * de-program the DMACR and PMUXCR register.
162 */
163static int p1022_ds_machine_remove(struct platform_device *sound_device)
164{
165 struct snd_soc_card *card = platform_get_drvdata(sound_device);
166 struct machine_data *mdata =
167 container_of(card, struct machine_data, card);
168 struct ccsr_guts_85xx __iomem *guts;
169
170 guts = ioremap(guts_phys, sizeof(struct ccsr_guts_85xx));
171 if (!guts) {
172 dev_err(card->dev, "could not map global utilities\n");
173 return -ENOMEM;
174 }
175
176 /* Restore the signal routing */
177 clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_UART0_I2C1_MASK);
178 clrbits32(&guts->pmuxcr, CCSR_GUTS_PMUXCR_SSI_DMA_TDM_MASK);
179 guts_set_dmuxcr(guts, mdata->dma_id[0], mdata->dma_channel_id[0], 0);
180 guts_set_dmuxcr(guts, mdata->dma_id[1], mdata->dma_channel_id[1], 0);
181
182 iounmap(guts);
183
184 return 0;
185}
186
187/**
188 * p1022_ds_ops: ASoC machine driver operations
189 */
190static struct snd_soc_ops p1022_ds_ops = {
191 .startup = p1022_ds_startup,
192};
193
194/**
195 * get_node_by_phandle_name - get a node by its phandle name
196 *
197 * This function takes a node, the name of a property in that node, and a
198 * compatible string. Assuming the property is a phandle to another node,
199 * it returns that node, (optionally) if that node is compatible.
200 *
201 * If the property is not a phandle, or the node it points to is not compatible
202 * with the specific string, then NULL is returned.
203 */
204static struct device_node *get_node_by_phandle_name(struct device_node *np,
205 const char *name, const char *compatible)
206{
207 np = of_parse_phandle(np, name, 0);
208 if (!np)
209 return NULL;
210
211 if (!of_device_is_compatible(np, compatible)) {
212 of_node_put(np);
213 return NULL;
214 }
215
216 return np;
217}
218
219/**
220 * get_parent_cell_index -- return the cell-index of the parent of a node
221 *
222 * Return the value of the cell-index property of the parent of the given
223 * node. This is used for DMA channel nodes that need to know the DMA ID
224 * of the controller they are on.
225 */
226static int get_parent_cell_index(struct device_node *np)
227{
228 struct device_node *parent = of_get_parent(np);
229 const u32 *iprop;
230 int ret = -1;
231
232 if (!parent)
233 return -1;
234
235 iprop = of_get_property(parent, "cell-index", NULL);
236 if (iprop)
237 ret = *iprop;
238
239 of_node_put(parent);
240
241 return ret;
242}
243
244/**
245 * codec_node_dev_name - determine the dev_name for a codec node
246 *
247 * This function determines the dev_name for an I2C node. This is the name
248 * that would be returned by dev_name() if this device_node were part of a
249 * 'struct device' It's ugly and hackish, but it works.
250 *
251 * The dev_name for such devices include the bus number and I2C address. For
252 * example, "cs4270-codec.0-004f".
253 */
254static int codec_node_dev_name(struct device_node *np, char *buf, size_t len)
255{
256 const u32 *iprop;
257 int bus, addr;
258 char temp[DAI_NAME_SIZE];
259
260 of_modalias_node(np, temp, DAI_NAME_SIZE);
261
262 iprop = of_get_property(np, "reg", NULL);
263 if (!iprop)
264 return -EINVAL;
265
266 addr = *iprop;
267
268 bus = get_parent_cell_index(np);
269 if (bus < 0)
270 return bus;
271
272 snprintf(buf, len, "%s-codec.%u-%04x", temp, bus, addr);
273
274 return 0;
275}
276
277static int get_dma_channel(struct device_node *ssi_np,
278 const char *compatible,
279 struct snd_soc_dai_link *dai,
280 unsigned int *dma_channel_id,
281 unsigned int *dma_id)
282{
283 struct resource res;
284 struct device_node *dma_channel_np;
285 const u32 *iprop;
286 int ret;
287
288 dma_channel_np = get_node_by_phandle_name(ssi_np, compatible,
289 "fsl,ssi-dma-channel");
290 if (!dma_channel_np)
291 return -EINVAL;
292
293 /* Determine the dev_name for the device_node. This code mimics the
294 * behavior of of_device_make_bus_id(). We need this because ASoC uses
295 * the dev_name() of the device to match the platform (DMA) device with
296 * the CPU (SSI) device. It's all ugly and hackish, but it works (for
297 * now).
298 *
299 * dai->platform name should already point to an allocated buffer.
300 */
301 ret = of_address_to_resource(dma_channel_np, 0, &res);
302 if (ret)
303 return ret;
304 snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
305 (unsigned long long) res.start, dma_channel_np->name);
306
307 iprop = of_get_property(dma_channel_np, "cell-index", NULL);
308 if (!iprop) {
309 of_node_put(dma_channel_np);
310 return -EINVAL;
311 }
312
313 *dma_channel_id = *iprop;
314 *dma_id = get_parent_cell_index(dma_channel_np);
315 of_node_put(dma_channel_np);
316
317 return 0;
318}
319
320/**
321 * p1022_ds_probe: platform probe function for the machine driver
322 *
323 * Although this is a machine driver, the SSI node is the "master" node with
324 * respect to audio hardware connections. Therefore, we create a new ASoC
325 * device for each new SSI node that has a codec attached.
326 */
327static int p1022_ds_probe(struct platform_device *pdev)
328{
329 struct device *dev = pdev->dev.parent;
330 /* ssi_pdev is the platform device for the SSI node that probed us */
331 struct platform_device *ssi_pdev =
332 container_of(dev, struct platform_device, dev);
333 struct device_node *np = ssi_pdev->dev.of_node;
334 struct device_node *codec_np = NULL;
335 struct platform_device *sound_device = NULL;
336 struct machine_data *mdata;
337 int ret = -ENODEV;
338 const char *sprop;
339 const u32 *iprop;
340
341 /* Find the codec node for this SSI. */
342 codec_np = of_parse_phandle(np, "codec-handle", 0);
343 if (!codec_np) {
344 dev_err(dev, "could not find codec node\n");
345 return -EINVAL;
346 }
347
348 mdata = kzalloc(sizeof(struct machine_data), GFP_KERNEL);
349 if (!mdata)
350 return -ENOMEM;
351
352 mdata->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
353 mdata->dai[0].ops = &p1022_ds_ops;
354
355 /* Determine the codec name, it will be used as the codec DAI name */
356 ret = codec_node_dev_name(codec_np, mdata->codec_name, DAI_NAME_SIZE);
357 if (ret) {
358 dev_err(&pdev->dev, "invalid codec node %s\n",
359 codec_np->full_name);
360 ret = -EINVAL;
361 goto error;
362 }
363 mdata->dai[0].codec_name = mdata->codec_name;
364
365 /* We register two DAIs per SSI, one for playback and the other for
366 * capture. We support codecs that have separate DAIs for both playback
367 * and capture.
368 */
369 memcpy(&mdata->dai[1], &mdata->dai[0], sizeof(struct snd_soc_dai_link));
370
371 /* The DAI names from the codec (snd_soc_dai_driver.name) */
372 mdata->dai[0].codec_dai_name = "wm8776-hifi-playback";
373 mdata->dai[1].codec_dai_name = "wm8776-hifi-capture";
374
375 /* Get the device ID */
376 iprop = of_get_property(np, "cell-index", NULL);
377 if (!iprop) {
378 dev_err(&pdev->dev, "cell-index property not found\n");
379 ret = -EINVAL;
380 goto error;
381 }
382 mdata->ssi_id = *iprop;
383
384 /* Get the serial format and clock direction. */
385 sprop = of_get_property(np, "fsl,mode", NULL);
386 if (!sprop) {
387 dev_err(&pdev->dev, "fsl,mode property not found\n");
388 ret = -EINVAL;
389 goto error;
390 }
391
392 if (strcasecmp(sprop, "i2s-slave") == 0) {
393 mdata->dai_format = SND_SOC_DAIFMT_I2S;
394 mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
395 mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
396
397 /* In i2s-slave mode, the codec has its own clock source, so we
398 * need to get the frequency from the device tree and pass it to
399 * the codec driver.
400 */
401 iprop = of_get_property(codec_np, "clock-frequency", NULL);
402 if (!iprop || !*iprop) {
403 dev_err(&pdev->dev, "codec bus-frequency "
404 "property is missing or invalid\n");
405 ret = -EINVAL;
406 goto error;
407 }
408 mdata->clk_frequency = *iprop;
409 } else if (strcasecmp(sprop, "i2s-master") == 0) {
410 mdata->dai_format = SND_SOC_DAIFMT_I2S;
411 mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
412 mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
413 } else if (strcasecmp(sprop, "lj-slave") == 0) {
414 mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
415 mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
416 mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
417 } else if (strcasecmp(sprop, "lj-master") == 0) {
418 mdata->dai_format = SND_SOC_DAIFMT_LEFT_J;
419 mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
420 mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
421 } else if (strcasecmp(sprop, "rj-slave") == 0) {
422 mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
423 mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
424 mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
425 } else if (strcasecmp(sprop, "rj-master") == 0) {
426 mdata->dai_format = SND_SOC_DAIFMT_RIGHT_J;
427 mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
428 mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
429 } else if (strcasecmp(sprop, "ac97-slave") == 0) {
430 mdata->dai_format = SND_SOC_DAIFMT_AC97;
431 mdata->codec_clk_direction = SND_SOC_CLOCK_OUT;
432 mdata->cpu_clk_direction = SND_SOC_CLOCK_IN;
433 } else if (strcasecmp(sprop, "ac97-master") == 0) {
434 mdata->dai_format = SND_SOC_DAIFMT_AC97;
435 mdata->codec_clk_direction = SND_SOC_CLOCK_IN;
436 mdata->cpu_clk_direction = SND_SOC_CLOCK_OUT;
437 } else {
438 dev_err(&pdev->dev,
439 "unrecognized fsl,mode property '%s'\n", sprop);
440 ret = -EINVAL;
441 goto error;
442 }
443
444 if (!mdata->clk_frequency) {
445 dev_err(&pdev->dev, "unknown clock frequency\n");
446 ret = -EINVAL;
447 goto error;
448 }
449
450 /* Find the playback DMA channel to use. */
451 mdata->dai[0].platform_name = mdata->platform_name[0];
452 ret = get_dma_channel(np, "fsl,playback-dma", &mdata->dai[0],
453 &mdata->dma_channel_id[0],
454 &mdata->dma_id[0]);
455 if (ret) {
456 dev_err(&pdev->dev, "missing/invalid playback DMA phandle\n");
457 goto error;
458 }
459
460 /* Find the capture DMA channel to use. */
461 mdata->dai[1].platform_name = mdata->platform_name[1];
462 ret = get_dma_channel(np, "fsl,capture-dma", &mdata->dai[1],
463 &mdata->dma_channel_id[1],
464 &mdata->dma_id[1]);
465 if (ret) {
466 dev_err(&pdev->dev, "missing/invalid capture DMA phandle\n");
467 goto error;
468 }
469
470 /* Initialize our DAI data structure. */
471 mdata->dai[0].stream_name = "playback";
472 mdata->dai[1].stream_name = "capture";
473 mdata->dai[0].name = mdata->dai[0].stream_name;
474 mdata->dai[1].name = mdata->dai[1].stream_name;
475
476 mdata->card.probe = p1022_ds_machine_probe;
477 mdata->card.remove = p1022_ds_machine_remove;
478 mdata->card.name = pdev->name; /* The platform driver name */
479 mdata->card.num_links = 2;
480 mdata->card.dai_link = mdata->dai;
481
482 /* Allocate a new audio platform device structure */
483 sound_device = platform_device_alloc("soc-audio", -1);
484 if (!sound_device) {
485 dev_err(&pdev->dev, "platform device alloc failed\n");
486 ret = -ENOMEM;
487 goto error;
488 }
489
490 /* Associate the card data with the sound device */
491 platform_set_drvdata(sound_device, &mdata->card);
492
493 /* Register with ASoC */
494 ret = platform_device_add(sound_device);
495 if (ret) {
496 dev_err(&pdev->dev, "platform device add failed\n");
497 goto error;
498 }
499
500 of_node_put(codec_np);
501
502 return 0;
503
504error:
505 of_node_put(codec_np);
506
507 if (sound_device)
508 platform_device_unregister(sound_device);
509
510 kfree(mdata);
511
512 return ret;
513}
514
515/**
516 * p1022_ds_remove: remove the platform device
517 *
518 * This function is called when the platform device is removed.
519 */
520static int __devexit p1022_ds_remove(struct platform_device *pdev)
521{
522 struct platform_device *sound_device = dev_get_drvdata(&pdev->dev);
523 struct snd_soc_card *card = platform_get_drvdata(sound_device);
524 struct machine_data *mdata =
525 container_of(card, struct machine_data, card);
526
527 platform_device_unregister(sound_device);
528
529 kfree(mdata);
530 sound_device->dev.platform_data = NULL;
531
532 dev_set_drvdata(&pdev->dev, NULL);
533
534 return 0;
535}
536
537static struct platform_driver p1022_ds_driver = {
538 .probe = p1022_ds_probe,
539 .remove = __devexit_p(p1022_ds_remove),
540 .driver = {
541 /* The name must match the 'model' property in the device tree,
542 * in lowercase letters, but only the part after that last
543 * comma. This is because some model properties have a "fsl,"
544 * prefix.
545 */
546 .name = "snd-soc-p1022",
547 .owner = THIS_MODULE,
548 },
549};
550
551/**
552 * p1022_ds_init: machine driver initialization.
553 *
554 * This function is called when this module is loaded.
555 */
556static int __init p1022_ds_init(void)
557{
558 struct device_node *guts_np;
559 struct resource res;
560
561 pr_info("Freescale P1022 DS ALSA SoC machine driver\n");
562
563 /* Get the physical address of the global utilities registers */
564 guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
565 if (of_address_to_resource(guts_np, 0, &res)) {
566 pr_err("p1022-ds: missing/invalid global utilities node\n");
567 return -EINVAL;
568 }
569 guts_phys = res.start;
570 of_node_put(guts_np);
571
572 return platform_driver_register(&p1022_ds_driver);
573}
574
575/**
576 * p1022_ds_exit: machine driver exit
577 *
578 * This function is called when this driver is unloaded.
579 */
580static void __exit p1022_ds_exit(void)
581{
582 platform_driver_unregister(&p1022_ds_driver);
583}
584
585module_init(p1022_ds_init);
586module_exit(p1022_ds_exit);
587
588MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
589MODULE_DESCRIPTION("Freescale P1022 DS ALSA SoC machine driver");
590MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 9d88efa06e3c..438146addbb8 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -584,7 +584,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = {
584 .name = "CX20442", 584 .name = "CX20442",
585 .stream_name = "CX20442", 585 .stream_name = "CX20442",
586 .cpu_dai_name ="omap-mcbsp-dai.0", 586 .cpu_dai_name ="omap-mcbsp-dai.0",
587 .codec_dai_name = "cx20442-hifi", 587 .codec_dai_name = "cx20442-voice",
588 .init = ams_delta_cx20442_init, 588 .init = ams_delta_cx20442_init,
589 .platform_name = "omap-pcm-audio", 589 .platform_name = "omap-pcm-audio",
590 .codec_name = "cx20442-codec", 590 .codec_name = "cx20442-codec",
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index e30c8325f35e..37f191bbfdd9 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -117,6 +117,24 @@ config SND_PXA2XX_SOC_PALM27X
117 Say Y if you want to add support for SoC audio on 117 Say Y if you want to add support for SoC audio on
118 Palm T|X, T5, E2 or LifeDrive handheld computer. 118 Palm T|X, T5, E2 or LifeDrive handheld computer.
119 119
120config SND_SOC_SAARB
121 tristate "SoC Audio support for Marvell Saarb"
122 depends on SND_PXA2XX_SOC && MACH_SAARB
123 select SND_PXA_SOC_SSP
124 select SND_SOC_88PM860X
125 help
126 Say Y if you want to add support for SoC audio on the
127 Marvell Saarb reference platform.
128
129config SND_SOC_TAVOREVB3
130 tristate "SoC Audio support for Marvell Tavor EVB3"
131 depends on SND_PXA2XX_SOC && MACH_TAVOREVB3
132 select SND_PXA_SOC_SSP
133 select SND_SOC_88PM860X
134 help
135 Say Y if you want to add support for SoC audio on the
136 Marvell Saarb reference platform.
137
120config SND_SOC_ZYLONITE 138config SND_SOC_ZYLONITE
121 tristate "SoC Audio support for Marvell Zylonite" 139 tristate "SoC Audio support for Marvell Zylonite"
122 depends on SND_PXA2XX_SOC && MACH_ZYLONITE 140 depends on SND_PXA2XX_SOC && MACH_ZYLONITE
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index caa03d8f4789..07660165ec8d 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -19,6 +19,8 @@ snd-soc-e800-objs := e800_wm9712.o
19snd-soc-spitz-objs := spitz.o 19snd-soc-spitz-objs := spitz.o
20snd-soc-em-x270-objs := em-x270.o 20snd-soc-em-x270-objs := em-x270.o
21snd-soc-palm27x-objs := palm27x.o 21snd-soc-palm27x-objs := palm27x.o
22snd-soc-saarb-objs := saarb.o
23snd-soc-tavorevb3-objs := tavorevb3.o
22snd-soc-zylonite-objs := zylonite.o 24snd-soc-zylonite-objs := zylonite.o
23snd-soc-magician-objs := magician.o 25snd-soc-magician-objs := magician.o
24snd-soc-mioa701-objs := mioa701_wm9713.o 26snd-soc-mioa701-objs := mioa701_wm9713.o
@@ -38,6 +40,8 @@ obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
38obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o 40obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
39obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o 41obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
40obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o 42obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
43obj-$(CONFIG_SND_SOC_SAARB) += snd-soc-saarb.o
44obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o
41obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o 45obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
42obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o 46obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
43obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o 47obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c
index 555689cf6727..97e9423615c9 100644
--- a/sound/soc/pxa/corgi.c
+++ b/sound/soc/pxa/corgi.c
@@ -149,7 +149,7 @@ static int corgi_hw_params(struct snd_pcm_substream *substream,
149 return ret; 149 return ret;
150 150
151 /* set the codec system clock for DAC and ADC */ 151 /* set the codec system clock for DAC and ADC */
152 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, 152 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
153 SND_SOC_CLOCK_IN); 153 SND_SOC_CLOCK_IN);
154 if (ret < 0) 154 if (ret < 0)
155 return ret; 155 return ret;
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c
index f614607b2055..c82cedb602fd 100644
--- a/sound/soc/pxa/e740_wm9705.c
+++ b/sound/soc/pxa/e740_wm9705.c
@@ -198,6 +198,9 @@ free_mic_amp_gpio:
198static void __exit e740_exit(void) 198static void __exit e740_exit(void)
199{ 199{
200 platform_device_unregister(e740_snd_device); 200 platform_device_unregister(e740_snd_device);
201 gpio_free(GPIO_E740_WM9705_nAVDD2);
202 gpio_free(GPIO_E740_AMP_ON);
203 gpio_free(GPIO_E740_MIC_ON);
201} 204}
202 205
203module_init(e740_init); 206module_init(e740_init);
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c
index add0e1c25bc8..fa752f6ec37d 100644
--- a/sound/soc/pxa/poodle.c
+++ b/sound/soc/pxa/poodle.c
@@ -128,7 +128,7 @@ static int poodle_hw_params(struct snd_pcm_substream *substream,
128 return ret; 128 return ret;
129 129
130 /* set the codec system clock for DAC and ADC */ 130 /* set the codec system clock for DAC and ADC */
131 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK, clk, 131 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
132 SND_SOC_CLOCK_IN); 132 SND_SOC_CLOCK_IN);
133 if (ret < 0) 133 if (ret < 0)
134 return ret; 134 return ret;
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index 9c2bafa112ad..ac51c6d25c42 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -24,7 +24,6 @@
24#include <mach/dma.h> 24#include <mach/dma.h>
25#include <mach/audio.h> 25#include <mach/audio.h>
26 26
27#include "pxa2xx-pcm.h"
28#include "pxa2xx-ac97.h" 27#include "pxa2xx-ac97.h"
29 28
30static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97) 29static void pxa2xx_ac97_warm_reset(struct snd_ac97 *ac97)
diff --git a/sound/soc/pxa/saarb.c b/sound/soc/pxa/saarb.c
new file mode 100644
index 000000000000..d63cb474b4e1
--- /dev/null
+++ b/sound/soc/pxa/saarb.c
@@ -0,0 +1,200 @@
1/*
2 * saarb.c -- SoC audio for saarb
3 *
4 * Copyright (C) 2010 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/device.h>
15#include <linux/clk.h>
16#include <linux/i2c.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22#include <sound/jack.h>
23
24#include <asm/mach-types.h>
25
26#include "../codecs/88pm860x-codec.h"
27#include "pxa-ssp.h"
28
29static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd);
30
31static struct platform_device *saarb_snd_device;
32
33static struct snd_soc_jack hs_jack, mic_jack;
34
35static struct snd_soc_jack_pin hs_jack_pins[] = {
36 { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
37};
38
39static struct snd_soc_jack_pin mic_jack_pins[] = {
40 { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
41};
42
43/* saarb machine dapm widgets */
44static const struct snd_soc_dapm_widget saarb_dapm_widgets[] = {
45 SND_SOC_DAPM_HP("Headphone Stereophone", NULL),
46 SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
47 SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
48 SND_SOC_DAPM_SPK("Ext Speaker", NULL),
49 SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
50 SND_SOC_DAPM_MIC("Headset Mic", NULL),
51 SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
52};
53
54/* saarb machine audio map */
55static const struct snd_soc_dapm_route audio_map[] = {
56 {"Headset Stereophone", NULL, "HS1"},
57 {"Headset Stereophone", NULL, "HS2"},
58
59 {"Ext Speaker", NULL, "LSP"},
60 {"Ext Speaker", NULL, "LSN"},
61
62 {"Lineout Out 1", NULL, "LINEOUT1"},
63 {"Lineout Out 2", NULL, "LINEOUT2"},
64
65 {"MIC1P", NULL, "Mic1 Bias"},
66 {"MIC1N", NULL, "Mic1 Bias"},
67 {"Mic1 Bias", NULL, "Ext Mic 1"},
68
69 {"MIC2P", NULL, "Mic1 Bias"},
70 {"MIC2N", NULL, "Mic1 Bias"},
71 {"Mic1 Bias", NULL, "Headset Mic 2"},
72
73 {"MIC3P", NULL, "Mic3 Bias"},
74 {"MIC3N", NULL, "Mic3 Bias"},
75 {"Mic3 Bias", NULL, "Ext Mic 3"},
76};
77
78static int saarb_i2s_hw_params(struct snd_pcm_substream *substream,
79 struct snd_pcm_hw_params *params)
80{
81 struct snd_soc_pcm_runtime *rtd = substream->private_data;
82 struct snd_soc_dai *codec_dai = rtd->codec_dai;
83 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
84 int width = snd_pcm_format_physical_width(params_format(params));
85 int ret;
86
87 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
88 PM860X_CLK_DIR_OUT);
89 if (ret < 0)
90 return ret;
91
92 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
93 if (ret < 0)
94 return ret;
95
96 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
97 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
98 if (ret < 0)
99 return ret;
100 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
101 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
102 if (ret < 0)
103 return ret;
104
105 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
106
107 return ret;
108}
109
110static struct snd_soc_ops saarb_i2s_ops = {
111 .hw_params = saarb_i2s_hw_params,
112};
113
114static struct snd_soc_dai_link saarb_dai[] = {
115 {
116 .name = "88PM860x I2S",
117 .stream_name = "I2S Audio",
118 .cpu_dai_name = "pxa-ssp-dai.1",
119 .codec_dai_name = "88pm860x-i2s",
120 .platform_name = "pxa-pcm-audio",
121 .codec_name = "88pm860x-codec",
122 .init = saarb_pm860x_init,
123 .ops = &saarb_i2s_ops,
124 },
125};
126
127static struct snd_soc_card snd_soc_card_saarb = {
128 .name = "Saarb",
129 .dai_link = saarb_dai,
130 .num_links = ARRAY_SIZE(saarb_dai),
131};
132
133static int saarb_pm860x_init(struct snd_soc_pcm_runtime *rtd)
134{
135 struct snd_soc_codec *codec = rtd->codec;
136 int ret;
137
138 snd_soc_dapm_new_controls(codec, saarb_dapm_widgets,
139 ARRAY_SIZE(saarb_dapm_widgets));
140 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
141
142 /* connected pins */
143 snd_soc_dapm_enable_pin(codec, "Ext Speaker");
144 snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
145 snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
146 snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
147 snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
148
149 ret = snd_soc_dapm_sync(codec);
150 if (ret)
151 return ret;
152
153 /* Headset jack detection */
154 snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
155 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
156 &hs_jack);
157 snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
158 hs_jack_pins);
159 snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
160 &mic_jack);
161 snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
162 mic_jack_pins);
163
164 /* headphone, microphone detection & headset short detection */
165 pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
166 SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
167 pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
168 return 0;
169}
170
171static int __init saarb_init(void)
172{
173 int ret;
174
175 if (!machine_is_saarb())
176 return -ENODEV;
177 saarb_snd_device = platform_device_alloc("soc-audio", -1);
178 if (!saarb_snd_device)
179 return -ENOMEM;
180
181 platform_set_drvdata(saarb_snd_device, &snd_soc_card_saarb);
182
183 ret = platform_device_add(saarb_snd_device);
184 if (ret)
185 platform_device_put(saarb_snd_device);
186
187 return ret;
188}
189
190static void __exit saarb_exit(void)
191{
192 platform_device_unregister(saarb_snd_device);
193}
194
195module_init(saarb_init);
196module_exit(saarb_exit);
197
198MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
199MODULE_DESCRIPTION("ALSA SoC 88PM860x Saarb");
200MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/tavorevb3.c b/sound/soc/pxa/tavorevb3.c
new file mode 100644
index 000000000000..248c283fc4df
--- /dev/null
+++ b/sound/soc/pxa/tavorevb3.c
@@ -0,0 +1,200 @@
1/*
2 * tavorevb3.c -- SoC audio for Tavor EVB3
3 *
4 * Copyright (C) 2010 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/device.h>
15#include <linux/clk.h>
16#include <linux/i2c.h>
17#include <sound/core.h>
18#include <sound/pcm.h>
19#include <sound/pcm_params.h>
20#include <sound/soc.h>
21#include <sound/soc-dapm.h>
22#include <sound/jack.h>
23
24#include <asm/mach-types.h>
25
26#include "../codecs/88pm860x-codec.h"
27#include "pxa-ssp.h"
28
29static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd);
30
31static struct platform_device *evb3_snd_device;
32
33static struct snd_soc_jack hs_jack, mic_jack;
34
35static struct snd_soc_jack_pin hs_jack_pins[] = {
36 { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, },
37};
38
39static struct snd_soc_jack_pin mic_jack_pins[] = {
40 { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, },
41};
42
43/* tavorevb3 machine dapm widgets */
44static const struct snd_soc_dapm_widget evb3_dapm_widgets[] = {
45 SND_SOC_DAPM_HP("Headset Stereophone", NULL),
46 SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
47 SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
48 SND_SOC_DAPM_SPK("Ext Speaker", NULL),
49 SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
50 SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
51 SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
52};
53
54/* tavorevb3 machine audio map */
55static const struct snd_soc_dapm_route audio_map[] = {
56 {"Headset Stereophone", NULL, "HS1"},
57 {"Headset Stereophone", NULL, "HS2"},
58
59 {"Ext Speaker", NULL, "LSP"},
60 {"Ext Speaker", NULL, "LSN"},
61
62 {"Lineout Out 1", NULL, "LINEOUT1"},
63 {"Lineout Out 2", NULL, "LINEOUT2"},
64
65 {"MIC1P", NULL, "Mic1 Bias"},
66 {"MIC1N", NULL, "Mic1 Bias"},
67 {"Mic1 Bias", NULL, "Ext Mic 1"},
68
69 {"MIC2P", NULL, "Mic1 Bias"},
70 {"MIC2N", NULL, "Mic1 Bias"},
71 {"Mic1 Bias", NULL, "Headset Mic 2"},
72
73 {"MIC3P", NULL, "Mic3 Bias"},
74 {"MIC3N", NULL, "Mic3 Bias"},
75 {"Mic3 Bias", NULL, "Ext Mic 3"},
76};
77
78static int evb3_i2s_hw_params(struct snd_pcm_substream *substream,
79 struct snd_pcm_hw_params *params)
80{
81 struct snd_soc_pcm_runtime *rtd = substream->private_data;
82 struct snd_soc_dai *codec_dai = rtd->codec_dai;
83 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
84 int width = snd_pcm_format_physical_width(params_format(params));
85 int ret;
86
87 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_NET_PLL, 0,
88 PM860X_CLK_DIR_OUT);
89 if (ret < 0)
90 return ret;
91
92 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 0, PM860X_CLK_DIR_OUT);
93 if (ret < 0)
94 return ret;
95
96 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
97 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
98 if (ret < 0)
99 return ret;
100
101 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
102 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
103 if (ret < 0)
104 return ret;
105
106 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, width);
107 return ret;
108}
109
110static struct snd_soc_ops evb3_i2s_ops = {
111 .hw_params = evb3_i2s_hw_params,
112};
113
114static struct snd_soc_dai_link evb3_dai[] = {
115 {
116 .name = "88PM860x I2S",
117 .stream_name = "I2S Audio",
118 .cpu_dai_name = "pxa-ssp-dai.1",
119 .codec_dai_name = "88pm860x-i2s",
120 .platform_name = "pxa-pcm-audio",
121 .codec_name = "88pm860x-codec",
122 .init = evb3_pm860x_init,
123 .ops = &evb3_i2s_ops,
124 },
125};
126
127static struct snd_soc_card snd_soc_card_evb3 = {
128 .name = "Tavor EVB3",
129 .dai_link = evb3_dai,
130 .num_links = ARRAY_SIZE(evb3_dai),
131};
132
133static int evb3_pm860x_init(struct snd_soc_pcm_runtime *rtd)
134{
135 struct snd_soc_codec *codec = rtd->codec;
136 int ret;
137
138 snd_soc_dapm_new_controls(codec, evb3_dapm_widgets,
139 ARRAY_SIZE(evb3_dapm_widgets));
140 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
141
142 /* connected pins */
143 snd_soc_dapm_enable_pin(codec, "Ext Speaker");
144 snd_soc_dapm_enable_pin(codec, "Ext Mic 1");
145 snd_soc_dapm_enable_pin(codec, "Ext Mic 3");
146 snd_soc_dapm_disable_pin(codec, "Headset Mic 2");
147 snd_soc_dapm_disable_pin(codec, "Headset Stereophone");
148
149 ret = snd_soc_dapm_sync(codec);
150 if (ret)
151 return ret;
152
153 /* Headset jack detection */
154 snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE
155 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
156 &hs_jack);
157 snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
158 hs_jack_pins);
159 snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE,
160 &mic_jack);
161 snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins),
162 mic_jack_pins);
163
164 /* headphone, microphone detection & headset short detection */
165 pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE,
166 SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
167 pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE);
168 return 0;
169}
170
171static int __init tavorevb3_init(void)
172{
173 int ret;
174
175 if (!machine_is_tavorevb3())
176 return -ENODEV;
177 evb3_snd_device = platform_device_alloc("soc-audio", -1);
178 if (!evb3_snd_device)
179 return -ENOMEM;
180
181 platform_set_drvdata(evb3_snd_device, &snd_soc_card_evb3);
182
183 ret = platform_device_add(evb3_snd_device);
184 if (ret)
185 platform_device_put(evb3_snd_device);
186
187 return ret;
188}
189
190static void __exit tavorevb3_exit(void)
191{
192 platform_device_unregister(evb3_snd_device);
193}
194
195module_init(tavorevb3_init);
196module_exit(tavorevb3_exit);
197
198MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
199MODULE_DESCRIPTION("ALSA SoC 88PM860x Tavor EVB3");
200MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 7093c1787128..65352c7d4b7f 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3122,10 +3122,12 @@ int snd_soc_register_codec(struct device *dev,
3122 fixup_codec_formats(&dai_drv[i].capture); 3122 fixup_codec_formats(&dai_drv[i].capture);
3123 } 3123 }
3124 3124
3125 /* register DAIs */ 3125 /* register any DAIs */
3126 ret = snd_soc_register_dais(dev, dai_drv, num_dai); 3126 if (num_dai) {
3127 if (ret < 0) 3127 ret = snd_soc_register_dais(dev, dai_drv, num_dai);
3128 if (ret < 0)
3128 goto error; 3129 goto error;
3130 }
3129 3131
3130 mutex_lock(&client_mutex); 3132 mutex_lock(&client_mutex);
3131 list_add(&codec->list, &codec_list); 3133 list_add(&codec->list, &codec_list);
@@ -3164,8 +3166,9 @@ void snd_soc_unregister_codec(struct device *dev)
3164 return; 3166 return;
3165 3167
3166found: 3168found:
3167 for (i = 0; i < codec->num_dai; i++) 3169 if (codec->num_dai)
3168 snd_soc_unregister_dai(dev); 3170 for (i = 0; i < codec->num_dai; i++)
3171 snd_soc_unregister_dai(dev);
3169 3172
3170 mutex_lock(&client_mutex); 3173 mutex_lock(&client_mutex);
3171 list_del(&codec->list); 3174 list_del(&codec->list);