178 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Sound card driver for Intel Haswell Lynx Point with Realtek 56404 *5 * Copyright (C) 2013, Intel Corporation6 */7 8#include <linux/module.h>9#include <linux/platform_device.h>10#include <sound/core.h>11#include <sound/pcm.h>12#include <sound/pcm_params.h>13#include <sound/soc.h>14#include <sound/soc-acpi.h>15#include "../../codecs/rt5640.h"16 17static const struct snd_soc_dapm_widget card_widgets[] = {18 SND_SOC_DAPM_HP("Headphones", NULL),19 SND_SOC_DAPM_MIC("Mic", NULL),20};21 22static const struct snd_soc_dapm_route card_routes[] = {23 {"Headphones", NULL, "HPOR"},24 {"Headphones", NULL, "HPOL"},25 {"IN2P", NULL, "Mic"},26 27 /* CODEC BE connections */28 {"SSP0 CODEC IN", NULL, "AIF1 Capture"},29 {"AIF1 Playback", NULL, "SSP0 CODEC OUT"},30};31 32static int codec_link_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,33 struct snd_pcm_hw_params *params)34{35 struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);36 struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);37 38 /* The ADSP will convert the FE rate to 48k, stereo. */39 rate->min = rate->max = 48000;40 channels->min = channels->max = 2;41 /* Set SSP0 to 16 bit. */42 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE);43 44 return 0;45}46 47static int codec_link_hw_params(struct snd_pcm_substream *substream,48 struct snd_pcm_hw_params *params)49{50 struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);51 struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);52 int ret;53 54 ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, SND_SOC_CLOCK_IN);55 if (ret < 0) {56 dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret);57 return ret;58 }59 60 /* Set correct codec filter for DAI format and clock config. */61 snd_soc_component_update_bits(codec_dai->component, 0x83, 0xffff, 0x8000);62 63 return ret;64}65 66static const struct snd_soc_ops codec_link_ops = {67 .hw_params = codec_link_hw_params,68};69 70SND_SOC_DAILINK_DEF(system, DAILINK_COMP_ARRAY(COMP_CPU("System Pin")));71SND_SOC_DAILINK_DEF(offload0, DAILINK_COMP_ARRAY(COMP_CPU("Offload0 Pin")));72SND_SOC_DAILINK_DEF(offload1, DAILINK_COMP_ARRAY(COMP_CPU("Offload1 Pin")));73SND_SOC_DAILINK_DEF(loopback, DAILINK_COMP_ARRAY(COMP_CPU("Loopback Pin")));74 75SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));76SND_SOC_DAILINK_DEF(codec, DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT33CA:00", "rt5640-aif1")));77SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("haswell-pcm-audio")));78SND_SOC_DAILINK_DEF(ssp0_port, DAILINK_COMP_ARRAY(COMP_CPU("ssp0-port")));79 80static struct snd_soc_dai_link card_dai_links[] = {81 /* Front End DAI links */82 {83 .name = "System",84 .stream_name = "System Playback/Capture",85 .nonatomic = 1,86 .dynamic = 1,87 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},88 .dpcm_playback = 1,89 .dpcm_capture = 1,90 SND_SOC_DAILINK_REG(system, dummy, platform),91 },92 {93 .name = "Offload0",94 .stream_name = "Offload0 Playback",95 .nonatomic = 1,96 .dynamic = 1,97 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},98 .dpcm_playback = 1,99 SND_SOC_DAILINK_REG(offload0, dummy, platform),100 },101 {102 .name = "Offload1",103 .stream_name = "Offload1 Playback",104 .nonatomic = 1,105 .dynamic = 1,106 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},107 .dpcm_playback = 1,108 SND_SOC_DAILINK_REG(offload1, dummy, platform),109 },110 {111 .name = "Loopback",112 .stream_name = "Loopback",113 .nonatomic = 1,114 .dynamic = 1,115 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},116 .dpcm_capture = 1,117 SND_SOC_DAILINK_REG(loopback, dummy, platform),118 },119 /* Back End DAI links */120 {121 /* SSP0 - Codec */122 .name = "Codec",123 .id = 0,124 .nonatomic = 1,125 .no_pcm = 1,126 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC,127 .ignore_pmdown_time = 1,128 .be_hw_params_fixup = codec_link_hw_params_fixup,129 .ops = &codec_link_ops,130 .dpcm_playback = 1,131 .dpcm_capture = 1,132 SND_SOC_DAILINK_REG(ssp0_port, codec, platform),133 },134};135 136static struct snd_soc_card hsw_rt5640_card = {137 .name = "haswell-rt5640",138 .owner = THIS_MODULE,139 .dai_link = card_dai_links,140 .num_links = ARRAY_SIZE(card_dai_links),141 .dapm_widgets = card_widgets,142 .num_dapm_widgets = ARRAY_SIZE(card_widgets),143 .dapm_routes = card_routes,144 .num_dapm_routes = ARRAY_SIZE(card_routes),145 .fully_routed = true,146};147 148static int hsw_rt5640_probe(struct platform_device *pdev)149{150 struct snd_soc_acpi_mach *mach;151 struct device *dev = &pdev->dev;152 int ret;153 154 hsw_rt5640_card.dev = dev;155 mach = dev_get_platdata(dev);156 157 ret = snd_soc_fixup_dai_links_platform_name(&hsw_rt5640_card, mach->mach_params.platform);158 if (ret)159 return ret;160 161 return devm_snd_soc_register_card(dev, &hsw_rt5640_card);162}163 164static struct platform_driver hsw_rt5640_driver = {165 .probe = hsw_rt5640_probe,166 .driver = {167 .name = "hsw_rt5640",168 .pm = &snd_soc_pm_ops,169 },170};171 172module_platform_driver(hsw_rt5640_driver)173 174MODULE_AUTHOR("Liam Girdwood, Xingchao Wang");175MODULE_DESCRIPTION("Sound card driver for Intel Haswell Lynx Point with Realtek 5640");176MODULE_LICENSE("GPL");177MODULE_ALIAS("platform:hsw_rt5640");178