diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/ux500-mop500.txt | 39 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/sound/ux500-msp.txt | 43 | ||||
-rw-r--r-- | arch/arm/mach-ux500/board-mop500-msp.c | 79 | ||||
-rw-r--r-- | arch/arm/mach-ux500/include/mach/msp.h | 2 | ||||
-rw-r--r-- | include/linux/mfd/abx500/ab8500-codec.h | 6 | ||||
-rw-r--r-- | sound/soc/codecs/ab8500-codec.c | 81 | ||||
-rw-r--r-- | sound/soc/ux500/mop500.c | 47 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_dai.c | 6 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_i2s.c | 89 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_msp_i2s.h | 8 |
10 files changed, 292 insertions, 108 deletions
diff --git a/Documentation/devicetree/bindings/sound/ux500-mop500.txt b/Documentation/devicetree/bindings/sound/ux500-mop500.txt new file mode 100644 index 000000000000..48e071c96b46 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ux500-mop500.txt | |||
@@ -0,0 +1,39 @@ | |||
1 | * MOP500 Audio Machine Driver | ||
2 | |||
3 | This node is responsible for linking together all ux500 Audio Driver components. | ||
4 | |||
5 | Required properties: | ||
6 | - compatible : "stericsson,snd-soc-mop500" | ||
7 | |||
8 | Non-standard properties: | ||
9 | - stericsson,cpu-dai : Phandle to the CPU-side DAI | ||
10 | - stericsson,audio-codec : Phandle to the Audio CODEC | ||
11 | - stericsson,card-name : Over-ride default card name | ||
12 | |||
13 | Example: | ||
14 | |||
15 | sound { | ||
16 | compatible = "stericsson,snd-soc-mop500"; | ||
17 | |||
18 | stericsson,cpu-dai = <&msp1 &msp3>; | ||
19 | stericsson,audio-codec = <&codec>; | ||
20 | }; | ||
21 | |||
22 | msp1: msp@80124000 { | ||
23 | compatible = "stericsson,ux500-msp-i2s"; | ||
24 | reg = <0x80124000 0x1000>; | ||
25 | interrupts = <0 62 0x4>; | ||
26 | v-ape-supply = <&db8500_vape_reg>; | ||
27 | }; | ||
28 | |||
29 | msp3: msp@80125000 { | ||
30 | compatible = "stericsson,ux500-msp-i2s"; | ||
31 | reg = <0x80125000 0x1000>; | ||
32 | interrupts = <0 62 0x4>; | ||
33 | v-ape-supply = <&db8500_vape_reg>; | ||
34 | }; | ||
35 | |||
36 | codec: ab8500-codec { | ||
37 | compatible = "stericsson,ab8500-codec"; | ||
38 | stericsson,earpeice-cmv = <950>; /* Units in mV. */ | ||
39 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/ux500-msp.txt b/Documentation/devicetree/bindings/sound/ux500-msp.txt new file mode 100644 index 000000000000..99acd9c774e1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ux500-msp.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | * ux500 MSP (CPU-side Digital Audio Interface) | ||
2 | |||
3 | Required properties: | ||
4 | - compatible :"stericsson,ux500-msp-i2s" | ||
5 | - reg : Physical base address and length of the device's registers. | ||
6 | |||
7 | Optional properties: | ||
8 | - interrupts : The interrupt output from the device. | ||
9 | - interrupt-parent : The parent interrupt controller. | ||
10 | - <name>-supply : Phandle to the regulator <name> supply | ||
11 | |||
12 | Example: | ||
13 | |||
14 | sound { | ||
15 | compatible = "stericsson,snd-soc-mop500"; | ||
16 | |||
17 | stericsson,platform-pcm-dma = <&pcm>; | ||
18 | stericsson,cpu-dai = <&msp1 &msp3>; | ||
19 | stericsson,audio-codec = <&codec>; | ||
20 | }; | ||
21 | |||
22 | pcm: ux500-pcm { | ||
23 | compatible = "stericsson,ux500-pcm"; | ||
24 | }; | ||
25 | |||
26 | msp1: msp@80124000 { | ||
27 | compatible = "stericsson,ux500-msp-i2s"; | ||
28 | reg = <0x80124000 0x1000>; | ||
29 | interrupts = <0 62 0x4>; | ||
30 | v-ape-supply = <&db8500_vape_reg>; | ||
31 | }; | ||
32 | |||
33 | msp3: msp@80125000 { | ||
34 | compatible = "stericsson,ux500-msp-i2s"; | ||
35 | reg = <0x80125000 0x1000>; | ||
36 | interrupts = <0 62 0x4>; | ||
37 | v-ape-supply = <&db8500_vape_reg>; | ||
38 | }; | ||
39 | |||
40 | codec: ab8500-codec { | ||
41 | compatible = "stericsson,ab8500-codec"; | ||
42 | stericsson,earpeice-cmv = <950>; /* Units in mV. */ | ||
43 | }; | ||
diff --git a/arch/arm/mach-ux500/board-mop500-msp.c b/arch/arm/mach-ux500/board-mop500-msp.c index df15646036aa..ace6c051bc1a 100644 --- a/arch/arm/mach-ux500/board-mop500-msp.c +++ b/arch/arm/mach-ux500/board-mop500-msp.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/platform_device.h> | 7 | #include <linux/platform_device.h> |
8 | #include <linux/init.h> | 8 | #include <linux/init.h> |
9 | #include <linux/gpio.h> | 9 | #include <linux/gpio.h> |
10 | #include <linux/pinctrl/consumer.h> | ||
11 | 10 | ||
12 | #include <plat/gpio-nomadik.h> | 11 | #include <plat/gpio-nomadik.h> |
13 | #include <plat/pincfg.h> | 12 | #include <plat/pincfg.h> |
@@ -23,53 +22,6 @@ | |||
23 | #include "devices-db8500.h" | 22 | #include "devices-db8500.h" |
24 | #include "pins-db8500.h" | 23 | #include "pins-db8500.h" |
25 | 24 | ||
26 | /* MSP1/3 Tx/Rx usage protection */ | ||
27 | static DEFINE_SPINLOCK(msp_rxtx_lock); | ||
28 | |||
29 | /* Reference Count */ | ||
30 | static int msp_rxtx_ref; | ||
31 | |||
32 | /* Pin modes */ | ||
33 | struct pinctrl *msp1_p; | ||
34 | struct pinctrl_state *msp1_def; | ||
35 | struct pinctrl_state *msp1_sleep; | ||
36 | |||
37 | int msp13_i2s_init(void) | ||
38 | { | ||
39 | int retval = 0; | ||
40 | unsigned long flags; | ||
41 | |||
42 | spin_lock_irqsave(&msp_rxtx_lock, flags); | ||
43 | if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_def))) { | ||
44 | retval = pinctrl_select_state(msp1_p, msp1_def); | ||
45 | if (retval) | ||
46 | pr_err("could not set MSP1 defstate\n"); | ||
47 | } | ||
48 | if (!retval) | ||
49 | msp_rxtx_ref++; | ||
50 | spin_unlock_irqrestore(&msp_rxtx_lock, flags); | ||
51 | |||
52 | return retval; | ||
53 | } | ||
54 | |||
55 | int msp13_i2s_exit(void) | ||
56 | { | ||
57 | int retval = 0; | ||
58 | unsigned long flags; | ||
59 | |||
60 | spin_lock_irqsave(&msp_rxtx_lock, flags); | ||
61 | WARN_ON(!msp_rxtx_ref); | ||
62 | msp_rxtx_ref--; | ||
63 | if (msp_rxtx_ref == 0 && !(IS_ERR(msp1_p) || IS_ERR(msp1_sleep))) { | ||
64 | retval = pinctrl_select_state(msp1_p, msp1_sleep); | ||
65 | if (retval) | ||
66 | pr_err("could not set MSP1 sleepstate\n"); | ||
67 | } | ||
68 | spin_unlock_irqrestore(&msp_rxtx_lock, flags); | ||
69 | |||
70 | return retval; | ||
71 | } | ||
72 | |||
73 | static struct stedma40_chan_cfg msp0_dma_rx = { | 25 | static struct stedma40_chan_cfg msp0_dma_rx = { |
74 | .high_priority = true, | 26 | .high_priority = true, |
75 | .dir = STEDMA40_PERIPH_TO_MEM, | 27 | .dir = STEDMA40_PERIPH_TO_MEM, |
@@ -132,8 +84,6 @@ static struct msp_i2s_platform_data msp1_platform_data = { | |||
132 | .id = MSP_I2S_1, | 84 | .id = MSP_I2S_1, |
133 | .msp_i2s_dma_rx = NULL, | 85 | .msp_i2s_dma_rx = NULL, |
134 | .msp_i2s_dma_tx = &msp1_dma_tx, | 86 | .msp_i2s_dma_tx = &msp1_dma_tx, |
135 | .msp_i2s_init = msp13_i2s_init, | ||
136 | .msp_i2s_exit = msp13_i2s_exit, | ||
137 | }; | 87 | }; |
138 | 88 | ||
139 | static struct stedma40_chan_cfg msp2_dma_rx = { | 89 | static struct stedma40_chan_cfg msp2_dma_rx = { |
@@ -219,49 +169,22 @@ static struct msp_i2s_platform_data msp3_platform_data = { | |||
219 | .id = MSP_I2S_3, | 169 | .id = MSP_I2S_3, |
220 | .msp_i2s_dma_rx = &msp1_dma_rx, | 170 | .msp_i2s_dma_rx = &msp1_dma_rx, |
221 | .msp_i2s_dma_tx = NULL, | 171 | .msp_i2s_dma_tx = NULL, |
222 | .msp_i2s_init = msp13_i2s_init, | ||
223 | .msp_i2s_exit = msp13_i2s_exit, | ||
224 | }; | 172 | }; |
225 | 173 | ||
226 | int mop500_msp_init(struct device *parent) | 174 | int mop500_msp_init(struct device *parent) |
227 | { | 175 | { |
228 | struct platform_device *msp1; | ||
229 | |||
230 | pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__); | 176 | pr_info("%s: Register platform-device 'snd-soc-mop500'.\n", __func__); |
231 | platform_device_register(&snd_soc_mop500); | 177 | platform_device_register(&snd_soc_mop500); |
232 | 178 | ||
233 | pr_info("Initialize MSP I2S-devices.\n"); | 179 | pr_info("Initialize MSP I2S-devices.\n"); |
234 | db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, | 180 | db8500_add_msp_i2s(parent, 0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, |
235 | &msp0_platform_data); | 181 | &msp0_platform_data); |
236 | msp1 = db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, | 182 | db8500_add_msp_i2s(parent, 1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, |
237 | &msp1_platform_data); | 183 | &msp1_platform_data); |
238 | db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, | 184 | db8500_add_msp_i2s(parent, 2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, |
239 | &msp2_platform_data); | 185 | &msp2_platform_data); |
240 | db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, | 186 | db8500_add_msp_i2s(parent, 3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, |
241 | &msp3_platform_data); | 187 | &msp3_platform_data); |
242 | 188 | ||
243 | /* Get the pinctrl handle for MSP1 */ | ||
244 | if (msp1) { | ||
245 | msp1_p = pinctrl_get(&msp1->dev); | ||
246 | if (IS_ERR(msp1_p)) | ||
247 | dev_err(&msp1->dev, "could not get MSP1 pinctrl\n"); | ||
248 | else { | ||
249 | msp1_def = pinctrl_lookup_state(msp1_p, | ||
250 | PINCTRL_STATE_DEFAULT); | ||
251 | if (IS_ERR(msp1_def)) { | ||
252 | dev_err(&msp1->dev, | ||
253 | "could not get MSP1 defstate\n"); | ||
254 | } | ||
255 | msp1_sleep = pinctrl_lookup_state(msp1_p, | ||
256 | PINCTRL_STATE_SLEEP); | ||
257 | if (IS_ERR(msp1_sleep)) | ||
258 | dev_err(&msp1->dev, | ||
259 | "could not get MSP1 idlestate\n"); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | pr_info("%s: Register platform-device 'ux500-pcm'\n", __func__); | ||
264 | platform_device_register(&ux500_pcm); | ||
265 | |||
266 | return 0; | 189 | return 0; |
267 | } | 190 | } |
diff --git a/arch/arm/mach-ux500/include/mach/msp.h b/arch/arm/mach-ux500/include/mach/msp.h index 798be19129ef..3cc7142eee02 100644 --- a/arch/arm/mach-ux500/include/mach/msp.h +++ b/arch/arm/mach-ux500/include/mach/msp.h | |||
@@ -22,8 +22,6 @@ struct msp_i2s_platform_data { | |||
22 | enum msp_i2s_id id; | 22 | enum msp_i2s_id id; |
23 | struct stedma40_chan_cfg *msp_i2s_dma_rx; | 23 | struct stedma40_chan_cfg *msp_i2s_dma_rx; |
24 | struct stedma40_chan_cfg *msp_i2s_dma_tx; | 24 | struct stedma40_chan_cfg *msp_i2s_dma_tx; |
25 | int (*msp_i2s_init) (void); | ||
26 | int (*msp_i2s_exit) (void); | ||
27 | }; | 25 | }; |
28 | 26 | ||
29 | #endif | 27 | #endif |
diff --git a/include/linux/mfd/abx500/ab8500-codec.h b/include/linux/mfd/abx500/ab8500-codec.h index dc6529202cdd..d7079413def0 100644 --- a/include/linux/mfd/abx500/ab8500-codec.h +++ b/include/linux/mfd/abx500/ab8500-codec.h | |||
@@ -23,7 +23,8 @@ enum amic_type { | |||
23 | /* Mic-biases */ | 23 | /* Mic-biases */ |
24 | enum amic_micbias { | 24 | enum amic_micbias { |
25 | AMIC_MICBIAS_VAMIC1, | 25 | AMIC_MICBIAS_VAMIC1, |
26 | AMIC_MICBIAS_VAMIC2 | 26 | AMIC_MICBIAS_VAMIC2, |
27 | AMIC_MICBIAS_UNKNOWN | ||
27 | }; | 28 | }; |
28 | 29 | ||
29 | /* Bias-voltage */ | 30 | /* Bias-voltage */ |
@@ -31,7 +32,8 @@ enum ear_cm_voltage { | |||
31 | EAR_CMV_0_95V, | 32 | EAR_CMV_0_95V, |
32 | EAR_CMV_1_10V, | 33 | EAR_CMV_1_10V, |
33 | EAR_CMV_1_27V, | 34 | EAR_CMV_1_27V, |
34 | EAR_CMV_1_58V | 35 | EAR_CMV_1_58V, |
36 | EAR_CMV_UNKNOWN | ||
35 | }; | 37 | }; |
36 | 38 | ||
37 | /* Analog microphone settings */ | 39 | /* Analog microphone settings */ |
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 2c1c2524ef8c..af547490b4f7 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/mfd/abx500/ab8500-sysctrl.h> | 34 | #include <linux/mfd/abx500/ab8500-sysctrl.h> |
35 | #include <linux/mfd/abx500/ab8500-codec.h> | 35 | #include <linux/mfd/abx500/ab8500-codec.h> |
36 | #include <linux/regulator/consumer.h> | 36 | #include <linux/regulator/consumer.h> |
37 | #include <linux/of.h> | ||
37 | 38 | ||
38 | #include <sound/core.h> | 39 | #include <sound/core.h> |
39 | #include <sound/pcm.h> | 40 | #include <sound/pcm.h> |
@@ -2394,9 +2395,65 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = { | |||
2394 | } | 2395 | } |
2395 | }; | 2396 | }; |
2396 | 2397 | ||
2398 | static void ab8500_codec_of_probe(struct device *dev, struct device_node *np, | ||
2399 | struct ab8500_codec_platform_data *codec) | ||
2400 | { | ||
2401 | u32 value; | ||
2402 | |||
2403 | if (of_get_property(np, "stericsson,amic1-type-single-ended", NULL)) | ||
2404 | codec->amics.mic1_type = AMIC_TYPE_SINGLE_ENDED; | ||
2405 | else | ||
2406 | codec->amics.mic1_type = AMIC_TYPE_DIFFERENTIAL; | ||
2407 | |||
2408 | if (of_get_property(np, "stericsson,amic2-type-single-ended", NULL)) | ||
2409 | codec->amics.mic2_type = AMIC_TYPE_SINGLE_ENDED; | ||
2410 | else | ||
2411 | codec->amics.mic2_type = AMIC_TYPE_DIFFERENTIAL; | ||
2412 | |||
2413 | /* Has a non-standard Vamic been requested? */ | ||
2414 | if (of_get_property(np, "stericsson,amic1a-bias-vamic2", NULL)) | ||
2415 | codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC2; | ||
2416 | else | ||
2417 | codec->amics.mic1a_micbias = AMIC_MICBIAS_VAMIC1; | ||
2418 | |||
2419 | if (of_get_property(np, "stericsson,amic1b-bias-vamic2", NULL)) | ||
2420 | codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC2; | ||
2421 | else | ||
2422 | codec->amics.mic1b_micbias = AMIC_MICBIAS_VAMIC1; | ||
2423 | |||
2424 | if (of_get_property(np, "stericsson,amic2-bias-vamic1", NULL)) | ||
2425 | codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC1; | ||
2426 | else | ||
2427 | codec->amics.mic2_micbias = AMIC_MICBIAS_VAMIC2; | ||
2428 | |||
2429 | if (!of_property_read_u32(np, "stericsson,earpeice-cmv", &value)) { | ||
2430 | switch (value) { | ||
2431 | case 950 : | ||
2432 | codec->ear_cmv = EAR_CMV_0_95V; | ||
2433 | break; | ||
2434 | case 1100 : | ||
2435 | codec->ear_cmv = EAR_CMV_1_10V; | ||
2436 | break; | ||
2437 | case 1270 : | ||
2438 | codec->ear_cmv = EAR_CMV_1_27V; | ||
2439 | break; | ||
2440 | case 1580 : | ||
2441 | codec->ear_cmv = EAR_CMV_1_58V; | ||
2442 | break; | ||
2443 | default : | ||
2444 | codec->ear_cmv = EAR_CMV_UNKNOWN; | ||
2445 | dev_err(dev, "Unsuitable earpiece voltage found in DT\n"); | ||
2446 | } | ||
2447 | } else { | ||
2448 | dev_warn(dev, "No earpiece voltage found in DT - using default\n"); | ||
2449 | codec->ear_cmv = EAR_CMV_0_95V; | ||
2450 | } | ||
2451 | } | ||
2452 | |||
2397 | static int ab8500_codec_probe(struct snd_soc_codec *codec) | 2453 | static int ab8500_codec_probe(struct snd_soc_codec *codec) |
2398 | { | 2454 | { |
2399 | struct device *dev = codec->dev; | 2455 | struct device *dev = codec->dev; |
2456 | struct device_node *np = dev->of_node; | ||
2400 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); | 2457 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); |
2401 | struct ab8500_platform_data *pdata; | 2458 | struct ab8500_platform_data *pdata; |
2402 | struct filter_control *fc; | 2459 | struct filter_control *fc; |
@@ -2407,6 +2464,30 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) | |||
2407 | /* Setup AB8500 according to board-settings */ | 2464 | /* Setup AB8500 according to board-settings */ |
2408 | pdata = dev_get_platdata(dev->parent); | 2465 | pdata = dev_get_platdata(dev->parent); |
2409 | 2466 | ||
2467 | if (np) { | ||
2468 | if (!pdata) | ||
2469 | pdata = devm_kzalloc(dev, | ||
2470 | sizeof(struct ab8500_platform_data), | ||
2471 | GFP_KERNEL); | ||
2472 | |||
2473 | if (pdata && !pdata->codec) | ||
2474 | pdata->codec | ||
2475 | = devm_kzalloc(dev, | ||
2476 | sizeof(struct ab8500_codec_platform_data), | ||
2477 | GFP_KERNEL); | ||
2478 | |||
2479 | if (!(pdata && pdata->codec)) | ||
2480 | return -ENOMEM; | ||
2481 | |||
2482 | ab8500_codec_of_probe(dev, np, pdata->codec); | ||
2483 | |||
2484 | } else { | ||
2485 | if (!(pdata && pdata->codec)) { | ||
2486 | dev_err(dev, "No codec platform data or DT found\n"); | ||
2487 | return -EINVAL; | ||
2488 | } | ||
2489 | } | ||
2490 | |||
2410 | status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); | 2491 | status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); |
2411 | if (status < 0) { | 2492 | if (status < 0) { |
2412 | pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); | 2493 | pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); |
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index 31c4d26d0359..356611d9654d 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/spi/spi.h> | 18 | #include <linux/spi/spi.h> |
19 | #include <linux/of.h> | ||
19 | 20 | ||
20 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
21 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
@@ -56,16 +57,47 @@ static struct snd_soc_card mop500_card = { | |||
56 | .num_links = ARRAY_SIZE(mop500_dai_links), | 57 | .num_links = ARRAY_SIZE(mop500_dai_links), |
57 | }; | 58 | }; |
58 | 59 | ||
60 | static int __devinit mop500_of_probe(struct platform_device *pdev, | ||
61 | struct device_node *np) | ||
62 | { | ||
63 | struct device_node *codec_np, *msp_np[2]; | ||
64 | int i; | ||
65 | |||
66 | msp_np[0] = of_parse_phandle(np, "stericsson,cpu-dai", 0); | ||
67 | msp_np[1] = of_parse_phandle(np, "stericsson,cpu-dai", 1); | ||
68 | codec_np = of_parse_phandle(np, "stericsson,audio-codec", 0); | ||
69 | |||
70 | if (!(msp_np[0] && msp_np[1] && codec_np)) { | ||
71 | dev_err(&pdev->dev, "Phandle missing or invalid\n"); | ||
72 | return -EINVAL; | ||
73 | } | ||
74 | |||
75 | for (i = 0; i < 2; i++) { | ||
76 | mop500_dai_links[i].cpu_of_node = msp_np[i]; | ||
77 | mop500_dai_links[i].cpu_dai_name = NULL; | ||
78 | mop500_dai_links[i].codec_of_node = codec_np; | ||
79 | mop500_dai_links[i].codec_name = NULL; | ||
80 | } | ||
81 | |||
82 | snd_soc_of_parse_card_name(&mop500_card, "stericsson,card-name"); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
59 | static int __devinit mop500_probe(struct platform_device *pdev) | 86 | static int __devinit mop500_probe(struct platform_device *pdev) |
60 | { | 87 | { |
88 | struct device_node *np = pdev->dev.of_node; | ||
61 | int ret; | 89 | int ret; |
62 | 90 | ||
63 | pr_debug("%s: Enter.\n", __func__); | ||
64 | |||
65 | dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); | 91 | dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); |
66 | 92 | ||
67 | mop500_card.dev = &pdev->dev; | 93 | mop500_card.dev = &pdev->dev; |
68 | 94 | ||
95 | if (np) { | ||
96 | ret = mop500_of_probe(pdev, np); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | } | ||
100 | |||
69 | dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n", | 101 | dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n", |
70 | __func__, mop500_card.name); | 102 | __func__, mop500_card.name); |
71 | platform_set_drvdata(pdev, &mop500_card); | 103 | platform_set_drvdata(pdev, &mop500_card); |
@@ -83,8 +115,7 @@ static int __devinit mop500_probe(struct platform_device *pdev) | |||
83 | ret = snd_soc_register_card(&mop500_card); | 115 | ret = snd_soc_register_card(&mop500_card); |
84 | if (ret) | 116 | if (ret) |
85 | dev_err(&pdev->dev, | 117 | dev_err(&pdev->dev, |
86 | "Error: snd_soc_register_card failed (%d)!\n", | 118 | "Error: snd_soc_register_card failed (%d)!\n", ret); |
87 | ret); | ||
88 | 119 | ||
89 | return ret; | 120 | return ret; |
90 | } | 121 | } |
@@ -97,14 +128,20 @@ static int __devexit mop500_remove(struct platform_device *pdev) | |||
97 | 128 | ||
98 | snd_soc_unregister_card(mop500_card); | 129 | snd_soc_unregister_card(mop500_card); |
99 | mop500_ab8500_remove(mop500_card); | 130 | mop500_ab8500_remove(mop500_card); |
100 | 131 | ||
101 | return 0; | 132 | return 0; |
102 | } | 133 | } |
103 | 134 | ||
135 | static const struct of_device_id snd_soc_mop500_match[] = { | ||
136 | { .compatible = "stericsson,snd-soc-mop500", }, | ||
137 | {}, | ||
138 | }; | ||
139 | |||
104 | static struct platform_driver snd_soc_mop500_driver = { | 140 | static struct platform_driver snd_soc_mop500_driver = { |
105 | .driver = { | 141 | .driver = { |
106 | .owner = THIS_MODULE, | 142 | .owner = THIS_MODULE, |
107 | .name = "snd-soc-mop500", | 143 | .name = "snd-soc-mop500", |
144 | .of_match_table = snd_soc_mop500_match, | ||
108 | }, | 145 | }, |
109 | .probe = mop500_probe, | 146 | .probe = mop500_probe, |
110 | .remove = __devexit_p(mop500_remove), | 147 | .remove = __devexit_p(mop500_remove), |
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 772cb19d2fb3..be94bf9bf94f 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c | |||
@@ -833,10 +833,16 @@ static int __devexit ux500_msp_drv_remove(struct platform_device *pdev) | |||
833 | return 0; | 833 | return 0; |
834 | } | 834 | } |
835 | 835 | ||
836 | static const struct of_device_id ux500_msp_i2s_match[] = { | ||
837 | { .compatible = "stericsson,ux500-msp-i2s", }, | ||
838 | {}, | ||
839 | }; | ||
840 | |||
836 | static struct platform_driver msp_i2s_driver = { | 841 | static struct platform_driver msp_i2s_driver = { |
837 | .driver = { | 842 | .driver = { |
838 | .name = "ux500-msp-i2s", | 843 | .name = "ux500-msp-i2s", |
839 | .owner = THIS_MODULE, | 844 | .owner = THIS_MODULE, |
845 | .of_match_table = ux500_msp_i2s_match, | ||
840 | }, | 846 | }, |
841 | .probe = ux500_msp_drv_probe, | 847 | .probe = ux500_msp_drv_probe, |
842 | .remove = ux500_msp_drv_remove, | 848 | .remove = ux500_msp_drv_remove, |
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index 1b7c2f58ce13..b7c996e77570 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c | |||
@@ -15,8 +15,10 @@ | |||
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/pinctrl/consumer.h> | ||
18 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/of.h> | ||
20 | 22 | ||
21 | #include <mach/hardware.h> | 23 | #include <mach/hardware.h> |
22 | #include <mach/msp.h> | 24 | #include <mach/msp.h> |
@@ -25,6 +27,9 @@ | |||
25 | 27 | ||
26 | #include "ux500_msp_i2s.h" | 28 | #include "ux500_msp_i2s.h" |
27 | 29 | ||
30 | /* MSP1/3 Tx/Rx usage protection */ | ||
31 | static DEFINE_SPINLOCK(msp_rxtx_lock); | ||
32 | |||
28 | /* Protocol desciptors */ | 33 | /* Protocol desciptors */ |
29 | static const struct msp_protdesc prot_descs[] = { | 34 | static const struct msp_protdesc prot_descs[] = { |
30 | { /* I2S */ | 35 | { /* I2S */ |
@@ -352,17 +357,23 @@ static int configure_multichannel(struct ux500_msp *msp, | |||
352 | 357 | ||
353 | static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config) | 358 | static int enable_msp(struct ux500_msp *msp, struct ux500_msp_config *config) |
354 | { | 359 | { |
355 | int status = 0; | 360 | int status = 0, retval = 0; |
356 | u32 reg_val_DMACR, reg_val_GCR; | 361 | u32 reg_val_DMACR, reg_val_GCR; |
362 | unsigned long flags; | ||
357 | 363 | ||
358 | /* Check msp state whether in RUN or CONFIGURED Mode */ | 364 | /* Check msp state whether in RUN or CONFIGURED Mode */ |
359 | if ((msp->msp_state == MSP_STATE_IDLE) && (msp->plat_init)) { | 365 | if (msp->msp_state == MSP_STATE_IDLE) { |
360 | status = msp->plat_init(); | 366 | spin_lock_irqsave(&msp_rxtx_lock, flags); |
361 | if (status) { | 367 | if (msp->pinctrl_rxtx_ref == 0 && |
362 | dev_err(msp->dev, "%s: ERROR: Failed to init MSP (%d)!\n", | 368 | !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_def))) { |
363 | __func__, status); | 369 | retval = pinctrl_select_state(msp->pinctrl_p, |
364 | return status; | 370 | msp->pinctrl_def); |
371 | if (retval) | ||
372 | pr_err("could not set MSP defstate\n"); | ||
365 | } | 373 | } |
374 | if (!retval) | ||
375 | msp->pinctrl_rxtx_ref++; | ||
376 | spin_unlock_irqrestore(&msp_rxtx_lock, flags); | ||
366 | } | 377 | } |
367 | 378 | ||
368 | /* Configure msp with protocol dependent settings */ | 379 | /* Configure msp with protocol dependent settings */ |
@@ -620,7 +631,8 @@ int ux500_msp_i2s_trigger(struct ux500_msp *msp, int cmd, int direction) | |||
620 | 631 | ||
621 | int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) | 632 | int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) |
622 | { | 633 | { |
623 | int status = 0; | 634 | int status = 0, retval = 0; |
635 | unsigned long flags; | ||
624 | 636 | ||
625 | dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir); | 637 | dev_dbg(msp->dev, "%s: Enter (dir = 0x%01x).\n", __func__, dir); |
626 | 638 | ||
@@ -631,12 +643,19 @@ int ux500_msp_i2s_close(struct ux500_msp *msp, unsigned int dir) | |||
631 | writel((readl(msp->registers + MSP_GCR) & | 643 | writel((readl(msp->registers + MSP_GCR) & |
632 | (~(FRAME_GEN_ENABLE | SRG_ENABLE))), | 644 | (~(FRAME_GEN_ENABLE | SRG_ENABLE))), |
633 | msp->registers + MSP_GCR); | 645 | msp->registers + MSP_GCR); |
634 | if (msp->plat_exit) | 646 | |
635 | status = msp->plat_exit(); | 647 | spin_lock_irqsave(&msp_rxtx_lock, flags); |
636 | if (status) | 648 | WARN_ON(!msp->pinctrl_rxtx_ref); |
637 | dev_warn(msp->dev, | 649 | msp->pinctrl_rxtx_ref--; |
638 | "%s: WARN: ux500_msp_i2s_exit failed (%d)!\n", | 650 | if (msp->pinctrl_rxtx_ref == 0 && |
639 | __func__, status); | 651 | !(IS_ERR(msp->pinctrl_p) || IS_ERR(msp->pinctrl_sleep))) { |
652 | retval = pinctrl_select_state(msp->pinctrl_p, | ||
653 | msp->pinctrl_sleep); | ||
654 | if (retval) | ||
655 | pr_err("could not set MSP sleepstate\n"); | ||
656 | } | ||
657 | spin_unlock_irqrestore(&msp_rxtx_lock, flags); | ||
658 | |||
640 | writel(0, msp->registers + MSP_GCR); | 659 | writel(0, msp->registers + MSP_GCR); |
641 | writel(0, msp->registers + MSP_TCF); | 660 | writel(0, msp->registers + MSP_TCF); |
642 | writel(0, msp->registers + MSP_RCF); | 661 | writel(0, msp->registers + MSP_RCF); |
@@ -665,20 +684,33 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, | |||
665 | { | 684 | { |
666 | struct resource *res = NULL; | 685 | struct resource *res = NULL; |
667 | struct i2s_controller *i2s_cont; | 686 | struct i2s_controller *i2s_cont; |
687 | struct device_node *np = pdev->dev.of_node; | ||
668 | struct ux500_msp *msp; | 688 | struct ux500_msp *msp; |
669 | 689 | ||
670 | dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__, | ||
671 | pdev->name, platform_data->id); | ||
672 | |||
673 | *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL); | 690 | *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL); |
674 | msp = *msp_p; | 691 | msp = *msp_p; |
675 | if (!msp) | 692 | if (!msp) |
676 | return -ENOMEM; | 693 | return -ENOMEM; |
677 | 694 | ||
695 | if (np) { | ||
696 | if (!platform_data) { | ||
697 | platform_data = devm_kzalloc(&pdev->dev, | ||
698 | sizeof(struct msp_i2s_platform_data), GFP_KERNEL); | ||
699 | if (!platform_data) | ||
700 | ret = -ENOMEM; | ||
701 | } | ||
702 | } else | ||
703 | if (!platform_data) | ||
704 | ret = -EINVAL; | ||
705 | |||
706 | if (ret) | ||
707 | goto err_res; | ||
708 | |||
709 | dev_dbg(&pdev->dev, "%s: Enter (name: %s, id: %d).\n", __func__, | ||
710 | pdev->name, platform_data->id); | ||
711 | |||
678 | msp->id = platform_data->id; | 712 | msp->id = platform_data->id; |
679 | msp->dev = &pdev->dev; | 713 | msp->dev = &pdev->dev; |
680 | msp->plat_init = platform_data->msp_i2s_init; | ||
681 | msp->plat_exit = platform_data->msp_i2s_exit; | ||
682 | msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx; | 714 | msp->dma_cfg_rx = platform_data->msp_i2s_dma_rx; |
683 | msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx; | 715 | msp->dma_cfg_tx = platform_data->msp_i2s_dma_tx; |
684 | 716 | ||
@@ -715,6 +747,25 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev, | |||
715 | dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name); | 747 | dev_dbg(&pdev->dev, "I2S device-name: '%s'\n", i2s_cont->name); |
716 | msp->i2s_cont = i2s_cont; | 748 | msp->i2s_cont = i2s_cont; |
717 | 749 | ||
750 | msp->pinctrl_p = pinctrl_get(msp->dev); | ||
751 | if (IS_ERR(msp->pinctrl_p)) | ||
752 | dev_err(&pdev->dev, "could not get MSP pinctrl\n"); | ||
753 | else { | ||
754 | msp->pinctrl_def = pinctrl_lookup_state(msp->pinctrl_p, | ||
755 | PINCTRL_STATE_DEFAULT); | ||
756 | if (IS_ERR(msp->pinctrl_def)) { | ||
757 | dev_err(&pdev->dev, | ||
758 | "could not get MSP defstate (%li)\n", | ||
759 | PTR_ERR(msp->pinctrl_def)); | ||
760 | } | ||
761 | msp->pinctrl_sleep = pinctrl_lookup_state(msp->pinctrl_p, | ||
762 | PINCTRL_STATE_SLEEP); | ||
763 | if (IS_ERR(msp->pinctrl_sleep)) | ||
764 | dev_err(&pdev->dev, | ||
765 | "could not get MSP idlestate (%li)\n", | ||
766 | PTR_ERR(msp->pinctrl_def)); | ||
767 | } | ||
768 | |||
718 | return 0; | 769 | return 0; |
719 | } | 770 | } |
720 | 771 | ||
diff --git a/sound/soc/ux500/ux500_msp_i2s.h b/sound/soc/ux500/ux500_msp_i2s.h index 2d9136da9865..1311c0df7628 100644 --- a/sound/soc/ux500/ux500_msp_i2s.h +++ b/sound/soc/ux500/ux500_msp_i2s.h | |||
@@ -524,14 +524,18 @@ struct ux500_msp { | |||
524 | struct dma_chan *rx_pipeid; | 524 | struct dma_chan *rx_pipeid; |
525 | enum msp_state msp_state; | 525 | enum msp_state msp_state; |
526 | int (*transfer) (struct ux500_msp *msp, struct i2s_message *message); | 526 | int (*transfer) (struct ux500_msp *msp, struct i2s_message *message); |
527 | int (*plat_init) (void); | ||
528 | int (*plat_exit) (void); | ||
529 | struct timer_list notify_timer; | 527 | struct timer_list notify_timer; |
530 | int def_elem_len; | 528 | int def_elem_len; |
531 | unsigned int dir_busy; | 529 | unsigned int dir_busy; |
532 | int loopback_enable; | 530 | int loopback_enable; |
533 | u32 backup_regs[MAX_MSP_BACKUP_REGS]; | 531 | u32 backup_regs[MAX_MSP_BACKUP_REGS]; |
534 | unsigned int f_bitclk; | 532 | unsigned int f_bitclk; |
533 | /* Pin modes */ | ||
534 | struct pinctrl *pinctrl_p; | ||
535 | struct pinctrl_state *pinctrl_def; | ||
536 | struct pinctrl_state *pinctrl_sleep; | ||
537 | /* Reference Count */ | ||
538 | int pinctrl_rxtx_ref; | ||
535 | }; | 539 | }; |
536 | 540 | ||
537 | struct ux500_msp_dma_params { | 541 | struct ux500_msp_dma_params { |