summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorDara Ramesh <dramesh@nvidia.com>2013-01-22 20:11:19 +0530
committerRiham Haidar <rhaidar@nvidia.com>2013-01-28 17:30:30 -0800
commitc0eee11129f154781b26ba159286d0db4d3237d6 (patch)
tree20a84f4b77e133a9b443c1c6a45c5b3e7bf01652 /sound
parentd51f612d098328a464278afbafb12c83d7cd411b (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.c100
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: