1 /* 2 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219 3 * 4 * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 #include <linux/module.h> 20 #include <linux/platform_device.h> 21 #include <linux/slab.h> 22 #include <linux/gpio.h> 23 #include <linux/of_gpio.h> 24 #include <linux/delay.h> 25 #include <linux/spi/spi.h> 26 #include <linux/input.h> 27 #include <sound/core.h> 28 #include <sound/jack.h> 29 #include <sound/pcm.h> 30 #include <sound/pcm_params.h> 31 #include <sound/soc.h> 32 #include "rockchip_i2s.h" 33 #include "../codecs/da7219.h" 34 #include "../codecs/da7219-aad.h" 35 #include "../codecs/rt5514.h" 36 37 #define DRV_NAME "rk3399-gru-sound" 38 39 #define SOUND_FS 256 40 41 static unsigned int rt5514_dmic_delay; 42 43 static struct snd_soc_jack rockchip_sound_jack; 44 45 static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = { 46 SND_SOC_DAPM_HP("Headphones", NULL), 47 SND_SOC_DAPM_SPK("Speakers", NULL), 48 SND_SOC_DAPM_MIC("Headset Mic", NULL), 49 SND_SOC_DAPM_MIC("Int Mic", NULL), 50 }; 51 52 static const struct snd_soc_dapm_route rockchip_dapm_routes[] = { 53 /* Input Lines */ 54 {"MIC", NULL, "Headset Mic"}, 55 {"DMIC1L", NULL, "Int Mic"}, 56 {"DMIC1R", NULL, "Int Mic"}, 57 58 /* Output Lines */ 59 {"Headphones", NULL, "HPL"}, 60 {"Headphones", NULL, "HPR"}, 61 {"Speakers", NULL, "Speaker"}, 62 }; 63 64 static const struct snd_kcontrol_new rockchip_controls[] = { 65 SOC_DAPM_PIN_SWITCH("Headphones"), 66 SOC_DAPM_PIN_SWITCH("Speakers"), 67 SOC_DAPM_PIN_SWITCH("Headset Mic"), 68 SOC_DAPM_PIN_SWITCH("Int Mic"), 69 }; 70 71 static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream, 72 struct snd_pcm_hw_params *params) 73 { 74 struct snd_soc_pcm_runtime *rtd = substream->private_data; 75 unsigned int mclk; 76 int ret; 77 78 /* max98357a supports these sample rates */ 79 switch (params_rate(params)) { 80 case 8000: 81 case 16000: 82 case 48000: 83 case 96000: 84 mclk = params_rate(params) * SOUND_FS; 85 break; 86 default: 87 dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n", 88 __func__, params_rate(params)); 89 return -EINVAL; 90 } 91 92 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0); 93 if (ret) { 94 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", 95 __func__, mclk, ret); 96 return ret; 97 } 98 99 return 0; 100 } 101 102 static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream, 103 struct snd_pcm_hw_params *params) 104 { 105 struct snd_soc_pcm_runtime *rtd = substream->private_data; 106 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 107 struct snd_soc_dai *codec_dai = rtd->codec_dai; 108 unsigned int mclk; 109 int ret; 110 111 mclk = params_rate(params) * SOUND_FS; 112 113 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 114 SND_SOC_CLOCK_OUT); 115 if (ret < 0) { 116 dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret); 117 return ret; 118 } 119 120 ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK, 121 mclk, SND_SOC_CLOCK_IN); 122 if (ret) { 123 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n", 124 __func__, params_rate(params) * 512, ret); 125 return ret; 126 } 127 128 /* Wait for DMIC stable */ 129 msleep(rt5514_dmic_delay); 130 131 return 0; 132 } 133 134 static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream, 135 struct snd_pcm_hw_params *params) 136 { 137 struct snd_soc_pcm_runtime *rtd = substream->private_data; 138 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 139 struct snd_soc_dai *codec_dai = rtd->codec_dai; 140 int mclk, ret; 141 142 /* in bypass mode, the mclk has to be one of the frequencies below */ 143 switch (params_rate(params)) { 144 case 8000: 145 case 16000: 146 case 24000: 147 case 32000: 148 case 48000: 149 case 64000: 150 case 96000: 151 mclk = 12288000; 152 break; 153 case 11025: 154 case 22050: 155 case 44100: 156 case 88200: 157 mclk = 11289600; 158 break; 159 default: 160 return -EINVAL; 161 } 162 163 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, 164 SND_SOC_CLOCK_OUT); 165 if (ret < 0) { 166 dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret); 167 return ret; 168 } 169 170 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, 171 SND_SOC_CLOCK_IN); 172 if (ret < 0) { 173 dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret); 174 return ret; 175 } 176 177 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); 178 if (ret < 0) { 179 dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret); 180 return ret; 181 } 182 183 return 0; 184 } 185 186 static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) 187 { 188 struct snd_soc_codec *codec = rtd->codec_dais[0]->codec; 189 struct snd_soc_dai *codec_dai = rtd->codec_dai; 190 int ret; 191 192 /* We need default MCLK and PLL settings for the accessory detection */ 193 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000, 194 SND_SOC_CLOCK_IN); 195 if (ret < 0) { 196 dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret); 197 return ret; 198 } 199 200 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); 201 if (ret < 0) { 202 dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret); 203 return ret; 204 } 205 206 /* Enable Headset and 4 Buttons Jack detection */ 207 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", 208 SND_JACK_HEADSET | SND_JACK_LINEOUT | 209 SND_JACK_BTN_0 | SND_JACK_BTN_1 | 210 SND_JACK_BTN_2 | SND_JACK_BTN_3, 211 &rockchip_sound_jack, NULL, 0); 212 213 if (ret) { 214 dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret); 215 return ret; 216 } 217 218 snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA); 219 snd_jack_set_key( 220 rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 221 snd_jack_set_key( 222 rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 223 snd_jack_set_key( 224 rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 225 226 da7219_aad_jack_det(codec, &rockchip_sound_jack); 227 228 return 0; 229 } 230 231 static const struct snd_soc_ops rockchip_sound_max98357a_ops = { 232 .hw_params = rockchip_sound_max98357a_hw_params, 233 }; 234 235 static const struct snd_soc_ops rockchip_sound_rt5514_ops = { 236 .hw_params = rockchip_sound_rt5514_hw_params, 237 }; 238 239 static const struct snd_soc_ops rockchip_sound_da7219_ops = { 240 .hw_params = rockchip_sound_da7219_hw_params, 241 }; 242 243 enum { 244 DAILINK_MAX98357A, 245 DAILINK_RT5514, 246 DAILINK_DA7219, 247 DAILINK_RT5514_DSP, 248 }; 249 250 #define DAILINK_ENTITIES (DAILINK_DA7219 + 1) 251 252 static struct snd_soc_dai_link rockchip_dailinks[] = { 253 [DAILINK_MAX98357A] = { 254 .name = "MAX98357A", 255 .stream_name = "MAX98357A PCM", 256 .codec_dai_name = "HiFi", 257 .ops = &rockchip_sound_max98357a_ops, 258 /* set max98357a as slave */ 259 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 260 SND_SOC_DAIFMT_CBS_CFS, 261 }, 262 [DAILINK_RT5514] = { 263 .name = "RT5514", 264 .stream_name = "RT5514 PCM", 265 .codec_dai_name = "rt5514-aif1", 266 .ops = &rockchip_sound_rt5514_ops, 267 /* set rt5514 as slave */ 268 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 269 SND_SOC_DAIFMT_CBS_CFS, 270 }, 271 [DAILINK_DA7219] = { 272 .name = "DA7219", 273 .stream_name = "DA7219 PCM", 274 .codec_dai_name = "da7219-hifi", 275 .init = rockchip_sound_da7219_init, 276 .ops = &rockchip_sound_da7219_ops, 277 /* set da7219 as slave */ 278 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 279 SND_SOC_DAIFMT_CBS_CFS, 280 }, 281 /* RT5514 DSP for voice wakeup via spi bus */ 282 [DAILINK_RT5514_DSP] = { 283 .name = "RT5514 DSP", 284 .stream_name = "Wake on Voice", 285 .codec_name = "snd-soc-dummy", 286 .codec_dai_name = "snd-soc-dummy-dai", 287 }, 288 }; 289 290 static struct snd_soc_card rockchip_sound_card = { 291 .name = "rk3399-gru-sound", 292 .owner = THIS_MODULE, 293 .dai_link = rockchip_dailinks, 294 .num_links = ARRAY_SIZE(rockchip_dailinks), 295 .dapm_widgets = rockchip_dapm_widgets, 296 .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets), 297 .dapm_routes = rockchip_dapm_routes, 298 .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes), 299 .controls = rockchip_controls, 300 .num_controls = ARRAY_SIZE(rockchip_controls), 301 }; 302 303 static int rockchip_sound_match_stub(struct device *dev, void *data) 304 { 305 return 1; 306 } 307 308 static int rockchip_sound_probe(struct platform_device *pdev) 309 { 310 struct snd_soc_card *card = &rockchip_sound_card; 311 struct device_node *cpu_node; 312 struct device *dev; 313 struct device_driver *drv; 314 int i, ret; 315 316 cpu_node = of_parse_phandle(pdev->dev.of_node, "rockchip,cpu", 0); 317 if (!cpu_node) { 318 dev_err(&pdev->dev, "Property 'rockchip,cpu' missing or invalid\n"); 319 return -EINVAL; 320 } 321 322 for (i = 0; i < DAILINK_ENTITIES; i++) { 323 rockchip_dailinks[i].platform_of_node = cpu_node; 324 rockchip_dailinks[i].cpu_of_node = cpu_node; 325 326 rockchip_dailinks[i].codec_of_node = 327 of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i); 328 if (!rockchip_dailinks[i].codec_of_node) { 329 dev_err(&pdev->dev, 330 "Property[%d] 'rockchip,codec' missing or invalid\n", i); 331 return -EINVAL; 332 } 333 } 334 335 /** 336 * To acquire the spi driver of the rt5514 and set the dai-links names 337 * for soc_bind_dai_link 338 */ 339 drv = driver_find("rt5514", &spi_bus_type); 340 if (!drv) { 341 dev_err(&pdev->dev, "Can not find the rt5514 driver at the spi bus\n"); 342 return -EINVAL; 343 } 344 345 dev = driver_find_device(drv, NULL, NULL, rockchip_sound_match_stub); 346 if (!dev) { 347 dev_err(&pdev->dev, "Can not find the rt5514 device\n"); 348 return -ENODEV; 349 } 350 351 /* Set DMIC delay */ 352 ret = device_property_read_u32(&pdev->dev, "dmic-delay", 353 &rt5514_dmic_delay); 354 if (ret) { 355 rt5514_dmic_delay = 0; 356 dev_dbg(&pdev->dev, 357 "no optional property 'dmic-delay' found, default: no delay\n"); 358 } 359 360 rockchip_dailinks[DAILINK_RT5514_DSP].cpu_name = kstrdup_const(dev_name(dev), GFP_KERNEL); 361 rockchip_dailinks[DAILINK_RT5514_DSP].cpu_dai_name = kstrdup_const(dev_name(dev), GFP_KERNEL); 362 rockchip_dailinks[DAILINK_RT5514_DSP].platform_name = kstrdup_const(dev_name(dev), GFP_KERNEL); 363 364 card->dev = &pdev->dev; 365 platform_set_drvdata(pdev, card); 366 367 ret = devm_snd_soc_register_card(&pdev->dev, card); 368 if (ret) 369 dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", 370 __func__, ret); 371 372 return ret; 373 } 374 375 static const struct of_device_id rockchip_sound_of_match[] = { 376 { .compatible = "rockchip,rk3399-gru-sound", }, 377 {}, 378 }; 379 380 static struct platform_driver rockchip_sound_driver = { 381 .probe = rockchip_sound_probe, 382 .driver = { 383 .name = DRV_NAME, 384 .of_match_table = rockchip_sound_of_match, 385 #ifdef CONFIG_PM 386 .pm = &snd_soc_pm_ops, 387 #endif 388 }, 389 }; 390 391 module_platform_driver(rockchip_sound_driver); 392 393 MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>"); 394 MODULE_DESCRIPTION("Rockchip ASoC Machine Driver"); 395 MODULE_LICENSE("GPL v2"); 396 MODULE_ALIAS("platform:" DRV_NAME); 397 MODULE_DEVICE_TABLE(of, rockchip_sound_of_match); 398