asoc: tegra: add speaker AMP EDP support
Dara Ramesh [Tue, 5 Feb 2013 12:47:33 +0000 (17:47 +0530)]
a) added speaker AMP EDP support for TI codec
b) set speaker AMP EDP state with E1 in probe function

Bug 1160686

Change-Id: I749ec8aba26d83fdd29aba2080230da5161d0c9e
Signed-off-by: Dara Ramesh <dramesh@nvidia.com>
Reviewed-on: http://git-master/r/197478
Reviewed-by: Riham Haidar <rhaidar@nvidia.com>
Tested-by: Riham Haidar <rhaidar@nvidia.com>

arch/arm/mach-tegra/board-pluto.c
sound/soc/tegra/tegra_aic326x.c
sound/soc/tegra/tegra_cs42l73.c

index f37b126..16dd9e4 100644 (file)
@@ -493,6 +493,7 @@ static struct tegra_asoc_platform_data pluto_aic3262_pdata = {
        .gpio_int_mic_en        = TEGRA_GPIO_INT_MIC_EN,
        .gpio_ext_mic_en        = TEGRA_GPIO_EXT_MIC_EN,
        .gpio_ldo1_en           = TEGRA_GPIO_LDO1_EN,
+       .edp_states             = {1776, 888, 0},
        .i2s_param[HIFI_CODEC]  = {
                .audio_port_id  = 1,
                .is_i2s_master  = 1,
index 8cd04b7..8c9b953 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/regulator/consumer.h>
+#include <linux/edp.h>
 #ifdef CONFIG_SWITCH
 #include <linux/switch.h>
 #endif
@@ -96,6 +97,7 @@ struct tegra_aic326x {
        struct regulator *dmic_1v8_reg;
        struct regulator *hmic_reg;
        enum snd_soc_bias_level bias_level;
+       struct edp_client *spk_edp_client;
 #endif
        int clock_enabled;
 };
@@ -967,14 +969,58 @@ static struct snd_soc_jack_pin tegra_aic326x_hp_jack_pins[] = {
 };
 #endif
 
+static void tegra_speaker_throttle(unsigned int new_state,  void *priv_data)
+{
+       struct tegra_aic326x *machine = priv_data;
+       struct snd_soc_card *card;
+       struct snd_soc_codec *codec;
+
+       if (!machine)
+               return;
+
+       card = machine->pcard;
+       codec = card->rtd[DAI_LINK_HIFI].codec;
+
+       /* set speaker amplifier voulme to 6dB, E0 state */
+       snd_soc_write(codec, AIC3262_SPK_AMP_CNTL_R4, 0x11);
+
+}
+
 static int tegra_aic326x_event_int_spk(struct snd_soc_dapm_widget *w,
                                        struct snd_kcontrol *k, int event)
 {
        struct snd_soc_dapm_context *dapm = w->dapm;
        struct snd_soc_card *card = dapm->card;
+       struct snd_soc_codec *codec = card->rtd[DAI_LINK_HIFI].codec;
        struct tegra_aic326x *machine = snd_soc_card_get_drvdata(card);
        struct tegra_asoc_platform_data *pdata = machine->pdata;
+       unsigned int approved;
+       int ret;
 
+       if (machine->spk_edp_client == NULL)
+               goto err_null_spk_edp_client;
+
+       if (SND_SOC_DAPM_EVENT_ON(event)) {
+               ret = edp_update_client_request(
+                               machine->spk_edp_client,
+                               TEGRA_SPK_EDP_NEG_1, &approved);
+               if (ret || approved != TEGRA_SPK_EDP_NEG_1) {
+                       /*  set speaker amplifier voulme to 6 dB, E0 state */
+                       snd_soc_write(codec, AIC3262_SPK_AMP_CNTL_R4, 0x11);
+               } else {
+                       /*  set speaker amplifier voulme to 18 dB, E-1 state */
+                       snd_soc_write(codec, AIC3262_SPK_AMP_CNTL_R4, 0x33);
+               }
+       } else {
+               ret = edp_update_client_request(
+                                       machine->spk_edp_client,
+                                       TEGRA_SPK_EDP_1, NULL);
+               if (ret) {
+                       dev_err(card->dev,
+                               "E+1 state transition failed\n");
+               }
+       }
+err_null_spk_edp_client:
        if (!(machine->gpio_requested & GPIO_SPKR_EN))
                return 0;
 
@@ -1363,8 +1409,10 @@ static struct snd_soc_card snd_soc_tegra_aic326x = {
 static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &snd_soc_tegra_aic326x;
+       struct snd_soc_codec *codec;
        struct tegra_aic326x *machine;
        struct tegra_asoc_platform_data *pdata;
+       struct edp_manager *battery_manager = NULL;
        int ret;
 #ifndef CONFIG_ARCH_TEGRA_2x_SOC
        int i;
@@ -1476,6 +1524,52 @@ static __devinit int tegra_aic326x_driver_probe(struct platform_device *pdev)
        }
 #endif
 
+       if (pdata->edp_states == NULL)
+               return 0;
+
+       machine->spk_edp_client = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct edp_client),
+                                       GFP_KERNEL);
+       if (IS_ERR_OR_NULL(machine->spk_edp_client)) {
+               dev_err(&pdev->dev, "could not allocate edp client\n");
+               return 0;
+       }
+       machine->spk_edp_client->name[EDP_NAME_LEN - 1] = '\0';
+       strncpy(machine->spk_edp_client->name, "speaker", EDP_NAME_LEN - 1);
+       machine->spk_edp_client->states = pdata->edp_states;
+       machine->spk_edp_client->num_states = TEGRA_SPK_EDP_NUM_STATES;
+       machine->spk_edp_client->e0_index = TEGRA_SPK_EDP_ZERO;
+       machine->spk_edp_client->priority = EDP_MAX_PRIO - 2;
+       machine->spk_edp_client->throttle = tegra_speaker_throttle;
+       machine->spk_edp_client->private_data = machine;
+
+       battery_manager = edp_get_manager("battery");
+       if (!battery_manager) {
+               dev_err(&pdev->dev, "unable to get edp manager\n");
+       } else {
+               /* register speaker edp client */
+               ret = edp_register_client(battery_manager,
+                                       machine->spk_edp_client);
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to register edp client\n");
+                       devm_kfree(&pdev->dev, machine->spk_edp_client);
+                       machine->spk_edp_client = NULL;
+                       return 0;
+               }
+               codec = card->rtd[DAI_LINK_HIFI].codec;
+               /*  set speaker amplifier volume to 6 dB , E0 state*/
+               snd_soc_write(codec, AIC3262_SPK_AMP_CNTL_R4, 0x11);
+               /* request E1 */
+               ret = edp_update_client_request(machine->spk_edp_client,
+                               TEGRA_SPK_EDP_1, NULL);
+               if (ret) {
+                       dev_err(&pdev->dev,
+                                       "unable to set E1 EDP state\n");
+                       edp_unregister_client(machine->spk_edp_client);
+                       devm_kfree(&pdev->dev, machine->spk_edp_client);
+                       machine->spk_edp_client = NULL;
+               }
+       }
        return 0;
 
 err_unregister_card:
index 3f5d600..aff9392 100644 (file)
@@ -1463,17 +1463,18 @@ static __devinit int tegra_cs42l73_driver_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev, "unable to register edp client\n");
                        devm_kfree(&pdev->dev, machine->spk_edp_client);
                        machine->spk_edp_client = NULL;
+                       return 0;
                }
                codec = card->rtd[DAI_LINK_HIFI].codec;
                /* set codec volume to 0 dB , E0 state*/
                snd_soc_write(codec, CS42L73_SPKDVOL, 0x0);
                snd_soc_write(codec, CS42L73_ESLDVOL, 0x0);
-               /* request E0 */
+               /* request E1 */
                ret = edp_update_client_request(machine->spk_edp_client,
-                               TEGRA_SPK_EDP_ZERO, NULL);
+                               TEGRA_SPK_EDP_1, NULL);
                if (ret) {
                        dev_err(&pdev->dev,
-                                       "unable to set E0 EDP state\n");
+                                       "unable to set E1 EDP state\n");
                        edp_unregister_client(machine->spk_edp_client);
                        devm_kfree(&pdev->dev, machine->spk_edp_client);
                        machine->spk_edp_client = NULL;