^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) //
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) // Copyright 2009 Simtec Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/gpio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sound/soc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/platform_data/asoc-s3c24xx_simtec.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "s3c24xx-i2s.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "s3c24xx_simtec.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) static struct s3c24xx_audio_simtec_pdata *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) static struct clk *xtal_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) static int spk_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static int spk_unmute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * speaker_gain_get - read the speaker gain setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * @kcontrol: The control for the speaker gain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * @ucontrol: The value that needs to be updated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * Read the value for the AMP gain control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static int speaker_gain_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) ucontrol->value.integer.value[0] = spk_gain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * speaker_gain_set - set the value of the speaker amp gain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * @value: The value to write.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static void speaker_gain_set(int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) gpio_set_value_cansleep(pdata->amp_gain[0], value & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * speaker_gain_put - set the speaker gain setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @kcontrol: The control for the speaker gain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * @ucontrol: The value that needs to be set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * Set the value of the speaker gain from the specified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * @ucontrol setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * Note, if the speaker amp is muted, then we do not set a gain value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * as at-least one of the ICs that is fitted will try and power up even
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * if the main control is set to off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int speaker_gain_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) int value = ucontrol->value.integer.value[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) spk_gain = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) if (!spk_unmute)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) speaker_gain_set(value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static const struct snd_kcontrol_new amp_gain_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) speaker_gain_get, speaker_gain_put),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * spk_unmute_state - set the unmute state of the speaker
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * @to: zero to unmute, non-zero to ununmute.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static void spk_unmute_state(int to)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) pr_debug("%s: to=%d\n", __func__, to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) spk_unmute = to;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) gpio_set_value(pdata->amp_gpio, to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* if we're umuting, also re-set the gain */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (to && pdata->amp_gain[0] > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) speaker_gain_set(spk_gain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * speaker_unmute_get - read the speaker unmute setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * @kcontrol: The control for the speaker gain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * @ucontrol: The value that needs to be updated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Read the value for the AMP gain control.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static int speaker_unmute_get(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) ucontrol->value.integer.value[0] = spk_unmute;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) * speaker_unmute_put - set the speaker unmute setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * @kcontrol: The control for the speaker gain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * @ucontrol: The value that needs to be set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) * Set the value of the speaker gain from the specified
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) * @ucontrol setting.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static int speaker_unmute_put(struct snd_kcontrol *kcontrol,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) struct snd_ctl_elem_value *ucontrol)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) spk_unmute_state(ucontrol->value.integer.value[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /* This is added as a manual control as the speaker amps create clicks
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * when their power state is changed, which are far more noticeable than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * anything produced by the CODEC itself.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static const struct snd_kcontrol_new amp_unmute_controls[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) speaker_unmute_get, speaker_unmute_put),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) void simtec_audio_init(struct snd_soc_pcm_runtime *rtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) struct snd_soc_card *card = rtd->card;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (pdata->amp_gpio > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) pr_debug("%s: adding amp routes\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) snd_soc_add_card_controls(card, amp_unmute_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ARRAY_SIZE(amp_unmute_controls));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (pdata->amp_gain[0] > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pr_debug("%s: adding amp controls\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) snd_soc_add_card_controls(card, amp_gain_controls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) ARRAY_SIZE(amp_gain_controls));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) EXPORT_SYMBOL_GPL(simtec_audio_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define CODEC_CLOCK 12000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * simtec_hw_params - update hardware parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) * @substream: The audio substream instance.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) * @params: The parameters requested.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * Update the codec data routing and configuration settings
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * from the supplied data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int simtec_hw_params(struct snd_pcm_substream *substream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ret = snd_soc_dai_set_sysclk(codec_dai, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) CODEC_CLOCK, SND_SOC_CLOCK_IN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) pr_err( "%s: failed setting codec sysclk\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (pdata->use_mpllin) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 0, SND_SOC_CLOCK_OUT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) pr_err("%s: failed to set MPLLin as clksrc\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (pdata->output_cdclk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) int cdclk_scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) cdclk_scale--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) cdclk_scale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /* call any board supplied startup code, this currently only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * covers the bast/vr1000 which have a CPLD in the way of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * LRCLK */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (pd->startup)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) pd->startup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static const struct snd_soc_ops simtec_snd_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) .hw_params = simtec_hw_params,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) * attach_gpio_amp - get and configure the necessary gpios
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) * @dev: The device we're probing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) * @pd: The platform data supplied by the board.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) * If there is a GPIO based amplifier attached to the board, claim
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) * the necessary GPIO lines for it, and set default values.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) static int attach_gpio_amp(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) struct s3c24xx_audio_simtec_pdata *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) /* attach gpio amp gain (if any) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (pdata->amp_gain[0] > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) dev_err(dev, "cannot get amp gpio gain0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) dev_err(dev, "cannot get amp gpio gain1\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) gpio_free(pdata->amp_gain[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) gpio_direction_output(pd->amp_gain[0], 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) gpio_direction_output(pd->amp_gain[1], 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) /* note, currently we assume GPA0 isn't valid amp */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (pdata->amp_gpio > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ret = gpio_request(pd->amp_gpio, "gpio-amp");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) dev_err(dev, "cannot get amp gpio %d (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) pd->amp_gpio, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) goto err_amp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* set the amp off at startup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) spk_unmute_state(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) err_amp:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (pd->amp_gain[0] > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) gpio_free(pd->amp_gain[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) gpio_free(pd->amp_gain[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (pd->amp_gain[0] > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) gpio_free(pd->amp_gain[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) gpio_free(pd->amp_gain[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (pd->amp_gpio > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) gpio_free(pd->amp_gpio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) static int simtec_audio_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) simtec_call_startup(pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) const struct dev_pm_ops simtec_audio_pmops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) .resume = simtec_audio_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) EXPORT_SYMBOL_GPL(simtec_audio_pmops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) int simtec_audio_core_probe(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct snd_soc_card *card)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct platform_device *snd_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) card->dai_link->ops = &simtec_snd_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) card->dai_link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) SND_SOC_DAIFMT_CBM_CFM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) pdata = pdev->dev.platform_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (!pdata) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) dev_err(&pdev->dev, "no platform data supplied\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) simtec_call_startup(pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) xtal_clk = clk_get(&pdev->dev, "xtal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (IS_ERR(xtal_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) dev_err(&pdev->dev, "could not get clkout0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) ret = attach_gpio_amp(&pdev->dev, pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) goto err_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) snd_dev = platform_device_alloc("soc-audio", -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) if (!snd_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) goto err_gpio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) platform_set_drvdata(snd_dev, card);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ret = platform_device_add(snd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) dev_err(&pdev->dev, "failed to add soc-audio dev\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) goto err_pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) platform_set_drvdata(pdev, snd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) err_pdev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) platform_device_put(snd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) err_gpio:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) detach_gpio_amp(pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) err_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) clk_put(xtal_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) EXPORT_SYMBOL_GPL(simtec_audio_core_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) int simtec_audio_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct platform_device *snd_dev = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) platform_device_unregister(snd_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) detach_gpio_amp(pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) clk_put(xtal_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) EXPORT_SYMBOL_GPL(simtec_audio_remove);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) MODULE_LICENSE("GPL");