treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / sound / soc / pxa / poodle.c
blob59ef04d0467a622d453366bbbbbd330b8c3891a9
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * poodle.c -- SoC audio for Poodle
5 * Copyright 2005 Wolfson Microelectronics PLC.
6 * Copyright 2005 Openedhand Ltd.
8 * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
9 * Richard Purdie <richard@openedhand.com>
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/timer.h>
15 #include <linux/i2c.h>
16 #include <linux/interrupt.h>
17 #include <linux/platform_device.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/soc.h>
22 #include <asm/mach-types.h>
23 #include <asm/hardware/locomo.h>
24 #include <mach/poodle.h>
25 #include <mach/audio.h>
27 #include "../codecs/wm8731.h"
28 #include "pxa2xx-i2s.h"
30 #define POODLE_HP 1
31 #define POODLE_HP_OFF 0
32 #define POODLE_SPK_ON 1
33 #define POODLE_SPK_OFF 0
35 /* audio clock in Hz - rounded from 12.235MHz */
36 #define POODLE_AUDIO_CLOCK 12288000
38 static int poodle_jack_func;
39 static int poodle_spk_func;
41 static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
43 /* set up jack connection */
44 if (poodle_jack_func == POODLE_HP) {
45 /* set = unmute headphone */
46 locomo_gpio_write(&poodle_locomo_device.dev,
47 POODLE_LOCOMO_GPIO_MUTE_L, 1);
48 locomo_gpio_write(&poodle_locomo_device.dev,
49 POODLE_LOCOMO_GPIO_MUTE_R, 1);
50 snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
51 } else {
52 locomo_gpio_write(&poodle_locomo_device.dev,
53 POODLE_LOCOMO_GPIO_MUTE_L, 0);
54 locomo_gpio_write(&poodle_locomo_device.dev,
55 POODLE_LOCOMO_GPIO_MUTE_R, 0);
56 snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
59 /* set the endpoints to their new connection states */
60 if (poodle_spk_func == POODLE_SPK_ON)
61 snd_soc_dapm_enable_pin(dapm, "Ext Spk");
62 else
63 snd_soc_dapm_disable_pin(dapm, "Ext Spk");
65 /* signal a DAPM event */
66 snd_soc_dapm_sync(dapm);
69 static int poodle_startup(struct snd_pcm_substream *substream)
71 struct snd_soc_pcm_runtime *rtd = substream->private_data;
73 /* check the jack status at stream startup */
74 poodle_ext_control(&rtd->card->dapm);
76 return 0;
79 /* we need to unmute the HP at shutdown as the mute burns power on poodle */
80 static void poodle_shutdown(struct snd_pcm_substream *substream)
82 /* set = unmute headphone */
83 locomo_gpio_write(&poodle_locomo_device.dev,
84 POODLE_LOCOMO_GPIO_MUTE_L, 1);
85 locomo_gpio_write(&poodle_locomo_device.dev,
86 POODLE_LOCOMO_GPIO_MUTE_R, 1);
89 static int poodle_hw_params(struct snd_pcm_substream *substream,
90 struct snd_pcm_hw_params *params)
92 struct snd_soc_pcm_runtime *rtd = substream->private_data;
93 struct snd_soc_dai *codec_dai = rtd->codec_dai;
94 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
95 unsigned int clk = 0;
96 int ret = 0;
98 switch (params_rate(params)) {
99 case 8000:
100 case 16000:
101 case 48000:
102 case 96000:
103 clk = 12288000;
104 break;
105 case 11025:
106 case 22050:
107 case 44100:
108 clk = 11289600;
109 break;
112 /* set the codec system clock for DAC and ADC */
113 ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
114 SND_SOC_CLOCK_IN);
115 if (ret < 0)
116 return ret;
118 /* set the I2S system clock as input (unused) */
119 ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
120 SND_SOC_CLOCK_IN);
121 if (ret < 0)
122 return ret;
124 return 0;
127 static const struct snd_soc_ops poodle_ops = {
128 .startup = poodle_startup,
129 .hw_params = poodle_hw_params,
130 .shutdown = poodle_shutdown,
133 static int poodle_get_jack(struct snd_kcontrol *kcontrol,
134 struct snd_ctl_elem_value *ucontrol)
136 ucontrol->value.enumerated.item[0] = poodle_jack_func;
137 return 0;
140 static int poodle_set_jack(struct snd_kcontrol *kcontrol,
141 struct snd_ctl_elem_value *ucontrol)
143 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
145 if (poodle_jack_func == ucontrol->value.enumerated.item[0])
146 return 0;
148 poodle_jack_func = ucontrol->value.enumerated.item[0];
149 poodle_ext_control(&card->dapm);
150 return 1;
153 static int poodle_get_spk(struct snd_kcontrol *kcontrol,
154 struct snd_ctl_elem_value *ucontrol)
156 ucontrol->value.enumerated.item[0] = poodle_spk_func;
157 return 0;
160 static int poodle_set_spk(struct snd_kcontrol *kcontrol,
161 struct snd_ctl_elem_value *ucontrol)
163 struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
165 if (poodle_spk_func == ucontrol->value.enumerated.item[0])
166 return 0;
168 poodle_spk_func = ucontrol->value.enumerated.item[0];
169 poodle_ext_control(&card->dapm);
170 return 1;
173 static int poodle_amp_event(struct snd_soc_dapm_widget *w,
174 struct snd_kcontrol *k, int event)
176 if (SND_SOC_DAPM_EVENT_ON(event))
177 locomo_gpio_write(&poodle_locomo_device.dev,
178 POODLE_LOCOMO_GPIO_AMP_ON, 0);
179 else
180 locomo_gpio_write(&poodle_locomo_device.dev,
181 POODLE_LOCOMO_GPIO_AMP_ON, 1);
183 return 0;
186 /* poodle machine dapm widgets */
187 static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
188 SND_SOC_DAPM_HP("Headphone Jack", NULL),
189 SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
190 SND_SOC_DAPM_MIC("Microphone", NULL),
193 /* Corgi machine connections to the codec pins */
194 static const struct snd_soc_dapm_route poodle_audio_map[] = {
196 /* headphone connected to LHPOUT1, RHPOUT1 */
197 {"Headphone Jack", NULL, "LHPOUT"},
198 {"Headphone Jack", NULL, "RHPOUT"},
200 /* speaker connected to LOUT, ROUT */
201 {"Ext Spk", NULL, "ROUT"},
202 {"Ext Spk", NULL, "LOUT"},
204 {"MICIN", NULL, "Microphone"},
207 static const char * const jack_function[] = {"Off", "Headphone"};
208 static const char * const spk_function[] = {"Off", "On"};
209 static const struct soc_enum poodle_enum[] = {
210 SOC_ENUM_SINGLE_EXT(2, jack_function),
211 SOC_ENUM_SINGLE_EXT(2, spk_function),
214 static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
215 SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
216 poodle_set_jack),
217 SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
218 poodle_set_spk),
221 /* poodle digital audio interface glue - connects codec <--> CPU */
222 SND_SOC_DAILINK_DEFS(wm8731,
223 DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
224 DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
225 DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
227 static struct snd_soc_dai_link poodle_dai = {
228 .name = "WM8731",
229 .stream_name = "WM8731",
230 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
231 SND_SOC_DAIFMT_CBS_CFS,
232 .ops = &poodle_ops,
233 SND_SOC_DAILINK_REG(wm8731),
236 /* poodle audio machine driver */
237 static struct snd_soc_card poodle = {
238 .name = "Poodle",
239 .dai_link = &poodle_dai,
240 .num_links = 1,
241 .owner = THIS_MODULE,
243 .controls = wm8731_poodle_controls,
244 .num_controls = ARRAY_SIZE(wm8731_poodle_controls),
245 .dapm_widgets = wm8731_dapm_widgets,
246 .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
247 .dapm_routes = poodle_audio_map,
248 .num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
249 .fully_routed = true,
252 static int poodle_probe(struct platform_device *pdev)
254 struct snd_soc_card *card = &poodle;
255 int ret;
257 locomo_gpio_set_dir(&poodle_locomo_device.dev,
258 POODLE_LOCOMO_GPIO_AMP_ON, 0);
259 /* should we mute HP at startup - burning power ?*/
260 locomo_gpio_set_dir(&poodle_locomo_device.dev,
261 POODLE_LOCOMO_GPIO_MUTE_L, 0);
262 locomo_gpio_set_dir(&poodle_locomo_device.dev,
263 POODLE_LOCOMO_GPIO_MUTE_R, 0);
265 card->dev = &pdev->dev;
267 ret = devm_snd_soc_register_card(&pdev->dev, card);
268 if (ret)
269 dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
270 ret);
271 return ret;
274 static struct platform_driver poodle_driver = {
275 .driver = {
276 .name = "poodle-audio",
277 .pm = &snd_soc_pm_ops,
279 .probe = poodle_probe,
282 module_platform_driver(poodle_driver);
284 /* Module information */
285 MODULE_AUTHOR("Richard Purdie");
286 MODULE_DESCRIPTION("ALSA SoC Poodle");
287 MODULE_LICENSE("GPL");
288 MODULE_ALIAS("platform:poodle-audio");