1/* 2 * Intel Haswell Lynxpoint SST Audio 3 * 4 * Copyright (C) 2013, Intel Corporation. All rights reserved. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License version 8 * 2 as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 */ 16 17#include <linux/module.h> 18#include <linux/platform_device.h> 19#include <sound/core.h> 20#include <sound/pcm.h> 21#include <sound/soc.h> 22#include <sound/pcm_params.h> 23 24#include "../common/sst-dsp.h" 25#include "../haswell/sst-haswell-ipc.h" 26 27#include "../../codecs/rt5640.h" 28 29/* Haswell ULT platforms have a Headphone and Mic jack */ 30static const struct snd_soc_dapm_widget haswell_widgets[] = { 31 SND_SOC_DAPM_HP("Headphones", NULL), 32 SND_SOC_DAPM_MIC("Mic", NULL), 33}; 34 35static const struct snd_soc_dapm_route haswell_rt5640_map[] = { 36 37 {"Headphones", NULL, "HPOR"}, 38 {"Headphones", NULL, "HPOL"}, 39 {"IN2P", NULL, "Mic"}, 40 41 /* CODEC BE connections */ 42 {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, 43 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, 44}; 45 46static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, 47 struct snd_pcm_hw_params *params) 48{ 49 struct snd_interval *rate = hw_param_interval(params, 50 SNDRV_PCM_HW_PARAM_RATE); 51 struct snd_interval *channels = hw_param_interval(params, 52 SNDRV_PCM_HW_PARAM_CHANNELS); 53 54 /* The ADSP will covert the FE rate to 48k, stereo */ 55 rate->min = rate->max = 48000; 56 channels->min = channels->max = 2; 57 58 /* set SSP0 to 16 bit */ 59 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); 60 return 0; 61} 62 63static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, 64 struct snd_pcm_hw_params *params) 65{ 66 struct snd_soc_pcm_runtime *rtd = substream->private_data; 67 struct snd_soc_dai *codec_dai = rtd->codec_dai; 68 int ret; 69 70 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, 71 SND_SOC_CLOCK_IN); 72 73 if (ret < 0) { 74 dev_err(rtd->dev, "can't set codec sysclk configuration\n"); 75 return ret; 76 } 77 78 /* set correct codec filter for DAI format and clock config */ 79 snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000); 80 81 return ret; 82} 83 84static struct snd_soc_ops haswell_rt5640_ops = { 85 .hw_params = haswell_rt5640_hw_params, 86}; 87 88static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) 89{ 90 struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); 91 struct sst_hsw *haswell = pdata->dsp; 92 int ret; 93 94 /* Set ADSP SSP port settings */ 95 ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0, 96 SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, 97 SST_HSW_DEVICE_CLOCK_MASTER, 9); 98 if (ret < 0) { 99 dev_err(rtd->dev, "failed to set device config\n"); 100 return ret; 101 } 102 103 return 0; 104} 105 106static struct snd_soc_dai_link haswell_rt5640_dais[] = { 107 /* Front End DAI links */ 108 { 109 .name = "System", 110 .stream_name = "System Playback/Capture", 111 .cpu_dai_name = "System Pin", 112 .platform_name = "haswell-pcm-audio", 113 .dynamic = 1, 114 .codec_name = "snd-soc-dummy", 115 .codec_dai_name = "snd-soc-dummy-dai", 116 .init = haswell_rtd_init, 117 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 118 .dpcm_playback = 1, 119 .dpcm_capture = 1, 120 }, 121 { 122 .name = "Offload0", 123 .stream_name = "Offload0 Playback", 124 .cpu_dai_name = "Offload0 Pin", 125 .platform_name = "haswell-pcm-audio", 126 .dynamic = 1, 127 .codec_name = "snd-soc-dummy", 128 .codec_dai_name = "snd-soc-dummy-dai", 129 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 130 .dpcm_playback = 1, 131 }, 132 { 133 .name = "Offload1", 134 .stream_name = "Offload1 Playback", 135 .cpu_dai_name = "Offload1 Pin", 136 .platform_name = "haswell-pcm-audio", 137 .dynamic = 1, 138 .codec_name = "snd-soc-dummy", 139 .codec_dai_name = "snd-soc-dummy-dai", 140 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 141 .dpcm_playback = 1, 142 }, 143 { 144 .name = "Loopback", 145 .stream_name = "Loopback", 146 .cpu_dai_name = "Loopback Pin", 147 .platform_name = "haswell-pcm-audio", 148 .dynamic = 0, 149 .codec_name = "snd-soc-dummy", 150 .codec_dai_name = "snd-soc-dummy-dai", 151 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, 152 .dpcm_capture = 1, 153 }, 154 155 /* Back End DAI links */ 156 { 157 /* SSP0 - Codec */ 158 .name = "Codec", 159 .be_id = 0, 160 .cpu_dai_name = "snd-soc-dummy-dai", 161 .platform_name = "snd-soc-dummy", 162 .no_pcm = 1, 163 .codec_name = "i2c-INT33CA:00", 164 .codec_dai_name = "rt5640-aif1", 165 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 166 SND_SOC_DAIFMT_CBS_CFS, 167 .ignore_suspend = 1, 168 .ignore_pmdown_time = 1, 169 .be_hw_params_fixup = haswell_ssp0_fixup, 170 .ops = &haswell_rt5640_ops, 171 .dpcm_playback = 1, 172 .dpcm_capture = 1, 173 }, 174}; 175 176/* audio machine driver for Haswell Lynxpoint DSP + RT5640 */ 177static struct snd_soc_card haswell_rt5640 = { 178 .name = "haswell-rt5640", 179 .owner = THIS_MODULE, 180 .dai_link = haswell_rt5640_dais, 181 .num_links = ARRAY_SIZE(haswell_rt5640_dais), 182 .dapm_widgets = haswell_widgets, 183 .num_dapm_widgets = ARRAY_SIZE(haswell_widgets), 184 .dapm_routes = haswell_rt5640_map, 185 .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map), 186 .fully_routed = true, 187}; 188 189static int haswell_audio_probe(struct platform_device *pdev) 190{ 191 haswell_rt5640.dev = &pdev->dev; 192 193 return devm_snd_soc_register_card(&pdev->dev, &haswell_rt5640); 194} 195 196static struct platform_driver haswell_audio = { 197 .probe = haswell_audio_probe, 198 .driver = { 199 .name = "haswell-audio", 200 }, 201}; 202 203module_platform_driver(haswell_audio) 204 205/* Module information */ 206MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); 207MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint"); 208MODULE_LICENSE("GPL v2"); 209MODULE_ALIAS("platform:haswell-audio"); 210