diff options
author | Dara Ramesh <dramesh@nvidia.com> | 2013-01-22 20:11:19 +0530 |
---|---|---|
committer | Riham Haidar <rhaidar@nvidia.com> | 2013-01-28 17:30:30 -0800 |
commit | c0eee11129f154781b26ba159286d0db4d3237d6 (patch) | |
tree | 20a84f4b77e133a9b443c1c6a45c5b3e7bf01652 /sound | |
parent | d51f612d098328a464278afbafb12c83d7cd411b (diff) |
soc: tegra: cs42l73: add speaker AMP EDP support
a) registered speaker AMP EDP client
b) implemented throttle callback function for EDP
Bug 1160686
Change-Id: I79906d3fd5dbfbedea7512d9745c59d700e325d5
Signed-off-by: Dara Ramesh <dramesh@nvidia.com>
Reviewed-on: http://git-master/r/193065
Reviewed-by: Riham Haidar <rhaidar@nvidia.com>
Tested-by: Riham Haidar <rhaidar@nvidia.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/tegra/tegra_cs42l73.c | 100 |
1 files changed, 99 insertions, 1 deletions
diff --git a/sound/soc/tegra/tegra_cs42l73.c b/sound/soc/tegra/tegra_cs42l73.c index 2b71cdd9c00c..3f5d600ab974 100644 --- a/sound/soc/tegra/tegra_cs42l73.c +++ b/sound/soc/tegra/tegra_cs42l73.c @@ -1,4 +1,4 @@ -/* + /* * tegra_cs42l73.c - Tegra machine ASoC driver for boards using CS42L73 codec. * * Author: Vijay Mali <vmali@nvidia.com> @@ -31,6 +31,7 @@ #include <linux/regulator/consumer.h> #include <linux/delay.h> #include <linux/a2220.h> +#include <linux/edp.h> #ifdef CONFIG_SWITCH #include <linux/switch.h> #endif @@ -92,6 +93,7 @@ struct tegra_cs42l73 { struct regulator *dmic_1v8_reg; struct regulator *hmic_reg; struct regulator *spkr_reg; + struct edp_client *spk_edp_client; enum snd_soc_bias_level bias_level; struct snd_soc_card *pcard; #ifdef CONFIG_SWITCH @@ -968,13 +970,34 @@ static int tegra_cs42l73_event_int_mic(struct snd_soc_dapm_widget *w, return 0; } +static void tegra_speaker_throttle(unsigned int new_state, void *priv_data) +{ + struct tegra_cs42l73 *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 codec voulme to 0 dB, E0 state */ + snd_soc_write(codec, CS42L73_SPKDVOL, 0x0); + snd_soc_write(codec, CS42L73_ESLDVOL, 0x0); + +} + static int tegra_cs42l73_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_cs42l73 *machine = snd_soc_card_get_drvdata(card); struct tegra_asoc_platform_data *pdata = machine->pdata; + unsigned int approved; + int ret; if (machine->spkr_reg) { if (SND_SOC_DAPM_EVENT_ON(event)) @@ -983,6 +1006,32 @@ static int tegra_cs42l73_event_int_spk(struct snd_soc_dapm_widget *w, regulator_disable(machine->spkr_reg); } + 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 codec voulme to 0 dB, E0 state */ + snd_soc_write(codec, CS42L73_SPKDVOL, 0x0); + snd_soc_write(codec, CS42L73_ESLDVOL, 0x0); + } else { + /* set codec voulme to +6 dB, E-1 state */ + snd_soc_write(codec, CS42L73_SPKDVOL, 0x0c); + snd_soc_write(codec, CS42L73_ESLDVOL, 0x0c); + } + } 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; @@ -1254,8 +1303,10 @@ static struct snd_soc_card snd_soc_tegra_cs42l73 = { static __devinit int tegra_cs42l73_driver_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_tegra_cs42l73; + struct snd_soc_codec *codec; struct tegra_cs42l73 *machine; struct tegra_asoc_platform_data *pdata; + struct edp_manager *battery_manager = NULL; int ret; int i; pdata = pdev->dev.platform_data; @@ -1382,6 +1433,53 @@ static __devinit int tegra_cs42l73_driver_probe(struct platform_device *pdev) goto err_unregister_card; } + 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; + } + 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 */ + ret = edp_update_client_request(machine->spk_edp_client, + TEGRA_SPK_EDP_ZERO, NULL); + if (ret) { + dev_err(&pdev->dev, + "unable to set E0 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: |