| // SPDX-License-Identifier: GPL-2.0 | 
 | // Copyright (c) 2018, Linaro Limited | 
 |  | 
 | #include <linux/module.h> | 
 | #include <linux/platform_device.h> | 
 | #include <linux/of_device.h> | 
 | #include <sound/soc.h> | 
 | #include <sound/soc-dapm.h> | 
 | #include <sound/pcm.h> | 
 | #include "common.h" | 
 |  | 
 | static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | 
 | 				      struct snd_pcm_hw_params *params) | 
 | { | 
 | 	struct snd_interval *rate = hw_param_interval(params, | 
 | 					SNDRV_PCM_HW_PARAM_RATE); | 
 | 	struct snd_interval *channels = hw_param_interval(params, | 
 | 					SNDRV_PCM_HW_PARAM_CHANNELS); | 
 |  | 
 | 	rate->min = rate->max = 48000; | 
 | 	channels->min = channels->max = 2; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static void apq8096_add_be_ops(struct snd_soc_card *card) | 
 | { | 
 | 	struct snd_soc_dai_link *link = card->dai_link; | 
 | 	int i, num_links = card->num_links; | 
 |  | 
 | 	for (i = 0; i < num_links; i++) { | 
 | 		if (link->no_pcm == 1) | 
 | 			link->be_hw_params_fixup = apq8096_be_hw_params_fixup; | 
 | 		link++; | 
 | 	} | 
 | } | 
 |  | 
 | static int apq8096_platform_probe(struct platform_device *pdev) | 
 | { | 
 | 	struct snd_soc_card *card; | 
 | 	struct device *dev = &pdev->dev; | 
 | 	int ret; | 
 |  | 
 | 	card = kzalloc(sizeof(*card), GFP_KERNEL); | 
 | 	if (!card) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	card->dev = dev; | 
 | 	dev_set_drvdata(dev, card); | 
 | 	ret = qcom_snd_parse_of(card); | 
 | 	if (ret) { | 
 | 		dev_err(dev, "Error parsing OF data\n"); | 
 | 		goto err; | 
 | 	} | 
 |  | 
 | 	apq8096_add_be_ops(card); | 
 | 	ret = snd_soc_register_card(card); | 
 | 	if (ret) | 
 | 		goto err_card_register; | 
 |  | 
 | 	return 0; | 
 |  | 
 | err_card_register: | 
 | 	kfree(card->dai_link); | 
 | err: | 
 | 	kfree(card); | 
 | 	return ret; | 
 | } | 
 |  | 
 | static int apq8096_platform_remove(struct platform_device *pdev) | 
 | { | 
 | 	struct snd_soc_card *card = dev_get_drvdata(&pdev->dev); | 
 |  | 
 | 	snd_soc_unregister_card(card); | 
 | 	kfree(card->dai_link); | 
 | 	kfree(card); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static const struct of_device_id msm_snd_apq8096_dt_match[] = { | 
 | 	{.compatible = "qcom,apq8096-sndcard"}, | 
 | 	{} | 
 | }; | 
 |  | 
 | MODULE_DEVICE_TABLE(of, msm_snd_apq8096_dt_match); | 
 |  | 
 | static struct platform_driver msm_snd_apq8096_driver = { | 
 | 	.probe  = apq8096_platform_probe, | 
 | 	.remove = apq8096_platform_remove, | 
 | 	.driver = { | 
 | 		.name = "msm-snd-apq8096", | 
 | 		.of_match_table = msm_snd_apq8096_dt_match, | 
 | 	}, | 
 | }; | 
 | module_platform_driver(msm_snd_apq8096_driver); | 
 | MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org"); | 
 | MODULE_DESCRIPTION("APQ8096 ASoC Machine Driver"); | 
 | MODULE_LICENSE("GPL v2"); |