Linux Audio

Check our new training course

Loading...
v4.10.11
 
  1/*
  2 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License version 2 and
  6 * only version 2 as published by the Free Software Foundation.
  7 *
  8 * This program is distributed in the hope that it will be useful,
  9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 11 * GNU General Public License for more details.
 12 *
 13 * storm.c -- ALSA SoC machine driver for QTi ipq806x-based Storm board
 14 */
 15
 16#include <linux/device.h>
 17#include <linux/module.h>
 18#include <linux/of.h>
 19#include <linux/mod_devicetable.h>
 20#include <linux/platform_device.h>
 21#include <sound/pcm.h>
 22#include <sound/pcm_params.h>
 23#include <sound/soc.h>
 24
 25#define STORM_SYSCLK_MULT			4
 26
 27static int storm_ops_hw_params(struct snd_pcm_substream *substream,
 28		struct snd_pcm_hw_params *params)
 29{
 30	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 31	struct snd_soc_card *card = soc_runtime->card;
 32	snd_pcm_format_t format = params_format(params);
 33	unsigned int rate = params_rate(params);
 34	unsigned int sysclk_freq;
 35	int bitwidth, ret;
 36
 37	bitwidth = snd_pcm_format_width(format);
 38	if (bitwidth < 0) {
 39		dev_err(card->dev, "%s() invalid bit width given: %d\n",
 40				__func__, bitwidth);
 41		return bitwidth;
 42	}
 43
 44	/*
 45	 * as the CPU DAI is the I2S bus master and no system clock is needed by
 46	 * the MAX98357a DAC, simply set the system clock to be a constant
 47	 * multiple of the bit clock for the clock divider
 48	 */
 49	sysclk_freq = rate * bitwidth * 2 * STORM_SYSCLK_MULT;
 50
 51	ret = snd_soc_dai_set_sysclk(soc_runtime->cpu_dai, 0, sysclk_freq, 0);
 52	if (ret) {
 53		dev_err(card->dev, "%s() error setting sysclk to %u: %d\n",
 54				__func__, sysclk_freq, ret);
 55		return ret;
 56	}
 57
 58	return 0;
 59}
 60
 61static const struct snd_soc_ops storm_soc_ops = {
 62	.hw_params	= storm_ops_hw_params,
 63};
 64
 
 
 
 
 
 65static struct snd_soc_dai_link storm_dai_link = {
 66	.name		= "Primary",
 67	.stream_name	= "Primary",
 68	.codec_dai_name	= "HiFi",
 69	.ops		= &storm_soc_ops,
 
 70};
 71
 72static int storm_parse_of(struct snd_soc_card *card)
 73{
 74	struct snd_soc_dai_link *dai_link = card->dai_link;
 75	struct device_node *np = card->dev->of_node;
 76
 77	dai_link->cpu_of_node = of_parse_phandle(np, "cpu", 0);
 78	if (!dai_link->cpu_of_node) {
 79		dev_err(card->dev, "%s() error getting cpu phandle\n",
 80				__func__);
 81		return -EINVAL;
 82	}
 83	dai_link->platform_of_node = dai_link->cpu_of_node;
 84
 85	dai_link->codec_of_node = of_parse_phandle(np, "codec", 0);
 86	if (!dai_link->codec_of_node) {
 87		dev_err(card->dev, "%s() error getting codec phandle\n",
 88				__func__);
 89		return -EINVAL;
 90	}
 91
 92	return 0;
 93}
 94
 95static int storm_platform_probe(struct platform_device *pdev)
 96{
 97	struct snd_soc_card *card;
 98	int ret;
 99
100	card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
101	if (!card)
102		return -ENOMEM;
103
104	card->dev = &pdev->dev;
105	platform_set_drvdata(pdev, card);
106
107	ret = snd_soc_of_parse_card_name(card, "qcom,model");
108	if (ret) {
109		dev_err(&pdev->dev, "%s() error parsing card name: %d\n",
110				__func__, ret);
111		return ret;
112	}
113
114	card->dai_link	= &storm_dai_link;
115	card->num_links	= 1;
116
117	ret = storm_parse_of(card);
118	if (ret) {
119		dev_err(&pdev->dev, "%s() error resolving dai links: %d\n",
120				__func__, ret);
121		return ret;
122	}
123
124	ret = devm_snd_soc_register_card(&pdev->dev, card);
125	if (ret)
126		dev_err(&pdev->dev, "%s() error registering soundcard: %d\n",
127				__func__, ret);
128
129	return ret;
130
131}
132
133#ifdef CONFIG_OF
134static const struct of_device_id storm_device_id[]  = {
135	{ .compatible = "google,storm-audio" },
136	{},
137};
138MODULE_DEVICE_TABLE(of, storm_device_id);
139#endif
140
141static struct platform_driver storm_platform_driver = {
142	.driver = {
143		.name = "storm-audio",
144		.of_match_table =
145			of_match_ptr(storm_device_id),
146	},
147	.probe = storm_platform_probe,
148};
149module_platform_driver(storm_platform_driver);
150
151MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver");
152MODULE_LICENSE("GPL v2");
v5.4
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
  4 *
 
 
 
 
 
 
 
 
 
  5 * storm.c -- ALSA SoC machine driver for QTi ipq806x-based Storm board
  6 */
  7
  8#include <linux/device.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/mod_devicetable.h>
 12#include <linux/platform_device.h>
 13#include <sound/pcm.h>
 14#include <sound/pcm_params.h>
 15#include <sound/soc.h>
 16
 17#define STORM_SYSCLK_MULT			4
 18
 19static int storm_ops_hw_params(struct snd_pcm_substream *substream,
 20		struct snd_pcm_hw_params *params)
 21{
 22	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 23	struct snd_soc_card *card = soc_runtime->card;
 24	snd_pcm_format_t format = params_format(params);
 25	unsigned int rate = params_rate(params);
 26	unsigned int sysclk_freq;
 27	int bitwidth, ret;
 28
 29	bitwidth = snd_pcm_format_width(format);
 30	if (bitwidth < 0) {
 31		dev_err(card->dev, "invalid bit width given: %d\n", bitwidth);
 
 32		return bitwidth;
 33	}
 34
 35	/*
 36	 * as the CPU DAI is the I2S bus master and no system clock is needed by
 37	 * the MAX98357a DAC, simply set the system clock to be a constant
 38	 * multiple of the bit clock for the clock divider
 39	 */
 40	sysclk_freq = rate * bitwidth * 2 * STORM_SYSCLK_MULT;
 41
 42	ret = snd_soc_dai_set_sysclk(soc_runtime->cpu_dai, 0, sysclk_freq, 0);
 43	if (ret) {
 44		dev_err(card->dev, "error setting sysclk to %u: %d\n",
 45			sysclk_freq, ret);
 46		return ret;
 47	}
 48
 49	return 0;
 50}
 51
 52static const struct snd_soc_ops storm_soc_ops = {
 53	.hw_params	= storm_ops_hw_params,
 54};
 55
 56SND_SOC_DAILINK_DEFS(hifi,
 57	DAILINK_COMP_ARRAY(COMP_EMPTY()),
 58	DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
 59	DAILINK_COMP_ARRAY(COMP_EMPTY()));
 60
 61static struct snd_soc_dai_link storm_dai_link = {
 62	.name		= "Primary",
 63	.stream_name	= "Primary",
 
 64	.ops		= &storm_soc_ops,
 65	SND_SOC_DAILINK_REG(hifi),
 66};
 67
 68static int storm_parse_of(struct snd_soc_card *card)
 69{
 70	struct snd_soc_dai_link *dai_link = card->dai_link;
 71	struct device_node *np = card->dev->of_node;
 72
 73	dai_link->cpus->of_node = of_parse_phandle(np, "cpu", 0);
 74	if (!dai_link->cpus->of_node) {
 75		dev_err(card->dev, "error getting cpu phandle\n");
 
 76		return -EINVAL;
 77	}
 78	dai_link->platforms->of_node = dai_link->cpus->of_node;
 79
 80	dai_link->codecs->of_node = of_parse_phandle(np, "codec", 0);
 81	if (!dai_link->codecs->of_node) {
 82		dev_err(card->dev, "error getting codec phandle\n");
 
 83		return -EINVAL;
 84	}
 85
 86	return 0;
 87}
 88
 89static int storm_platform_probe(struct platform_device *pdev)
 90{
 91	struct snd_soc_card *card;
 92	int ret;
 93
 94	card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
 95	if (!card)
 96		return -ENOMEM;
 97
 98	card->dev = &pdev->dev;
 
 99
100	ret = snd_soc_of_parse_card_name(card, "qcom,model");
101	if (ret) {
102		dev_err(&pdev->dev, "error parsing card name: %d\n", ret);
 
103		return ret;
104	}
105
106	card->dai_link	= &storm_dai_link;
107	card->num_links	= 1;
108
109	ret = storm_parse_of(card);
110	if (ret) {
111		dev_err(&pdev->dev, "error resolving dai links: %d\n", ret);
 
112		return ret;
113	}
114
115	ret = devm_snd_soc_register_card(&pdev->dev, card);
116	if (ret)
117		dev_err(&pdev->dev, "error registering soundcard: %d\n", ret);
 
118
119	return ret;
120
121}
122
123#ifdef CONFIG_OF
124static const struct of_device_id storm_device_id[]  = {
125	{ .compatible = "google,storm-audio" },
126	{},
127};
128MODULE_DEVICE_TABLE(of, storm_device_id);
129#endif
130
131static struct platform_driver storm_platform_driver = {
132	.driver = {
133		.name = "storm-audio",
134		.of_match_table =
135			of_match_ptr(storm_device_id),
136	},
137	.probe = storm_platform_probe,
138};
139module_platform_driver(storm_platform_driver);
140
141MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver");
142MODULE_LICENSE("GPL v2");