Merge "ASoC: msm8974: Adding support for AUXPCM"
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 032c814..3d022a3 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -97,25 +97,42 @@
- compatible : "qcom,msm-auxpcm-resource"
- - qcom,msm-cpudai-auxpcm-clk: clock for auxpcm
+ - qcom,msm-cpudai-auxpcm-clk: clock for auxpcm. The first value is
+ for 8khz mode, the second is for
+ 16khz
- - qcom,msm-cpudai-auxpcm-mode: mode information
+ - qcom,msm-cpudai-auxpcm-mode: mode information. The first value is
+ for 8khz mode, the second is for
+ 16khz
0 - for PCM
- - qcom,msm-cpudai-auxpcm-sync: sync information
+ - qcom,msm-cpudai-auxpcm-sync: sync information. The first value is
+ for 8khz mode, the second is for
+ 16khz
- - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame
+ - qcom,msm-cpudai-auxpcm-frame: No.of bytes per frame. The first
+ value is for 8khz mode, the second
+ is for 16khz
5 - 256BPF
+ 4 - 128BPF
- - qcom,msm-cpudai-auxpcm-quant: Type of quantization
+ - qcom,msm-cpudai-auxpcm-quant: Type of quantization. The first
+ value is for 8khz mode, the second
+ is for 16khz
2 - Linear quantization
- qcom,msm-cpudai-auxpcm-slot: Slot number for multichannel scenario
+ The first value is for 8khz mode the
+ second is for 16khz
Value is 1
- - qcom,msm-cpudai-auxpcm-data: Data field - 0
+ - qcom,msm-cpudai-auxpcm-data: Data field - 0. The first value is
+ for 8khz mode, the second is for
+ 16khz
- - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000
+ - qcom,msm-cpudai-auxpcm-pcm-clk-rate: Clock rate for pcm - 2048000. The
+ first value is for 8khz mode, the
+ second is for auxpcm
[Second Level Nodes]
@@ -302,13 +319,13 @@
qcom,msm-auxpcm {
compatible = "qcom,msm-auxpcm-resource";
qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
- qcom,msm-cpudai-auxpcm-mode = <0>;
- qcom,msm-cpudai-auxpcm-sync = <1>;
- qcom,msm-cpudai-auxpcm-frame = <5>;
- qcom,msm-cpudai-auxpcm-quant = <2>;
- qcom,msm-cpudai-auxpcm-slot = <1>;
- qcom,msm-cpudai-auxpcm-data = <0>;
- qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
qcom,msm-auxpcm-rx {
qcom,msm-auxpcm-dev-id = <4106>;
@@ -357,6 +374,10 @@
- taiko-mclk-clk : phandle to PMIC8941 clkdiv1 node.
- qcom,taiko-mclk-clk-freq : Taiko mclk Freq in Hz. currently only 9600000Hz
is supported.
+- prim-auxpcm-gpio-clk : GPIO on which AUXPCM clk signal is coming.
+- prim-auxpcm-gpio-sync : GPIO on which AUXPCM SYNC signal is coming.
+- prim-auxpcm-gpio-din : GPIO on which AUXPCM DIN signal is coming.
+- prim-auxpcm-gpio-dout : GPIO on which AUXPCM DOUT signal is coming.
Optional properties:
- qcom,hdmi-audio-rx: specifies if HDMI audio support is enabled or not.
@@ -401,6 +422,11 @@
qcom,taiko-mclk-clk-freq = <9600000>;
qcom,hdmi-audio-rx;
+
+ prim-auxpcm-gpio-clk = <&msmgpio 65 0>;
+ prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+ prim-auxpcm-gpio-din = <&msmgpio 67 0>;
+ prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
};
* msm-dai-mi2s
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index b673526..8838953 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -431,6 +431,10 @@
qcom,cdc-mclk-gpios = <&pm8941_gpios 15 0>;
taiko-mclk-clk = <&pm8941_clkdiv1>;
qcom,taiko-mclk-clk-freq = <9600000>;
+ prim-auxpcm-gpio-clk = <&msmgpio 65 0>;
+ prim-auxpcm-gpio-sync = <&msmgpio 66 0>;
+ prim-auxpcm-gpio-din = <&msmgpio 67 0>;
+ prim-auxpcm-gpio-dout = <&msmgpio 68 0>;
};
spmi_bus: qcom,spmi@fc4c0000 {
@@ -823,13 +827,13 @@
qcom,msm-auxpcm {
compatible = "qcom,msm-auxpcm-resource";
qcom,msm-cpudai-auxpcm-clk = "pcm_clk";
- qcom,msm-cpudai-auxpcm-mode = <0>;
- qcom,msm-cpudai-auxpcm-sync = <1>;
- qcom,msm-cpudai-auxpcm-frame = <5>;
- qcom,msm-cpudai-auxpcm-quant = <2>;
- qcom,msm-cpudai-auxpcm-slot = <1>;
- qcom,msm-cpudai-auxpcm-data = <0>;
- qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>;
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-slot = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
qcom,msm-auxpcm-rx {
qcom,msm-auxpcm-dev-id = <4106>;
diff --git a/arch/arm/mach-msm/board-8974-gpiomux.c b/arch/arm/mach-msm/board-8974-gpiomux.c
index 6672f49..b1e107d 100644
--- a/arch/arm/mach-msm/board-8974-gpiomux.c
+++ b/arch/arm/mach-msm/board-8974-gpiomux.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -640,6 +640,51 @@
},
},
};
+
+static struct gpiomux_setting pri_auxpcm_act_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_8MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
+
+static struct gpiomux_setting pri_auxpcm_sus_cfg = {
+ .func = GPIOMUX_FUNC_1,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_DOWN,
+};
+
+static struct msm_gpiomux_config msm8974_pri_auxpcm_configs[] __initdata = {
+ {
+ .gpio = 65,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 66,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 67,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+ {
+ .gpio = 68,
+ .settings = {
+ [GPIOMUX_SUSPENDED] = &pri_auxpcm_sus_cfg,
+ [GPIOMUX_ACTIVE] = &pri_auxpcm_act_cfg,
+ },
+ },
+};
+
static struct msm_gpiomux_config wcnss_5wire_interface[] = {
{
.gpio = 36,
@@ -902,6 +947,9 @@
msm_gpiomux_install(msm_hdmi_configs, ARRAY_SIZE(msm_hdmi_configs));
msm_gpiomux_install(msm_mhl_configs, ARRAY_SIZE(msm_mhl_configs));
+ msm_gpiomux_install(msm8974_pri_auxpcm_configs,
+ ARRAY_SIZE(msm8974_pri_auxpcm_configs));
+
if (machine_is_msm8974_rumi())
msm_gpiomux_install(msm_rumi_blsp_configs,
ARRAY_SIZE(msm_rumi_blsp_configs));
diff --git a/arch/arm/mach-msm/clock-8974.c b/arch/arm/mach-msm/clock-8974.c
index 435cc7d..ed4e377 100644
--- a/arch/arm/mach-msm/clock-8974.c
+++ b/arch/arm/mach-msm/clock-8974.c
@@ -5375,6 +5375,14 @@
"msm-dai-q6.4106"),
CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
"msm-dai-q6.4106"),
+ CLK_LOOKUP("pcm_clk", audio_core_lpaif_pcm0_clk_src.c,
+ "msm-dai-q6.4107"),
+ CLK_LOOKUP("ibit_clk", audio_core_lpaif_pcm0_ibit_clk.c,
+ "msm-dai-q6.4107"),
+ CLK_LOOKUP("core_oe_src_clk", audio_core_lpaif_pcmoe_clk_src.c,
+ "msm-dai-q6.4107"),
+ CLK_LOOKUP("core_oe_clk", audio_core_lpaif_pcmoe_clk.c,
+ "msm-dai-q6.4107"),
CLK_LOOKUP("br_clk", audio_wrapper_br_clk.c, "fdd00000.qcom,ocmem"),
CLK_LOOKUP("bus_clk", gcc_mss_q6_bimc_axi_clk.c, "fc880000.qcom,mss"),
diff --git a/include/sound/msm-dai-q6-v2.h b/include/sound/msm-dai-q6-v2.h
index 4ecd435..c04cbfc 100644
--- a/include/sound/msm-dai-q6-v2.h
+++ b/include/sound/msm-dai-q6-v2.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -26,8 +26,7 @@
#define MSM_TERT_MI2S 2
#define MSM_QUAT_MI2S 3
-struct msm_dai_auxpcm_pdata {
- const char *clk;
+struct msm_dai_auxpcm_config {
u16 mode;
u16 sync;
u16 frame;
@@ -40,6 +39,12 @@
int pcm_clk_rate;
};
+struct msm_dai_auxpcm_pdata {
+ const char *clk;
+ struct msm_dai_auxpcm_config mode_8k;
+ struct msm_dai_auxpcm_config mode_16k;
+};
+
struct msm_mi2s_pdata {
u16 rx_sd_lines;
u16 tx_sd_lines;
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index 633066f..cc1668e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -28,6 +28,7 @@
#include <mach/socinfo.h>
#include <qdsp6v2/msm-pcm-routing-v2.h>
#include "../codecs/wcd9320.h"
+#include <linux/io.h>
#define DRV_NAME "msm8974-asoc-taiko"
@@ -40,15 +41,21 @@
#define BTSCO_RATE_8KHZ 8000
#define BTSCO_RATE_16KHZ 16000
+static int msm8974_auxpcm_rate = 8000;
#define LO_1_SPK_AMP 0x1
#define LO_3_SPK_AMP 0x2
#define LO_2_SPK_AMP 0x4
#define LO_4_SPK_AMP 0x8
-#define GPIO_AUX_PCM_DOUT 43
-#define GPIO_AUX_PCM_DIN 44
-#define GPIO_AUX_PCM_SYNC 45
-#define GPIO_AUX_PCM_CLK 46
+#define LPAIF_OFFSET 0xFE000000
+#define LPAIF_PRI_MODE_MUXSEL (LPAIF_OFFSET + 0x2B000)
+#define LPAIF_SEC_MODE_MUXSEL (LPAIF_OFFSET + 0x2C000)
+#define LPAIF_TER_MODE_MUXSEL (LPAIF_OFFSET + 0x2D000)
+#define LPAIF_QUAD_MODE_MUXSEL (LPAIF_OFFSET + 0x2E000)
+
+#define I2S_PCM_SEL 1
+#define I2S_PCM_SEL_OFFSET 1
+
#define WCD9XXX_MBHC_DEF_BUTTONS 8
#define WCD9XXX_MBHC_DEF_RLOADS 5
@@ -57,6 +64,13 @@
/* It takes about 13ms for Class-D PAs to ramp-up */
#define EXT_CLASS_D_EN_DELAY 13000
+#define NUM_OF_AUXPCM_GPIOS 4
+
+static const char *const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
+static const struct soc_enum msm8974_auxpcm_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
+};
+
void *def_taiko_mbhc_cal(void);
static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
bool dapm);
@@ -75,11 +89,34 @@
.swap_gnd_mic = NULL,
};
+struct msm_auxpcm_gpio {
+ unsigned gpio_no;
+ const char *gpio_name;
+};
+
+struct msm_auxpcm_ctrl {
+ struct msm_auxpcm_gpio *pin_data;
+ u32 cnt;
+};
+
struct msm8974_asoc_mach_data {
int mclk_gpio;
u32 mclk_freq;
+ struct msm_auxpcm_ctrl *pri_auxpcm_ctrl;
};
+#define GPIO_NAME_INDEX 0
+#define DT_PARSE_INDEX 1
+
+static char *msm_auxpcm_gpio_name[][2] = {
+ {"PRIM_AUXPCM_CLK", "prim-auxpcm-gpio-clk"},
+ {"PRIM_AUXPCM_SYNC", "prim-auxpcm-gpio-sync"},
+ {"PRIM_AUXPCM_DIN", "prim-auxpcm-gpio-din"},
+ {"PRIM_AUXPCM_DOUT", "prim-auxpcm-gpio-dout"},
+};
+
+void *lpaif_pri_muxsel_virt_addr;
+
/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
enum {
SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
@@ -471,6 +508,30 @@
return 0;
}
+static int msm8974_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = msm8974_auxpcm_rate;
+ return 0;
+}
+
+static int msm8974_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ switch (ucontrol->value.integer.value[0]) {
+ case 0:
+ msm8974_auxpcm_rate = 8000;
+ break;
+ case 1:
+ msm8974_auxpcm_rate = 16000;
+ break;
+ default:
+ msm8974_auxpcm_rate = 8000;
+ break;
+ }
+ return 0;
+}
+
static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -480,8 +541,7 @@
struct snd_interval *channels =
hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- /* PCM only supports mono output with 8khz sample rate */
- rate->min = rate->max = 8000;
+ rate->min = rate->max = msm8974_auxpcm_rate;
channels->min = channels->max = 1;
return 0;
@@ -516,59 +576,86 @@
return 0;
}
-static int msm_aux_pcm_get_gpios(void)
+static int msm_aux_pcm_get_gpios(struct snd_pcm_substream *substream)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ struct msm_auxpcm_gpio *pin_data = NULL;
int ret = 0;
+ int i;
+ int j;
- pr_debug("%s\n", __func__);
-
- ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
- __func__, GPIO_AUX_PCM_DOUT);
- goto fail_dout;
+ if (pdata == NULL) {
+ pr_err("%s: pdata is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
}
- ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
- __func__, GPIO_AUX_PCM_DIN);
- goto fail_din;
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ ret = gpio_request(pin_data->gpio_no,
+ pin_data->gpio_name);
+ pr_debug("%s: gpio = %d, gpio name = %s\n"
+ "ret = %d\n", __func__,
+ pin_data->gpio_no,
+ pin_data->gpio_name,
+ ret);
+ if (ret) {
+ pr_err("%s: Failed to request gpio %d\n",
+ __func__, pin_data->gpio_no);
+ /* Release all GPIOs on failure */
+ for (j = i; j >= 0; j--)
+ gpio_free(pin_data->gpio_no);
+ goto err;
+ }
}
- ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
- __func__, GPIO_AUX_PCM_SYNC);
- goto fail_sync;
- }
- ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
- if (ret < 0) {
- pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
- __func__, GPIO_AUX_PCM_CLK);
- goto fail_clk;
- }
-
- return 0;
-
-fail_clk:
- gpio_free(GPIO_AUX_PCM_SYNC);
-fail_sync:
- gpio_free(GPIO_AUX_PCM_DIN);
-fail_din:
- gpio_free(GPIO_AUX_PCM_DOUT);
-fail_dout:
-
+err:
return ret;
}
-static int msm_aux_pcm_free_gpios(void)
-{
- gpio_free(GPIO_AUX_PCM_DIN);
- gpio_free(GPIO_AUX_PCM_DOUT);
- gpio_free(GPIO_AUX_PCM_SYNC);
- gpio_free(GPIO_AUX_PCM_CLK);
- return 0;
+static int msm_aux_pcm_free_gpios(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_card *card = rtd->card;
+ struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+ struct msm_auxpcm_ctrl *auxpcm_ctrl = NULL;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ int ret = 0;
+ int i;
+
+ if (pdata == NULL) {
+ pr_err("%s: pdata is NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ auxpcm_ctrl = pdata->pri_auxpcm_ctrl;
+
+ if (auxpcm_ctrl == NULL || auxpcm_ctrl->pin_data == NULL) {
+ pr_err("%s: Ctrl pointers are NULL\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ pin_data = auxpcm_ctrl->pin_data;
+ for (i = 0; i < auxpcm_ctrl->cnt; i++, pin_data++) {
+ gpio_free(pin_data->gpio_no);
+ pr_debug("%s: gpio = %d, gpio_name = %s\n",
+ __func__, pin_data->gpio_no,
+ pin_data->gpio_name);
+ }
+err:
+ return ret;
}
static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
@@ -577,8 +664,16 @@
pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
- if (atomic_inc_return(&auxpcm_rsc_ref) == 1)
- ret = msm_aux_pcm_get_gpios();
+
+ if (atomic_inc_return(&auxpcm_rsc_ref) == 1) {
+ if (lpaif_pri_muxsel_virt_addr != NULL)
+ iowrite32(I2S_PCM_SEL << I2S_PCM_SEL_OFFSET,
+ lpaif_pri_muxsel_virt_addr);
+ else
+ pr_err("%s lpaif_pri_muxsel_virt_addr is NULL\n",
+ __func__);
+ ret = msm_aux_pcm_get_gpios(substream);
+ }
if (ret < 0) {
pr_err("%s: Aux PCM GPIO request failed\n", __func__);
return -EINVAL;
@@ -592,7 +687,7 @@
pr_debug("%s(): substream = %s, auxpcm_rsc_ref counter = %d\n",
__func__, substream->name, atomic_read(&auxpcm_rsc_ref));
if (atomic_dec_return(&auxpcm_rsc_ref) == 0)
- msm_aux_pcm_free_gpios();
+ msm_aux_pcm_free_gpios(substream);
}
static struct snd_soc_ops msm_auxpcm_be_ops = {
.startup = msm_auxpcm_startup,
@@ -651,11 +746,13 @@
static const struct snd_kcontrol_new msm_snd_controls[] = {
SOC_ENUM_EXT("Speaker Function", msm_snd_enum[0], msm8974_get_spk,
- msm8974_set_spk),
+ msm8974_set_spk),
SOC_ENUM_EXT("SLIM_0_RX Channels", msm_snd_enum[1],
- msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
+ msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
SOC_ENUM_EXT("SLIM_0_TX Channels", msm_snd_enum[2],
- msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
+ SOC_ENUM_EXT("AUX PCM SampleRate", msm8974_auxpcm_enum[0],
+ msm8974_auxpcm_rate_get, msm8974_auxpcm_rate_put),
};
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
@@ -867,6 +964,7 @@
{
pr_debug("%s(): substream = %s stream = %d\n", __func__,
substream->name, substream->stream);
+
}
static struct snd_soc_ops msm8974_be_ops = {
@@ -1363,6 +1461,69 @@
.name = "msm8974-taiko-snd-card",
};
+static int msm8974_dtparse_auxpcm(struct platform_device *pdev,
+ struct msm8974_asoc_mach_data **pdata)
+{
+ int ret = 0;
+ int i = 0;
+ struct msm_auxpcm_gpio *pin_data = NULL;
+ struct msm_auxpcm_ctrl *ctrl;
+ unsigned int gpio_no[NUM_OF_AUXPCM_GPIOS];
+ enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW;
+ int prim_cnt = 0;
+
+ pin_data = devm_kzalloc(&pdev->dev, (ARRAY_SIZE(gpio_no) *
+ sizeof(struct msm_auxpcm_gpio)),
+ GFP_KERNEL);
+ if (!pin_data) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(gpio_no); i++) {
+ gpio_no[i] = of_get_named_gpio_flags(pdev->dev.of_node,
+ msm_auxpcm_gpio_name[i][DT_PARSE_INDEX],
+ 0, &flags);
+
+ if (gpio_no[i] > 0) {
+ pin_data[i].gpio_name =
+ msm_auxpcm_gpio_name[prim_cnt][GPIO_NAME_INDEX];
+ pin_data[i].gpio_no = gpio_no[i];
+ dev_dbg(&pdev->dev, "%s:GPIO gpio[%s] =\n"
+ "0x%x\n", __func__,
+ pin_data[i].gpio_name,
+ pin_data[i].gpio_no);
+ prim_cnt++;
+ } else {
+ dev_err(&pdev->dev, "%s:Invalid AUXPCM GPIO[%s]= %x\n",
+ __func__,
+ msm_auxpcm_gpio_name[i][GPIO_NAME_INDEX],
+ gpio_no[i]);
+ ret = -ENODEV;
+ goto err;
+ }
+ }
+
+ ctrl = devm_kzalloc(&pdev->dev,
+ sizeof(struct msm_auxpcm_ctrl), GFP_KERNEL);
+ if (!ctrl) {
+ dev_err(&pdev->dev, "No memory for gpio\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ ctrl->pin_data = pin_data;
+ ctrl->cnt = prim_cnt;
+ (*pdata)->pri_auxpcm_ctrl = ctrl;
+ return ret;
+
+err:
+ if (pin_data)
+ devm_kfree(&pdev->dev, pin_data);
+ return ret;
+}
+
static int msm8974_prepare_codec_mclk(struct snd_soc_card *card)
{
struct msm8974_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
@@ -1413,6 +1574,13 @@
goto err;
}
+ ret = msm8974_dtparse_auxpcm(pdev, &pdata);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: Auxpcm pin data parse failed\n", __func__);
+ goto err;
+ }
+
card->dev = &pdev->dev;
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, pdata);
@@ -1489,6 +1657,12 @@
spdev = pdev;
ext_spk_amp_regulator = NULL;
+ lpaif_pri_muxsel_virt_addr = ioremap(LPAIF_PRI_MODE_MUXSEL, 4);
+ if (lpaif_pri_muxsel_virt_addr == NULL) {
+ pr_err("%s Pri muxsel virt addr is null\n", __func__);
+ ret = -EINVAL;
+ goto err;
+ }
return 0;
err:
devm_kfree(&pdev->dev, pdata);
@@ -1506,7 +1680,7 @@
gpio_free(pdata->mclk_gpio);
if (ext_spk_amp_gpio >= 0)
gpio_free(ext_spk_amp_gpio);
-
+ iounmap(lpaif_pri_muxsel_virt_addr);
snd_soc_unregister_card(card);
return 0;
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index a7a80a6..ab92269 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2012-2013, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -33,6 +33,12 @@
STATUS_MAX
};
+enum {
+ RATE_8KHZ,
+ RATE_16KHZ,
+ RATE_MAX_NUM_OF_AUX_PCM_RATES,
+};
+
struct msm_dai_q6_dai_data {
DECLARE_BITMAP(status_mask, STATUS_MAX);
u32 rate;
@@ -92,25 +98,49 @@
return -EINVAL;
}
dai_data->channels = params_channels(params);
-
- if (params_rate(params) != 8000) {
- dev_err(dai->dev, "AUX PCM supports only 8KHz sampling rate\n");
- return -EINVAL;
- }
dai_data->rate = params_rate(params);
- dai_data->port_config.pcm.pcm_cfg_minor_version =
+ switch (dai_data->rate) {
+ case 8000:
+ dai_data->port_config.pcm.pcm_cfg_minor_version =
AFE_API_VERSION_PCM_CONFIG;
- dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode;
- dai_data->port_config.pcm.sync_src = auxpcm_pdata->sync;
- dai_data->port_config.pcm.frame_setting = auxpcm_pdata->frame;
- dai_data->port_config.pcm.quantype = auxpcm_pdata->quant;
- dai_data->port_config.pcm.ctrl_data_out_enable = auxpcm_pdata->data;
- dai_data->port_config.pcm.sample_rate = dai_data->rate;
- dai_data->port_config.pcm.num_channels = dai_data->channels;
- dai_data->port_config.pcm.bit_width = 16;
- dai_data->port_config.pcm.slot_number_mapping[0] = auxpcm_pdata->slot;
-
+ dai_data->port_config.pcm.aux_mode = auxpcm_pdata->mode_8k.mode;
+ dai_data->port_config.pcm.sync_src = auxpcm_pdata->mode_8k.sync;
+ dai_data->port_config.pcm.frame_setting =
+ auxpcm_pdata->mode_8k.frame;
+ dai_data->port_config.pcm.quantype =
+ auxpcm_pdata->mode_8k.quant;
+ dai_data->port_config.pcm.ctrl_data_out_enable =
+ auxpcm_pdata->mode_8k.data;
+ dai_data->port_config.pcm.sample_rate = dai_data->rate;
+ dai_data->port_config.pcm.num_channels = dai_data->channels;
+ dai_data->port_config.pcm.bit_width = 16;
+ dai_data->port_config.pcm.slot_number_mapping[0] =
+ auxpcm_pdata->mode_8k.slot;
+ break;
+ case 16000:
+ dai_data->port_config.pcm.pcm_cfg_minor_version =
+ AFE_API_VERSION_PCM_CONFIG;
+ dai_data->port_config.pcm.aux_mode =
+ auxpcm_pdata->mode_16k.mode;
+ dai_data->port_config.pcm.sync_src =
+ auxpcm_pdata->mode_16k.sync;
+ dai_data->port_config.pcm.frame_setting =
+ auxpcm_pdata->mode_16k.frame;
+ dai_data->port_config.pcm.quantype =
+ auxpcm_pdata->mode_16k.quant;
+ dai_data->port_config.pcm.ctrl_data_out_enable =
+ auxpcm_pdata->mode_16k.data;
+ dai_data->port_config.pcm.sample_rate = dai_data->rate;
+ dai_data->port_config.pcm.num_channels = dai_data->channels;
+ dai_data->port_config.pcm.bit_width = 16;
+ dai_data->port_config.pcm.slot_number_mapping[0] =
+ auxpcm_pdata->mode_16k.slot;
+ break;
+ default:
+ dev_err(dai->dev, "AUX PCM supports only 8kHz and 16kHz sampling rate\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -166,6 +196,7 @@
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
int rc = 0;
+ unsigned long pcm_clk_rate;
auxpcm_pdata = dai->dev->platform_data;
@@ -210,27 +241,43 @@
* assert/deasset and afe_open sequence is not followed.
*/
- rc = clk_set_rate(pcm_src_clk, auxpcm_pdata->pcm_clk_rate);
+ if (dai_data->rate == 8000) {
+ pcm_clk_rate = auxpcm_pdata->mode_8k.pcm_clk_rate;
+ } else if (dai_data->rate == 16000) {
+ pcm_clk_rate = (auxpcm_pdata->mode_16k.pcm_clk_rate);
+ } else {
+ dev_err(dai->dev, "%s: Invalid AUX PCM rate %d\n", __func__,
+ dai_data->rate);
+ mutex_unlock(&aux_pcm_mutex);
+ return -EINVAL;
+ }
+
+ rc = clk_set_rate(pcm_src_clk, pcm_clk_rate);
+
if (rc < 0) {
pr_err("%s: clk_set_rate failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
rc = clk_prepare_enable(pcm_branch_clk);
if (rc) {
pr_err("%s: clk enable failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
rc = clk_set_rate(pcm_oe_src_clk, 24576000>>1);
if (rc < 0) {
pr_err("%s: clk_set_rate on pcm oe failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
rc = clk_prepare_enable(pcm_oe_branch_clk);
if (rc) {
pr_err("%s: clk enable pcm_oe_branch_clk failed\n", __func__);
+ mutex_unlock(&aux_pcm_mutex);
goto fail;
}
@@ -1060,7 +1107,7 @@
{
int rc = 0;
struct msm_dai_auxpcm_pdata *auxpcm_pdata = NULL;
- u32 property_val;
+ uint32_t val_array[RATE_MAX_NUM_OF_AUX_PCM_RATES];
auxpcm_pdata = kzalloc(sizeof(struct msm_dai_auxpcm_pdata),
GFP_KERNEL);
@@ -1078,62 +1125,81 @@
__func__);
goto fail_free_plat;
}
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-mode", &property_val);
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-mode",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-mode missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->mode = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-sync", &property_val);
+ auxpcm_pdata->mode_8k.mode = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.mode = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-sync",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-sync missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->sync = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-frame", &property_val);
+ auxpcm_pdata->mode_8k.sync = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.sync = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-frame",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-frame missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->frame = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-quant", &property_val);
+ auxpcm_pdata->mode_8k.frame = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.frame = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-quant",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-quant missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->quant = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-slot", &property_val);
+ auxpcm_pdata->mode_8k.quant = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.quant = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-slot",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-slot missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->slot = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
- "qcom,msm-cpudai-auxpcm-data", &property_val);
+ auxpcm_pdata->mode_8k.slot = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.slot = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
+ "qcom,msm-cpudai-auxpcm-data",
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
if (rc) {
dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-data missing in DT node\n",
__func__);
goto fail_free_plat;
}
- auxpcm_pdata->data = (u16)property_val;
- rc = of_property_read_u32(pdev->dev.of_node,
+ auxpcm_pdata->mode_8k.data = (u16)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.data = (u16)val_array[RATE_16KHZ];
+
+ rc = of_property_read_u32_array(pdev->dev.of_node,
"qcom,msm-cpudai-auxpcm-pcm-clk-rate",
- &auxpcm_pdata->pcm_clk_rate);
- if (rc) {
- dev_err(&pdev->dev, "%s: qcom,msm-cpudai-auxpcm-pcm-clk-rate missing in DT node\n",
- __func__);
- goto fail_free_plat;
- }
+ val_array, RATE_MAX_NUM_OF_AUX_PCM_RATES);
+
+ auxpcm_pdata->mode_8k.pcm_clk_rate = (int)val_array[RATE_8KHZ];
+ auxpcm_pdata->mode_16k.pcm_clk_rate = (int)val_array[RATE_16KHZ];
+
platform_set_drvdata(pdev, auxpcm_pdata);
rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);