1/* 2 * ASoC machine driver for Snow boards 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 */ 13 14#include <linux/module.h> 15#include <linux/platform_device.h> 16#include <linux/of.h> 17#include <linux/of_device.h> 18 19#include <sound/soc.h> 20 21#include "i2s.h" 22 23#define FIN_PLL_RATE 24000000 24 25static struct snd_soc_dai_link snow_dai[] = { 26 { 27 .name = "Primary", 28 .stream_name = "Primary", 29 .codec_dai_name = "HiFi", 30 .dai_fmt = SND_SOC_DAIFMT_I2S | 31 SND_SOC_DAIFMT_NB_NF | 32 SND_SOC_DAIFMT_CBS_CFS, 33 }, 34}; 35 36static int snow_late_probe(struct snd_soc_card *card) 37{ 38 struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; 39 struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; 40 int ret; 41 42 /* Set the MCLK rate for the codec */ 43 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 44 FIN_PLL_RATE, SND_SOC_CLOCK_IN); 45 if (ret < 0) 46 return ret; 47 48 /* Select I2S Bus clock to set RCLK and BCLK */ 49 ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, 50 0, SND_SOC_CLOCK_IN); 51 if (ret < 0) 52 return ret; 53 54 return 0; 55} 56 57static struct snd_soc_card snow_snd = { 58 .name = "Snow-I2S", 59 .owner = THIS_MODULE, 60 .dai_link = snow_dai, 61 .num_links = ARRAY_SIZE(snow_dai), 62 63 .late_probe = snow_late_probe, 64}; 65 66static int snow_probe(struct platform_device *pdev) 67{ 68 struct snd_soc_card *card = &snow_snd; 69 struct device_node *i2s_node, *codec_node; 70 int i, ret; 71 72 i2s_node = of_parse_phandle(pdev->dev.of_node, 73 "samsung,i2s-controller", 0); 74 if (!i2s_node) { 75 dev_err(&pdev->dev, 76 "Property 'i2s-controller' missing or invalid\n"); 77 return -EINVAL; 78 } 79 80 codec_node = of_parse_phandle(pdev->dev.of_node, 81 "samsung,audio-codec", 0); 82 if (!codec_node) { 83 dev_err(&pdev->dev, 84 "Property 'audio-codec' missing or invalid\n"); 85 return -EINVAL; 86 } 87 88 for (i = 0; i < ARRAY_SIZE(snow_dai); i++) { 89 snow_dai[i].codec_of_node = codec_node; 90 snow_dai[i].cpu_of_node = i2s_node; 91 snow_dai[i].platform_of_node = i2s_node; 92 } 93 94 card->dev = &pdev->dev; 95 96 /* Update card-name if provided through DT, else use default name */ 97 snd_soc_of_parse_card_name(card, "samsung,model"); 98 99 ret = devm_snd_soc_register_card(&pdev->dev, card); 100 if (ret) { 101 dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); 102 return ret; 103 } 104 105 return ret; 106} 107 108static const struct of_device_id snow_of_match[] = { 109 { .compatible = "google,snow-audio-max98090", }, 110 { .compatible = "google,snow-audio-max98091", }, 111 { .compatible = "google,snow-audio-max98095", }, 112 {}, 113}; 114MODULE_DEVICE_TABLE(of, snow_of_match); 115 116static struct platform_driver snow_driver = { 117 .driver = { 118 .name = "snow-audio", 119 .pm = &snd_soc_pm_ops, 120 .of_match_table = snow_of_match, 121 }, 122 .probe = snow_probe, 123}; 124 125module_platform_driver(snow_driver); 126 127MODULE_DESCRIPTION("ALSA SoC Audio machine driver for Snow"); 128MODULE_LICENSE("GPL"); 129