brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 9619f55 Raw
218 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// Copyright (c) 2014, Insignal Co., Ltd.4//5//  Author: Claude <claude@insginal.co.kr>6 7#include <linux/module.h>8#include <linux/of.h>9#include <linux/platform_device.h>10#include <linux/clk.h>11 12#include <sound/soc.h>13#include <sound/soc-dapm.h>14#include <sound/pcm.h>15#include <sound/pcm_params.h>16 17#include "../codecs/wm8994.h"18#include "i2s.h"19 20static int arndale_rt5631_hw_params(struct snd_pcm_substream *substream,21				    struct snd_pcm_hw_params *params)22{23	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);24	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);25	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);26	int rfs, ret;27	unsigned long rclk;28 29	rfs = 256;30 31	rclk = params_rate(params) * rfs;32 33	ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,34					0, SND_SOC_CLOCK_OUT);35	if (ret < 0)36		return ret;37 38	ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,39					0, SND_SOC_CLOCK_OUT);40 41	if (ret < 0)42		return ret;43 44	ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);45	if (ret < 0)46		return ret;47 48	return 0;49}50 51static const struct snd_soc_ops arndale_rt5631_ops = {52	.hw_params = arndale_rt5631_hw_params,53};54 55static int arndale_wm1811_hw_params(struct snd_pcm_substream *substream,56				    struct snd_pcm_hw_params *params)57{58	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);59	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);60	unsigned int rfs, rclk;61 62	/* Ensure AIF1CLK is >= 3 MHz for optimal performance */63	if (params_width(params) == 24)64		rfs = 384;65	else if (params_rate(params) == 8000 || params_rate(params) == 11025)66		rfs = 512;67	else68		rfs = 256;69 70	rclk = params_rate(params) * rfs;71 72	/*73	 * We add 1 to the frequency value to ensure proper EPLL setting74	 * for each audio sampling rate (see epll_24mhz_tbl in drivers/clk/75	 * samsung/clk-exynos5250.c for list of available EPLL rates).76	 * The CODEC uses clk API and the value will be rounded hence the MCLK177	 * clock's frequency will still be exact multiple of the sample rate.78	 */79	return snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1,80					rclk + 1, SND_SOC_CLOCK_IN);81}82 83static const struct snd_soc_ops arndale_wm1811_ops = {84	.hw_params = arndale_wm1811_hw_params,85};86 87SND_SOC_DAILINK_DEFS(rt5631_hifi,88	DAILINK_COMP_ARRAY(COMP_EMPTY()),89	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5631-aif1")),90	DAILINK_COMP_ARRAY(COMP_EMPTY()));91 92static struct snd_soc_dai_link arndale_rt5631_dai[] = {93	{94		.name = "RT5631 HiFi",95		.stream_name = "Primary",96		.dai_fmt = SND_SOC_DAIFMT_I2S97			| SND_SOC_DAIFMT_NB_NF98			| SND_SOC_DAIFMT_CBS_CFS,99		.ops = &arndale_rt5631_ops,100		SND_SOC_DAILINK_REG(rt5631_hifi),101	},102};103 104SND_SOC_DAILINK_DEFS(wm1811_hifi,105	DAILINK_COMP_ARRAY(COMP_EMPTY()),106	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")),107	DAILINK_COMP_ARRAY(COMP_EMPTY()));108 109static struct snd_soc_dai_link arndale_wm1811_dai[] = {110	{111		.name = "WM1811 HiFi",112		.stream_name = "Primary",113		.dai_fmt = SND_SOC_DAIFMT_I2S114			| SND_SOC_DAIFMT_NB_NF115			| SND_SOC_DAIFMT_CBM_CFM,116		.ops = &arndale_wm1811_ops,117		SND_SOC_DAILINK_REG(wm1811_hifi),118	},119};120 121static struct snd_soc_card arndale_rt5631 = {122	.name = "Arndale RT5631",123	.owner = THIS_MODULE,124	.dai_link = arndale_rt5631_dai,125	.num_links = ARRAY_SIZE(arndale_rt5631_dai),126};127 128static struct snd_soc_card arndale_wm1811 = {129	.name = "Arndale WM1811",130	.owner = THIS_MODULE,131	.dai_link = arndale_wm1811_dai,132	.num_links = ARRAY_SIZE(arndale_wm1811_dai),133};134 135static void arndale_put_of_nodes(struct snd_soc_card *card)136{137	struct snd_soc_dai_link *dai_link;138	int i;139 140	for_each_card_prelinks(card, i, dai_link) {141		of_node_put(dai_link->cpus->of_node);142		of_node_put(dai_link->codecs->of_node);143	}144}145 146static int arndale_audio_probe(struct platform_device *pdev)147{148	struct device_node *np = pdev->dev.of_node;149	struct snd_soc_card *card;150	struct snd_soc_dai_link *dai_link;151	int ret;152 153	card = (struct snd_soc_card *)of_device_get_match_data(&pdev->dev);154	card->dev = &pdev->dev;155	dai_link = card->dai_link;156 157	dai_link->cpus->of_node = of_parse_phandle(np, "samsung,audio-cpu", 0);158	if (!dai_link->cpus->of_node) {159		dev_err(&pdev->dev,160			"Property 'samsung,audio-cpu' missing or invalid\n");161		return -EINVAL;162	}163 164	if (!dai_link->platforms->name)165		dai_link->platforms->of_node = dai_link->cpus->of_node;166 167	dai_link->codecs->of_node = of_parse_phandle(np, "samsung,audio-codec", 0);168	if (!dai_link->codecs->of_node) {169		dev_err(&pdev->dev,170			"Property 'samsung,audio-codec' missing or invalid\n");171		ret = -EINVAL;172		goto err_put_of_nodes;173	}174 175	ret = devm_snd_soc_register_card(card->dev, card);176	if (ret) {177		dev_err_probe(&pdev->dev, ret,178			      "snd_soc_register_card() failed\n");179		goto err_put_of_nodes;180	}181	return 0;182 183err_put_of_nodes:184	arndale_put_of_nodes(card);185	return ret;186}187 188static void arndale_audio_remove(struct platform_device *pdev)189{190	struct snd_soc_card *card = platform_get_drvdata(pdev);191 192	arndale_put_of_nodes(card);193}194 195static const struct of_device_id arndale_audio_of_match[] = {196	{ .compatible = "samsung,arndale-rt5631",  .data = &arndale_rt5631 },197	{ .compatible = "samsung,arndale-alc5631", .data = &arndale_rt5631 },198	{ .compatible = "samsung,arndale-wm1811",  .data = &arndale_wm1811 },199	{},200};201MODULE_DEVICE_TABLE(of, arndale_audio_of_match);202 203static struct platform_driver arndale_audio_driver = {204	.driver = {205		.name = "arndale-audio",206		.pm = &snd_soc_pm_ops,207		.of_match_table = arndale_audio_of_match,208	},209	.probe = arndale_audio_probe,210	.remove = arndale_audio_remove,211};212 213module_platform_driver(arndale_audio_driver);214 215MODULE_AUTHOR("Claude <claude@insignal.co.kr>");216MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");217MODULE_LICENSE("GPL");218