diff options
31 files changed, 2695 insertions, 447 deletions
diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt index a5e63fa47dc5..c454e67f54bb 100644 --- a/Documentation/devicetree/bindings/sound/max98090.txt +++ b/Documentation/devicetree/bindings/sound/max98090.txt | |||
| @@ -4,7 +4,7 @@ This device supports I2C only. | |||
| 4 | 4 | ||
| 5 | Required properties: | 5 | Required properties: |
| 6 | 6 | ||
| 7 | - compatible : "maxim,max98090". | 7 | - compatible : "maxim,max98090" or "maxim,max98091". |
| 8 | 8 | ||
| 9 | - reg : The I2C address of the device. | 9 | - reg : The I2C address of the device. |
| 10 | 10 | ||
diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h new file mode 100644 index 000000000000..0a4e140315b6 --- /dev/null +++ b/arch/x86/include/asm/platform_sst_audio.h | |||
| @@ -0,0 +1,78 @@ | |||
| 1 | /* | ||
| 2 | * platform_sst_audio.h: sst audio platform data header file | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012-14 Intel Corporation | ||
| 5 | * Author: Jeeja KP <jeeja.kp@intel.com> | ||
| 6 | * Omair Mohammed Abdullah <omair.m.abdullah@intel.com> | ||
| 7 | * Vinod Koul ,vinod.koul@intel.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * as published by the Free Software Foundation; version 2 | ||
| 12 | * of the License. | ||
| 13 | */ | ||
| 14 | #ifndef _PLATFORM_SST_AUDIO_H_ | ||
| 15 | #define _PLATFORM_SST_AUDIO_H_ | ||
| 16 | |||
| 17 | #include <linux/sfi.h> | ||
| 18 | |||
| 19 | enum sst_audio_task_id_mrfld { | ||
| 20 | SST_TASK_ID_NONE = 0, | ||
| 21 | SST_TASK_ID_SBA = 1, | ||
| 22 | SST_TASK_ID_MEDIA = 3, | ||
| 23 | SST_TASK_ID_MAX = SST_TASK_ID_MEDIA, | ||
| 24 | }; | ||
| 25 | |||
| 26 | /* Device IDs for Merrifield are Pipe IDs, | ||
| 27 | * ref: DSP spec v0.75 */ | ||
| 28 | enum sst_audio_device_id_mrfld { | ||
| 29 | /* Output pipeline IDs */ | ||
| 30 | PIPE_ID_OUT_START = 0x0, | ||
| 31 | PIPE_CODEC_OUT0 = 0x2, | ||
| 32 | PIPE_CODEC_OUT1 = 0x3, | ||
| 33 | PIPE_SPROT_LOOP_OUT = 0x4, | ||
| 34 | PIPE_MEDIA_LOOP1_OUT = 0x5, | ||
| 35 | PIPE_MEDIA_LOOP2_OUT = 0x6, | ||
| 36 | PIPE_VOIP_OUT = 0xC, | ||
| 37 | PIPE_PCM0_OUT = 0xD, | ||
| 38 | PIPE_PCM1_OUT = 0xE, | ||
| 39 | PIPE_PCM2_OUT = 0xF, | ||
| 40 | PIPE_MEDIA0_OUT = 0x12, | ||
| 41 | PIPE_MEDIA1_OUT = 0x13, | ||
| 42 | /* Input Pipeline IDs */ | ||
| 43 | PIPE_ID_IN_START = 0x80, | ||
| 44 | PIPE_CODEC_IN0 = 0x82, | ||
| 45 | PIPE_CODEC_IN1 = 0x83, | ||
| 46 | PIPE_SPROT_LOOP_IN = 0x84, | ||
| 47 | PIPE_MEDIA_LOOP1_IN = 0x85, | ||
| 48 | PIPE_MEDIA_LOOP2_IN = 0x86, | ||
| 49 | PIPE_VOIP_IN = 0x8C, | ||
| 50 | PIPE_PCM0_IN = 0x8D, | ||
| 51 | PIPE_PCM1_IN = 0x8E, | ||
| 52 | PIPE_MEDIA0_IN = 0x8F, | ||
| 53 | PIPE_MEDIA1_IN = 0x90, | ||
| 54 | PIPE_MEDIA2_IN = 0x91, | ||
| 55 | PIPE_RSVD = 0xFF, | ||
| 56 | }; | ||
| 57 | |||
| 58 | /* The stream map for each platform consists of an array of the below | ||
| 59 | * stream map structure. | ||
| 60 | */ | ||
| 61 | struct sst_dev_stream_map { | ||
| 62 | u8 dev_num; /* device id */ | ||
| 63 | u8 subdev_num; /* substream */ | ||
| 64 | u8 direction; | ||
| 65 | u8 device_id; /* fw id */ | ||
| 66 | u8 task_id; /* fw task */ | ||
| 67 | u8 status; | ||
| 68 | }; | ||
| 69 | |||
| 70 | struct sst_platform_data { | ||
| 71 | /* Intel software platform id*/ | ||
| 72 | struct sst_dev_stream_map *pdev_strm_map; | ||
| 73 | unsigned int strm_map_size; | ||
| 74 | }; | ||
| 75 | |||
| 76 | int add_sst_platform_device(void); | ||
| 77 | #endif | ||
| 78 | |||
diff --git a/include/sound/rt286.h b/include/sound/rt286.h new file mode 100644 index 000000000000..eb773d1485f2 --- /dev/null +++ b/include/sound/rt286.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* | ||
| 2 | * linux/sound/rt286.h -- Platform data for RT286 | ||
| 3 | * | ||
| 4 | * Copyright 2013 Realtek Microelectronics | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #ifndef __LINUX_SND_RT286_H | ||
| 12 | #define __LINUX_SND_RT286_H | ||
| 13 | |||
| 14 | struct rt286_platform_data { | ||
| 15 | bool cbj_en; /*combo jack enable*/ | ||
| 16 | bool gpio2_en; /*GPIO2 enable*/ | ||
| 17 | }; | ||
| 18 | |||
| 19 | #endif | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e4a1d2aece36..4c7542571484 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
| @@ -75,6 +75,7 @@ config SND_SOC_ALL_CODECS | |||
| 75 | select SND_SOC_PCM3008 | 75 | select SND_SOC_PCM3008 |
| 76 | select SND_SOC_PCM512x_I2C if I2C | 76 | select SND_SOC_PCM512x_I2C if I2C |
| 77 | select SND_SOC_PCM512x_SPI if SPI_MASTER | 77 | select SND_SOC_PCM512x_SPI if SPI_MASTER |
| 78 | select SND_SOC_RT286 if I2C | ||
| 78 | select SND_SOC_RT5631 if I2C | 79 | select SND_SOC_RT5631 if I2C |
| 79 | select SND_SOC_RT5640 if I2C | 80 | select SND_SOC_RT5640 if I2C |
| 80 | select SND_SOC_RT5645 if I2C | 81 | select SND_SOC_RT5645 if I2C |
| @@ -455,6 +456,9 @@ config SND_SOC_RL6231 | |||
| 455 | default m if SND_SOC_RT5645=m | 456 | default m if SND_SOC_RT5645=m |
| 456 | default m if SND_SOC_RT5651=m | 457 | default m if SND_SOC_RT5651=m |
| 457 | 458 | ||
| 459 | config SND_SOC_RT286 | ||
| 460 | tristate | ||
| 461 | |||
| 458 | config SND_SOC_RT5631 | 462 | config SND_SOC_RT5631 |
| 459 | tristate | 463 | tristate |
| 460 | 464 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 97b80a1e03af..ade412e49bd0 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
| @@ -69,6 +69,7 @@ snd-soc-pcm512x-objs := pcm512x.o | |||
| 69 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | 69 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o |
| 70 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | 70 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o |
| 71 | snd-soc-rl6231-objs := rl6231.o | 71 | snd-soc-rl6231-objs := rl6231.o |
| 72 | snd-soc-rt286-objs := rt286.o | ||
| 72 | snd-soc-rt5631-objs := rt5631.o | 73 | snd-soc-rt5631-objs := rt5631.o |
| 73 | snd-soc-rt5640-objs := rt5640.o | 74 | snd-soc-rt5640-objs := rt5640.o |
| 74 | snd-soc-rt5645-objs := rt5645.o | 75 | snd-soc-rt5645-objs := rt5645.o |
| @@ -237,6 +238,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | |||
| 237 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | 238 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o |
| 238 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | 239 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o |
| 239 | obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o | 240 | obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o |
| 241 | obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o | ||
| 240 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 242 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
| 241 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 243 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
| 242 | obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o | 244 | obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index d97f1ce7ff7d..4a063fa88526 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
| @@ -26,10 +26,6 @@ | |||
| 26 | #include <sound/max98090.h> | 26 | #include <sound/max98090.h> |
| 27 | #include "max98090.h" | 27 | #include "max98090.h" |
| 28 | 28 | ||
| 29 | #define DEBUG | ||
| 30 | #define EXTMIC_METHOD | ||
| 31 | #define EXTMIC_METHOD_TEST | ||
| 32 | |||
| 33 | /* Allows for sparsely populated register maps */ | 29 | /* Allows for sparsely populated register maps */ |
| 34 | static struct reg_default max98090_reg[] = { | 30 | static struct reg_default max98090_reg[] = { |
| 35 | { 0x00, 0x00 }, /* 00 Software Reset */ | 31 | { 0x00, 0x00 }, /* 00 Software Reset */ |
| @@ -820,7 +816,6 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, | |||
| 820 | else | 816 | else |
| 821 | val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT; | 817 | val = (val & M98090_MIC_PA2EN_MASK) >> M98090_MIC_PA2EN_SHIFT; |
| 822 | 818 | ||
| 823 | |||
| 824 | if (val >= 1) { | 819 | if (val >= 1) { |
| 825 | if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) { | 820 | if (w->reg == M98090_REG_MIC1_INPUT_LEVEL) { |
| 826 | max98090->pa1en = val - 1; /* Update for volatile */ | 821 | max98090->pa1en = val - 1; /* Update for volatile */ |
| @@ -1140,7 +1135,6 @@ static const struct snd_kcontrol_new max98090_mixhprsel_mux = | |||
| 1140 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); | 1135 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); |
| 1141 | 1136 | ||
| 1142 | static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { | 1137 | static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { |
| 1143 | |||
| 1144 | SND_SOC_DAPM_INPUT("MIC1"), | 1138 | SND_SOC_DAPM_INPUT("MIC1"), |
| 1145 | SND_SOC_DAPM_INPUT("MIC2"), | 1139 | SND_SOC_DAPM_INPUT("MIC2"), |
| 1146 | SND_SOC_DAPM_INPUT("DMICL"), | 1140 | SND_SOC_DAPM_INPUT("DMICL"), |
| @@ -1304,7 +1298,6 @@ static const struct snd_soc_dapm_widget max98090_dapm_widgets[] = { | |||
| 1304 | }; | 1298 | }; |
| 1305 | 1299 | ||
| 1306 | static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { | 1300 | static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { |
| 1307 | |||
| 1308 | SND_SOC_DAPM_INPUT("DMIC3"), | 1301 | SND_SOC_DAPM_INPUT("DMIC3"), |
| 1309 | SND_SOC_DAPM_INPUT("DMIC4"), | 1302 | SND_SOC_DAPM_INPUT("DMIC4"), |
| 1310 | 1303 | ||
| @@ -1315,7 +1308,6 @@ static const struct snd_soc_dapm_widget max98091_dapm_widgets[] = { | |||
| 1315 | }; | 1308 | }; |
| 1316 | 1309 | ||
| 1317 | static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | 1310 | static const struct snd_soc_dapm_route max98090_dapm_routes[] = { |
| 1318 | |||
| 1319 | {"MIC1 Input", NULL, "MIC1"}, | 1311 | {"MIC1 Input", NULL, "MIC1"}, |
| 1320 | {"MIC2 Input", NULL, "MIC2"}, | 1312 | {"MIC2 Input", NULL, "MIC2"}, |
| 1321 | 1313 | ||
| @@ -1493,17 +1485,14 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
| 1493 | {"SPKR", NULL, "SPK Right Out"}, | 1485 | {"SPKR", NULL, "SPK Right Out"}, |
| 1494 | {"RCVL", NULL, "RCV Left Out"}, | 1486 | {"RCVL", NULL, "RCV Left Out"}, |
| 1495 | {"RCVR", NULL, "RCV Right Out"}, | 1487 | {"RCVR", NULL, "RCV Right Out"}, |
| 1496 | |||
| 1497 | }; | 1488 | }; |
| 1498 | 1489 | ||
| 1499 | static const struct snd_soc_dapm_route max98091_dapm_routes[] = { | 1490 | static const struct snd_soc_dapm_route max98091_dapm_routes[] = { |
| 1500 | |||
| 1501 | /* DMIC inputs */ | 1491 | /* DMIC inputs */ |
| 1502 | {"DMIC3", NULL, "DMIC3_ENA"}, | 1492 | {"DMIC3", NULL, "DMIC3_ENA"}, |
| 1503 | {"DMIC4", NULL, "DMIC4_ENA"}, | 1493 | {"DMIC4", NULL, "DMIC4_ENA"}, |
| 1504 | {"DMIC3", NULL, "AHPF"}, | 1494 | {"DMIC3", NULL, "AHPF"}, |
| 1505 | {"DMIC4", NULL, "AHPF"}, | 1495 | {"DMIC4", NULL, "AHPF"}, |
| 1506 | |||
| 1507 | }; | 1496 | }; |
| 1508 | 1497 | ||
| 1509 | static int max98090_add_widgets(struct snd_soc_codec *codec) | 1498 | static int max98090_add_widgets(struct snd_soc_codec *codec) |
| @@ -1531,7 +1520,6 @@ static int max98090_add_widgets(struct snd_soc_codec *codec) | |||
| 1531 | 1520 | ||
| 1532 | snd_soc_dapm_add_routes(dapm, max98091_dapm_routes, | 1521 | snd_soc_dapm_add_routes(dapm, max98091_dapm_routes, |
| 1533 | ARRAY_SIZE(max98091_dapm_routes)); | 1522 | ARRAY_SIZE(max98091_dapm_routes)); |
| 1534 | |||
| 1535 | } | 1523 | } |
| 1536 | 1524 | ||
| 1537 | return 0; | 1525 | return 0; |
| @@ -2212,22 +2200,11 @@ static struct snd_soc_dai_driver max98090_dai[] = { | |||
| 2212 | } | 2200 | } |
| 2213 | }; | 2201 | }; |
| 2214 | 2202 | ||
| 2215 | static void max98090_handle_pdata(struct snd_soc_codec *codec) | ||
| 2216 | { | ||
| 2217 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | ||
| 2218 | struct max98090_pdata *pdata = max98090->pdata; | ||
| 2219 | |||
| 2220 | if (!pdata) { | ||
| 2221 | dev_err(codec->dev, "No platform data\n"); | ||
| 2222 | return; | ||
| 2223 | } | ||
| 2224 | |||
| 2225 | } | ||
| 2226 | |||
| 2227 | static int max98090_probe(struct snd_soc_codec *codec) | 2203 | static int max98090_probe(struct snd_soc_codec *codec) |
| 2228 | { | 2204 | { |
| 2229 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 2205 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
| 2230 | struct max98090_cdata *cdata; | 2206 | struct max98090_cdata *cdata; |
| 2207 | enum max98090_type devtype; | ||
| 2231 | int ret = 0; | 2208 | int ret = 0; |
| 2232 | 2209 | ||
| 2233 | dev_dbg(codec->dev, "max98090_probe\n"); | 2210 | dev_dbg(codec->dev, "max98090_probe\n"); |
| @@ -2263,16 +2240,21 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
| 2263 | } | 2240 | } |
| 2264 | 2241 | ||
| 2265 | if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) { | 2242 | if ((ret >= M98090_REVA) && (ret <= M98090_REVA + 0x0f)) { |
| 2266 | max98090->devtype = MAX98090; | 2243 | devtype = MAX98090; |
| 2267 | dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret); | 2244 | dev_info(codec->dev, "MAX98090 REVID=0x%02x\n", ret); |
| 2268 | } else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) { | 2245 | } else if ((ret >= M98091_REVA) && (ret <= M98091_REVA + 0x0f)) { |
| 2269 | max98090->devtype = MAX98091; | 2246 | devtype = MAX98091; |
| 2270 | dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret); | 2247 | dev_info(codec->dev, "MAX98091 REVID=0x%02x\n", ret); |
| 2271 | } else { | 2248 | } else { |
| 2272 | max98090->devtype = MAX98090; | 2249 | devtype = MAX98090; |
| 2273 | dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret); | 2250 | dev_err(codec->dev, "Unrecognized revision 0x%02x\n", ret); |
| 2274 | } | 2251 | } |
| 2275 | 2252 | ||
| 2253 | if (max98090->devtype != devtype) { | ||
| 2254 | dev_warn(codec->dev, "Mismatch in DT specified CODEC type.\n"); | ||
| 2255 | max98090->devtype = devtype; | ||
| 2256 | } | ||
| 2257 | |||
| 2276 | max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; | 2258 | max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; |
| 2277 | 2259 | ||
| 2278 | INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); | 2260 | INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); |
| @@ -2317,8 +2299,6 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
| 2317 | snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, | 2299 | snd_soc_update_bits(codec, M98090_REG_MIC_BIAS_VOLTAGE, |
| 2318 | M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); | 2300 | M98090_MBVSEL_MASK, M98090_MBVSEL_2V8); |
| 2319 | 2301 | ||
| 2320 | max98090_handle_pdata(codec); | ||
| 2321 | |||
| 2322 | max98090_add_widgets(codec); | 2302 | max98090_add_widgets(codec); |
| 2323 | 2303 | ||
| 2324 | err_access: | 2304 | err_access: |
| @@ -2428,7 +2408,7 @@ static int max98090_runtime_suspend(struct device *dev) | |||
| 2428 | } | 2408 | } |
| 2429 | #endif | 2409 | #endif |
| 2430 | 2410 | ||
| 2431 | #ifdef CONFIG_PM | 2411 | #ifdef CONFIG_PM_SLEEP |
| 2432 | static int max98090_resume(struct device *dev) | 2412 | static int max98090_resume(struct device *dev) |
| 2433 | { | 2413 | { |
| 2434 | struct max98090_priv *max98090 = dev_get_drvdata(dev); | 2414 | struct max98090_priv *max98090 = dev_get_drvdata(dev); |
| @@ -2460,12 +2440,14 @@ static const struct dev_pm_ops max98090_pm = { | |||
| 2460 | 2440 | ||
| 2461 | static const struct i2c_device_id max98090_i2c_id[] = { | 2441 | static const struct i2c_device_id max98090_i2c_id[] = { |
| 2462 | { "max98090", MAX98090 }, | 2442 | { "max98090", MAX98090 }, |
| 2443 | { "max98091", MAX98091 }, | ||
| 2463 | { } | 2444 | { } |
| 2464 | }; | 2445 | }; |
| 2465 | MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); | 2446 | MODULE_DEVICE_TABLE(i2c, max98090_i2c_id); |
| 2466 | 2447 | ||
| 2467 | static const struct of_device_id max98090_of_match[] = { | 2448 | static const struct of_device_id max98090_of_match[] = { |
| 2468 | { .compatible = "maxim,max98090", }, | 2449 | { .compatible = "maxim,max98090", }, |
| 2450 | { .compatible = "maxim,max98091", }, | ||
| 2469 | { } | 2451 | { } |
| 2470 | }; | 2452 | }; |
| 2471 | MODULE_DEVICE_TABLE(of, max98090_of_match); | 2453 | MODULE_DEVICE_TABLE(of, max98090_of_match); |
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 9965277b595a..388f90a597fa 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c | |||
| @@ -766,11 +766,11 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) | |||
| 766 | 766 | ||
| 767 | ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); | 767 | ret = of_property_read_u32(np, "adc-port", &priv->adc_ssi_port); |
| 768 | if (ret) | 768 | if (ret) |
| 769 | return ret; | 769 | goto out; |
| 770 | 770 | ||
| 771 | ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); | 771 | ret = of_property_read_u32(np, "dac-port", &priv->dac_ssi_port); |
| 772 | if (ret) | 772 | if (ret) |
| 773 | return ret; | 773 | goto out; |
| 774 | } | 774 | } |
| 775 | 775 | ||
| 776 | dev_set_drvdata(&pdev->dev, priv); | 776 | dev_set_drvdata(&pdev->dev, priv); |
| @@ -783,6 +783,8 @@ static int __init mc13783_codec_probe(struct platform_device *pdev) | |||
| 783 | ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783, | 783 | ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_mc13783, |
| 784 | mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async)); | 784 | mc13783_dai_async, ARRAY_SIZE(mc13783_dai_async)); |
| 785 | 785 | ||
| 786 | out: | ||
| 787 | of_node_put(np); | ||
| 786 | return ret; | 788 | return ret; |
| 787 | } | 789 | } |
| 788 | 790 | ||
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c new file mode 100644 index 000000000000..218f86efd196 --- /dev/null +++ b/sound/soc/codecs/rt286.c | |||
| @@ -0,0 +1,1224 @@ | |||
| 1 | /* | ||
| 2 | * rt286.c -- RT286 ALSA SoC audio codec driver | ||
| 3 | * | ||
| 4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
| 5 | * Author: Bard Liao <bardliao@realtek.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/init.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/pm.h> | ||
| 17 | #include <linux/i2c.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/spi/spi.h> | ||
| 20 | #include <linux/acpi.h> | ||
| 21 | #include <sound/core.h> | ||
| 22 | #include <sound/pcm.h> | ||
| 23 | #include <sound/pcm_params.h> | ||
| 24 | #include <sound/soc.h> | ||
| 25 | #include <sound/soc-dapm.h> | ||
| 26 | #include <sound/initval.h> | ||
| 27 | #include <sound/tlv.h> | ||
| 28 | #include <sound/jack.h> | ||
| 29 | #include <linux/workqueue.h> | ||
| 30 | #include <sound/rt286.h> | ||
| 31 | #include <sound/hda_verbs.h> | ||
| 32 | |||
| 33 | #include "rt286.h" | ||
| 34 | |||
| 35 | #define RT286_VENDOR_ID 0x10ec0286 | ||
| 36 | |||
| 37 | struct rt286_priv { | ||
| 38 | struct regmap *regmap; | ||
| 39 | struct snd_soc_codec *codec; | ||
| 40 | struct rt286_platform_data pdata; | ||
| 41 | struct i2c_client *i2c; | ||
| 42 | struct snd_soc_jack *jack; | ||
| 43 | struct delayed_work jack_detect_work; | ||
| 44 | int sys_clk; | ||
| 45 | struct reg_default *index_cache; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static struct reg_default rt286_index_def[] = { | ||
| 49 | { 0x01, 0xaaaa }, | ||
| 50 | { 0x02, 0x8aaa }, | ||
| 51 | { 0x03, 0x0002 }, | ||
| 52 | { 0x04, 0xaf01 }, | ||
| 53 | { 0x08, 0x000d }, | ||
| 54 | { 0x09, 0xd810 }, | ||
| 55 | { 0x0a, 0x0060 }, | ||
| 56 | { 0x0b, 0x0000 }, | ||
| 57 | { 0x0d, 0x2800 }, | ||
| 58 | { 0x0f, 0x0000 }, | ||
| 59 | { 0x19, 0x0a17 }, | ||
| 60 | { 0x20, 0x0020 }, | ||
| 61 | { 0x33, 0x0208 }, | ||
| 62 | { 0x49, 0x0004 }, | ||
| 63 | { 0x4f, 0x50e9 }, | ||
| 64 | { 0x50, 0x2c00 }, | ||
| 65 | { 0x63, 0x2902 }, | ||
| 66 | { 0x67, 0x1111 }, | ||
| 67 | { 0x68, 0x1016 }, | ||
| 68 | { 0x69, 0x273f }, | ||
| 69 | }; | ||
| 70 | #define INDEX_CACHE_SIZE ARRAY_SIZE(rt286_index_def) | ||
| 71 | |||
| 72 | static const struct reg_default rt286_reg[] = { | ||
| 73 | { 0x00170500, 0x00000400 }, | ||
| 74 | { 0x00220000, 0x00000031 }, | ||
| 75 | { 0x00239000, 0x0000007f }, | ||
| 76 | { 0x0023a000, 0x0000007f }, | ||
| 77 | { 0x00270500, 0x00000400 }, | ||
| 78 | { 0x00370500, 0x00000400 }, | ||
| 79 | { 0x00870500, 0x00000400 }, | ||
| 80 | { 0x00920000, 0x00000031 }, | ||
| 81 | { 0x00935000, 0x000000c3 }, | ||
| 82 | { 0x00936000, 0x000000c3 }, | ||
| 83 | { 0x00970500, 0x00000400 }, | ||
| 84 | { 0x00b37000, 0x00000097 }, | ||
| 85 | { 0x00b37200, 0x00000097 }, | ||
| 86 | { 0x00b37300, 0x00000097 }, | ||
| 87 | { 0x00c37000, 0x00000000 }, | ||
| 88 | { 0x00c37100, 0x00000080 }, | ||
| 89 | { 0x01270500, 0x00000400 }, | ||
| 90 | { 0x01370500, 0x00000400 }, | ||
| 91 | { 0x01371f00, 0x411111f0 }, | ||
| 92 | { 0x01439000, 0x00000080 }, | ||
| 93 | { 0x0143a000, 0x00000080 }, | ||
| 94 | { 0x01470700, 0x00000000 }, | ||
| 95 | { 0x01470500, 0x00000400 }, | ||
| 96 | { 0x01470c00, 0x00000000 }, | ||
| 97 | { 0x01470100, 0x00000000 }, | ||
| 98 | { 0x01837000, 0x00000000 }, | ||
| 99 | { 0x01870500, 0x00000400 }, | ||
| 100 | { 0x02050000, 0x00000000 }, | ||
| 101 | { 0x02139000, 0x00000080 }, | ||
| 102 | { 0x0213a000, 0x00000080 }, | ||
| 103 | { 0x02170100, 0x00000000 }, | ||
| 104 | { 0x02170500, 0x00000400 }, | ||
| 105 | { 0x02170700, 0x00000000 }, | ||
| 106 | { 0x02270100, 0x00000000 }, | ||
| 107 | { 0x02370100, 0x00000000 }, | ||
| 108 | { 0x02040000, 0x00004002 }, | ||
| 109 | { 0x01870700, 0x00000020 }, | ||
| 110 | { 0x00830000, 0x000000c3 }, | ||
| 111 | { 0x00930000, 0x000000c3 }, | ||
| 112 | { 0x01270700, 0x00000000 }, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static bool rt286_volatile_register(struct device *dev, unsigned int reg) | ||
| 116 | { | ||
| 117 | switch (reg) { | ||
| 118 | case 0 ... 0xff: | ||
| 119 | case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): | ||
| 120 | case RT286_GET_HP_SENSE: | ||
| 121 | case RT286_GET_MIC1_SENSE: | ||
| 122 | case RT286_PROC_COEF: | ||
| 123 | return true; | ||
| 124 | default: | ||
| 125 | return false; | ||
| 126 | } | ||
| 127 | |||
| 128 | |||
| 129 | } | ||
| 130 | |||
| 131 | static bool rt286_readable_register(struct device *dev, unsigned int reg) | ||
| 132 | { | ||
| 133 | switch (reg) { | ||
| 134 | case 0 ... 0xff: | ||
| 135 | case RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): | ||
| 136 | case RT286_GET_HP_SENSE: | ||
| 137 | case RT286_GET_MIC1_SENSE: | ||
| 138 | case RT286_SET_AUDIO_POWER: | ||
| 139 | case RT286_SET_HPO_POWER: | ||
| 140 | case RT286_SET_SPK_POWER: | ||
| 141 | case RT286_SET_DMIC1_POWER: | ||
| 142 | case RT286_SPK_MUX: | ||
| 143 | case RT286_HPO_MUX: | ||
| 144 | case RT286_ADC0_MUX: | ||
| 145 | case RT286_ADC1_MUX: | ||
| 146 | case RT286_SET_MIC1: | ||
| 147 | case RT286_SET_PIN_HPO: | ||
| 148 | case RT286_SET_PIN_SPK: | ||
| 149 | case RT286_SET_PIN_DMIC1: | ||
| 150 | case RT286_SPK_EAPD: | ||
| 151 | case RT286_SET_AMP_GAIN_HPO: | ||
| 152 | case RT286_SET_DMIC2_DEFAULT: | ||
| 153 | case RT286_DACL_GAIN: | ||
| 154 | case RT286_DACR_GAIN: | ||
| 155 | case RT286_ADCL_GAIN: | ||
| 156 | case RT286_ADCR_GAIN: | ||
| 157 | case RT286_MIC_GAIN: | ||
| 158 | case RT286_SPOL_GAIN: | ||
| 159 | case RT286_SPOR_GAIN: | ||
| 160 | case RT286_HPOL_GAIN: | ||
| 161 | case RT286_HPOR_GAIN: | ||
| 162 | case RT286_F_DAC_SWITCH: | ||
| 163 | case RT286_F_RECMIX_SWITCH: | ||
| 164 | case RT286_REC_MIC_SWITCH: | ||
| 165 | case RT286_REC_I2S_SWITCH: | ||
| 166 | case RT286_REC_LINE_SWITCH: | ||
| 167 | case RT286_REC_BEEP_SWITCH: | ||
| 168 | case RT286_DAC_FORMAT: | ||
| 169 | case RT286_ADC_FORMAT: | ||
| 170 | case RT286_COEF_INDEX: | ||
| 171 | case RT286_PROC_COEF: | ||
| 172 | case RT286_SET_AMP_GAIN_ADC_IN1: | ||
| 173 | case RT286_SET_AMP_GAIN_ADC_IN2: | ||
| 174 | case RT286_SET_POWER(RT286_DAC_OUT1): | ||
| 175 | case RT286_SET_POWER(RT286_DAC_OUT2): | ||
| 176 | case RT286_SET_POWER(RT286_ADC_IN1): | ||
| 177 | case RT286_SET_POWER(RT286_ADC_IN2): | ||
| 178 | case RT286_SET_POWER(RT286_DMIC2): | ||
| 179 | case RT286_SET_POWER(RT286_MIC1): | ||
| 180 | return true; | ||
| 181 | default: | ||
| 182 | return false; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | ||
| 187 | { | ||
| 188 | struct i2c_client *client = context; | ||
| 189 | struct rt286_priv *rt286 = i2c_get_clientdata(client); | ||
| 190 | u8 data[4]; | ||
| 191 | int ret, i; | ||
| 192 | |||
| 193 | /*handle index registers*/ | ||
| 194 | if (reg <= 0xff) { | ||
| 195 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | ||
| 196 | reg = RT286_PROC_COEF; | ||
| 197 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | ||
| 198 | if (reg == rt286->index_cache[i].reg) { | ||
| 199 | rt286->index_cache[i].def = value; | ||
| 200 | break; | ||
| 201 | } | ||
| 202 | |||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | data[0] = (reg >> 24) & 0xff; | ||
| 207 | data[1] = (reg >> 16) & 0xff; | ||
| 208 | /* | ||
| 209 | * 4 bit VID: reg should be 0 | ||
| 210 | * 12 bit VID: value should be 0 | ||
| 211 | * So we use an OR operator to handle it rather than use if condition. | ||
| 212 | */ | ||
| 213 | data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff); | ||
| 214 | data[3] = value & 0xff; | ||
| 215 | |||
| 216 | ret = i2c_master_send(client, data, 4); | ||
| 217 | |||
| 218 | if (ret == 4) | ||
| 219 | return 0; | ||
| 220 | else | ||
| 221 | pr_err("ret=%d\n", ret); | ||
| 222 | if (ret < 0) | ||
| 223 | return ret; | ||
| 224 | else | ||
| 225 | return -EIO; | ||
| 226 | } | ||
| 227 | |||
| 228 | static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) | ||
| 229 | { | ||
| 230 | struct i2c_client *client = context; | ||
| 231 | struct i2c_msg xfer[2]; | ||
| 232 | int ret; | ||
| 233 | __be32 be_reg; | ||
| 234 | unsigned int index, vid, buf = 0x0; | ||
| 235 | |||
| 236 | /*handle index registers*/ | ||
| 237 | if (reg <= 0xff) { | ||
| 238 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | ||
| 239 | reg = RT286_PROC_COEF; | ||
| 240 | } | ||
| 241 | |||
| 242 | reg = reg | 0x80000; | ||
| 243 | vid = (reg >> 8) & 0xfff; | ||
| 244 | |||
| 245 | if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) { | ||
| 246 | index = (reg >> 8) & 0xf; | ||
| 247 | reg = (reg & ~0xf0f) | index; | ||
| 248 | } | ||
| 249 | be_reg = cpu_to_be32(reg); | ||
| 250 | |||
| 251 | /* Write register */ | ||
| 252 | xfer[0].addr = client->addr; | ||
| 253 | xfer[0].flags = 0; | ||
| 254 | xfer[0].len = 4; | ||
| 255 | xfer[0].buf = (u8 *)&be_reg; | ||
| 256 | |||
| 257 | /* Read data */ | ||
| 258 | xfer[1].addr = client->addr; | ||
| 259 | xfer[1].flags = I2C_M_RD; | ||
| 260 | xfer[1].len = 4; | ||
| 261 | xfer[1].buf = (u8 *)&buf; | ||
| 262 | |||
| 263 | ret = i2c_transfer(client->adapter, xfer, 2); | ||
| 264 | if (ret < 0) | ||
| 265 | return ret; | ||
| 266 | else if (ret != 2) | ||
| 267 | return -EIO; | ||
| 268 | |||
| 269 | *value = be32_to_cpu(buf); | ||
| 270 | |||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | static void rt286_index_sync(struct snd_soc_codec *codec) | ||
| 275 | { | ||
| 276 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 277 | int i; | ||
| 278 | |||
| 279 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | ||
| 280 | snd_soc_write(codec, rt286->index_cache[i].reg, | ||
| 281 | rt286->index_cache[i].def); | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 285 | static int rt286_support_power_controls[] = { | ||
| 286 | RT286_DAC_OUT1, | ||
| 287 | RT286_DAC_OUT2, | ||
| 288 | RT286_ADC_IN1, | ||
| 289 | RT286_ADC_IN2, | ||
| 290 | RT286_MIC1, | ||
| 291 | RT286_DMIC1, | ||
| 292 | RT286_DMIC2, | ||
| 293 | RT286_SPK_OUT, | ||
| 294 | RT286_HP_OUT, | ||
| 295 | }; | ||
| 296 | #define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls) | ||
| 297 | |||
| 298 | static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic) | ||
| 299 | { | ||
| 300 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 301 | unsigned int val, buf; | ||
| 302 | int i; | ||
| 303 | |||
| 304 | *hp = false; | ||
| 305 | *mic = false; | ||
| 306 | |||
| 307 | if (rt286->pdata.cbj_en) { | ||
| 308 | buf = snd_soc_read(codec, RT286_GET_HP_SENSE); | ||
| 309 | *hp = buf & 0x80000000; | ||
| 310 | if (*hp) { | ||
| 311 | /* power on HV,VERF */ | ||
| 312 | snd_soc_update_bits(codec, | ||
| 313 | RT286_POWER_CTRL1, 0x1001, 0x0); | ||
| 314 | /* power LDO1 */ | ||
| 315 | snd_soc_update_bits(codec, | ||
| 316 | RT286_POWER_CTRL2, 0x4, 0x4); | ||
| 317 | snd_soc_write(codec, RT286_SET_MIC1, 0x24); | ||
| 318 | val = snd_soc_read(codec, RT286_CBJ_CTRL2); | ||
| 319 | |||
| 320 | msleep(200); | ||
| 321 | i = 40; | ||
| 322 | while (((val & 0x0800) == 0) && (i > 0)) { | ||
| 323 | val = snd_soc_read(codec, | ||
| 324 | RT286_CBJ_CTRL2); | ||
| 325 | i--; | ||
| 326 | msleep(20); | ||
| 327 | } | ||
| 328 | |||
| 329 | if (0x0400 == (val & 0x0700)) { | ||
| 330 | *mic = false; | ||
| 331 | |||
| 332 | snd_soc_write(codec, | ||
| 333 | RT286_SET_MIC1, 0x20); | ||
| 334 | /* power off HV,VERF */ | ||
| 335 | snd_soc_update_bits(codec, | ||
| 336 | RT286_POWER_CTRL1, 0x1001, 0x1001); | ||
| 337 | snd_soc_update_bits(codec, | ||
| 338 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | ||
| 339 | snd_soc_update_bits(codec, | ||
| 340 | RT286_CBJ_CTRL1, 0x0030, 0x0000); | ||
| 341 | snd_soc_update_bits(codec, | ||
| 342 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | ||
| 343 | } else if ((0x0200 == (val & 0x0700)) || | ||
| 344 | (0x0100 == (val & 0x0700))) { | ||
| 345 | *mic = true; | ||
| 346 | snd_soc_update_bits(codec, | ||
| 347 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | ||
| 348 | snd_soc_update_bits(codec, | ||
| 349 | RT286_CBJ_CTRL1, 0x0030, 0x0020); | ||
| 350 | snd_soc_update_bits(codec, | ||
| 351 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | ||
| 352 | } else { | ||
| 353 | *mic = false; | ||
| 354 | } | ||
| 355 | |||
| 356 | snd_soc_update_bits(codec, | ||
| 357 | RT286_MISC_CTRL1, | ||
| 358 | 0x0060, 0x0000); | ||
| 359 | } else { | ||
| 360 | snd_soc_update_bits(codec, | ||
| 361 | RT286_MISC_CTRL1, | ||
| 362 | 0x0060, 0x0020); | ||
| 363 | snd_soc_update_bits(codec, | ||
| 364 | RT286_A_BIAS_CTRL3, | ||
| 365 | 0xc000, 0x8000); | ||
| 366 | snd_soc_update_bits(codec, | ||
| 367 | RT286_CBJ_CTRL1, | ||
| 368 | 0x0030, 0x0020); | ||
| 369 | snd_soc_update_bits(codec, | ||
| 370 | RT286_A_BIAS_CTRL2, | ||
| 371 | 0xc000, 0x8000); | ||
| 372 | |||
| 373 | *mic = false; | ||
| 374 | } | ||
| 375 | } else { | ||
| 376 | buf = snd_soc_read(codec, RT286_GET_HP_SENSE); | ||
| 377 | *hp = buf & 0x80000000; | ||
| 378 | buf = snd_soc_read(codec, RT286_GET_MIC1_SENSE); | ||
| 379 | *mic = buf & 0x80000000; | ||
| 380 | } | ||
| 381 | |||
| 382 | return 0; | ||
| 383 | } | ||
| 384 | |||
| 385 | static void rt286_jack_detect_work(struct work_struct *work) | ||
| 386 | { | ||
| 387 | struct rt286_priv *rt286 = | ||
| 388 | container_of(work, struct rt286_priv, jack_detect_work.work); | ||
| 389 | int status = 0; | ||
| 390 | bool hp = false; | ||
| 391 | bool mic = false; | ||
| 392 | |||
| 393 | rt286_jack_detect(rt286->codec, &hp, &mic); | ||
| 394 | |||
| 395 | if (hp == true) | ||
| 396 | status |= SND_JACK_HEADPHONE; | ||
| 397 | |||
| 398 | if (mic == true) | ||
| 399 | status |= SND_JACK_MICROPHONE; | ||
| 400 | |||
| 401 | snd_soc_jack_report(rt286->jack, status, | ||
| 402 | SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); | ||
| 403 | } | ||
| 404 | |||
| 405 | int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | ||
| 406 | { | ||
| 407 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 408 | |||
| 409 | rt286->jack = jack; | ||
| 410 | |||
| 411 | /* Send an initial empty report */ | ||
| 412 | snd_soc_jack_report(rt286->jack, 0, | ||
| 413 | SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); | ||
| 414 | |||
| 415 | return 0; | ||
| 416 | } | ||
| 417 | EXPORT_SYMBOL_GPL(rt286_mic_detect); | ||
| 418 | |||
| 419 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); | ||
| 420 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); | ||
| 421 | |||
| 422 | static const struct snd_kcontrol_new rt286_snd_controls[] = { | ||
| 423 | SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT286_DACL_GAIN, | ||
| 424 | RT286_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv), | ||
| 425 | SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT286_ADCL_GAIN, | ||
| 426 | RT286_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), | ||
| 427 | SOC_SINGLE_TLV("AMIC Volume", RT286_MIC_GAIN, | ||
| 428 | 0, 0x3, 0, mic_vol_tlv), | ||
| 429 | SOC_DOUBLE_R("Speaker Playback Switch", RT286_SPOL_GAIN, | ||
| 430 | RT286_SPOR_GAIN, RT286_MUTE_SFT, 1, 1), | ||
| 431 | }; | ||
| 432 | |||
| 433 | /* Digital Mixer */ | ||
| 434 | static const struct snd_kcontrol_new rt286_front_mix[] = { | ||
| 435 | SOC_DAPM_SINGLE("DAC Switch", RT286_F_DAC_SWITCH, | ||
| 436 | RT286_MUTE_SFT, 1, 1), | ||
| 437 | SOC_DAPM_SINGLE("RECMIX Switch", RT286_F_RECMIX_SWITCH, | ||
| 438 | RT286_MUTE_SFT, 1, 1), | ||
| 439 | }; | ||
| 440 | |||
| 441 | /* Analog Input Mixer */ | ||
| 442 | static const struct snd_kcontrol_new rt286_rec_mix[] = { | ||
| 443 | SOC_DAPM_SINGLE("Mic1 Switch", RT286_REC_MIC_SWITCH, | ||
| 444 | RT286_MUTE_SFT, 1, 1), | ||
| 445 | SOC_DAPM_SINGLE("I2S Switch", RT286_REC_I2S_SWITCH, | ||
| 446 | RT286_MUTE_SFT, 1, 1), | ||
| 447 | SOC_DAPM_SINGLE("Line1 Switch", RT286_REC_LINE_SWITCH, | ||
| 448 | RT286_MUTE_SFT, 1, 1), | ||
| 449 | SOC_DAPM_SINGLE("Beep Switch", RT286_REC_BEEP_SWITCH, | ||
| 450 | RT286_MUTE_SFT, 1, 1), | ||
| 451 | }; | ||
| 452 | |||
| 453 | static const struct snd_kcontrol_new spo_enable_control = | ||
| 454 | SOC_DAPM_SINGLE("Switch", RT286_SET_PIN_SPK, | ||
| 455 | RT286_SET_PIN_SFT, 1, 0); | ||
| 456 | |||
| 457 | static const struct snd_kcontrol_new hpol_enable_control = | ||
| 458 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOL_GAIN, | ||
| 459 | RT286_MUTE_SFT, 1, 1); | ||
| 460 | |||
| 461 | static const struct snd_kcontrol_new hpor_enable_control = | ||
| 462 | SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT286_HPOR_GAIN, | ||
| 463 | RT286_MUTE_SFT, 1, 1); | ||
| 464 | |||
| 465 | /* ADC0 source */ | ||
| 466 | static const char * const rt286_adc_src[] = { | ||
| 467 | "Mic", "RECMIX", "Dmic" | ||
| 468 | }; | ||
| 469 | |||
| 470 | static const int rt286_adc_values[] = { | ||
| 471 | 0, 4, 5, | ||
| 472 | }; | ||
| 473 | |||
| 474 | static SOC_VALUE_ENUM_SINGLE_DECL( | ||
| 475 | rt286_adc0_enum, RT286_ADC0_MUX, RT286_ADC_SEL_SFT, | ||
| 476 | RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values); | ||
| 477 | |||
| 478 | static const struct snd_kcontrol_new rt286_adc0_mux = | ||
| 479 | SOC_DAPM_ENUM("ADC 0 source", rt286_adc0_enum); | ||
| 480 | |||
| 481 | static SOC_VALUE_ENUM_SINGLE_DECL( | ||
| 482 | rt286_adc1_enum, RT286_ADC1_MUX, RT286_ADC_SEL_SFT, | ||
| 483 | RT286_ADC_SEL_MASK, rt286_adc_src, rt286_adc_values); | ||
| 484 | |||
| 485 | static const struct snd_kcontrol_new rt286_adc1_mux = | ||
| 486 | SOC_DAPM_ENUM("ADC 1 source", rt286_adc1_enum); | ||
| 487 | |||
| 488 | static const char * const rt286_dac_src[] = { | ||
| 489 | "Front", "Surround" | ||
| 490 | }; | ||
| 491 | /* HP-OUT source */ | ||
| 492 | static SOC_ENUM_SINGLE_DECL(rt286_hpo_enum, RT286_HPO_MUX, | ||
| 493 | 0, rt286_dac_src); | ||
| 494 | |||
| 495 | static const struct snd_kcontrol_new rt286_hpo_mux = | ||
| 496 | SOC_DAPM_ENUM("HPO source", rt286_hpo_enum); | ||
| 497 | |||
| 498 | /* SPK-OUT source */ | ||
| 499 | static SOC_ENUM_SINGLE_DECL(rt286_spo_enum, RT286_SPK_MUX, | ||
| 500 | 0, rt286_dac_src); | ||
| 501 | |||
| 502 | static const struct snd_kcontrol_new rt286_spo_mux = | ||
| 503 | SOC_DAPM_ENUM("SPO source", rt286_spo_enum); | ||
| 504 | |||
| 505 | static int rt286_spk_event(struct snd_soc_dapm_widget *w, | ||
| 506 | struct snd_kcontrol *kcontrol, int event) | ||
| 507 | { | ||
| 508 | struct snd_soc_codec *codec = w->codec; | ||
| 509 | |||
| 510 | switch (event) { | ||
| 511 | case SND_SOC_DAPM_POST_PMU: | ||
| 512 | snd_soc_write(codec, | ||
| 513 | RT286_SPK_EAPD, RT286_SET_EAPD_HIGH); | ||
| 514 | break; | ||
| 515 | case SND_SOC_DAPM_PRE_PMD: | ||
| 516 | snd_soc_write(codec, | ||
| 517 | RT286_SPK_EAPD, RT286_SET_EAPD_LOW); | ||
| 518 | break; | ||
| 519 | |||
| 520 | default: | ||
| 521 | return 0; | ||
| 522 | } | ||
| 523 | |||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | static int rt286_set_dmic1_event(struct snd_soc_dapm_widget *w, | ||
| 528 | struct snd_kcontrol *kcontrol, int event) | ||
| 529 | { | ||
| 530 | struct snd_soc_codec *codec = w->codec; | ||
| 531 | |||
| 532 | switch (event) { | ||
| 533 | case SND_SOC_DAPM_POST_PMU: | ||
| 534 | snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0x20); | ||
| 535 | break; | ||
| 536 | case SND_SOC_DAPM_PRE_PMD: | ||
| 537 | snd_soc_write(codec, RT286_SET_PIN_DMIC1, 0); | ||
| 538 | break; | ||
| 539 | default: | ||
| 540 | return 0; | ||
| 541 | } | ||
| 542 | |||
| 543 | return 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | static int rt286_adc_event(struct snd_soc_dapm_widget *w, | ||
| 547 | struct snd_kcontrol *kcontrol, int event) | ||
| 548 | { | ||
| 549 | struct snd_soc_codec *codec = w->codec; | ||
| 550 | unsigned int nid; | ||
| 551 | |||
| 552 | nid = (w->reg >> 20) & 0xff; | ||
| 553 | |||
| 554 | switch (event) { | ||
| 555 | case SND_SOC_DAPM_POST_PMU: | ||
| 556 | snd_soc_update_bits(codec, | ||
| 557 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), | ||
| 558 | 0x7080, 0x7000); | ||
| 559 | break; | ||
| 560 | case SND_SOC_DAPM_PRE_PMD: | ||
| 561 | snd_soc_update_bits(codec, | ||
| 562 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), | ||
| 563 | 0x7080, 0x7080); | ||
| 564 | break; | ||
| 565 | default: | ||
| 566 | return 0; | ||
| 567 | } | ||
| 568 | |||
| 569 | return 0; | ||
| 570 | } | ||
| 571 | |||
| 572 | static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { | ||
| 573 | /* Input Lines */ | ||
| 574 | SND_SOC_DAPM_INPUT("DMIC1 Pin"), | ||
| 575 | SND_SOC_DAPM_INPUT("DMIC2 Pin"), | ||
| 576 | SND_SOC_DAPM_INPUT("MIC1"), | ||
| 577 | SND_SOC_DAPM_INPUT("LINE1"), | ||
| 578 | SND_SOC_DAPM_INPUT("Beep"), | ||
| 579 | |||
| 580 | /* DMIC */ | ||
| 581 | SND_SOC_DAPM_PGA_E("DMIC1", RT286_SET_POWER(RT286_DMIC1), 0, 1, | ||
| 582 | NULL, 0, rt286_set_dmic1_event, | ||
| 583 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
| 584 | SND_SOC_DAPM_PGA("DMIC2", RT286_SET_POWER(RT286_DMIC2), 0, 1, | ||
| 585 | NULL, 0), | ||
| 586 | SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM, | ||
| 587 | 0, 0, NULL, 0), | ||
| 588 | |||
| 589 | /* REC Mixer */ | ||
| 590 | SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0, | ||
| 591 | rt286_rec_mix, ARRAY_SIZE(rt286_rec_mix)), | ||
| 592 | |||
| 593 | /* ADCs */ | ||
| 594 | SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0), | ||
| 595 | SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), | ||
| 596 | |||
| 597 | /* ADC Mux */ | ||
| 598 | SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT286_SET_POWER(RT286_ADC_IN1), 0, 1, | ||
| 599 | &rt286_adc0_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | | ||
| 600 | SND_SOC_DAPM_POST_PMU), | ||
| 601 | SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT286_SET_POWER(RT286_ADC_IN2), 0, 1, | ||
| 602 | &rt286_adc1_mux, rt286_adc_event, SND_SOC_DAPM_PRE_PMD | | ||
| 603 | SND_SOC_DAPM_POST_PMU), | ||
| 604 | |||
| 605 | /* Audio Interface */ | ||
| 606 | SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
| 607 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
| 608 | SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), | ||
| 609 | SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
| 610 | |||
| 611 | /* Output Side */ | ||
| 612 | /* DACs */ | ||
| 613 | SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0), | ||
| 614 | SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0), | ||
| 615 | |||
| 616 | /* Output Mux */ | ||
| 617 | SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt286_spo_mux), | ||
| 618 | SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt286_hpo_mux), | ||
| 619 | |||
| 620 | SND_SOC_DAPM_SUPPLY("HP Power", RT286_SET_PIN_HPO, | ||
| 621 | RT286_SET_PIN_SFT, 0, NULL, 0), | ||
| 622 | |||
| 623 | /* Output Mixer */ | ||
| 624 | SND_SOC_DAPM_MIXER("Front", RT286_SET_POWER(RT286_DAC_OUT1), 0, 1, | ||
| 625 | rt286_front_mix, ARRAY_SIZE(rt286_front_mix)), | ||
| 626 | SND_SOC_DAPM_PGA("Surround", RT286_SET_POWER(RT286_DAC_OUT2), 0, 1, | ||
| 627 | NULL, 0), | ||
| 628 | |||
| 629 | /* Output Pga */ | ||
| 630 | SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0, | ||
| 631 | &spo_enable_control, rt286_spk_event, | ||
| 632 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
| 633 | SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0, | ||
| 634 | &hpol_enable_control), | ||
| 635 | SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0, | ||
| 636 | &hpor_enable_control), | ||
| 637 | |||
| 638 | /* Output Lines */ | ||
| 639 | SND_SOC_DAPM_OUTPUT("SPOL"), | ||
| 640 | SND_SOC_DAPM_OUTPUT("SPOR"), | ||
| 641 | SND_SOC_DAPM_OUTPUT("HPO Pin"), | ||
| 642 | SND_SOC_DAPM_OUTPUT("SPDIF"), | ||
| 643 | }; | ||
| 644 | |||
| 645 | static const struct snd_soc_dapm_route rt286_dapm_routes[] = { | ||
| 646 | {"DMIC1", NULL, "DMIC1 Pin"}, | ||
| 647 | {"DMIC2", NULL, "DMIC2 Pin"}, | ||
| 648 | {"DMIC1", NULL, "DMIC Receiver"}, | ||
| 649 | {"DMIC2", NULL, "DMIC Receiver"}, | ||
| 650 | |||
| 651 | {"RECMIX", "Beep Switch", "Beep"}, | ||
| 652 | {"RECMIX", "Line1 Switch", "LINE1"}, | ||
| 653 | {"RECMIX", "Mic1 Switch", "MIC1"}, | ||
| 654 | |||
| 655 | {"ADC 0 Mux", "Dmic", "DMIC1"}, | ||
| 656 | {"ADC 0 Mux", "RECMIX", "RECMIX"}, | ||
| 657 | {"ADC 0 Mux", "Mic", "MIC1"}, | ||
| 658 | {"ADC 1 Mux", "Dmic", "DMIC2"}, | ||
| 659 | {"ADC 1 Mux", "RECMIX", "RECMIX"}, | ||
| 660 | {"ADC 1 Mux", "Mic", "MIC1"}, | ||
| 661 | |||
| 662 | {"ADC 0", NULL, "ADC 0 Mux"}, | ||
| 663 | {"ADC 1", NULL, "ADC 1 Mux"}, | ||
| 664 | |||
| 665 | {"AIF1TX", NULL, "ADC 0"}, | ||
| 666 | {"AIF2TX", NULL, "ADC 1"}, | ||
| 667 | |||
| 668 | {"DAC 0", NULL, "AIF1RX"}, | ||
| 669 | {"DAC 1", NULL, "AIF2RX"}, | ||
| 670 | |||
| 671 | {"Front", "DAC Switch", "DAC 0"}, | ||
| 672 | {"Front", "RECMIX Switch", "RECMIX"}, | ||
| 673 | |||
| 674 | {"Surround", NULL, "DAC 1"}, | ||
| 675 | |||
| 676 | {"SPK Mux", "Front", "Front"}, | ||
| 677 | {"SPK Mux", "Surround", "Surround"}, | ||
| 678 | |||
| 679 | {"HPO Mux", "Front", "Front"}, | ||
| 680 | {"HPO Mux", "Surround", "Surround"}, | ||
| 681 | |||
| 682 | {"SPO", "Switch", "SPK Mux"}, | ||
| 683 | {"HPO L", "Switch", "HPO Mux"}, | ||
| 684 | {"HPO R", "Switch", "HPO Mux"}, | ||
| 685 | {"HPO L", NULL, "HP Power"}, | ||
| 686 | {"HPO R", NULL, "HP Power"}, | ||
| 687 | |||
| 688 | {"SPOL", NULL, "SPO"}, | ||
| 689 | {"SPOR", NULL, "SPO"}, | ||
| 690 | {"HPO Pin", NULL, "HPO L"}, | ||
| 691 | {"HPO Pin", NULL, "HPO R"}, | ||
| 692 | }; | ||
| 693 | |||
| 694 | static int rt286_hw_params(struct snd_pcm_substream *substream, | ||
| 695 | struct snd_pcm_hw_params *params, | ||
| 696 | struct snd_soc_dai *dai) | ||
| 697 | { | ||
| 698 | struct snd_soc_codec *codec = dai->codec; | ||
| 699 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 700 | unsigned int val = 0; | ||
| 701 | int d_len_code; | ||
| 702 | |||
| 703 | switch (params_rate(params)) { | ||
| 704 | /* bit 14 0:48K 1:44.1K */ | ||
| 705 | case 44100: | ||
| 706 | val |= 0x4000; | ||
| 707 | break; | ||
| 708 | case 48000: | ||
| 709 | break; | ||
| 710 | default: | ||
| 711 | dev_err(codec->dev, "Unsupported sample rate %d\n", | ||
| 712 | params_rate(params)); | ||
| 713 | return -EINVAL; | ||
| 714 | } | ||
| 715 | switch (rt286->sys_clk) { | ||
| 716 | case 12288000: | ||
| 717 | case 24576000: | ||
| 718 | if (params_rate(params) != 48000) { | ||
| 719 | dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", | ||
| 720 | params_rate(params), rt286->sys_clk); | ||
| 721 | return -EINVAL; | ||
| 722 | } | ||
| 723 | break; | ||
| 724 | case 11289600: | ||
| 725 | case 22579200: | ||
| 726 | if (params_rate(params) != 44100) { | ||
| 727 | dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", | ||
| 728 | params_rate(params), rt286->sys_clk); | ||
| 729 | return -EINVAL; | ||
| 730 | } | ||
| 731 | break; | ||
| 732 | } | ||
| 733 | |||
| 734 | if (params_channels(params) <= 16) { | ||
| 735 | /* bit 3:0 Number of Channel */ | ||
| 736 | val |= (params_channels(params) - 1); | ||
| 737 | } else { | ||
| 738 | dev_err(codec->dev, "Unsupported channels %d\n", | ||
| 739 | params_channels(params)); | ||
| 740 | return -EINVAL; | ||
| 741 | } | ||
| 742 | |||
| 743 | d_len_code = 0; | ||
| 744 | switch (params_width(params)) { | ||
| 745 | /* bit 6:4 Bits per Sample */ | ||
| 746 | case 16: | ||
| 747 | d_len_code = 0; | ||
| 748 | val |= (0x1 << 4); | ||
| 749 | break; | ||
| 750 | case 32: | ||
| 751 | d_len_code = 2; | ||
| 752 | val |= (0x4 << 4); | ||
| 753 | break; | ||
| 754 | case 20: | ||
| 755 | d_len_code = 1; | ||
| 756 | val |= (0x2 << 4); | ||
| 757 | break; | ||
| 758 | case 24: | ||
| 759 | d_len_code = 2; | ||
| 760 | val |= (0x3 << 4); | ||
| 761 | break; | ||
| 762 | case 8: | ||
| 763 | d_len_code = 3; | ||
| 764 | break; | ||
| 765 | default: | ||
| 766 | return -EINVAL; | ||
| 767 | } | ||
| 768 | |||
| 769 | snd_soc_update_bits(codec, | ||
| 770 | RT286_I2S_CTRL1, 0x0018, d_len_code << 3); | ||
| 771 | dev_dbg(codec->dev, "format val = 0x%x\n", val); | ||
| 772 | |||
| 773 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 774 | snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x407f, val); | ||
| 775 | else | ||
| 776 | snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x407f, val); | ||
| 777 | |||
| 778 | return 0; | ||
| 779 | } | ||
| 780 | |||
| 781 | static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
| 782 | { | ||
| 783 | struct snd_soc_codec *codec = dai->codec; | ||
| 784 | |||
| 785 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 786 | case SND_SOC_DAIFMT_CBM_CFM: | ||
| 787 | snd_soc_update_bits(codec, | ||
| 788 | RT286_I2S_CTRL1, 0x800, 0x800); | ||
| 789 | break; | ||
| 790 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 791 | snd_soc_update_bits(codec, | ||
| 792 | RT286_I2S_CTRL1, 0x800, 0x0); | ||
| 793 | break; | ||
| 794 | default: | ||
| 795 | return -EINVAL; | ||
| 796 | } | ||
| 797 | |||
| 798 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 799 | case SND_SOC_DAIFMT_I2S: | ||
| 800 | snd_soc_update_bits(codec, | ||
| 801 | RT286_I2S_CTRL1, 0x300, 0x0); | ||
| 802 | break; | ||
| 803 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 804 | snd_soc_update_bits(codec, | ||
| 805 | RT286_I2S_CTRL1, 0x300, 0x1 << 8); | ||
| 806 | break; | ||
| 807 | case SND_SOC_DAIFMT_DSP_A: | ||
| 808 | snd_soc_update_bits(codec, | ||
| 809 | RT286_I2S_CTRL1, 0x300, 0x2 << 8); | ||
| 810 | break; | ||
| 811 | case SND_SOC_DAIFMT_DSP_B: | ||
| 812 | snd_soc_update_bits(codec, | ||
| 813 | RT286_I2S_CTRL1, 0x300, 0x3 << 8); | ||
| 814 | break; | ||
| 815 | default: | ||
| 816 | return -EINVAL; | ||
| 817 | } | ||
| 818 | /* bit 15 Stream Type 0:PCM 1:Non-PCM */ | ||
| 819 | snd_soc_update_bits(codec, RT286_DAC_FORMAT, 0x8000, 0); | ||
| 820 | snd_soc_update_bits(codec, RT286_ADC_FORMAT, 0x8000, 0); | ||
| 821 | |||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | |||
| 825 | static int rt286_set_dai_sysclk(struct snd_soc_dai *dai, | ||
| 826 | int clk_id, unsigned int freq, int dir) | ||
| 827 | { | ||
| 828 | struct snd_soc_codec *codec = dai->codec; | ||
| 829 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 830 | |||
| 831 | dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq); | ||
| 832 | |||
| 833 | if (RT286_SCLK_S_MCLK == clk_id) { | ||
| 834 | snd_soc_update_bits(codec, | ||
| 835 | RT286_I2S_CTRL2, 0x0100, 0x0); | ||
| 836 | snd_soc_update_bits(codec, | ||
| 837 | RT286_PLL_CTRL1, 0x20, 0x20); | ||
| 838 | } else { | ||
| 839 | snd_soc_update_bits(codec, | ||
| 840 | RT286_I2S_CTRL2, 0x0100, 0x0100); | ||
| 841 | snd_soc_update_bits(codec, | ||
| 842 | RT286_PLL_CTRL, 0x4, 0x4); | ||
| 843 | snd_soc_update_bits(codec, | ||
| 844 | RT286_PLL_CTRL1, 0x20, 0x0); | ||
| 845 | } | ||
| 846 | |||
| 847 | switch (freq) { | ||
| 848 | case 19200000: | ||
| 849 | if (RT286_SCLK_S_MCLK == clk_id) { | ||
| 850 | dev_err(codec->dev, "Should not use MCLK\n"); | ||
| 851 | return -EINVAL; | ||
| 852 | } | ||
| 853 | snd_soc_update_bits(codec, | ||
| 854 | RT286_I2S_CTRL2, 0x40, 0x40); | ||
| 855 | break; | ||
| 856 | case 24000000: | ||
| 857 | if (RT286_SCLK_S_MCLK == clk_id) { | ||
| 858 | dev_err(codec->dev, "Should not use MCLK\n"); | ||
| 859 | return -EINVAL; | ||
| 860 | } | ||
| 861 | snd_soc_update_bits(codec, | ||
| 862 | RT286_I2S_CTRL2, 0x40, 0x0); | ||
| 863 | break; | ||
| 864 | case 12288000: | ||
| 865 | case 11289600: | ||
| 866 | snd_soc_update_bits(codec, | ||
| 867 | RT286_I2S_CTRL2, 0x8, 0x0); | ||
| 868 | snd_soc_update_bits(codec, | ||
| 869 | RT286_CLK_DIV, 0xfc1e, 0x0004); | ||
| 870 | break; | ||
| 871 | case 24576000: | ||
| 872 | case 22579200: | ||
| 873 | snd_soc_update_bits(codec, | ||
| 874 | RT286_I2S_CTRL2, 0x8, 0x8); | ||
| 875 | snd_soc_update_bits(codec, | ||
| 876 | RT286_CLK_DIV, 0xfc1e, 0x5406); | ||
| 877 | break; | ||
| 878 | default: | ||
| 879 | dev_err(codec->dev, "Unsupported system clock\n"); | ||
| 880 | return -EINVAL; | ||
| 881 | } | ||
| 882 | |||
| 883 | rt286->sys_clk = freq; | ||
| 884 | |||
| 885 | return 0; | ||
| 886 | } | ||
| 887 | |||
| 888 | static int rt286_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) | ||
| 889 | { | ||
| 890 | struct snd_soc_codec *codec = dai->codec; | ||
| 891 | |||
| 892 | dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); | ||
| 893 | if (50 == ratio) | ||
| 894 | snd_soc_update_bits(codec, | ||
| 895 | RT286_I2S_CTRL1, 0x1000, 0x1000); | ||
| 896 | else | ||
| 897 | snd_soc_update_bits(codec, | ||
| 898 | RT286_I2S_CTRL1, 0x1000, 0x0); | ||
| 899 | |||
| 900 | |||
| 901 | return 0; | ||
| 902 | } | ||
| 903 | |||
| 904 | static int rt286_set_bias_level(struct snd_soc_codec *codec, | ||
| 905 | enum snd_soc_bias_level level) | ||
| 906 | { | ||
| 907 | switch (level) { | ||
| 908 | case SND_SOC_BIAS_PREPARE: | ||
| 909 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | ||
| 910 | snd_soc_write(codec, | ||
| 911 | RT286_SET_AUDIO_POWER, AC_PWRST_D0); | ||
| 912 | snd_soc_update_bits(codec, | ||
| 913 | RT286_DC_GAIN, 0x200, 0x200); | ||
| 914 | } | ||
| 915 | break; | ||
| 916 | |||
| 917 | case SND_SOC_BIAS_ON: | ||
| 918 | mdelay(10); | ||
| 919 | break; | ||
| 920 | |||
| 921 | case SND_SOC_BIAS_STANDBY: | ||
| 922 | snd_soc_write(codec, | ||
| 923 | RT286_SET_AUDIO_POWER, AC_PWRST_D3); | ||
| 924 | snd_soc_update_bits(codec, | ||
| 925 | RT286_DC_GAIN, 0x200, 0x0); | ||
| 926 | break; | ||
| 927 | |||
| 928 | default: | ||
| 929 | break; | ||
| 930 | } | ||
| 931 | codec->dapm.bias_level = level; | ||
| 932 | |||
| 933 | return 0; | ||
| 934 | } | ||
| 935 | |||
| 936 | static irqreturn_t rt286_irq(int irq, void *data) | ||
| 937 | { | ||
| 938 | struct rt286_priv *rt286 = data; | ||
| 939 | bool hp = false; | ||
| 940 | bool mic = false; | ||
| 941 | int status = 0; | ||
| 942 | |||
| 943 | rt286_jack_detect(rt286->codec, &hp, &mic); | ||
| 944 | |||
| 945 | /* Clear IRQ */ | ||
| 946 | snd_soc_update_bits(rt286->codec, | ||
| 947 | RT286_IRQ_CTRL, 0x1, 0x1); | ||
| 948 | |||
| 949 | if (hp == true) | ||
| 950 | status |= SND_JACK_HEADPHONE; | ||
| 951 | |||
| 952 | if (mic == true) | ||
| 953 | status |= SND_JACK_MICROPHONE; | ||
| 954 | |||
| 955 | snd_soc_jack_report(rt286->jack, status, | ||
| 956 | SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); | ||
| 957 | |||
| 958 | pm_wakeup_event(&rt286->i2c->dev, 300); | ||
| 959 | |||
| 960 | return IRQ_HANDLED; | ||
| 961 | } | ||
| 962 | |||
| 963 | static int rt286_probe(struct snd_soc_codec *codec) | ||
| 964 | { | ||
| 965 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 966 | |||
| 967 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | ||
| 968 | rt286->codec = codec; | ||
| 969 | |||
| 970 | return 0; | ||
| 971 | } | ||
| 972 | |||
| 973 | static int rt286_remove(struct snd_soc_codec *codec) | ||
| 974 | { | ||
| 975 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 976 | |||
| 977 | cancel_delayed_work_sync(&rt286->jack_detect_work); | ||
| 978 | |||
| 979 | return 0; | ||
| 980 | } | ||
| 981 | |||
| 982 | #ifdef CONFIG_PM | ||
| 983 | static int rt286_suspend(struct snd_soc_codec *codec) | ||
| 984 | { | ||
| 985 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 986 | |||
| 987 | regcache_cache_only(rt286->regmap, true); | ||
| 988 | regcache_mark_dirty(rt286->regmap); | ||
| 989 | |||
| 990 | return 0; | ||
| 991 | } | ||
| 992 | |||
| 993 | static int rt286_resume(struct snd_soc_codec *codec) | ||
| 994 | { | ||
| 995 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 996 | |||
| 997 | regcache_cache_only(rt286->regmap, false); | ||
| 998 | rt286_index_sync(codec); | ||
| 999 | regcache_sync(rt286->regmap); | ||
| 1000 | |||
| 1001 | return 0; | ||
| 1002 | } | ||
| 1003 | #else | ||
| 1004 | #define rt286_suspend NULL | ||
| 1005 | #define rt286_resume NULL | ||
| 1006 | #endif | ||
| 1007 | |||
| 1008 | #define RT286_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) | ||
| 1009 | #define RT286_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
| 1010 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) | ||
| 1011 | |||
| 1012 | static const struct snd_soc_dai_ops rt286_aif_dai_ops = { | ||
| 1013 | .hw_params = rt286_hw_params, | ||
| 1014 | .set_fmt = rt286_set_dai_fmt, | ||
| 1015 | .set_sysclk = rt286_set_dai_sysclk, | ||
| 1016 | .set_bclk_ratio = rt286_set_bclk_ratio, | ||
| 1017 | }; | ||
| 1018 | |||
| 1019 | static struct snd_soc_dai_driver rt286_dai[] = { | ||
| 1020 | { | ||
| 1021 | .name = "rt286-aif1", | ||
| 1022 | .id = RT286_AIF1, | ||
| 1023 | .playback = { | ||
| 1024 | .stream_name = "AIF1 Playback", | ||
| 1025 | .channels_min = 1, | ||
| 1026 | .channels_max = 2, | ||
| 1027 | .rates = RT286_STEREO_RATES, | ||
| 1028 | .formats = RT286_FORMATS, | ||
| 1029 | }, | ||
| 1030 | .capture = { | ||
| 1031 | .stream_name = "AIF1 Capture", | ||
| 1032 | .channels_min = 1, | ||
| 1033 | .channels_max = 2, | ||
| 1034 | .rates = RT286_STEREO_RATES, | ||
| 1035 | .formats = RT286_FORMATS, | ||
| 1036 | }, | ||
| 1037 | .ops = &rt286_aif_dai_ops, | ||
| 1038 | .symmetric_rates = 1, | ||
| 1039 | }, | ||
| 1040 | { | ||
| 1041 | .name = "rt286-aif2", | ||
| 1042 | .id = RT286_AIF2, | ||
| 1043 | .playback = { | ||
| 1044 | .stream_name = "AIF2 Playback", | ||
| 1045 | .channels_min = 1, | ||
| 1046 | .channels_max = 2, | ||
| 1047 | .rates = RT286_STEREO_RATES, | ||
| 1048 | .formats = RT286_FORMATS, | ||
| 1049 | }, | ||
| 1050 | .capture = { | ||
| 1051 | .stream_name = "AIF2 Capture", | ||
| 1052 | .channels_min = 1, | ||
| 1053 | .channels_max = 2, | ||
| 1054 | .rates = RT286_STEREO_RATES, | ||
| 1055 | .formats = RT286_FORMATS, | ||
| 1056 | }, | ||
| 1057 | .ops = &rt286_aif_dai_ops, | ||
| 1058 | .symmetric_rates = 1, | ||
| 1059 | }, | ||
| 1060 | |||
| 1061 | }; | ||
| 1062 | |||
| 1063 | static struct snd_soc_codec_driver soc_codec_dev_rt286 = { | ||
| 1064 | .probe = rt286_probe, | ||
| 1065 | .remove = rt286_remove, | ||
| 1066 | .suspend = rt286_suspend, | ||
| 1067 | .resume = rt286_resume, | ||
| 1068 | .set_bias_level = rt286_set_bias_level, | ||
| 1069 | .idle_bias_off = true, | ||
| 1070 | .controls = rt286_snd_controls, | ||
| 1071 | .num_controls = ARRAY_SIZE(rt286_snd_controls), | ||
| 1072 | .dapm_widgets = rt286_dapm_widgets, | ||
| 1073 | .num_dapm_widgets = ARRAY_SIZE(rt286_dapm_widgets), | ||
| 1074 | .dapm_routes = rt286_dapm_routes, | ||
| 1075 | .num_dapm_routes = ARRAY_SIZE(rt286_dapm_routes), | ||
| 1076 | }; | ||
| 1077 | |||
| 1078 | static const struct regmap_config rt286_regmap = { | ||
| 1079 | .reg_bits = 32, | ||
| 1080 | .val_bits = 32, | ||
| 1081 | .max_register = 0x02370100, | ||
| 1082 | .volatile_reg = rt286_volatile_register, | ||
| 1083 | .readable_reg = rt286_readable_register, | ||
| 1084 | .reg_write = rt286_hw_write, | ||
| 1085 | .reg_read = rt286_hw_read, | ||
| 1086 | .cache_type = REGCACHE_RBTREE, | ||
| 1087 | .reg_defaults = rt286_reg, | ||
| 1088 | .num_reg_defaults = ARRAY_SIZE(rt286_reg), | ||
| 1089 | }; | ||
| 1090 | |||
| 1091 | static const struct i2c_device_id rt286_i2c_id[] = { | ||
| 1092 | {"rt286", 0}, | ||
| 1093 | {} | ||
| 1094 | }; | ||
| 1095 | MODULE_DEVICE_TABLE(i2c, rt286_i2c_id); | ||
| 1096 | |||
| 1097 | static const struct acpi_device_id rt286_acpi_match[] = { | ||
| 1098 | { "INT343A", 0 }, | ||
| 1099 | {}, | ||
| 1100 | }; | ||
| 1101 | MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); | ||
| 1102 | |||
| 1103 | static int rt286_i2c_probe(struct i2c_client *i2c, | ||
| 1104 | const struct i2c_device_id *id) | ||
| 1105 | { | ||
| 1106 | struct rt286_platform_data *pdata = dev_get_platdata(&i2c->dev); | ||
| 1107 | struct rt286_priv *rt286; | ||
| 1108 | int i, ret; | ||
| 1109 | |||
| 1110 | rt286 = devm_kzalloc(&i2c->dev, sizeof(*rt286), | ||
| 1111 | GFP_KERNEL); | ||
| 1112 | if (NULL == rt286) | ||
| 1113 | return -ENOMEM; | ||
| 1114 | |||
| 1115 | rt286->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt286_regmap); | ||
| 1116 | if (IS_ERR(rt286->regmap)) { | ||
| 1117 | ret = PTR_ERR(rt286->regmap); | ||
| 1118 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
| 1119 | ret); | ||
| 1120 | return ret; | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | regmap_read(rt286->regmap, | ||
| 1124 | RT286_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); | ||
| 1125 | if (ret != RT286_VENDOR_ID) { | ||
| 1126 | dev_err(&i2c->dev, | ||
| 1127 | "Device with ID register %x is not rt286\n", ret); | ||
| 1128 | return -ENODEV; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | rt286->index_cache = rt286_index_def; | ||
| 1132 | rt286->i2c = i2c; | ||
| 1133 | i2c_set_clientdata(i2c, rt286); | ||
| 1134 | |||
| 1135 | if (pdata) | ||
| 1136 | rt286->pdata = *pdata; | ||
| 1137 | |||
| 1138 | regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); | ||
| 1139 | |||
| 1140 | for (i = 0; i < RT286_POWER_REG_LEN; i++) | ||
| 1141 | regmap_write(rt286->regmap, | ||
| 1142 | RT286_SET_POWER(rt286_support_power_controls[i]), | ||
| 1143 | AC_PWRST_D1); | ||
| 1144 | |||
| 1145 | if (!rt286->pdata.cbj_en) { | ||
| 1146 | regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); | ||
| 1147 | regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); | ||
| 1148 | regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); | ||
| 1149 | regmap_update_bits(rt286->regmap, | ||
| 1150 | RT286_CBJ_CTRL1, 0xf000, 0xb000); | ||
| 1151 | } else { | ||
| 1152 | regmap_update_bits(rt286->regmap, | ||
| 1153 | RT286_CBJ_CTRL1, 0xf000, 0x5000); | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | mdelay(10); | ||
| 1157 | |||
| 1158 | if (!rt286->pdata.gpio2_en) | ||
| 1159 | regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0x4000); | ||
| 1160 | else | ||
| 1161 | regmap_write(rt286->regmap, RT286_SET_DMIC2_DEFAULT, 0); | ||
| 1162 | |||
| 1163 | mdelay(10); | ||
| 1164 | |||
| 1165 | /*Power down LDO2*/ | ||
| 1166 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0); | ||
| 1167 | |||
| 1168 | /*Set depop parameter*/ | ||
| 1169 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); | ||
| 1170 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); | ||
| 1171 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); | ||
| 1172 | |||
| 1173 | if (rt286->i2c->irq) { | ||
| 1174 | regmap_update_bits(rt286->regmap, | ||
| 1175 | RT286_IRQ_CTRL, 0x2, 0x2); | ||
| 1176 | |||
| 1177 | INIT_DELAYED_WORK(&rt286->jack_detect_work, | ||
| 1178 | rt286_jack_detect_work); | ||
| 1179 | schedule_delayed_work(&rt286->jack_detect_work, | ||
| 1180 | msecs_to_jiffies(1250)); | ||
| 1181 | |||
| 1182 | ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, | ||
| 1183 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); | ||
| 1184 | if (ret != 0) { | ||
| 1185 | dev_err(&i2c->dev, | ||
| 1186 | "Failed to reguest IRQ: %d\n", ret); | ||
| 1187 | return ret; | ||
| 1188 | } | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt286, | ||
| 1192 | rt286_dai, ARRAY_SIZE(rt286_dai)); | ||
| 1193 | |||
| 1194 | return ret; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | static int rt286_i2c_remove(struct i2c_client *i2c) | ||
| 1198 | { | ||
| 1199 | struct rt286_priv *rt286 = i2c_get_clientdata(i2c); | ||
| 1200 | |||
| 1201 | if (i2c->irq) | ||
| 1202 | free_irq(i2c->irq, rt286); | ||
| 1203 | snd_soc_unregister_codec(&i2c->dev); | ||
| 1204 | |||
| 1205 | return 0; | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | |||
| 1209 | static struct i2c_driver rt286_i2c_driver = { | ||
| 1210 | .driver = { | ||
| 1211 | .name = "rt286", | ||
| 1212 | .owner = THIS_MODULE, | ||
| 1213 | .acpi_match_table = ACPI_PTR(rt286_acpi_match), | ||
| 1214 | }, | ||
| 1215 | .probe = rt286_i2c_probe, | ||
| 1216 | .remove = rt286_i2c_remove, | ||
| 1217 | .id_table = rt286_i2c_id, | ||
| 1218 | }; | ||
| 1219 | |||
| 1220 | module_i2c_driver(rt286_i2c_driver); | ||
| 1221 | |||
| 1222 | MODULE_DESCRIPTION("ASoC RT286 driver"); | ||
| 1223 | MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); | ||
| 1224 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/rt286.h b/sound/soc/codecs/rt286.h new file mode 100644 index 000000000000..b539b7320a79 --- /dev/null +++ b/sound/soc/codecs/rt286.h | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | /* | ||
| 2 | * rt286.h -- RT286 ALSA SoC audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2011 Realtek Microelectronics | ||
| 5 | * Author: Johnny Hsu <johnnyhsu@realtek.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 __RT286_H__ | ||
| 13 | #define __RT286_H__ | ||
| 14 | |||
| 15 | #define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) | ||
| 16 | |||
| 17 | #define RT286_AUDIO_FUNCTION_GROUP 0x01 | ||
| 18 | #define RT286_DAC_OUT1 0x02 | ||
| 19 | #define RT286_DAC_OUT2 0x03 | ||
| 20 | #define RT286_ADC_IN1 0x09 | ||
| 21 | #define RT286_ADC_IN2 0x08 | ||
| 22 | #define RT286_MIXER_IN 0x0b | ||
| 23 | #define RT286_MIXER_OUT1 0x0c | ||
| 24 | #define RT286_MIXER_OUT2 0x0d | ||
| 25 | #define RT286_DMIC1 0x12 | ||
| 26 | #define RT286_DMIC2 0x13 | ||
| 27 | #define RT286_SPK_OUT 0x14 | ||
| 28 | #define RT286_MIC1 0x18 | ||
| 29 | #define RT286_LINE1 0x1a | ||
| 30 | #define RT286_BEEP 0x1d | ||
| 31 | #define RT286_SPDIF 0x1e | ||
| 32 | #define RT286_VENDOR_REGISTERS 0x20 | ||
| 33 | #define RT286_HP_OUT 0x21 | ||
| 34 | #define RT286_MIXER_IN1 0x22 | ||
| 35 | #define RT286_MIXER_IN2 0x23 | ||
| 36 | |||
| 37 | #define RT286_SET_PIN_SFT 6 | ||
| 38 | #define RT286_SET_PIN_ENABLE 0x40 | ||
| 39 | #define RT286_SET_PIN_DISABLE 0 | ||
| 40 | #define RT286_SET_EAPD_HIGH 0x2 | ||
| 41 | #define RT286_SET_EAPD_LOW 0 | ||
| 42 | |||
| 43 | #define RT286_MUTE_SFT 7 | ||
| 44 | |||
| 45 | /* Verb commands */ | ||
| 46 | #define RT286_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM) | ||
| 47 | #define RT286_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0) | ||
| 48 | #define RT286_SET_AUDIO_POWER RT286_SET_POWER(RT286_AUDIO_FUNCTION_GROUP) | ||
| 49 | #define RT286_SET_HPO_POWER RT286_SET_POWER(RT286_HP_OUT) | ||
| 50 | #define RT286_SET_SPK_POWER RT286_SET_POWER(RT286_SPK_OUT) | ||
| 51 | #define RT286_SET_DMIC1_POWER RT286_SET_POWER(RT286_DMIC1) | ||
| 52 | #define RT286_SPK_MUX\ | ||
| 53 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_SPK_OUT, 0) | ||
| 54 | #define RT286_HPO_MUX\ | ||
| 55 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_HP_OUT, 0) | ||
| 56 | #define RT286_ADC0_MUX\ | ||
| 57 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN1, 0) | ||
| 58 | #define RT286_ADC1_MUX\ | ||
| 59 | VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT286_MIXER_IN2, 0) | ||
| 60 | #define RT286_SET_MIC1\ | ||
| 61 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_MIC1, 0) | ||
| 62 | #define RT286_SET_PIN_HPO\ | ||
| 63 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_HP_OUT, 0) | ||
| 64 | #define RT286_SET_PIN_SPK\ | ||
| 65 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_SPK_OUT, 0) | ||
| 66 | #define RT286_SET_PIN_DMIC1\ | ||
| 67 | VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT286_DMIC1, 0) | ||
| 68 | #define RT286_SPK_EAPD\ | ||
| 69 | VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT286_SPK_OUT, 0) | ||
| 70 | #define RT286_SET_AMP_GAIN_HPO\ | ||
| 71 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0) | ||
| 72 | #define RT286_SET_AMP_GAIN_ADC_IN1\ | ||
| 73 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0) | ||
| 74 | #define RT286_SET_AMP_GAIN_ADC_IN2\ | ||
| 75 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN2, 0) | ||
| 76 | #define RT286_GET_HP_SENSE\ | ||
| 77 | VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_HP_OUT, 0) | ||
| 78 | #define RT286_GET_MIC1_SENSE\ | ||
| 79 | VERB_CMD(AC_VERB_GET_PIN_SENSE, RT286_MIC1, 0) | ||
| 80 | #define RT286_SET_DMIC2_DEFAULT\ | ||
| 81 | VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT286_DMIC2, 0) | ||
| 82 | #define RT286_DACL_GAIN\ | ||
| 83 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0xa000) | ||
| 84 | #define RT286_DACR_GAIN\ | ||
| 85 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_DAC_OUT1, 0x9000) | ||
| 86 | #define RT286_ADCL_GAIN\ | ||
| 87 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x6000) | ||
| 88 | #define RT286_ADCR_GAIN\ | ||
| 89 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_ADC_IN1, 0x5000) | ||
| 90 | #define RT286_MIC_GAIN\ | ||
| 91 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIC1, 0x7000) | ||
| 92 | #define RT286_SPOL_GAIN\ | ||
| 93 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0xa000) | ||
| 94 | #define RT286_SPOR_GAIN\ | ||
| 95 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_SPK_OUT, 0x9000) | ||
| 96 | #define RT286_HPOL_GAIN\ | ||
| 97 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0xa000) | ||
| 98 | #define RT286_HPOR_GAIN\ | ||
| 99 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_HP_OUT, 0x9000) | ||
| 100 | #define RT286_F_DAC_SWITCH\ | ||
| 101 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7000) | ||
| 102 | #define RT286_F_RECMIX_SWITCH\ | ||
| 103 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_OUT1, 0x7100) | ||
| 104 | #define RT286_REC_MIC_SWITCH\ | ||
| 105 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7000) | ||
| 106 | #define RT286_REC_I2S_SWITCH\ | ||
| 107 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7100) | ||
| 108 | #define RT286_REC_LINE_SWITCH\ | ||
| 109 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7200) | ||
| 110 | #define RT286_REC_BEEP_SWITCH\ | ||
| 111 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT286_MIXER_IN, 0x7300) | ||
| 112 | #define RT286_DAC_FORMAT\ | ||
| 113 | VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_DAC_OUT1, 0) | ||
| 114 | #define RT286_ADC_FORMAT\ | ||
| 115 | VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT286_ADC_IN1, 0) | ||
| 116 | #define RT286_COEF_INDEX\ | ||
| 117 | VERB_CMD(AC_VERB_SET_COEF_INDEX, RT286_VENDOR_REGISTERS, 0) | ||
| 118 | #define RT286_PROC_COEF\ | ||
| 119 | VERB_CMD(AC_VERB_SET_PROC_COEF, RT286_VENDOR_REGISTERS, 0) | ||
| 120 | |||
| 121 | /* Index registers */ | ||
| 122 | #define RT286_A_BIAS_CTRL1 0x01 | ||
| 123 | #define RT286_A_BIAS_CTRL2 0x02 | ||
| 124 | #define RT286_POWER_CTRL1 0x03 | ||
| 125 | #define RT286_A_BIAS_CTRL3 0x04 | ||
| 126 | #define RT286_POWER_CTRL2 0x08 | ||
| 127 | #define RT286_I2S_CTRL1 0x09 | ||
| 128 | #define RT286_I2S_CTRL2 0x0a | ||
| 129 | #define RT286_CLK_DIV 0x0b | ||
| 130 | #define RT286_DC_GAIN 0x0d | ||
| 131 | #define RT286_POWER_CTRL3 0x0f | ||
| 132 | #define RT286_MIC1_DET_CTRL 0x19 | ||
| 133 | #define RT286_MISC_CTRL1 0x20 | ||
| 134 | #define RT286_IRQ_CTRL 0x33 | ||
| 135 | #define RT286_PLL_CTRL1 0x49 | ||
| 136 | #define RT286_CBJ_CTRL1 0x4f | ||
| 137 | #define RT286_CBJ_CTRL2 0x50 | ||
| 138 | #define RT286_PLL_CTRL 0x63 | ||
| 139 | #define RT286_DEPOP_CTRL1 0x66 | ||
| 140 | #define RT286_DEPOP_CTRL2 0x67 | ||
| 141 | #define RT286_DEPOP_CTRL3 0x68 | ||
| 142 | #define RT286_DEPOP_CTRL4 0x69 | ||
| 143 | |||
| 144 | /* SPDIF (0x06) */ | ||
| 145 | #define RT286_SPDIF_SEL_SFT 0 | ||
| 146 | #define RT286_SPDIF_SEL_PCM0 0 | ||
| 147 | #define RT286_SPDIF_SEL_PCM1 1 | ||
| 148 | #define RT286_SPDIF_SEL_SPOUT 2 | ||
| 149 | #define RT286_SPDIF_SEL_PP 3 | ||
| 150 | |||
| 151 | /* RECMIX (0x0b) */ | ||
| 152 | #define RT286_M_REC_BEEP_SFT 0 | ||
| 153 | #define RT286_M_REC_LINE1_SFT 1 | ||
| 154 | #define RT286_M_REC_MIC1_SFT 2 | ||
| 155 | #define RT286_M_REC_I2S_SFT 3 | ||
| 156 | |||
| 157 | /* Front (0x0c) */ | ||
| 158 | #define RT286_M_FRONT_DAC_SFT 0 | ||
| 159 | #define RT286_M_FRONT_REC_SFT 1 | ||
| 160 | |||
| 161 | /* SPK-OUT (0x14) */ | ||
| 162 | #define RT286_M_SPK_MUX_SFT 14 | ||
| 163 | #define RT286_SPK_SEL_MASK 0x1 | ||
| 164 | #define RT286_SPK_SEL_SFT 0 | ||
| 165 | #define RT286_SPK_SEL_F 0 | ||
| 166 | #define RT286_SPK_SEL_S 1 | ||
| 167 | |||
| 168 | /* HP-OUT (0x21) */ | ||
| 169 | #define RT286_M_HP_MUX_SFT 14 | ||
| 170 | #define RT286_HP_SEL_MASK 0x1 | ||
| 171 | #define RT286_HP_SEL_SFT 0 | ||
| 172 | #define RT286_HP_SEL_F 0 | ||
| 173 | #define RT286_HP_SEL_S 1 | ||
| 174 | |||
| 175 | /* ADC (0x22) (0x23) */ | ||
| 176 | #define RT286_ADC_SEL_MASK 0x7 | ||
| 177 | #define RT286_ADC_SEL_SFT 0 | ||
| 178 | #define RT286_ADC_SEL_SURR 0 | ||
| 179 | #define RT286_ADC_SEL_FRONT 1 | ||
| 180 | #define RT286_ADC_SEL_DMIC 2 | ||
| 181 | #define RT286_ADC_SEL_BEEP 4 | ||
| 182 | #define RT286_ADC_SEL_LINE1 5 | ||
| 183 | #define RT286_ADC_SEL_I2S 6 | ||
| 184 | #define RT286_ADC_SEL_MIC1 7 | ||
| 185 | |||
| 186 | #define RT286_SCLK_S_MCLK 0 | ||
| 187 | #define RT286_SCLK_S_PLL 1 | ||
| 188 | |||
| 189 | enum { | ||
| 190 | RT286_AIF1, | ||
| 191 | RT286_AIF2, | ||
| 192 | RT286_AIFS, | ||
| 193 | }; | ||
| 194 | |||
| 195 | int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); | ||
| 196 | |||
| 197 | #endif /* __RT286_H__ */ | ||
| 198 | |||
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index c30fedb3e149..f5b4a9c79cdf 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
| @@ -58,3 +58,15 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH | |||
| 58 | help | 58 | help |
| 59 | This adds audio driver for Intel Baytrail platform based boards | 59 | This adds audio driver for Intel Baytrail platform based boards |
| 60 | with the MAX98090 audio codec. | 60 | with the MAX98090 audio codec. |
| 61 | |||
| 62 | config SND_SOC_INTEL_BROADWELL_MACH | ||
| 63 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | ||
| 64 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC | ||
| 65 | select SND_SOC_INTEL_HASWELL | ||
| 66 | select SND_COMPRESS_OFFLOAD | ||
| 67 | select SND_SOC_RT286 | ||
| 68 | help | ||
| 69 | This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell | ||
| 70 | Ultrabook platforms. | ||
| 71 | Say Y if you have such a device | ||
| 72 | If unsure select "N". | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 4bfca79a42ba..7acbfc43a0c6 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
| @@ -24,7 +24,9 @@ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o | |||
| 24 | snd-soc-sst-haswell-objs := haswell.o | 24 | snd-soc-sst-haswell-objs := haswell.o |
| 25 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 25 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
| 26 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 26 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
| 27 | snd-soc-sst-broadwell-objs := broadwell.o | ||
| 27 | 28 | ||
| 28 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 29 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
| 29 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 30 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
| 30 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | 31 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o |
| 32 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | ||
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c new file mode 100644 index 000000000000..0e550f14028f --- /dev/null +++ b/sound/soc/intel/broadwell.c | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | /* | ||
| 2 | * Intel Broadwell Wildcatpoint SST Audio | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <sound/core.h> | ||
| 20 | #include <sound/pcm.h> | ||
| 21 | #include <sound/soc.h> | ||
| 22 | #include <sound/pcm_params.h> | ||
| 23 | |||
| 24 | #include "sst-dsp.h" | ||
| 25 | #include "sst-haswell-ipc.h" | ||
| 26 | |||
| 27 | #include "../codecs/rt286.h" | ||
| 28 | |||
| 29 | static const struct snd_soc_dapm_widget broadwell_widgets[] = { | ||
| 30 | SND_SOC_DAPM_HP("Headphones", NULL), | ||
| 31 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
| 32 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
| 33 | SND_SOC_DAPM_MIC("DMIC1", NULL), | ||
| 34 | SND_SOC_DAPM_MIC("DMIC2", NULL), | ||
| 35 | SND_SOC_DAPM_LINE("Line Jack", NULL), | ||
| 36 | }; | ||
| 37 | |||
| 38 | static const struct snd_soc_dapm_route broadwell_rt286_map[] = { | ||
| 39 | |||
| 40 | /* speaker */ | ||
| 41 | {"Speaker", NULL, "SPOR"}, | ||
| 42 | {"Speaker", NULL, "SPOL"}, | ||
| 43 | |||
| 44 | /* HP jack connectors - unknown if we have jack deteck */ | ||
| 45 | {"Headphones", NULL, "HPO Pin"}, | ||
| 46 | |||
| 47 | /* other jacks */ | ||
| 48 | {"MIC1", NULL, "Mic Jack"}, | ||
| 49 | {"LINE1", NULL, "Line Jack"}, | ||
| 50 | |||
| 51 | /* digital mics */ | ||
| 52 | {"DMIC1 Pin", NULL, "DMIC1"}, | ||
| 53 | {"DMIC2 Pin", NULL, "DMIC2"}, | ||
| 54 | |||
| 55 | /* CODEC BE connections */ | ||
| 56 | {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, | ||
| 57 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | ||
| 58 | }; | ||
| 59 | |||
| 60 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | ||
| 61 | struct snd_pcm_hw_params *params) | ||
| 62 | { | ||
| 63 | struct snd_interval *rate = hw_param_interval(params, | ||
| 64 | SNDRV_PCM_HW_PARAM_RATE); | ||
| 65 | struct snd_interval *channels = hw_param_interval(params, | ||
| 66 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 67 | |||
| 68 | /* The ADSP will covert the FE rate to 48k, stereo */ | ||
| 69 | rate->min = rate->max = 48000; | ||
| 70 | channels->min = channels->max = 2; | ||
| 71 | |||
| 72 | /* set SSP0 to 16 bit */ | ||
| 73 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
| 74 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 75 | SNDRV_PCM_FORMAT_S16_LE); | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, | ||
| 80 | struct snd_pcm_hw_params *params) | ||
| 81 | { | ||
| 82 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 83 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 84 | int ret; | ||
| 85 | |||
| 86 | ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, | ||
| 87 | SND_SOC_CLOCK_IN); | ||
| 88 | |||
| 89 | if (ret < 0) { | ||
| 90 | dev_err(rtd->dev, "can't set codec sysclk configuration\n"); | ||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | return ret; | ||
| 95 | } | ||
| 96 | |||
| 97 | static struct snd_soc_ops broadwell_rt286_ops = { | ||
| 98 | .hw_params = broadwell_rt286_hw_params, | ||
| 99 | }; | ||
| 100 | |||
| 101 | static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) | ||
| 102 | { | ||
| 103 | struct snd_soc_codec *codec = rtd->codec; | ||
| 104 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 105 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); | ||
| 106 | struct sst_hsw *broadwell = pdata->dsp; | ||
| 107 | int ret; | ||
| 108 | |||
| 109 | /* Set ADSP SSP port settings */ | ||
| 110 | ret = sst_hsw_device_set_config(broadwell, SST_HSW_DEVICE_SSP_0, | ||
| 111 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
| 112 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
| 113 | if (ret < 0) { | ||
| 114 | dev_err(rtd->dev, "error: failed to set device config\n"); | ||
| 115 | return ret; | ||
| 116 | } | ||
| 117 | |||
| 118 | /* always connected - check HP for jack detect */ | ||
| 119 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | ||
| 120 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | ||
| 121 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | ||
| 122 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | ||
| 123 | snd_soc_dapm_enable_pin(dapm, "DMIC1"); | ||
| 124 | snd_soc_dapm_enable_pin(dapm, "DMIC2"); | ||
| 125 | |||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* broadwell digital audio interface glue - connects codec <--> CPU */ | ||
| 130 | static struct snd_soc_dai_link broadwell_rt286_dais[] = { | ||
| 131 | /* Front End DAI links */ | ||
| 132 | { | ||
| 133 | .name = "System PCM", | ||
| 134 | .stream_name = "System Playback", | ||
| 135 | .cpu_dai_name = "System Pin", | ||
| 136 | .platform_name = "haswell-pcm-audio", | ||
| 137 | .dynamic = 1, | ||
| 138 | .codec_name = "snd-soc-dummy", | ||
| 139 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 140 | .init = broadwell_rtd_init, | ||
| 141 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 142 | .dpcm_playback = 1, | ||
| 143 | }, | ||
| 144 | { | ||
| 145 | .name = "Offload0", | ||
| 146 | .stream_name = "Offload0 Playback", | ||
| 147 | .cpu_dai_name = "Offload0 Pin", | ||
| 148 | .platform_name = "haswell-pcm-audio", | ||
| 149 | .dynamic = 1, | ||
| 150 | .codec_name = "snd-soc-dummy", | ||
| 151 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 152 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 153 | .dpcm_playback = 1, | ||
| 154 | }, | ||
| 155 | { | ||
| 156 | .name = "Offload1", | ||
| 157 | .stream_name = "Offload1 Playback", | ||
| 158 | .cpu_dai_name = "Offload1 Pin", | ||
| 159 | .platform_name = "haswell-pcm-audio", | ||
| 160 | .dynamic = 1, | ||
| 161 | .codec_name = "snd-soc-dummy", | ||
| 162 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 163 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 164 | .dpcm_playback = 1, | ||
| 165 | }, | ||
| 166 | { | ||
| 167 | .name = "Loopback PCM", | ||
| 168 | .stream_name = "Loopback", | ||
| 169 | .cpu_dai_name = "Loopback Pin", | ||
| 170 | .platform_name = "haswell-pcm-audio", | ||
| 171 | .dynamic = 0, | ||
| 172 | .codec_name = "snd-soc-dummy", | ||
| 173 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 174 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 175 | .dpcm_capture = 1, | ||
| 176 | }, | ||
| 177 | { | ||
| 178 | .name = "Capture PCM", | ||
| 179 | .stream_name = "Capture", | ||
| 180 | .cpu_dai_name = "Capture Pin", | ||
| 181 | .platform_name = "haswell-pcm-audio", | ||
| 182 | .dynamic = 1, | ||
| 183 | .codec_name = "snd-soc-dummy", | ||
| 184 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 185 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 186 | .dpcm_capture = 1, | ||
| 187 | }, | ||
| 188 | |||
| 189 | /* Back End DAI links */ | ||
| 190 | { | ||
| 191 | /* SSP0 - Codec */ | ||
| 192 | .name = "Codec", | ||
| 193 | .be_id = 0, | ||
| 194 | .cpu_dai_name = "snd-soc-dummy-dai", | ||
| 195 | .platform_name = "snd-soc-dummy", | ||
| 196 | .no_pcm = 1, | ||
| 197 | .codec_name = "i2c-INT343A:00", | ||
| 198 | .codec_dai_name = "rt286-aif1", | ||
| 199 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
| 200 | SND_SOC_DAIFMT_CBS_CFS, | ||
| 201 | .ignore_suspend = 1, | ||
| 202 | .ignore_pmdown_time = 1, | ||
| 203 | .be_hw_params_fixup = broadwell_ssp0_fixup, | ||
| 204 | .ops = &broadwell_rt286_ops, | ||
| 205 | .dpcm_playback = 1, | ||
| 206 | .dpcm_capture = 1, | ||
| 207 | }, | ||
| 208 | }; | ||
| 209 | |||
| 210 | /* broadwell audio machine driver for WPT + RT286S */ | ||
| 211 | static struct snd_soc_card broadwell_rt286 = { | ||
| 212 | .name = "broadwell-rt286", | ||
| 213 | .owner = THIS_MODULE, | ||
| 214 | .dai_link = broadwell_rt286_dais, | ||
| 215 | .num_links = ARRAY_SIZE(broadwell_rt286_dais), | ||
| 216 | .dapm_widgets = broadwell_widgets, | ||
| 217 | .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), | ||
| 218 | .dapm_routes = broadwell_rt286_map, | ||
| 219 | .num_dapm_routes = ARRAY_SIZE(broadwell_rt286_map), | ||
| 220 | .fully_routed = true, | ||
| 221 | }; | ||
| 222 | |||
| 223 | static int broadwell_audio_probe(struct platform_device *pdev) | ||
| 224 | { | ||
| 225 | broadwell_rt286.dev = &pdev->dev; | ||
| 226 | |||
| 227 | return snd_soc_register_card(&broadwell_rt286); | ||
| 228 | } | ||
| 229 | |||
| 230 | static int broadwell_audio_remove(struct platform_device *pdev) | ||
| 231 | { | ||
| 232 | snd_soc_unregister_card(&broadwell_rt286); | ||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | static struct platform_driver broadwell_audio = { | ||
| 237 | .probe = broadwell_audio_probe, | ||
| 238 | .remove = broadwell_audio_remove, | ||
| 239 | .driver = { | ||
| 240 | .name = "broadwell-audio", | ||
| 241 | .owner = THIS_MODULE, | ||
| 242 | }, | ||
| 243 | }; | ||
| 244 | |||
| 245 | module_platform_driver(broadwell_audio) | ||
| 246 | |||
| 247 | /* Module information */ | ||
| 248 | MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); | ||
| 249 | MODULE_DESCRIPTION("Intel SST Audio for WPT/Broadwell"); | ||
| 250 | MODULE_LICENSE("GPL v2"); | ||
| 251 | MODULE_ALIAS("platform:broadwell-audio"); | ||
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index 5cfb41ec3fab..b8b8af571ef1 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c | |||
| @@ -63,14 +63,6 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { | |||
| 63 | .pin = "Headset Mic", | 63 | .pin = "Headset Mic", |
| 64 | .mask = SND_JACK_MICROPHONE, | 64 | .mask = SND_JACK_MICROPHONE, |
| 65 | }, | 65 | }, |
| 66 | { | ||
| 67 | .pin = "Ext Spk", | ||
| 68 | .mask = SND_JACK_LINEOUT, | ||
| 69 | }, | ||
| 70 | { | ||
| 71 | .pin = "Int Mic", | ||
| 72 | .mask = SND_JACK_LINEIN, | ||
| 73 | }, | ||
| 74 | }; | 66 | }; |
| 75 | 67 | ||
| 76 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { | 68 | static struct snd_soc_jack_gpio hs_jack_gpios[] = { |
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 53d160d39972..234a58de3c53 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c | |||
| @@ -34,6 +34,7 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | |||
| 34 | }; | 34 | }; |
| 35 | 35 | ||
| 36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | 36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { |
| 37 | {"Headset Mic", NULL, "MICBIAS1"}, | ||
| 37 | {"IN2P", NULL, "Headset Mic"}, | 38 | {"IN2P", NULL, "Headset Mic"}, |
| 38 | {"IN2N", NULL, "Headset Mic"}, | 39 | {"IN2N", NULL, "Headset Mic"}, |
| 39 | {"DMIC1", NULL, "Internal Mic"}, | 40 | {"DMIC1", NULL, "Internal Mic"}, |
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h new file mode 100644 index 000000000000..14063ab8c7c5 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013-14 Intel Corp | ||
| 3 | * Author: Ramesh Babu <ramesh.babu.koul@intel.com> | ||
| 4 | * Omair M Abdullah <omair.m.abdullah@intel.com> | ||
| 5 | * Samreen Nilofer <samreen.nilofer@intel.com> | ||
| 6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 18 | * | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __SST_CONTROLS_V2_H__ | ||
| 22 | #define __SST_CONTROLS_V2_H__ | ||
| 23 | |||
| 24 | enum { | ||
| 25 | MERR_DPCM_AUDIO = 0, | ||
| 26 | MERR_DPCM_COMPR, | ||
| 27 | }; | ||
| 28 | |||
| 29 | |||
| 30 | #endif | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index d207b22ea330..67673a2c0f41 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
| @@ -122,6 +122,26 @@ struct sst_byt_tstamp { | |||
| 122 | u32 channel_peak[8]; | 122 | u32 channel_peak[8]; |
| 123 | } __packed; | 123 | } __packed; |
| 124 | 124 | ||
| 125 | struct sst_byt_fw_version { | ||
| 126 | u8 build; | ||
| 127 | u8 minor; | ||
| 128 | u8 major; | ||
| 129 | u8 type; | ||
| 130 | } __packed; | ||
| 131 | |||
| 132 | struct sst_byt_fw_build_info { | ||
| 133 | u8 date[16]; | ||
| 134 | u8 time[16]; | ||
| 135 | } __packed; | ||
| 136 | |||
| 137 | struct sst_byt_fw_init { | ||
| 138 | struct sst_byt_fw_version fw_version; | ||
| 139 | struct sst_byt_fw_build_info build_info; | ||
| 140 | u16 result; | ||
| 141 | u8 module_id; | ||
| 142 | u8 debug_info; | ||
| 143 | } __packed; | ||
| 144 | |||
| 125 | /* driver internal IPC message structure */ | 145 | /* driver internal IPC message structure */ |
| 126 | struct ipc_message { | 146 | struct ipc_message { |
| 127 | struct list_head list; | 147 | struct list_head list; |
| @@ -868,6 +888,7 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 868 | { | 888 | { |
| 869 | struct sst_byt *byt; | 889 | struct sst_byt *byt; |
| 870 | struct sst_fw *byt_sst_fw; | 890 | struct sst_fw *byt_sst_fw; |
| 891 | struct sst_byt_fw_init init; | ||
| 871 | int err; | 892 | int err; |
| 872 | 893 | ||
| 873 | dev_dbg(dev, "initialising Byt DSP IPC\n"); | 894 | dev_dbg(dev, "initialising Byt DSP IPC\n"); |
| @@ -929,6 +950,15 @@ int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 929 | goto boot_err; | 950 | goto boot_err; |
| 930 | } | 951 | } |
| 931 | 952 | ||
| 953 | /* show firmware information */ | ||
| 954 | sst_dsp_inbox_read(byt->dsp, &init, sizeof(init)); | ||
| 955 | dev_info(byt->dev, "FW version: %02x.%02x.%02x.%02x\n", | ||
| 956 | init.fw_version.major, init.fw_version.minor, | ||
| 957 | init.fw_version.build, init.fw_version.type); | ||
| 958 | dev_info(byt->dev, "Build type: %x\n", init.fw_version.type); | ||
| 959 | dev_info(byt->dev, "Build date: %s %s\n", | ||
| 960 | init.build_info.date, init.build_info.time); | ||
| 961 | |||
| 932 | pdata->dsp = byt; | 962 | pdata->dsp = byt; |
| 933 | byt->fw = byt_sst_fw; | 963 | byt->fw = byt_sst_fw; |
| 934 | 964 | ||
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index 0b715b20a2d7..cd23060a0d86 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c | |||
| @@ -224,19 +224,23 @@ EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); | |||
| 224 | 224 | ||
| 225 | void sst_dsp_dump(struct sst_dsp *sst) | 225 | void sst_dsp_dump(struct sst_dsp *sst) |
| 226 | { | 226 | { |
| 227 | sst->ops->dump(sst); | 227 | if (sst->ops->dump) |
| 228 | sst->ops->dump(sst); | ||
| 228 | } | 229 | } |
| 229 | EXPORT_SYMBOL_GPL(sst_dsp_dump); | 230 | EXPORT_SYMBOL_GPL(sst_dsp_dump); |
| 230 | 231 | ||
| 231 | void sst_dsp_reset(struct sst_dsp *sst) | 232 | void sst_dsp_reset(struct sst_dsp *sst) |
| 232 | { | 233 | { |
| 233 | sst->ops->reset(sst); | 234 | if (sst->ops->reset) |
| 235 | sst->ops->reset(sst); | ||
| 234 | } | 236 | } |
| 235 | EXPORT_SYMBOL_GPL(sst_dsp_reset); | 237 | EXPORT_SYMBOL_GPL(sst_dsp_reset); |
| 236 | 238 | ||
| 237 | int sst_dsp_boot(struct sst_dsp *sst) | 239 | int sst_dsp_boot(struct sst_dsp *sst) |
| 238 | { | 240 | { |
| 239 | sst->ops->boot(sst); | 241 | if (sst->ops->boot) |
| 242 | sst->ops->boot(sst); | ||
| 243 | |||
| 240 | return 0; | 244 | return 0; |
| 241 | } | 245 | } |
| 242 | EXPORT_SYMBOL_GPL(sst_dsp_boot); | 246 | EXPORT_SYMBOL_GPL(sst_dsp_boot); |
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index e44423be66c4..3165dfa97408 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h | |||
| @@ -52,7 +52,11 @@ | |||
| 52 | #define SST_CLKCTL 0x78 | 52 | #define SST_CLKCTL 0x78 |
| 53 | #define SST_CSR2 0x80 | 53 | #define SST_CSR2 0x80 |
| 54 | #define SST_LTRC 0xE0 | 54 | #define SST_LTRC 0xE0 |
| 55 | #define SST_HDMC 0xE8 | 55 | #define SST_HMDC 0xE8 |
| 56 | |||
| 57 | #define SST_SHIM_BEGIN SST_CSR | ||
| 58 | #define SST_SHIM_END SST_HDMC | ||
| 59 | |||
| 56 | #define SST_DBGO 0xF0 | 60 | #define SST_DBGO 0xF0 |
| 57 | 61 | ||
| 58 | #define SST_SHIM_SIZE 0x100 | 62 | #define SST_SHIM_SIZE 0x100 |
| @@ -73,6 +77,8 @@ | |||
| 73 | #define SST_CSR_S0IOCS (0x1 << 21) | 77 | #define SST_CSR_S0IOCS (0x1 << 21) |
| 74 | #define SST_CSR_S1IOCS (0x1 << 23) | 78 | #define SST_CSR_S1IOCS (0x1 << 23) |
| 75 | #define SST_CSR_LPCS (0x1 << 31) | 79 | #define SST_CSR_LPCS (0x1 << 31) |
| 80 | #define SST_CSR_24MHZ_LPCS (SST_CSR_SBCS0 | SST_CSR_SBCS1 | SST_CSR_LPCS) | ||
| 81 | #define SST_CSR_24MHZ_NO_LPCS (SST_CSR_SBCS0 | SST_CSR_SBCS1) | ||
| 76 | #define SST_BYT_CSR_RST (0x1 << 0) | 82 | #define SST_BYT_CSR_RST (0x1 << 0) |
| 77 | #define SST_BYT_CSR_VECTOR_SEL (0x1 << 1) | 83 | #define SST_BYT_CSR_VECTOR_SEL (0x1 << 1) |
| 78 | #define SST_BYT_CSR_STALL (0x1 << 2) | 84 | #define SST_BYT_CSR_STALL (0x1 << 2) |
| @@ -92,6 +98,14 @@ | |||
| 92 | #define SST_IMRX_DONE (0x1 << 0) | 98 | #define SST_IMRX_DONE (0x1 << 0) |
| 93 | #define SST_BYT_IMRX_REQUEST (0x1 << 1) | 99 | #define SST_BYT_IMRX_REQUEST (0x1 << 1) |
| 94 | 100 | ||
| 101 | /* IMRD / IMD */ | ||
| 102 | #define SST_IMRD_DONE (0x1 << 0) | ||
| 103 | #define SST_IMRD_BUSY (0x1 << 1) | ||
| 104 | #define SST_IMRD_SSP0 (0x1 << 16) | ||
| 105 | #define SST_IMRD_DMAC0 (0x1 << 21) | ||
| 106 | #define SST_IMRD_DMAC1 (0x1 << 22) | ||
| 107 | #define SST_IMRD_DMAC (SST_IMRD_DMAC0 | SST_IMRD_DMAC1) | ||
| 108 | |||
| 95 | /* IPCX / IPCC */ | 109 | /* IPCX / IPCC */ |
| 96 | #define SST_IPCX_DONE (0x1 << 30) | 110 | #define SST_IPCX_DONE (0x1 << 30) |
| 97 | #define SST_IPCX_BUSY (0x1 << 31) | 111 | #define SST_IPCX_BUSY (0x1 << 31) |
| @@ -118,9 +132,21 @@ | |||
| 118 | /* LTRC */ | 132 | /* LTRC */ |
| 119 | #define SST_LTRC_VAL(x) (x << 0) | 133 | #define SST_LTRC_VAL(x) (x << 0) |
| 120 | 134 | ||
| 121 | /* HDMC */ | 135 | /* HMDC */ |
| 122 | #define SST_HDMC_HDDA0(x) (x << 0) | 136 | #define SST_HMDC_HDDA0(x) (x << 0) |
| 123 | #define SST_HDMC_HDDA1(x) (x << 7) | 137 | #define SST_HMDC_HDDA1(x) (x << 7) |
| 138 | #define SST_HMDC_HDDA_E0_CH0 1 | ||
| 139 | #define SST_HMDC_HDDA_E0_CH1 2 | ||
| 140 | #define SST_HMDC_HDDA_E0_CH2 4 | ||
| 141 | #define SST_HMDC_HDDA_E0_CH3 8 | ||
| 142 | #define SST_HMDC_HDDA_E1_CH0 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH0) | ||
| 143 | #define SST_HMDC_HDDA_E1_CH1 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH1) | ||
| 144 | #define SST_HMDC_HDDA_E1_CH2 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH2) | ||
| 145 | #define SST_HMDC_HDDA_E1_CH3 SST_HMDC_HDDA1(SST_HMDC_HDDA_E0_CH3) | ||
| 146 | #define SST_HMDC_HDDA_E0_ALLCH (SST_HMDC_HDDA_E0_CH0 | SST_HMDC_HDDA_E0_CH1 | \ | ||
| 147 | SST_HMDC_HDDA_E0_CH2 | SST_HMDC_HDDA_E0_CH3) | ||
| 148 | #define SST_HMDC_HDDA_E1_ALLCH (SST_HMDC_HDDA_E1_CH0 | SST_HMDC_HDDA_E1_CH1 | \ | ||
| 149 | SST_HMDC_HDDA_E1_CH2 | SST_HMDC_HDDA_E1_CH3) | ||
| 124 | 150 | ||
| 125 | 151 | ||
| 126 | /* SST Vendor Defined Registers and bits */ | 152 | /* SST Vendor Defined Registers and bits */ |
| @@ -130,11 +156,16 @@ | |||
| 130 | #define SST_VDRTCTL3 0xaC | 156 | #define SST_VDRTCTL3 0xaC |
| 131 | 157 | ||
| 132 | /* VDRTCTL0 */ | 158 | /* VDRTCTL0 */ |
| 159 | #define SST_VDRTCL0_APLLSE_MASK 1 | ||
| 133 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 | 160 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 |
| 134 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) | 161 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) |
| 135 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 | 162 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 |
| 136 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) | 163 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) |
| 137 | 164 | ||
| 165 | /* PMCS */ | ||
| 166 | #define SST_PMCS 0x84 | ||
| 167 | #define SST_PMCS_PS_MASK 0x3 | ||
| 168 | |||
| 138 | struct sst_dsp; | 169 | struct sst_dsp; |
| 139 | 170 | ||
| 140 | /* | 171 | /* |
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index a33b931181dc..4b6c163c10ff 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
| @@ -28,9 +28,6 @@ | |||
| 28 | #include <linux/firmware.h> | 28 | #include <linux/firmware.h> |
| 29 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
| 30 | 30 | ||
| 31 | #include <linux/acpi.h> | ||
| 32 | #include <acpi/acpi_bus.h> | ||
| 33 | |||
| 34 | #include "sst-dsp.h" | 31 | #include "sst-dsp.h" |
| 35 | #include "sst-dsp-priv.h" | 32 | #include "sst-dsp-priv.h" |
| 36 | #include "sst-haswell-ipc.h" | 33 | #include "sst-haswell-ipc.h" |
| @@ -272,9 +269,9 @@ static void hsw_boot(struct sst_dsp *sst) | |||
| 272 | SST_CSR2_SDFD_SSP1); | 269 | SST_CSR2_SDFD_SSP1); |
| 273 | 270 | ||
| 274 | /* enable DMA engine 0,1 all channels to access host memory */ | 271 | /* enable DMA engine 0,1 all channels to access host memory */ |
| 275 | sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC, | 272 | sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC, |
| 276 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff), | 273 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff), |
| 277 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff)); | 274 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff)); |
| 278 | 275 | ||
| 279 | /* disable all clock gating */ | 276 | /* disable all clock gating */ |
| 280 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); | 277 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); |
| @@ -313,9 +310,7 @@ static const struct sst_adsp_memregion lp_region[] = { | |||
| 313 | 310 | ||
| 314 | /* wild cat point ADSP mem regions */ | 311 | /* wild cat point ADSP mem regions */ |
| 315 | static const struct sst_adsp_memregion wpt_region[] = { | 312 | static const struct sst_adsp_memregion wpt_region[] = { |
| 316 | {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | 313 | {0x00000, 0xA0000, 20, SST_MEM_DRAM}, /* D-SRAM0,D-SRAM1,D-SRAM2 - 20 * 32kB */ |
| 317 | {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */ | ||
| 318 | {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */ | ||
| 319 | {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */ | 314 | {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */ |
| 320 | }; | 315 | }; |
| 321 | 316 | ||
| @@ -339,21 +334,40 @@ static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
| 339 | return 0; | 334 | return 0; |
| 340 | } | 335 | } |
| 341 | 336 | ||
| 337 | struct sst_sram_shift { | ||
| 338 | u32 dev_id; /* SST Device IDs */ | ||
| 339 | u32 iram_shift; | ||
| 340 | u32 dram_shift; | ||
| 341 | }; | ||
| 342 | |||
| 343 | static const struct sst_sram_shift sram_shift[] = { | ||
| 344 | {SST_DEV_ID_LYNX_POINT, 6, 16}, /* lp */ | ||
| 345 | {SST_DEV_ID_WILDCAT_POINT, 2, 12}, /* wpt */ | ||
| 346 | }; | ||
| 342 | static u32 hsw_block_get_bit(struct sst_mem_block *block) | 347 | static u32 hsw_block_get_bit(struct sst_mem_block *block) |
| 343 | { | 348 | { |
| 344 | u32 bit = 0, shift = 0; | 349 | u32 bit = 0, shift = 0, index; |
| 350 | struct sst_dsp *sst = block->dsp; | ||
| 345 | 351 | ||
| 346 | switch (block->type) { | 352 | for (index = 0; index < ARRAY_SIZE(sram_shift); index++) { |
| 347 | case SST_MEM_DRAM: | 353 | if (sram_shift[index].dev_id == sst->id) |
| 348 | shift = 16; | 354 | break; |
| 349 | break; | ||
| 350 | case SST_MEM_IRAM: | ||
| 351 | shift = 6; | ||
| 352 | break; | ||
| 353 | default: | ||
| 354 | return 0; | ||
| 355 | } | 355 | } |
| 356 | 356 | ||
| 357 | if (index < ARRAY_SIZE(sram_shift)) { | ||
| 358 | switch (block->type) { | ||
| 359 | case SST_MEM_DRAM: | ||
| 360 | shift = sram_shift[index].dram_shift; | ||
| 361 | break; | ||
| 362 | case SST_MEM_IRAM: | ||
| 363 | shift = sram_shift[index].iram_shift; | ||
| 364 | break; | ||
| 365 | default: | ||
| 366 | shift = 0; | ||
| 367 | } | ||
| 368 | } else | ||
| 369 | shift = 0; | ||
| 370 | |||
| 357 | bit = 1 << (block->index + shift); | 371 | bit = 1 << (block->index + shift); |
| 358 | 372 | ||
| 359 | return bit; | 373 | return bit; |
| @@ -501,8 +515,9 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
| 501 | } | 515 | } |
| 502 | } | 516 | } |
| 503 | 517 | ||
| 504 | /* set default power gating mask */ | 518 | /* set default power gating control, enable power gating control for all blocks. that is, |
| 505 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0); | 519 | can't be accessed, please enable each block before accessing. */ |
| 520 | writel(0xffffffff, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
| 506 | 521 | ||
| 507 | return 0; | 522 | return 0; |
| 508 | } | 523 | } |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index 434236343ddf..b6291516dbbf 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
| @@ -183,7 +183,7 @@ struct sst_hsw_ipc_fw_ready { | |||
| 183 | u32 inbox_size; | 183 | u32 inbox_size; |
| 184 | u32 outbox_size; | 184 | u32 outbox_size; |
| 185 | u32 fw_info_size; | 185 | u32 fw_info_size; |
| 186 | u8 fw_info[1]; | 186 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; |
| 187 | } __attribute__((packed)); | 187 | } __attribute__((packed)); |
| 188 | 188 | ||
| 189 | struct ipc_message { | 189 | struct ipc_message { |
| @@ -457,9 +457,10 @@ static void ipc_tx_msgs(struct kthread_work *work) | |||
| 457 | return; | 457 | return; |
| 458 | } | 458 | } |
| 459 | 459 | ||
| 460 | /* if the DSP is busy we will TX messages after IRQ */ | 460 | /* if the DSP is busy, we will TX messages after IRQ. |
| 461 | * also postpone if we are in the middle of procesing completion irq*/ | ||
| 461 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); | 462 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); |
| 462 | if (ipcx & SST_IPCX_BUSY) { | 463 | if (ipcx & (SST_IPCX_BUSY | SST_IPCX_DONE)) { |
| 463 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | 464 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); |
| 464 | return; | 465 | return; |
| 465 | } | 466 | } |
| @@ -502,6 +503,7 @@ static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg, | |||
| 502 | ipc_shim_dbg(hsw, "message timeout"); | 503 | ipc_shim_dbg(hsw, "message timeout"); |
| 503 | 504 | ||
| 504 | trace_ipc_error("error message timeout for", msg->header); | 505 | trace_ipc_error("error message timeout for", msg->header); |
| 506 | list_del(&msg->list); | ||
| 505 | ret = -ETIMEDOUT; | 507 | ret = -ETIMEDOUT; |
| 506 | } else { | 508 | } else { |
| 507 | 509 | ||
| @@ -569,6 +571,9 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | |||
| 569 | { | 571 | { |
| 570 | struct sst_hsw_ipc_fw_ready fw_ready; | 572 | struct sst_hsw_ipc_fw_ready fw_ready; |
| 571 | u32 offset; | 573 | u32 offset; |
| 574 | u8 fw_info[IPC_MAX_MAILBOX_BYTES - 5 * sizeof(u32)]; | ||
| 575 | char *tmp[5], *pinfo; | ||
| 576 | int i = 0; | ||
| 572 | 577 | ||
| 573 | offset = (header & 0x1FFFFFFF) << 3; | 578 | offset = (header & 0x1FFFFFFF) << 3; |
| 574 | 579 | ||
| @@ -589,6 +594,19 @@ static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | |||
| 589 | fw_ready.inbox_offset, fw_ready.inbox_size); | 594 | fw_ready.inbox_offset, fw_ready.inbox_size); |
| 590 | dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n", | 595 | dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n", |
| 591 | fw_ready.outbox_offset, fw_ready.outbox_size); | 596 | fw_ready.outbox_offset, fw_ready.outbox_size); |
| 597 | if (fw_ready.fw_info_size < sizeof(fw_ready.fw_info)) { | ||
| 598 | fw_ready.fw_info[fw_ready.fw_info_size] = 0; | ||
| 599 | dev_dbg(hsw->dev, " Firmware info: %s \n", fw_ready.fw_info); | ||
| 600 | |||
| 601 | /* log the FW version info got from the mailbox here. */ | ||
| 602 | memcpy(fw_info, fw_ready.fw_info, fw_ready.fw_info_size); | ||
| 603 | pinfo = &fw_info[0]; | ||
| 604 | for (i = 0; i < sizeof(tmp) / sizeof(char *); i++) | ||
| 605 | tmp[i] = strsep(&pinfo, " "); | ||
| 606 | dev_info(hsw->dev, "FW loaded, mailbox readback FW info: type %s, - " | ||
| 607 | "version: %s.%s, build %s, source commit id: %s\n", | ||
| 608 | tmp[0], tmp[1], tmp[2], tmp[3], tmp[4]); | ||
| 609 | } | ||
| 592 | } | 610 | } |
| 593 | 611 | ||
| 594 | static void hsw_notification_work(struct work_struct *work) | 612 | static void hsw_notification_work(struct work_struct *work) |
| @@ -671,7 +689,9 @@ static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) | |||
| 671 | switch (stream_msg) { | 689 | switch (stream_msg) { |
| 672 | case IPC_STR_STAGE_MESSAGE: | 690 | case IPC_STR_STAGE_MESSAGE: |
| 673 | case IPC_STR_NOTIFICATION: | 691 | case IPC_STR_NOTIFICATION: |
| 692 | break; | ||
| 674 | case IPC_STR_RESET: | 693 | case IPC_STR_RESET: |
| 694 | trace_ipc_notification("stream reset", stream->reply.stream_hw_id); | ||
| 675 | break; | 695 | break; |
| 676 | case IPC_STR_PAUSE: | 696 | case IPC_STR_PAUSE: |
| 677 | stream->running = false; | 697 | stream->running = false; |
| @@ -762,7 +782,8 @@ static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | |||
| 762 | } | 782 | } |
| 763 | 783 | ||
| 764 | /* update any stream states */ | 784 | /* update any stream states */ |
| 765 | hsw_stream_update(hsw, msg); | 785 | if (msg_get_global_type(header) == IPC_GLB_STREAM_MESSAGE) |
| 786 | hsw_stream_update(hsw, msg); | ||
| 766 | 787 | ||
| 767 | /* wake up and return the error if we have waiters on this message ? */ | 788 | /* wake up and return the error if we have waiters on this message ? */ |
| 768 | list_del(&msg->list); | 789 | list_del(&msg->list); |
| @@ -1628,7 +1649,7 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
| 1628 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) | 1649 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) |
| 1629 | { | 1650 | { |
| 1630 | u32 header, state_; | 1651 | u32 header, state_; |
| 1631 | int ret; | 1652 | int ret, item; |
| 1632 | 1653 | ||
| 1633 | header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); | 1654 | header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); |
| 1634 | state_ = state; | 1655 | state_ = state; |
| @@ -1642,6 +1663,13 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
| 1642 | return ret; | 1663 | return ret; |
| 1643 | } | 1664 | } |
| 1644 | 1665 | ||
| 1666 | for (item = 0; item < dx->entries_no; item++) { | ||
| 1667 | dev_dbg(hsw->dev, | ||
| 1668 | "Item[%d] offset[%x] - size[%x] - source[%x]\n", | ||
| 1669 | item, dx->mem_info[item].offset, | ||
| 1670 | dx->mem_info[item].size, | ||
| 1671 | dx->mem_info[item].source); | ||
| 1672 | } | ||
| 1645 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", | 1673 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", |
| 1646 | dx->entries_no, state); | 1674 | dx->entries_no, state); |
| 1647 | 1675 | ||
| @@ -1775,8 +1803,6 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
| 1775 | 1803 | ||
| 1776 | /* get the FW version */ | 1804 | /* get the FW version */ |
| 1777 | sst_hsw_fw_get_version(hsw, &version); | 1805 | sst_hsw_fw_get_version(hsw, &version); |
| 1778 | dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n", | ||
| 1779 | version.type, version.major, version.minor, version.build); | ||
| 1780 | 1806 | ||
| 1781 | /* get the globalmixer */ | 1807 | /* get the globalmixer */ |
| 1782 | ret = sst_hsw_mixer_get_info(hsw); | 1808 | ret = sst_hsw_mixer_get_info(hsw); |
diff --git a/sound/soc/intel/sst-mfld-dsp.h b/sound/soc/intel/sst-mfld-dsp.h index 8d482d76475a..4257263157cd 100644 --- a/sound/soc/intel/sst-mfld-dsp.h +++ b/sound/soc/intel/sst-mfld-dsp.h | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | /* | 3 | /* |
| 4 | * sst_mfld_dsp.h - Intel SST Driver for audio engine | 4 | * sst_mfld_dsp.h - Intel SST Driver for audio engine |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2008-12 Intel Corporation | 6 | * Copyright (C) 2008-14 Intel Corporation |
| 7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> | 7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> |
| 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 9 | * | 9 | * |
| @@ -19,6 +19,142 @@ | |||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #define SST_MAX_BIN_BYTES 1024 | ||
| 23 | |||
| 24 | #define MAX_DBG_RW_BYTES 80 | ||
| 25 | #define MAX_NUM_SCATTER_BUFFERS 8 | ||
| 26 | #define MAX_LOOP_BACK_DWORDS 8 | ||
| 27 | /* IPC base address and mailbox, timestamp offsets */ | ||
| 28 | #define SST_MAILBOX_SIZE 0x0400 | ||
| 29 | #define SST_MAILBOX_SEND 0x0000 | ||
| 30 | #define SST_TIME_STAMP 0x1800 | ||
| 31 | #define SST_TIME_STAMP_MRFLD 0x800 | ||
| 32 | #define SST_RESERVED_OFFSET 0x1A00 | ||
| 33 | #define SST_SCU_LPE_MAILBOX 0x1000 | ||
| 34 | #define SST_LPE_SCU_MAILBOX 0x1400 | ||
| 35 | #define SST_SCU_LPE_LOG_BUF (SST_SCU_LPE_MAILBOX+16) | ||
| 36 | #define PROCESS_MSG 0x80 | ||
| 37 | |||
| 38 | /* Message ID's for IPC messages */ | ||
| 39 | /* Bits B7: SST or IA/SC ; B6-B4: Msg Category; B3-B0: Msg Type */ | ||
| 40 | |||
| 41 | /* I2L Firmware/Codec Download msgs */ | ||
| 42 | #define IPC_IA_PREP_LIB_DNLD 0x01 | ||
| 43 | #define IPC_IA_LIB_DNLD_CMPLT 0x02 | ||
| 44 | #define IPC_IA_GET_FW_VERSION 0x04 | ||
| 45 | #define IPC_IA_GET_FW_BUILD_INF 0x05 | ||
| 46 | #define IPC_IA_GET_FW_INFO 0x06 | ||
| 47 | #define IPC_IA_GET_FW_CTXT 0x07 | ||
| 48 | #define IPC_IA_SET_FW_CTXT 0x08 | ||
| 49 | #define IPC_IA_PREPARE_SHUTDOWN 0x31 | ||
| 50 | /* I2L Codec Config/control msgs */ | ||
| 51 | #define IPC_PREP_D3 0x10 | ||
| 52 | #define IPC_IA_SET_CODEC_PARAMS 0x10 | ||
| 53 | #define IPC_IA_GET_CODEC_PARAMS 0x11 | ||
| 54 | #define IPC_IA_SET_PPP_PARAMS 0x12 | ||
| 55 | #define IPC_IA_GET_PPP_PARAMS 0x13 | ||
| 56 | #define IPC_SST_PERIOD_ELAPSED_MRFLD 0xA | ||
| 57 | #define IPC_IA_ALG_PARAMS 0x1A | ||
| 58 | #define IPC_IA_TUNING_PARAMS 0x1B | ||
| 59 | #define IPC_IA_SET_RUNTIME_PARAMS 0x1C | ||
| 60 | #define IPC_IA_SET_PARAMS 0x1 | ||
| 61 | #define IPC_IA_GET_PARAMS 0x2 | ||
| 62 | |||
| 63 | #define IPC_EFFECTS_CREATE 0xE | ||
| 64 | #define IPC_EFFECTS_DESTROY 0xF | ||
| 65 | |||
| 66 | /* I2L Stream config/control msgs */ | ||
| 67 | #define IPC_IA_ALLOC_STREAM_MRFLD 0x2 | ||
| 68 | #define IPC_IA_ALLOC_STREAM 0x20 /* Allocate a stream ID */ | ||
| 69 | #define IPC_IA_FREE_STREAM_MRFLD 0x03 | ||
| 70 | #define IPC_IA_FREE_STREAM 0x21 /* Free the stream ID */ | ||
| 71 | #define IPC_IA_SET_STREAM_PARAMS 0x22 | ||
| 72 | #define IPC_IA_SET_STREAM_PARAMS_MRFLD 0x12 | ||
| 73 | #define IPC_IA_GET_STREAM_PARAMS 0x23 | ||
| 74 | #define IPC_IA_PAUSE_STREAM 0x24 | ||
| 75 | #define IPC_IA_PAUSE_STREAM_MRFLD 0x4 | ||
| 76 | #define IPC_IA_RESUME_STREAM 0x25 | ||
| 77 | #define IPC_IA_RESUME_STREAM_MRFLD 0x5 | ||
| 78 | #define IPC_IA_DROP_STREAM 0x26 | ||
| 79 | #define IPC_IA_DROP_STREAM_MRFLD 0x07 | ||
| 80 | #define IPC_IA_DRAIN_STREAM 0x27 /* Short msg with str_id */ | ||
| 81 | #define IPC_IA_DRAIN_STREAM_MRFLD 0x8 | ||
| 82 | #define IPC_IA_CONTROL_ROUTING 0x29 | ||
| 83 | #define IPC_IA_VTSV_UPDATE_MODULES 0x20 | ||
| 84 | #define IPC_IA_VTSV_DETECTED 0x21 | ||
| 85 | |||
| 86 | #define IPC_IA_START_STREAM_MRFLD 0X06 | ||
| 87 | #define IPC_IA_START_STREAM 0x30 /* Short msg with str_id */ | ||
| 88 | |||
| 89 | #define IPC_IA_SET_GAIN_MRFLD 0x21 | ||
| 90 | /* Debug msgs */ | ||
| 91 | #define IPC_IA_DBG_MEM_READ 0x40 | ||
| 92 | #define IPC_IA_DBG_MEM_WRITE 0x41 | ||
| 93 | #define IPC_IA_DBG_LOOP_BACK 0x42 | ||
| 94 | #define IPC_IA_DBG_LOG_ENABLE 0x45 | ||
| 95 | #define IPC_IA_DBG_SET_PROBE_PARAMS 0x47 | ||
| 96 | |||
| 97 | /* L2I Firmware/Codec Download msgs */ | ||
| 98 | #define IPC_IA_FW_INIT_CMPLT 0x81 | ||
| 99 | #define IPC_IA_FW_INIT_CMPLT_MRFLD 0x01 | ||
| 100 | #define IPC_IA_FW_ASYNC_ERR_MRFLD 0x11 | ||
| 101 | |||
| 102 | /* L2I Codec Config/control msgs */ | ||
| 103 | #define IPC_SST_FRAGMENT_ELPASED 0x90 /* Request IA more data */ | ||
| 104 | |||
| 105 | #define IPC_SST_BUF_UNDER_RUN 0x92 /* PB Under run and stopped */ | ||
| 106 | #define IPC_SST_BUF_OVER_RUN 0x93 /* CAP Under run and stopped */ | ||
| 107 | #define IPC_SST_DRAIN_END 0x94 /* PB Drain complete and stopped */ | ||
| 108 | #define IPC_SST_CHNGE_SSP_PARAMS 0x95 /* PB SSP parameters changed */ | ||
| 109 | #define IPC_SST_STREAM_PROCESS_FATAL_ERR 0x96/* error in processing a stream */ | ||
| 110 | #define IPC_SST_PERIOD_ELAPSED 0x97 /* period elapsed */ | ||
| 111 | |||
| 112 | #define IPC_SST_ERROR_EVENT 0x99 /* Buffer over run occurred */ | ||
| 113 | /* L2S messages */ | ||
| 114 | #define IPC_SC_DDR_LINK_UP 0xC0 | ||
| 115 | #define IPC_SC_DDR_LINK_DOWN 0xC1 | ||
| 116 | #define IPC_SC_SET_LPECLK_REQ 0xC2 | ||
| 117 | #define IPC_SC_SSP_BIT_BANG 0xC3 | ||
| 118 | |||
| 119 | /* L2I Error reporting msgs */ | ||
| 120 | #define IPC_IA_MEM_ALLOC_FAIL 0xE0 | ||
| 121 | #define IPC_IA_PROC_ERR 0xE1 /* error in processing a | ||
| 122 | stream can be used by playback and | ||
| 123 | capture modules */ | ||
| 124 | |||
| 125 | /* L2I Debug msgs */ | ||
| 126 | #define IPC_IA_PRINT_STRING 0xF0 | ||
| 127 | |||
| 128 | /* Buffer under-run */ | ||
| 129 | #define IPC_IA_BUF_UNDER_RUN_MRFLD 0x0B | ||
| 130 | |||
| 131 | /* Mrfld specific defines: | ||
| 132 | * For asynchronous messages(INIT_CMPLT, PERIOD_ELAPSED, ASYNC_ERROR) | ||
| 133 | * received from FW, the format is: | ||
| 134 | * - IPC High: pvt_id is set to zero. Always short message. | ||
| 135 | * - msg_id is in lower 16-bits of IPC low payload. | ||
| 136 | * - pipe_id is in higher 16-bits of IPC low payload for period_elapsed. | ||
| 137 | * - error id is in higher 16-bits of IPC low payload for async errors. | ||
| 138 | */ | ||
| 139 | #define SST_ASYNC_DRV_ID 0 | ||
| 140 | |||
| 141 | /* Command Response or Acknowledge message to any IPC message will have | ||
| 142 | * same message ID and stream ID information which is sent. | ||
| 143 | * There is no specific Ack message ID. The data field is used as response | ||
| 144 | * meaning. | ||
| 145 | */ | ||
| 146 | enum ackData { | ||
| 147 | IPC_ACK_SUCCESS = 0, | ||
| 148 | IPC_ACK_FAILURE, | ||
| 149 | }; | ||
| 150 | |||
| 151 | enum ipc_ia_msg_id { | ||
| 152 | IPC_CMD = 1, /*!< Task Control message ID */ | ||
| 153 | IPC_SET_PARAMS = 2,/*!< Task Set param message ID */ | ||
| 154 | IPC_GET_PARAMS = 3, /*!< Task Get param message ID */ | ||
| 155 | IPC_INVALID = 0xFF, /*!<Task Get param message ID */ | ||
| 156 | }; | ||
| 157 | |||
| 22 | enum sst_codec_types { | 158 | enum sst_codec_types { |
| 23 | /* AUDIO/MUSIC CODEC Type Definitions */ | 159 | /* AUDIO/MUSIC CODEC Type Definitions */ |
| 24 | SST_CODEC_TYPE_UNKNOWN = 0, | 160 | SST_CODEC_TYPE_UNKNOWN = 0, |
| @@ -35,14 +171,157 @@ enum stream_type { | |||
| 35 | SST_STREAM_TYPE_MUSIC = 1, | 171 | SST_STREAM_TYPE_MUSIC = 1, |
| 36 | }; | 172 | }; |
| 37 | 173 | ||
| 174 | enum sst_error_codes { | ||
| 175 | /* Error code,response to msgId: Description */ | ||
| 176 | /* Common error codes */ | ||
| 177 | SST_SUCCESS = 0, /* Success */ | ||
| 178 | SST_ERR_INVALID_STREAM_ID = 1, | ||
| 179 | SST_ERR_INVALID_MSG_ID = 2, | ||
| 180 | SST_ERR_INVALID_STREAM_OP = 3, | ||
| 181 | SST_ERR_INVALID_PARAMS = 4, | ||
| 182 | SST_ERR_INVALID_CODEC = 5, | ||
| 183 | SST_ERR_INVALID_MEDIA_TYPE = 6, | ||
| 184 | SST_ERR_STREAM_ERR = 7, | ||
| 185 | |||
| 186 | SST_ERR_STREAM_IN_USE = 15, | ||
| 187 | }; | ||
| 188 | |||
| 189 | struct ipc_dsp_hdr { | ||
| 190 | u16 mod_index_id:8; /*!< DSP Command ID specific to tasks */ | ||
| 191 | u16 pipe_id:8; /*!< instance of the module in the pipeline */ | ||
| 192 | u16 mod_id; /*!< Pipe_id */ | ||
| 193 | u16 cmd_id; /*!< Module ID = lpe_algo_types_t */ | ||
| 194 | u16 length; /*!< Length of the payload only */ | ||
| 195 | } __packed; | ||
| 196 | |||
| 197 | union ipc_header_high { | ||
| 198 | struct { | ||
| 199 | u32 msg_id:8; /* Message ID - Max 256 Message Types */ | ||
| 200 | u32 task_id:4; /* Task ID associated with this comand */ | ||
| 201 | u32 drv_id:4; /* Identifier for the driver to track*/ | ||
| 202 | u32 rsvd1:8; /* Reserved */ | ||
| 203 | u32 result:4; /* Reserved */ | ||
| 204 | u32 res_rqd:1; /* Response rqd */ | ||
| 205 | u32 large:1; /* Large Message if large = 1 */ | ||
| 206 | u32 done:1; /* bit 30 - Done bit */ | ||
| 207 | u32 busy:1; /* bit 31 - busy bit*/ | ||
| 208 | } part; | ||
| 209 | u32 full; | ||
| 210 | } __packed; | ||
| 211 | /* IPC header */ | ||
| 212 | union ipc_header_mrfld { | ||
| 213 | struct { | ||
| 214 | u32 header_low_payload; | ||
| 215 | union ipc_header_high header_high; | ||
| 216 | } p; | ||
| 217 | u64 full; | ||
| 218 | } __packed; | ||
| 219 | /* CAUTION NOTE: All IPC message body must be multiple of 32 bits.*/ | ||
| 220 | |||
| 221 | /* IPC Header */ | ||
| 222 | union ipc_header { | ||
| 223 | struct { | ||
| 224 | u32 msg_id:8; /* Message ID - Max 256 Message Types */ | ||
| 225 | u32 str_id:5; | ||
| 226 | u32 large:1; /* Large Message if large = 1 */ | ||
| 227 | u32 reserved:2; /* Reserved for future use */ | ||
| 228 | u32 data:14; /* Ack/Info for msg, size of msg in Mailbox */ | ||
| 229 | u32 done:1; /* bit 30 */ | ||
| 230 | u32 busy:1; /* bit 31 */ | ||
| 231 | } part; | ||
| 232 | u32 full; | ||
| 233 | } __packed; | ||
| 234 | |||
| 235 | /* Firmware build info */ | ||
| 236 | struct sst_fw_build_info { | ||
| 237 | unsigned char date[16]; /* Firmware build date */ | ||
| 238 | unsigned char time[16]; /* Firmware build time */ | ||
| 239 | } __packed; | ||
| 240 | |||
| 241 | /* Firmware Version info */ | ||
| 242 | struct snd_sst_fw_version { | ||
| 243 | u8 build; /* build number*/ | ||
| 244 | u8 minor; /* minor number*/ | ||
| 245 | u8 major; /* major number*/ | ||
| 246 | u8 type; /* build type */ | ||
| 247 | }; | ||
| 248 | |||
| 249 | struct ipc_header_fw_init { | ||
| 250 | struct snd_sst_fw_version fw_version;/* Firmware version details */ | ||
| 251 | struct sst_fw_build_info build_info; | ||
| 252 | u16 result; /* Fw init result */ | ||
| 253 | u8 module_id; /* Module ID in case of error */ | ||
| 254 | u8 debug_info; /* Debug info from Module ID in case of fail */ | ||
| 255 | } __packed; | ||
| 256 | |||
| 257 | struct snd_sst_tstamp { | ||
| 258 | u64 ring_buffer_counter; /* PB/CP: Bytes copied from/to DDR. */ | ||
| 259 | u64 hardware_counter; /* PB/CP: Bytes DMAed to/from SSP. */ | ||
| 260 | u64 frames_decoded; | ||
| 261 | u64 bytes_decoded; | ||
| 262 | u64 bytes_copied; | ||
| 263 | u32 sampling_frequency; | ||
| 264 | u32 channel_peak[8]; | ||
| 265 | } __packed; | ||
| 266 | |||
| 267 | /* Stream type params struture for Alloc stream */ | ||
| 268 | struct snd_sst_str_type { | ||
| 269 | u8 codec_type; /* Codec type */ | ||
| 270 | u8 str_type; /* 1 = voice 2 = music */ | ||
| 271 | u8 operation; /* Playback or Capture */ | ||
| 272 | u8 protected_str; /* 0=Non DRM, 1=DRM */ | ||
| 273 | u8 time_slots; | ||
| 274 | u8 reserved; /* Reserved */ | ||
| 275 | u16 result; /* Result used for acknowledgment */ | ||
| 276 | } __packed; | ||
| 277 | |||
| 278 | /* Library info structure */ | ||
| 279 | struct module_info { | ||
| 280 | u32 lib_version; | ||
| 281 | u32 lib_type;/*TBD- KLOCKWORK u8 lib_type;*/ | ||
| 282 | u32 media_type; | ||
| 283 | u8 lib_name[12]; | ||
| 284 | u32 lib_caps; | ||
| 285 | unsigned char b_date[16]; /* Lib build date */ | ||
| 286 | unsigned char b_time[16]; /* Lib build time */ | ||
| 287 | } __packed; | ||
| 288 | |||
| 289 | /* Library slot info */ | ||
| 290 | struct lib_slot_info { | ||
| 291 | u8 slot_num; /* 1 or 2 */ | ||
| 292 | u8 reserved1; | ||
| 293 | u16 reserved2; | ||
| 294 | u32 iram_size; /* slot size in IRAM */ | ||
| 295 | u32 dram_size; /* slot size in DRAM */ | ||
| 296 | u32 iram_offset; /* starting offset of slot in IRAM */ | ||
| 297 | u32 dram_offset; /* starting offset of slot in DRAM */ | ||
| 298 | } __packed; | ||
| 299 | |||
| 300 | struct snd_ppp_mixer_params { | ||
| 301 | __u32 type; /*Type of the parameter */ | ||
| 302 | __u32 size; | ||
| 303 | __u32 input_stream_bitmap; /*Input stream Bit Map*/ | ||
| 304 | } __packed; | ||
| 305 | |||
| 306 | struct snd_sst_lib_download { | ||
| 307 | struct module_info lib_info; /* library info type, capabilities etc */ | ||
| 308 | struct lib_slot_info slot_info; /* slot info to be downloaded */ | ||
| 309 | u32 mod_entry_pt; | ||
| 310 | }; | ||
| 311 | |||
| 312 | struct snd_sst_lib_download_info { | ||
| 313 | struct snd_sst_lib_download dload_lib; | ||
| 314 | u16 result; /* Result used for acknowledgment */ | ||
| 315 | u8 pvt_id; /* Private ID */ | ||
| 316 | u8 reserved; /* for alignment */ | ||
| 317 | }; | ||
| 38 | struct snd_pcm_params { | 318 | struct snd_pcm_params { |
| 39 | u8 num_chan; /* 1=Mono, 2=Stereo */ | 319 | u8 num_chan; /* 1=Mono, 2=Stereo */ |
| 40 | u8 pcm_wd_sz; /* 16/24 - bit*/ | 320 | u8 pcm_wd_sz; /* 16/24 - bit*/ |
| 41 | u32 reserved; /* Bitrate in bits per second */ | 321 | u8 use_offload_path; /* 0-PCM using period elpased & ALSA interfaces |
| 42 | u32 sfreq; /* Sampling rate in Hz */ | 322 | 1-PCM stream via compressed interface */ |
| 43 | u8 use_offload_path; | ||
| 44 | u8 reserved2; | 323 | u8 reserved2; |
| 45 | u16 reserved3; | 324 | u32 sfreq; /* Sampling rate in Hz */ |
| 46 | u8 channel_map[8]; | 325 | u8 channel_map[8]; |
| 47 | } __packed; | 326 | } __packed; |
| 48 | 327 | ||
| @@ -76,6 +355,7 @@ struct snd_aac_params { | |||
| 76 | struct snd_wma_params { | 355 | struct snd_wma_params { |
| 77 | u8 num_chan; /* 1=Mono, 2=Stereo */ | 356 | u8 num_chan; /* 1=Mono, 2=Stereo */ |
| 78 | u8 pcm_wd_sz; /* 16/24 - bit*/ | 357 | u8 pcm_wd_sz; /* 16/24 - bit*/ |
| 358 | u16 reserved1; | ||
| 79 | u32 brate; /* Use the hard coded value. */ | 359 | u32 brate; /* Use the hard coded value. */ |
| 80 | u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ | 360 | u32 sfreq; /* Sampling freq eg. 8000, 441000, 48000 */ |
| 81 | u32 channel_mask; /* Channel Mask */ | 361 | u32 channel_mask; /* Channel Mask */ |
| @@ -101,26 +381,153 @@ struct sst_address_info { | |||
| 101 | }; | 381 | }; |
| 102 | 382 | ||
| 103 | struct snd_sst_alloc_params_ext { | 383 | struct snd_sst_alloc_params_ext { |
| 104 | struct sst_address_info ring_buf_info[8]; | 384 | __u16 sg_count; |
| 105 | u8 sg_count; | 385 | __u16 reserved; |
| 106 | u8 reserved; | 386 | __u32 frag_size; /*Number of samples after which period elapsed |
| 107 | u16 reserved2; | ||
| 108 | u32 frag_size; /*Number of samples after which period elapsed | ||
| 109 | message is sent valid only if path = 0*/ | 387 | message is sent valid only if path = 0*/ |
| 110 | } __packed; | 388 | struct sst_address_info ring_buf_info[8]; |
| 389 | }; | ||
| 111 | 390 | ||
| 112 | struct snd_sst_stream_params { | 391 | struct snd_sst_stream_params { |
| 113 | union snd_sst_codec_params uc; | 392 | union snd_sst_codec_params uc; |
| 114 | } __packed; | 393 | } __packed; |
| 115 | 394 | ||
| 116 | struct snd_sst_params { | 395 | struct snd_sst_params { |
| 396 | u32 result; | ||
| 117 | u32 stream_id; | 397 | u32 stream_id; |
| 118 | u8 codec; | 398 | u8 codec; |
| 119 | u8 ops; | 399 | u8 ops; |
| 120 | u8 stream_type; | 400 | u8 stream_type; |
| 121 | u8 device_type; | 401 | u8 device_type; |
| 402 | u8 task; | ||
| 122 | struct snd_sst_stream_params sparams; | 403 | struct snd_sst_stream_params sparams; |
| 123 | struct snd_sst_alloc_params_ext aparams; | 404 | struct snd_sst_alloc_params_ext aparams; |
| 124 | }; | 405 | }; |
| 125 | 406 | ||
| 407 | struct snd_sst_alloc_mrfld { | ||
| 408 | u16 codec_type; | ||
| 409 | u8 operation; | ||
| 410 | u8 sg_count; | ||
| 411 | struct sst_address_info ring_buf_info[8]; | ||
| 412 | u32 frag_size; | ||
| 413 | u32 ts; | ||
| 414 | struct snd_sst_stream_params codec_params; | ||
| 415 | } __packed; | ||
| 416 | |||
| 417 | /* Alloc stream params structure */ | ||
| 418 | struct snd_sst_alloc_params { | ||
| 419 | struct snd_sst_str_type str_type; | ||
| 420 | struct snd_sst_stream_params stream_params; | ||
| 421 | struct snd_sst_alloc_params_ext alloc_params; | ||
| 422 | } __packed; | ||
| 423 | |||
| 424 | /* Alloc stream response message */ | ||
| 425 | struct snd_sst_alloc_response { | ||
| 426 | struct snd_sst_str_type str_type; /* Stream type for allocation */ | ||
| 427 | struct snd_sst_lib_download lib_dnld; /* Valid only for codec dnld */ | ||
| 428 | }; | ||
| 429 | |||
| 430 | /* Drop response */ | ||
| 431 | struct snd_sst_drop_response { | ||
| 432 | u32 result; | ||
| 433 | u32 bytes; | ||
| 434 | }; | ||
| 435 | |||
| 436 | struct snd_sst_async_msg { | ||
| 437 | u32 msg_id; /* Async msg id */ | ||
| 438 | u32 payload[0]; | ||
| 439 | }; | ||
| 440 | |||
| 441 | struct snd_sst_async_err_msg { | ||
| 442 | u32 fw_resp; /* Firmware Result */ | ||
| 443 | u32 lib_resp; /*Library result */ | ||
| 444 | } __packed; | ||
| 445 | |||
| 446 | struct snd_sst_vol { | ||
| 447 | u32 stream_id; | ||
| 448 | s32 volume; | ||
| 449 | u32 ramp_duration; | ||
| 450 | u32 ramp_type; /* Ramp type, default=0 */ | ||
| 451 | }; | ||
| 452 | |||
| 453 | /* Gain library parameters for mrfld | ||
| 454 | * based on DSP command spec v0.82 | ||
| 455 | */ | ||
| 456 | struct snd_sst_gain_v2 { | ||
| 457 | u16 gain_cell_num; /* num of gain cells to modify*/ | ||
| 458 | u8 cell_nbr_idx; /* instance index*/ | ||
| 459 | u8 cell_path_idx; /* pipe-id */ | ||
| 460 | u16 module_id; /*module id */ | ||
| 461 | u16 left_cell_gain; /* left gain value in dB*/ | ||
| 462 | u16 right_cell_gain; /* right gain value in dB*/ | ||
| 463 | u16 gain_time_const; /* gain time constant*/ | ||
| 464 | } __packed; | ||
| 465 | |||
| 466 | struct snd_sst_mute { | ||
| 467 | u32 stream_id; | ||
| 468 | u32 mute; | ||
| 469 | }; | ||
| 470 | |||
| 471 | struct snd_sst_runtime_params { | ||
| 472 | u8 type; | ||
| 473 | u8 str_id; | ||
| 474 | u8 size; | ||
| 475 | u8 rsvd; | ||
| 476 | void *addr; | ||
| 477 | } __packed; | ||
| 478 | |||
| 479 | enum stream_param_type { | ||
| 480 | SST_SET_TIME_SLOT = 0, | ||
| 481 | SST_SET_CHANNEL_INFO = 1, | ||
| 482 | OTHERS = 2, /*reserved for future params*/ | ||
| 483 | }; | ||
| 484 | |||
| 485 | /* CSV Voice call routing structure */ | ||
| 486 | struct snd_sst_control_routing { | ||
| 487 | u8 control; /* 0=start, 1=Stop */ | ||
| 488 | u8 reserved[3]; /* Reserved- for 32 bit alignment */ | ||
| 489 | }; | ||
| 490 | |||
| 491 | struct ipc_post { | ||
| 492 | struct list_head node; | ||
| 493 | union ipc_header header; /* driver specific */ | ||
| 494 | bool is_large; | ||
| 495 | bool is_process_reply; | ||
| 496 | union ipc_header_mrfld mrfld_header; | ||
| 497 | char *mailbox_data; | ||
| 498 | }; | ||
| 499 | |||
| 500 | struct snd_sst_ctxt_params { | ||
| 501 | u32 address; /* Physical Address in DDR where the context is stored */ | ||
| 502 | u32 size; /* size of the context */ | ||
| 503 | }; | ||
| 504 | |||
| 505 | struct snd_sst_lpe_log_params { | ||
| 506 | u8 dbg_type; | ||
| 507 | u8 module_id; | ||
| 508 | u8 log_level; | ||
| 509 | u8 reserved; | ||
| 510 | } __packed; | ||
| 511 | |||
| 512 | enum snd_sst_bytes_type { | ||
| 513 | SND_SST_BYTES_SET = 0x1, | ||
| 514 | SND_SST_BYTES_GET = 0x2, | ||
| 515 | }; | ||
| 516 | |||
| 517 | struct snd_sst_bytes_v2 { | ||
| 518 | u8 type; | ||
| 519 | u8 ipc_msg; | ||
| 520 | u8 block; | ||
| 521 | u8 task_id; | ||
| 522 | u8 pipe_id; | ||
| 523 | u8 rsvd; | ||
| 524 | u16 len; | ||
| 525 | char bytes[0]; | ||
| 526 | }; | ||
| 527 | |||
| 528 | #define MAX_VTSV_FILES 2 | ||
| 529 | struct snd_sst_vtsv_info { | ||
| 530 | struct sst_address_info vfiles[MAX_VTSV_FILES]; | ||
| 531 | } __packed; | ||
| 532 | |||
| 126 | #endif /* __SST_MFLD_DSP_H__ */ | 533 | #endif /* __SST_MFLD_DSP_H__ */ |
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 02abd19fce1d..29c059ca19e8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c | |||
| @@ -100,14 +100,19 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, | |||
| 100 | int retval; | 100 | int retval; |
| 101 | struct snd_sst_params str_params; | 101 | struct snd_sst_params str_params; |
| 102 | struct sst_compress_cb cb; | 102 | struct sst_compress_cb cb; |
| 103 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | ||
| 104 | struct snd_soc_platform *platform = rtd->platform; | ||
| 105 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | ||
| 103 | 106 | ||
| 104 | stream = cstream->runtime->private_data; | 107 | stream = cstream->runtime->private_data; |
| 105 | /* construct fw structure for this*/ | 108 | /* construct fw structure for this*/ |
| 106 | memset(&str_params, 0, sizeof(str_params)); | 109 | memset(&str_params, 0, sizeof(str_params)); |
| 107 | 110 | ||
| 108 | str_params.ops = STREAM_OPS_PLAYBACK; | 111 | /* fill the device type and stream id to pass to SST driver */ |
| 109 | str_params.stream_type = SST_STREAM_TYPE_MUSIC; | 112 | retval = sst_fill_stream_params(cstream, ctx, &str_params, true); |
| 110 | str_params.device_type = SND_SST_DEVICE_COMPRESS; | 113 | pr_debug("compr_set_params: fill stream params ret_val = 0x%x\n", retval); |
| 114 | if (retval < 0) | ||
| 115 | return retval; | ||
| 111 | 116 | ||
| 112 | switch (params->codec.id) { | 117 | switch (params->codec.id) { |
| 113 | case SND_AUDIOCODEC_MP3: { | 118 | case SND_AUDIOCODEC_MP3: { |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 7c790f51d259..706212a6a68c 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * sst_mfld_platform.c - Intel MID Platform driver | 2 | * sst_mfld_platform.c - Intel MID Platform driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010-2013 Intel Corp | 4 | * Copyright (C) 2010-2014 Intel Corp |
| 5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
| 6 | * Author: Harsha Priya <priya.harsha@intel.com> | 6 | * Author: Harsha Priya <priya.harsha@intel.com> |
| 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -27,7 +27,9 @@ | |||
| 27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
| 28 | #include <sound/soc.h> | 28 | #include <sound/soc.h> |
| 29 | #include <sound/compress_driver.h> | 29 | #include <sound/compress_driver.h> |
| 30 | #include <asm/platform_sst_audio.h> | ||
| 30 | #include "sst-mfld-platform.h" | 31 | #include "sst-mfld-platform.h" |
| 32 | #include "sst-atom-controls.h" | ||
| 31 | 33 | ||
| 32 | struct sst_device *sst; | 34 | struct sst_device *sst; |
| 33 | static DEFINE_MUTEX(sst_lock); | 35 | static DEFINE_MUTEX(sst_lock); |
| @@ -92,6 +94,13 @@ static struct snd_pcm_hardware sst_platform_pcm_hw = { | |||
| 92 | .fifo_size = SST_FIFO_SIZE, | 94 | .fifo_size = SST_FIFO_SIZE, |
| 93 | }; | 95 | }; |
| 94 | 96 | ||
| 97 | static struct sst_dev_stream_map dpcm_strm_map[] = { | ||
| 98 | {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* Reserved, not in use */ | ||
| 99 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0}, | ||
| 100 | {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0}, | ||
| 101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, | ||
| 102 | }; | ||
| 103 | |||
| 95 | /* MFLD - MSIC */ | 104 | /* MFLD - MSIC */ |
| 96 | static struct snd_soc_dai_driver sst_platform_dai[] = { | 105 | static struct snd_soc_dai_driver sst_platform_dai[] = { |
| 97 | { | 106 | { |
| @@ -143,58 +152,142 @@ static inline int sst_get_stream_status(struct sst_runtime_stream *stream) | |||
| 143 | return state; | 152 | return state; |
| 144 | } | 153 | } |
| 145 | 154 | ||
| 155 | static void sst_fill_alloc_params(struct snd_pcm_substream *substream, | ||
| 156 | struct snd_sst_alloc_params_ext *alloc_param) | ||
| 157 | { | ||
| 158 | unsigned int channels; | ||
| 159 | snd_pcm_uframes_t period_size; | ||
| 160 | ssize_t periodbytes; | ||
| 161 | ssize_t buffer_bytes = snd_pcm_lib_buffer_bytes(substream); | ||
| 162 | u32 buffer_addr = virt_to_phys(substream->dma_buffer.area); | ||
| 163 | |||
| 164 | channels = substream->runtime->channels; | ||
| 165 | period_size = substream->runtime->period_size; | ||
| 166 | periodbytes = samples_to_bytes(substream->runtime, period_size); | ||
| 167 | alloc_param->ring_buf_info[0].addr = buffer_addr; | ||
| 168 | alloc_param->ring_buf_info[0].size = buffer_bytes; | ||
| 169 | alloc_param->sg_count = 1; | ||
| 170 | alloc_param->reserved = 0; | ||
| 171 | alloc_param->frag_size = periodbytes * channels; | ||
| 172 | |||
| 173 | } | ||
| 146 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, | 174 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, |
| 147 | struct sst_pcm_params *param) | 175 | struct snd_sst_stream_params *param) |
| 148 | { | 176 | { |
| 177 | param->uc.pcm_params.num_chan = (u8) substream->runtime->channels; | ||
| 178 | param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; | ||
| 179 | param->uc.pcm_params.sfreq = substream->runtime->rate; | ||
| 180 | |||
| 181 | /* PCM stream via ALSA interface */ | ||
| 182 | param->uc.pcm_params.use_offload_path = 0; | ||
| 183 | param->uc.pcm_params.reserved2 = 0; | ||
| 184 | memset(param->uc.pcm_params.channel_map, 0, sizeof(u8)); | ||
| 149 | 185 | ||
| 150 | param->num_chan = (u8) substream->runtime->channels; | ||
| 151 | param->pcm_wd_sz = substream->runtime->sample_bits; | ||
| 152 | param->reserved = 0; | ||
| 153 | param->sfreq = substream->runtime->rate; | ||
| 154 | param->ring_buffer_size = snd_pcm_lib_buffer_bytes(substream); | ||
| 155 | param->period_count = substream->runtime->period_size; | ||
| 156 | param->ring_buffer_addr = virt_to_phys(substream->dma_buffer.area); | ||
| 157 | pr_debug("period_cnt = %d\n", param->period_count); | ||
| 158 | pr_debug("sfreq= %d, wd_sz = %d\n", param->sfreq, param->pcm_wd_sz); | ||
| 159 | } | 186 | } |
| 160 | 187 | ||
| 161 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream) | 188 | static int sst_get_stream_mapping(int dev, int sdev, int dir, |
| 189 | struct sst_dev_stream_map *map, int size) | ||
| 190 | { | ||
| 191 | int i; | ||
| 192 | |||
| 193 | if (map == NULL) | ||
| 194 | return -EINVAL; | ||
| 195 | |||
| 196 | |||
| 197 | /* index 0 is not used in stream map */ | ||
| 198 | for (i = 1; i < size; i++) { | ||
| 199 | if ((map[i].dev_num == dev) && (map[i].direction == dir)) | ||
| 200 | return i; | ||
| 201 | } | ||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | int sst_fill_stream_params(void *substream, | ||
| 206 | const struct sst_data *ctx, struct snd_sst_params *str_params, bool is_compress) | ||
| 207 | { | ||
| 208 | int map_size; | ||
| 209 | int index; | ||
| 210 | struct sst_dev_stream_map *map; | ||
| 211 | struct snd_pcm_substream *pstream = NULL; | ||
| 212 | struct snd_compr_stream *cstream = NULL; | ||
| 213 | |||
| 214 | map = ctx->pdata->pdev_strm_map; | ||
| 215 | map_size = ctx->pdata->strm_map_size; | ||
| 216 | |||
| 217 | if (is_compress == true) | ||
| 218 | cstream = (struct snd_compr_stream *)substream; | ||
| 219 | else | ||
| 220 | pstream = (struct snd_pcm_substream *)substream; | ||
| 221 | |||
| 222 | str_params->stream_type = SST_STREAM_TYPE_MUSIC; | ||
| 223 | |||
| 224 | /* For pcm streams */ | ||
| 225 | if (pstream) { | ||
| 226 | index = sst_get_stream_mapping(pstream->pcm->device, | ||
| 227 | pstream->number, pstream->stream, | ||
| 228 | map, map_size); | ||
| 229 | if (index <= 0) | ||
| 230 | return -EINVAL; | ||
| 231 | |||
| 232 | str_params->stream_id = index; | ||
| 233 | str_params->device_type = map[index].device_id; | ||
| 234 | str_params->task = map[index].task_id; | ||
| 235 | |||
| 236 | str_params->ops = (u8)pstream->stream; | ||
| 237 | } | ||
| 238 | |||
| 239 | if (cstream) { | ||
| 240 | index = sst_get_stream_mapping(cstream->device->device, | ||
| 241 | 0, cstream->direction, | ||
| 242 | map, map_size); | ||
| 243 | if (index <= 0) | ||
| 244 | return -EINVAL; | ||
| 245 | str_params->stream_id = index; | ||
| 246 | str_params->device_type = map[index].device_id; | ||
| 247 | str_params->task = map[index].task_id; | ||
| 248 | |||
| 249 | str_params->ops = (u8)cstream->direction; | ||
| 250 | } | ||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, | ||
| 255 | struct snd_soc_platform *platform) | ||
| 162 | { | 256 | { |
| 163 | struct sst_runtime_stream *stream = | 257 | struct sst_runtime_stream *stream = |
| 164 | substream->runtime->private_data; | 258 | substream->runtime->private_data; |
| 165 | struct sst_pcm_params param = {0}; | 259 | struct snd_sst_stream_params param = {{{0,},},}; |
| 166 | struct sst_stream_params str_params = {0}; | 260 | struct snd_sst_params str_params = {0}; |
| 167 | int ret_val; | 261 | struct snd_sst_alloc_params_ext alloc_params = {0}; |
| 262 | int ret_val = 0; | ||
| 263 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | ||
| 168 | 264 | ||
| 169 | /* set codec params and inform SST driver the same */ | 265 | /* set codec params and inform SST driver the same */ |
| 170 | sst_fill_pcm_params(substream, ¶m); | 266 | sst_fill_pcm_params(substream, ¶m); |
| 267 | sst_fill_alloc_params(substream, &alloc_params); | ||
| 171 | substream->runtime->dma_area = substream->dma_buffer.area; | 268 | substream->runtime->dma_area = substream->dma_buffer.area; |
| 172 | str_params.sparams = param; | 269 | str_params.sparams = param; |
| 173 | str_params.codec = param.codec; | 270 | str_params.aparams = alloc_params; |
| 174 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 271 | str_params.codec = SST_CODEC_TYPE_PCM; |
| 175 | str_params.ops = STREAM_OPS_PLAYBACK; | 272 | |
| 176 | str_params.device_type = substream->pcm->device + 1; | 273 | /* fill the device type and stream id to pass to SST driver */ |
| 177 | pr_debug("Playbck stream,Device %d\n", | 274 | ret_val = sst_fill_stream_params(substream, ctx, &str_params, false); |
| 178 | substream->pcm->device); | ||
| 179 | } else { | ||
| 180 | str_params.ops = STREAM_OPS_CAPTURE; | ||
| 181 | str_params.device_type = SND_SST_DEVICE_CAPTURE; | ||
| 182 | pr_debug("Capture stream,Device %d\n", | ||
| 183 | substream->pcm->device); | ||
| 184 | } | ||
| 185 | ret_val = stream->ops->open(&str_params); | ||
| 186 | pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); | ||
| 187 | if (ret_val < 0) | 275 | if (ret_val < 0) |
| 188 | return ret_val; | 276 | return ret_val; |
| 189 | 277 | ||
| 190 | stream->stream_info.str_id = ret_val; | 278 | stream->stream_info.str_id = str_params.stream_id; |
| 191 | pr_debug("str id : %d\n", stream->stream_info.str_id); | 279 | |
| 280 | ret_val = stream->ops->open(&str_params); | ||
| 281 | if (ret_val <= 0) | ||
| 282 | return ret_val; | ||
| 283 | |||
| 284 | |||
| 192 | return ret_val; | 285 | return ret_val; |
| 193 | } | 286 | } |
| 194 | 287 | ||
| 195 | static void sst_period_elapsed(void *mad_substream) | 288 | static void sst_period_elapsed(void *arg) |
| 196 | { | 289 | { |
| 197 | struct snd_pcm_substream *substream = mad_substream; | 290 | struct snd_pcm_substream *substream = arg; |
| 198 | struct sst_runtime_stream *stream; | 291 | struct sst_runtime_stream *stream; |
| 199 | int status; | 292 | int status; |
| 200 | 293 | ||
| @@ -218,7 +311,7 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
| 218 | pr_debug("setting buffer ptr param\n"); | 311 | pr_debug("setting buffer ptr param\n"); |
| 219 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 312 | sst_set_stream_status(stream, SST_PLATFORM_INIT); |
| 220 | stream->stream_info.period_elapsed = sst_period_elapsed; | 313 | stream->stream_info.period_elapsed = sst_period_elapsed; |
| 221 | stream->stream_info.mad_substream = substream; | 314 | stream->stream_info.arg = substream; |
| 222 | stream->stream_info.buffer_ptr = 0; | 315 | stream->stream_info.buffer_ptr = 0; |
| 223 | stream->stream_info.sfreq = substream->runtime->rate; | 316 | stream->stream_info.sfreq = substream->runtime->rate; |
| 224 | ret_val = stream->ops->device_control( | 317 | ret_val = stream->ops->device_control( |
| @@ -230,19 +323,12 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
| 230 | } | 323 | } |
| 231 | /* end -- helper functions */ | 324 | /* end -- helper functions */ |
| 232 | 325 | ||
| 233 | static int sst_platform_open(struct snd_pcm_substream *substream) | 326 | static int sst_media_open(struct snd_pcm_substream *substream, |
| 327 | struct snd_soc_dai *dai) | ||
| 234 | { | 328 | { |
| 329 | int ret_val = 0; | ||
| 235 | struct snd_pcm_runtime *runtime = substream->runtime; | 330 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 236 | struct sst_runtime_stream *stream; | 331 | struct sst_runtime_stream *stream; |
| 237 | int ret_val; | ||
| 238 | |||
| 239 | pr_debug("sst_platform_open called\n"); | ||
| 240 | |||
| 241 | snd_soc_set_runtime_hwparams(substream, &sst_platform_pcm_hw); | ||
| 242 | ret_val = snd_pcm_hw_constraint_integer(runtime, | ||
| 243 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
| 244 | if (ret_val < 0) | ||
| 245 | return ret_val; | ||
| 246 | 332 | ||
| 247 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | 333 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
| 248 | if (!stream) | 334 | if (!stream) |
| @@ -251,50 +337,69 @@ static int sst_platform_open(struct snd_pcm_substream *substream) | |||
| 251 | 337 | ||
| 252 | /* get the sst ops */ | 338 | /* get the sst ops */ |
| 253 | mutex_lock(&sst_lock); | 339 | mutex_lock(&sst_lock); |
| 254 | if (!sst) { | 340 | if (!sst || |
| 341 | !try_module_get(sst->dev->driver->owner)) { | ||
| 255 | pr_err("no device available to run\n"); | 342 | pr_err("no device available to run\n"); |
| 256 | mutex_unlock(&sst_lock); | 343 | ret_val = -ENODEV; |
| 257 | kfree(stream); | 344 | goto out_ops; |
| 258 | return -ENODEV; | ||
| 259 | } | ||
| 260 | if (!try_module_get(sst->dev->driver->owner)) { | ||
| 261 | mutex_unlock(&sst_lock); | ||
| 262 | kfree(stream); | ||
| 263 | return -ENODEV; | ||
| 264 | } | 345 | } |
| 265 | stream->ops = sst->ops; | 346 | stream->ops = sst->ops; |
| 266 | mutex_unlock(&sst_lock); | 347 | mutex_unlock(&sst_lock); |
| 267 | 348 | ||
| 268 | stream->stream_info.str_id = 0; | 349 | stream->stream_info.str_id = 0; |
| 269 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 350 | |
| 270 | stream->stream_info.mad_substream = substream; | 351 | stream->stream_info.arg = substream; |
| 271 | /* allocate memory for SST API set */ | 352 | /* allocate memory for SST API set */ |
| 272 | runtime->private_data = stream; | 353 | runtime->private_data = stream; |
| 273 | 354 | ||
| 274 | return 0; | 355 | /* Make sure, that the period size is always even */ |
| 356 | snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
| 357 | SNDRV_PCM_HW_PARAM_PERIODS, 2); | ||
| 358 | |||
| 359 | return snd_pcm_hw_constraint_integer(runtime, | ||
| 360 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
| 361 | out_ops: | ||
| 362 | kfree(stream); | ||
| 363 | mutex_unlock(&sst_lock); | ||
| 364 | return ret_val; | ||
| 275 | } | 365 | } |
| 276 | 366 | ||
| 277 | static int sst_platform_close(struct snd_pcm_substream *substream) | 367 | static void sst_media_close(struct snd_pcm_substream *substream, |
| 368 | struct snd_soc_dai *dai) | ||
| 278 | { | 369 | { |
| 279 | struct sst_runtime_stream *stream; | 370 | struct sst_runtime_stream *stream; |
| 280 | int ret_val = 0, str_id; | 371 | int ret_val = 0, str_id; |
| 281 | 372 | ||
| 282 | pr_debug("sst_platform_close called\n"); | ||
| 283 | stream = substream->runtime->private_data; | 373 | stream = substream->runtime->private_data; |
| 284 | str_id = stream->stream_info.str_id; | 374 | str_id = stream->stream_info.str_id; |
| 285 | if (str_id) | 375 | if (str_id) |
| 286 | ret_val = stream->ops->close(str_id); | 376 | ret_val = stream->ops->close(str_id); |
| 287 | module_put(sst->dev->driver->owner); | 377 | module_put(sst->dev->driver->owner); |
| 288 | kfree(stream); | 378 | kfree(stream); |
| 289 | return ret_val; | ||
| 290 | } | 379 | } |
| 291 | 380 | ||
| 292 | static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | 381 | static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, |
| 382 | struct snd_pcm_substream *substream) | ||
| 383 | { | ||
| 384 | struct sst_data *sst = snd_soc_platform_get_drvdata(platform); | ||
| 385 | struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; | ||
| 386 | struct sst_runtime_stream *stream = | ||
| 387 | substream->runtime->private_data; | ||
| 388 | u32 str_id = stream->stream_info.str_id; | ||
| 389 | unsigned int pipe_id; | ||
| 390 | pipe_id = map[str_id].device_id; | ||
| 391 | |||
| 392 | pr_debug("%s: got pipe_id = %#x for str_id = %d\n", | ||
| 393 | __func__, pipe_id, str_id); | ||
| 394 | return pipe_id; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int sst_media_prepare(struct snd_pcm_substream *substream, | ||
| 398 | struct snd_soc_dai *dai) | ||
| 293 | { | 399 | { |
| 294 | struct sst_runtime_stream *stream; | 400 | struct sst_runtime_stream *stream; |
| 295 | int ret_val = 0, str_id; | 401 | int ret_val = 0, str_id; |
| 296 | 402 | ||
| 297 | pr_debug("sst_platform_pcm_prepare called\n"); | ||
| 298 | stream = substream->runtime->private_data; | 403 | stream = substream->runtime->private_data; |
| 299 | str_id = stream->stream_info.str_id; | 404 | str_id = stream->stream_info.str_id; |
| 300 | if (stream->stream_info.str_id) { | 405 | if (stream->stream_info.str_id) { |
| @@ -303,8 +408,8 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 303 | return ret_val; | 408 | return ret_val; |
| 304 | } | 409 | } |
| 305 | 410 | ||
| 306 | ret_val = sst_platform_alloc_stream(substream); | 411 | ret_val = sst_platform_alloc_stream(substream, dai->platform); |
| 307 | if (ret_val < 0) | 412 | if (ret_val <= 0) |
| 308 | return ret_val; | 413 | return ret_val; |
| 309 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), | 414 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), |
| 310 | "%d", stream->stream_info.str_id); | 415 | "%d", stream->stream_info.str_id); |
| @@ -316,6 +421,41 @@ static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | |||
| 316 | return ret_val; | 421 | return ret_val; |
| 317 | } | 422 | } |
| 318 | 423 | ||
| 424 | static int sst_media_hw_params(struct snd_pcm_substream *substream, | ||
| 425 | struct snd_pcm_hw_params *params, | ||
| 426 | struct snd_soc_dai *dai) | ||
| 427 | { | ||
| 428 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 429 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
| 430 | return 0; | ||
| 431 | } | ||
| 432 | |||
| 433 | static int sst_media_hw_free(struct snd_pcm_substream *substream, | ||
| 434 | struct snd_soc_dai *dai) | ||
| 435 | { | ||
| 436 | return snd_pcm_lib_free_pages(substream); | ||
| 437 | } | ||
| 438 | |||
| 439 | static struct snd_soc_dai_ops sst_media_dai_ops = { | ||
| 440 | .startup = sst_media_open, | ||
| 441 | .shutdown = sst_media_close, | ||
| 442 | .prepare = sst_media_prepare, | ||
| 443 | .hw_params = sst_media_hw_params, | ||
| 444 | .hw_free = sst_media_hw_free, | ||
| 445 | }; | ||
| 446 | |||
| 447 | static int sst_platform_open(struct snd_pcm_substream *substream) | ||
| 448 | { | ||
| 449 | struct snd_pcm_runtime *runtime; | ||
| 450 | |||
| 451 | if (substream->pcm->internal) | ||
| 452 | return 0; | ||
| 453 | |||
| 454 | runtime = substream->runtime; | ||
| 455 | runtime->hw = sst_platform_pcm_hw; | ||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | |||
| 319 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | 459 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, |
| 320 | int cmd) | 460 | int cmd) |
| 321 | { | 461 | { |
| @@ -331,7 +471,7 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
| 331 | pr_debug("sst: Trigger Start\n"); | 471 | pr_debug("sst: Trigger Start\n"); |
| 332 | str_cmd = SST_SND_START; | 472 | str_cmd = SST_SND_START; |
| 333 | status = SST_PLATFORM_RUNNING; | 473 | status = SST_PLATFORM_RUNNING; |
| 334 | stream->stream_info.mad_substream = substream; | 474 | stream->stream_info.arg = substream; |
| 335 | break; | 475 | break; |
| 336 | case SNDRV_PCM_TRIGGER_STOP: | 476 | case SNDRV_PCM_TRIGGER_STOP: |
| 337 | pr_debug("sst: in stop\n"); | 477 | pr_debug("sst: in stop\n"); |
| @@ -377,32 +517,15 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer | |||
| 377 | pr_err("sst: error code = %d\n", ret_val); | 517 | pr_err("sst: error code = %d\n", ret_val); |
| 378 | return ret_val; | 518 | return ret_val; |
| 379 | } | 519 | } |
| 380 | return stream->stream_info.buffer_ptr; | 520 | substream->runtime->delay = str_info->pcm_delay; |
| 381 | } | 521 | return str_info->buffer_ptr; |
| 382 | |||
| 383 | static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 384 | struct snd_pcm_hw_params *params) | ||
| 385 | { | ||
| 386 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 387 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
| 388 | |||
| 389 | return 0; | ||
| 390 | } | ||
| 391 | |||
| 392 | static int sst_platform_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 393 | { | ||
| 394 | return snd_pcm_lib_free_pages(substream); | ||
| 395 | } | 522 | } |
| 396 | 523 | ||
| 397 | static struct snd_pcm_ops sst_platform_ops = { | 524 | static struct snd_pcm_ops sst_platform_ops = { |
| 398 | .open = sst_platform_open, | 525 | .open = sst_platform_open, |
| 399 | .close = sst_platform_close, | ||
| 400 | .ioctl = snd_pcm_lib_ioctl, | 526 | .ioctl = snd_pcm_lib_ioctl, |
| 401 | .prepare = sst_platform_pcm_prepare, | ||
| 402 | .trigger = sst_platform_pcm_trigger, | 527 | .trigger = sst_platform_pcm_trigger, |
| 403 | .pointer = sst_platform_pcm_pointer, | 528 | .pointer = sst_platform_pcm_pointer, |
| 404 | .hw_params = sst_platform_pcm_hw_params, | ||
| 405 | .hw_free = sst_platform_pcm_hw_free, | ||
| 406 | }; | 529 | }; |
| 407 | 530 | ||
| 408 | static void sst_pcm_free(struct snd_pcm *pcm) | 531 | static void sst_pcm_free(struct snd_pcm *pcm) |
| @@ -413,15 +536,15 @@ static void sst_pcm_free(struct snd_pcm *pcm) | |||
| 413 | 536 | ||
| 414 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) | 537 | static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) |
| 415 | { | 538 | { |
| 539 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
| 416 | struct snd_pcm *pcm = rtd->pcm; | 540 | struct snd_pcm *pcm = rtd->pcm; |
| 417 | int retval = 0; | 541 | int retval = 0; |
| 418 | 542 | ||
| 419 | pr_debug("sst_pcm_new called\n"); | 543 | if (dai->driver->playback.channels_min || |
| 420 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | 544 | dai->driver->capture.channels_min) { |
| 421 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
| 422 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, | 545 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, |
| 423 | SNDRV_DMA_TYPE_CONTINUOUS, | 546 | SNDRV_DMA_TYPE_CONTINUOUS, |
| 424 | snd_dma_continuous_data(GFP_KERNEL), | 547 | snd_dma_continuous_data(GFP_DMA), |
| 425 | SST_MIN_BUFFER, SST_MAX_BUFFER); | 548 | SST_MIN_BUFFER, SST_MAX_BUFFER); |
| 426 | if (retval) { | 549 | if (retval) { |
| 427 | pr_err("dma buffer allocationf fail\n"); | 550 | pr_err("dma buffer allocationf fail\n"); |
| @@ -445,10 +568,28 @@ static const struct snd_soc_component_driver sst_component = { | |||
| 445 | 568 | ||
| 446 | static int sst_platform_probe(struct platform_device *pdev) | 569 | static int sst_platform_probe(struct platform_device *pdev) |
| 447 | { | 570 | { |
| 571 | struct sst_data *drv; | ||
| 448 | int ret; | 572 | int ret; |
| 573 | struct sst_platform_data *pdata; | ||
| 574 | |||
| 575 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); | ||
| 576 | if (drv == NULL) { | ||
| 577 | pr_err("kzalloc failed\n"); | ||
| 578 | return -ENOMEM; | ||
| 579 | } | ||
| 580 | |||
| 581 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
| 582 | if (pdata == NULL) { | ||
| 583 | pr_err("kzalloc failed for pdata\n"); | ||
| 584 | return -ENOMEM; | ||
| 585 | } | ||
| 586 | |||
| 587 | pdata->pdev_strm_map = dpcm_strm_map; | ||
| 588 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); | ||
| 589 | drv->pdata = pdata; | ||
| 590 | mutex_init(&drv->lock); | ||
| 591 | dev_set_drvdata(&pdev->dev, drv); | ||
| 449 | 592 | ||
| 450 | pr_debug("sst_platform_probe called\n"); | ||
| 451 | sst = NULL; | ||
| 452 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); | 593 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); |
| 453 | if (ret) { | 594 | if (ret) { |
| 454 | pr_err("registering soc platform failed\n"); | 595 | pr_err("registering soc platform failed\n"); |
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c5e7dc49e3c..6c6a42c08e24 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
| @@ -39,9 +39,10 @@ extern struct sst_device *sst; | |||
| 39 | 39 | ||
| 40 | struct pcm_stream_info { | 40 | struct pcm_stream_info { |
| 41 | int str_id; | 41 | int str_id; |
| 42 | void *mad_substream; | 42 | void *arg; |
| 43 | void (*period_elapsed) (void *mad_substream); | 43 | void (*period_elapsed) (void *arg); |
| 44 | unsigned long long buffer_ptr; | 44 | unsigned long long buffer_ptr; |
| 45 | unsigned long long pcm_delay; | ||
| 45 | int sfreq; | 46 | int sfreq; |
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| @@ -62,7 +63,9 @@ enum sst_controls { | |||
| 62 | SST_SND_BUFFER_POINTER = 0x05, | 63 | SST_SND_BUFFER_POINTER = 0x05, |
| 63 | SST_SND_STREAM_INIT = 0x06, | 64 | SST_SND_STREAM_INIT = 0x06, |
| 64 | SST_SND_START = 0x07, | 65 | SST_SND_START = 0x07, |
| 65 | SST_MAX_CONTROLS = 0x07, | 66 | SST_SET_BYTE_STREAM = 0x100A, |
| 67 | SST_GET_BYTE_STREAM = 0x100B, | ||
| 68 | SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, | ||
| 66 | }; | 69 | }; |
| 67 | 70 | ||
| 68 | enum sst_stream_ops { | 71 | enum sst_stream_ops { |
| @@ -124,8 +127,9 @@ struct compress_sst_ops { | |||
| 124 | }; | 127 | }; |
| 125 | 128 | ||
| 126 | struct sst_ops { | 129 | struct sst_ops { |
| 127 | int (*open) (struct sst_stream_params *str_param); | 130 | int (*open) (struct snd_sst_params *str_param); |
| 128 | int (*device_control) (int cmd, void *arg); | 131 | int (*device_control) (int cmd, void *arg); |
| 132 | int (*set_generic_params)(enum sst_controls cmd, void *arg); | ||
| 129 | int (*close) (unsigned int str_id); | 133 | int (*close) (unsigned int str_id); |
| 130 | }; | 134 | }; |
| 131 | 135 | ||
| @@ -143,10 +147,27 @@ struct sst_device { | |||
| 143 | char *name; | 147 | char *name; |
| 144 | struct device *dev; | 148 | struct device *dev; |
| 145 | struct sst_ops *ops; | 149 | struct sst_ops *ops; |
| 150 | struct platform_device *pdev; | ||
| 146 | struct compress_sst_ops *compr_ops; | 151 | struct compress_sst_ops *compr_ops; |
| 147 | }; | 152 | }; |
| 148 | 153 | ||
| 154 | struct sst_data; | ||
| 149 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); | 155 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); |
| 156 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, | ||
| 157 | struct snd_sst_params *str_params, bool is_compress); | ||
| 158 | |||
| 159 | struct sst_algo_int_control_v2 { | ||
| 160 | struct soc_mixer_control mc; | ||
| 161 | u16 module_id; /* module identifieer */ | ||
| 162 | u16 pipe_id; /* location info: pipe_id + instance_id */ | ||
| 163 | u16 instance_id; | ||
| 164 | unsigned int value; /* Value received is stored here */ | ||
| 165 | }; | ||
| 166 | struct sst_data { | ||
| 167 | struct platform_device *pdev; | ||
| 168 | struct sst_platform_data *pdata; | ||
| 169 | struct mutex lock; | ||
| 170 | }; | ||
| 150 | int sst_register_dsp(struct sst_device *sst); | 171 | int sst_register_dsp(struct sst_device *sst); |
| 151 | int sst_unregister_dsp(struct sst_device *sst); | 172 | int sst_unregister_dsp(struct sst_device *sst); |
| 152 | #endif | 173 | #endif |
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index 06f4e8aa93ae..132bb83f8e99 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config SND_KIRKWOOD_SOC | 1 | config SND_KIRKWOOD_SOC |
| 2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" | 2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" |
| 3 | depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU || MACH_KIRKWOOD || COMPILE_TEST | 3 | depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST |
| 4 | help | 4 | help |
| 5 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
| 6 | the Kirkwood I2S interface. You will also need to select the | 6 | the Kirkwood I2S interface. You will also need to select the |
| @@ -15,20 +15,3 @@ config SND_KIRKWOOD_SOC_ARMADA370_DB | |||
| 15 | Say Y if you want to add support for SoC audio on | 15 | Say Y if you want to add support for SoC audio on |
| 16 | the Armada 370 Development Board. | 16 | the Armada 370 Development Board. |
| 17 | 17 | ||
| 18 | config SND_KIRKWOOD_SOC_OPENRD | ||
| 19 | tristate "SoC Audio support for Kirkwood Openrd Client" | ||
| 20 | depends on SND_KIRKWOOD_SOC && (MACH_OPENRD_CLIENT || MACH_OPENRD_ULTIMATE || COMPILE_TEST) | ||
| 21 | depends on I2C | ||
| 22 | select SND_SOC_CS42L51 | ||
| 23 | help | ||
| 24 | Say Y if you want to add support for SoC audio on | ||
| 25 | Openrd Client. | ||
| 26 | |||
| 27 | config SND_KIRKWOOD_SOC_T5325 | ||
| 28 | tristate "SoC Audio support for HP t5325" | ||
| 29 | depends on SND_KIRKWOOD_SOC && (MACH_T5325 || COMPILE_TEST) && I2C | ||
| 30 | select SND_SOC_ALC5623 | ||
| 31 | help | ||
| 32 | Say Y if you want to add support for SoC audio on | ||
| 33 | the HP t5325 thin client. | ||
| 34 | |||
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile index 7c1d8fe09e6b..c36b03d8006c 100644 --- a/sound/soc/kirkwood/Makefile +++ b/sound/soc/kirkwood/Makefile | |||
| @@ -2,10 +2,6 @@ snd-soc-kirkwood-objs := kirkwood-dma.o kirkwood-i2s.o | |||
| 2 | 2 | ||
| 3 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o | 3 | obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o |
| 4 | 4 | ||
| 5 | snd-soc-openrd-objs := kirkwood-openrd.o | ||
| 6 | snd-soc-t5325-objs := kirkwood-t5325.o | ||
| 7 | snd-soc-armada-370-db-objs := armada-370-db.o | 5 | snd-soc-armada-370-db-objs := armada-370-db.o |
| 8 | 6 | ||
| 9 | obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o | 7 | obj-$(CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB) += snd-soc-armada-370-db.o |
| 10 | obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o | ||
| 11 | obj-$(CONFIG_SND_KIRKWOOD_SOC_T5325) += snd-soc-t5325.o | ||
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index aac22fccdcdc..4cf2245950d7 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c | |||
| @@ -28,11 +28,12 @@ static struct kirkwood_dma_data *kirkwood_priv(struct snd_pcm_substream *subs) | |||
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { | 30 | static struct snd_pcm_hardware kirkwood_dma_snd_hw = { |
| 31 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | 31 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
| 32 | SNDRV_PCM_INFO_MMAP | | 32 | SNDRV_PCM_INFO_MMAP | |
| 33 | SNDRV_PCM_INFO_MMAP_VALID | | 33 | SNDRV_PCM_INFO_MMAP_VALID | |
| 34 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 34 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
| 35 | SNDRV_PCM_INFO_PAUSE), | 35 | SNDRV_PCM_INFO_PAUSE | |
| 36 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
| 36 | .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES, | 37 | .buffer_bytes_max = KIRKWOOD_SND_MAX_BUFFER_BYTES, |
| 37 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, | 38 | .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES, |
| 38 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, | 39 | .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES, |
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c index 9f842222e798..0704cd6d2314 100644 --- a/sound/soc/kirkwood/kirkwood-i2s.c +++ b/sound/soc/kirkwood/kirkwood-i2s.c | |||
| @@ -212,7 +212,8 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 212 | KIRKWOOD_PLAYCTL_SIZE_MASK); | 212 | KIRKWOOD_PLAYCTL_SIZE_MASK); |
| 213 | priv->ctl_play |= ctl_play; | 213 | priv->ctl_play |= ctl_play; |
| 214 | } else { | 214 | } else { |
| 215 | priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK; | 215 | priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK | |
| 216 | KIRKWOOD_RECCTL_SIZE_MASK); | ||
| 216 | priv->ctl_rec |= ctl_rec; | 217 | priv->ctl_rec |= ctl_rec; |
| 217 | } | 218 | } |
| 218 | 219 | ||
| @@ -221,14 +222,24 @@ static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 221 | return 0; | 222 | return 0; |
| 222 | } | 223 | } |
| 223 | 224 | ||
| 225 | static unsigned kirkwood_i2s_play_mute(unsigned ctl) | ||
| 226 | { | ||
| 227 | if (!(ctl & KIRKWOOD_PLAYCTL_I2S_EN)) | ||
| 228 | ctl |= KIRKWOOD_PLAYCTL_I2S_MUTE; | ||
| 229 | if (!(ctl & KIRKWOOD_PLAYCTL_SPDIF_EN)) | ||
| 230 | ctl |= KIRKWOOD_PLAYCTL_SPDIF_MUTE; | ||
| 231 | return ctl; | ||
| 232 | } | ||
| 233 | |||
| 224 | static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | 234 | static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, |
| 225 | int cmd, struct snd_soc_dai *dai) | 235 | int cmd, struct snd_soc_dai *dai) |
| 226 | { | 236 | { |
| 237 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 227 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); | 238 | struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai); |
| 228 | uint32_t ctl, value; | 239 | uint32_t ctl, value; |
| 229 | 240 | ||
| 230 | ctl = readl(priv->io + KIRKWOOD_PLAYCTL); | 241 | ctl = readl(priv->io + KIRKWOOD_PLAYCTL); |
| 231 | if (ctl & KIRKWOOD_PLAYCTL_PAUSE) { | 242 | if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) { |
| 232 | unsigned timeout = 5000; | 243 | unsigned timeout = 5000; |
| 233 | /* | 244 | /* |
| 234 | * The Armada510 spec says that if we enter pause mode, the | 245 | * The Armada510 spec says that if we enter pause mode, the |
| @@ -256,14 +267,16 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
| 256 | ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ | 267 | ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */ |
| 257 | else | 268 | else |
| 258 | ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ | 269 | ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */ |
| 259 | 270 | ctl = kirkwood_i2s_play_mute(ctl); | |
| 260 | value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK; | 271 | value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK; |
| 261 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 272 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
| 262 | 273 | ||
| 263 | /* enable interrupts */ | 274 | /* enable interrupts */ |
| 264 | value = readl(priv->io + KIRKWOOD_INT_MASK); | 275 | if (!runtime->no_period_wakeup) { |
| 265 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; | 276 | value = readl(priv->io + KIRKWOOD_INT_MASK); |
| 266 | writel(value, priv->io + KIRKWOOD_INT_MASK); | 277 | value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES; |
| 278 | writel(value, priv->io + KIRKWOOD_INT_MASK); | ||
| 279 | } | ||
| 267 | 280 | ||
| 268 | /* enable playback */ | 281 | /* enable playback */ |
| 269 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 282 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
| @@ -295,6 +308,7 @@ static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream, | |||
| 295 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 308 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| 296 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | | 309 | ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE | |
| 297 | KIRKWOOD_PLAYCTL_SPDIF_MUTE); | 310 | KIRKWOOD_PLAYCTL_SPDIF_MUTE); |
| 311 | ctl = kirkwood_i2s_play_mute(ctl); | ||
| 298 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); | 312 | writel(ctl, priv->io + KIRKWOOD_PLAYCTL); |
| 299 | break; | 313 | break; |
| 300 | 314 | ||
| @@ -322,8 +336,7 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | |||
| 322 | else | 336 | else |
| 323 | ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ | 337 | ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */ |
| 324 | 338 | ||
| 325 | value = ctl & ~(KIRKWOOD_RECCTL_I2S_EN | | 339 | value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK; |
| 326 | KIRKWOOD_RECCTL_SPDIF_EN); | ||
| 327 | writel(value, priv->io + KIRKWOOD_RECCTL); | 340 | writel(value, priv->io + KIRKWOOD_RECCTL); |
| 328 | 341 | ||
| 329 | /* enable interrupts */ | 342 | /* enable interrupts */ |
| @@ -347,7 +360,7 @@ static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream, | |||
| 347 | 360 | ||
| 348 | /* disable all records */ | 361 | /* disable all records */ |
| 349 | value = readl(priv->io + KIRKWOOD_RECCTL); | 362 | value = readl(priv->io + KIRKWOOD_RECCTL); |
| 350 | value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); | 363 | value &= ~KIRKWOOD_RECCTL_ENABLE_MASK; |
| 351 | writel(value, priv->io + KIRKWOOD_RECCTL); | 364 | writel(value, priv->io + KIRKWOOD_RECCTL); |
| 352 | break; | 365 | break; |
| 353 | 366 | ||
| @@ -411,7 +424,7 @@ static int kirkwood_i2s_init(struct kirkwood_dma_data *priv) | |||
| 411 | writel(value, priv->io + KIRKWOOD_PLAYCTL); | 424 | writel(value, priv->io + KIRKWOOD_PLAYCTL); |
| 412 | 425 | ||
| 413 | value = readl(priv->io + KIRKWOOD_RECCTL); | 426 | value = readl(priv->io + KIRKWOOD_RECCTL); |
| 414 | value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN); | 427 | value &= ~KIRKWOOD_RECCTL_ENABLE_MASK; |
| 415 | writel(value, priv->io + KIRKWOOD_RECCTL); | 428 | writel(value, priv->io + KIRKWOOD_RECCTL); |
| 416 | 429 | ||
| 417 | return 0; | 430 | return 0; |
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c deleted file mode 100644 index 65f2a5b9ec3b..000000000000 --- a/sound/soc/kirkwood/kirkwood-openrd.c +++ /dev/null | |||
| @@ -1,109 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * kirkwood-openrd.c | ||
| 3 | * | ||
| 4 | * (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
| 5 | * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms of the GNU General Public License as published by the | ||
| 9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 10 | * option) any later version. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/moduleparam.h> | ||
| 15 | #include <linux/interrupt.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <sound/soc.h> | ||
| 19 | #include <linux/platform_data/asoc-kirkwood.h> | ||
| 20 | #include "../codecs/cs42l51.h" | ||
| 21 | |||
| 22 | static int openrd_client_hw_params(struct snd_pcm_substream *substream, | ||
| 23 | struct snd_pcm_hw_params *params) | ||
| 24 | { | ||
| 25 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 26 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 27 | unsigned int freq; | ||
| 28 | |||
| 29 | switch (params_rate(params)) { | ||
| 30 | default: | ||
| 31 | case 44100: | ||
| 32 | freq = 11289600; | ||
| 33 | break; | ||
| 34 | case 48000: | ||
| 35 | freq = 12288000; | ||
| 36 | break; | ||
| 37 | case 96000: | ||
| 38 | freq = 24576000; | ||
| 39 | break; | ||
| 40 | } | ||
| 41 | |||
| 42 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); | ||
| 43 | |||
| 44 | } | ||
| 45 | |||
| 46 | static struct snd_soc_ops openrd_client_ops = { | ||
| 47 | .hw_params = openrd_client_hw_params, | ||
| 48 | }; | ||
| 49 | |||
| 50 | |||
| 51 | static struct snd_soc_dai_link openrd_client_dai[] = { | ||
| 52 | { | ||
| 53 | .name = "CS42L51", | ||
| 54 | .stream_name = "CS42L51 HiFi", | ||
| 55 | .cpu_dai_name = "i2s", | ||
| 56 | .platform_name = "mvebu-audio", | ||
| 57 | .codec_dai_name = "cs42l51-hifi", | ||
| 58 | .codec_name = "cs42l51-codec.0-004a", | ||
| 59 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, | ||
| 60 | .ops = &openrd_client_ops, | ||
| 61 | }, | ||
| 62 | }; | ||
| 63 | |||
| 64 | |||
| 65 | static struct snd_soc_card openrd_client = { | ||
| 66 | .name = "OpenRD Client", | ||
| 67 | .owner = THIS_MODULE, | ||
| 68 | .dai_link = openrd_client_dai, | ||
| 69 | .num_links = ARRAY_SIZE(openrd_client_dai), | ||
| 70 | }; | ||
| 71 | |||
| 72 | static int openrd_probe(struct platform_device *pdev) | ||
| 73 | { | ||
| 74 | struct snd_soc_card *card = &openrd_client; | ||
| 75 | int ret; | ||
| 76 | |||
| 77 | card->dev = &pdev->dev; | ||
| 78 | |||
| 79 | ret = snd_soc_register_card(card); | ||
| 80 | if (ret) | ||
| 81 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
| 82 | ret); | ||
| 83 | return ret; | ||
| 84 | } | ||
| 85 | |||
| 86 | static int openrd_remove(struct platform_device *pdev) | ||
| 87 | { | ||
| 88 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
| 89 | |||
| 90 | snd_soc_unregister_card(card); | ||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static struct platform_driver openrd_driver = { | ||
| 95 | .driver = { | ||
| 96 | .name = "openrd-client-audio", | ||
| 97 | .owner = THIS_MODULE, | ||
| 98 | }, | ||
| 99 | .probe = openrd_probe, | ||
| 100 | .remove = openrd_remove, | ||
| 101 | }; | ||
| 102 | |||
| 103 | module_platform_driver(openrd_driver); | ||
| 104 | |||
| 105 | /* Module information */ | ||
| 106 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | ||
| 107 | MODULE_DESCRIPTION("ALSA SoC OpenRD Client"); | ||
| 108 | MODULE_LICENSE("GPL"); | ||
| 109 | MODULE_ALIAS("platform:openrd-client-audio"); | ||
diff --git a/sound/soc/kirkwood/kirkwood-t5325.c b/sound/soc/kirkwood/kirkwood-t5325.c deleted file mode 100644 index 844b8415a011..000000000000 --- a/sound/soc/kirkwood/kirkwood-t5325.c +++ /dev/null | |||
| @@ -1,116 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * kirkwood-t5325.c | ||
| 3 | * | ||
| 4 | * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/moduleparam.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <sound/soc.h> | ||
| 18 | #include <linux/platform_data/asoc-kirkwood.h> | ||
| 19 | #include "../codecs/alc5623.h" | ||
| 20 | |||
| 21 | static int t5325_hw_params(struct snd_pcm_substream *substream, | ||
| 22 | struct snd_pcm_hw_params *params) | ||
| 23 | { | ||
| 24 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 25 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 26 | unsigned int freq; | ||
| 27 | |||
| 28 | freq = params_rate(params) * 256; | ||
| 29 | |||
| 30 | return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); | ||
| 31 | |||
| 32 | } | ||
| 33 | |||
| 34 | static struct snd_soc_ops t5325_ops = { | ||
| 35 | .hw_params = t5325_hw_params, | ||
| 36 | }; | ||
| 37 | |||
| 38 | static const struct snd_soc_dapm_widget t5325_dapm_widgets[] = { | ||
| 39 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
| 40 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
| 41 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
| 42 | }; | ||
| 43 | |||
| 44 | static const struct snd_soc_dapm_route t5325_route[] = { | ||
| 45 | { "Headphone Jack", NULL, "HPL" }, | ||
| 46 | { "Headphone Jack", NULL, "HPR" }, | ||
| 47 | |||
| 48 | {"Speaker", NULL, "SPKOUT"}, | ||
| 49 | {"Speaker", NULL, "SPKOUTN"}, | ||
| 50 | |||
| 51 | { "MIC1", NULL, "Mic Jack" }, | ||
| 52 | { "MIC2", NULL, "Mic Jack" }, | ||
| 53 | }; | ||
| 54 | |||
| 55 | static struct snd_soc_dai_link t5325_dai[] = { | ||
| 56 | { | ||
| 57 | .name = "ALC5621", | ||
| 58 | .stream_name = "ALC5621 HiFi", | ||
| 59 | .cpu_dai_name = "i2s", | ||
| 60 | .platform_name = "mvebu-audio", | ||
| 61 | .codec_dai_name = "alc5621-hifi", | ||
| 62 | .codec_name = "alc562x-codec.0-001a", | ||
| 63 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, | ||
| 64 | .ops = &t5325_ops, | ||
| 65 | }, | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct snd_soc_card t5325 = { | ||
| 69 | .name = "t5325", | ||
| 70 | .owner = THIS_MODULE, | ||
| 71 | .dai_link = t5325_dai, | ||
| 72 | .num_links = ARRAY_SIZE(t5325_dai), | ||
| 73 | |||
| 74 | .dapm_widgets = t5325_dapm_widgets, | ||
| 75 | .num_dapm_widgets = ARRAY_SIZE(t5325_dapm_widgets), | ||
| 76 | .dapm_routes = t5325_route, | ||
| 77 | .num_dapm_routes = ARRAY_SIZE(t5325_route), | ||
| 78 | }; | ||
| 79 | |||
| 80 | static int t5325_probe(struct platform_device *pdev) | ||
| 81 | { | ||
| 82 | struct snd_soc_card *card = &t5325; | ||
| 83 | int ret; | ||
| 84 | |||
| 85 | card->dev = &pdev->dev; | ||
| 86 | |||
| 87 | ret = snd_soc_register_card(card); | ||
| 88 | if (ret) | ||
| 89 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
| 90 | ret); | ||
| 91 | return ret; | ||
| 92 | } | ||
| 93 | |||
| 94 | static int t5325_remove(struct platform_device *pdev) | ||
| 95 | { | ||
| 96 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
| 97 | |||
| 98 | snd_soc_unregister_card(card); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct platform_driver t5325_driver = { | ||
| 103 | .driver = { | ||
| 104 | .name = "t5325-audio", | ||
| 105 | .owner = THIS_MODULE, | ||
| 106 | }, | ||
| 107 | .probe = t5325_probe, | ||
| 108 | .remove = t5325_remove, | ||
| 109 | }; | ||
| 110 | |||
| 111 | module_platform_driver(t5325_driver); | ||
| 112 | |||
| 113 | MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>"); | ||
| 114 | MODULE_DESCRIPTION("ALSA SoC t5325 audio client"); | ||
| 115 | MODULE_LICENSE("GPL"); | ||
| 116 | MODULE_ALIAS("platform:t5325-audio"); | ||
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h index bf23afbba1d7..90e32a781424 100644 --- a/sound/soc/kirkwood/kirkwood.h +++ b/sound/soc/kirkwood/kirkwood.h | |||
| @@ -38,6 +38,9 @@ | |||
| 38 | #define KIRKWOOD_RECCTL_SIZE_24 (1<<0) | 38 | #define KIRKWOOD_RECCTL_SIZE_24 (1<<0) |
| 39 | #define KIRKWOOD_RECCTL_SIZE_32 (0<<0) | 39 | #define KIRKWOOD_RECCTL_SIZE_32 (0<<0) |
| 40 | 40 | ||
| 41 | #define KIRKWOOD_RECCTL_ENABLE_MASK (KIRKWOOD_RECCTL_SPDIF_EN | \ | ||
| 42 | KIRKWOOD_RECCTL_I2S_EN) | ||
| 43 | |||
| 41 | #define KIRKWOOD_REC_BUF_ADDR 0x1004 | 44 | #define KIRKWOOD_REC_BUF_ADDR 0x1004 |
| 42 | #define KIRKWOOD_REC_BUF_SIZE 0x1008 | 45 | #define KIRKWOOD_REC_BUF_SIZE 0x1008 |
| 43 | #define KIRKWOOD_REC_BYTE_COUNT 0x100C | 46 | #define KIRKWOOD_REC_BYTE_COUNT 0x100C |
| @@ -121,9 +124,9 @@ | |||
| 121 | 124 | ||
| 122 | /* Theses values come from the marvell alsa driver */ | 125 | /* Theses values come from the marvell alsa driver */ |
| 123 | /* need to find where they come from */ | 126 | /* need to find where they come from */ |
| 124 | #define KIRKWOOD_SND_MIN_PERIODS 8 | 127 | #define KIRKWOOD_SND_MIN_PERIODS 2 |
| 125 | #define KIRKWOOD_SND_MAX_PERIODS 16 | 128 | #define KIRKWOOD_SND_MAX_PERIODS 16 |
| 126 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x800 | 129 | #define KIRKWOOD_SND_MIN_PERIOD_BYTES 256 |
| 127 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000 | 130 | #define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x8000 |
| 128 | #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ | 131 | #define KIRKWOOD_SND_MAX_BUFFER_BYTES (KIRKWOOD_SND_MAX_PERIOD_BYTES \ |
| 129 | * KIRKWOOD_SND_MAX_PERIODS) | 132 | * KIRKWOOD_SND_MAX_PERIODS) |
