Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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");