1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
5 * storm.c -- ALSA SoC machine driver for QTi ipq806x-based Storm board
8 #include <linux/device.h>
9 #include <linux/module.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>
17 #define STORM_SYSCLK_MULT 4
19 static int storm_ops_hw_params(struct snd_pcm_substream
*substream
,
20 struct snd_pcm_hw_params
*params
)
22 struct snd_soc_pcm_runtime
*soc_runtime
= snd_soc_substream_to_rtd(substream
);
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
;
29 bitwidth
= snd_pcm_format_width(format
);
31 dev_err(card
->dev
, "invalid bit width given: %d\n", bitwidth
);
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
40 sysclk_freq
= rate
* bitwidth
* 2 * STORM_SYSCLK_MULT
;
42 ret
= snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(soc_runtime
, 0), 0, sysclk_freq
, 0);
44 dev_err(card
->dev
, "error setting sysclk to %u: %d\n",
52 static const struct snd_soc_ops storm_soc_ops
= {
53 .hw_params
= storm_ops_hw_params
,
56 SND_SOC_DAILINK_DEFS(hifi
,
57 DAILINK_COMP_ARRAY(COMP_EMPTY()),
58 DAILINK_COMP_ARRAY(COMP_CODEC(NULL
, "HiFi")),
59 DAILINK_COMP_ARRAY(COMP_EMPTY()));
61 static struct snd_soc_dai_link storm_dai_link
= {
63 .stream_name
= "Primary",
64 .ops
= &storm_soc_ops
,
65 SND_SOC_DAILINK_REG(hifi
),
68 static int storm_parse_of(struct snd_soc_card
*card
)
70 struct snd_soc_dai_link
*dai_link
= card
->dai_link
;
71 struct device_node
*np
= card
->dev
->of_node
;
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");
78 dai_link
->platforms
->of_node
= dai_link
->cpus
->of_node
;
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");
89 static int storm_platform_probe(struct platform_device
*pdev
)
91 struct snd_soc_card
*card
;
94 card
= devm_kzalloc(&pdev
->dev
, sizeof(*card
), GFP_KERNEL
);
98 card
->dev
= &pdev
->dev
;
99 card
->owner
= THIS_MODULE
;
101 ret
= snd_soc_of_parse_card_name(card
, "qcom,model");
103 dev_err(&pdev
->dev
, "error parsing card name: %d\n", ret
);
107 card
->dai_link
= &storm_dai_link
;
110 ret
= storm_parse_of(card
);
112 dev_err(&pdev
->dev
, "error resolving dai links: %d\n", ret
);
116 ret
= devm_snd_soc_register_card(&pdev
->dev
, card
);
118 dev_err(&pdev
->dev
, "error registering soundcard: %d\n", ret
);
125 static const struct of_device_id storm_device_id
[] = {
126 { .compatible
= "google,storm-audio" },
129 MODULE_DEVICE_TABLE(of
, storm_device_id
);
132 static struct platform_driver storm_platform_driver
= {
134 .name
= "storm-audio",
136 of_match_ptr(storm_device_id
),
138 .probe
= storm_platform_probe
,
140 module_platform_driver(storm_platform_driver
);
142 MODULE_DESCRIPTION("QTi IPQ806x-based Storm Machine Driver");
143 MODULE_LICENSE("GPL");