xref: /kernel/linux/linux-5.10/sound/soc/pxa/magician.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * SoC audio for HTC Magician
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2006 Philipp Zabel <philipp.zabel@gmail.com>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * based on spitz.c,
88c2ecf20Sopenharmony_ci * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
98c2ecf20Sopenharmony_ci *          Richard Purdie <richard@openedhand.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/timer.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
168c2ecf20Sopenharmony_ci#include <linux/delay.h>
178c2ecf20Sopenharmony_ci#include <linux/gpio.h>
188c2ecf20Sopenharmony_ci#include <linux/i2c.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <sound/core.h>
218c2ecf20Sopenharmony_ci#include <sound/pcm.h>
228c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
238c2ecf20Sopenharmony_ci#include <sound/soc.h>
248c2ecf20Sopenharmony_ci#include <sound/uda1380.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include <mach/magician.h>
278c2ecf20Sopenharmony_ci#include <asm/mach-types.h>
288c2ecf20Sopenharmony_ci#include "../codecs/uda1380.h"
298c2ecf20Sopenharmony_ci#include "pxa2xx-i2s.h"
308c2ecf20Sopenharmony_ci#include "pxa-ssp.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define MAGICIAN_MIC       0
338c2ecf20Sopenharmony_ci#define MAGICIAN_MIC_EXT   1
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic int magician_hp_switch;
368c2ecf20Sopenharmony_cistatic int magician_spk_switch = 1;
378c2ecf20Sopenharmony_cistatic int magician_in_sel = MAGICIAN_MIC;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic void magician_ext_control(struct snd_soc_dapm_context *dapm)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	snd_soc_dapm_mutex_lock(dapm);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	if (magician_spk_switch)
458c2ecf20Sopenharmony_ci		snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
468c2ecf20Sopenharmony_ci	else
478c2ecf20Sopenharmony_ci		snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
488c2ecf20Sopenharmony_ci	if (magician_hp_switch)
498c2ecf20Sopenharmony_ci		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
508c2ecf20Sopenharmony_ci	else
518c2ecf20Sopenharmony_ci		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	switch (magician_in_sel) {
548c2ecf20Sopenharmony_ci	case MAGICIAN_MIC:
558c2ecf20Sopenharmony_ci		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic");
568c2ecf20Sopenharmony_ci		snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic");
578c2ecf20Sopenharmony_ci		break;
588c2ecf20Sopenharmony_ci	case MAGICIAN_MIC_EXT:
598c2ecf20Sopenharmony_ci		snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic");
608c2ecf20Sopenharmony_ci		snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic");
618c2ecf20Sopenharmony_ci		break;
628c2ecf20Sopenharmony_ci	}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	snd_soc_dapm_sync_unlocked(dapm);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	snd_soc_dapm_mutex_unlock(dapm);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int magician_startup(struct snd_pcm_substream *substream)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	/* check the jack status at stream startup */
748c2ecf20Sopenharmony_ci	magician_ext_control(&rtd->card->dapm);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return 0;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * Magician uses SSP port for playback.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_cistatic int magician_playback_hw_params(struct snd_pcm_substream *substream,
838c2ecf20Sopenharmony_ci				       struct snd_pcm_hw_params *params)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
868c2ecf20Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
878c2ecf20Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
888c2ecf20Sopenharmony_ci	unsigned int width;
898c2ecf20Sopenharmony_ci	int ret = 0;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	/* set codec DAI configuration */
928c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
938c2ecf20Sopenharmony_ci			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
948c2ecf20Sopenharmony_ci	if (ret < 0)
958c2ecf20Sopenharmony_ci		return ret;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/* set cpu DAI configuration */
988c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
998c2ecf20Sopenharmony_ci			SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
1008c2ecf20Sopenharmony_ci	if (ret < 0)
1018c2ecf20Sopenharmony_ci		return ret;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	width = snd_pcm_format_physical_width(params_format(params));
1048c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width);
1058c2ecf20Sopenharmony_ci	if (ret < 0)
1068c2ecf20Sopenharmony_ci		return ret;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	/* set audio clock as clock source */
1098c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0,
1108c2ecf20Sopenharmony_ci			SND_SOC_CLOCK_OUT);
1118c2ecf20Sopenharmony_ci	if (ret < 0)
1128c2ecf20Sopenharmony_ci		return ret;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return 0;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci/*
1188c2ecf20Sopenharmony_ci * Magician uses I2S for capture.
1198c2ecf20Sopenharmony_ci */
1208c2ecf20Sopenharmony_cistatic int magician_capture_hw_params(struct snd_pcm_substream *substream,
1218c2ecf20Sopenharmony_ci				      struct snd_pcm_hw_params *params)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1248c2ecf20Sopenharmony_ci	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
1258c2ecf20Sopenharmony_ci	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
1268c2ecf20Sopenharmony_ci	int ret = 0;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	/* set codec DAI configuration */
1298c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_fmt(codec_dai,
1308c2ecf20Sopenharmony_ci			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
1318c2ecf20Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS);
1328c2ecf20Sopenharmony_ci	if (ret < 0)
1338c2ecf20Sopenharmony_ci		return ret;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* set cpu DAI configuration */
1368c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_fmt(cpu_dai,
1378c2ecf20Sopenharmony_ci			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
1388c2ecf20Sopenharmony_ci			SND_SOC_DAIFMT_CBS_CFS);
1398c2ecf20Sopenharmony_ci	if (ret < 0)
1408c2ecf20Sopenharmony_ci		return ret;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	/* set the I2S system clock as output */
1438c2ecf20Sopenharmony_ci	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
1448c2ecf20Sopenharmony_ci			SND_SOC_CLOCK_OUT);
1458c2ecf20Sopenharmony_ci	if (ret < 0)
1468c2ecf20Sopenharmony_ci		return ret;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic const struct snd_soc_ops magician_capture_ops = {
1528c2ecf20Sopenharmony_ci	.startup = magician_startup,
1538c2ecf20Sopenharmony_ci	.hw_params = magician_capture_hw_params,
1548c2ecf20Sopenharmony_ci};
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic const struct snd_soc_ops magician_playback_ops = {
1578c2ecf20Sopenharmony_ci	.startup = magician_startup,
1588c2ecf20Sopenharmony_ci	.hw_params = magician_playback_hw_params,
1598c2ecf20Sopenharmony_ci};
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int magician_get_hp(struct snd_kcontrol *kcontrol,
1628c2ecf20Sopenharmony_ci			     struct snd_ctl_elem_value *ucontrol)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = magician_hp_switch;
1658c2ecf20Sopenharmony_ci	return 0;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_cistatic int magician_set_hp(struct snd_kcontrol *kcontrol,
1698c2ecf20Sopenharmony_ci			     struct snd_ctl_elem_value *ucontrol)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	if (magician_hp_switch == ucontrol->value.integer.value[0])
1748c2ecf20Sopenharmony_ci		return 0;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	magician_hp_switch = ucontrol->value.integer.value[0];
1778c2ecf20Sopenharmony_ci	magician_ext_control(&card->dapm);
1788c2ecf20Sopenharmony_ci	return 1;
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_cistatic int magician_get_spk(struct snd_kcontrol *kcontrol,
1828c2ecf20Sopenharmony_ci			    struct snd_ctl_elem_value *ucontrol)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	ucontrol->value.integer.value[0] = magician_spk_switch;
1858c2ecf20Sopenharmony_ci	return 0;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int magician_set_spk(struct snd_kcontrol *kcontrol,
1898c2ecf20Sopenharmony_ci			    struct snd_ctl_elem_value *ucontrol)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	if (magician_spk_switch == ucontrol->value.integer.value[0])
1948c2ecf20Sopenharmony_ci		return 0;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	magician_spk_switch = ucontrol->value.integer.value[0];
1978c2ecf20Sopenharmony_ci	magician_ext_control(&card->dapm);
1988c2ecf20Sopenharmony_ci	return 1;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic int magician_get_input(struct snd_kcontrol *kcontrol,
2028c2ecf20Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	ucontrol->value.enumerated.item[0] = magician_in_sel;
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int magician_set_input(struct snd_kcontrol *kcontrol,
2098c2ecf20Sopenharmony_ci			      struct snd_ctl_elem_value *ucontrol)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	if (magician_in_sel == ucontrol->value.enumerated.item[0])
2128c2ecf20Sopenharmony_ci		return 0;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	magician_in_sel = ucontrol->value.enumerated.item[0];
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	switch (magician_in_sel) {
2178c2ecf20Sopenharmony_ci	case MAGICIAN_MIC:
2188c2ecf20Sopenharmony_ci		gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 1);
2198c2ecf20Sopenharmony_ci		break;
2208c2ecf20Sopenharmony_ci	case MAGICIAN_MIC_EXT:
2218c2ecf20Sopenharmony_ci		gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 0);
2228c2ecf20Sopenharmony_ci	}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	return 1;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int magician_spk_power(struct snd_soc_dapm_widget *w,
2288c2ecf20Sopenharmony_ci				struct snd_kcontrol *k, int event)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, SND_SOC_DAPM_EVENT_ON(event));
2318c2ecf20Sopenharmony_ci	return 0;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic int magician_hp_power(struct snd_soc_dapm_widget *w,
2358c2ecf20Sopenharmony_ci				struct snd_kcontrol *k, int event)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, SND_SOC_DAPM_EVENT_ON(event));
2388c2ecf20Sopenharmony_ci	return 0;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic int magician_mic_bias(struct snd_soc_dapm_widget *w,
2428c2ecf20Sopenharmony_ci				struct snd_kcontrol *k, int event)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, SND_SOC_DAPM_EVENT_ON(event));
2458c2ecf20Sopenharmony_ci	return 0;
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci/* magician machine dapm widgets */
2498c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
2508c2ecf20Sopenharmony_ci	SND_SOC_DAPM_HP("Headphone Jack", magician_hp_power),
2518c2ecf20Sopenharmony_ci	SND_SOC_DAPM_SPK("Speaker", magician_spk_power),
2528c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MIC("Call Mic", magician_mic_bias),
2538c2ecf20Sopenharmony_ci	SND_SOC_DAPM_MIC("Headset Mic", magician_mic_bias),
2548c2ecf20Sopenharmony_ci};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/* magician machine audio_map */
2578c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route audio_map[] = {
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* Headphone connected to VOUTL, VOUTR */
2608c2ecf20Sopenharmony_ci	{"Headphone Jack", NULL, "VOUTL"},
2618c2ecf20Sopenharmony_ci	{"Headphone Jack", NULL, "VOUTR"},
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* Speaker connected to VOUTL, VOUTR */
2648c2ecf20Sopenharmony_ci	{"Speaker", NULL, "VOUTL"},
2658c2ecf20Sopenharmony_ci	{"Speaker", NULL, "VOUTR"},
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Mics are connected to VINM */
2688c2ecf20Sopenharmony_ci	{"VINM", NULL, "Headset Mic"},
2698c2ecf20Sopenharmony_ci	{"VINM", NULL, "Call Mic"},
2708c2ecf20Sopenharmony_ci};
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic const char * const input_select[] = {"Call Mic", "Headset Mic"};
2738c2ecf20Sopenharmony_cistatic const struct soc_enum magician_in_sel_enum =
2748c2ecf20Sopenharmony_ci	SOC_ENUM_SINGLE_EXT(2, input_select);
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new uda1380_magician_controls[] = {
2778c2ecf20Sopenharmony_ci	SOC_SINGLE_BOOL_EXT("Headphone Switch",
2788c2ecf20Sopenharmony_ci			(unsigned long)&magician_hp_switch,
2798c2ecf20Sopenharmony_ci			magician_get_hp, magician_set_hp),
2808c2ecf20Sopenharmony_ci	SOC_SINGLE_BOOL_EXT("Speaker Switch",
2818c2ecf20Sopenharmony_ci			(unsigned long)&magician_spk_switch,
2828c2ecf20Sopenharmony_ci			magician_get_spk, magician_set_spk),
2838c2ecf20Sopenharmony_ci	SOC_ENUM_EXT("Input Select", magician_in_sel_enum,
2848c2ecf20Sopenharmony_ci			magician_get_input, magician_set_input),
2858c2ecf20Sopenharmony_ci};
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci/* magician digital audio interface glue - connects codec <--> CPU */
2888c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(playback,
2898c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.0")),
2908c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-0018",
2918c2ecf20Sopenharmony_ci				      "uda1380-hifi-playback")),
2928c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEFS(capture,
2958c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
2968c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-0018",
2978c2ecf20Sopenharmony_ci				      "uda1380-hifi-capture")),
2988c2ecf20Sopenharmony_ci	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link magician_dai[] = {
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	.name = "uda1380",
3038c2ecf20Sopenharmony_ci	.stream_name = "UDA1380 Playback",
3048c2ecf20Sopenharmony_ci	.ops = &magician_playback_ops,
3058c2ecf20Sopenharmony_ci	SND_SOC_DAILINK_REG(playback),
3068c2ecf20Sopenharmony_ci},
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	.name = "uda1380",
3098c2ecf20Sopenharmony_ci	.stream_name = "UDA1380 Capture",
3108c2ecf20Sopenharmony_ci	.ops = &magician_capture_ops,
3118c2ecf20Sopenharmony_ci	SND_SOC_DAILINK_REG(capture),
3128c2ecf20Sopenharmony_ci}
3138c2ecf20Sopenharmony_ci};
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/* magician audio machine driver */
3168c2ecf20Sopenharmony_cistatic struct snd_soc_card snd_soc_card_magician = {
3178c2ecf20Sopenharmony_ci	.name = "Magician",
3188c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
3198c2ecf20Sopenharmony_ci	.dai_link = magician_dai,
3208c2ecf20Sopenharmony_ci	.num_links = ARRAY_SIZE(magician_dai),
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	.controls = uda1380_magician_controls,
3238c2ecf20Sopenharmony_ci	.num_controls = ARRAY_SIZE(uda1380_magician_controls),
3248c2ecf20Sopenharmony_ci	.dapm_widgets = uda1380_dapm_widgets,
3258c2ecf20Sopenharmony_ci	.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
3268c2ecf20Sopenharmony_ci	.dapm_routes = audio_map,
3278c2ecf20Sopenharmony_ci	.num_dapm_routes = ARRAY_SIZE(audio_map),
3288c2ecf20Sopenharmony_ci	.fully_routed = true,
3298c2ecf20Sopenharmony_ci};
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic struct platform_device *magician_snd_device;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci/*
3348c2ecf20Sopenharmony_ci * FIXME: move into magician board file once merged into the pxa tree
3358c2ecf20Sopenharmony_ci */
3368c2ecf20Sopenharmony_cistatic struct uda1380_platform_data uda1380_info = {
3378c2ecf20Sopenharmony_ci	.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
3388c2ecf20Sopenharmony_ci	.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
3398c2ecf20Sopenharmony_ci	.dac_clk    = UDA1380_DAC_CLK_WSPLL,
3408c2ecf20Sopenharmony_ci};
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic struct i2c_board_info i2c_board_info[] = {
3438c2ecf20Sopenharmony_ci	{
3448c2ecf20Sopenharmony_ci		I2C_BOARD_INFO("uda1380", 0x18),
3458c2ecf20Sopenharmony_ci		.platform_data = &uda1380_info,
3468c2ecf20Sopenharmony_ci	},
3478c2ecf20Sopenharmony_ci};
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int __init magician_init(void)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	int ret;
3528c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter;
3538c2ecf20Sopenharmony_ci	struct i2c_client *client;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!machine_is_magician())
3568c2ecf20Sopenharmony_ci		return -ENODEV;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	adapter = i2c_get_adapter(0);
3598c2ecf20Sopenharmony_ci	if (!adapter)
3608c2ecf20Sopenharmony_ci		return -ENODEV;
3618c2ecf20Sopenharmony_ci	client = i2c_new_client_device(adapter, i2c_board_info);
3628c2ecf20Sopenharmony_ci	i2c_put_adapter(adapter);
3638c2ecf20Sopenharmony_ci	if (IS_ERR(client))
3648c2ecf20Sopenharmony_ci		return PTR_ERR(client);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
3678c2ecf20Sopenharmony_ci	if (ret)
3688c2ecf20Sopenharmony_ci		goto err_request_spk;
3698c2ecf20Sopenharmony_ci	ret = gpio_request(EGPIO_MAGICIAN_EP_POWER, "EP_POWER");
3708c2ecf20Sopenharmony_ci	if (ret)
3718c2ecf20Sopenharmony_ci		goto err_request_ep;
3728c2ecf20Sopenharmony_ci	ret = gpio_request(EGPIO_MAGICIAN_MIC_POWER, "MIC_POWER");
3738c2ecf20Sopenharmony_ci	if (ret)
3748c2ecf20Sopenharmony_ci		goto err_request_mic;
3758c2ecf20Sopenharmony_ci	ret = gpio_request(EGPIO_MAGICIAN_IN_SEL0, "IN_SEL0");
3768c2ecf20Sopenharmony_ci	if (ret)
3778c2ecf20Sopenharmony_ci		goto err_request_in_sel0;
3788c2ecf20Sopenharmony_ci	ret = gpio_request(EGPIO_MAGICIAN_IN_SEL1, "IN_SEL1");
3798c2ecf20Sopenharmony_ci	if (ret)
3808c2ecf20Sopenharmony_ci		goto err_request_in_sel1;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	magician_snd_device = platform_device_alloc("soc-audio", -1);
3858c2ecf20Sopenharmony_ci	if (!magician_snd_device) {
3868c2ecf20Sopenharmony_ci		ret = -ENOMEM;
3878c2ecf20Sopenharmony_ci		goto err_pdev;
3888c2ecf20Sopenharmony_ci	}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	platform_set_drvdata(magician_snd_device, &snd_soc_card_magician);
3918c2ecf20Sopenharmony_ci	ret = platform_device_add(magician_snd_device);
3928c2ecf20Sopenharmony_ci	if (ret) {
3938c2ecf20Sopenharmony_ci		platform_device_put(magician_snd_device);
3948c2ecf20Sopenharmony_ci		goto err_pdev;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_cierr_pdev:
4008c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
4018c2ecf20Sopenharmony_cierr_request_in_sel1:
4028c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
4038c2ecf20Sopenharmony_cierr_request_in_sel0:
4048c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
4058c2ecf20Sopenharmony_cierr_request_mic:
4068c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_EP_POWER);
4078c2ecf20Sopenharmony_cierr_request_ep:
4088c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
4098c2ecf20Sopenharmony_cierr_request_spk:
4108c2ecf20Sopenharmony_ci	return ret;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_cistatic void __exit magician_exit(void)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	platform_device_unregister(magician_snd_device);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
4188c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
4198c2ecf20Sopenharmony_ci	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
4228c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
4238c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
4248c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_EP_POWER);
4258c2ecf20Sopenharmony_ci	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
4268c2ecf20Sopenharmony_ci}
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_cimodule_init(magician_init);
4298c2ecf20Sopenharmony_cimodule_exit(magician_exit);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ciMODULE_AUTHOR("Philipp Zabel");
4328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC Magician");
4338c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
434