diff options
author | Ola Lilja <elilola@steludxu2785.(none)> | 2011-04-27 16:07:50 +0200 |
---|---|---|
committer | Jonas ABERG <jonas.aberg@stericsson.com> | 2011-04-28 14:52:32 +0200 |
commit | cca519d4e671d063997762827266119b242271f3 (patch) | |
tree | b2f76511357a68e42e8ad5f1c781bad696a086d2 /sound | |
parent | 8c47a81fd5ae01ccb4f7a2a5cd808e3dff873490 (diff) |
Ux500 ASoC: Move enabling of regulators
Regulators is no longer enabled during machine-driver init,
but rather done before playback, and disabled after playback
is finished.
Change-Id: I5f6bfc3dd60b139ce4e786160104e4daaa4040fc
Signed-off-by: Ola Lilja <ola.o.lilja@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/21788
Reviewed-by: Roger NILSSON1 <roger.xr.nilsson@stericsson.com>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/ab8500_audio.c | 76 | ||||
-rw-r--r-- | sound/soc/codecs/ab8500_audio.h | 5 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_ab8500.c | 204 |
3 files changed, 165 insertions, 120 deletions
diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c index 5191328142d..b84a6bd389f 100644 --- a/sound/soc/codecs/ab8500_audio.c +++ b/sound/soc/codecs/ab8500_audio.c @@ -174,7 +174,6 @@ static struct clk *clk_ptr_audioclk; static struct clk *clk_ptr_sysclk; static DEFINE_MUTEX(power_lock); static int ab8500_power_count; -static bool ab8500_vibra_on; /* Reads an arbitrary register from the ab8500 chip. */ @@ -1619,6 +1618,28 @@ static int ab8500_codec_set_bit_delay_if1(struct snd_soc_codec *codec, unsigned return 0; } +/* Configures audio macrocell into the AB8500 Chip */ +static void ab8500_codec_configure_audio_macrocell(struct snd_soc_codec *codec) +{ + int data; + + data = ab8500_codec_read_reg(codec, AB8500_SYS_CTRL2_BLOCK, AB8500_CTRL3_REG); + data &= ~CLK_32K_OUT2_DISABLE; + ab8500_codec_write_reg(codec, AB8500_SYS_CTRL2_BLOCK, AB8500_CTRL3_REG, data); + data |= INACTIVE_RESET_AUDIO; + ab8500_codec_write_reg(codec, AB8500_SYS_CTRL2_BLOCK, AB8500_CTRL3_REG, data); + + data = ab8500_codec_read_reg(codec, AB8500_SYS_CTRL2_BLOCK, + AB8500_SYSULPCLK_CTRL1_REG); + data |= ENABLE_AUDIO_CLK_TO_AUDIO_BLK; + ab8500_codec_write_reg(codec, AB8500_SYS_CTRL2_BLOCK, + AB8500_SYSULPCLK_CTRL1_REG, data); + + data = ab8500_codec_read_reg(codec, AB8500_MISC, AB8500_GPIO_DIR4_REG); + data |= GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | GPIO31_DIR_OUTPUT; + ab8500_codec_write_reg(codec, AB8500_MISC, AB8500_GPIO_DIR4_REG, data); +} + static int ab8500_codec_power_control_inc(struct snd_soc_codec *codec) { int ret; @@ -1679,30 +1700,27 @@ static void ab8500_codec_power_control_dec(struct snd_soc_codec *codec) void ab8500_audio_pwm_vibra(unsigned char speed_left_pos, unsigned char speed_left_neg, unsigned char speed_right_pos, - unsigned char speed_right_neg) + unsigned char speed_right_neg, + bool power_change) { unsigned int clear_mask, set_mask; - bool ab8500_vibra_on_new; + bool vibra_on; if (ab8500_codec == NULL) { pr_err("%s: ERROR: AB8500 ASoC-driver not yet probed!\n", __func__); return; } - ab8500_vibra_on_new = speed_left_pos | speed_left_neg | speed_right_pos | speed_right_neg; - if (!ab8500_vibra_on_new) { - pr_debug("%s: PWM-vibra off.\n", __func__); - clear_mask = BMASK(REG_ANACONF4_ENVIB1) | BMASK(REG_ANACONF4_ENVIB2); - ab8500_codec_update_reg_audio(ab8500_codec, REG_ANACONF4, clear_mask, 0x00); - ab8500_vibra_on = false; - ab8500_codec_power_control_dec(ab8500_codec); - return; - } - - if (!ab8500_vibra_on) { - pr_debug("%s: PWM-vibra on.\n", __func__); - ab8500_vibra_on = true; - ab8500_codec_power_control_inc(ab8500_codec); + if (power_change) { + vibra_on = speed_left_pos | speed_left_neg | speed_right_pos | speed_right_neg; + if (vibra_on) { + ab8500_codec_power_control_inc(ab8500_codec); + } else { + clear_mask = BMASK(REG_ANACONF4_ENVIB1) | BMASK(REG_ANACONF4_ENVIB2); + ab8500_codec_update_reg_audio(ab8500_codec, REG_ANACONF4, clear_mask, 0x00); + ab8500_codec_power_control_dec(ab8500_codec); + return; + } } pr_debug("%s: PWM-vibra (%d, %d, %d, %d).\n", @@ -1858,7 +1876,6 @@ static int ab8500_codec_pcm_startup(struct snd_pcm_substream *substream, { pr_debug("%s Enter.\n", __func__); - return 0; } @@ -2184,28 +2201,6 @@ struct snd_soc_dai_driver ab8500_codec_dai[] = { } }; -/* Configures audio macrocell into the AB8500 Chip */ -static void ab8500_codec_configure_audio_macrocell(struct snd_soc_codec *codec) -{ - int data; - - data = ab8500_codec_read_reg(codec, AB8500_SYS_CTRL2_BLOCK, AB8500_CTRL3_REG); - data &= ~CLK_32K_OUT2_DISABLE; - ab8500_codec_write_reg(codec, AB8500_SYS_CTRL2_BLOCK, AB8500_CTRL3_REG, data); - data |= INACTIVE_RESET_AUDIO; - ab8500_codec_write_reg(codec, AB8500_SYS_CTRL2_BLOCK, AB8500_CTRL3_REG, data); - - data = ab8500_codec_read_reg(codec, AB8500_SYS_CTRL2_BLOCK, - AB8500_SYSULPCLK_CTRL1_REG); - data |= ENABLE_AUDIO_CLK_TO_AUDIO_BLK; - ab8500_codec_write_reg(codec, AB8500_SYS_CTRL2_BLOCK, - AB8500_SYSULPCLK_CTRL1_REG, data); - - data = ab8500_codec_read_reg(codec, AB8500_MISC, AB8500_GPIO_DIR4_REG); - data |= GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | GPIO31_DIR_OUTPUT; - ab8500_codec_write_reg(codec, AB8500_MISC, AB8500_GPIO_DIR4_REG, data); -} - static int ab8500_codec_probe(struct snd_soc_codec *codec) { int i, ret; @@ -2233,7 +2228,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) } ab8500_codec = codec; - ab8500_vibra_on = false; ab8500_power_count = 0; clk_ptr_sysclk = clk_get(codec->dev, "sysclk"); diff --git a/sound/soc/codecs/ab8500_audio.h b/sound/soc/codecs/ab8500_audio.h index 3bdb141bb76..8f66801eaf0 100644 --- a/sound/soc/codecs/ab8500_audio.h +++ b/sound/soc/codecs/ab8500_audio.h @@ -23,6 +23,11 @@ extern struct snd_soc_dai_driver ab8500_codec_dai[]; extern struct snd_soc_codec_driver soc_codec_dev_ab8500; /* Extended interface for codec-driver */ +void ab8500_audio_pwm_vibra(unsigned char speed_left_pos, + unsigned char speed_left_neg, + unsigned char speed_right_pos, + unsigned char speed_right_neg, + bool power_change); int ab8500_audio_set_word_length(struct snd_soc_dai *dai, unsigned int wl); int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, unsigned int delay); int ab8500_audio_setup_if1(struct snd_soc_codec *codec, diff --git a/sound/soc/ux500/ux500_ab8500.c b/sound/soc/ux500/ux500_ab8500.c index f1ef75fcba0..4ffac884635 100644 --- a/sound/soc/ux500/ux500_ab8500.c +++ b/sound/soc/ux500/ux500_ab8500.c @@ -55,15 +55,59 @@ static struct regulator_bulk_data ab8500_regus[4] = { { .supply = "v-amic2" } }; +static int enable_regulator(const char *name) +{ + int i, status; + + for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) { + if (strcmp(name, ab8500_regus[i].supply) != 0) + continue; + + status = regulator_enable(ab8500_regus[i].consumer); + if (status != 0) { + pr_err("%s: Failure with regulator %s (%d)\n", + __func__, name, status); + return status; + }; + + pr_debug("%s: Enabled regulator %s.\n", __func__, name); + return 0; + } + + return -EINVAL; +} + +static void disable_regulator(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) { + if (strcmp(name, ab8500_regus[i].supply) == 0) { + regulator_disable(ab8500_regus[i].consumer); + pr_debug("%s: Disabled regulator %s.\n", __func__, name); + return; + } + } +} + int ux500_ab8500_startup(struct snd_pcm_substream *substream) { + int i; + int status = 0; + pr_info("%s: Enter\n", __func__); - return 0; + /* Enable regulators */ + for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) + status += enable_regulator(ab8500_regus[i].supply); + + return status; } void ux500_ab8500_shutdown(struct snd_pcm_substream *substream) { + int i; + pr_info("%s: Enter\n", __func__); /* Reset slots configuration to default(s) */ @@ -71,6 +115,10 @@ void ux500_ab8500_shutdown(struct snd_pcm_substream *substream) tx_slots = DEF_TX_SLOTS; else rx_slots = DEF_RX_SLOTS; + + /* Disable regulators */ + for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) + disable_regulator(ab8500_regus[i].supply); } int ux500_ab8500_hw_params(struct snd_pcm_substream *substream, @@ -184,11 +232,50 @@ int ux500_ab8500_hw_params(struct snd_pcm_substream *substream, return 0; } +static int create_jack(struct snd_soc_codec *codec) +{ + return snd_soc_jack_new(codec, + "AB8500 Hs Status", + SND_JACK_HEADPHONE | + SND_JACK_MICROPHONE | + SND_JACK_HEADSET | + SND_JACK_LINEOUT | + SND_JACK_MECHANICAL | + SND_JACK_VIDEOOUT, + &jack); +} + +void ux500_ab8500_jack_report(int value) +{ + if (jack.jack) + snd_soc_jack_report(&jack, value, 0xFF); +} +EXPORT_SYMBOL_GPL(ux500_ab8500_jack_report); + + +int ux500_ab8500_machine_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_codec *codec = rtd->codec; + int status; + + pr_info("%s Enter.\n", __func__); + + /* TODO: Add required DAPM routes to control regulators on demand */ + + status = create_jack(codec); + if (status < 0) { + pr_err("%s: Failed to create Jack (%d).\n", __func__, status); + return status; + } + + return 0; +} + static int create_regulators(void) { int i, status = 0; - pr_info("%s: Enter.\n", __func__); + pr_debug("%s: Enter.\n", __func__); for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) ab8500_regus[i].consumer = NULL; @@ -219,84 +306,50 @@ err_get: return status; } -static int enable_regulator(const char *name) -{ - int i, status; - - for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) { - if (strcmp(name, ab8500_regus[i].supply) != 0) - continue; - - status = regulator_enable(ab8500_regus[i].consumer); +static bool vibra_on; - if (status != 0) { - pr_err("%s: Failure with regulator %s (%d)\n", - __func__, name, status); - return status; - } else { - pr_info("%s: Enabled regulator %s.\n", - __func__, name); - return 0; - } - } - - return -EINVAL; -} - -static void disable_regulator(const char *name) +void ux500_ab8500_audio_pwm_vibra(unsigned char speed_left_pos, + unsigned char speed_left_neg, + unsigned char speed_right_pos, + unsigned char speed_right_neg) { - int i; - - for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) { - if (strcmp(name, ab8500_regus[i].supply) == 0) { - regulator_disable(ab8500_regus[i].consumer); - return; - } + int i, ret; + bool vibra_on_new; + bool power_change = false; + + vibra_on_new = speed_left_pos | speed_left_neg | speed_right_pos | speed_right_neg; + if ((!vibra_on_new) && (vibra_on)) { + for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) + disable_regulator(ab8500_regus[i].supply); + + pr_debug("%s: PWM-vibra off.\n", __func__); + vibra_on = false; + power_change = true; } -} - -static int create_jack(struct snd_soc_codec *codec) -{ - return snd_soc_jack_new(codec, - "AB8500 Hs Status", - SND_JACK_HEADPHONE | - SND_JACK_MICROPHONE | - SND_JACK_HEADSET | - SND_JACK_LINEOUT | - SND_JACK_MECHANICAL | - SND_JACK_VIDEOOUT, - &jack); -} - -void ux500_ab8500_jack_report(int value) -{ - if (jack.jack) - snd_soc_jack_report(&jack, value, 0xFF); -} -EXPORT_SYMBOL_GPL(ux500_ab8500_jack_report); - -int ux500_ab8500_machine_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_codec *codec = rtd->codec; - int status; - - pr_info("%s Enter.\n", __func__); - - /* TODO: Add required DAPM routes to control regulators on demand */ - - status = create_jack(codec); - if (status < 0) { - pr_err("%s: Failed to create Jack (%d).\n", __func__, status); - return status; + if ((vibra_on_new) && (!vibra_on)) { + ret = 0; + for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) + ret += enable_regulator(ab8500_regus[i].supply); + if (ret < 0) + pr_err("%s: ERROR: Unable to enable regulators (ret = %d)!\n", + __func__, + ret); + + pr_debug("%s: PWM-vibra on.\n", __func__); + vibra_on = true; + power_change = true; } - return 0; + ab8500_audio_pwm_vibra(speed_left_pos, + speed_left_neg, + speed_right_pos, + speed_right_neg, + power_change); } int ux500_ab8500_soc_machine_drv_init(void) { - int i; int status = 0; pr_info("%s: Enter.\n", __func__); @@ -308,22 +361,15 @@ int ux500_ab8500_soc_machine_drv_init(void) return status; } - /* TODO: Enable only regulators really needed at this point.. */ - for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) - status += enable_regulator(ab8500_regus[i].supply); + vibra_on = false; - return status; + return 0; } void ux500_ab8500_soc_machine_drv_cleanup(void) { - int i; - pr_info("%s: Enter.\n", __func__); - /* Roll out all the regulators */ - for (i = 0; i < ARRAY_SIZE(ab8500_regus); ++i) - disable_regulator(ab8500_regus[i].supply); regulator_bulk_free(ARRAY_SIZE(ab8500_regus), ab8500_regus); } |