0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/clk.h>
0011 #include <linux/i2c.h>
0012 #include <linux/platform_device.h>
0013 #include <sound/core.h>
0014 #include <sound/pcm.h>
0015 #include <sound/soc.h>
0016
0017 #include <asm/mach-types.h>
0018 #include <linux/gpio.h>
0019 #include <linux/module.h>
0020 #include <linux/platform_data/asoc-ti-mcbsp.h>
0021
0022 #include "omap-mcbsp.h"
0023
0024 #define N810_HEADSET_AMP_GPIO 10
0025 #define N810_SPEAKER_AMP_GPIO 101
0026
0027 enum {
0028 N810_JACK_DISABLED,
0029 N810_JACK_HP,
0030 N810_JACK_HS,
0031 N810_JACK_MIC,
0032 };
0033
0034 static struct clk *sys_clkout2;
0035 static struct clk *sys_clkout2_src;
0036 static struct clk *func96m_clk;
0037
0038 static int n810_spk_func;
0039 static int n810_jack_func;
0040 static int n810_dmic_func;
0041
0042 static void n810_ext_control(struct snd_soc_dapm_context *dapm)
0043 {
0044 int hp = 0, line1l = 0;
0045
0046 switch (n810_jack_func) {
0047 case N810_JACK_HS:
0048 line1l = 1;
0049 fallthrough;
0050 case N810_JACK_HP:
0051 hp = 1;
0052 break;
0053 case N810_JACK_MIC:
0054 line1l = 1;
0055 break;
0056 }
0057
0058 snd_soc_dapm_mutex_lock(dapm);
0059
0060 if (n810_spk_func)
0061 snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
0062 else
0063 snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
0064
0065 if (hp)
0066 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
0067 else
0068 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
0069 if (line1l)
0070 snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic");
0071 else
0072 snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic");
0073
0074 if (n810_dmic_func)
0075 snd_soc_dapm_enable_pin_unlocked(dapm, "DMic");
0076 else
0077 snd_soc_dapm_disable_pin_unlocked(dapm, "DMic");
0078
0079 snd_soc_dapm_sync_unlocked(dapm);
0080
0081 snd_soc_dapm_mutex_unlock(dapm);
0082 }
0083
0084 static int n810_startup(struct snd_pcm_substream *substream)
0085 {
0086 struct snd_pcm_runtime *runtime = substream->runtime;
0087 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0088
0089 snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2);
0090
0091 n810_ext_control(&rtd->card->dapm);
0092 return clk_prepare_enable(sys_clkout2);
0093 }
0094
0095 static void n810_shutdown(struct snd_pcm_substream *substream)
0096 {
0097 clk_disable_unprepare(sys_clkout2);
0098 }
0099
0100 static int n810_hw_params(struct snd_pcm_substream *substream,
0101 struct snd_pcm_hw_params *params)
0102 {
0103 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
0104 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
0105 int err;
0106
0107
0108 err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000,
0109 SND_SOC_CLOCK_IN);
0110
0111 return err;
0112 }
0113
0114 static const struct snd_soc_ops n810_ops = {
0115 .startup = n810_startup,
0116 .hw_params = n810_hw_params,
0117 .shutdown = n810_shutdown,
0118 };
0119
0120 static int n810_get_spk(struct snd_kcontrol *kcontrol,
0121 struct snd_ctl_elem_value *ucontrol)
0122 {
0123 ucontrol->value.enumerated.item[0] = n810_spk_func;
0124
0125 return 0;
0126 }
0127
0128 static int n810_set_spk(struct snd_kcontrol *kcontrol,
0129 struct snd_ctl_elem_value *ucontrol)
0130 {
0131 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0132
0133 if (n810_spk_func == ucontrol->value.enumerated.item[0])
0134 return 0;
0135
0136 n810_spk_func = ucontrol->value.enumerated.item[0];
0137 n810_ext_control(&card->dapm);
0138
0139 return 1;
0140 }
0141
0142 static int n810_get_jack(struct snd_kcontrol *kcontrol,
0143 struct snd_ctl_elem_value *ucontrol)
0144 {
0145 ucontrol->value.enumerated.item[0] = n810_jack_func;
0146
0147 return 0;
0148 }
0149
0150 static int n810_set_jack(struct snd_kcontrol *kcontrol,
0151 struct snd_ctl_elem_value *ucontrol)
0152 {
0153 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0154
0155 if (n810_jack_func == ucontrol->value.enumerated.item[0])
0156 return 0;
0157
0158 n810_jack_func = ucontrol->value.enumerated.item[0];
0159 n810_ext_control(&card->dapm);
0160
0161 return 1;
0162 }
0163
0164 static int n810_get_input(struct snd_kcontrol *kcontrol,
0165 struct snd_ctl_elem_value *ucontrol)
0166 {
0167 ucontrol->value.enumerated.item[0] = n810_dmic_func;
0168
0169 return 0;
0170 }
0171
0172 static int n810_set_input(struct snd_kcontrol *kcontrol,
0173 struct snd_ctl_elem_value *ucontrol)
0174 {
0175 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
0176
0177 if (n810_dmic_func == ucontrol->value.enumerated.item[0])
0178 return 0;
0179
0180 n810_dmic_func = ucontrol->value.enumerated.item[0];
0181 n810_ext_control(&card->dapm);
0182
0183 return 1;
0184 }
0185
0186 static int n810_spk_event(struct snd_soc_dapm_widget *w,
0187 struct snd_kcontrol *k, int event)
0188 {
0189 if (SND_SOC_DAPM_EVENT_ON(event))
0190 gpio_set_value(N810_SPEAKER_AMP_GPIO, 1);
0191 else
0192 gpio_set_value(N810_SPEAKER_AMP_GPIO, 0);
0193
0194 return 0;
0195 }
0196
0197 static int n810_jack_event(struct snd_soc_dapm_widget *w,
0198 struct snd_kcontrol *k, int event)
0199 {
0200 if (SND_SOC_DAPM_EVENT_ON(event))
0201 gpio_set_value(N810_HEADSET_AMP_GPIO, 1);
0202 else
0203 gpio_set_value(N810_HEADSET_AMP_GPIO, 0);
0204
0205 return 0;
0206 }
0207
0208 static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
0209 SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
0210 SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
0211 SND_SOC_DAPM_MIC("DMic", NULL),
0212 SND_SOC_DAPM_MIC("HS Mic", NULL),
0213 };
0214
0215 static const struct snd_soc_dapm_route audio_map[] = {
0216 {"Headphone Jack", NULL, "HPLOUT"},
0217 {"Headphone Jack", NULL, "HPROUT"},
0218
0219 {"Ext Spk", NULL, "LLOUT"},
0220 {"Ext Spk", NULL, "RLOUT"},
0221
0222 {"DMic Rate 64", NULL, "DMic"},
0223 {"DMic", NULL, "Mic Bias"},
0224
0225
0226
0227
0228
0229 {"LINE1L", NULL, "HS Mic"},
0230 };
0231
0232 static const char *spk_function[] = {"Off", "On"};
0233 static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"};
0234 static const char *input_function[] = {"ADC", "Digital Mic"};
0235 static const struct soc_enum n810_enum[] = {
0236 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function),
0237 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function),
0238 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function),
0239 };
0240
0241 static const struct snd_kcontrol_new aic33_n810_controls[] = {
0242 SOC_ENUM_EXT("Speaker Function", n810_enum[0],
0243 n810_get_spk, n810_set_spk),
0244 SOC_ENUM_EXT("Jack Function", n810_enum[1],
0245 n810_get_jack, n810_set_jack),
0246 SOC_ENUM_EXT("Input Select", n810_enum[2],
0247 n810_get_input, n810_set_input),
0248 };
0249
0250
0251 SND_SOC_DAILINK_DEFS(aic33,
0252 DAILINK_COMP_ARRAY(COMP_CPU("48076000.mcbsp")),
0253 DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018",
0254 "tlv320aic3x-hifi")),
0255 DAILINK_COMP_ARRAY(COMP_PLATFORM("48076000.mcbsp")));
0256
0257 static struct snd_soc_dai_link n810_dai = {
0258 .name = "TLV320AIC33",
0259 .stream_name = "AIC33",
0260 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
0261 SND_SOC_DAIFMT_CBM_CFM,
0262 .ops = &n810_ops,
0263 SND_SOC_DAILINK_REG(aic33),
0264 };
0265
0266
0267 static struct snd_soc_card snd_soc_n810 = {
0268 .name = "N810",
0269 .owner = THIS_MODULE,
0270 .dai_link = &n810_dai,
0271 .num_links = 1,
0272
0273 .controls = aic33_n810_controls,
0274 .num_controls = ARRAY_SIZE(aic33_n810_controls),
0275 .dapm_widgets = aic33_dapm_widgets,
0276 .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets),
0277 .dapm_routes = audio_map,
0278 .num_dapm_routes = ARRAY_SIZE(audio_map),
0279 .fully_routed = true,
0280 };
0281
0282 static struct platform_device *n810_snd_device;
0283
0284 static int __init n810_soc_init(void)
0285 {
0286 int err;
0287 struct device *dev;
0288
0289 if (!of_have_populated_dt() ||
0290 (!of_machine_is_compatible("nokia,n810") &&
0291 !of_machine_is_compatible("nokia,n810-wimax")))
0292 return -ENODEV;
0293
0294 n810_snd_device = platform_device_alloc("soc-audio", -1);
0295 if (!n810_snd_device)
0296 return -ENOMEM;
0297
0298 platform_set_drvdata(n810_snd_device, &snd_soc_n810);
0299 err = platform_device_add(n810_snd_device);
0300 if (err)
0301 goto err1;
0302
0303 dev = &n810_snd_device->dev;
0304
0305 sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
0306 if (IS_ERR(sys_clkout2_src)) {
0307 dev_err(dev, "Could not get sys_clkout2_src clock\n");
0308 err = PTR_ERR(sys_clkout2_src);
0309 goto err2;
0310 }
0311 sys_clkout2 = clk_get(dev, "sys_clkout2");
0312 if (IS_ERR(sys_clkout2)) {
0313 dev_err(dev, "Could not get sys_clkout2\n");
0314 err = PTR_ERR(sys_clkout2);
0315 goto err3;
0316 }
0317
0318
0319
0320
0321 func96m_clk = clk_get(dev, "func_96m_ck");
0322 if (IS_ERR(func96m_clk)) {
0323 dev_err(dev, "Could not get func 96M clock\n");
0324 err = PTR_ERR(func96m_clk);
0325 goto err4;
0326 }
0327 clk_set_parent(sys_clkout2_src, func96m_clk);
0328 clk_set_rate(sys_clkout2, 12000000);
0329
0330 if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) ||
0331 (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) {
0332 err = -EINVAL;
0333 goto err4;
0334 }
0335
0336 gpio_direction_output(N810_HEADSET_AMP_GPIO, 0);
0337 gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0);
0338
0339 return 0;
0340 err4:
0341 clk_put(sys_clkout2);
0342 err3:
0343 clk_put(sys_clkout2_src);
0344 err2:
0345 platform_device_del(n810_snd_device);
0346 err1:
0347 platform_device_put(n810_snd_device);
0348
0349 return err;
0350 }
0351
0352 static void __exit n810_soc_exit(void)
0353 {
0354 gpio_free(N810_SPEAKER_AMP_GPIO);
0355 gpio_free(N810_HEADSET_AMP_GPIO);
0356 clk_put(sys_clkout2_src);
0357 clk_put(sys_clkout2);
0358 clk_put(func96m_clk);
0359
0360 platform_device_unregister(n810_snd_device);
0361 }
0362
0363 module_init(n810_soc_init);
0364 module_exit(n810_soc_exit);
0365
0366 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
0367 MODULE_DESCRIPTION("ALSA SoC Nokia N810");
0368 MODULE_LICENSE("GPL");