n810.c (9141B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * n810.c -- SoC audio for Nokia N810 4 * 5 * Copyright (C) 2008 Nokia Corporation 6 * 7 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> 8 */ 9 10#include <linux/clk.h> 11#include <linux/i2c.h> 12#include <linux/platform_device.h> 13#include <sound/core.h> 14#include <sound/pcm.h> 15#include <sound/soc.h> 16 17#include <asm/mach-types.h> 18#include <linux/gpio.h> 19#include <linux/module.h> 20#include <linux/platform_data/asoc-ti-mcbsp.h> 21 22#include "omap-mcbsp.h" 23 24#define N810_HEADSET_AMP_GPIO 10 25#define N810_SPEAKER_AMP_GPIO 101 26 27enum { 28 N810_JACK_DISABLED, 29 N810_JACK_HP, 30 N810_JACK_HS, 31 N810_JACK_MIC, 32}; 33 34static struct clk *sys_clkout2; 35static struct clk *sys_clkout2_src; 36static struct clk *func96m_clk; 37 38static int n810_spk_func; 39static int n810_jack_func; 40static int n810_dmic_func; 41 42static void n810_ext_control(struct snd_soc_dapm_context *dapm) 43{ 44 int hp = 0, line1l = 0; 45 46 switch (n810_jack_func) { 47 case N810_JACK_HS: 48 line1l = 1; 49 fallthrough; 50 case N810_JACK_HP: 51 hp = 1; 52 break; 53 case N810_JACK_MIC: 54 line1l = 1; 55 break; 56 } 57 58 snd_soc_dapm_mutex_lock(dapm); 59 60 if (n810_spk_func) 61 snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); 62 else 63 snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); 64 65 if (hp) 66 snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); 67 else 68 snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); 69 if (line1l) 70 snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); 71 else 72 snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); 73 74 if (n810_dmic_func) 75 snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); 76 else 77 snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); 78 79 snd_soc_dapm_sync_unlocked(dapm); 80 81 snd_soc_dapm_mutex_unlock(dapm); 82} 83 84static int n810_startup(struct snd_pcm_substream *substream) 85{ 86 struct snd_pcm_runtime *runtime = substream->runtime; 87 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 88 89 snd_pcm_hw_constraint_single(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, 2); 90 91 n810_ext_control(&rtd->card->dapm); 92 return clk_prepare_enable(sys_clkout2); 93} 94 95static void n810_shutdown(struct snd_pcm_substream *substream) 96{ 97 clk_disable_unprepare(sys_clkout2); 98} 99 100static int n810_hw_params(struct snd_pcm_substream *substream, 101 struct snd_pcm_hw_params *params) 102{ 103 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 104 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 105 int err; 106 107 /* Set the codec system clock for DAC and ADC */ 108 err = snd_soc_dai_set_sysclk(codec_dai, 0, 12000000, 109 SND_SOC_CLOCK_IN); 110 111 return err; 112} 113 114static const struct snd_soc_ops n810_ops = { 115 .startup = n810_startup, 116 .hw_params = n810_hw_params, 117 .shutdown = n810_shutdown, 118}; 119 120static int n810_get_spk(struct snd_kcontrol *kcontrol, 121 struct snd_ctl_elem_value *ucontrol) 122{ 123 ucontrol->value.enumerated.item[0] = n810_spk_func; 124 125 return 0; 126} 127 128static int n810_set_spk(struct snd_kcontrol *kcontrol, 129 struct snd_ctl_elem_value *ucontrol) 130{ 131 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 132 133 if (n810_spk_func == ucontrol->value.enumerated.item[0]) 134 return 0; 135 136 n810_spk_func = ucontrol->value.enumerated.item[0]; 137 n810_ext_control(&card->dapm); 138 139 return 1; 140} 141 142static int n810_get_jack(struct snd_kcontrol *kcontrol, 143 struct snd_ctl_elem_value *ucontrol) 144{ 145 ucontrol->value.enumerated.item[0] = n810_jack_func; 146 147 return 0; 148} 149 150static int n810_set_jack(struct snd_kcontrol *kcontrol, 151 struct snd_ctl_elem_value *ucontrol) 152{ 153 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 154 155 if (n810_jack_func == ucontrol->value.enumerated.item[0]) 156 return 0; 157 158 n810_jack_func = ucontrol->value.enumerated.item[0]; 159 n810_ext_control(&card->dapm); 160 161 return 1; 162} 163 164static int n810_get_input(struct snd_kcontrol *kcontrol, 165 struct snd_ctl_elem_value *ucontrol) 166{ 167 ucontrol->value.enumerated.item[0] = n810_dmic_func; 168 169 return 0; 170} 171 172static int n810_set_input(struct snd_kcontrol *kcontrol, 173 struct snd_ctl_elem_value *ucontrol) 174{ 175 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); 176 177 if (n810_dmic_func == ucontrol->value.enumerated.item[0]) 178 return 0; 179 180 n810_dmic_func = ucontrol->value.enumerated.item[0]; 181 n810_ext_control(&card->dapm); 182 183 return 1; 184} 185 186static int n810_spk_event(struct snd_soc_dapm_widget *w, 187 struct snd_kcontrol *k, int event) 188{ 189 if (SND_SOC_DAPM_EVENT_ON(event)) 190 gpio_set_value(N810_SPEAKER_AMP_GPIO, 1); 191 else 192 gpio_set_value(N810_SPEAKER_AMP_GPIO, 0); 193 194 return 0; 195} 196 197static int n810_jack_event(struct snd_soc_dapm_widget *w, 198 struct snd_kcontrol *k, int event) 199{ 200 if (SND_SOC_DAPM_EVENT_ON(event)) 201 gpio_set_value(N810_HEADSET_AMP_GPIO, 1); 202 else 203 gpio_set_value(N810_HEADSET_AMP_GPIO, 0); 204 205 return 0; 206} 207 208static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = { 209 SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event), 210 SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event), 211 SND_SOC_DAPM_MIC("DMic", NULL), 212 SND_SOC_DAPM_MIC("HS Mic", NULL), 213}; 214 215static const struct snd_soc_dapm_route audio_map[] = { 216 {"Headphone Jack", NULL, "HPLOUT"}, 217 {"Headphone Jack", NULL, "HPROUT"}, 218 219 {"Ext Spk", NULL, "LLOUT"}, 220 {"Ext Spk", NULL, "RLOUT"}, 221 222 {"DMic Rate 64", NULL, "DMic"}, 223 {"DMic", NULL, "Mic Bias"}, 224 225 /* 226 * Note that the mic bias is coming from Retu/Vilma and we don't have 227 * control over it atm. The analog HS mic is not working. <- TODO 228 */ 229 {"LINE1L", NULL, "HS Mic"}, 230}; 231 232static const char *spk_function[] = {"Off", "On"}; 233static const char *jack_function[] = {"Off", "Headphone", "Headset", "Mic"}; 234static const char *input_function[] = {"ADC", "Digital Mic"}; 235static const struct soc_enum n810_enum[] = { 236 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), 237 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(jack_function), jack_function), 238 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(input_function), input_function), 239}; 240 241static const struct snd_kcontrol_new aic33_n810_controls[] = { 242 SOC_ENUM_EXT("Speaker Function", n810_enum[0], 243 n810_get_spk, n810_set_spk), 244 SOC_ENUM_EXT("Jack Function", n810_enum[1], 245 n810_get_jack, n810_set_jack), 246 SOC_ENUM_EXT("Input Select", n810_enum[2], 247 n810_get_input, n810_set_input), 248}; 249 250/* Digital audio interface glue - connects codec <--> CPU */ 251SND_SOC_DAILINK_DEFS(aic33, 252 DAILINK_COMP_ARRAY(COMP_CPU("48076000.mcbsp")), 253 DAILINK_COMP_ARRAY(COMP_CODEC("tlv320aic3x-codec.1-0018", 254 "tlv320aic3x-hifi")), 255 DAILINK_COMP_ARRAY(COMP_PLATFORM("48076000.mcbsp"))); 256 257static struct snd_soc_dai_link n810_dai = { 258 .name = "TLV320AIC33", 259 .stream_name = "AIC33", 260 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 261 SND_SOC_DAIFMT_CBM_CFM, 262 .ops = &n810_ops, 263 SND_SOC_DAILINK_REG(aic33), 264}; 265 266/* Audio machine driver */ 267static struct snd_soc_card snd_soc_n810 = { 268 .name = "N810", 269 .owner = THIS_MODULE, 270 .dai_link = &n810_dai, 271 .num_links = 1, 272 273 .controls = aic33_n810_controls, 274 .num_controls = ARRAY_SIZE(aic33_n810_controls), 275 .dapm_widgets = aic33_dapm_widgets, 276 .num_dapm_widgets = ARRAY_SIZE(aic33_dapm_widgets), 277 .dapm_routes = audio_map, 278 .num_dapm_routes = ARRAY_SIZE(audio_map), 279 .fully_routed = true, 280}; 281 282static struct platform_device *n810_snd_device; 283 284static int __init n810_soc_init(void) 285{ 286 int err; 287 struct device *dev; 288 289 if (!of_have_populated_dt() || 290 (!of_machine_is_compatible("nokia,n810") && 291 !of_machine_is_compatible("nokia,n810-wimax"))) 292 return -ENODEV; 293 294 n810_snd_device = platform_device_alloc("soc-audio", -1); 295 if (!n810_snd_device) 296 return -ENOMEM; 297 298 platform_set_drvdata(n810_snd_device, &snd_soc_n810); 299 err = platform_device_add(n810_snd_device); 300 if (err) 301 goto err1; 302 303 dev = &n810_snd_device->dev; 304 305 sys_clkout2_src = clk_get(dev, "sys_clkout2_src"); 306 if (IS_ERR(sys_clkout2_src)) { 307 dev_err(dev, "Could not get sys_clkout2_src clock\n"); 308 err = PTR_ERR(sys_clkout2_src); 309 goto err2; 310 } 311 sys_clkout2 = clk_get(dev, "sys_clkout2"); 312 if (IS_ERR(sys_clkout2)) { 313 dev_err(dev, "Could not get sys_clkout2\n"); 314 err = PTR_ERR(sys_clkout2); 315 goto err3; 316 } 317 /* 318 * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use 319 * 96 MHz as its parent in order to get 12 MHz 320 */ 321 func96m_clk = clk_get(dev, "func_96m_ck"); 322 if (IS_ERR(func96m_clk)) { 323 dev_err(dev, "Could not get func 96M clock\n"); 324 err = PTR_ERR(func96m_clk); 325 goto err4; 326 } 327 clk_set_parent(sys_clkout2_src, func96m_clk); 328 clk_set_rate(sys_clkout2, 12000000); 329 330 if (WARN_ON((gpio_request(N810_HEADSET_AMP_GPIO, "hs_amp") < 0) || 331 (gpio_request(N810_SPEAKER_AMP_GPIO, "spk_amp") < 0))) { 332 err = -EINVAL; 333 goto err4; 334 } 335 336 gpio_direction_output(N810_HEADSET_AMP_GPIO, 0); 337 gpio_direction_output(N810_SPEAKER_AMP_GPIO, 0); 338 339 return 0; 340err4: 341 clk_put(sys_clkout2); 342err3: 343 clk_put(sys_clkout2_src); 344err2: 345 platform_device_del(n810_snd_device); 346err1: 347 platform_device_put(n810_snd_device); 348 349 return err; 350} 351 352static void __exit n810_soc_exit(void) 353{ 354 gpio_free(N810_SPEAKER_AMP_GPIO); 355 gpio_free(N810_HEADSET_AMP_GPIO); 356 clk_put(sys_clkout2_src); 357 clk_put(sys_clkout2); 358 clk_put(func96m_clk); 359 360 platform_device_unregister(n810_snd_device); 361} 362 363module_init(n810_soc_init); 364module_exit(n810_soc_exit); 365 366MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>"); 367MODULE_DESCRIPTION("ALSA SoC Nokia N810"); 368MODULE_LICENSE("GPL");